]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - plugins/image/bmp.cpp
transfer from internal tree r5311 branches/1.4-gpl
[xonotic/netradiant.git] / plugins / image / bmp.cpp
1 /*\r
2 Copyright (C) 1999-2007 id Software, Inc. and contributors.\r
3 For a list of contributors, see the accompanying CONTRIBUTORS file.\r
4 \r
5 This file is part of GtkRadiant.\r
6 \r
7 GtkRadiant is free software; you can redistribute it and/or modify\r
8 it under the terms of the GNU General Public License as published by\r
9 the Free Software Foundation; either version 2 of the License, or\r
10 (at your option) any later version.\r
11 \r
12 GtkRadiant is distributed in the hope that it will be useful,\r
13 but WITHOUT ANY WARRANTY; without even the implied warranty of\r
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
15 GNU General Public License for more details.\r
16 \r
17 You should have received a copy of the GNU General Public License\r
18 along with GtkRadiant; if not, write to the Free Software\r
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\r
20 */\r
21 \r
22 #include <stdio.h>\r
23 #include <string.h>\r
24 #include <glib.h>\r
25 #include "bmp.h"\r
26 \r
27 #include "image.h"\r
28 \r
29 static void BMPLineNone(FILE *f, char *sline, int pixbytes, int width)\r
30 {\r
31     int nbytes, i, k, j;\r
32 \r
33         switch (pixbytes)\r
34         {\r
35             case 1 :\r
36             nbytes = (width + 3) / 4;\r
37             nbytes *= 4;\r
38 \r
39             fread(sline, width, 1, f);\r
40             nbytes -= width;\r
41 \r
42             while (nbytes-- > 0) fgetc(f);\r
43                         return;\r
44 \r
45                 case 3 :\r
46                         nbytes = ((width * 3) + 3) / 4;\r
47                         nbytes *= 4;\r
48 \r
49                         fread(sline, width, 3, f);\r
50                         nbytes -= width * 3;\r
51 \r
52                         while (nbytes-- > 0) fgetc(f);\r
53 \r
54                         // reorder bgr to rgb\r
55                         for (i = 0, j = 0; i < width; i++, j += 3)\r
56                         {\r
57                                 k = sline[j];\r
58                                 sline[j] = sline[j+2];\r
59                                 sline[j+2] = k;\r
60                         }\r
61 \r
62                         return;\r
63         }\r
64 \r
65         Error("BMPLineNone failed.");\r
66 }\r
67 \r
68 \r
69 static void BMPLineRLE8(FILE *f, char *sline, int pixbytes, int width)\r
70 {\r
71     Error("RLE8 not yet supported.");\r
72 }\r
73 \r
74 \r
75 static void BMPLineRLE4(FILE *f, char *sline, int pixbytes, int width)\r
76 {\r
77     Error("RLE4 not yet supported.");\r
78 }\r
79 \r
80 \r
81 static void BMPLine(FILE *f, char *scanline, int pixbytes, int width, int rle)\r
82 {\r
83     switch (rle)\r
84     {\r
85             case xBI_NONE : BMPLineNone(f, scanline, pixbytes, width); return;\r
86             case xBI_RLE8 : BMPLineRLE8(f, scanline, pixbytes, width); return;\r
87             case xBI_RLE4 : BMPLineRLE4(f, scanline, pixbytes, width); return;\r
88     }\r
89 \r
90     Error("Unknown compression type.");\r
91 }\r
92 \r
93 \r
94 /*\r
95 static void PrintHeader(binfo_t *b)\r
96 {\r
97     printf("biSize         : %ld\n", b->biSize);\r
98     printf("biWidth        : %ld\n", b->biWidth);\r
99     printf("biHeight       : %ld\n", b->biHeight);\r
100     printf("biPlanes       : %d\n", b->biPlanes);\r
101     printf("biBitCount     : %d\n", b->biBitCount);\r
102     printf("biCompression  : %ld\n", b->biCompression);\r
103     printf("biSizeImage    : %ld\n", b->biSizeImage);\r
104     printf("biXPelsPerMeter: %ld\n", b->biXPelsPerMeter);\r
105     printf("biYPelsPerMeter: %ld\n", b->biYPelsPerMeter);\r
106     printf("biClrUsed      : %ld\n", b->biClrUsed);\r
107     printf("biClrImportant : %ld\n", b->biClrImportant);\r
108 }\r
109 */\r
110 \r
111 // FIXME: calls to Error(const char *, ... ) are dependant on qe3.cpp\r
112 void LoadBMP(char *filename, bitmap_t *bit)\r
113 {\r
114     FILE    *f;\r
115     bmphd_t  bhd;\r
116     binfo_t  info;\r
117     //    int      pxlsize = 1;\r
118     int      rowbytes, i, pixbytes;\r
119     char    *scanline;\r
120 \r
121     // open file\r
122     if ((f = fopen(filename, "rb")) == NULL)\r
123     {\r
124             Error("Unable to open file");// %s.", filename);\r
125     }\r
126 \r
127     // read in bitmap header\r
128     if (fread(&bhd, sizeof(bhd), 1, f) != 1)\r
129     {\r
130                 fclose(f);\r
131             Error("Unable to read in bitmap header.");\r
132     }\r
133 \r
134     // make sure we have a valid bitmap file\r
135     if (bhd.bfType != BMP_SIGNATURE_WORD)\r
136     {\r
137                 fclose(f);\r
138             Error("Invalid BMP file");//: %s", filename);\r
139     }\r
140 \r
141     // load in info header\r
142     if (fread(&info, sizeof(info), 1, f) != 1)\r
143     {\r
144                 fclose(f);\r
145             Error("Unable to read bitmap info header.");\r
146     }\r
147 \r
148     // make sure this is an info type of bitmap\r
149     if (info.biSize != sizeof(binfo_t))\r
150     {\r
151                 fclose(f);\r
152             Error("We only support the info bitmap type.");\r
153     }\r
154 \r
155     // PrintHeader(&info);\r
156 \r
157         bit->bpp      = info.biBitCount;\r
158         bit->width    = info.biWidth;\r
159     bit->height   = info.biHeight;\r
160     bit->data     = NULL;\r
161     bit->palette  = NULL;\r
162 \r
163     //currently we only read in 8 and 24 bit bmp files\r
164         if      (info.biBitCount == 8)  pixbytes = 1;\r
165         else if (info.biBitCount == 24) pixbytes = 3;\r
166         else\r
167     {\r
168       Error("Only 8BPP and 24BPP supported");\r
169                 //Error("BPP %d not supported.", info.biBitCount);\r
170     }\r
171 \r
172     // if this is an eight bit image load palette\r
173         if (pixbytes == 1)\r
174     {\r
175             drgb_t q;\r
176 \r
177             bit->palette = reinterpret_cast<rgb_t*>(g_malloc(sizeof(rgb_t) * 256));\r
178 \r
179             for (i = 0; i < 256; i++)\r
180             {\r
181                 if (fread(&q, sizeof(drgb_t), 1, f) != 1)\r
182                 {\r
183                                 fclose(f); g_free(bit->palette);\r
184                         Error("Unable to read palette.");\r
185                         }\r
186 \r
187                 bit->palette[i].r   = q.red;\r
188                 bit->palette[i].g   = q.green;\r
189                 bit->palette[i].b   = q.blue;\r
190                 }\r
191     }\r
192 \r
193     // position to start of bitmap\r
194     fseek(f, bhd.bfOffBits, SEEK_SET);\r
195 \r
196     // create scanline to read data into\r
197     rowbytes = ((info.biWidth * pixbytes) + 3) / 4;\r
198     rowbytes *= 4;\r
199 \r
200     scanline = reinterpret_cast<char*>(g_malloc(rowbytes));\r
201 \r
202     // alloc space for new bitmap\r
203     bit->data = reinterpret_cast<unsigned char*>(g_malloc(info.biWidth * pixbytes * info.biHeight));\r
204 \r
205     // read in image\r
206     for (i = 0; i < info.biHeight; i++)\r
207     {\r
208             BMPLine(f, scanline, pixbytes, info.biWidth, info.biCompression);\r
209 \r
210             // store line\r
211             memcpy(&bit->data[info.biWidth * pixbytes * (info.biHeight - i - 1)], scanline, info.biWidth * pixbytes);\r
212     }\r
213 \r
214     g_free(scanline);\r
215     fclose(f);\r
216 }\r
217 \r
218 \r
219 \r
220 static void BMPEncodeLine(FILE *f, unsigned char *data, int npxls, int pixbytes)\r
221 {\r
222     int nbytes, i, j, k;\r
223 \r
224         switch (pixbytes)\r
225         {\r
226             case 1 :\r
227             nbytes = (npxls + 3) / 4;\r
228             nbytes *= 4;\r
229 \r
230             fwrite(data, npxls, 1, f);\r
231             nbytes -= npxls;\r
232 \r
233             while (nbytes-- > 0) fputc(0, f);\r
234                         return;\r
235 \r
236         case 3 :\r
237                         // reorder rgb to bgr\r
238                         for (i = 0, j = 0; i < npxls; i++, j+= 3)\r
239                         {\r
240                                 k = data[j];\r
241                                 data[j] = data[j + 2];\r
242                                 data[j + 2] = k;\r
243                         }\r
244 \r
245                         nbytes = ((npxls * 3) + 3) / 4;\r
246                         nbytes *= 4;\r
247 \r
248                         fwrite(data, npxls, 3, f);\r
249                         nbytes -= npxls * 3;\r
250 \r
251                         while (nbytes-- > 0) fputc(0, f);\r
252                         return;\r
253         }\r
254 \r
255         Error("BMPEncodeLine Failed.");\r
256 }\r
257 \r
258 \r
259 \r
260 void WriteBMP(char *filename, bitmap_t *bit)\r
261 {\r
262     FILE    *f;\r
263     bmphd_t  header;\r
264     binfo_t  info;\r
265     drgb_t   q;        // palette that gets written\r
266     long     bmofs;\r
267     int      w, h, i;\r
268         int      pixbytes;\r
269 \r
270     if      (bit->bpp == 8)  pixbytes = 1;\r
271         else if (bit->bpp == 24) pixbytes = 3;\r
272 \r
273         else\r
274     {\r
275     Error("Only 8BPP and 24BPP supported");\r
276                 //Error("BPP %d not supported.", bit->bpp);\r
277     }\r
278 \r
279 \r
280     if ((f = fopen(filename, "wb")) == NULL)\r
281     {\r
282             Error("Unable to open file");//%s.", filename);\r
283     }\r
284 \r
285     // write out an empty header as a place holder\r
286     if (fwrite(&header, sizeof(header), 1, f) != 1)\r
287     {\r
288             Error("Unable to fwrite.");\r
289     }\r
290 \r
291     // init and write info header\r
292     info.biSize          = sizeof(binfo_t);\r
293     info.biWidth         = bit->width;\r
294     info.biHeight        = bit->height;\r
295     info.biPlanes        = 1;\r
296     info.biBitCount      = bit->bpp;\r
297     info.biCompression   = xBI_NONE;\r
298     info.biSizeImage     = bit->width * bit->height;\r
299     info.biXPelsPerMeter = 0;\r
300     info.biYPelsPerMeter = 0;\r
301     info.biClrUsed       = 256;\r
302     info.biClrImportant  = 256;\r
303 \r
304     if (fwrite(&info, sizeof(binfo_t), 1, f) != 1)\r
305     {\r
306             Error("fwrite failed.");\r
307     }\r
308 \r
309     // write out palette if we need to\r
310         if (bit->bpp == 8)\r
311         {\r
312         for (i = 0; i < 256; i++)\r
313         {\r
314                 q.red   = bit->palette[i].r;\r
315                 q.green = bit->palette[i].g;\r
316                 q.blue  = bit->palette[i].b;\r
317 \r
318                 fwrite(&q, sizeof(q), 1, f);\r
319                 }\r
320     }\r
321 \r
322     // save offset to start of bitmap\r
323     bmofs = ftell(f);\r
324 \r
325     // output bitmap\r
326     w = bit->width;\r
327     h = bit->height;\r
328 \r
329     for (i = h - 1; i >= 0; i--)\r
330     {\r
331             BMPEncodeLine(f, &bit->data[w * pixbytes * i], w, pixbytes);\r
332     }\r
333 \r
334     // update and rewrite file header\r
335     header.bfType    = BMP_SIGNATURE_WORD;\r
336     header.bfSize    = ftell(f);\r
337     header.bfOffBits = bmofs;\r
338 \r
339     fseek(f, 0L, SEEK_SET);\r
340     fwrite(&header, sizeof(header), 1, f);\r
341 \r
342     fclose(f);\r
343 }\r
344 \r
345 \r
346 void NewBMP(int width, int height, int bpp, bitmap_t *bit)\r
347 {\r
348         int pixbytes;\r
349 \r
350         if      (bpp == 8)  pixbytes = 1;\r
351         else if (bpp == 24) pixbytes = 3;\r
352 \r
353         else\r
354         {\r
355                 Error("NewBMP: 8 or 24 bit only.");\r
356         }\r
357 \r
358         bit->bpp    = bpp;\r
359         bit->width  = width;\r
360         bit->height = height;\r
361 \r
362         bit->data = reinterpret_cast<unsigned char*>(g_malloc(width * height * pixbytes));\r
363 \r
364         if (bit->data == NULL)\r
365         {\r
366                 Error("NewBMP: g_malloc failed.");\r
367         }\r
368 \r
369         // see if we need to create a palette\r
370         if (pixbytes == 1)\r
371         {\r
372                 bit->palette = (rgb_t *) g_malloc(768);\r
373 \r
374                 if (bit->palette == NULL)\r
375                 {\r
376                         Error("NewBMP: unable to g_malloc palette.");\r
377                 }\r
378         }\r
379         else\r
380         {\r
381                 bit->palette = NULL;\r
382         }\r
383 }\r
384 \r
385 \r
386 \r
387 void FreeBMP(bitmap_t *bitmap)\r
388 {\r
389     if (bitmap->palette)\r
390     {\r
391             g_free(bitmap->palette);\r
392             bitmap->palette = NULL;\r
393     }\r
394 \r
395     if (bitmap->data)\r
396     {\r
397             g_free(bitmap->data);\r
398             bitmap->data = NULL;\r
399     }\r
400 }\r
401 \r
402 \r