1
// Copyright (C) 2002-2011 Nikolaus Gebhardt
2
// This file is part of the "Irrlicht Engine".
3
// For conditions of distribution and use, see copyright notice in irrlicht.h
5
#include "CImageWriterBMP.h"
7
#ifdef _IRR_COMPILE_WITH_BMP_WRITER_
9
#include "CImageLoaderBMP.h"
10
#include "IWriteFile.h"
11
#include "CColorConverter.h"
12
#include "irrString.h"
19
IImageWriter* createImageWriterBMP()
21
return new CImageWriterBMP;
24
CImageWriterBMP::CImageWriterBMP()
27
setDebugName("CImageWriterBMP");
31
bool CImageWriterBMP::isAWriteableFileExtension(const io::path& filename) const
33
return core::hasFileExtension ( filename, "bmp" );
36
bool CImageWriterBMP::writeImage(io::IWriteFile* file, IImage* image, u32 param) const
38
// we always write 24-bit color because nothing really reads 32-bit
40
SBMPHeader imageHeader;
41
imageHeader.Id = 0x4d42;
42
imageHeader.Reserved = 0;
43
imageHeader.BitmapDataOffset = sizeof(imageHeader);
44
imageHeader.BitmapHeaderSize = 0x28;
45
imageHeader.Width = image->getDimension().Width;
46
imageHeader.Height = image->getDimension().Height;
47
imageHeader.Planes = 1;
49
imageHeader.Compression = 0;
50
imageHeader.PixelPerMeterX = 0;
51
imageHeader.PixelPerMeterY = 0;
52
imageHeader.Colors = 0;
53
imageHeader.ImportantColors = 0;
55
// data size is rounded up to next larger 4 bytes boundary
56
imageHeader.BitmapDataSize = imageHeader.Width * imageHeader.BPP / 8;
57
imageHeader.BitmapDataSize = (imageHeader.BitmapDataSize + 3) & ~3;
58
imageHeader.BitmapDataSize *= imageHeader.Height;
60
// file size is data size plus offset to data
61
imageHeader.FileSize = imageHeader.BitmapDataOffset + imageHeader.BitmapDataSize;
63
// bitmaps are stored upside down and padded so we always do this
64
void (*CColorConverter_convertFORMATtoFORMAT)(const void*, s32, void*) = 0;
65
switch(image->getColorFormat())
68
CColorConverter_convertFORMATtoFORMAT
69
= CColorConverter::convert_R8G8B8toR8G8B8;
72
CColorConverter_convertFORMATtoFORMAT
73
= CColorConverter::convert_A8R8G8B8toB8G8R8;
76
CColorConverter_convertFORMATtoFORMAT
77
= CColorConverter::convert_A1R5G5B5toR8G8B8;
80
CColorConverter_convertFORMATtoFORMAT
81
= CColorConverter::convert_R5G6B5toR8G8B8;
85
// couldn't find a color converter
86
if (!CColorConverter_convertFORMATtoFORMAT)
89
// write the bitmap header
90
if (file->write(&imageHeader, sizeof(imageHeader)) != sizeof(imageHeader))
93
u8* scan_lines = (u8*)image->lock();
97
// size of one pixel in bytes
98
u32 pixel_size = image->getBytesPerPixel();
100
// length of one row of the source image in bytes
101
u32 row_stride = (pixel_size * imageHeader.Width);
103
// length of one row in bytes, rounded up to nearest 4-byte boundary
104
s32 row_size = ((3 * imageHeader.Width) + 3) & ~3;
106
// allocate and clear memory for our scan line
107
u8* row_pointer = new u8[row_size];
108
memset(row_pointer, 0, row_size);
110
// convert the image to 24-bit BGR and flip it over
112
for (y = imageHeader.Height - 1; 0 <= y; --y)
114
if (image->getColorFormat()==ECF_R8G8B8)
115
CColorConverter::convert24BitTo24Bit(&scan_lines[y * row_stride], row_pointer, imageHeader.Width, 1, 0, false, true);
117
// source, length [pixels], destination
118
CColorConverter_convertFORMATtoFORMAT(&scan_lines[y * row_stride], imageHeader.Width, row_pointer);
119
if (file->write(row_pointer, row_size) < row_size)
123
// clean up our scratch area
124
delete [] row_pointer;
126
// give back image handle