]> git.saurik.com Git - wxWidgets.git/blame - src/common/imagpng.cpp
better error message
[wxWidgets.git] / src / common / imagpng.cpp
CommitLineData
e9c4b1a2 1/////////////////////////////////////////////////////////////////////////////
27bb2b7c 2// Name: src/common/imagepng.cpp
e9c4b1a2
JS
3// Purpose: wxImage PNG handler
4// Author: Robert Roebling
5// RCS-ID: $Id$
6// Copyright: (c) Robert Roebling
7// Licence: wxWindows licence
8/////////////////////////////////////////////////////////////////////////////
9
27bb2b7c
VZ
10// ============================================================================
11// declarations
12// ============================================================================
13
8f493002
VS
14#ifdef __GNUG__
15#pragma implementation "imagpng.h"
16#endif
e9c4b1a2 17
27bb2b7c
VZ
18// ----------------------------------------------------------------------------
19// headers
20// ----------------------------------------------------------------------------
21
e9c4b1a2
JS
22// For compilers that support precompilation, includes "wx.h".
23#include "wx/wxprec.h"
24
25#ifdef __BORLANDC__
ce4169a4
RR
26 #pragma hdrstop
27#endif
28
29#ifndef WX_PRECOMP
30 #include "wx/defs.h"
e9c4b1a2
JS
31#endif
32
c96ea657 33#if wxUSE_IMAGE && wxUSE_LIBPNG
ce4169a4 34
8f493002 35#include "wx/imagpng.h"
e9c4b1a2
JS
36#include "wx/bitmap.h"
37#include "wx/debug.h"
38#include "wx/log.h"
39#include "wx/app.h"
ce4169a4 40#include "png.h"
e9c4b1a2
JS
41#include "wx/filefn.h"
42#include "wx/wfstream.h"
43#include "wx/intl.h"
44#include "wx/module.h"
45
46// For memcpy
47#include <string.h>
48
49#ifdef __SALFORDC__
50#ifdef FAR
51#undef FAR
52#endif
53#endif
54
27bb2b7c
VZ
55// ----------------------------------------------------------------------------
56// constants
57// ----------------------------------------------------------------------------
58
59// image can not have any transparent pixels at all, have only 100% opaque
60// and/or 100% transparent pixels in which case a simple mask is enough to
61// store this information in wxImage or have a real alpha channel in which case
62// we need to have it in wxImage as well
63enum Transparency
64{
65 Transparency_None,
66 Transparency_Mask,
67 Transparency_Alpha
68};
69
70// ----------------------------------------------------------------------------
71// local functions
72// ----------------------------------------------------------------------------
73
74// return the kind of transparency needed for this image assuming that it does
75// have transparent pixels, i.e. either Transparency_Alpha or Transparency_Mask
76static Transparency
77CheckTransparency(const unsigned char *ptr,
78 png_uint_32 x, png_uint_32 y, png_uint_32 w, png_uint_32 h);
79
80// init the alpha channel for the image and fill it with 1s up to (x, y)
81static unsigned char *InitAlpha(wxImage *image, png_uint_32 x, png_uint_32 y);
82
83// find a free colour for the mask in the PNG data array
84static void
85FindMaskColour(unsigned char **lines, png_uint_32 width, png_uint_32 height,
86 unsigned char& rMask, unsigned char& gMask, unsigned char& bMask);
e9c4b1a2 87
27bb2b7c
VZ
88// ============================================================================
89// wxPNGHandler implementation
90// ============================================================================
e9c4b1a2 91
e9c4b1a2 92IMPLEMENT_DYNAMIC_CLASS(wxPNGHandler,wxImageHandler)
e9c4b1a2 93
e30285ab 94#if wxUSE_STREAMS
9ab6ee85 95
0729bd19 96#ifndef PNGLINKAGEMODE
30e0e251
VZ
97 #ifdef __WATCOMC__
98 // we need an explicit cdecl for Watcom, at least according to
99 //
100 // http://sf.net/tracker/index.php?func=detail&aid=651492&group_id=9863&atid=109863
101 //
102 // more testing is needed for this however, please remove this comment
103 // if you can confirm that my fix works with Watcom 11
104 #define PNGLINKAGEMODE cdecl
105 #else
106 #define PNGLINKAGEMODE LINKAGEMODE
107 #endif
717b9bf2
DW
108#endif
109
bdffd806
VS
110
111// VS: wxPNGInfoStruct declared below is a hack that needs some explanation.
27bb2b7c
VZ
112// First, let me describe what's the problem: libpng uses jmp_buf in
113// its png_struct structure. Unfortunately, this structure is
114// compiler-specific and may vary in size, so if you use libpng compiled
bdffd806 115// as DLL with another compiler than the main executable, it may not work
27bb2b7c 116// (this is for example the case with wxMGL port and SciTech MGL library
bdffd806 117// that provides custom runtime-loadable libpng implementation with jmpbuf
27bb2b7c 118// disabled altogether). Luckily, it is still possible to use setjmp() &
bdffd806
VS
119// longjmp() as long as the structure is not part of png_struct.
120//
121// Sadly, there's no clean way to attach user-defined data to png_struct.
122// There is only one customizable place, png_struct.io_ptr, which is meant
27bb2b7c 123// only for I/O routines and is set with png_set_read_fn or
bdffd806
VS
124// png_set_write_fn. The hacky part is that we use io_ptr to store
125// a pointer to wxPNGInfoStruct that holds I/O structures _and_ jmp_buf.
126
127struct wxPNGInfoStruct
128{
129 jmp_buf jmpbuf;
130 bool verbose;
27bb2b7c 131
bdffd806
VS
132 union
133 {
134 wxInputStream *in;
135 wxOutputStream *out;
136 } stream;
137};
138
139#define WX_PNG_INFO(png_ptr) ((wxPNGInfoStruct*)png_get_io_ptr(png_ptr))
140
27bb2b7c
VZ
141// ----------------------------------------------------------------------------
142// helper functions
143// ----------------------------------------------------------------------------
bdffd806 144
90350682
VZ
145extern "C"
146{
147
148void PNGLINKAGEMODE _PNG_stream_reader( png_structp png_ptr, png_bytep data, png_size_t length )
e9c4b1a2 149{
bdffd806 150 WX_PNG_INFO(png_ptr)->stream.in->Read(data, length);
e9c4b1a2
JS
151}
152
90350682 153void PNGLINKAGEMODE _PNG_stream_writer( png_structp png_ptr, png_bytep data, png_size_t length )
e9c4b1a2 154{
bdffd806 155 WX_PNG_INFO(png_ptr)->stream.out->Write(data, length);
e9c4b1a2
JS
156}
157
deb2fec0
SB
158// from pngerror.c
159// so that the libpng doesn't send anything on stderr
160void
bdffd806 161PNGLINKAGEMODE wx_png_error(png_structp png_ptr, png_const_charp message)
deb2fec0 162{
bdffd806 163 wxPNGInfoStruct *info = WX_PNG_INFO(png_ptr);
2b5f62a0
VZ
164 if (info->verbose)
165 wxLogError( wxString::FromAscii(message) );
bdffd806 166
deb2fec0 167#ifdef USE_FAR_KEYWORD
bdffd806
VS
168 {
169 jmp_buf jmpbuf;
170 png_memcpy(jmpbuf,info->jmpbuf,sizeof(jmp_buf));
171 longjmp(jmpbuf, 1);
172 }
deb2fec0 173#else
bdffd806 174 longjmp(info->jmpbuf, 1);
deb2fec0
SB
175#endif
176}
177
178void
bdffd806 179PNGLINKAGEMODE wx_png_warning(png_structp png_ptr, png_const_charp message)
deb2fec0 180{
bdffd806 181 wxPNGInfoStruct *info = WX_PNG_INFO(png_ptr);
2b5f62a0
VZ
182 if (info->verbose)
183 wxLogWarning( wxString::FromAscii(message) );
deb2fec0
SB
184}
185
90350682
VZ
186} // extern "C"
187
27bb2b7c
VZ
188// ----------------------------------------------------------------------------
189// LoadFile() helpers
190// ----------------------------------------------------------------------------
191
d26d9754
VZ
192// determine the kind of transparency we need for this image: if the only alpha
193// values it has are 0 and 0xff then we can simply create a mask for it, we
194// should be ok with a simple mask but otherwise we need a full blown alpha
195// channel in wxImage
196//
197// parameters:
198// ptr the start of the data to examine
199// x, y starting position
200// w, h size of the image
201// numColBytes number of colour bytes (1 for grey scale, 3 for RGB)
202// (NB: alpha always follows the colour bytes)
27bb2b7c
VZ
203Transparency
204CheckTransparency(const unsigned char *ptr,
d26d9754
VZ
205 png_uint_32 x, png_uint_32 y, png_uint_32 w, png_uint_32 h,
206 size_t numColBytes)
27bb2b7c 207{
d26d9754
VZ
208 // suppose that a mask will suffice and check all the remaining alpha
209 // values to see if it does
27bb2b7c
VZ
210 unsigned char a2;
211 unsigned const char *ptr2 = ptr;
212 for ( png_uint_32 y2 = y; y2 < h; y2++ )
213 {
214 for ( png_uint_32 x2 = x + 1; x2 < w; x2++ )
215 {
216 // skip the grey byte
d26d9754
VZ
217 ptr2 += numColBytes;
218 a2 = *ptr2++;
27bb2b7c
VZ
219
220 if ( a2 && a2 != 0xff )
221 {
d26d9754
VZ
222 // not fully opaque nor fully transparent, hence need alpha
223 return Transparency_Alpha;
27bb2b7c 224 }
27bb2b7c
VZ
225 }
226 }
227
d26d9754
VZ
228 // mask will be enough
229 return Transparency_Mask;
27bb2b7c
VZ
230}
231
232unsigned char *InitAlpha(wxImage *image, png_uint_32 x, png_uint_32 y)
233{
234 // create alpha channel
235 image->SetAlpha();
236
237 unsigned char *alpha = image->GetAlpha();
238
239 // set alpha for the pixels we had so far
240 for ( png_uint_32 y2 = 0; y2 <= y; y2++ )
241 {
242 for ( png_uint_32 x2 = 0; x2 < x; x2++ )
243 {
244 // all the previous pixels were opaque
245 *alpha++ = 0xff;
246 }
247 }
248
249 return alpha;
250}
251
252void
253FindMaskColour(unsigned char **lines, png_uint_32 width, png_uint_32 height,
254 unsigned char& rMask, unsigned char& gMask, unsigned char& bMask)
255{
256 // choosing the colour for the mask is more
257 // difficult: we need to iterate over the entire
258 // image for this in order to choose an unused
259 // colour (this is not very efficient but what else
260 // can we do?)
261 wxImageHistogram h;
262 unsigned nentries = 0;
263 unsigned char r2, g2, b2;
264 for ( png_uint_32 y2 = 0; y2 < height; y2++ )
265 {
266 const unsigned char *p = lines[y2];
267 for ( png_uint_32 x2 = 0; x2 < width; x2++ )
268 {
269 r2 = *p++;
270 g2 = *p++;
271 b2 = *p++;
272
273 wxImageHistogramEntry&
274 entry = h[wxImageHistogram:: MakeKey(r2, g2, b2)];
275
276 if ( entry.value++ == 0 )
277 entry.index = nentries++;
278 }
279 }
280
281 if ( !h.FindFirstUnusedColour(&rMask, &gMask, &bMask) )
282 {
283 wxLogWarning(_("Too many colours in PNG, the image may be slightly blurred."));
284
285 // use a fixed mask colour and we'll fudge
286 // the real pixels with this colour (see
287 // below)
288 rMask = 0xfe;
289 gMask = 0;
290 bMask = 0xff;
291 }
292}
293
294// ----------------------------------------------------------------------------
295// reading PNGs
296// ----------------------------------------------------------------------------
297
298bool wxPNGHandler::DoCanRead( wxInputStream& stream )
299{
300 unsigned char hdr[4];
301
302 if ( !stream.Read(hdr, WXSIZEOF(hdr)) )
303 return FALSE;
304
305 return memcmp(hdr, "\211PNG", WXSIZEOF(hdr)) == 0;
306}
307
308// convert data from RGB to wxImage format
309static
310void CopyDataFromPNG(wxImage *image,
311 unsigned char **lines,
312 png_uint_32 width,
313 png_uint_32 height,
314 int color_type)
315{
316 Transparency transparency = Transparency_None;
317
318 // only non NULL if transparency == Transparency_Alpha
319 unsigned char *alpha = NULL;
320
321 // RGB of the mask colour if transparency == Transparency_Mask
322 // (but init them anyhow to avoid compiler warnings)
323 unsigned char rMask = 0,
324 gMask = 0,
325 bMask = 0;
326
327 unsigned char *ptrDst = image->GetData();
328 if ( !(color_type & PNG_COLOR_MASK_COLOR) )
329 {
330 // grey image: GAGAGA... where G == grey component and A == alpha
331 for ( png_uint_32 y = 0; y < height; y++ )
332 {
333 const unsigned char *ptrSrc = lines[y];
334 for ( png_uint_32 x = 0; x < width; x++ )
335 {
336 unsigned char g = *ptrSrc++;
337 unsigned char a = *ptrSrc++;
338
339 // the first time we encounter a transparent pixel we must
340 // decide about what to do about them
341 if ( a != 0xff && transparency == Transparency_None )
342 {
343 // we'll need at least the mask for this image and
344 // maybe even full alpha channel info: the former is
345 // only enough if we have alpha values of 0 and 0xff
346 // only, otherwisewe need the latter
d26d9754
VZ
347 transparency = CheckTransparency
348 (
349 ptrSrc,
350 x, y,
351 width, height,
352 1
353 );
27bb2b7c
VZ
354
355 if ( transparency == Transparency_Mask )
356 {
357 // let's choose this colour for the mask: this is
358 // not a problem here as all the other pixels are
359 // grey, i.e. R == G == B which is not the case for
360 // this one so no confusion is possible
361 rMask = 0xff;
362 gMask = 0;
363 bMask = 0xff;
364 }
365 else // transparency == Transparency_Alpha
366 {
367 alpha = InitAlpha(image, x, y);
368 }
369 }
370
371 switch ( transparency )
372 {
373 case Transparency_Alpha:
374 *alpha++ = a;
375 // fall through
376
377 case Transparency_None:
378 *ptrDst++ = g;
379 *ptrDst++ = g;
380 *ptrDst++ = g;
381 break;
382
383 case Transparency_Mask:
384 *ptrDst++ = rMask;
385 *ptrDst++ = bMask;
386 *ptrDst++ = gMask;
387 }
388 }
389 }
390 }
391 else // colour image: RGBRGB...
392 {
393 for ( png_uint_32 y = 0; y < height; y++ )
394 {
395 const unsigned char *ptrSrc = lines[y];
396 for ( png_uint_32 x = 0; x < width; x++ )
397 {
398 unsigned char r = *ptrSrc++;
399 unsigned char g = *ptrSrc++;
400 unsigned char b = *ptrSrc++;
401 unsigned char a = *ptrSrc++;
402
403 // the logic here is the same as for the grey case except
404 // where noted
405 if ( a != 0xff && transparency == Transparency_None )
406 {
d26d9754
VZ
407 transparency = CheckTransparency
408 (
409 ptrSrc,
410 x, y,
411 width, height,
412 3
413 );
27bb2b7c
VZ
414
415 if ( transparency == Transparency_Mask )
416 {
417 FindMaskColour(lines, width, height,
418 rMask, gMask, bMask);
419 }
420 else // transparency == Transparency_Alpha
421 {
422 alpha = InitAlpha(image, x, y);
423 }
424
425 }
426
427 switch ( transparency )
428 {
429 case Transparency_Alpha:
430 *alpha++ = a;
431 // fall through
432
433 case Transparency_None:
434 *ptrDst++ = r;
435 *ptrDst++ = g;
436 *ptrDst++ = b;
437 break;
438
439 case Transparency_Mask:
440 // if we couldn't find a unique colour for the mask, we
441 // can have real pixels with the same value as the mask
442 // and it's better to slightly change their colour than
443 // to make them transparent
444 if ( r == rMask && g == gMask && b == bMask )
445 {
446 r++;
447 }
448
449 *ptrDst++ = rMask;
450 *ptrDst++ = bMask;
451 *ptrDst++ = gMask;
452 }
453 }
454 }
455 }
456
457 if ( transparency == Transparency_Mask )
458 {
459 image->SetMaskColour(rMask, gMask, bMask);
460 }
461}
462
3ca6a5f0
BP
463// temporarily disable the warning C4611 (interaction between '_setjmp' and
464// C++ object destruction is non-portable) - I don't see any dtors here
465#ifdef __VISUALC__
466 #pragma warning(disable:4611)
467#endif /* VC++ */
468
27bb2b7c
VZ
469bool
470wxPNGHandler::LoadFile(wxImage *image,
471 wxInputStream& stream,
472 bool verbose,
473 int WXUNUSED(index))
e9c4b1a2
JS
474{
475 // VZ: as this function uses setjmp() the only fool proof error handling
476 // method is to use goto (setjmp is not really C++ dtors friendly...)
717b9bf2 477
27bb2b7c
VZ
478 unsigned char **lines = NULL;
479 png_infop info_ptr = (png_infop) NULL;
bdffd806
VS
480 wxPNGInfoStruct wxinfo;
481
482 wxinfo.verbose = verbose;
483 wxinfo.stream.in = &stream;
717b9bf2 484
e9c4b1a2 485 image->Destroy();
717b9bf2 486
e9c4b1a2
JS
487 png_structp png_ptr = png_create_read_struct( PNG_LIBPNG_VER_STRING,
488 (voidp) NULL,
489 (png_error_ptr) NULL,
490 (png_error_ptr) NULL );
491 if (!png_ptr)
27bb2b7c 492 goto error;
717b9bf2 493
bdffd806
VS
494 png_set_error_fn(png_ptr, (png_voidp)NULL, wx_png_error, wx_png_warning);
495
496 // NB: please see the comment near wxPNGInfoStruct declaration for
497 // explanation why this line is mandatory
498 png_set_read_fn( png_ptr, &wxinfo, _PNG_stream_reader);
deb2fec0 499
e9c4b1a2
JS
500 info_ptr = png_create_info_struct( png_ptr );
501 if (!info_ptr)
27bb2b7c 502 goto error;
717b9bf2 503
bdffd806 504 if (setjmp(wxinfo.jmpbuf))
27bb2b7c 505 goto error;
717b9bf2 506
27bb2b7c
VZ
507 png_uint_32 i, width, height;
508 int bit_depth, color_type, interlace_type;
717b9bf2 509
e9c4b1a2
JS
510 png_read_info( png_ptr, info_ptr );
511 png_get_IHDR( png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, (int*) NULL, (int*) NULL );
717b9bf2 512
e9c4b1a2
JS
513 if (color_type == PNG_COLOR_TYPE_PALETTE)
514 png_set_expand( png_ptr );
717b9bf2 515
2b5f62a0
VZ
516 // Fix for Bug [ 439207 ] Monochrome PNG images come up black
517 if (bit_depth < 8)
518 png_set_expand( png_ptr );
519
e9c4b1a2
JS
520 png_set_strip_16( png_ptr );
521 png_set_packing( png_ptr );
522 if (png_get_valid( png_ptr, info_ptr, PNG_INFO_tRNS))
523 png_set_expand( png_ptr );
524 png_set_filler( png_ptr, 0xff, PNG_FILLER_AFTER );
717b9bf2 525
479cd5de 526 image->Create( (int)width, (int)height );
717b9bf2 527
e9c4b1a2 528 if (!image->Ok())
27bb2b7c 529 goto error;
717b9bf2 530
479cd5de 531 lines = (unsigned char **)malloc( (size_t)(height * sizeof(unsigned char *)) );
27bb2b7c
VZ
532 if ( !lines )
533 goto error;
717b9bf2 534
e9c4b1a2
JS
535 for (i = 0; i < height; i++)
536 {
479cd5de 537 if ((lines[i] = (unsigned char *)malloc( (size_t)(width * (sizeof(unsigned char) * 4)))) == NULL)
e9c4b1a2
JS
538 {
539 for ( unsigned int n = 0; n < i; n++ )
540 free( lines[n] );
541 goto error;
542 }
543 }
717b9bf2 544
27bb2b7c
VZ
545 png_read_image( png_ptr, lines );
546 png_read_end( png_ptr, info_ptr );
547 png_destroy_read_struct( &png_ptr, &info_ptr, (png_infopp) NULL );
717b9bf2 548
27bb2b7c
VZ
549 // loaded successfully, now init wxImage with this data
550 CopyDataFromPNG(image, lines, width, height, color_type);
717b9bf2 551
27bb2b7c
VZ
552 for ( i = 0; i < height; i++ )
553 free( lines[i] );
554 free( lines );
717b9bf2 555
e9c4b1a2 556 return TRUE;
95ee0ac8 557
27bb2b7c 558error:
58c837a4
RR
559 if (verbose)
560 wxLogError(_("Couldn't load a PNG image - file is corrupted or not enough memory."));
717b9bf2 561
e9c4b1a2
JS
562 if ( image->Ok() )
563 {
564 image->Destroy();
565 }
717b9bf2 566
e9c4b1a2
JS
567 if ( lines )
568 {
569 free( lines );
570 }
717b9bf2 571
e9c4b1a2
JS
572 if ( png_ptr )
573 {
574 if ( info_ptr )
575 {
576 png_destroy_read_struct( &png_ptr, &info_ptr, (png_infopp) NULL );
577 free(info_ptr);
578 }
579 else
580 png_destroy_read_struct( &png_ptr, (png_infopp) NULL, (png_infopp) NULL );
581 }
582 return FALSE;
583}
584
27bb2b7c
VZ
585// ----------------------------------------------------------------------------
586// writing PNGs
587// ----------------------------------------------------------------------------
588
deb2fec0 589bool wxPNGHandler::SaveFile( wxImage *image, wxOutputStream& stream, bool verbose )
e9c4b1a2 590{
bdffd806 591 wxPNGInfoStruct wxinfo;
717b9bf2 592
bdffd806
VS
593 wxinfo.verbose = verbose;
594 wxinfo.stream.out = &stream;
deb2fec0 595
bdffd806
VS
596 png_structp png_ptr = png_create_write_struct( PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
597 if (!png_ptr)
598 {
599 if (verbose)
600 wxLogError(_("Couldn't save PNG image."));
601 return FALSE;
602 }
717b9bf2 603
bdffd806 604 png_set_error_fn(png_ptr, (png_voidp)NULL, wx_png_error, wx_png_warning);
717b9bf2 605
bdffd806
VS
606 png_infop info_ptr = png_create_info_struct(png_ptr);
607 if (info_ptr == NULL)
608 {
609 png_destroy_write_struct( &png_ptr, (png_infopp)NULL );
610 if (verbose)
611 wxLogError(_("Couldn't save PNG image."));
612 return FALSE;
613 }
717b9bf2 614
bdffd806
VS
615 if (setjmp(wxinfo.jmpbuf))
616 {
617 png_destroy_write_struct( &png_ptr, (png_infopp)NULL );
618 if (verbose)
619 wxLogError(_("Couldn't save PNG image."));
620 return FALSE;
621 }
717b9bf2 622
bdffd806
VS
623 // NB: please see the comment near wxPNGInfoStruct declaration for
624 // explanation why this line is mandatory
625 png_set_write_fn( png_ptr, &wxinfo, _PNG_stream_writer, NULL);
626
627 png_set_IHDR( png_ptr, info_ptr, image->GetWidth(), image->GetHeight(), 8,
628 PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE,
629 PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
630
631 png_color_8 sig_bit;
632 sig_bit.red = 8;
633 sig_bit.green = 8;
634 sig_bit.blue = 8;
635 sig_bit.alpha = 8;
636 png_set_sBIT( png_ptr, info_ptr, &sig_bit );
637 png_write_info( png_ptr, info_ptr );
638 png_set_shift( png_ptr, &sig_bit );
639 png_set_packing( png_ptr );
717b9bf2 640
bdffd806
VS
641 unsigned char *data = (unsigned char *)malloc( image->GetWidth()*4 );
642 if (!data)
643 {
644 png_destroy_write_struct( &png_ptr, (png_infopp)NULL );
645 return FALSE;
646 }
717b9bf2 647
bdffd806
VS
648 for (int y = 0; y < image->GetHeight(); y++)
649 {
650 unsigned char *ptr = image->GetData() + (y * image->GetWidth() * 3);
651 for (int x = 0; x < image->GetWidth(); x++)
e9c4b1a2 652 {
bdffd806
VS
653 data[(x << 2) + 0] = *ptr++;
654 data[(x << 2) + 1] = *ptr++;
655 data[(x << 2) + 2] = *ptr++;
656 if (( !image->HasMask() ) || \
657 (data[(x << 2) + 0] != image->GetMaskRed()) || \
658 (data[(x << 2) + 1] != image->GetMaskGreen()) || \
659 (data[(x << 2) + 2] != image->GetMaskBlue()))
e9c4b1a2 660 {
bdffd806
VS
661 data[(x << 2) + 3] = 255;
662 }
663 else
664 {
665 data[(x << 2) + 3] = 0;
e9c4b1a2 666 }
e9c4b1a2 667 }
bdffd806
VS
668 png_bytep row_ptr = data;
669 png_write_rows( png_ptr, &row_ptr, 1 );
e9c4b1a2 670 }
bdffd806
VS
671
672 free(data);
673 png_write_end( png_ptr, info_ptr );
674 png_destroy_write_struct( &png_ptr, (png_infopp)&info_ptr );
675
e9c4b1a2
JS
676 return TRUE;
677}
e9c4b1a2 678
3ca6a5f0
BP
679#ifdef __VISUALC__
680 #pragma warning(default:4611)
681#endif /* VC++ */
682
9ab6ee85 683#endif // wxUSE_STREAMS
e9c4b1a2 684
9ab6ee85 685#endif // wxUSE_LIBPNG