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