• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* libs/graphics/images/SkImageDecoder_libpng.cpp
2 **
3 ** Copyright 2006, The Android Open Source Project
4 **
5 ** Licensed under the Apache License, Version 2.0 (the "License");
6 ** you may not use this file except in compliance with the License.
7 ** You may obtain a copy of the License at
8 **
9 **     http://www.apache.org/licenses/LICENSE-2.0
10 **
11 ** Unless required by applicable law or agreed to in writing, software
12 ** distributed under the License is distributed on an "AS IS" BASIS,
13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 ** See the License for the specific language governing permissions and
15 ** limitations under the License.
16 */
17 
18 #include "SkImageDecoder.h"
19 #include "SkImageEncoder.h"
20 #include "SkColor.h"
21 #include "SkColorPriv.h"
22 #include "SkDither.h"
23 #include "SkMath.h"
24 #include "SkScaledBitmapSampler.h"
25 #include "SkStream.h"
26 #include "SkTemplates.h"
27 #include "SkUtils.h"
28 
29 extern "C" {
30 #include "png.h"
31 }
32 
33 class SkPNGImageIndex {
34 public:
SkPNGImageIndex()35     SkPNGImageIndex() {
36         inputStream = NULL;
37         png_ptr = NULL;
38     }
~SkPNGImageIndex()39     virtual ~SkPNGImageIndex() {
40         if (png_ptr) {
41             png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL);
42         }
43         if (inputStream) {
44             delete inputStream;
45         }
46     }
47     png_structp png_ptr;
48     png_infop info_ptr;
49     SkStream *inputStream;
50 };
51 
52 class SkPNGImageDecoder : public SkImageDecoder {
53 public:
SkPNGImageDecoder()54     SkPNGImageDecoder() {
55         index = NULL;
56     }
getFormat() const57     virtual Format getFormat() const {
58         return kPNG_Format;
59     }
~SkPNGImageDecoder()60     virtual ~SkPNGImageDecoder() {
61         if (index) {
62             delete index;
63         }
64     }
65 
66 protected:
67     virtual bool onBuildTileIndex(SkStream *stream,
68              int *width, int *height);
69     virtual bool onDecodeRegion(SkBitmap* bitmap, SkIRect rect);
70     virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode);
71 
72 private:
73     bool onDecodeInit(SkStream* stream, png_structp *png_ptrp,
74             png_infop *info_ptrp);
75     bool decodePalette(png_structp png_ptr, png_infop info_ptr,
76         bool *hasAlphap, bool *reallyHasAlphap, SkColorTable **colorTablep);
77     bool getBitmapConfig(png_structp png_ptr, png_infop info_ptr,
78         SkBitmap::Config *config, bool *hasAlpha, bool *doDither,
79         SkPMColor *theTranspColor);
80     SkPNGImageIndex *index;
81 };
82 
83 #ifndef png_jmpbuf
84 #  define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf)
85 #endif
86 
87 #define PNG_BYTES_TO_CHECK 4
88 
89 /* Automatically clean up after throwing an exception */
90 struct PNGAutoClean {
PNGAutoCleanPNGAutoClean91     PNGAutoClean(png_structp p, png_infop i): png_ptr(p), info_ptr(i) {}
~PNGAutoCleanPNGAutoClean92     ~PNGAutoClean() {
93         png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL);
94     }
95 private:
96     png_structp png_ptr;
97     png_infop info_ptr;
98 };
99 
sk_read_fn(png_structp png_ptr,png_bytep data,png_size_t length)100 static void sk_read_fn(png_structp png_ptr, png_bytep data, png_size_t length) {
101     SkStream* sk_stream = (SkStream*) png_ptr->io_ptr;
102     size_t bytes = sk_stream->read(data, length);
103     if (bytes != length) {
104         png_error(png_ptr, "Read Error!");
105     }
106 }
107 
sk_seek_fn(png_structp png_ptr,png_uint_32 offset)108 static void sk_seek_fn(png_structp png_ptr, png_uint_32 offset) {
109     SkStream* sk_stream = (SkStream*) png_ptr->io_ptr;
110     sk_stream->rewind();
111     (void)sk_stream->skip(offset);
112 }
113 
sk_read_user_chunk(png_structp png_ptr,png_unknown_chunkp chunk)114 static int sk_read_user_chunk(png_structp png_ptr, png_unknown_chunkp chunk) {
115     SkImageDecoder::Peeker* peeker =
116                     (SkImageDecoder::Peeker*)png_get_user_chunk_ptr(png_ptr);
117     // peek() returning true means continue decoding
118     return peeker->peek((const char*)chunk->name, chunk->data, chunk->size) ?
119             1 : -1;
120 }
121 
sk_error_fn(png_structp png_ptr,png_const_charp msg)122 static void sk_error_fn(png_structp png_ptr, png_const_charp msg) {
123 #if 0
124     SkDebugf("------ png error %s\n", msg);
125 #endif
126     longjmp(png_jmpbuf(png_ptr), 1);
127 }
128 
skip_src_rows(png_structp png_ptr,uint8_t storage[],int count)129 static void skip_src_rows(png_structp png_ptr, uint8_t storage[], int count) {
130     for (int i = 0; i < count; i++) {
131         uint8_t* tmp = storage;
132         png_read_rows(png_ptr, &tmp, png_bytepp_NULL, 1);
133     }
134 }
135 
pos_le(int value,int max)136 static bool pos_le(int value, int max) {
137     return value > 0 && value <= max;
138 }
139 
substituteTranspColor(SkBitmap * bm,SkPMColor match)140 static bool substituteTranspColor(SkBitmap* bm, SkPMColor match) {
141     SkASSERT(bm->config() == SkBitmap::kARGB_8888_Config);
142 
143     bool reallyHasAlpha = false;
144 
145     for (int y = bm->height() - 1; y >= 0; --y) {
146         SkPMColor* p = bm->getAddr32(0, y);
147         for (int x = bm->width() - 1; x >= 0; --x) {
148             if (match == *p) {
149                 *p = 0;
150                 reallyHasAlpha = true;
151             }
152             p += 1;
153         }
154     }
155     return reallyHasAlpha;
156 }
157 
canUpscalePaletteToConfig(SkBitmap::Config dstConfig,bool srcHasAlpha)158 static bool canUpscalePaletteToConfig(SkBitmap::Config dstConfig,
159                                       bool srcHasAlpha) {
160     switch (dstConfig) {
161         case SkBitmap::kARGB_8888_Config:
162         case SkBitmap::kARGB_4444_Config:
163             return true;
164         case SkBitmap::kRGB_565_Config:
165             // only return true if the src is opaque (since 565 is opaque)
166             return !srcHasAlpha;
167         default:
168             return false;
169     }
170 }
171 
172 // call only if color_type is PALETTE. Returns true if the ctable has alpha
hasTransparencyInPalette(png_structp png_ptr,png_infop info_ptr)173 static bool hasTransparencyInPalette(png_structp png_ptr, png_infop info_ptr) {
174     png_bytep trans;
175     int num_trans;
176 
177     if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
178         png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, NULL);
179         return num_trans > 0;
180     }
181     return false;
182 }
183 
onDecodeInit(SkStream * sk_stream,png_structp * png_ptrp,png_infop * info_ptrp)184 bool SkPNGImageDecoder::onDecodeInit(SkStream* sk_stream,
185         png_structp *png_ptrp, png_infop *info_ptrp)
186 {
187     /* Create and initialize the png_struct with the desired error handler
188     * functions.  If you want to use the default stderr and longjump method,
189     * you can supply NULL for the last three parameters.  We also supply the
190     * the compiler header file version, so that we know if the application
191     * was compiled with a compatible version of the library.  */
192     png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
193         NULL, sk_error_fn, NULL);
194     //   png_voidp user_error_ptr, user_error_fn, user_warning_fn);
195     if (png_ptr == NULL) {
196         return false;
197     }
198     *png_ptrp = png_ptr;
199 
200     /* Allocate/initialize the memory for image information. */
201     png_infop info_ptr = png_create_info_struct(png_ptr);
202     if (info_ptr == NULL) {
203         png_destroy_read_struct(&png_ptr, png_infopp_NULL, png_infopp_NULL);
204         return false;
205     }
206     *info_ptrp = info_ptr;
207 
208     /* Set error handling if you are using the setjmp/longjmp method (this is
209     * the normal method of doing things with libpng).  REQUIRED unless you
210     * set up your own error handlers in the png_create_read_struct() earlier.
211     */
212     if (setjmp(png_jmpbuf(png_ptr))) {
213         return false;
214     }
215 
216     /* If you are using replacement read functions, instead of calling
217     * png_init_io() here you would call:
218     */
219     png_set_read_fn(png_ptr, (void *)sk_stream, sk_read_fn);
220     png_set_seek_fn(png_ptr, sk_seek_fn);
221     /* where user_io_ptr is a structure you want available to the callbacks */
222     /* If we have already read some of the signature */
223     // png_set_sig_bytes(png_ptr, 0 /* sig_read */ );
224 
225     // hookup our peeker so we can see any user-chunks the caller may be interested in
226     png_set_keep_unknown_chunks(png_ptr, PNG_HANDLE_CHUNK_ALWAYS, (png_byte*)"", 0);
227     if (this->getPeeker()) {
228         png_set_read_user_chunk_fn(png_ptr, (png_voidp)this->getPeeker(), sk_read_user_chunk);
229     }
230 
231     /* The call to png_read_info() gives us all of the information from the
232     * PNG file before the first IDAT (image data chunk). */
233     png_read_info(png_ptr, info_ptr);
234     png_uint_32 origWidth, origHeight;
235     int bit_depth, color_type, interlace_type;
236     png_get_IHDR(png_ptr, info_ptr, &origWidth, &origHeight, &bit_depth,
237             &color_type, &interlace_type, int_p_NULL, int_p_NULL);
238 
239     /* tell libpng to strip 16 bit/color files down to 8 bits/color */
240     if (bit_depth == 16) {
241         png_set_strip_16(png_ptr);
242     }
243     /* Extract multiple pixels with bit depths of 1, 2, and 4 from a single
244      * byte into separate bytes (useful for paletted and grayscale images). */
245     if (bit_depth < 8) {
246         png_set_packing(png_ptr);
247     }
248     /* Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel */
249     if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) {
250         png_set_gray_1_2_4_to_8(png_ptr);
251     }
252 
253     /* Make a grayscale image into RGB. */
254     if (color_type == PNG_COLOR_TYPE_GRAY ||
255         color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
256         png_set_gray_to_rgb(png_ptr);
257     }
258     return true;
259 }
260 
onDecode(SkStream * sk_stream,SkBitmap * decodedBitmap,Mode mode)261 bool SkPNGImageDecoder::onDecode(SkStream* sk_stream, SkBitmap* decodedBitmap,
262                                  Mode mode) {
263     png_structp png_ptr;
264     png_infop info_ptr;
265 
266     if (onDecodeInit(sk_stream, &png_ptr, &info_ptr) == false) {
267         return false;
268     }
269 
270     if (setjmp(png_jmpbuf(png_ptr))) {
271         return false;
272     }
273 
274     PNGAutoClean autoClean(png_ptr, info_ptr);
275 
276     png_uint_32 origWidth, origHeight;
277     int bit_depth, color_type, interlace_type;
278     png_get_IHDR(png_ptr, info_ptr, &origWidth, &origHeight, &bit_depth,
279             &color_type, &interlace_type, int_p_NULL, int_p_NULL);
280 
281     SkBitmap::Config    config;
282     bool                hasAlpha = false;
283     bool                doDither = this->getDitherImage();
284     SkPMColor           theTranspColor = 0; // 0 tells us not to try to match
285 
286     if (getBitmapConfig(png_ptr, info_ptr, &config, &hasAlpha,
287                 &doDither, &theTranspColor) == false) {
288         return false;
289     }
290 
291     const int sampleSize = this->getSampleSize();
292     SkScaledBitmapSampler sampler(origWidth, origHeight, sampleSize);
293 
294     decodedBitmap->setConfig(config, sampler.scaledWidth(),
295                              sampler.scaledHeight(), 0);
296     if (SkImageDecoder::kDecodeBounds_Mode == mode) {
297         return true;
298     }
299 
300     // from here down we are concerned with colortables and pixels
301 
302     // we track if we actually see a non-opaque pixels, since sometimes a PNG sets its colortype
303     // to |= PNG_COLOR_MASK_ALPHA, but all of its pixels are in fact opaque. We care, since we
304     // draw lots faster if we can flag the bitmap has being opaque
305     bool reallyHasAlpha = false;
306     SkColorTable* colorTable = NULL;
307 
308     if (color_type == PNG_COLOR_TYPE_PALETTE) {
309         decodePalette(png_ptr, info_ptr, &hasAlpha,
310                 &reallyHasAlpha, &colorTable);
311     }
312 
313     SkAutoUnref aur(colorTable);
314 
315     if (!this->allocPixelRef(decodedBitmap,
316                              SkBitmap::kIndex8_Config == config ?
317                                 colorTable : NULL)) {
318         return false;
319     }
320 
321     SkAutoLockPixels alp(*decodedBitmap);
322 
323     /* Add filler (or alpha) byte (before/after each RGB triplet) */
324     if (color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_GRAY) {
325         png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER);
326     }
327 
328     /* Turn on interlace handling.  REQUIRED if you are not using
329     * png_read_image().  To see how to handle interlacing passes,
330     * see the png_read_row() method below:
331     */
332     const int number_passes = interlace_type != PNG_INTERLACE_NONE ?
333                         png_set_interlace_handling(png_ptr) : 1;
334 
335     /* Optional call to gamma correct and add the background to the palette
336     * and update info structure.  REQUIRED if you are expecting libpng to
337     * update the palette for you (ie you selected such a transform above).
338     */
339     png_read_update_info(png_ptr, info_ptr);
340 
341     if (SkBitmap::kIndex8_Config == config && 1 == sampleSize) {
342         for (int i = 0; i < number_passes; i++) {
343             for (png_uint_32 y = 0; y < origHeight; y++) {
344                 uint8_t* bmRow = decodedBitmap->getAddr8(0, y);
345                 png_read_rows(png_ptr, &bmRow, png_bytepp_NULL, 1);
346             }
347         }
348     } else {
349         SkScaledBitmapSampler::SrcConfig sc;
350         int srcBytesPerPixel = 4;
351 
352         if (colorTable != NULL) {
353             sc = SkScaledBitmapSampler::kIndex;
354             srcBytesPerPixel = 1;
355         } else if (hasAlpha) {
356             sc = SkScaledBitmapSampler::kRGBA;
357         } else {
358             sc = SkScaledBitmapSampler::kRGBX;
359         }
360 
361         /*  We have to pass the colortable explicitly, since we may have one
362             even if our decodedBitmap doesn't, due to the request that we
363             upscale png's palette to a direct model
364          */
365         SkAutoLockColors ctLock(colorTable);
366         if (!sampler.begin(decodedBitmap, sc, doDither, ctLock.colors())) {
367             return false;
368         }
369         const int height = decodedBitmap->height();
370 
371         if (number_passes > 1) {
372             SkAutoMalloc storage(origWidth * origHeight * srcBytesPerPixel);
373             uint8_t* base = (uint8_t*)storage.get();
374             size_t rb = origWidth * srcBytesPerPixel;
375 
376             for (int i = 0; i < number_passes; i++) {
377                 uint8_t* row = base;
378                 for (png_uint_32 y = 0; y < origHeight; y++) {
379                     uint8_t* bmRow = row;
380                     png_read_rows(png_ptr, &bmRow, png_bytepp_NULL, 1);
381                     row += rb;
382                 }
383             }
384             // now sample it
385             base += sampler.srcY0() * rb;
386             for (int y = 0; y < height; y++) {
387                 reallyHasAlpha |= sampler.next(base);
388                 base += sampler.srcDY() * rb;
389             }
390         } else {
391             SkAutoMalloc storage(origWidth * srcBytesPerPixel);
392             uint8_t* srcRow = (uint8_t*)storage.get();
393             skip_src_rows(png_ptr, srcRow, sampler.srcY0());
394 
395             for (int y = 0; y < height; y++) {
396                 uint8_t* tmp = srcRow;
397                 png_read_rows(png_ptr, &tmp, png_bytepp_NULL, 1);
398                 reallyHasAlpha |= sampler.next(srcRow);
399                 if (y < height - 1) {
400                     skip_src_rows(png_ptr, srcRow, sampler.srcDY() - 1);
401                 }
402             }
403 
404             // skip the rest of the rows (if any)
405             png_uint_32 read = (height - 1) * sampler.srcDY() +
406                                sampler.srcY0() + 1;
407             SkASSERT(read <= origHeight);
408             skip_src_rows(png_ptr, srcRow, origHeight - read);
409         }
410     }
411 
412     /* read rest of file, and get additional chunks in info_ptr - REQUIRED */
413     png_read_end(png_ptr, info_ptr);
414 
415     if (0 != theTranspColor) {
416         reallyHasAlpha |= substituteTranspColor(decodedBitmap, theTranspColor);
417     }
418     decodedBitmap->setIsOpaque(!reallyHasAlpha);
419     return true;
420 }
421 
onBuildTileIndex(SkStream * sk_stream,int * width,int * height)422 bool SkPNGImageDecoder::onBuildTileIndex(SkStream* sk_stream, int *width,
423         int *height) {
424     png_structp png_ptr;
425     png_infop   info_ptr;
426 
427     this->index = new SkPNGImageIndex();
428 
429     if (onDecodeInit(sk_stream, &png_ptr, &info_ptr) == false) {
430         return false;
431     }
432 
433     int bit_depth, color_type, interlace_type;
434     png_uint_32 origWidth, origHeight;
435     png_get_IHDR(png_ptr, info_ptr, &origWidth, &origHeight, &bit_depth,
436             &color_type, &interlace_type, int_p_NULL, int_p_NULL);
437 
438     *width = origWidth;
439     *height = origHeight;
440 
441     png_build_index(png_ptr);
442     this->index->png_ptr = png_ptr;
443     this->index->info_ptr = info_ptr;
444     return true;
445 }
446 
getBitmapConfig(png_structp png_ptr,png_infop info_ptr,SkBitmap::Config * configp,bool * hasAlphap,bool * doDitherp,SkPMColor * theTranspColorp)447 bool SkPNGImageDecoder::getBitmapConfig(png_structp png_ptr, png_infop info_ptr,
448         SkBitmap::Config *configp, bool *hasAlphap, bool *doDitherp,
449         SkPMColor *theTranspColorp) {
450     png_uint_32 origWidth, origHeight;
451     int bit_depth, color_type, interlace_type;
452     png_get_IHDR(png_ptr, info_ptr, &origWidth, &origHeight, &bit_depth,
453             &color_type, &interlace_type, int_p_NULL, int_p_NULL);
454 
455     // check for sBIT chunk data, in case we should disable dithering because
456     // our data is not truely 8bits per component
457     if (*doDitherp) {
458 #if 0
459         SkDebugf("----- sBIT %d %d %d %d\n", info_ptr->sig_bit.red,
460                  info_ptr->sig_bit.green, info_ptr->sig_bit.blue,
461                  info_ptr->sig_bit.alpha);
462 #endif
463         // 0 seems to indicate no information available
464         if (pos_le(info_ptr->sig_bit.red, SK_R16_BITS) &&
465                 pos_le(info_ptr->sig_bit.green, SK_G16_BITS) &&
466                 pos_le(info_ptr->sig_bit.blue, SK_B16_BITS)) {
467             *doDitherp = false;
468         }
469     }
470 
471     if (color_type == PNG_COLOR_TYPE_PALETTE) {
472         bool paletteHasAlpha = hasTransparencyInPalette(png_ptr, info_ptr);
473         *configp = this->getPrefConfig(kIndex_SrcDepth, paletteHasAlpha);
474         // now see if we can upscale to their requested config
475         if (!canUpscalePaletteToConfig(*configp, paletteHasAlpha)) {
476             *configp = SkBitmap::kIndex8_Config;
477         }
478     } else {
479         png_color_16p   transpColor = NULL;
480         int             numTransp = 0;
481 
482         png_get_tRNS(png_ptr, info_ptr, NULL, &numTransp, &transpColor);
483 
484         bool valid = png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS);
485 
486         if (valid && numTransp == 1 && transpColor != NULL) {
487             /*  Compute our transparent color, which we'll match against later.
488                 We don't really handle 16bit components properly here, since we
489                 do our compare *after* the values have been knocked down to 8bit
490                 which means we will find more matches than we should. The real
491                 fix seems to be to see the actual 16bit components, do the
492                 compare, and then knock it down to 8bits ourselves.
493             */
494             if (color_type & PNG_COLOR_MASK_COLOR) {
495                 if (16 == bit_depth) {
496                     *theTranspColorp = SkPackARGB32(0xFF, transpColor->red >> 8,
497                               transpColor->green >> 8, transpColor->blue >> 8);
498                 } else {
499                     *theTranspColorp = SkPackARGB32(0xFF, transpColor->red,
500                                       transpColor->green, transpColor->blue);
501                 }
502             } else {    // gray
503                 if (16 == bit_depth) {
504                     *theTranspColorp = SkPackARGB32(0xFF, transpColor->gray >> 8,
505                               transpColor->gray >> 8, transpColor->gray >> 8);
506                 } else {
507                     *theTranspColorp = SkPackARGB32(0xFF, transpColor->gray,
508                                           transpColor->gray, transpColor->gray);
509                 }
510             }
511         }
512 
513         if (valid ||
514                 PNG_COLOR_TYPE_RGB_ALPHA == color_type ||
515                 PNG_COLOR_TYPE_GRAY_ALPHA == color_type) {
516             *hasAlphap = true;
517         }
518         *configp = this->getPrefConfig(k32Bit_SrcDepth, *hasAlphap);
519         // now match the request against our capabilities
520         if (*hasAlphap) {
521             if (*configp != SkBitmap::kARGB_4444_Config) {
522                 *configp = SkBitmap::kARGB_8888_Config;
523             }
524         } else {
525             if (*configp != SkBitmap::kRGB_565_Config &&
526                 *configp != SkBitmap::kARGB_4444_Config) {
527                 *configp = SkBitmap::kARGB_8888_Config;
528             }
529         }
530     }
531 
532     // sanity check for size
533     {
534         Sk64 size;
535         size.setMul(origWidth, origHeight);
536         if (size.isNeg() || !size.is32()) {
537             return false;
538         }
539         // now check that if we are 4-bytes per pixel, we also don't overflow
540         if (size.get32() > (0x7FFFFFFF >> 2)) {
541             return false;
542         }
543     }
544 
545     if (!this->chooseFromOneChoice(*configp, origWidth, origHeight)) {
546         return false;
547     }
548     return true;
549 }
550 
decodePalette(png_structp png_ptr,png_infop info_ptr,bool * hasAlphap,bool * reallyHasAlphap,SkColorTable ** colorTablep)551 bool SkPNGImageDecoder::decodePalette(png_structp png_ptr, png_infop info_ptr,
552         bool *hasAlphap, bool *reallyHasAlphap, SkColorTable **colorTablep) {
553     int num_palette;
554     png_colorp palette;
555     png_bytep trans;
556     int num_trans;
557     bool reallyHasAlpha = false;
558     SkColorTable* colorTable = NULL;
559 
560     png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette);
561 
562     /*  BUGGY IMAGE WORKAROUND
563 
564         We hit some images (e.g. fruit_.png) who contain bytes that are == colortable_count
565         which is a problem since we use the byte as an index. To work around this we grow
566         the colortable by 1 (if its < 256) and duplicate the last color into that slot.
567         */
568     int colorCount = num_palette + (num_palette < 256);
569 
570     colorTable = SkNEW_ARGS(SkColorTable, (colorCount));
571 
572     SkPMColor* colorPtr = colorTable->lockColors();
573     if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
574         png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, NULL);
575         *hasAlphap = (num_trans > 0);
576     } else {
577         num_trans = 0;
578         colorTable->setFlags(colorTable->getFlags() | SkColorTable::kColorsAreOpaque_Flag);
579     }
580     // check for bad images that might make us crash
581     if (num_trans > num_palette) {
582         num_trans = num_palette;
583     }
584 
585     int index = 0;
586     int transLessThanFF = 0;
587 
588     for (; index < num_trans; index++) {
589         transLessThanFF |= (int)*trans - 0xFF;
590         *colorPtr++ = SkPreMultiplyARGB(*trans++, palette->red, palette->green, palette->blue);
591         palette++;
592     }
593     reallyHasAlpha |= (transLessThanFF < 0);
594 
595     for (; index < num_palette; index++) {
596         *colorPtr++ = SkPackARGB32(0xFF, palette->red, palette->green, palette->blue);
597         palette++;
598     }
599 
600     // see BUGGY IMAGE WORKAROUND comment above
601     if (num_palette < 256) {
602         *colorPtr = colorPtr[-1];
603     }
604     colorTable->unlockColors(true);
605     *colorTablep = colorTable;
606     *reallyHasAlphap = reallyHasAlpha;
607     return true;
608 }
609 
onDecodeRegion(SkBitmap * bm,SkIRect rect)610 bool SkPNGImageDecoder::onDecodeRegion(SkBitmap* bm, SkIRect rect) {
611     int i;
612     png_structp png_ptr = this->index->png_ptr;
613     png_infop info_ptr = this->index->info_ptr;
614     if (setjmp(png_jmpbuf(png_ptr))) {
615         return false;
616     }
617 
618     int requestedHeight = rect.fBottom - rect.fTop;
619     int requestedWidth = rect.fRight - rect.fLeft;
620 
621     png_uint_32 origWidth, origHeight;
622     int bit_depth, color_type, interlace_type;
623     png_get_IHDR(png_ptr, info_ptr, &origWidth, &origHeight, &bit_depth,
624             &color_type, &interlace_type, int_p_NULL, int_p_NULL);
625 
626     SkBitmap::Config    config;
627     bool                hasAlpha = false;
628     bool                doDither = this->getDitherImage();
629     SkPMColor           theTranspColor = 0; // 0 tells us not to try to match
630 
631     if (getBitmapConfig(png_ptr, info_ptr, &config, &hasAlpha,
632                 &doDither, &theTranspColor) == false) {
633         return false;
634     }
635 
636     const int sampleSize = this->getSampleSize();
637     SkScaledBitmapSampler sampler(origWidth, requestedHeight, sampleSize);
638 
639     SkBitmap *decodedBitmap = new SkBitmap;
640     SkAutoTDelete<SkBitmap> adb(decodedBitmap);
641 
642     decodedBitmap->setConfig(config, sampler.scaledWidth(),
643                              sampler.scaledHeight(), 0);
644 
645     // from here down we are concerned with colortables and pixels
646 
647     // we track if we actually see a non-opaque pixels, since sometimes a PNG sets its colortype
648     // to |= PNG_COLOR_MASK_ALPHA, but all of its pixels are in fact opaque. We care, since we
649     // draw lots faster if we can flag the bitmap has being opaque
650     bool reallyHasAlpha = false;
651     SkColorTable* colorTable = NULL;
652 
653     if (color_type == PNG_COLOR_TYPE_PALETTE) {
654         decodePalette(png_ptr, info_ptr, &hasAlpha,
655                 &reallyHasAlpha, &colorTable);
656     }
657 
658     SkAutoUnref aur(colorTable);
659 
660     if (!this->allocPixelRef(decodedBitmap,
661                              SkBitmap::kIndex8_Config == config ?
662                                 colorTable : NULL)) {
663         return false;
664     }
665 
666     SkAutoLockPixels alp(*decodedBitmap);
667 
668     /* Add filler (or alpha) byte (before/after each RGB triplet) */
669     if (color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_GRAY) {
670         png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER);
671     }
672 
673     /* Turn on interlace handling.  REQUIRED if you are not using
674     * png_read_image().  To see how to handle interlacing passes,
675     * see the png_read_row() method below:
676     */
677     const int number_passes = interlace_type != PNG_INTERLACE_NONE ?
678                         png_set_interlace_handling(png_ptr) : 1;
679 
680     /* Optional call to gamma correct and add the background to the palette
681     * and update info structure.  REQUIRED if you are expecting libpng to
682     * update the palette for you (ie you selected such a transform above).
683     */
684     png_ptr->pass = 0;
685     png_read_update_info(png_ptr, info_ptr);
686 
687     SkDebugf("Request size %d %d\n", requestedWidth, requestedHeight);
688 
689     int actualTop = rect.fTop;
690 
691     if (SkBitmap::kIndex8_Config == config && 1 == sampleSize) {
692         for (int i = 0; i < number_passes; i++) {
693             png_configure_decoder(png_ptr, &actualTop, i);
694             for (int j = 0; j < rect.fTop - actualTop; j++) {
695                 uint8_t* bmRow = decodedBitmap->getAddr8(0, 0);
696                 png_read_rows(png_ptr, &bmRow, png_bytepp_NULL, 1);
697             }
698             for (png_uint_32 y = 0; y < origHeight; y++) {
699                 uint8_t* bmRow = decodedBitmap->getAddr8(0, y);
700                 png_read_rows(png_ptr, &bmRow, png_bytepp_NULL, 1);
701             }
702         }
703     } else {
704         SkScaledBitmapSampler::SrcConfig sc;
705         int srcBytesPerPixel = 4;
706 
707         if (colorTable != NULL) {
708             sc = SkScaledBitmapSampler::kIndex;
709             srcBytesPerPixel = 1;
710         } else if (hasAlpha) {
711             sc = SkScaledBitmapSampler::kRGBA;
712         } else {
713             sc = SkScaledBitmapSampler::kRGBX;
714         }
715 
716         /*  We have to pass the colortable explicitly, since we may have one
717             even if our decodedBitmap doesn't, due to the request that we
718             upscale png's palette to a direct model
719          */
720         SkAutoLockColors ctLock(colorTable);
721         if (!sampler.begin(decodedBitmap, sc, doDither, ctLock.colors())) {
722             return false;
723         }
724         const int height = decodedBitmap->height();
725 
726         if (number_passes > 1) {
727             SkAutoMalloc storage(origWidth * origHeight * srcBytesPerPixel);
728             uint8_t* base = (uint8_t*)storage.get();
729             size_t rb = origWidth * srcBytesPerPixel;
730 
731             for (int i = 0; i < number_passes; i++) {
732                 png_configure_decoder(png_ptr, &actualTop, i);
733                 for (int j = 0; j < rect.fTop - actualTop; j++) {
734                     uint8_t* bmRow = decodedBitmap->getAddr8(0, 0);
735                     png_read_rows(png_ptr, &bmRow, png_bytepp_NULL, 1);
736                 }
737                 uint8_t* row = base;
738                 for (png_uint_32 y = 0; y < requestedHeight; y++) {
739                     uint8_t* bmRow = row;
740                     png_read_rows(png_ptr, &bmRow, png_bytepp_NULL, 1);
741                     row += rb;
742                 }
743             }
744             // now sample it
745             base += sampler.srcY0() * rb;
746             for (int y = 0; y < height; y++) {
747                 reallyHasAlpha |= sampler.next(base);
748                 base += sampler.srcDY() * rb;
749             }
750         } else {
751             SkAutoMalloc storage(origWidth * srcBytesPerPixel);
752             uint8_t* srcRow = (uint8_t*)storage.get();
753 
754             png_configure_decoder(png_ptr, &actualTop, 0);
755             skip_src_rows(png_ptr, srcRow, sampler.srcY0());
756 
757             for (int i = 0; i < rect.fTop - actualTop; i++) {
758                 uint8_t* bmRow = decodedBitmap->getAddr8(0, 0);
759                 png_read_rows(png_ptr, &bmRow, png_bytepp_NULL, 1);
760             }
761             for (int y = 0; y < height; y++) {
762                 uint8_t* tmp = srcRow;
763                 png_read_rows(png_ptr, &tmp, png_bytepp_NULL, 1);
764                 reallyHasAlpha |= sampler.next(srcRow);
765                 if (y < height - 1) {
766                     skip_src_rows(png_ptr, srcRow, sampler.srcDY() - 1);
767                 }
768             }
769         }
770     }
771     cropBitmap(bm, decodedBitmap, sampleSize, rect.fLeft, rect.fTop,
772                 requestedWidth, requestedHeight, 0, rect.fTop);
773 
774     if (0 != theTranspColor) {
775         reallyHasAlpha |= substituteTranspColor(decodedBitmap, theTranspColor);
776     }
777     decodedBitmap->setIsOpaque(!reallyHasAlpha);
778     return true;
779 }
780 
781 ///////////////////////////////////////////////////////////////////////////////
782 
783 #include "SkColorPriv.h"
784 #include "SkUnPreMultiply.h"
785 
sk_write_fn(png_structp png_ptr,png_bytep data,png_size_t len)786 static void sk_write_fn(png_structp png_ptr, png_bytep data, png_size_t len) {
787     SkWStream* sk_stream = (SkWStream*)png_ptr->io_ptr;
788     if (!sk_stream->write(data, len)) {
789         png_error(png_ptr, "sk_write_fn Error!");
790     }
791 }
792 
793 typedef void (*transform_scanline_proc)(const char* SK_RESTRICT src,
794                                         int width, char* SK_RESTRICT dst);
795 
transform_scanline_565(const char * SK_RESTRICT src,int width,char * SK_RESTRICT dst)796 static void transform_scanline_565(const char* SK_RESTRICT src, int width,
797                                    char* SK_RESTRICT dst) {
798     const uint16_t* SK_RESTRICT srcP = (const uint16_t*)src;
799     for (int i = 0; i < width; i++) {
800         unsigned c = *srcP++;
801         *dst++ = SkPacked16ToR32(c);
802         *dst++ = SkPacked16ToG32(c);
803         *dst++ = SkPacked16ToB32(c);
804     }
805 }
806 
transform_scanline_888(const char * SK_RESTRICT src,int width,char * SK_RESTRICT dst)807 static void transform_scanline_888(const char* SK_RESTRICT src, int width,
808                                    char* SK_RESTRICT dst) {
809     const SkPMColor* SK_RESTRICT srcP = (const SkPMColor*)src;
810     for (int i = 0; i < width; i++) {
811         SkPMColor c = *srcP++;
812         *dst++ = SkGetPackedR32(c);
813         *dst++ = SkGetPackedG32(c);
814         *dst++ = SkGetPackedB32(c);
815     }
816 }
817 
transform_scanline_444(const char * SK_RESTRICT src,int width,char * SK_RESTRICT dst)818 static void transform_scanline_444(const char* SK_RESTRICT src, int width,
819                                    char* SK_RESTRICT dst) {
820     const SkPMColor16* SK_RESTRICT srcP = (const SkPMColor16*)src;
821     for (int i = 0; i < width; i++) {
822         SkPMColor16 c = *srcP++;
823         *dst++ = SkPacked4444ToR32(c);
824         *dst++ = SkPacked4444ToG32(c);
825         *dst++ = SkPacked4444ToB32(c);
826     }
827 }
828 
transform_scanline_8888(const char * SK_RESTRICT src,int width,char * SK_RESTRICT dst)829 static void transform_scanline_8888(const char* SK_RESTRICT src, int width,
830                                     char* SK_RESTRICT dst) {
831     const SkPMColor* SK_RESTRICT srcP = (const SkPMColor*)src;
832     const SkUnPreMultiply::Scale* SK_RESTRICT table =
833                                               SkUnPreMultiply::GetScaleTable();
834 
835     for (int i = 0; i < width; i++) {
836         SkPMColor c = *srcP++;
837         unsigned a = SkGetPackedA32(c);
838         unsigned r = SkGetPackedR32(c);
839         unsigned g = SkGetPackedG32(c);
840         unsigned b = SkGetPackedB32(c);
841 
842         if (0 != a && 255 != a) {
843             SkUnPreMultiply::Scale scale = table[a];
844             r = SkUnPreMultiply::ApplyScale(scale, r);
845             g = SkUnPreMultiply::ApplyScale(scale, g);
846             b = SkUnPreMultiply::ApplyScale(scale, b);
847         }
848         *dst++ = r;
849         *dst++ = g;
850         *dst++ = b;
851         *dst++ = a;
852     }
853 }
854 
transform_scanline_4444(const char * SK_RESTRICT src,int width,char * SK_RESTRICT dst)855 static void transform_scanline_4444(const char* SK_RESTRICT src, int width,
856                                     char* SK_RESTRICT dst) {
857     const SkPMColor16* SK_RESTRICT srcP = (const SkPMColor16*)src;
858     const SkUnPreMultiply::Scale* SK_RESTRICT table =
859                                               SkUnPreMultiply::GetScaleTable();
860 
861     for (int i = 0; i < width; i++) {
862         SkPMColor16 c = *srcP++;
863         unsigned a = SkPacked4444ToA32(c);
864         unsigned r = SkPacked4444ToR32(c);
865         unsigned g = SkPacked4444ToG32(c);
866         unsigned b = SkPacked4444ToB32(c);
867 
868         if (0 != a && 255 != a) {
869             SkUnPreMultiply::Scale scale = table[a];
870             r = SkUnPreMultiply::ApplyScale(scale, r);
871             g = SkUnPreMultiply::ApplyScale(scale, g);
872             b = SkUnPreMultiply::ApplyScale(scale, b);
873         }
874         *dst++ = r;
875         *dst++ = g;
876         *dst++ = b;
877         *dst++ = a;
878     }
879 }
880 
transform_scanline_index8(const char * SK_RESTRICT src,int width,char * SK_RESTRICT dst)881 static void transform_scanline_index8(const char* SK_RESTRICT src, int width,
882                                       char* SK_RESTRICT dst) {
883     memcpy(dst, src, width);
884 }
885 
choose_proc(SkBitmap::Config config,bool hasAlpha)886 static transform_scanline_proc choose_proc(SkBitmap::Config config,
887                                            bool hasAlpha) {
888     // we don't care about search on alpha if we're kIndex8, since only the
889     // colortable packing cares about that distinction, not the pixels
890     if (SkBitmap::kIndex8_Config == config) {
891         hasAlpha = false;   // we store false in the table entries for kIndex8
892     }
893 
894     static const struct {
895         SkBitmap::Config        fConfig;
896         bool                    fHasAlpha;
897         transform_scanline_proc fProc;
898     } gMap[] = {
899         { SkBitmap::kRGB_565_Config,    false,  transform_scanline_565 },
900         { SkBitmap::kARGB_8888_Config,  false,  transform_scanline_888 },
901         { SkBitmap::kARGB_8888_Config,  true,   transform_scanline_8888 },
902         { SkBitmap::kARGB_4444_Config,  false,  transform_scanline_444 },
903         { SkBitmap::kARGB_4444_Config,  true,   transform_scanline_4444 },
904         { SkBitmap::kIndex8_Config,     false,   transform_scanline_index8 },
905     };
906 
907     for (int i = SK_ARRAY_COUNT(gMap) - 1; i >= 0; --i) {
908         if (gMap[i].fConfig == config && gMap[i].fHasAlpha == hasAlpha) {
909             return gMap[i].fProc;
910         }
911     }
912     sk_throw();
913     return NULL;
914 }
915 
916 // return the minimum legal bitdepth (by png standards) for this many colortable
917 // entries. SkBitmap always stores in 8bits per pixel, but for colorcount <= 16,
918 // we can use fewer bits per in png
computeBitDepth(int colorCount)919 static int computeBitDepth(int colorCount) {
920 #if 0
921     int bits = SkNextLog2(colorCount);
922     SkASSERT(bits >= 1 && bits <= 8);
923     // now we need bits itself to be a power of 2 (e.g. 1, 2, 4, 8)
924     return SkNextPow2(bits);
925 #else
926     // for the moment, we don't know how to pack bitdepth < 8
927     return 8;
928 #endif
929 }
930 
931 /*  Pack palette[] with the corresponding colors, and if hasAlpha is true, also
932     pack trans[] and return the number of trans[] entries written. If hasAlpha
933     is false, the return value will always be 0.
934 
935     Note: this routine takes care of unpremultiplying the RGB values when we
936     have alpha in the colortable, since png doesn't support premul colors
937 */
pack_palette(SkColorTable * ctable,png_color * SK_RESTRICT palette,png_byte * SK_RESTRICT trans,bool hasAlpha)938 static inline int pack_palette(SkColorTable* ctable,
939                                png_color* SK_RESTRICT palette,
940                                png_byte* SK_RESTRICT trans, bool hasAlpha) {
941     SkAutoLockColors alc(ctable);
942     const SkPMColor* SK_RESTRICT colors = alc.colors();
943     const int ctCount = ctable->count();
944     int i, num_trans = 0;
945 
946     if (hasAlpha) {
947         /*  first see if we have some number of fully opaque at the end of the
948             ctable. PNG allows num_trans < num_palette, but all of the trans
949             entries must come first in the palette. If I was smarter, I'd
950             reorder the indices and ctable so that all non-opaque colors came
951             first in the palette. But, since that would slow down the encode,
952             I'm leaving the indices and ctable order as is, and just looking
953             at the tail of the ctable for opaqueness.
954         */
955         num_trans = ctCount;
956         for (i = ctCount - 1; i >= 0; --i) {
957             if (SkGetPackedA32(colors[i]) != 0xFF) {
958                 break;
959             }
960             num_trans -= 1;
961         }
962 
963         const SkUnPreMultiply::Scale* SK_RESTRICT table =
964                                             SkUnPreMultiply::GetScaleTable();
965 
966         for (i = 0; i < num_trans; i++) {
967             const SkPMColor c = *colors++;
968             const unsigned a = SkGetPackedA32(c);
969             const SkUnPreMultiply::Scale s = table[a];
970             trans[i] = a;
971             palette[i].red = SkUnPreMultiply::ApplyScale(s, SkGetPackedR32(c));
972             palette[i].green = SkUnPreMultiply::ApplyScale(s,SkGetPackedG32(c));
973             palette[i].blue = SkUnPreMultiply::ApplyScale(s, SkGetPackedB32(c));
974         }
975         // now fall out of this if-block to use common code for the trailing
976         // opaque entries
977     }
978 
979     // these (remaining) entries are opaque
980     for (i = num_trans; i < ctCount; i++) {
981         SkPMColor c = *colors++;
982         palette[i].red = SkGetPackedR32(c);
983         palette[i].green = SkGetPackedG32(c);
984         palette[i].blue = SkGetPackedB32(c);
985     }
986     return num_trans;
987 }
988 
989 class SkPNGImageEncoder : public SkImageEncoder {
990 protected:
991     virtual bool onEncode(SkWStream* stream, const SkBitmap& bm, int quality);
992 };
993 
onEncode(SkWStream * stream,const SkBitmap & bitmap,int)994 bool SkPNGImageEncoder::onEncode(SkWStream* stream, const SkBitmap& bitmap,
995                                  int /*quality*/) {
996     SkBitmap::Config config = bitmap.getConfig();
997 
998     const bool hasAlpha = !bitmap.isOpaque();
999     int colorType = PNG_COLOR_MASK_COLOR;
1000     int bitDepth = 8;   // default for color
1001     png_color_8 sig_bit;
1002 
1003     switch (config) {
1004         case SkBitmap::kIndex8_Config:
1005             colorType |= PNG_COLOR_MASK_PALETTE;
1006             // fall through to the ARGB_8888 case
1007         case SkBitmap::kARGB_8888_Config:
1008             sig_bit.red = 8;
1009             sig_bit.green = 8;
1010             sig_bit.blue = 8;
1011             sig_bit.alpha = 8;
1012             break;
1013         case SkBitmap::kARGB_4444_Config:
1014             sig_bit.red = 4;
1015             sig_bit.green = 4;
1016             sig_bit.blue = 4;
1017             sig_bit.alpha = 4;
1018             break;
1019         case SkBitmap::kRGB_565_Config:
1020             sig_bit.red = 5;
1021             sig_bit.green = 6;
1022             sig_bit.blue = 5;
1023             sig_bit.alpha = 0;
1024             break;
1025         default:
1026             return false;
1027     }
1028 
1029     if (hasAlpha) {
1030         // don't specify alpha if we're a palette, even if our ctable has alpha
1031         if (!(colorType & PNG_COLOR_MASK_PALETTE)) {
1032             colorType |= PNG_COLOR_MASK_ALPHA;
1033         }
1034     } else {
1035         sig_bit.alpha = 0;
1036     }
1037 
1038     SkAutoLockPixels alp(bitmap);
1039     // readyToDraw checks for pixels (and colortable if that is required)
1040     if (!bitmap.readyToDraw()) {
1041         return false;
1042     }
1043 
1044     // we must do this after we have locked the pixels
1045     SkColorTable* ctable = bitmap.getColorTable();
1046     if (NULL != ctable) {
1047         if (ctable->count() == 0) {
1048             return false;
1049         }
1050         // check if we can store in fewer than 8 bits
1051         bitDepth = computeBitDepth(ctable->count());
1052     }
1053 
1054     png_structp png_ptr;
1055     png_infop info_ptr;
1056 
1057     png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, sk_error_fn,
1058                                       NULL);
1059     if (NULL == png_ptr) {
1060         return false;
1061     }
1062 
1063     info_ptr = png_create_info_struct(png_ptr);
1064     if (NULL == info_ptr) {
1065         png_destroy_write_struct(&png_ptr,  png_infopp_NULL);
1066         return false;
1067     }
1068 
1069     /* Set error handling.  REQUIRED if you aren't supplying your own
1070     * error handling functions in the png_create_write_struct() call.
1071     */
1072     if (setjmp(png_jmpbuf(png_ptr))) {
1073         png_destroy_write_struct(&png_ptr, &info_ptr);
1074         return false;
1075     }
1076 
1077     png_set_write_fn(png_ptr, (void*)stream, sk_write_fn, png_flush_ptr_NULL);
1078 
1079     /* Set the image information here.  Width and height are up to 2^31,
1080     * bit_depth is one of 1, 2, 4, 8, or 16, but valid values also depend on
1081     * the color_type selected. color_type is one of PNG_COLOR_TYPE_GRAY,
1082     * PNG_COLOR_TYPE_GRAY_ALPHA, PNG_COLOR_TYPE_PALETTE, PNG_COLOR_TYPE_RGB,
1083     * or PNG_COLOR_TYPE_RGB_ALPHA.  interlace is either PNG_INTERLACE_NONE or
1084     * PNG_INTERLACE_ADAM7, and the compression_type and filter_type MUST
1085     * currently be PNG_COMPRESSION_TYPE_BASE and PNG_FILTER_TYPE_BASE. REQUIRED
1086     */
1087 
1088     png_set_IHDR(png_ptr, info_ptr, bitmap.width(), bitmap.height(),
1089                  bitDepth, colorType,
1090                  PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE,
1091                  PNG_FILTER_TYPE_BASE);
1092 
1093     // set our colortable/trans arrays if needed
1094     png_color paletteColors[256];
1095     png_byte trans[256];
1096     if (SkBitmap::kIndex8_Config == config) {
1097         SkColorTable* ct = bitmap.getColorTable();
1098         int numTrans = pack_palette(ct, paletteColors, trans, hasAlpha);
1099         png_set_PLTE(png_ptr, info_ptr, paletteColors, ct->count());
1100         if (numTrans > 0) {
1101             png_set_tRNS(png_ptr, info_ptr, trans, numTrans, NULL);
1102         }
1103     }
1104 
1105     png_set_sBIT(png_ptr, info_ptr, &sig_bit);
1106     png_write_info(png_ptr, info_ptr);
1107 
1108     const char* srcImage = (const char*)bitmap.getPixels();
1109     SkAutoSMalloc<1024> rowStorage(bitmap.width() << 2);
1110     char* storage = (char*)rowStorage.get();
1111     transform_scanline_proc proc = choose_proc(config, hasAlpha);
1112 
1113     for (int y = 0; y < bitmap.height(); y++) {
1114         png_bytep row_ptr = (png_bytep)storage;
1115         proc(srcImage, bitmap.width(), storage);
1116         png_write_rows(png_ptr, &row_ptr, 1);
1117         srcImage += bitmap.rowBytes();
1118     }
1119 
1120     png_write_end(png_ptr, info_ptr);
1121 
1122     /* clean up after the write, and free any memory allocated */
1123     png_destroy_write_struct(&png_ptr, &info_ptr);
1124     return true;
1125 }
1126 
1127 ///////////////////////////////////////////////////////////////////////////////
1128 
1129 #include "SkTRegistry.h"
1130 
DFactory(SkStream * stream)1131 static SkImageDecoder* DFactory(SkStream* stream) {
1132     char buf[PNG_BYTES_TO_CHECK];
1133     if (stream->read(buf, PNG_BYTES_TO_CHECK) == PNG_BYTES_TO_CHECK &&
1134         !png_sig_cmp((png_bytep) buf, (png_size_t)0, PNG_BYTES_TO_CHECK)) {
1135         return SkNEW(SkPNGImageDecoder);
1136     }
1137     return NULL;
1138 }
1139 
EFactory(SkImageEncoder::Type t)1140 static SkImageEncoder* EFactory(SkImageEncoder::Type t) {
1141     return (SkImageEncoder::kPNG_Type == t) ? SkNEW(SkPNGImageEncoder) : NULL;
1142 }
1143 
1144 static SkTRegistry<SkImageEncoder*, SkImageEncoder::Type> gEReg(EFactory);
1145 static SkTRegistry<SkImageDecoder*, SkStream*> gDReg(DFactory);
1146