• 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 SkPNGImageDecoder : public SkImageDecoder {
34 public:
getFormat() const35     virtual Format getFormat() const {
36         return kPNG_Format;
37     }
38 
39 protected:
40     virtual bool onDecode(SkStream* stream, SkBitmap* bm,
41                           SkBitmap::Config pref, Mode);
42 };
43 
44 #ifndef png_jmpbuf
45 #  define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf)
46 #endif
47 
48 #define PNG_BYTES_TO_CHECK 4
49 
50 /* Automatically clean up after throwing an exception */
51 struct PNGAutoClean {
PNGAutoCleanPNGAutoClean52     PNGAutoClean(png_structp p, png_infop i): png_ptr(p), info_ptr(i) {}
~PNGAutoCleanPNGAutoClean53     ~PNGAutoClean() {
54         png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL);
55     }
56 private:
57     png_structp png_ptr;
58     png_infop info_ptr;
59 };
60 
sk_read_fn(png_structp png_ptr,png_bytep data,png_size_t length)61 static void sk_read_fn(png_structp png_ptr, png_bytep data, png_size_t length) {
62     SkStream* sk_stream = (SkStream*) png_ptr->io_ptr;
63     size_t bytes = sk_stream->read(data, length);
64     if (bytes != length) {
65         png_error(png_ptr, "Read Error!");
66     }
67 }
68 
sk_read_user_chunk(png_structp png_ptr,png_unknown_chunkp chunk)69 static int sk_read_user_chunk(png_structp png_ptr, png_unknown_chunkp chunk) {
70     SkImageDecoder::Peeker* peeker =
71                     (SkImageDecoder::Peeker*)png_get_user_chunk_ptr(png_ptr);
72     // peek() returning true means continue decoding
73     return peeker->peek((const char*)chunk->name, chunk->data, chunk->size) ?
74             1 : -1;
75 }
76 
sk_error_fn(png_structp png_ptr,png_const_charp msg)77 static void sk_error_fn(png_structp png_ptr, png_const_charp msg) {
78 #if 0
79     SkDebugf("------ png error %s\n", msg);
80 #endif
81     longjmp(png_jmpbuf(png_ptr), 1);
82 }
83 
skip_src_rows(png_structp png_ptr,uint8_t storage[],int count)84 static void skip_src_rows(png_structp png_ptr, uint8_t storage[], int count) {
85     for (int i = 0; i < count; i++) {
86         uint8_t* tmp = storage;
87         png_read_rows(png_ptr, &tmp, png_bytepp_NULL, 1);
88     }
89 }
90 
pos_le(int value,int max)91 static bool pos_le(int value, int max) {
92     return value > 0 && value <= max;
93 }
94 
substituteTranspColor(SkBitmap * bm,SkPMColor match)95 static bool substituteTranspColor(SkBitmap* bm, SkPMColor match) {
96     SkASSERT(bm->config() == SkBitmap::kARGB_8888_Config);
97 
98     bool reallyHasAlpha = false;
99 
100     for (int y = bm->height() - 1; y >= 0; --y) {
101         SkPMColor* p = bm->getAddr32(0, y);
102         for (int x = bm->width() - 1; x >= 0; --x) {
103             if (match == *p) {
104                 *p = 0;
105                 reallyHasAlpha = true;
106             }
107             p += 1;
108         }
109     }
110     return reallyHasAlpha;
111 }
112 
canUpscalePaletteToConfig(SkBitmap::Config prefConfig,bool srcHasAlpha)113 static bool canUpscalePaletteToConfig(SkBitmap::Config prefConfig,
114                                       bool srcHasAlpha) {
115     switch (prefConfig) {
116         case SkBitmap::kARGB_8888_Config:
117         case SkBitmap::kARGB_4444_Config:
118             return true;
119         case SkBitmap::kRGB_565_Config:
120             // only return true if the src is opaque (since 565 is opaque)
121             return !srcHasAlpha;
122         default:
123             return false;
124     }
125 }
126 
127 // call only if color_type is PALETTE. Returns true if the ctable has alpha
hasTransparencyInPalette(png_structp png_ptr,png_infop info_ptr)128 static bool hasTransparencyInPalette(png_structp png_ptr, png_infop info_ptr) {
129     png_bytep trans;
130     int num_trans;
131 
132     if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
133         png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, NULL);
134         return num_trans > 0;
135     }
136     return false;
137 }
138 
onDecode(SkStream * sk_stream,SkBitmap * decodedBitmap,SkBitmap::Config prefConfig,Mode mode)139 bool SkPNGImageDecoder::onDecode(SkStream* sk_stream, SkBitmap* decodedBitmap,
140                                  SkBitmap::Config prefConfig, Mode mode) {
141 //    SkAutoTrace    apr("SkPNGImageDecoder::onDecode");
142 
143     /* Create and initialize the png_struct with the desired error handler
144     * functions.  If you want to use the default stderr and longjump method,
145     * you can supply NULL for the last three parameters.  We also supply the
146     * the compiler header file version, so that we know if the application
147     * was compiled with a compatible version of the library.  */
148     png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
149         NULL, sk_error_fn, NULL);
150     //   png_voidp user_error_ptr, user_error_fn, user_warning_fn);
151     if (png_ptr == NULL) {
152         return false;
153     }
154 
155     /* Allocate/initialize the memory for image information. */
156     png_infop info_ptr = png_create_info_struct(png_ptr);
157     if (info_ptr == NULL) {
158         png_destroy_read_struct(&png_ptr, png_infopp_NULL, png_infopp_NULL);
159         return false;
160     }
161 
162     PNGAutoClean autoClean(png_ptr, info_ptr);
163 
164     /* Set error handling if you are using the setjmp/longjmp method (this is
165     * the normal method of doing things with libpng).  REQUIRED unless you
166     * set up your own error handlers in the png_create_read_struct() earlier.
167     */
168     if (setjmp(png_jmpbuf(png_ptr))) {
169         return false;
170     }
171 
172     /* If you are using replacement read functions, instead of calling
173     * png_init_io() here you would call:
174     */
175     png_set_read_fn(png_ptr, (void *)sk_stream, sk_read_fn);
176     /* where user_io_ptr is a structure you want available to the callbacks */
177     /* If we have already read some of the signature */
178 //  png_set_sig_bytes(png_ptr, 0 /* sig_read */ );
179 
180     // hookup our peeker so we can see any user-chunks the caller may be interested in
181     png_set_keep_unknown_chunks(png_ptr, PNG_HANDLE_CHUNK_ALWAYS, (png_byte*)"", 0);
182     if (this->getPeeker()) {
183         png_set_read_user_chunk_fn(png_ptr, (png_voidp)this->getPeeker(), sk_read_user_chunk);
184     }
185 
186     /* The call to png_read_info() gives us all of the information from the
187     * PNG file before the first IDAT (image data chunk). */
188     png_read_info(png_ptr, info_ptr);
189     png_uint_32 origWidth, origHeight;
190     int bit_depth, color_type, interlace_type;
191     png_get_IHDR(png_ptr, info_ptr, &origWidth, &origHeight, &bit_depth, &color_type,
192         &interlace_type, int_p_NULL, int_p_NULL);
193 
194     /* tell libpng to strip 16 bit/color files down to 8 bits/color */
195     if (bit_depth == 16) {
196         png_set_strip_16(png_ptr);
197     }
198     /* Extract multiple pixels with bit depths of 1, 2, and 4 from a single
199      * byte into separate bytes (useful for paletted and grayscale images). */
200     if (bit_depth < 8) {
201         png_set_packing(png_ptr);
202     }
203     /* Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel */
204     if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) {
205         png_set_gray_1_2_4_to_8(png_ptr);
206     }
207 
208     /* Make a grayscale image into RGB. */
209     if (color_type == PNG_COLOR_TYPE_GRAY ||
210         color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
211         png_set_gray_to_rgb(png_ptr);
212     }
213 
214     SkBitmap::Config    config;
215     bool                hasAlpha = false;
216     bool                doDither = this->getDitherImage();
217     SkPMColor           theTranspColor = 0; // 0 tells us not to try to match
218 
219     // check for sBIT chunk data, in case we should disable dithering because
220     // our data is not truely 8bits per component
221     if (doDither) {
222 #if 0
223         SkDebugf("----- sBIT %d %d %d %d\n", info_ptr->sig_bit.red,
224                  info_ptr->sig_bit.green, info_ptr->sig_bit.blue,
225                  info_ptr->sig_bit.alpha);
226 #endif
227         // 0 seems to indicate no information available
228         if (pos_le(info_ptr->sig_bit.red, SK_R16_BITS) &&
229                 pos_le(info_ptr->sig_bit.green, SK_G16_BITS) &&
230                 pos_le(info_ptr->sig_bit.blue, SK_B16_BITS)) {
231             doDither = false;
232         }
233     }
234 
235     if (color_type == PNG_COLOR_TYPE_PALETTE) {
236         config = SkBitmap::kIndex8_Config;
237         // now see if we can upscale to their requested config
238         bool paletteHasAlpha = hasTransparencyInPalette(png_ptr, info_ptr);
239         if (canUpscalePaletteToConfig(prefConfig, paletteHasAlpha)) {
240             config = prefConfig;
241         }
242     } else {
243         png_color_16p   transpColor = NULL;
244         int             numTransp = 0;
245 
246         png_get_tRNS(png_ptr, info_ptr, NULL, &numTransp, &transpColor);
247 
248         bool valid = png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS);
249 
250         if (valid && numTransp == 1 && transpColor != NULL) {
251             /*  Compute our transparent color, which we'll match against later.
252                 We don't really handle 16bit components properly here, since we
253                 do our compare *after* the values have been knocked down to 8bit
254                 which means we will find more matches than we should. The real
255                 fix seems to be to see the actual 16bit components, do the
256                 compare, and then knock it down to 8bits ourselves.
257             */
258             if (color_type & PNG_COLOR_MASK_COLOR) {
259                 if (16 == bit_depth) {
260                     theTranspColor = SkPackARGB32(0xFF, transpColor->red >> 8,
261                               transpColor->green >> 8, transpColor->blue >> 8);
262                 } else {
263                     theTranspColor = SkPackARGB32(0xFF, transpColor->red,
264                                       transpColor->green, transpColor->blue);
265                 }
266             } else {    // gray
267                 if (16 == bit_depth) {
268                     theTranspColor = SkPackARGB32(0xFF, transpColor->gray >> 8,
269                               transpColor->gray >> 8, transpColor->gray >> 8);
270                 } else {
271                     theTranspColor = SkPackARGB32(0xFF, transpColor->gray,
272                                           transpColor->gray, transpColor->gray);
273                 }
274             }
275         }
276 
277         if (valid ||
278                 PNG_COLOR_TYPE_RGB_ALPHA == color_type ||
279                 PNG_COLOR_TYPE_GRAY_ALPHA == color_type) {
280             hasAlpha = true;
281             config = SkBitmap::kARGB_8888_Config;
282         } else {    // we get to choose the config
283             config = prefConfig;
284             if (config == SkBitmap::kNo_Config) {
285                 config = SkImageDecoder::GetDeviceConfig();
286             }
287             if (config != SkBitmap::kRGB_565_Config &&
288                     config != SkBitmap::kARGB_4444_Config) {
289                 config = SkBitmap::kARGB_8888_Config;
290             }
291         }
292     }
293 
294     // sanity check for size
295     {
296         Sk64 size;
297         size.setMul(origWidth, origHeight);
298         if (size.isNeg() || !size.is32()) {
299             return false;
300         }
301         // now check that if we are 4-bytes per pixel, we also don't overflow
302         if (size.get32() > (0x7FFFFFFF >> 2)) {
303             return false;
304         }
305     }
306 
307     if (!this->chooseFromOneChoice(config, origWidth, origHeight)) {
308         return false;
309     }
310 
311     const int sampleSize = this->getSampleSize();
312     SkScaledBitmapSampler sampler(origWidth, origHeight, sampleSize);
313 
314     // we must always return the same config, independent of mode, so if we were
315     // going to respect prefConfig, it must have happened by now
316 
317     decodedBitmap->setConfig(config, sampler.scaledWidth(),
318                              sampler.scaledHeight(), 0);
319     if (SkImageDecoder::kDecodeBounds_Mode == mode) {
320         return true;
321     }
322 
323     // from here down we are concerned with colortables and pixels
324 
325     // we track if we actually see a non-opaque pixels, since sometimes a PNG sets its colortype
326     // to |= PNG_COLOR_MASK_ALPHA, but all of its pixels are in fact opaque. We care, since we
327     // draw lots faster if we can flag the bitmap has being opaque
328     bool reallyHasAlpha = false;
329     SkColorTable* colorTable = NULL;
330 
331     if (color_type == PNG_COLOR_TYPE_PALETTE) {
332         int num_palette;
333         png_colorp palette;
334         png_bytep trans;
335         int num_trans;
336 
337         png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette);
338 
339         /*  BUGGY IMAGE WORKAROUND
340 
341             We hit some images (e.g. fruit_.png) who contain bytes that are == colortable_count
342             which is a problem since we use the byte as an index. To work around this we grow
343             the colortable by 1 (if its < 256) and duplicate the last color into that slot.
344         */
345         int colorCount = num_palette + (num_palette < 256);
346 
347         colorTable = SkNEW_ARGS(SkColorTable, (colorCount));
348 
349         SkPMColor* colorPtr = colorTable->lockColors();
350         if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
351             png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, NULL);
352             hasAlpha = (num_trans > 0);
353         } else {
354             num_trans = 0;
355             colorTable->setFlags(colorTable->getFlags() | SkColorTable::kColorsAreOpaque_Flag);
356         }
357         // check for bad images that might make us crash
358         if (num_trans > num_palette) {
359             num_trans = num_palette;
360         }
361 
362         int index = 0;
363         int transLessThanFF = 0;
364 
365         for (; index < num_trans; index++) {
366             transLessThanFF |= (int)*trans - 0xFF;
367             *colorPtr++ = SkPreMultiplyARGB(*trans++, palette->red, palette->green, palette->blue);
368             palette++;
369         }
370         reallyHasAlpha |= (transLessThanFF < 0);
371 
372         for (; index < num_palette; index++) {
373             *colorPtr++ = SkPackARGB32(0xFF, palette->red, palette->green, palette->blue);
374             palette++;
375         }
376 
377         // see BUGGY IMAGE WORKAROUND comment above
378         if (num_palette < 256) {
379             *colorPtr = colorPtr[-1];
380         }
381         colorTable->unlockColors(true);
382     }
383 
384     SkAutoUnref aur(colorTable);
385 
386     if (!this->allocPixelRef(decodedBitmap,
387                              SkBitmap::kIndex8_Config == config ?
388                                 colorTable : NULL)) {
389         return false;
390     }
391 
392     SkAutoLockPixels alp(*decodedBitmap);
393 
394     /* swap the RGBA or GA data to ARGB or AG (or BGRA to ABGR) */
395 //  if (color_type == PNG_COLOR_TYPE_RGB_ALPHA)
396 //      ; // png_set_swap_alpha(png_ptr);
397 
398     /* swap bytes of 16 bit files to least significant byte first */
399     //   png_set_swap(png_ptr);
400 
401     /* Add filler (or alpha) byte (before/after each RGB triplet) */
402     if (color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_GRAY) {
403         png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER);
404     }
405 
406     /* Turn on interlace handling.  REQUIRED if you are not using
407     * png_read_image().  To see how to handle interlacing passes,
408     * see the png_read_row() method below:
409     */
410     const int number_passes = interlace_type != PNG_INTERLACE_NONE ?
411                         png_set_interlace_handling(png_ptr) : 1;
412 
413     /* Optional call to gamma correct and add the background to the palette
414     * and update info structure.  REQUIRED if you are expecting libpng to
415     * update the palette for you (ie you selected such a transform above).
416     */
417     png_read_update_info(png_ptr, info_ptr);
418 
419     if (SkBitmap::kIndex8_Config == config && 1 == sampleSize) {
420         for (int i = 0; i < number_passes; i++) {
421             for (png_uint_32 y = 0; y < origHeight; y++) {
422                 uint8_t* bmRow = decodedBitmap->getAddr8(0, y);
423                 png_read_rows(png_ptr, &bmRow, png_bytepp_NULL, 1);
424             }
425         }
426     } else {
427         SkScaledBitmapSampler::SrcConfig sc;
428         int srcBytesPerPixel = 4;
429 
430         if (colorTable != NULL) {
431             sc = SkScaledBitmapSampler::kIndex;
432             srcBytesPerPixel = 1;
433         } else if (hasAlpha) {
434             sc = SkScaledBitmapSampler::kRGBA;
435         } else {
436             sc = SkScaledBitmapSampler::kRGBX;
437         }
438 
439         /*  We have to pass the colortable explicitly, since we may have one
440             even if our decodedBitmap doesn't, due to the request that we
441             upscale png's palette to a direct model
442          */
443         SkAutoLockColors ctLock(colorTable);
444         if (!sampler.begin(decodedBitmap, sc, doDither, ctLock.colors())) {
445             return false;
446         }
447         const int height = decodedBitmap->height();
448 
449         if (number_passes > 1) {
450             SkAutoMalloc storage(origWidth * origHeight * srcBytesPerPixel);
451             uint8_t* base = (uint8_t*)storage.get();
452             size_t rb = origWidth * srcBytesPerPixel;
453 
454             for (int i = 0; i < number_passes; i++) {
455                 uint8_t* row = base;
456                 for (png_uint_32 y = 0; y < origHeight; y++) {
457                     uint8_t* bmRow = row;
458                     png_read_rows(png_ptr, &bmRow, png_bytepp_NULL, 1);
459                     row += rb;
460                 }
461             }
462             // now sample it
463             base += sampler.srcY0() * rb;
464             for (int y = 0; y < height; y++) {
465                 reallyHasAlpha |= sampler.next(base);
466                 base += sampler.srcDY() * rb;
467             }
468         } else {
469             SkAutoMalloc storage(origWidth * srcBytesPerPixel);
470             uint8_t* srcRow = (uint8_t*)storage.get();
471             skip_src_rows(png_ptr, srcRow, sampler.srcY0());
472 
473             for (int y = 0; y < height; y++) {
474                 uint8_t* tmp = srcRow;
475                 png_read_rows(png_ptr, &tmp, png_bytepp_NULL, 1);
476                 reallyHasAlpha |= sampler.next(srcRow);
477                 if (y < height - 1) {
478                     skip_src_rows(png_ptr, srcRow, sampler.srcDY() - 1);
479                 }
480             }
481 
482             // skip the rest of the rows (if any)
483             png_uint_32 read = (height - 1) * sampler.srcDY() +
484                                sampler.srcY0() + 1;
485             SkASSERT(read <= origHeight);
486             skip_src_rows(png_ptr, srcRow, origHeight - read);
487         }
488     }
489 
490     /* read rest of file, and get additional chunks in info_ptr - REQUIRED */
491     png_read_end(png_ptr, info_ptr);
492 
493     if (0 != theTranspColor) {
494         reallyHasAlpha |= substituteTranspColor(decodedBitmap, theTranspColor);
495     }
496     decodedBitmap->setIsOpaque(!reallyHasAlpha);
497     return true;
498 }
499 
500 ///////////////////////////////////////////////////////////////////////////////
501 
502 #include "SkColorPriv.h"
503 #include "SkUnPreMultiply.h"
504 
sk_write_fn(png_structp png_ptr,png_bytep data,png_size_t len)505 static void sk_write_fn(png_structp png_ptr, png_bytep data, png_size_t len) {
506     SkWStream* sk_stream = (SkWStream*)png_ptr->io_ptr;
507     if (!sk_stream->write(data, len)) {
508         png_error(png_ptr, "sk_write_fn Error!");
509     }
510 }
511 
512 typedef void (*transform_scanline_proc)(const char* SK_RESTRICT src,
513                                         int width, char* SK_RESTRICT dst);
514 
transform_scanline_565(const char * SK_RESTRICT src,int width,char * SK_RESTRICT dst)515 static void transform_scanline_565(const char* SK_RESTRICT src, int width,
516                                    char* SK_RESTRICT dst) {
517     const uint16_t* SK_RESTRICT srcP = (const uint16_t*)src;
518     for (int i = 0; i < width; i++) {
519         unsigned c = *srcP++;
520         *dst++ = SkPacked16ToR32(c);
521         *dst++ = SkPacked16ToG32(c);
522         *dst++ = SkPacked16ToB32(c);
523     }
524 }
525 
transform_scanline_888(const char * SK_RESTRICT src,int width,char * SK_RESTRICT dst)526 static void transform_scanline_888(const char* SK_RESTRICT src, int width,
527                                    char* SK_RESTRICT dst) {
528     const SkPMColor* SK_RESTRICT srcP = (const SkPMColor*)src;
529     for (int i = 0; i < width; i++) {
530         SkPMColor c = *srcP++;
531         *dst++ = SkGetPackedR32(c);
532         *dst++ = SkGetPackedG32(c);
533         *dst++ = SkGetPackedB32(c);
534     }
535 }
536 
transform_scanline_444(const char * SK_RESTRICT src,int width,char * SK_RESTRICT dst)537 static void transform_scanline_444(const char* SK_RESTRICT src, int width,
538                                    char* SK_RESTRICT dst) {
539     const SkPMColor16* SK_RESTRICT srcP = (const SkPMColor16*)src;
540     for (int i = 0; i < width; i++) {
541         SkPMColor16 c = *srcP++;
542         *dst++ = SkPacked4444ToR32(c);
543         *dst++ = SkPacked4444ToG32(c);
544         *dst++ = SkPacked4444ToB32(c);
545     }
546 }
547 
transform_scanline_8888(const char * SK_RESTRICT src,int width,char * SK_RESTRICT dst)548 static void transform_scanline_8888(const char* SK_RESTRICT src, int width,
549                                     char* SK_RESTRICT dst) {
550     const SkPMColor* SK_RESTRICT srcP = (const SkPMColor*)src;
551     const SkUnPreMultiply::Scale* SK_RESTRICT table =
552                                               SkUnPreMultiply::GetScaleTable();
553 
554     for (int i = 0; i < width; i++) {
555         SkPMColor c = *srcP++;
556         unsigned a = SkGetPackedA32(c);
557         unsigned r = SkGetPackedR32(c);
558         unsigned g = SkGetPackedG32(c);
559         unsigned b = SkGetPackedB32(c);
560 
561         if (0 != a && 255 != a) {
562             SkUnPreMultiply::Scale scale = table[a];
563             r = SkUnPreMultiply::ApplyScale(scale, r);
564             g = SkUnPreMultiply::ApplyScale(scale, g);
565             b = SkUnPreMultiply::ApplyScale(scale, b);
566         }
567         *dst++ = r;
568         *dst++ = g;
569         *dst++ = b;
570         *dst++ = a;
571     }
572 }
573 
transform_scanline_4444(const char * SK_RESTRICT src,int width,char * SK_RESTRICT dst)574 static void transform_scanline_4444(const char* SK_RESTRICT src, int width,
575                                     char* SK_RESTRICT dst) {
576     const SkPMColor16* SK_RESTRICT srcP = (const SkPMColor16*)src;
577     const SkUnPreMultiply::Scale* SK_RESTRICT table =
578                                               SkUnPreMultiply::GetScaleTable();
579 
580     for (int i = 0; i < width; i++) {
581         SkPMColor16 c = *srcP++;
582         unsigned a = SkPacked4444ToA32(c);
583         unsigned r = SkPacked4444ToR32(c);
584         unsigned g = SkPacked4444ToG32(c);
585         unsigned b = SkPacked4444ToB32(c);
586 
587         if (0 != a && 255 != a) {
588             SkUnPreMultiply::Scale scale = table[a];
589             r = SkUnPreMultiply::ApplyScale(scale, r);
590             g = SkUnPreMultiply::ApplyScale(scale, g);
591             b = SkUnPreMultiply::ApplyScale(scale, b);
592         }
593         *dst++ = r;
594         *dst++ = g;
595         *dst++ = b;
596         *dst++ = a;
597     }
598 }
599 
transform_scanline_index8(const char * SK_RESTRICT src,int width,char * SK_RESTRICT dst)600 static void transform_scanline_index8(const char* SK_RESTRICT src, int width,
601                                       char* SK_RESTRICT dst) {
602     memcpy(dst, src, width);
603 }
604 
choose_proc(SkBitmap::Config config,bool hasAlpha)605 static transform_scanline_proc choose_proc(SkBitmap::Config config,
606                                            bool hasAlpha) {
607     // we don't care about search on alpha if we're kIndex8, since only the
608     // colortable packing cares about that distinction, not the pixels
609     if (SkBitmap::kIndex8_Config == config) {
610         hasAlpha = false;   // we store false in the table entries for kIndex8
611     }
612 
613     static const struct {
614         SkBitmap::Config        fConfig;
615         bool                    fHasAlpha;
616         transform_scanline_proc fProc;
617     } gMap[] = {
618         { SkBitmap::kRGB_565_Config,    false,  transform_scanline_565 },
619         { SkBitmap::kARGB_8888_Config,  false,  transform_scanline_888 },
620         { SkBitmap::kARGB_8888_Config,  true,   transform_scanline_8888 },
621         { SkBitmap::kARGB_4444_Config,  false,  transform_scanline_444 },
622         { SkBitmap::kARGB_4444_Config,  true,   transform_scanline_4444 },
623         { SkBitmap::kIndex8_Config,     false,   transform_scanline_index8 },
624     };
625 
626     for (int i = SK_ARRAY_COUNT(gMap) - 1; i >= 0; --i) {
627         if (gMap[i].fConfig == config && gMap[i].fHasAlpha == hasAlpha) {
628             return gMap[i].fProc;
629         }
630     }
631     sk_throw();
632     return NULL;
633 }
634 
635 // return the minimum legal bitdepth (by png standards) for this many colortable
636 // entries. SkBitmap always stores in 8bits per pixel, but for colorcount <= 16,
637 // we can use fewer bits per in png
computeBitDepth(int colorCount)638 static int computeBitDepth(int colorCount) {
639 #if 0
640     int bits = SkNextLog2(colorCount);
641     SkASSERT(bits >= 1 && bits <= 8);
642     // now we need bits itself to be a power of 2 (e.g. 1, 2, 4, 8)
643     return SkNextPow2(bits);
644 #else
645     // for the moment, we don't know how to pack bitdepth < 8
646     return 8;
647 #endif
648 }
649 
650 /*  Pack palette[] with the corresponding colors, and if hasAlpha is true, also
651     pack trans[] and return the number of trans[] entries written. If hasAlpha
652     is false, the return value will always be 0.
653 
654     Note: this routine takes care of unpremultiplying the RGB values when we
655     have alpha in the colortable, since png doesn't support premul colors
656 */
pack_palette(SkColorTable * ctable,png_color * SK_RESTRICT palette,png_byte * SK_RESTRICT trans,bool hasAlpha)657 static inline int pack_palette(SkColorTable* ctable,
658                                png_color* SK_RESTRICT palette,
659                                png_byte* SK_RESTRICT trans, bool hasAlpha) {
660     SkAutoLockColors alc(ctable);
661     const SkPMColor* SK_RESTRICT colors = alc.colors();
662     const int ctCount = ctable->count();
663     int i, num_trans = 0;
664 
665     if (hasAlpha) {
666         /*  first see if we have some number of fully opaque at the end of the
667             ctable. PNG allows num_trans < num_palette, but all of the trans
668             entries must come first in the palette. If I was smarter, I'd
669             reorder the indices and ctable so that all non-opaque colors came
670             first in the palette. But, since that would slow down the encode,
671             I'm leaving the indices and ctable order as is, and just looking
672             at the tail of the ctable for opaqueness.
673         */
674         num_trans = ctCount;
675         for (i = ctCount - 1; i >= 0; --i) {
676             if (SkGetPackedA32(colors[i]) != 0xFF) {
677                 break;
678             }
679             num_trans -= 1;
680         }
681 
682         const SkUnPreMultiply::Scale* SK_RESTRICT table =
683                                             SkUnPreMultiply::GetScaleTable();
684 
685         for (i = 0; i < num_trans; i++) {
686             const SkPMColor c = *colors++;
687             const unsigned a = SkGetPackedA32(c);
688             const SkUnPreMultiply::Scale s = table[a];
689             trans[i] = a;
690             palette[i].red = SkUnPreMultiply::ApplyScale(s, SkGetPackedR32(c));
691             palette[i].green = SkUnPreMultiply::ApplyScale(s,SkGetPackedG32(c));
692             palette[i].blue = SkUnPreMultiply::ApplyScale(s, SkGetPackedB32(c));
693         }
694         // now fall out of this if-block to use common code for the trailing
695         // opaque entries
696     }
697 
698     // these (remaining) entries are opaque
699     for (i = num_trans; i < ctCount; i++) {
700         SkPMColor c = *colors++;
701         palette[i].red = SkGetPackedR32(c);
702         palette[i].green = SkGetPackedG32(c);
703         palette[i].blue = SkGetPackedB32(c);
704     }
705     return num_trans;
706 }
707 
708 class SkPNGImageEncoder : public SkImageEncoder {
709 protected:
710     virtual bool onEncode(SkWStream* stream, const SkBitmap& bm, int quality);
711 };
712 
onEncode(SkWStream * stream,const SkBitmap & bitmap,int)713 bool SkPNGImageEncoder::onEncode(SkWStream* stream, const SkBitmap& bitmap,
714                                  int /*quality*/) {
715     SkBitmap::Config config = bitmap.getConfig();
716 
717     const bool hasAlpha = !bitmap.isOpaque();
718     int colorType = PNG_COLOR_MASK_COLOR;
719     int bitDepth = 8;   // default for color
720     png_color_8 sig_bit;
721 
722     switch (config) {
723         case SkBitmap::kIndex8_Config:
724             colorType |= PNG_COLOR_MASK_PALETTE;
725             // fall through to the ARGB_8888 case
726         case SkBitmap::kARGB_8888_Config:
727             sig_bit.red = 8;
728             sig_bit.green = 8;
729             sig_bit.blue = 8;
730             sig_bit.alpha = 8;
731             break;
732         case SkBitmap::kARGB_4444_Config:
733             sig_bit.red = 4;
734             sig_bit.green = 4;
735             sig_bit.blue = 4;
736             sig_bit.alpha = 4;
737             break;
738         case SkBitmap::kRGB_565_Config:
739             sig_bit.red = 5;
740             sig_bit.green = 6;
741             sig_bit.blue = 5;
742             sig_bit.alpha = 0;
743             break;
744         default:
745             return false;
746     }
747 
748     if (hasAlpha) {
749         // don't specify alpha if we're a palette, even if our ctable has alpha
750         if (!(colorType & PNG_COLOR_MASK_PALETTE)) {
751             colorType |= PNG_COLOR_MASK_ALPHA;
752         }
753     } else {
754         sig_bit.alpha = 0;
755     }
756 
757     SkAutoLockPixels alp(bitmap);
758     // readyToDraw checks for pixels (and colortable if that is required)
759     if (!bitmap.readyToDraw()) {
760         return false;
761     }
762 
763     // we must do this after we have locked the pixels
764     SkColorTable* ctable = bitmap.getColorTable();
765     if (NULL != ctable) {
766         if (ctable->count() == 0) {
767             return false;
768         }
769         // check if we can store in fewer than 8 bits
770         bitDepth = computeBitDepth(ctable->count());
771     }
772 
773     png_structp png_ptr;
774     png_infop info_ptr;
775 
776     png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, sk_error_fn,
777                                       NULL);
778     if (NULL == png_ptr) {
779         return false;
780     }
781 
782     info_ptr = png_create_info_struct(png_ptr);
783     if (NULL == info_ptr) {
784         png_destroy_write_struct(&png_ptr,  png_infopp_NULL);
785         return false;
786     }
787 
788     /* Set error handling.  REQUIRED if you aren't supplying your own
789     * error handling functions in the png_create_write_struct() call.
790     */
791     if (setjmp(png_jmpbuf(png_ptr))) {
792         png_destroy_write_struct(&png_ptr, &info_ptr);
793         return false;
794     }
795 
796     png_set_write_fn(png_ptr, (void*)stream, sk_write_fn, png_flush_ptr_NULL);
797 
798     /* Set the image information here.  Width and height are up to 2^31,
799     * bit_depth is one of 1, 2, 4, 8, or 16, but valid values also depend on
800     * the color_type selected. color_type is one of PNG_COLOR_TYPE_GRAY,
801     * PNG_COLOR_TYPE_GRAY_ALPHA, PNG_COLOR_TYPE_PALETTE, PNG_COLOR_TYPE_RGB,
802     * or PNG_COLOR_TYPE_RGB_ALPHA.  interlace is either PNG_INTERLACE_NONE or
803     * PNG_INTERLACE_ADAM7, and the compression_type and filter_type MUST
804     * currently be PNG_COMPRESSION_TYPE_BASE and PNG_FILTER_TYPE_BASE. REQUIRED
805     */
806 
807     png_set_IHDR(png_ptr, info_ptr, bitmap.width(), bitmap.height(),
808                  bitDepth, colorType,
809                  PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE,
810                  PNG_FILTER_TYPE_BASE);
811 
812     // set our colortable/trans arrays if needed
813     png_color paletteColors[256];
814     png_byte trans[256];
815     if (SkBitmap::kIndex8_Config == config) {
816         SkColorTable* ct = bitmap.getColorTable();
817         int numTrans = pack_palette(ct, paletteColors, trans, hasAlpha);
818         png_set_PLTE(png_ptr, info_ptr, paletteColors, ct->count());
819         if (numTrans > 0) {
820             png_set_tRNS(png_ptr, info_ptr, trans, numTrans, NULL);
821         }
822     }
823 
824     png_set_sBIT(png_ptr, info_ptr, &sig_bit);
825     png_write_info(png_ptr, info_ptr);
826 
827     const char* srcImage = (const char*)bitmap.getPixels();
828     SkAutoSMalloc<1024> rowStorage(bitmap.width() << 2);
829     char* storage = (char*)rowStorage.get();
830     transform_scanline_proc proc = choose_proc(config, hasAlpha);
831 
832     for (int y = 0; y < bitmap.height(); y++) {
833         png_bytep row_ptr = (png_bytep)storage;
834         proc(srcImage, bitmap.width(), storage);
835         png_write_rows(png_ptr, &row_ptr, 1);
836         srcImage += bitmap.rowBytes();
837     }
838 
839     png_write_end(png_ptr, info_ptr);
840 
841     /* clean up after the write, and free any memory allocated */
842     png_destroy_write_struct(&png_ptr, &info_ptr);
843     return true;
844 }
845 
846 ///////////////////////////////////////////////////////////////////////////////
847 
848 #include "SkTRegistry.h"
849 
DFactory(SkStream * stream)850 static SkImageDecoder* DFactory(SkStream* stream) {
851     char buf[PNG_BYTES_TO_CHECK];
852     if (stream->read(buf, PNG_BYTES_TO_CHECK) == PNG_BYTES_TO_CHECK &&
853         !png_sig_cmp((png_bytep) buf, (png_size_t)0, PNG_BYTES_TO_CHECK)) {
854         return SkNEW(SkPNGImageDecoder);
855     }
856     return NULL;
857 }
858 
EFactory(SkImageEncoder::Type t)859 static SkImageEncoder* EFactory(SkImageEncoder::Type t) {
860     return (SkImageEncoder::kPNG_Type == t) ? SkNEW(SkPNGImageEncoder) : NULL;
861 }
862 
863 static SkTRegistry<SkImageEncoder*, SkImageEncoder::Type> gEReg(EFactory);
864 static SkTRegistry<SkImageDecoder*, SkStream*> gDReg(DFactory);
865