Пример #1
0
bool CImageWriterBMP::writeImage(io::IWriteFile* file, IImage* image, u32 param) const
{
	// we always write 24-bit color because nothing really reads 32-bit

	SBMPHeader imageHeader;
	imageHeader.Id = 0x4d42;
	imageHeader.Reserved = 0;
	imageHeader.BitmapDataOffset = sizeof(imageHeader);
	imageHeader.BitmapHeaderSize = 0x28;
	imageHeader.Width = image->getDimension().Width;
	imageHeader.Height = image->getDimension().Height;
	imageHeader.Planes = 1;
	imageHeader.BPP = 24;
	imageHeader.Compression = 0;
	imageHeader.PixelPerMeterX = 0;
	imageHeader.PixelPerMeterY = 0;
	imageHeader.Colors = 0;
	imageHeader.ImportantColors = 0;

	// data size is rounded up to next larger 4 bytes boundary
	imageHeader.BitmapDataSize = imageHeader.Width * imageHeader.BPP / 8;
	imageHeader.BitmapDataSize = (imageHeader.BitmapDataSize + 3) & ~3;
	imageHeader.BitmapDataSize *= imageHeader.Height;

	// file size is data size plus offset to data
	imageHeader.FileSize = imageHeader.BitmapDataOffset + imageHeader.BitmapDataSize;

	// bitmaps are stored upside down and padded so we always do this
	void (*CColorConverter_convertFORMATtoFORMAT)(const void*, s32, void*) = 0;
	switch(image->getColorFormat())
	{
	case ECF_R8G8B8:
		CColorConverter_convertFORMATtoFORMAT
			= CColorConverter::convert_R8G8B8toR8G8B8;
		break;
	case ECF_A8R8G8B8:
		CColorConverter_convertFORMATtoFORMAT
			= CColorConverter::convert_A8R8G8B8toB8G8R8;
		break;
	case ECF_A1R5G5B5:
		CColorConverter_convertFORMATtoFORMAT
			= CColorConverter::convert_A1R5G5B5toR8G8B8;
		break;
	case ECF_R5G6B5:
		CColorConverter_convertFORMATtoFORMAT
			= CColorConverter::convert_R5G6B5toR8G8B8;
		break;
	}

	// couldn't find a color converter
	if (!CColorConverter_convertFORMATtoFORMAT)
		return false;

	// write the bitmap header
	if (file->write(&imageHeader, sizeof(imageHeader)) != sizeof(imageHeader))
		return false;

	u8* scan_lines = (u8*)image->lock();
	if (!scan_lines)
		return false;

	// size of one pixel in bytes
	u32 pixel_size = image->getBytesPerPixel();

	// length of one row of the source image in bytes
	u32 row_stride = (pixel_size * imageHeader.Width);

	// length of one row in bytes, rounded up to nearest 4-byte boundary
	s32 row_size = ((3 * imageHeader.Width) + 3) & ~3;

	// allocate and clear memory for our scan line
	u8* row_pointer = new u8[row_size];
	memset(row_pointer, 0, row_size);

	// convert the image to 24-bit BGR and flip it over
	s32 y;
	for (y = imageHeader.Height - 1; 0 <= y; --y)
	{
		if (image->getColorFormat()==ECF_R8G8B8)
			CColorConverter::convert24BitTo24Bit(&scan_lines[y * row_stride], row_pointer, imageHeader.Width, 1, 0, false, true);
		else
			// source, length [pixels], destination
			CColorConverter_convertFORMATtoFORMAT(&scan_lines[y * row_stride], imageHeader.Width, row_pointer);
		if (file->write(row_pointer, row_size) < row_size)
			break;
	}

	// clean up our scratch area
	delete [] row_pointer;

	// give back image handle
	image->unlock();

	return y < 0;
}
bool CImageWriterBMP::writeAsset(io::IWriteFile* _file, const SAssetWriteParams& _params, IAssetWriterOverride* _override)
{
    if (!_override)
        getDefaultOverride(_override);

    SAssetWriteContext ctx{_params, _file};

	// we always write 24-bit color because nothing really reads 32-bit
    const asset::CImageData* image =
#   ifndef _DEBUG
        static_cast<const asset::CImageData*>(_params.rootAsset);
#   else
        dynamic_cast<const asset::CImageData*>(_params.rootAsset);
#   endif
    assert(image);

    io::IWriteFile* file = _override->getOutputFile(_file, ctx, {image, 0u});

	SBMPHeader imageHeader;
	imageHeader.Id = 0x4d42;
	imageHeader.Reserved = 0;
	imageHeader.BitmapDataOffset = sizeof(imageHeader);
	imageHeader.BitmapHeaderSize = 0x28;
	imageHeader.Width = image->getSize().X;
	imageHeader.Height = image->getSize().Y;
	imageHeader.Planes = 1;
	imageHeader.BPP = 24;
	imageHeader.Compression = 0;
	imageHeader.PixelPerMeterX = 0;
	imageHeader.PixelPerMeterY = 0;
	imageHeader.Colors = 0;
	imageHeader.ImportantColors = 0;

	// data size is rounded up to next larger 4 bytes boundary
	imageHeader.BitmapDataSize = imageHeader.Width * imageHeader.BPP / 8;
	imageHeader.BitmapDataSize = (imageHeader.BitmapDataSize + 3) & ~3;
	imageHeader.BitmapDataSize *= imageHeader.Height;

	// file size is data size plus offset to data
	imageHeader.FileSize = imageHeader.BitmapDataOffset + imageHeader.BitmapDataSize;

	// bitmaps are stored upside down and padded so we always do this
	void (*CColorConverter_convertFORMATtoFORMAT)(const void*, int32_t, void*) = 0;
	switch(image->getColorFormat())
	{
	case asset::EF_R8G8B8_UNORM:
		CColorConverter_convertFORMATtoFORMAT
			= video::CColorConverter::convert_R8G8B8toR8G8B8;
		break;
	case asset::EF_B8G8R8A8_UNORM:
		CColorConverter_convertFORMATtoFORMAT
			= video::CColorConverter::convert_A8R8G8B8toB8G8R8;
		break;
	case asset::EF_A1R5G5B5_UNORM_PACK16:
		CColorConverter_convertFORMATtoFORMAT
			= video::CColorConverter::convert_A1R5G5B5toR8G8B8;
		break;
	case asset::EF_B5G6R5_UNORM_PACK16:
		CColorConverter_convertFORMATtoFORMAT
			= video::CColorConverter::convert_R5G6B5toR8G8B8;
		break;
#ifndef _DEBUG
	default:
		break;
#endif
	}

	// couldn't find a color converter
	if (!CColorConverter_convertFORMATtoFORMAT)
		return false;

	// write the bitmap header
	if (file->write(&imageHeader, sizeof(imageHeader)) != sizeof(imageHeader))
		return false;

	uint8_t* scan_lines = (uint8_t*)image->getData();
	if (!scan_lines)
		return false;

	// size of one pixel in bits
	uint32_t pixel_size_bits = image->getBitsPerPixel();

	// length of one row of the source image in bytes
	uint32_t row_stride = (pixel_size_bits * imageHeader.Width)/8;

	// length of one row in bytes, rounded up to nearest 4-byte boundary
	int32_t row_size = ((3 * imageHeader.Width) + 3) & ~3;

	// allocate and clear memory for our scan line
	uint8_t* row_pointer = new uint8_t[row_size];
	memset(row_pointer, 0, row_size);

	// convert the image to 24-bit BGR and flip it over
	int32_t y;
	for (y = imageHeader.Height - 1; 0 <= y; --y)
	{
		if (image->getColorFormat()==asset::EF_R8G8B8_UNORM)
            video::CColorConverter::convert24BitTo24Bit(&scan_lines[y * row_stride], row_pointer, imageHeader.Width, 1, 0, false, true);
		else
			// source, length [pixels], destination
			CColorConverter_convertFORMATtoFORMAT(&scan_lines[y * row_stride], imageHeader.Width, row_pointer);
		if (file->write(row_pointer, row_size) < row_size)
			break;
	}

	// clean up our scratch area
	delete [] row_pointer;

	return y < 0;
}
bool CImageWriterTGA::writeImage(io::IWriteFile *file, IImage *image,u32 param)
{
	STGAHeader imageHeader;
	imageHeader.IdLength = 0;
	imageHeader.ColorMapType = 0;
	imageHeader.ImageType = 2;
	imageHeader.FirstEntryIndex[0] = 0;
	imageHeader.FirstEntryIndex[1] = 0;
	imageHeader.ColorMapLength = 0;
	imageHeader.ColorMapEntrySize = 0;
	imageHeader.XOrigin[0] = 0;
	imageHeader.XOrigin[1] = 0;
	imageHeader.YOrigin[0] = 0;
	imageHeader.YOrigin[1] = 0;
	imageHeader.ImageWidth = image->getDimension().Width;
	imageHeader.ImageHeight = image->getDimension().Height;

	// top left of image is the top. the image loader needs to
	// be fixed to only swap/flip
	imageHeader.ImageDescriptor = (1 << 5);

   // chances are good we'll need to swizzle data, so i'm going
	// to convert and write one scan line at a time. it's also
	// a bit cleaner this way
	void (*CColorConverter_convertFORMATtoFORMAT)(const void*, s32, void*) = 0;
	switch(image->getColorFormat())
	{
	case ECF_A8R8G8B8:
		CColorConverter_convertFORMATtoFORMAT
			= CColorConverter::convert_A8R8G8B8toA8R8G8B8;
		imageHeader.PixelDepth = 32;
		imageHeader.ImageDescriptor |= 8;
		break;
	case ECF_A1R5G5B5:
		CColorConverter_convertFORMATtoFORMAT
			= CColorConverter::convert_A1R5G5B5toA1R5G5B5;
		imageHeader.PixelDepth = 16;
		imageHeader.ImageDescriptor |= 1;
		break;
	case ECF_R5G6B5:
		CColorConverter_convertFORMATtoFORMAT
			= CColorConverter::convert_R5G6B5toA1R5G5B5;
		imageHeader.PixelDepth = 16;
		imageHeader.ImageDescriptor |= 1;
		break;
	case ECF_R8G8B8:
		CColorConverter_convertFORMATtoFORMAT
			= CColorConverter::convert_R8G8B8toR8G8B8;
		imageHeader.PixelDepth = 24;
		imageHeader.ImageDescriptor |= 0;
		break;
	}

	// couldn't find a color converter
	if (!CColorConverter_convertFORMATtoFORMAT)
		return false;

	if (file->write(&imageHeader, sizeof(imageHeader)) != sizeof(imageHeader))
		return false;

	u8* scan_lines = (u8*)image->lock();
	if (!scan_lines)
		return false;

	// size of one pixel in bytes
	u32 pixel_size = image->getBytesPerPixel();

	// length of one row of the source image in bytes
	u32 row_stride = (pixel_size * imageHeader.ImageWidth);

	// length of one output row in bytes
	s32 row_size = ((imageHeader.PixelDepth / 8) * imageHeader.ImageWidth);

	// allocate a row do translate data into
	u8* row_pointer = new u8[row_size];

	u32 y;
	for (y = 0; y < imageHeader.ImageHeight; ++y)
	{
		// source, length [pixels], destination
		if (image->getColorFormat()==ECF_R8G8B8)
			CColorConverter::convert24BitTo24Bit(&scan_lines[y * row_stride], row_pointer, imageHeader.ImageWidth, 1, 0, 0, true);
		else
			CColorConverter_convertFORMATtoFORMAT(&scan_lines[y * row_stride], imageHeader.ImageWidth, row_pointer);
		if (file->write(row_pointer, row_size) != row_size)
			break;
	}

	delete [] row_pointer;

	image->unlock();

	STGAFooter imageFooter;
	imageFooter.ExtensionOffset = 0;
	imageFooter.DeveloperOffset = 0;
	strncpy(imageFooter.Signature, "TRUEVISION-XFILE.", 18);

	if (file->write(&imageFooter, sizeof(imageFooter)) < (s32)sizeof(imageFooter))
		return false;

	return imageHeader.ImageHeight < y;
}
Пример #4
0
//! записывает битмап в файл
bool CImageSaverBMP::saveImage(IImage* image, io::IWriteFile* file)
{
	// we always write 24-bit color because nothing really reads 32-bit

	SBMPHeader imageHeader;
	imageHeader.Id = 0x4d42;
	imageHeader.Reserved = 0;
	imageHeader.BitmapDataOffset = sizeof(imageHeader);
	imageHeader.BitmapHeaderSize = 0x28;
	imageHeader.Width = image->getDimension().Width;
	imageHeader.Height = image->getDimension().Height;
	imageHeader.Planes = 1;
	imageHeader.BPP = 24;
	imageHeader.Compression = 0;
	imageHeader.PixelPerMeterX = 0;
	imageHeader.PixelPerMeterY = 0;
	imageHeader.Colors = 0;
	imageHeader.ImportantColors = 0;

    s32 widthInBytes = image->getDimension().Width * 3;
    s32 lineData = widthInBytes + ((4-(widthInBytes%4)))%4;

	// data size is rounded up to nearest 4 bytes
	imageHeader.BitmapDataSize = lineData*image->getDimension().Height + 2;

	// file size is data size plus offset to data
	imageHeader.FileSize = imageHeader.BitmapDataOffset + imageHeader.BitmapDataSize;

	// bitmaps are stored upside down and padded so we always do this
	void (*CColorConverter_convertFORMATtoFORMAT)(const void*, s32, void*) = 0; 
	switch(image->getColorFormat())
	{
	case ECF_R8G8B8:
		CColorConverter_convertFORMATtoFORMAT
			= CColorConverter::convert_R8G8B8toR8G8B8;
		break;
	case ECF_A8R8G8B8:
		CColorConverter_convertFORMATtoFORMAT
			= CColorConverter::convert_A8R8G8B8toR8G8B8;
	case ECF_A8B8G8R8:
		CColorConverter_convertFORMATtoFORMAT
			= CColorConverter::convert_A8B8G8R8toR8G8B8;
		break;
	case ECF_A1R5G5B5:
		CColorConverter_convertFORMATtoFORMAT
			= CColorConverter::convert_A1R5G5B5toR8G8B8;
		break;
	case ECF_R5G6B5:
		CColorConverter_convertFORMATtoFORMAT
			= CColorConverter::convert_R5G6B5toR8G8B8;
		break;
	}

	// couldn't find a color converter
	if (!CColorConverter_convertFORMATtoFORMAT)
		return false;

	// write the bitmap header
	if (file->write(&imageHeader, sizeof(imageHeader)) != sizeof(imageHeader))
		return false;

	u8* scan_lines = (u8*)image->getData();
	if (!scan_lines)
		return false;

	// size of one pixel in bytes
	u32 pixel_size = image->getBytesPerPixel();

	// length of one row of the source image in bytes
	u32 row_stride = (pixel_size * imageHeader.Width);

	// length of one row in bytes, rounded up to nearest 4-byte boundary
	s32 row_size = ((3 * imageHeader.Width) + 3) & ~3;

	// allocate and clear memory for our scan line
	u8* row_pointer = new u8[row_size];
	memset(row_pointer, 0, row_size);

	u8* flipped_row_pointer = new u8[row_size];
	memset(flipped_row_pointer, 0, row_size);

	// convert the image to 24-bit RGB and flip it over
	s32 y;
	for (y = imageHeader.Height - 1; 0 <= y; --y)
	{
		// convert the image to 24-bit RGB
		CColorConverter_convertFORMATtoFORMAT(&scan_lines[y * row_stride], imageHeader.Width, row_pointer);

		// flip color
		CColorConverter::convert_R8G8B8toB8G8R8(row_pointer, imageHeader.Width, flipped_row_pointer);

		if (file->write(flipped_row_pointer, row_size) < (u32)row_size)
			break;
	}

	// final two bytes
	u16 word=0;
	file->write(&word, 2);

	// clean up our scratch area
	delete [] row_pointer;
	delete [] flipped_row_pointer;

	return y < 0;
}