2 Copyright (C) 2001-2006, William Joseph.
5 This file is part of GtkRadiant.
7 GtkRadiant is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 GtkRadiant is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GtkRadiant; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
24 #include "ifilesystem.h"
26 typedef unsigned char byte;
29 #include "bytestreamutils.h"
32 typedef unsigned char PaletteEntry[4];
35 unsigned long fileSize;
36 unsigned long reserved0;
37 unsigned long bitmapDataOffset;
38 unsigned long bitmapHeaderSize;
41 unsigned short planes;
42 unsigned short bitsPerPixel;
43 unsigned long compression;
44 unsigned long bitmapDataSize;
48 unsigned long importantColors;
49 PaletteEntry palette[256];
53 PaletteEntry *m_palette;
55 ReadPixel8(PaletteEntry *palette) : m_palette(palette)
59 void operator()(PointerInputStream &inputStream, byte *&pixbuf) const
62 inputStream.read(&palIndex, 1);
63 *pixbuf++ = m_palette[palIndex][2];
64 *pixbuf++ = m_palette[palIndex][1];
65 *pixbuf++ = m_palette[palIndex][0];
72 void operator()(PointerInputStream &inputStream, byte *&pixbuf) const
74 unsigned short shortPixel;
75 inputStream.read(reinterpret_cast<byte *>( &shortPixel ), sizeof(unsigned short)); //!\todo Is this endian safe?
76 *pixbuf++ = static_cast<byte>( shortPixel & (31 << 10)) >> 7;
77 *pixbuf++ = static_cast<byte>( shortPixel & (31 << 5)) >> 2;
78 *pixbuf++ = static_cast<byte>( shortPixel & (31)) << 3;
85 void operator()(PointerInputStream &inputStream, byte *&pixbuf) const
88 inputStream.read(bgr, 3);
98 void operator()(PointerInputStream &inputStream, byte *&pixbuf) const
101 inputStream.read(bgra, 4);
109 template<typename ReadPixel>
110 void ReadBMP(PointerInputStream &inputStream, byte *bmpRGBA, int rows, int columns, ReadPixel readPixel)
112 for (int row = rows - 1; row >= 0; row--) {
113 byte *pixbuf = bmpRGBA + row * columns * 4;
115 for (int column = 0; column < columns; column++) {
116 readPixel(inputStream, pixbuf);
121 Image *LoadBMPBuff(PointerInputStream &inputStream, std::size_t length)
123 BMPHeader_t bmpHeader;
124 inputStream.read(reinterpret_cast<byte *>( bmpHeader.id ), 2);
125 bmpHeader.fileSize = istream_read_uint32_le(inputStream);
126 bmpHeader.reserved0 = istream_read_uint32_le(inputStream);
127 bmpHeader.bitmapDataOffset = istream_read_uint32_le(inputStream);
128 bmpHeader.bitmapHeaderSize = istream_read_uint32_le(inputStream);
129 bmpHeader.width = istream_read_uint32_le(inputStream);
130 bmpHeader.height = istream_read_uint32_le(inputStream);
131 bmpHeader.planes = istream_read_uint16_le(inputStream);
132 bmpHeader.bitsPerPixel = istream_read_uint16_le(inputStream);
133 bmpHeader.compression = istream_read_uint32_le(inputStream);
134 bmpHeader.bitmapDataSize = istream_read_uint32_le(inputStream);
135 bmpHeader.hRes = istream_read_uint32_le(inputStream);
136 bmpHeader.vRes = istream_read_uint32_le(inputStream);
137 bmpHeader.colors = istream_read_uint32_le(inputStream);
138 bmpHeader.importantColors = istream_read_uint32_le(inputStream);
140 if (bmpHeader.bitsPerPixel == 8) {
141 int paletteSize = bmpHeader.colors * 4;
142 inputStream.read(reinterpret_cast<byte *>( bmpHeader.palette ), paletteSize);
145 if (bmpHeader.id[0] != 'B' && bmpHeader.id[1] != 'M') {
146 globalErrorStream() << "LoadBMP: only Windows-style BMP files supported\n";
149 if (bmpHeader.fileSize != length) {
150 globalErrorStream() << "LoadBMP: header size does not match file size (" << Unsigned(bmpHeader.fileSize)
151 << " vs. " << Unsigned(length) << ")\n";
154 if (bmpHeader.compression != 0) {
155 globalErrorStream() << "LoadBMP: only uncompressed BMP files supported\n";
158 if (bmpHeader.bitsPerPixel < 8) {
159 globalErrorStream() << "LoadBMP: monochrome and 4-bit BMP files not supported\n";
163 int columns = bmpHeader.width;
164 int rows = bmpHeader.height;
169 RGBAImage *image = new RGBAImage(columns, rows);
171 switch (bmpHeader.bitsPerPixel) {
173 ReadBMP(inputStream, image->getRGBAPixels(), rows, columns, ReadPixel8(bmpHeader.palette));
176 ReadBMP(inputStream, image->getRGBAPixels(), rows, columns, ReadPixel16());
179 ReadBMP(inputStream, image->getRGBAPixels(), rows, columns, ReadPixel24());
182 ReadBMP(inputStream, image->getRGBAPixels(), rows, columns, ReadPixel32());
185 globalErrorStream() << "LoadBMP: illegal pixel_size '" << bmpHeader.bitsPerPixel << "'\n";
192 Image *LoadBMP(ArchiveFile &file)
194 ScopedArchiveBuffer buffer(file);
195 PointerInputStream inputStream(buffer.buffer);
196 return LoadBMPBuff(inputStream, buffer.length);