]>
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 | ||
4bc67cc5 RR |
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 | ||
ef539066 RR |
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 | ||
01111366 RR |
214 | bool wxImage::Ok() const |
215 | { | |
fd0eed64 | 216 | return (M_IMGDATA && M_IMGDATA->m_ok); |
01111366 RR |
217 | } |
218 | ||
219 | char unsigned *wxImage::GetData() const | |
220 | { | |
4bc67cc5 | 221 | wxCHECK_MSG( Ok(), (char unsigned *)NULL, "invalid image" ); |
01111366 | 222 | |
fd0eed64 | 223 | return M_IMGDATA->m_data; |
01111366 RR |
224 | } |
225 | ||
226 | void wxImage::SetData( char unsigned *WXUNUSED(data) ) | |
227 | { | |
4bc67cc5 | 228 | wxCHECK_RET( Ok(), "invalid image" ); |
01111366 RR |
229 | } |
230 | ||
231 | void wxImage::SetMaskColour( unsigned char r, unsigned char g, unsigned char b ) | |
232 | { | |
4bc67cc5 | 233 | wxCHECK_RET( Ok(), "invalid image" ); |
01111366 | 234 | |
fd0eed64 RR |
235 | M_IMGDATA->m_maskRed = r; |
236 | M_IMGDATA->m_maskGreen = g; | |
237 | M_IMGDATA->m_maskBlue = b; | |
238 | M_IMGDATA->m_hasMask = TRUE; | |
01111366 RR |
239 | } |
240 | ||
241 | unsigned char wxImage::GetMaskRed() const | |
242 | { | |
4bc67cc5 | 243 | wxCHECK_MSG( Ok(), 0, "invalid image" ); |
01111366 | 244 | |
fd0eed64 | 245 | return M_IMGDATA->m_maskRed; |
01111366 RR |
246 | } |
247 | ||
248 | unsigned char wxImage::GetMaskGreen() const | |
249 | { | |
4bc67cc5 | 250 | wxCHECK_MSG( Ok(), 0, "invalid image" ); |
fd0eed64 RR |
251 | |
252 | return M_IMGDATA->m_maskGreen; | |
01111366 RR |
253 | } |
254 | ||
255 | unsigned char wxImage::GetMaskBlue() const | |
256 | { | |
4bc67cc5 | 257 | wxCHECK_MSG( Ok(), 0, "invalid image" ); |
01111366 | 258 | |
fd0eed64 | 259 | return M_IMGDATA->m_maskBlue; |
01111366 RR |
260 | } |
261 | ||
262 | void wxImage::SetMask( bool mask ) | |
263 | { | |
4bc67cc5 | 264 | wxCHECK_RET( Ok(), "invalid image" ); |
01111366 | 265 | |
fd0eed64 | 266 | M_IMGDATA->m_hasMask = mask; |
01111366 RR |
267 | } |
268 | ||
269 | bool wxImage::HasMask() const | |
270 | { | |
4bc67cc5 | 271 | wxCHECK_MSG( Ok(), FALSE, "invalid image" ); |
01111366 | 272 | |
fd0eed64 | 273 | return M_IMGDATA->m_hasMask; |
01111366 RR |
274 | } |
275 | ||
276 | int wxImage::GetWidth() const | |
277 | { | |
4bc67cc5 RR |
278 | wxCHECK_MSG( Ok(), 0, "invalid image" ); |
279 | ||
280 | return M_IMGDATA->m_width; | |
01111366 RR |
281 | } |
282 | ||
283 | int wxImage::GetHeight() const | |
284 | { | |
4bc67cc5 RR |
285 | wxCHECK_MSG( Ok(), 0, "invalid image" ); |
286 | ||
287 | return M_IMGDATA->m_height; | |
01111366 RR |
288 | } |
289 | ||
290 | bool wxImage::LoadFile( const wxString& filename, long type ) | |
291 | { | |
fd0eed64 | 292 | UnRef(); |
dc86cb34 | 293 | |
fd0eed64 RR |
294 | if (!wxFileExists(filename)) |
295 | { | |
296 | wxLogWarning( "Image file does not exist." ); | |
dc86cb34 | 297 | |
fd0eed64 RR |
298 | return FALSE; |
299 | } | |
01111366 | 300 | |
fd0eed64 | 301 | m_refData = new wxImageRefData; |
01111366 | 302 | |
fd0eed64 | 303 | wxImageHandler *handler = FindHandler(type); |
01111366 | 304 | |
fd0eed64 RR |
305 | if (handler == NULL) |
306 | { | |
307 | wxLogWarning( "No image handler for type %d defined.", type ); | |
01111366 | 308 | |
fd0eed64 RR |
309 | return FALSE; |
310 | } | |
01111366 | 311 | |
fd0eed64 | 312 | return handler->LoadFile( this, filename ); |
01111366 RR |
313 | } |
314 | ||
315 | bool wxImage::SaveFile( const wxString& filename, int type ) | |
316 | { | |
4bc67cc5 RR |
317 | wxCHECK_MSG( Ok(), FALSE, "invalid image" ); |
318 | ||
fd0eed64 | 319 | wxImageHandler *handler = FindHandler(type); |
01111366 | 320 | |
fd0eed64 RR |
321 | if (handler == NULL) |
322 | { | |
323 | wxLogWarning( "No image handler for type %d defined.", type ); | |
01111366 | 324 | |
fd0eed64 RR |
325 | return FALSE; |
326 | } | |
01111366 | 327 | |
fd0eed64 | 328 | return handler->SaveFile( this, filename ); |
01111366 RR |
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 | { | |
fd0eed64 RR |
343 | wxImageHandler *handler = FindHandler(name); |
344 | if (handler) | |
345 | { | |
346 | sm_handlers.DeleteObject(handler); | |
347 | return TRUE; | |
348 | } | |
349 | else | |
350 | return FALSE; | |
01111366 RR |
351 | } |
352 | ||
353 | wxImageHandler *wxImage::FindHandler( const wxString& name ) | |
354 | { | |
fd0eed64 RR |
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; | |
01111366 RR |
363 | } |
364 | ||
365 | wxImageHandler *wxImage::FindHandler( const wxString& extension, long bitmapType ) | |
366 | { | |
fd0eed64 RR |
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; | |
01111366 RR |
377 | } |
378 | ||
379 | wxImageHandler *wxImage::FindHandler( long bitmapType ) | |
380 | { | |
fd0eed64 RR |
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 ); | |
01111366 RR |
395 | } |
396 | ||
397 | void wxImage::CleanUpHandlers() | |
398 | { | |
fd0eed64 RR |
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 | } | |
01111366 RR |
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 | { | |
fd0eed64 | 420 | return FALSE; |
01111366 RR |
421 | } |
422 | ||
423 | bool wxImageHandler::SaveFile( wxImage *WXUNUSED(image), const wxString& WXUNUSED(name) ) | |
424 | { | |
fd0eed64 | 425 | return FALSE; |
01111366 RR |
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; | |
0b4f9ee3 | 444 | unsigned int i; |
01111366 RR |
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 | ||
0b4f9ee3 | 500 | for (i = 0; i < height; i++) |
01111366 RR |
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 | } | |
0b4f9ee3 | 569 | for (i = 0; i < height; i++) free( lines[i] ); |
01111366 RR |
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; | |
0b4f9ee3 | 681 | #ifndef BI_RGB |
01111366 RR |
682 | #define BI_RGB 0 |
683 | #define BI_RLE8 1 | |
684 | #define BI_RLE4 2 | |
685 | #define BI_BITFIELDS 3 | |
0b4f9ee3 | 686 | #endif |
01111366 RR |
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 | { | |
df875e59 | 937 | linepos++; |
01111366 RR |
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 |