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