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