/[pcsx2_0.9.7]/trunk/3rdparty/wxWidgets/src/common/imagpng.cpp
ViewVC logotype

Annotation of /trunk/3rdparty/wxWidgets/src/common/imagpng.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 31 - (hide annotations) (download)
Tue Sep 7 03:24:11 2010 UTC (10 years, 4 months ago) by william
File size: 27774 byte(s)
committing r3113 initial commit again...
1 william 31 /////////////////////////////////////////////////////////////////////////////
2     // Name: src/common/imagepng.cpp
3     // Purpose: wxImage PNG handler
4     // Author: Robert Roebling
5     // RCS-ID: $Id: imagpng.cpp 53479 2008-05-07 16:23:55Z PC $
6     // Copyright: (c) Robert Roebling
7     // Licence: wxWindows licence
8     /////////////////////////////////////////////////////////////////////////////
9    
10     // ============================================================================
11     // declarations
12     // ============================================================================
13    
14     // ----------------------------------------------------------------------------
15     // headers
16     // ----------------------------------------------------------------------------
17    
18     // For compilers that support precompilation, includes "wx.h".
19     #include "wx/wxprec.h"
20    
21     #ifdef __BORLANDC__
22     #pragma hdrstop
23     #endif
24    
25     #if wxUSE_IMAGE && wxUSE_LIBPNG
26    
27     #include "wx/imagpng.h"
28    
29     #ifndef WX_PRECOMP
30     #include "wx/log.h"
31     #include "wx/app.h"
32     #include "wx/bitmap.h"
33     #include "wx/module.h"
34     #endif
35    
36     #include "png.h"
37     #include "wx/filefn.h"
38     #include "wx/wfstream.h"
39     #include "wx/intl.h"
40     #include "wx/palette.h"
41    
42     // For memcpy
43     #include <string.h>
44    
45     #ifdef __SALFORDC__
46     #ifdef FAR
47     #undef FAR
48     #endif
49     #endif
50    
51     // ----------------------------------------------------------------------------
52     // constants
53     // ----------------------------------------------------------------------------
54    
55     // image can not have any transparent pixels at all, have only 100% opaque
56     // and/or 100% transparent pixels in which case a simple mask is enough to
57     // store this information in wxImage or have a real alpha channel in which case
58     // we need to have it in wxImage as well
59     enum Transparency
60     {
61     Transparency_None,
62     Transparency_Mask,
63     Transparency_Alpha
64     };
65    
66     // ----------------------------------------------------------------------------
67     // local functions
68     // ----------------------------------------------------------------------------
69    
70     // return the kind of transparency needed for this image assuming that it does
71     // have transparent pixels, i.e. either Transparency_Alpha or Transparency_Mask
72     static Transparency
73     CheckTransparency(unsigned char **lines,
74     png_uint_32 x, png_uint_32 y, png_uint_32 w, png_uint_32 h,
75     size_t numColBytes);
76    
77     // init the alpha channel for the image and fill it with 1s up to (x, y)
78     static unsigned char *InitAlpha(wxImage *image, png_uint_32 x, png_uint_32 y);
79    
80     // find a free colour for the mask in the PNG data array
81     static void
82     FindMaskColour(unsigned char **lines, png_uint_32 width, png_uint_32 height,
83     unsigned char& rMask, unsigned char& gMask, unsigned char& bMask);
84    
85     // is the pixel with this value of alpha a fully opaque one?
86     static inline
87     bool IsOpaque(unsigned char a)
88     {
89     return a == 0xff;
90     }
91    
92     // is the pixel with this value of alpha a fully transparent one?
93     static inline
94     bool IsTransparent(unsigned char a)
95     {
96     return !a;
97     }
98    
99     // ============================================================================
100     // wxPNGHandler implementation
101     // ============================================================================
102    
103     IMPLEMENT_DYNAMIC_CLASS(wxPNGHandler,wxImageHandler)
104    
105     #if wxUSE_STREAMS
106    
107     #ifndef PNGLINKAGEMODE
108     #ifdef PNGAPI
109     #define PNGLINKAGEMODE PNGAPI
110     #elif defined(__WATCOMC__)
111     // we need an explicit cdecl for Watcom, at least according to
112     //
113     // http://sf.net/tracker/index.php?func=detail&aid=651492&group_id=9863&atid=109863
114     //
115     // more testing is needed for this however, please remove this comment
116     // if you can confirm that my fix works with Watcom 11
117     #define PNGLINKAGEMODE cdecl
118     #else
119     #define PNGLINKAGEMODE LINKAGEMODE
120     #endif
121     #endif
122    
123    
124     // VS: wxPNGInfoStruct declared below is a hack that needs some explanation.
125     // First, let me describe what's the problem: libpng uses jmp_buf in
126     // its png_struct structure. Unfortunately, this structure is
127     // compiler-specific and may vary in size, so if you use libpng compiled
128     // as DLL with another compiler than the main executable, it may not work
129     // (this is for example the case with wxMGL port and SciTech MGL library
130     // that provides custom runtime-loadable libpng implementation with jmpbuf
131     // disabled altogether). Luckily, it is still possible to use setjmp() &
132     // longjmp() as long as the structure is not part of png_struct.
133     //
134     // Sadly, there's no clean way to attach user-defined data to png_struct.
135     // There is only one customizable place, png_struct.io_ptr, which is meant
136     // only for I/O routines and is set with png_set_read_fn or
137     // png_set_write_fn. The hacky part is that we use io_ptr to store
138     // a pointer to wxPNGInfoStruct that holds I/O structures _and_ jmp_buf.
139    
140     struct wxPNGInfoStruct
141     {
142     jmp_buf jmpbuf;
143     bool verbose;
144    
145     union
146     {
147     wxInputStream *in;
148     wxOutputStream *out;
149     } stream;
150     };
151    
152     #define WX_PNG_INFO(png_ptr) ((wxPNGInfoStruct*)png_get_io_ptr(png_ptr))
153    
154     // ----------------------------------------------------------------------------
155     // helper functions
156     // ----------------------------------------------------------------------------
157    
158     extern "C"
159     {
160    
161     void PNGLINKAGEMODE wx_PNG_stream_reader( png_structp png_ptr, png_bytep data,
162     png_size_t length )
163     {
164     WX_PNG_INFO(png_ptr)->stream.in->Read(data, length);
165     }
166    
167     void PNGLINKAGEMODE wx_PNG_stream_writer( png_structp png_ptr, png_bytep data,
168     png_size_t length )
169     {
170     WX_PNG_INFO(png_ptr)->stream.out->Write(data, length);
171     }
172    
173     void
174     PNGLINKAGEMODE wx_png_warning(png_structp png_ptr, png_const_charp message)
175     {
176     wxPNGInfoStruct *info = png_ptr ? WX_PNG_INFO(png_ptr) : NULL;
177     if ( !info || info->verbose )
178     wxLogWarning( wxString::FromAscii(message) );
179     }
180    
181     // from pngerror.c
182     // so that the libpng doesn't send anything on stderr
183     void
184     PNGLINKAGEMODE wx_png_error(png_structp png_ptr, png_const_charp message)
185     {
186     wx_png_warning(NULL, message);
187    
188     // we're not using libpng built-in jump buffer (see comment before
189     // wxPNGInfoStruct above) so we have to return ourselves, otherwise libpng
190     // would just abort
191     longjmp(WX_PNG_INFO(png_ptr)->jmpbuf, 1);
192     }
193    
194     } // extern "C"
195    
196     // ----------------------------------------------------------------------------
197     // LoadFile() helpers
198     // ----------------------------------------------------------------------------
199    
200     // determine the kind of transparency we need for this image: if the only alpha
201     // values it has are 0 (transparent) and 0xff (opaque) then we can simply
202     // create a mask for it, we should be ok with a simple mask but otherwise we
203     // need a full blown alpha channel in wxImage
204     //
205     // parameters:
206     // lines raw PNG data
207     // x, y starting position
208     // w, h size of the image
209     // numColBytes number of colour bytes (1 for grey scale, 3 for RGB)
210     // (NB: alpha always follows the colour bytes)
211     Transparency
212     CheckTransparency(unsigned char **lines,
213     png_uint_32 x, png_uint_32 y, png_uint_32 w, png_uint_32 h,
214     size_t numColBytes)
215     {
216     // suppose that a mask will suffice and check all the remaining alpha
217     // values to see if it does
218     for ( ; y < h; y++ )
219     {
220     // each pixel is numColBytes+1 bytes, offset into the current line by
221     // the current x position
222     unsigned const char *ptr = lines[y] + (x * (numColBytes + 1));
223    
224     for ( png_uint_32 x2 = x; x2 < w; x2++ )
225     {
226     // skip the grey or colour byte(s)
227     ptr += numColBytes;
228    
229     unsigned char a2 = *ptr++;
230    
231     if ( !IsTransparent(a2) && !IsOpaque(a2) )
232     {
233     // not fully opaque nor fully transparent, hence need alpha
234     return Transparency_Alpha;
235     }
236     }
237    
238     // during the next loop iteration check all the pixels in the row
239     x = 0;
240     }
241    
242     // mask will be enough
243     return Transparency_Mask;
244     }
245    
246     unsigned char *InitAlpha(wxImage *image, png_uint_32 x, png_uint_32 y)
247     {
248     // create alpha channel
249     image->SetAlpha();
250    
251     unsigned char *alpha = image->GetAlpha();
252    
253     // set alpha for the pixels we had so far
254     png_uint_32 end = y * image->GetWidth() + x;
255     for ( png_uint_32 i = 0; i < end; i++ )
256     {
257     // all the previous pixels were opaque
258     *alpha++ = 0xff;
259     }
260    
261     return alpha;
262     }
263    
264     void
265     FindMaskColour(unsigned char **lines, png_uint_32 width, png_uint_32 height,
266     unsigned char& rMask, unsigned char& gMask, unsigned char& bMask)
267     {
268     // choosing the colour for the mask is more
269     // difficult: we need to iterate over the entire
270     // image for this in order to choose an unused
271     // colour (this is not very efficient but what else
272     // can we do?)
273     wxImageHistogram h;
274     unsigned nentries = 0;
275     unsigned char r2, g2, b2;
276     for ( png_uint_32 y2 = 0; y2 < height; y2++ )
277     {
278     const unsigned char *p = lines[y2];
279     for ( png_uint_32 x2 = 0; x2 < width; x2++ )
280     {
281     r2 = *p++;
282     g2 = *p++;
283     b2 = *p++;
284     ++p; // jump over alpha
285    
286     wxImageHistogramEntry&
287     entry = h[wxImageHistogram:: MakeKey(r2, g2, b2)];
288    
289     if ( entry.value++ == 0 )
290     entry.index = nentries++;
291     }
292     }
293    
294     if ( !h.FindFirstUnusedColour(&rMask, &gMask, &bMask) )
295     {
296     wxLogWarning(_("Too many colours in PNG, the image may be slightly blurred."));
297    
298     // use a fixed mask colour and we'll fudge
299     // the real pixels with this colour (see
300     // below)
301     rMask = 0xfe;
302     gMask = 0;
303     bMask = 0xff;
304     }
305     }
306    
307     // ----------------------------------------------------------------------------
308     // reading PNGs
309     // ----------------------------------------------------------------------------
310    
311     bool wxPNGHandler::DoCanRead( wxInputStream& stream )
312     {
313     unsigned char hdr[4];
314    
315     if ( !stream.Read(hdr, WXSIZEOF(hdr)) )
316     return false;
317    
318     return memcmp(hdr, "\211PNG", WXSIZEOF(hdr)) == 0;
319     }
320    
321     // convert data from RGB to wxImage format
322     static
323     void CopyDataFromPNG(wxImage *image,
324     unsigned char **lines,
325     png_uint_32 width,
326     png_uint_32 height,
327     int color_type)
328     {
329     Transparency transparency = Transparency_None;
330    
331     // only non NULL if transparency == Transparency_Alpha
332     unsigned char *alpha = NULL;
333    
334     // RGB of the mask colour if transparency == Transparency_Mask
335     // (but init them anyhow to avoid compiler warnings)
336     unsigned char rMask = 0,
337     gMask = 0,
338     bMask = 0;
339    
340     unsigned char *ptrDst = image->GetData();
341     if ( !(color_type & PNG_COLOR_MASK_COLOR) )
342     {
343     // grey image: GAGAGA... where G == grey component and A == alpha
344     for ( png_uint_32 y = 0; y < height; y++ )
345     {
346     const unsigned char *ptrSrc = lines[y];
347     for ( png_uint_32 x = 0; x < width; x++ )
348     {
349     unsigned char g = *ptrSrc++;
350     unsigned char a = *ptrSrc++;
351    
352     // the first time we encounter a transparent pixel we must
353     // decide about what to do about them
354     if ( !IsOpaque(a) && transparency == Transparency_None )
355     {
356     // we'll need at least the mask for this image and
357     // maybe even full alpha channel info: the former is
358     // only enough if we have alpha values of 0 and 0xff
359     // only, otherwisewe need the latter
360     transparency = CheckTransparency
361     (
362     lines,
363     x, y,
364     width, height,
365     1
366     );
367    
368     if ( transparency == Transparency_Mask )
369     {
370     // let's choose this colour for the mask: this is
371     // not a problem here as all the other pixels are
372     // grey, i.e. R == G == B which is not the case for
373     // this one so no confusion is possible
374     rMask = 0xff;
375     gMask = 0;
376     bMask = 0xff;
377     }
378     else // transparency == Transparency_Alpha
379     {
380     alpha = InitAlpha(image, x, y);
381     }
382     }
383    
384     switch ( transparency )
385     {
386     case Transparency_Mask:
387     if ( IsTransparent(a) )
388     {
389     *ptrDst++ = rMask;
390     *ptrDst++ = gMask;
391     *ptrDst++ = bMask;
392     break;
393     }
394     // else: !transparent
395    
396     // must be opaque then as otherwise we shouldn't be
397     // using the mask at all
398     wxASSERT_MSG( IsOpaque(a), _T("logic error") );
399    
400     // fall through
401    
402     case Transparency_Alpha:
403     if ( alpha )
404     *alpha++ = a;
405     // fall through
406    
407     case Transparency_None:
408     *ptrDst++ = g;
409     *ptrDst++ = g;
410     *ptrDst++ = g;
411     break;
412     }
413     }
414     }
415     }
416     else // colour image: RGBRGB...
417     {
418     for ( png_uint_32 y = 0; y < height; y++ )
419     {
420     const unsigned char *ptrSrc = lines[y];
421     for ( png_uint_32 x = 0; x < width; x++ )
422     {
423     unsigned char r = *ptrSrc++;
424     unsigned char g = *ptrSrc++;
425     unsigned char b = *ptrSrc++;
426     unsigned char a = *ptrSrc++;
427    
428     // the logic here is the same as for the grey case except
429     // where noted
430     if ( !IsOpaque(a) && transparency == Transparency_None )
431     {
432     transparency = CheckTransparency
433     (
434     lines,
435     x, y,
436     width, height,
437     3
438     );
439    
440     if ( transparency == Transparency_Mask )
441     {
442     FindMaskColour(lines, width, height,
443     rMask, gMask, bMask);
444     }
445     else // transparency == Transparency_Alpha
446     {
447     alpha = InitAlpha(image, x, y);
448     }
449    
450     }
451    
452     switch ( transparency )
453     {
454     case Transparency_Mask:
455     if ( IsTransparent(a) )
456     {
457     *ptrDst++ = rMask;
458     *ptrDst++ = gMask;
459     *ptrDst++ = bMask;
460     break;
461     }
462     else // !transparent
463     {
464     // must be opaque then as otherwise we shouldn't be
465     // using the mask at all
466     wxASSERT_MSG( IsOpaque(a), _T("logic error") );
467    
468     // if we couldn't find a unique colour for the
469     // mask, we can have real pixels with the same
470     // value as the mask and it's better to slightly
471     // change their colour than to make them
472     // transparent
473     if ( r == rMask && g == gMask && b == bMask )
474     {
475     r++;
476     }
477     }
478    
479     // fall through
480    
481     case Transparency_Alpha:
482     if ( alpha )
483     *alpha++ = a;
484     // fall through
485    
486     case Transparency_None:
487     *ptrDst++ = r;
488     *ptrDst++ = g;
489     *ptrDst++ = b;
490     break;
491     }
492     }
493     }
494     }
495    
496     if ( transparency == Transparency_Mask )
497     {
498     image->SetMaskColour(rMask, gMask, bMask);
499     }
500     }
501    
502     // temporarily disable the warning C4611 (interaction between '_setjmp' and
503     // C++ object destruction is non-portable) - I don't see any dtors here
504     #ifdef __VISUALC__
505     #pragma warning(disable:4611)
506     #endif /* VC++ */
507    
508     bool
509     wxPNGHandler::LoadFile(wxImage *image,
510     wxInputStream& stream,
511     bool verbose,
512     int WXUNUSED(index))
513     {
514     // VZ: as this function uses setjmp() the only fool-proof error handling
515     // method is to use goto (setjmp is not really C++ dtors friendly...)
516    
517     unsigned char **lines = NULL;
518     png_infop info_ptr = (png_infop) NULL;
519     wxPNGInfoStruct wxinfo;
520    
521     png_uint_32 i, width, height = 0;
522     int bit_depth, color_type, interlace_type;
523    
524     wxinfo.verbose = verbose;
525     wxinfo.stream.in = &stream;
526    
527     image->Destroy();
528    
529     png_structp png_ptr = png_create_read_struct
530     (
531     PNG_LIBPNG_VER_STRING,
532     (voidp) NULL,
533     wx_png_error,
534     wx_png_warning
535     );
536     if (!png_ptr)
537     goto error;
538    
539     // NB: please see the comment near wxPNGInfoStruct declaration for
540     // explanation why this line is mandatory
541     png_set_read_fn( png_ptr, &wxinfo, wx_PNG_stream_reader);
542    
543     info_ptr = png_create_info_struct( png_ptr );
544     if (!info_ptr)
545     goto error;
546    
547     if (setjmp(wxinfo.jmpbuf))
548     goto error;
549    
550     png_read_info( png_ptr, info_ptr );
551     png_get_IHDR( png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, (int*) NULL, (int*) NULL );
552    
553     if (color_type == PNG_COLOR_TYPE_PALETTE)
554     png_set_expand( png_ptr );
555    
556     // Fix for Bug [ 439207 ] Monochrome PNG images come up black
557     if (bit_depth < 8)
558     png_set_expand( png_ptr );
559    
560     png_set_strip_16( png_ptr );
561     png_set_packing( png_ptr );
562     if (png_get_valid( png_ptr, info_ptr, PNG_INFO_tRNS))
563     png_set_expand( png_ptr );
564     png_set_filler( png_ptr, 0xff, PNG_FILLER_AFTER );
565    
566     image->Create((int)width, (int)height, (bool) false /* no need to init pixels */);
567    
568     if (!image->Ok())
569     goto error;
570    
571     lines = (unsigned char **)malloc( (size_t)(height * sizeof(unsigned char *)) );
572     if ( !lines )
573     goto error;
574    
575     for (i = 0; i < height; i++)
576     {
577     if ((lines[i] = (unsigned char *)malloc( (size_t)(width * (sizeof(unsigned char) * 4)))) == NULL)
578     {
579     for ( unsigned int n = 0; n < i; n++ )
580     free( lines[n] );
581     goto error;
582     }
583     }
584    
585     png_read_image( png_ptr, lines );
586     png_read_end( png_ptr, info_ptr );
587    
588     #if wxUSE_PALETTE
589     if (color_type == PNG_COLOR_TYPE_PALETTE)
590     {
591     const size_t ncolors = info_ptr->num_palette;
592     unsigned char* r = new unsigned char[ncolors];
593     unsigned char* g = new unsigned char[ncolors];
594     unsigned char* b = new unsigned char[ncolors];
595    
596     for (size_t j = 0; j < ncolors; j++)
597     {
598     r[j] = info_ptr->palette[j].red;
599     g[j] = info_ptr->palette[j].green;
600     b[j] = info_ptr->palette[j].blue;
601     }
602    
603     image->SetPalette(wxPalette(ncolors, r, g, b));
604     delete[] r;
605     delete[] g;
606     delete[] b;
607     }
608     #endif // wxUSE_PALETTE
609    
610     png_destroy_read_struct( &png_ptr, &info_ptr, (png_infopp) NULL );
611    
612     // loaded successfully, now init wxImage with this data
613     CopyDataFromPNG(image, lines, width, height, color_type);
614    
615     for ( i = 0; i < height; i++ )
616     free( lines[i] );
617     free( lines );
618    
619     return true;
620    
621     error:
622     if (verbose)
623     wxLogError(_("Couldn't load a PNG image - file is corrupted or not enough memory."));
624    
625     if ( image->Ok() )
626     {
627     image->Destroy();
628     }
629    
630     if ( lines )
631     {
632     for ( unsigned int n = 0; n < height; n++ )
633     free( lines[n] );
634    
635     free( lines );
636     }
637    
638     if ( png_ptr )
639     {
640     if ( info_ptr )
641     {
642     png_destroy_read_struct( &png_ptr, &info_ptr, (png_infopp) NULL );
643     free(info_ptr);
644     }
645     else
646     png_destroy_read_struct( &png_ptr, (png_infopp) NULL, (png_infopp) NULL );
647     }
648     return false;
649     }
650    
651     // ----------------------------------------------------------------------------
652     // writing PNGs
653     // ----------------------------------------------------------------------------
654    
655     bool wxPNGHandler::SaveFile( wxImage *image, wxOutputStream& stream, bool verbose )
656     {
657     wxPNGInfoStruct wxinfo;
658    
659     wxinfo.verbose = verbose;
660     wxinfo.stream.out = &stream;
661    
662     png_structp png_ptr = png_create_write_struct
663     (
664     PNG_LIBPNG_VER_STRING,
665     NULL,
666     wx_png_error,
667     wx_png_warning
668     );
669     if (!png_ptr)
670     {
671     if (verbose)
672     wxLogError(_("Couldn't save PNG image."));
673     return false;
674     }
675    
676     png_infop info_ptr = png_create_info_struct(png_ptr);
677     if (info_ptr == NULL)
678     {
679     png_destroy_write_struct( &png_ptr, (png_infopp)NULL );
680     if (verbose)
681     wxLogError(_("Couldn't save PNG image."));
682     return false;
683     }
684    
685     if (setjmp(wxinfo.jmpbuf))
686     {
687     png_destroy_write_struct( &png_ptr, (png_infopp)NULL );
688     if (verbose)
689     wxLogError(_("Couldn't save PNG image."));
690     return false;
691     }
692    
693     // NB: please see the comment near wxPNGInfoStruct declaration for
694     // explanation why this line is mandatory
695     png_set_write_fn( png_ptr, &wxinfo, wx_PNG_stream_writer, NULL);
696    
697     const int iColorType = image->HasOption(wxIMAGE_OPTION_PNG_FORMAT)
698     ? image->GetOptionInt(wxIMAGE_OPTION_PNG_FORMAT)
699     : wxPNG_TYPE_COLOUR;
700     const int iBitDepth = image->HasOption(wxIMAGE_OPTION_PNG_BITDEPTH)
701     ? image->GetOptionInt(wxIMAGE_OPTION_PNG_BITDEPTH)
702     : 8;
703    
704     wxASSERT_MSG( iBitDepth == 8 || iBitDepth == 16,
705     _T("PNG bit depth must be 8 or 16") );
706    
707     bool bHasAlpha = image->HasAlpha();
708     bool bHasMask = image->HasMask();
709     bool bUseAlpha = bHasAlpha || bHasMask;
710    
711     int iPngColorType;
712     if ( iColorType==wxPNG_TYPE_COLOUR )
713     {
714     iPngColorType = bUseAlpha ? PNG_COLOR_TYPE_RGB_ALPHA
715     : PNG_COLOR_TYPE_RGB;
716     }
717     else
718     {
719     iPngColorType = bUseAlpha ? PNG_COLOR_TYPE_GRAY_ALPHA
720     : PNG_COLOR_TYPE_GRAY;
721     }
722    
723     png_set_IHDR( png_ptr, info_ptr, image->GetWidth(), image->GetHeight(),
724     iBitDepth, iPngColorType,
725     PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE,
726     PNG_FILTER_TYPE_BASE);
727    
728     int iElements;
729     png_color_8 sig_bit;
730    
731     if ( iPngColorType & PNG_COLOR_MASK_COLOR )
732     {
733     sig_bit.red =
734     sig_bit.green =
735     sig_bit.blue = (png_byte)iBitDepth;
736     iElements = 3;
737     }
738     else // grey
739     {
740     sig_bit.gray = (png_byte)iBitDepth;
741     iElements = 1;
742     }
743    
744     if ( iPngColorType & PNG_COLOR_MASK_ALPHA )
745     {
746     sig_bit.alpha = (png_byte)iBitDepth;
747     iElements++;
748     }
749    
750     if ( iBitDepth == 16 )
751     iElements *= 2;
752    
753     png_set_sBIT( png_ptr, info_ptr, &sig_bit );
754     png_write_info( png_ptr, info_ptr );
755     png_set_shift( png_ptr, &sig_bit );
756     png_set_packing( png_ptr );
757    
758     unsigned char *
759     data = (unsigned char *)malloc( image->GetWidth() * iElements );
760     if ( !data )
761     {
762     png_destroy_write_struct( &png_ptr, (png_infopp)NULL );
763     return false;
764     }
765    
766     unsigned char *
767     pAlpha = (unsigned char *)(bHasAlpha ? image->GetAlpha() : NULL);
768     int iHeight = image->GetHeight();
769     int iWidth = image->GetWidth();
770    
771     unsigned char uchMaskRed = 0, uchMaskGreen = 0, uchMaskBlue = 0;
772    
773     if ( bHasMask )
774     {
775     uchMaskRed = image->GetMaskRed();
776     uchMaskGreen = image->GetMaskGreen();
777     uchMaskBlue = image->GetMaskBlue();
778     }
779    
780     unsigned char *pColors = image->GetData();
781    
782     for (int y = 0; y != iHeight; ++y)
783     {
784     unsigned char *pData = data;
785     for (int x = 0; x != iWidth; x++)
786     {
787     unsigned char uchRed = *pColors++;
788     unsigned char uchGreen = *pColors++;
789     unsigned char uchBlue = *pColors++;
790    
791     switch ( iColorType )
792     {
793     default:
794     wxFAIL_MSG( _T("unknown wxPNG_TYPE_XXX") );
795     // fall through
796    
797     case wxPNG_TYPE_COLOUR:
798     *pData++ = uchRed;
799     if ( iBitDepth == 16 )
800     *pData++ = 0;
801     *pData++ = uchGreen;
802     if ( iBitDepth == 16 )
803     *pData++ = 0;
804     *pData++ = uchBlue;
805     if ( iBitDepth == 16 )
806     *pData++ = 0;
807     break;
808    
809     case wxPNG_TYPE_GREY:
810     {
811     // where do these coefficients come from? maybe we
812     // should have image options for them as well?
813     unsigned uiColor =
814     (unsigned) (76.544*(unsigned)uchRed +
815     150.272*(unsigned)uchGreen +
816     36.864*(unsigned)uchBlue);
817    
818     *pData++ = (unsigned char)((uiColor >> 8) & 0xFF);
819     if ( iBitDepth == 16 )
820     *pData++ = (unsigned char)(uiColor & 0xFF);
821     }
822     break;
823    
824     case wxPNG_TYPE_GREY_RED:
825     *pData++ = uchRed;
826     if ( iBitDepth == 16 )
827     *pData++ = 0;
828     break;
829     }
830    
831     if ( bUseAlpha )
832     {
833     unsigned char uchAlpha = 255;
834     if ( bHasAlpha )
835     uchAlpha = *pAlpha++;
836    
837     if ( bHasMask )
838     {
839     if ( (uchRed == uchMaskRed)
840     && (uchGreen == uchMaskGreen)
841     && (uchBlue == uchMaskBlue) )
842     uchAlpha = 0;
843     }
844    
845     *pData++ = uchAlpha;
846     if ( iBitDepth == 16 )
847     *pData++ = 0;
848     }
849     }
850    
851     png_bytep row_ptr = data;
852     png_write_rows( png_ptr, &row_ptr, 1 );
853     }
854    
855     free(data);
856     png_write_end( png_ptr, info_ptr );
857     png_destroy_write_struct( &png_ptr, (png_infopp)&info_ptr );
858    
859     return true;
860     }
861    
862     #ifdef __VISUALC__
863     #pragma warning(default:4611)
864     #endif /* VC++ */
865    
866     #endif // wxUSE_STREAMS
867    
868     #endif // wxUSE_LIBPNG

  ViewVC Help
Powered by ViewVC 1.1.22