]> git.saurik.com Git - wxWidgets.git/blob - src/common/image.cpp
wxIMage accessors
[wxWidgets.git] / src / common / image.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: image.cpp
3 // Purpose: wxImage
4 // Author: Robert Roebling
5 // RCS-ID: $Id$
6 // Copyright: (c) Robert Roebling
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
9
10 #ifdef __GNUG__
11 #pragma implementation "image.h"
12 #endif
13
14 // For compilers that support precompilation, includes "wx.h".
15 #include "wx/wxprec.h"
16
17 #ifdef __BORLANDC__
18 #pragma hdrstop
19 #endif
20
21 #include "wx/image.h"
22 #include "wx/debug.h"
23 #include "wx/log.h"
24 #include "../png/png.h"
25 #include "wx/filefn.h"
26
27 //-----------------------------------------------------------------------------
28 // wxImage
29 //-----------------------------------------------------------------------------
30
31 class wxImageRefData: public wxObjectRefData
32 {
33
34 public:
35 wxImageRefData(void);
36 ~wxImageRefData(void);
37
38 int m_width;
39 int m_height;
40 unsigned char *m_data;
41 bool m_hasMask;
42 unsigned char m_maskRed,m_maskGreen,m_maskBlue;
43 bool m_ok;
44 };
45
46 wxImageRefData::wxImageRefData(void)
47 {
48 m_width = 0;
49 m_height = 0;
50 m_data = (unsigned char*) NULL;
51 m_ok = FALSE;
52 m_maskRed = 0;
53 m_maskGreen = 0;
54 m_maskBlue = 0;
55 m_hasMask = FALSE;
56 }
57
58 wxImageRefData::~wxImageRefData(void)
59 {
60 if (m_data) free( m_data );
61 }
62
63 wxList wxImage::sm_handlers;
64
65 //-----------------------------------------------------------------------------
66
67 #define M_IMGDATA ((wxImageRefData *)m_refData)
68
69 #if !USE_SHARED_LIBRARIES
70 IMPLEMENT_DYNAMIC_CLASS(wxImage, wxObject)
71 #endif
72
73 wxImage::wxImage()
74 {
75 }
76
77 wxImage::wxImage( int width, int height )
78 {
79 Create( width, height );
80 }
81
82 wxImage::wxImage( const wxString& name, long type )
83 {
84 LoadFile( name, type );
85 }
86
87 wxImage::wxImage( const wxImage& image )
88 {
89 Ref(image);
90 }
91
92 wxImage::wxImage( const wxImage* image )
93 {
94 if (image) Ref(*image);
95 }
96
97 void wxImage::Create( int width, int height )
98 {
99 m_refData = new wxImageRefData();
100
101 M_IMGDATA->m_data = (unsigned char *) malloc( width*height*3 );
102 if (M_IMGDATA->m_data)
103 {
104 for (int l = 0; l < width*height*3; l++) M_IMGDATA->m_data[l] = 0;
105
106 M_IMGDATA->m_width = width;
107 M_IMGDATA->m_height = height;
108 M_IMGDATA->m_ok = TRUE;
109 }
110 else
111 {
112 UnRef();
113 }
114 }
115
116 void wxImage::Destroy()
117 {
118 UnRef();
119 }
120
121 wxImage wxImage::Scale( int width, int height )
122 {
123 wxImage image;
124
125 wxCHECK_MSG( Ok(), image, "invlaid image" );
126
127 wxCHECK_MSG( (width > 0) && (height > 0), image, "invalid image size" );
128
129 image.Create( width, height );
130
131 char unsigned *data = image.GetData();
132
133 wxCHECK_MSG( data, image, "unable to create image" );
134
135 if (M_IMGDATA->m_hasMask)
136 image.SetMaskColour( M_IMGDATA->m_maskRed, M_IMGDATA->m_maskGreen, M_IMGDATA->m_maskBlue );
137
138 double xscale = (double)width / (double)M_IMGDATA->m_width;
139 double yscale = (double)height / (double)M_IMGDATA->m_height;
140
141 for (int j = 0; j < height; j++)
142 {
143 for (int i = 0; i < width; i++)
144 {
145 int new_pos = 3*(j*width + i);
146 int old_pos = 3*((long)(j/yscale)*M_IMGDATA->m_width + (long)(i/xscale));
147 data[ new_pos ] = M_IMGDATA->m_data[ old_pos ];
148 data[ new_pos+1 ] = M_IMGDATA->m_data[ old_pos+1 ];
149 data[ new_pos+2 ] = M_IMGDATA->m_data[ old_pos+2 ];
150 }
151 }
152
153 return image;
154 }
155
156 void wxImage::SetRGB( int x, int y, unsigned char r, unsigned char g, unsigned char b )
157 {
158 wxCHECK_RET( Ok(), "invalid image" );
159
160 int w = M_IMGDATA->m_width;
161 int h = M_IMGDATA->m_height;
162
163 wxCHECK_RET( (x>=0) && (y>=0) && (x<w) && (y<h), "invalid image index" );
164
165 long pos = (y * w + x) * 3;
166
167 M_IMGDATA->m_data[ pos ] = r;
168 M_IMGDATA->m_data[ pos+1 ] = g;
169 M_IMGDATA->m_data[ pos+2 ] = b;
170 }
171
172 unsigned char wxImage::GetRed( int x, int y )
173 {
174 wxCHECK_MSG( Ok(), 0, "invalid image" );
175
176 int w = M_IMGDATA->m_width;
177 int h = M_IMGDATA->m_height;
178
179 wxCHECK_MSG( (x>=0) && (y>=0) && (x<w) && (y<h), 0, "invalid image index" );
180
181 long pos = (y * w + x) * 3;
182
183 return M_IMGDATA->m_data[pos];
184 }
185
186 unsigned char wxImage::GetGreen( int x, int y )
187 {
188 wxCHECK_MSG( Ok(), 0, "invalid image" );
189
190 int w = M_IMGDATA->m_width;
191 int h = M_IMGDATA->m_height;
192
193 wxCHECK_MSG( (x>=0) && (y>=0) && (x<w) && (y<h), 0, "invalid image index" );
194
195 long pos = (y * w + x) * 3;
196
197 return M_IMGDATA->m_data[pos+1];
198 }
199
200 unsigned char wxImage::GetBlue( int x, int y )
201 {
202 wxCHECK_MSG( Ok(), 0, "invalid image" );
203
204 int w = M_IMGDATA->m_width;
205 int h = M_IMGDATA->m_height;
206
207 wxCHECK_MSG( (x>=0) && (y>=0) && (x<w) && (y<h), 0, "invalid image index" );
208
209 long pos = (y * w + x) * 3;
210
211 return M_IMGDATA->m_data[pos+2];
212 }
213
214 bool wxImage::Ok() const
215 {
216 return (M_IMGDATA && M_IMGDATA->m_ok);
217 }
218
219 char unsigned *wxImage::GetData() const
220 {
221 wxCHECK_MSG( Ok(), (char unsigned *)NULL, "invalid image" );
222
223 return M_IMGDATA->m_data;
224 }
225
226 void wxImage::SetData( char unsigned *WXUNUSED(data) )
227 {
228 wxCHECK_RET( Ok(), "invalid image" );
229 }
230
231 void wxImage::SetMaskColour( unsigned char r, unsigned char g, unsigned char b )
232 {
233 wxCHECK_RET( Ok(), "invalid image" );
234
235 M_IMGDATA->m_maskRed = r;
236 M_IMGDATA->m_maskGreen = g;
237 M_IMGDATA->m_maskBlue = b;
238 M_IMGDATA->m_hasMask = TRUE;
239 }
240
241 unsigned char wxImage::GetMaskRed() const
242 {
243 wxCHECK_MSG( Ok(), 0, "invalid image" );
244
245 return M_IMGDATA->m_maskRed;
246 }
247
248 unsigned char wxImage::GetMaskGreen() const
249 {
250 wxCHECK_MSG( Ok(), 0, "invalid image" );
251
252 return M_IMGDATA->m_maskGreen;
253 }
254
255 unsigned char wxImage::GetMaskBlue() const
256 {
257 wxCHECK_MSG( Ok(), 0, "invalid image" );
258
259 return M_IMGDATA->m_maskBlue;
260 }
261
262 void wxImage::SetMask( bool mask )
263 {
264 wxCHECK_RET( Ok(), "invalid image" );
265
266 M_IMGDATA->m_hasMask = mask;
267 }
268
269 bool wxImage::HasMask() const
270 {
271 wxCHECK_MSG( Ok(), FALSE, "invalid image" );
272
273 return M_IMGDATA->m_hasMask;
274 }
275
276 int wxImage::GetWidth() const
277 {
278 wxCHECK_MSG( Ok(), 0, "invalid image" );
279
280 return M_IMGDATA->m_width;
281 }
282
283 int wxImage::GetHeight() const
284 {
285 wxCHECK_MSG( Ok(), 0, "invalid image" );
286
287 return M_IMGDATA->m_height;
288 }
289
290 bool wxImage::LoadFile( const wxString& filename, long type )
291 {
292 UnRef();
293
294 if (!wxFileExists(filename))
295 {
296 wxLogWarning( "Image file does not exist." );
297
298 return FALSE;
299 }
300
301 m_refData = new wxImageRefData;
302
303 wxImageHandler *handler = FindHandler(type);
304
305 if (handler == NULL)
306 {
307 wxLogWarning( "No image handler for type %d defined.", type );
308
309 return FALSE;
310 }
311
312 return handler->LoadFile( this, filename );
313 }
314
315 bool wxImage::SaveFile( const wxString& filename, int type )
316 {
317 wxCHECK_MSG( Ok(), FALSE, "invalid image" );
318
319 wxImageHandler *handler = FindHandler(type);
320
321 if (handler == NULL)
322 {
323 wxLogWarning( "No image handler for type %d defined.", type );
324
325 return FALSE;
326 }
327
328 return handler->SaveFile( this, filename );
329 }
330
331 void wxImage::AddHandler( wxImageHandler *handler )
332 {
333 sm_handlers.Append( handler );
334 }
335
336 void wxImage::InsertHandler( wxImageHandler *handler )
337 {
338 sm_handlers.Insert( handler );
339 }
340
341 bool wxImage::RemoveHandler( const wxString& name )
342 {
343 wxImageHandler *handler = FindHandler(name);
344 if (handler)
345 {
346 sm_handlers.DeleteObject(handler);
347 return TRUE;
348 }
349 else
350 return FALSE;
351 }
352
353 wxImageHandler *wxImage::FindHandler( const wxString& name )
354 {
355 wxNode *node = sm_handlers.First();
356 while (node)
357 {
358 wxImageHandler *handler = (wxImageHandler*)node->Data();
359 if (handler->GetName() == name) return handler;
360 node = node->Next();
361 }
362 return (wxImageHandler *)NULL;
363 }
364
365 wxImageHandler *wxImage::FindHandler( const wxString& extension, long bitmapType )
366 {
367 wxNode *node = sm_handlers.First();
368 while (node)
369 {
370 wxImageHandler *handler = (wxImageHandler*)node->Data();
371 if ( handler->GetExtension() == extension &&
372 (bitmapType == -1 || handler->GetType() == bitmapType) )
373 return handler;
374 node = node->Next();
375 }
376 return (wxImageHandler*)NULL;
377 }
378
379 wxImageHandler *wxImage::FindHandler( long bitmapType )
380 {
381 wxNode *node = sm_handlers.First();
382 while (node)
383 {
384 wxImageHandler *handler = (wxImageHandler *)node->Data();
385 if (handler->GetType() == bitmapType) return handler;
386 node = node->Next();
387 }
388 return NULL;
389 }
390
391 void wxImage::InitStandardHandlers()
392 {
393 AddHandler( new wxBMPHandler );
394 AddHandler( new wxPNGHandler );
395 }
396
397 void wxImage::CleanUpHandlers()
398 {
399 wxNode *node = sm_handlers.First();
400 while (node)
401 {
402 wxImageHandler *handler = (wxImageHandler *)node->Data();
403 wxNode *next = node->Next();
404 delete handler;
405 delete node;
406 node = next;
407 }
408 }
409
410 //-----------------------------------------------------------------------------
411 // wxImageHandler
412 //-----------------------------------------------------------------------------
413
414 #if !USE_SHARED_LIBRARIES
415 IMPLEMENT_DYNAMIC_CLASS(wxImageHandler,wxObject)
416 #endif
417
418 bool wxImageHandler::LoadFile( wxImage *WXUNUSED(image), const wxString& WXUNUSED(name) )
419 {
420 return FALSE;
421 }
422
423 bool wxImageHandler::SaveFile( wxImage *WXUNUSED(image), const wxString& WXUNUSED(name) )
424 {
425 return FALSE;
426 }
427
428 //-----------------------------------------------------------------------------
429 // wxPNGHandler
430 //-----------------------------------------------------------------------------
431
432 #if !USE_SHARED_LIBRARIES
433 IMPLEMENT_DYNAMIC_CLASS(wxPNGHandler,wxImageHandler)
434 #endif
435
436 bool wxPNGHandler::LoadFile( wxImage *image, const wxString& name )
437 {
438 FILE *f;
439 png_structp png_ptr;
440 png_infop info_ptr;
441 unsigned char *ptr, **lines, *ptr2;
442 int transp,bit_depth,color_type,interlace_type;
443 png_uint_32 width, height;
444 unsigned int i;
445
446 image->Destroy();
447
448 transp = 0;
449 png_ptr = png_create_read_struct( PNG_LIBPNG_VER_STRING, NULL, NULL, NULL );
450 if (!png_ptr) return FALSE;
451
452 info_ptr = png_create_info_struct( png_ptr );
453 if (!info_ptr)
454 {
455 png_destroy_read_struct( &png_ptr, NULL, NULL );
456 return FALSE;
457 }
458
459 if (setjmp(png_ptr->jmpbuf))
460 {
461 png_destroy_read_struct( &png_ptr, &info_ptr, NULL );
462 return FALSE;
463 }
464
465 if (info_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
466 {
467 png_destroy_read_struct( &png_ptr, &info_ptr, NULL );
468 return FALSE;
469 }
470
471 f = fopen( name, "rb" );
472 png_init_io( png_ptr, f );
473
474 png_read_info( png_ptr, info_ptr );
475 png_get_IHDR( png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, NULL, NULL );
476
477 if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_expand( png_ptr );
478
479 png_set_strip_16( png_ptr );
480 png_set_packing( png_ptr );
481 if (png_get_valid( png_ptr, info_ptr, PNG_INFO_tRNS)) png_set_expand( png_ptr );
482 png_set_filler( png_ptr, 0xff, PNG_FILLER_AFTER );
483
484 image->Create( width, height );
485
486 if (!image->Ok())
487 {
488 png_destroy_read_struct( &png_ptr, &info_ptr, NULL );
489 return FALSE;
490 }
491
492 lines = (unsigned char **)malloc( height * sizeof(unsigned char *) );
493 if (lines == NULL)
494 {
495 image->Destroy();
496 png_destroy_read_struct( &png_ptr, &info_ptr, NULL );
497 return FALSE;
498 }
499
500 for (i = 0; i < height; i++)
501 {
502 if ((lines[i] = (unsigned char *)malloc(width * (sizeof(unsigned char) * 4))) == NULL)
503 {
504 image->Destroy();
505 for (unsigned int n = 0; n < i; n++) free( lines[n] );
506 free( lines );
507 png_destroy_read_struct( &png_ptr, &info_ptr, NULL );
508 return FALSE;
509 }
510 }
511
512 png_read_image( png_ptr, lines );
513 png_destroy_read_struct( &png_ptr, &info_ptr, NULL );
514 ptr = image->GetData();
515 if ((color_type == PNG_COLOR_TYPE_GRAY) ||
516 (color_type == PNG_COLOR_TYPE_GRAY_ALPHA))
517 {
518 for (unsigned int y = 0; y < height; y++)
519 {
520 ptr2 = lines[y];
521 for (unsigned int x = 0; x < width; x++)
522 {
523 unsigned char r = *ptr2++;
524 unsigned char a = *ptr2++;
525 if (a < 128)
526 {
527 *ptr++ = 255;
528 *ptr++ = 0;
529 *ptr++ = 255;
530 transp = 1;
531 }
532 else
533 {
534 *ptr++ = r;
535 *ptr++ = r;
536 *ptr++ = r;
537 }
538 }
539 }
540 }
541 else
542 {
543 for (unsigned int y = 0; y < height; y++)
544 {
545 ptr2 = lines[y];
546 for (unsigned int x = 0; x < width; x++)
547 {
548 unsigned char r = *ptr2++;
549 unsigned char g = *ptr2++;
550 unsigned char b = *ptr2++;
551 unsigned char a = *ptr2++;
552 if (a < 128)
553 {
554 *ptr++ = 255;
555 *ptr++ = 0;
556 *ptr++ = 255;
557 transp = 1;
558 }
559 else
560 {
561 if ((r == 255) && (g == 0) && (b == 255)) r = 254;
562 *ptr++ = r;
563 *ptr++ = g;
564 *ptr++ = b;
565 }
566 }
567 }
568 }
569 for (i = 0; i < height; i++) free( lines[i] );
570 free( lines );
571 if (transp)
572 image->SetMaskColour( 255, 0, 255 );
573 else
574 image->SetMask( FALSE );
575
576 return TRUE;
577 }
578
579
580 bool wxPNGHandler::SaveFile( wxImage *image, const wxString& name )
581 {
582 FILE *f = fopen( name, "wb" );
583 if (f)
584 {
585 png_structp png_ptr = png_create_write_struct( PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
586 if (!png_ptr)
587 {
588 fclose( f );
589 return FALSE;
590 }
591
592 png_infop info_ptr = png_create_info_struct(png_ptr);
593 if (info_ptr == NULL)
594 {
595 fclose(f);
596 png_destroy_write_struct( &png_ptr, (png_infopp)NULL );
597 return FALSE;
598 }
599
600 if (setjmp(png_ptr->jmpbuf))
601 {
602 fclose( f );
603 png_destroy_write_struct( &png_ptr, (png_infopp)NULL );
604 return FALSE;
605 }
606
607 png_init_io( png_ptr, f );
608 png_set_IHDR( png_ptr, info_ptr, image->GetWidth(), image->GetHeight(), 8,
609 PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE,
610 PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
611
612 png_color_8 sig_bit;
613 sig_bit.red = 8;
614 sig_bit.green = 8;
615 sig_bit.blue = 8;
616 sig_bit.alpha = 8;
617 png_set_sBIT( png_ptr, info_ptr, &sig_bit );
618 png_write_info( png_ptr, info_ptr );
619 png_set_shift( png_ptr, &sig_bit );
620 png_set_packing( png_ptr );
621
622 unsigned char *data = (unsigned char *)malloc( image->GetWidth()*4 );
623 if (!data)
624 {
625 fclose( f );
626 png_destroy_write_struct( &png_ptr, (png_infopp)NULL );
627 return FALSE;
628 }
629
630 for (int y = 0; y < image->GetHeight(); y++)
631 {
632 unsigned char *ptr = image->GetData() + (y * image->GetWidth() * 3);
633 for (int x = 0; x < image->GetWidth(); x++)
634 {
635 data[(x << 2) + 0] = *ptr++;
636 data[(x << 2) + 1] = *ptr++;
637 data[(x << 2) + 2] = *ptr++;
638 if ((data[(x << 2) + 0] == image->GetMaskRed()) &&
639 (data[(x << 2) + 1] == image->GetMaskGreen()) &&
640 (data[(x << 2) + 2] == image->GetMaskBlue()))
641 data[(x << 2) + 3] = 0;
642 else
643 data[(x << 2) + 3] = 255;
644 }
645 png_bytep row_ptr = data;
646 png_write_rows( png_ptr, &row_ptr, 1 );
647 }
648 free(data);
649 png_write_end( png_ptr, info_ptr );
650 png_destroy_write_struct( &png_ptr, (png_infopp)NULL );
651
652 fclose(f);
653 }
654 return TRUE;
655 }
656
657 //-----------------------------------------------------------------------------
658 // wxBMPHandler
659 //-----------------------------------------------------------------------------
660
661 #if !USE_SHARED_LIBRARIES
662 IMPLEMENT_DYNAMIC_CLASS(wxBMPHandler,wxImageHandler)
663 #endif
664
665 bool wxBMPHandler::LoadFile( wxImage *image, const wxString& name )
666 {
667 FILE *file;
668 unsigned char *data, *ptr;
669 int done, i, bpp, planes, comp, ncolors, line, column,
670 linesize, linepos, rshift = 0, gshift = 0, bshift = 0;
671 unsigned char byte;
672 short int word;
673 long int dbuf[4], dword, rmask = 0, gmask = 0, bmask = 0, offset,
674 size;
675 signed char bbuf[4];
676 struct _cmap
677 {
678 unsigned char r, g, b;
679 }
680 *cmap = NULL;
681 #ifndef BI_RGB
682 #define BI_RGB 0
683 #define BI_RLE8 1
684 #define BI_RLE4 2
685 #define BI_BITFIELDS 3
686 #endif
687
688 image->Destroy();
689
690 file = fopen(name, "r");
691 if (!file)
692 return NULL;
693
694 done = 0;
695 /*
696 * Reading the bmp header
697 */
698
699 fread(&bbuf, 1, 2, file);
700
701 fread(dbuf, 4, 4, file);
702
703 size = dbuf[0];
704 offset = dbuf[2];
705
706 fread(dbuf, 4, 2, file);
707 int width = (int)dbuf[0];
708 int height = (int)dbuf[1];
709 if (width > 32767)
710 {
711 fprintf(stderr, "IMLIB ERROR: Image width > 32767 pixels for file\n");
712 fclose(file);
713 return FALSE;
714 }
715 if (height > 32767)
716 {
717 fprintf(stderr, "IMLIB ERROR: Image height > 32767 pixels for file\n");
718 fclose(file);
719 return FALSE;
720 }
721 fread(&word, 2, 1, file);
722 planes = (int)word;
723 fread(&word, 2, 1, file);
724 bpp = (int)word;
725 if (bpp != 1 && bpp != 4 && bpp != 8 && bpp && 16 && bpp != 24 && bpp != 32)
726 {
727 fprintf(stderr, "IMLIB ERROR: unknown bitdepth in file\n");
728 fclose(file);
729 return FALSE;
730 }
731 fread(dbuf, 4, 4, file);
732 comp = (int)dbuf[0];
733 if (comp != BI_RGB && comp != BI_RLE4 && comp != BI_RLE8 && comp != BI_BITFIELDS)
734 {
735 fprintf(stderr, "IMLIB ERROR: unknown encoding in Windows BMP file\n");
736 fclose(file);
737 return FALSE;
738 }
739 fread(dbuf, 4, 2, file);
740 ncolors = (int)dbuf[0];
741 if (ncolors == 0)
742 ncolors = 1 << bpp;
743 /* some more sanity checks */
744 if (((comp == BI_RLE4) && (bpp != 4)) || ((comp == BI_RLE8) && (bpp != 8)) || ((comp == BI_BITFIELDS) && (bpp != 16 && bpp != 32)))
745 {
746 fprintf(stderr, "IMLIB ERROR: encoding of BMP doesn't match bitdepth\n");
747 fclose(file);
748 return FALSE;
749 }
750 if (bpp < 16)
751 {
752 cmap = (struct _cmap *)malloc(sizeof(struct _cmap) * ncolors);
753
754 if (!cmap)
755 {
756 fprintf(stderr, "IMLIB ERROR: Cannot allocate RAM for color map in BMP file\n");
757 fclose(file);
758 return FALSE;
759 }
760 }
761 else
762 cmap = NULL;
763
764 image->Create( width, height );
765 ptr = image->GetData();
766 if (!ptr)
767 {
768 fprintf(stderr, "IMLIB ERROR: Cannot allocate RAM for RGB data in file\n");
769 fclose(file);
770 if (cmap)
771 free(cmap);
772 return FALSE;
773 }
774
775 /*
776 * Reading the palette, if it exists.
777 */
778 if (bpp < 16 && ncolors != 0)
779 {
780 for (i = 0; i < ncolors; i++)
781 {
782 fread(bbuf, 1, 4, file);
783 cmap[i].b = bbuf[0];
784 cmap[i].g = bbuf[1];
785 cmap[i].r = bbuf[2];
786 }
787 }
788 else if (bpp == 16 || bpp == 32)
789 {
790 if (comp == BI_BITFIELDS)
791 {
792 int bit = 0;
793
794 fread(dbuf, 4, 3, file);
795 bmask = dbuf[0];
796 gmask = dbuf[1];
797 rmask = dbuf[2];
798 /* find shift amount.. ugly, but i can't think of a better way */
799 for (bit = 0; bit < bpp; bit++)
800 {
801 if (bmask & (1 << bit))
802 bshift = bit;
803 if (gmask & (1 << bit))
804 gshift = bit;
805 if (rmask & (1 << bit))
806 rshift = bit;
807 }
808 }
809 else if (bpp == 16)
810 {
811 rmask = 0x7C00;
812 gmask = 0x03E0;
813 bmask = 0x001F;
814 rshift = 10;
815 gshift = 5;
816 bshift = 0;
817 }
818 else if (bpp == 32)
819 {
820 rmask = 0x00FF0000;
821 gmask = 0x0000FF00;
822 bmask = 0x000000FF;
823 rshift = 16;
824 gshift = 8;
825 bshift = 0;
826 }
827 }
828
829 /*
830 * REading the image data
831 */
832 fseek(file, offset, SEEK_SET);
833 data = ptr;
834
835 /* set the whole image to the background color */
836 if (bpp < 16 && (comp == BI_RLE4 || comp == BI_RLE8))
837 {
838 for (i = 0; i < width * height; i++)
839 {
840 *ptr++ = cmap[0].r;
841 *ptr++ = cmap[0].g;
842 *ptr++ = cmap[0].b;
843 }
844 ptr = data;
845 }
846 line = 0;
847 column = 0;
848 #define poffset (line * width * 3 + column * 3)
849
850 /*
851 * BMPs are stored upside down... hmmmmmmmmmm....
852 */
853
854 linesize = ((width * bpp + 31) / 32) * 4;
855 for (line = (height - 1); line >= 0; line--)
856 {
857 linepos = 0;
858 for (column = 0; column < width;)
859 {
860 if (bpp < 16)
861 {
862 int index;
863
864 linepos++;
865 byte = getc(file);
866 if (bpp == 1)
867 {
868 int bit = 0;
869
870 for (bit = 0; bit < 8; bit++)
871 {
872 index = ((byte & (0x80 >> bit)) ? 1 : 0);
873 ptr[poffset] = cmap[index].r;
874 ptr[poffset + 1] = cmap[index].g;
875 ptr[poffset + 2] = cmap[index].b;
876 column++;
877 }
878 }
879 else if (bpp == 4)
880 {
881 if (comp == BI_RLE4)
882 {
883 fprintf(stderr, "can't deal with 4bit encoded yet.\n");
884 image->Destroy();
885 free(cmap);
886 return FALSE;
887 }
888 else
889 {
890 int nibble = 0;
891
892 for (nibble = 0; nibble < 2; nibble++)
893 {
894 index = ((byte & (0xF0 >> nibble * 4)) >> (!nibble * 4));
895 if (index >= 16)
896 index = 15;
897 ptr[poffset] = cmap[index].r;
898 ptr[poffset + 1] = cmap[index].g;
899 ptr[poffset + 2] = cmap[index].b;
900 column++;
901 }
902 }
903 }
904 else if (bpp == 8)
905 {
906 if (comp == BI_RLE8)
907 {
908 unsigned char first;
909
910 first = byte;
911 byte = getc(file);
912 if (first == 0)
913 {
914 if (byte == 0)
915 {
916 /* column = width; */
917 }
918 else if (byte == 1)
919 {
920 column = width;
921 line = -1;
922 }
923 else if (byte == 2)
924 {
925 byte = getc(file);
926 column += byte;
927 linepos = column * bpp / 8;
928 byte = getc(file);
929 line += byte;
930 }
931 else
932 {
933 int absolute = byte;
934
935 for (i = 0; i < absolute; i++)
936 {
937 linepos++;
938 byte = getc(file);
939 ptr[poffset] = cmap[byte].r;
940 ptr[poffset + 1] = cmap[byte].g;
941 ptr[poffset + 2] = cmap[byte].b;
942 column++;
943 }
944 if (absolute & 0x01)
945 byte = getc(file);
946 }
947 }
948 else
949 {
950 for (i = 0; i < first; i++)
951 {
952 ptr[poffset] = cmap[byte].r;
953 ptr[poffset + 1] = cmap[byte].g;
954 ptr[poffset + 2] = cmap[byte].b;
955 column++;
956 linepos++;
957 }
958 }
959 }
960 else
961 {
962 ptr[poffset] = cmap[byte].r;
963 ptr[poffset + 1] = cmap[byte].g;
964 ptr[poffset + 2] = cmap[byte].b;
965 column++;
966 linepos += size;
967 }
968 }
969 }
970 else if (bpp == 24)
971 {
972 linepos += fread(&bbuf, 1, 3, file);
973 ptr[poffset] = (unsigned char)bbuf[2];
974 ptr[poffset + 1] = (unsigned char)bbuf[1];
975 ptr[poffset + 2] = (unsigned char)bbuf[0];
976 column++;
977 }
978 else if (bpp == 16)
979 {
980 unsigned char temp;
981
982 linepos += fread(&word, 2, 1, file);
983 temp = (word & rmask) >> rshift;
984 ptr[poffset] = temp;
985 temp = (word & gmask) >> gshift;
986 ptr[poffset + 1] = temp;
987 temp = (word & bmask) >> gshift;
988 ptr[poffset + 2] = temp;
989 column++;
990 }
991 else
992 {
993 unsigned char temp;
994
995 linepos += fread(&dword, 4, 1, file);
996 temp = (dword & rmask) >> rshift;
997 ptr[poffset] = temp;
998 temp = (dword & gmask) >> gshift;
999 ptr[poffset + 1] = temp;
1000 temp = (dword & bmask) >> bshift;
1001 ptr[poffset + 2] = temp;
1002 column++;
1003 }
1004 }
1005 while ((linepos < linesize) && (comp != 1) && (comp != 2))
1006 {
1007 int temp = fread(&byte, 1, 1, file);
1008
1009 linepos += temp;
1010 if (!temp)
1011 break;
1012 }
1013 }
1014 if (cmap) free(cmap);
1015
1016 image->SetMask( FALSE );
1017
1018 fclose(file);
1019 return TRUE;
1020 }
1021