Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1)

Side by Side Diff: src/images/SkImageDecoder_libpng.cpp

Issue 12604006: Upstream Android modifications to the image encoders/decoders. (Closed) Base URL: https://skia.googlecode.com/svn/trunk
Patch Set: minor fixes Created 7 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/images/SkImageDecoder_libico.cpp ('k') | src/images/SkImageDecoder_libwebp.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 1
2 /* 2 /*
3 * Copyright 2006 The Android Open Source Project 3 * Copyright 2006 The Android Open Source Project
4 * 4 *
5 * Use of this source code is governed by a BSD-style license that can be 5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file. 6 * found in the LICENSE file.
7 */ 7 */
8 8
9 9
10 #include "SkImageDecoder.h" 10 #include "SkImageDecoder.h"
11 #include "SkImageEncoder.h" 11 #include "SkImageEncoder.h"
12 #include "SkColor.h" 12 #include "SkColor.h"
13 #include "SkColorPriv.h" 13 #include "SkColorPriv.h"
14 #include "SkDither.h" 14 #include "SkDither.h"
15 #include "SkMath.h" 15 #include "SkMath.h"
16 #include "SkScaledBitmapSampler.h" 16 #include "SkScaledBitmapSampler.h"
17 #include "SkStream.h" 17 #include "SkStream.h"
18 #include "SkTemplates.h" 18 #include "SkTemplates.h"
19 #include "SkUtils.h" 19 #include "SkUtils.h"
20 #include "transform_scanline.h" 20 #include "transform_scanline.h"
21 21
22 extern "C" { 22 extern "C" {
23 #include "png.h" 23 #include "png.h"
24 } 24 }
25 25
26 class SkPNGImageIndex {
27 public:
28 SkPNGImageIndex(png_structp png_ptr, png_infop info_ptr) {
29 this->png_ptr = png_ptr;
30 this->info_ptr = info_ptr;
31 }
32 ~SkPNGImageIndex() {
33 if (NULL != png_ptr) {
34 png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL);
35 }
36 }
37
38 png_structp png_ptr;
39 png_infop info_ptr;
40 };
41
26 class SkPNGImageDecoder : public SkImageDecoder { 42 class SkPNGImageDecoder : public SkImageDecoder {
27 public: 43 public:
28 virtual Format getFormat() const { 44 SkPNGImageDecoder() {
45 fImageIndex = NULL;
46 }
47 virtual Format getFormat() const SK_OVERRIDE {
29 return kPNG_Format; 48 return kPNG_Format;
30 } 49 }
50 virtual ~SkPNGImageDecoder() {
51 SkDELETE(fImageIndex);
52 }
31 53
32 protected: 54 protected:
33 virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode); 55 #ifdef SK_BUILD_FOR_ANDROID
56 virtual bool onBuildTileIndex(SkStream *stream, int *width, int *height) SK_ OVERRIDE;
57 virtual bool onDecodeRegion(SkBitmap* bitmap, const SkIRect& region) SK_OVER RIDE;
58 #endif
59 virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode) SK_OVERRIDE;
60
61 private:
62 SkPNGImageIndex* fImageIndex;
63
64 bool onDecodeInit(SkStream* stream, png_structp *png_ptrp, png_infop *info_p trp);
65 bool decodePalette(png_structp png_ptr, png_infop info_ptr, bool *hasAlphap,
66 bool *reallyHasAlphap, SkColorTable **colorTablep);
67 bool getBitmapConfig(png_structp png_ptr, png_infop info_ptr,
68 SkBitmap::Config *config, bool *hasAlpha,
69 bool *doDither, SkPMColor *theTranspColor);
70
71 typedef SkImageDecoder INHERITED;
34 }; 72 };
35 73
36 #ifndef png_jmpbuf 74 #ifndef png_jmpbuf
37 # define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf) 75 # define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf)
38 #endif 76 #endif
39 77
40 #define PNG_BYTES_TO_CHECK 4 78 #define PNG_BYTES_TO_CHECK 4
41 79
42 /* Automatically clean up after throwing an exception */ 80 /* Automatically clean up after throwing an exception */
43 struct PNGAutoClean { 81 struct PNGAutoClean {
44 PNGAutoClean(png_structp p, png_infop i): png_ptr(p), info_ptr(i) {} 82 PNGAutoClean(png_structp p, png_infop i): png_ptr(p), info_ptr(i) {}
45 ~PNGAutoClean() { 83 ~PNGAutoClean() {
46 png_destroy_read_struct(&png_ptr, &info_ptr, NULL); 84 png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL);
47 } 85 }
48 private: 86 private:
49 png_structp png_ptr; 87 png_structp png_ptr;
50 png_infop info_ptr; 88 png_infop info_ptr;
51 }; 89 };
52 90
53 static void sk_read_fn(png_structp png_ptr, png_bytep data, png_size_t length) { 91 static void sk_read_fn(png_structp png_ptr, png_bytep data, png_size_t length) {
54 SkStream* sk_stream = (SkStream*)png_get_io_ptr(png_ptr); 92 SkStream* sk_stream = (SkStream*) png_ptr->io_ptr;
55 size_t bytes = sk_stream->read(data, length); 93 size_t bytes = sk_stream->read(data, length);
56 if (bytes != length) { 94 if (bytes != length) {
57 png_error(png_ptr, "Read Error!"); 95 png_error(png_ptr, "Read Error!");
58 } 96 }
59 } 97 }
60 98
99 #ifdef SK_BUILD_FOR_ANDROID
100 static void sk_seek_fn(png_structp png_ptr, png_uint_32 offset) {
101 SkStream* sk_stream = (SkStream*) png_ptr->io_ptr;
102 sk_stream->rewind();
103 (void)sk_stream->skip(offset);
104 }
105 #endif
106
61 static int sk_read_user_chunk(png_structp png_ptr, png_unknown_chunkp chunk) { 107 static int sk_read_user_chunk(png_structp png_ptr, png_unknown_chunkp chunk) {
62 SkImageDecoder::Peeker* peeker = 108 SkImageDecoder::Peeker* peeker =
63 (SkImageDecoder::Peeker*)png_get_user_chunk_ptr(png_ptr); 109 (SkImageDecoder::Peeker*)png_get_user_chunk_ptr(png_ptr);
64 // peek() returning true means continue decoding 110 // peek() returning true means continue decoding
65 return peeker->peek((const char*)chunk->name, chunk->data, chunk->size) ? 111 return peeker->peek((const char*)chunk->name, chunk->data, chunk->size) ?
66 1 : -1; 112 1 : -1;
67 } 113 }
68 114
69 static void sk_error_fn(png_structp png_ptr, png_const_charp msg) { 115 static void sk_error_fn(png_structp png_ptr, png_const_charp msg) {
70 #if 0 116 SkDEBUGF(("------ png error %s\n", msg));
71 SkDebugf("------ png error %s\n", msg);
72 #endif
73 longjmp(png_jmpbuf(png_ptr), 1); 117 longjmp(png_jmpbuf(png_ptr), 1);
74 } 118 }
75 119
76 static void skip_src_rows(png_structp png_ptr, uint8_t storage[], int count) { 120 static void skip_src_rows(png_structp png_ptr, uint8_t storage[], int count) {
77 for (int i = 0; i < count; i++) { 121 for (int i = 0; i < count; i++) {
78 uint8_t* tmp = storage; 122 uint8_t* tmp = storage;
79 png_read_rows(png_ptr, &tmp, NULL, 1); 123 png_read_rows(png_ptr, &tmp, png_bytepp_NULL, 1);
80 } 124 }
81 } 125 }
82 126
83 static bool pos_le(int value, int max) { 127 static bool pos_le(int value, int max) {
84 return value > 0 && value <= max; 128 return value > 0 && value <= max;
85 } 129 }
86 130
87 static bool substituteTranspColor(SkBitmap* bm, SkPMColor match) { 131 static bool substituteTranspColor(SkBitmap* bm, SkPMColor match) {
88 SkASSERT(bm->config() == SkBitmap::kARGB_8888_Config); 132 SkASSERT(bm->config() == SkBitmap::kARGB_8888_Config);
89 133
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
121 png_bytep trans; 165 png_bytep trans;
122 int num_trans; 166 int num_trans;
123 167
124 if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { 168 if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
125 png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, NULL); 169 png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, NULL);
126 return num_trans > 0; 170 return num_trans > 0;
127 } 171 }
128 return false; 172 return false;
129 } 173 }
130 174
131 bool SkPNGImageDecoder::onDecode(SkStream* sk_stream, SkBitmap* decodedBitmap, 175 bool SkPNGImageDecoder::onDecodeInit(SkStream* sk_stream, png_structp *png_ptrp,
132 Mode mode) { 176 png_infop *info_ptrp) {
133 // SkAutoTrace apr("SkPNGImageDecoder::onDecode");
134
135 /* Create and initialize the png_struct with the desired error handler 177 /* Create and initialize the png_struct with the desired error handler
136 * functions. If you want to use the default stderr and longjump method, 178 * functions. If you want to use the default stderr and longjump method,
137 * you can supply NULL for the last three parameters. We also supply the 179 * you can supply NULL for the last three parameters. We also supply the
138 * the compiler header file version, so that we know if the application 180 * the compiler header file version, so that we know if the application
139 * was compiled with a compatible version of the library. */ 181 * was compiled with a compatible version of the library. */
140 png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 182 png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
141 NULL, sk_error_fn, NULL); 183 NULL, sk_error_fn, NULL);
142 // png_voidp user_error_ptr, user_error_fn, user_warning_fn); 184 // png_voidp user_error_ptr, user_error_fn, user_warning_fn);
143 if (png_ptr == NULL) { 185 if (png_ptr == NULL) {
144 return false; 186 return false;
145 } 187 }
188 *png_ptrp = png_ptr;
146 189
147 /* Allocate/initialize the memory for image information. */ 190 /* Allocate/initialize the memory for image information. */
148 png_infop info_ptr = png_create_info_struct(png_ptr); 191 png_infop info_ptr = png_create_info_struct(png_ptr);
149 if (info_ptr == NULL) { 192 if (info_ptr == NULL) {
150 png_destroy_read_struct(&png_ptr, NULL, NULL); 193 png_destroy_read_struct(&png_ptr, png_infopp_NULL, png_infopp_NULL);
151 return false; 194 return false;
152 } 195 }
153 196 *info_ptrp = info_ptr;
154 PNGAutoClean autoClean(png_ptr, info_ptr);
155 197
156 /* Set error handling if you are using the setjmp/longjmp method (this is 198 /* Set error handling if you are using the setjmp/longjmp method (this is
157 * the normal method of doing things with libpng). REQUIRED unless you 199 * the normal method of doing things with libpng). REQUIRED unless you
158 * set up your own error handlers in the png_create_read_struct() earlier. 200 * set up your own error handlers in the png_create_read_struct() earlier.
159 */ 201 */
160 if (setjmp(png_jmpbuf(png_ptr))) { 202 if (setjmp(png_jmpbuf(png_ptr))) {
161 return false; 203 return false;
162 } 204 }
163 205
164 /* If you are using replacement read functions, instead of calling 206 /* If you are using replacement read functions, instead of calling
165 * png_init_io() here you would call: 207 * png_init_io() here you would call:
166 */ 208 */
167 png_set_read_fn(png_ptr, (void *)sk_stream, sk_read_fn); 209 png_set_read_fn(png_ptr, (void *)sk_stream, sk_read_fn);
210 #ifdef SK_BUILD_FOR_ANDROID
211 png_set_seek_fn(png_ptr, sk_seek_fn);
212 #endif
168 /* where user_io_ptr is a structure you want available to the callbacks */ 213 /* where user_io_ptr is a structure you want available to the callbacks */
169 /* If we have already read some of the signature */ 214 /* If we have already read some of the signature */
170 // png_set_sig_bytes(png_ptr, 0 /* sig_read */ ); 215 // png_set_sig_bytes(png_ptr, 0 /* sig_read */ );
171 216
172 // hookup our peeker so we can see any user-chunks the caller may be interes ted in 217 // hookup our peeker so we can see any user-chunks the caller may be interes ted in
173 png_set_keep_unknown_chunks(png_ptr, PNG_HANDLE_CHUNK_ALWAYS, (png_byte*)"", 0); 218 png_set_keep_unknown_chunks(png_ptr, PNG_HANDLE_CHUNK_ALWAYS, (png_byte*)"", 0);
174 if (this->getPeeker()) { 219 if (this->getPeeker()) {
175 png_set_read_user_chunk_fn(png_ptr, (png_voidp)this->getPeeker(), sk_rea d_user_chunk); 220 png_set_read_user_chunk_fn(png_ptr, (png_voidp)this->getPeeker(), sk_rea d_user_chunk);
176 } 221 }
177 222
178 /* The call to png_read_info() gives us all of the information from the 223 /* The call to png_read_info() gives us all of the information from the
179 * PNG file before the first IDAT (image data chunk). */ 224 * PNG file before the first IDAT (image data chunk). */
180 png_read_info(png_ptr, info_ptr); 225 png_read_info(png_ptr, info_ptr);
181 png_uint_32 origWidth, origHeight; 226 png_uint_32 origWidth, origHeight;
182 int bit_depth, color_type, interlace_type; 227 int bitDepth, colorType;
183 png_get_IHDR(png_ptr, info_ptr, &origWidth, &origHeight, &bit_depth, &color_ type, 228 png_get_IHDR(png_ptr, info_ptr, &origWidth, &origHeight, &bitDepth,
184 &interlace_type, NULL, NULL); 229 &colorType, int_p_NULL, int_p_NULL, int_p_NULL);
185 230
186 /* tell libpng to strip 16 bit/color files down to 8 bits/color */ 231 /* tell libpng to strip 16 bit/color files down to 8 bits/color */
187 if (bit_depth == 16) { 232 if (bitDepth == 16) {
188 png_set_strip_16(png_ptr); 233 png_set_strip_16(png_ptr);
189 } 234 }
190 /* Extract multiple pixels with bit depths of 1, 2, and 4 from a single 235 /* Extract multiple pixels with bit depths of 1, 2, and 4 from a single
191 * byte into separate bytes (useful for paletted and grayscale images). */ 236 * byte into separate bytes (useful for paletted and grayscale images). */
192 if (bit_depth < 8) { 237 if (bitDepth < 8) {
193 png_set_packing(png_ptr); 238 png_set_packing(png_ptr);
194 } 239 }
195 /* Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel */ 240 /* Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel */
196 if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) { 241 if (colorType == PNG_COLOR_TYPE_GRAY && bitDepth < 8) {
197 png_set_expand_gray_1_2_4_to_8(png_ptr); 242 png_set_gray_1_2_4_to_8(png_ptr);
198 } 243 }
199 244
200 /* Make a grayscale image into RGB. */ 245 /* Make a grayscale image into RGB. */
201 if (color_type == PNG_COLOR_TYPE_GRAY || 246 if (colorType == PNG_COLOR_TYPE_GRAY || colorType == PNG_COLOR_TYPE_GRAY_ALP HA) {
202 color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
203 png_set_gray_to_rgb(png_ptr); 247 png_set_gray_to_rgb(png_ptr);
204 } 248 }
249 return true;
250 }
251
252 bool SkPNGImageDecoder::onDecode(SkStream* sk_stream, SkBitmap* decodedBitmap,
253 Mode mode) {
254 png_structp png_ptr;
255 png_infop info_ptr;
256
257 if (!onDecodeInit(sk_stream, &png_ptr, &info_ptr)) {
258 return false;
259 }
260
261 if (setjmp(png_jmpbuf(png_ptr))) {
262 return false;
263 }
264
265 PNGAutoClean autoClean(png_ptr, info_ptr);
266
267 png_uint_32 origWidth, origHeight;
268 int bitDepth, colorType, interlaceType;
269 png_get_IHDR(png_ptr, info_ptr, &origWidth, &origHeight, &bitDepth,
270 &colorType, &interlaceType, int_p_NULL, int_p_NULL);
205 271
206 SkBitmap::Config config; 272 SkBitmap::Config config;
207 bool hasAlpha = false; 273 bool hasAlpha = false;
208 bool doDither = this->getDitherImage(); 274 bool doDither = this->getDitherImage();
209 SkPMColor theTranspColor = 0; // 0 tells us not to try to match 275 SkPMColor theTranspColor = 0; // 0 tells us not to try to match
210 276
277 if (!getBitmapConfig(png_ptr, info_ptr, &config, &hasAlpha, &doDither, &theT ranspColor)) {
278 return false;
279 }
280
281 const int sampleSize = this->getSampleSize();
282 SkScaledBitmapSampler sampler(origWidth, origHeight, sampleSize);
283
284 decodedBitmap->lockPixels();
285 void* rowptr = (void*) decodedBitmap->getPixels();
286 bool reuseBitmap = (rowptr != NULL);
287 decodedBitmap->unlockPixels();
288 if (reuseBitmap && (sampler.scaledWidth() != decodedBitmap->width() ||
289 sampler.scaledHeight() != decodedBitmap->height())) {
290 // Dimensions must match
291 return false;
292 }
293
294 if (!reuseBitmap) {
295 decodedBitmap->setConfig(config, sampler.scaledWidth(),
296 sampler.scaledHeight(), 0);
297 }
298 if (SkImageDecoder::kDecodeBounds_Mode == mode) {
299 return true;
300 }
301
302 // from here down we are concerned with colortables and pixels
303
304 // we track if we actually see a non-opaque pixels, since sometimes a PNG se ts its colortype
305 // to |= PNG_COLOR_MASK_ALPHA, but all of its pixels are in fact opaque. We care, since we
306 // draw lots faster if we can flag the bitmap has being opaque
307 bool reallyHasAlpha = false;
308 SkColorTable* colorTable = NULL;
309
310 if (colorType == PNG_COLOR_TYPE_PALETTE) {
311 decodePalette(png_ptr, info_ptr, &hasAlpha, &reallyHasAlpha, &colorTable );
312 }
313
314 SkAutoUnref aur(colorTable);
315
316 if (!reuseBitmap) {
317 if (!this->allocPixelRef(decodedBitmap,
318 SkBitmap::kIndex8_Config == config ? colorTable : NULL)) {
319 return false;
320 }
321 }
322
323 SkAutoLockPixels alp(*decodedBitmap);
324
325 /* Add filler (or alpha) byte (before/after each RGB triplet) */
326 if (colorType == PNG_COLOR_TYPE_RGB || colorType == PNG_COLOR_TYPE_GRAY) {
327 png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER);
328 }
329
330 /* Turn on interlace handling. REQUIRED if you are not using
331 * png_read_image(). To see how to handle interlacing passes,
332 * see the png_read_row() method below:
333 */
334 const int number_passes = (interlaceType != PNG_INTERLACE_NONE) ?
335 png_set_interlace_handling(png_ptr) : 1;
336
337 /* Optional call to gamma correct and add the background to the palette
338 * and update info structure. REQUIRED if you are expecting libpng to
339 * update the palette for you (ie you selected such a transform above).
340 */
341 png_read_update_info(png_ptr, info_ptr);
342
343 if (SkBitmap::kIndex8_Config == config && 1 == sampleSize) {
344 for (int i = 0; i < number_passes; i++) {
345 for (png_uint_32 y = 0; y < origHeight; y++) {
346 uint8_t* bmRow = decodedBitmap->getAddr8(0, y);
347 png_read_rows(png_ptr, &bmRow, png_bytepp_NULL, 1);
348 }
349 }
350 } else {
351 SkScaledBitmapSampler::SrcConfig sc;
352 int srcBytesPerPixel = 4;
353
354 if (colorTable != NULL) {
355 sc = SkScaledBitmapSampler::kIndex;
356 srcBytesPerPixel = 1;
357 } else if (hasAlpha) {
358 sc = SkScaledBitmapSampler::kRGBA;
359 } else {
360 sc = SkScaledBitmapSampler::kRGBX;
361 }
362
363 /* We have to pass the colortable explicitly, since we may have one
364 even if our decodedBitmap doesn't, due to the request that we
365 upscale png's palette to a direct model
366 */
367 SkAutoLockColors ctLock(colorTable);
368 if (!sampler.begin(decodedBitmap, sc, doDither, ctLock.colors())) {
369 return false;
370 }
371 const int height = decodedBitmap->height();
372
373 if (number_passes > 1) {
374 SkAutoMalloc storage(origWidth * origHeight * srcBytesPerPixel);
375 uint8_t* base = (uint8_t*)storage.get();
376 size_t rowBytes = origWidth * srcBytesPerPixel;
377
378 for (int i = 0; i < number_passes; i++) {
379 uint8_t* row = base;
380 for (png_uint_32 y = 0; y < origHeight; y++) {
381 uint8_t* bmRow = row;
382 png_read_rows(png_ptr, &bmRow, png_bytepp_NULL, 1);
383 row += rowBytes;
384 }
385 }
386 // now sample it
387 base += sampler.srcY0() * rowBytes;
388 for (int y = 0; y < height; y++) {
389 reallyHasAlpha |= sampler.next(base);
390 base += sampler.srcDY() * rowBytes;
391 }
392 } else {
393 SkAutoMalloc storage(origWidth * srcBytesPerPixel);
394 uint8_t* srcRow = (uint8_t*)storage.get();
395 skip_src_rows(png_ptr, srcRow, sampler.srcY0());
396
397 for (int y = 0; y < height; y++) {
398 uint8_t* tmp = srcRow;
399 png_read_rows(png_ptr, &tmp, png_bytepp_NULL, 1);
400 reallyHasAlpha |= sampler.next(srcRow);
401 if (y < height - 1) {
402 skip_src_rows(png_ptr, srcRow, sampler.srcDY() - 1);
403 }
404 }
405
406 // skip the rest of the rows (if any)
407 png_uint_32 read = (height - 1) * sampler.srcDY() +
408 sampler.srcY0() + 1;
409 SkASSERT(read <= origHeight);
410 skip_src_rows(png_ptr, srcRow, origHeight - read);
411 }
412 }
413
414 /* read rest of file, and get additional chunks in info_ptr - REQUIRED */
415 png_read_end(png_ptr, info_ptr);
416
417 if (0 != theTranspColor) {
418 reallyHasAlpha |= substituteTranspColor(decodedBitmap, theTranspColor);
419 }
420 decodedBitmap->setIsOpaque(!reallyHasAlpha);
421 if (reuseBitmap) {
422 decodedBitmap->notifyPixelsChanged();
423 }
424 return true;
425 }
426
427
428
429 bool SkPNGImageDecoder::getBitmapConfig(png_structp png_ptr, png_infop info_ptr,
430 SkBitmap::Config *configp, bool *hasAlph ap,
431 bool *doDitherp, SkPMColor *theTranspCol orp) {
432 png_uint_32 origWidth, origHeight;
433 int bitDepth, colorType;
434 png_get_IHDR(png_ptr, info_ptr, &origWidth, &origHeight, &bitDepth,
435 &colorType, int_p_NULL, int_p_NULL, int_p_NULL);
436
211 // check for sBIT chunk data, in case we should disable dithering because 437 // check for sBIT chunk data, in case we should disable dithering because
212 // our data is not truely 8bits per component 438 // our data is not truely 8bits per component
213 if (doDither) { 439 if (*doDitherp) {
214 png_color_8p sig_bit = NULL;
215 bool has_sbit = PNG_INFO_sBIT == png_get_sBIT(png_ptr, info_ptr,
216 &sig_bit);
217 #if 0 440 #if 0
218 if (has_sbit) { 441 SkDebugf("----- sBIT %d %d %d %d\n", info_ptr->sig_bit.red,
219 SkDebugf("----- sBIT %d %d %d %d\n", sig_bit->red, sig_bit->green, 442 info_ptr->sig_bit.green, info_ptr->sig_bit.blue,
220 sig_bit->blue, sig_bit->alpha); 443 info_ptr->sig_bit.alpha);
221 }
222 #endif 444 #endif
223 // 0 seems to indicate no information available 445 // 0 seems to indicate no information available
224 if (has_sbit && pos_le(sig_bit->red, SK_R16_BITS) && 446 if (pos_le(info_ptr->sig_bit.red, SK_R16_BITS) &&
225 pos_le(sig_bit->green, SK_G16_BITS) && 447 pos_le(info_ptr->sig_bit.green, SK_G16_BITS) &&
226 pos_le(sig_bit->blue, SK_B16_BITS)) { 448 pos_le(info_ptr->sig_bit.blue, SK_B16_BITS)) {
227 doDither = false; 449 *doDitherp = false;
228 } 450 }
229 } 451 }
230 452
231 if (color_type == PNG_COLOR_TYPE_PALETTE) { 453 if (colorType == PNG_COLOR_TYPE_PALETTE) {
232 bool paletteHasAlpha = hasTransparencyInPalette(png_ptr, info_ptr); 454 bool paletteHasAlpha = hasTransparencyInPalette(png_ptr, info_ptr);
233 config = this->getPrefConfig(kIndex_SrcDepth, paletteHasAlpha); 455 *configp = this->getPrefConfig(kIndex_SrcDepth, paletteHasAlpha);
234 // now see if we can upscale to their requested config 456 // now see if we can upscale to their requested config
235 if (!canUpscalePaletteToConfig(config, paletteHasAlpha)) { 457 if (!canUpscalePaletteToConfig(*configp, paletteHasAlpha)) {
236 config = SkBitmap::kIndex8_Config; 458 *configp = SkBitmap::kIndex8_Config;
237 } 459 }
238 } else { 460 } else {
239 png_color_16p transpColor = NULL; 461 png_color_16p transpColor = NULL;
240 int numTransp = 0; 462 int numTransp = 0;
241 463
242 png_get_tRNS(png_ptr, info_ptr, NULL, &numTransp, &transpColor); 464 png_get_tRNS(png_ptr, info_ptr, NULL, &numTransp, &transpColor);
243 465
244 bool valid = png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS); 466 bool valid = png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS);
245 467
246 if (valid && numTransp == 1 && transpColor != NULL) { 468 if (valid && numTransp == 1 && transpColor != NULL) {
247 /* Compute our transparent color, which we'll match against later. 469 /* Compute our transparent color, which we'll match against later.
248 We don't really handle 16bit components properly here, since we 470 We don't really handle 16bit components properly here, since we
249 do our compare *after* the values have been knocked down to 8bit 471 do our compare *after* the values have been knocked down to 8bit
250 which means we will find more matches than we should. The real 472 which means we will find more matches than we should. The real
251 fix seems to be to see the actual 16bit components, do the 473 fix seems to be to see the actual 16bit components, do the
252 compare, and then knock it down to 8bits ourselves. 474 compare, and then knock it down to 8bits ourselves.
253 */ 475 */
254 if (color_type & PNG_COLOR_MASK_COLOR) { 476 if (colorType & PNG_COLOR_MASK_COLOR) {
255 if (16 == bit_depth) { 477 if (16 == bitDepth) {
256 theTranspColor = SkPackARGB32(0xFF, transpColor->red >> 8, 478 *theTranspColorp = SkPackARGB32(0xFF, transpColor->red >> 8,
257 transpColor->green >> 8, transpColor->blue >> 8); 479 transpColor->green >> 8,
480 transpColor->blue >> 8);
258 } else { 481 } else {
259 theTranspColor = SkPackARGB32(0xFF, transpColor->red, 482 *theTranspColorp = SkPackARGB32(0xFF, transpColor->red,
260 transpColor->green, transpColor->blue); 483 transpColor->green,
484 transpColor->blue);
261 } 485 }
262 } else { // gray 486 } else { // gray
263 if (16 == bit_depth) { 487 if (16 == bitDepth) {
264 theTranspColor = SkPackARGB32(0xFF, transpColor->gray >> 8, 488 *theTranspColorp = SkPackARGB32(0xFF, transpColor->gray >> 8 ,
265 transpColor->gray >> 8, transpColor->gray >> 8); 489 transpColor->gray >> 8,
490 transpColor->gray >> 8);
266 } else { 491 } else {
267 theTranspColor = SkPackARGB32(0xFF, transpColor->gray, 492 *theTranspColorp = SkPackARGB32(0xFF, transpColor->gray,
268 transpColor->gray, transpColor->gray); 493 transpColor->gray,
494 transpColor->gray);
269 } 495 }
270 } 496 }
271 } 497 }
272 498
273 if (valid || 499 if (valid ||
274 PNG_COLOR_TYPE_RGB_ALPHA == color_type || 500 PNG_COLOR_TYPE_RGB_ALPHA == colorType ||
275 PNG_COLOR_TYPE_GRAY_ALPHA == color_type) { 501 PNG_COLOR_TYPE_GRAY_ALPHA == colorType) {
276 hasAlpha = true; 502 *hasAlphap = true;
277 } 503 }
278 config = this->getPrefConfig(k32Bit_SrcDepth, hasAlpha); 504 *configp = this->getPrefConfig(k32Bit_SrcDepth, *hasAlphap);
279 // now match the request against our capabilities 505 // now match the request against our capabilities
280 if (hasAlpha) { 506 if (*hasAlphap) {
281 if (config != SkBitmap::kARGB_4444_Config) { 507 if (*configp != SkBitmap::kARGB_4444_Config) {
282 config = SkBitmap::kARGB_8888_Config; 508 *configp = SkBitmap::kARGB_8888_Config;
283 } 509 }
284 } else { 510 } else {
285 if (config != SkBitmap::kRGB_565_Config && 511 if (*configp != SkBitmap::kRGB_565_Config &&
286 config != SkBitmap::kARGB_4444_Config) { 512 *configp != SkBitmap::kARGB_4444_Config) {
287 config = SkBitmap::kARGB_8888_Config; 513 *configp = SkBitmap::kARGB_8888_Config;
288 } 514 }
289 } 515 }
290 } 516 }
291 517
292 // sanity check for size 518 // sanity check for size
293 { 519 {
294 Sk64 size; 520 Sk64 size;
295 size.setMul(origWidth, origHeight); 521 size.setMul(origWidth, origHeight);
296 if (size.isNeg() || !size.is32()) { 522 if (size.isNeg() || !size.is32()) {
297 return false; 523 return false;
298 } 524 }
299 // now check that if we are 4-bytes per pixel, we also don't overflow 525 // now check that if we are 4-bytes per pixel, we also don't overflow
300 if (size.get32() > (0x7FFFFFFF >> 2)) { 526 if (size.get32() > (0x7FFFFFFF >> 2)) {
301 return false; 527 return false;
302 } 528 }
303 } 529 }
304 530
305 if (!this->chooseFromOneChoice(config, origWidth, origHeight)) { 531 return this->chooseFromOneChoice(*configp, origWidth, origHeight);
532 }
533
534 bool SkPNGImageDecoder::decodePalette(png_structp png_ptr, png_infop info_ptr,
535 bool *hasAlphap, bool *reallyHasAlphap,
536 SkColorTable **colorTablep) {
537 int numPalette;
538 png_colorp palette;
539 png_bytep trans;
540 int numTrans;
541 bool reallyHasAlpha = false;
542 SkColorTable* colorTable = NULL;
543
544 png_get_PLTE(png_ptr, info_ptr, &palette, &numPalette);
545
546 /* BUGGY IMAGE WORKAROUND
547
548 We hit some images (e.g. fruit_.png) who contain bytes that are == color table_count
549 which is a problem since we use the byte as an index. To work around thi s we grow
550 the colortable by 1 (if its < 256) and duplicate the last color into tha t slot.
551 */
552 int colorCount = numPalette + (numPalette < 256);
553
554 colorTable = SkNEW_ARGS(SkColorTable, (colorCount));
555
556 SkPMColor* colorPtr = colorTable->lockColors();
557 if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
558 png_get_tRNS(png_ptr, info_ptr, &trans, &numTrans, NULL);
559 *hasAlphap = (numTrans > 0);
560 } else {
561 numTrans = 0;
562 colorTable->setFlags(colorTable->getFlags() | SkColorTable::kColorsAreOp aque_Flag);
563 }
564 // check for bad images that might make us crash
565 if (numTrans > numPalette) {
566 numTrans = numPalette;
567 }
568
569 int index = 0;
570 int transLessThanFF = 0;
571
572 for (; index < numTrans; index++) {
573 transLessThanFF |= (int)*trans - 0xFF;
574 *colorPtr++ = SkPreMultiplyARGB(*trans++, palette->red, palette->green, palette->blue);
575 palette++;
576 }
577 reallyHasAlpha |= (transLessThanFF < 0);
578
579 for (; index < numPalette; index++) {
580 *colorPtr++ = SkPackARGB32(0xFF, palette->red, palette->green, palette-> blue);
581 palette++;
582 }
583
584 // see BUGGY IMAGE WORKAROUND comment above
585 if (numPalette < 256) {
586 *colorPtr = colorPtr[-1];
587 }
588 colorTable->unlockColors(true);
589 *colorTablep = colorTable;
590 *reallyHasAlphap = reallyHasAlpha;
591 return true;
592 }
593
594 #ifdef SK_BUILD_FOR_ANDROID
595
596 bool SkPNGImageDecoder::onBuildTileIndex(SkStream* sk_stream, int *width, int *h eight) {
597 png_structp png_ptr;
598 png_infop info_ptr;
599
600 if (!onDecodeInit(sk_stream, &png_ptr, &info_ptr)) {
601 return false;
602 }
603
604 if (setjmp(png_jmpbuf(png_ptr)) != 0) {
605 png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL);
606 return false;
607 }
608
609 png_uint_32 origWidth, origHeight;
610 int bitDepth, colorType;
611 png_get_IHDR(png_ptr, info_ptr, &origWidth, &origHeight, &bitDepth,
612 &colorType, int_p_NULL, int_p_NULL, int_p_NULL);
613
614 *width = origWidth;
615 *height = origHeight;
616
617 png_build_index(png_ptr);
618
619 if (fImageIndex) {
620 SkDELETE(fImageIndex);
621 }
622 fImageIndex = SkNEW_ARGS(SkPNGImageIndex, (png_ptr, info_ptr));
623
624 return true;
625 }
626
627 bool SkPNGImageDecoder::onDecodeRegion(SkBitmap* bm, const SkIRect& region) {
628 png_structp png_ptr = fImageIndex->png_ptr;
629 png_infop info_ptr = fImageIndex->info_ptr;
630 if (setjmp(png_jmpbuf(png_ptr))) {
631 return false;
632 }
633
634 png_uint_32 origWidth, origHeight;
635 int bitDepth, colorType, interlaceType;
636 png_get_IHDR(png_ptr, info_ptr, &origWidth, &origHeight, &bitDepth,
637 &colorType, &interlaceType, int_p_NULL, int_p_NULL);
638
639 SkIRect rect = SkIRect::MakeWH(origWidth, origHeight);
640
641 if (!rect.intersect(region)) {
642 // If the requested region is entirely outsides the image, just
643 // returns false
644 return false;
645 }
646
647 SkBitmap::Config config;
648 bool hasAlpha = false;
649 bool doDither = this->getDitherImage();
650 SkPMColor theTranspColor = 0; // 0 tells us not to try to match
651
652 if (!getBitmapConfig(png_ptr, info_ptr, &config, &hasAlpha, &doDither, &theT ranspColor)) {
306 return false; 653 return false;
307 } 654 }
308 655
309 const int sampleSize = this->getSampleSize(); 656 const int sampleSize = this->getSampleSize();
310 SkScaledBitmapSampler sampler(origWidth, origHeight, sampleSize); 657 SkScaledBitmapSampler sampler(origWidth, rect.height(), sampleSize);
311 658
312 decodedBitmap->setConfig(config, sampler.scaledWidth(), 659 SkBitmap decodedBitmap;
313 sampler.scaledHeight(), 0); 660 decodedBitmap.setConfig(config, sampler.scaledWidth(), sampler.scaledHeight( ), 0);
314 if (SkImageDecoder::kDecodeBounds_Mode == mode) {
315 return true;
316 }
317 661
318 // from here down we are concerned with colortables and pixels 662 // from here down we are concerned with colortables and pixels
319 663
320 // we track if we actually see a non-opaque pixels, since sometimes a PNG se ts its colortype 664 // we track if we actually see a non-opaque pixels, since sometimes a PNG se ts its colortype
321 // to |= PNG_COLOR_MASK_ALPHA, but all of its pixels are in fact opaque. We care, since we 665 // to |= PNG_COLOR_MASK_ALPHA, but all of its pixels are in fact opaque. We care, since we
322 // draw lots faster if we can flag the bitmap has being opaque 666 // draw lots faster if we can flag the bitmap has being opaque
323 bool reallyHasAlpha = false; 667 bool reallyHasAlpha = false;
324 SkColorTable* colorTable = NULL; 668 SkColorTable* colorTable = NULL;
325 669
326 if (color_type == PNG_COLOR_TYPE_PALETTE) { 670 if (colorType == PNG_COLOR_TYPE_PALETTE) {
327 int num_palette; 671 decodePalette(png_ptr, info_ptr, &hasAlpha, &reallyHasAlpha, &colorTable );
328 png_colorp palette;
329 png_bytep trans;
330 int num_trans;
331
332 png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette);
333
334 /* BUGGY IMAGE WORKAROUND
335
336 We hit some images (e.g. fruit_.png) who contain bytes that are == c olortable_count
337 which is a problem since we use the byte as an index. To work around this we grow
338 the colortable by 1 (if its < 256) and duplicate the last color into that slot.
339 */
340 int colorCount = num_palette + (num_palette < 256);
341
342 colorTable = SkNEW_ARGS(SkColorTable, (colorCount));
343
344 SkPMColor* colorPtr = colorTable->lockColors();
345 if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
346 png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, NULL);
347 hasAlpha = (num_trans > 0);
348 } else {
349 num_trans = 0;
350 colorTable->setFlags(colorTable->getFlags() | SkColorTable::kColorsA reOpaque_Flag);
351 }
352 // check for bad images that might make us crash
353 if (num_trans > num_palette) {
354 num_trans = num_palette;
355 }
356
357 int index = 0;
358 int transLessThanFF = 0;
359
360 for (; index < num_trans; index++) {
361 transLessThanFF |= (int)*trans - 0xFF;
362 *colorPtr++ = SkPreMultiplyARGB(*trans++, palette->red, palette->gre en, palette->blue);
363 palette++;
364 }
365 reallyHasAlpha |= (transLessThanFF < 0);
366
367 for (; index < num_palette; index++) {
368 *colorPtr++ = SkPackARGB32(0xFF, palette->red, palette->green, palet te->blue);
369 palette++;
370 }
371
372 // see BUGGY IMAGE WORKAROUND comment above
373 if (num_palette < 256) {
374 *colorPtr = colorPtr[-1];
375 }
376 colorTable->unlockColors(true);
377 } 672 }
378 673
379 SkAutoUnref aur(colorTable); 674 SkAutoUnref aur(colorTable);
380 675
381 if (!this->allocPixelRef(decodedBitmap, 676 // Check ahead of time if the swap(dest, src) is possible.
382 SkBitmap::kIndex8_Config == config ? 677 // If yes, then we will stick to AllocPixelRef since it's cheaper with the s wap happening.
383 colorTable : NULL)) { 678 // If no, then we will use alloc to allocate pixels to prevent garbage colle ction.
384 return false; 679 int w = rect.width() / sampleSize;
680 int h = rect.height() / sampleSize;
681 const bool swapOnly = (rect == region) && (w == decodedBitmap.width()) &&
682 (h == decodedBitmap.height()) && bm->isNull();
683 const bool needColorTable = SkBitmap::kIndex8_Config == config;
684 if (swapOnly) {
685 if (!this->allocPixelRef(&decodedBitmap, needColorTable ? colorTable : N ULL)) {
686 return false;
687 }
688 } else {
689 if (!decodedBitmap.allocPixels(NULL, needColorTable ? colorTable : NULL) ) {
690 return false;
691 }
385 } 692 }
386 693 SkAutoLockPixels alp(decodedBitmap);
387 SkAutoLockPixels alp(*decodedBitmap);
388
389 /* swap the RGBA or GA data to ARGB or AG (or BGRA to ABGR) */
390 // if (color_type == PNG_COLOR_TYPE_RGB_ALPHA)
391 // ; // png_set_swap_alpha(png_ptr);
392
393 /* swap bytes of 16 bit files to least significant byte first */
394 // png_set_swap(png_ptr);
395 694
396 /* Add filler (or alpha) byte (before/after each RGB triplet) */ 695 /* Add filler (or alpha) byte (before/after each RGB triplet) */
397 if (color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_GRAY) { 696 if (colorType == PNG_COLOR_TYPE_RGB || colorType == PNG_COLOR_TYPE_GRAY) {
398 png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER); 697 png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER);
399 } 698 }
400 699
401 /* Turn on interlace handling. REQUIRED if you are not using 700 /* Turn on interlace handling. REQUIRED if you are not using
402 * png_read_image(). To see how to handle interlacing passes, 701 * png_read_image(). To see how to handle interlacing passes,
403 * see the png_read_row() method below: 702 * see the png_read_row() method below:
404 */ 703 */
405 const int number_passes = interlace_type != PNG_INTERLACE_NONE ? 704 const int number_passes = (interlaceType != PNG_INTERLACE_NONE) ?
406 png_set_interlace_handling(png_ptr) : 1; 705 png_set_interlace_handling(png_ptr) : 1;
407 706
408 /* Optional call to gamma correct and add the background to the palette 707 /* Optional call to gamma correct and add the background to the palette
409 * and update info structure. REQUIRED if you are expecting libpng to 708 * and update info structure. REQUIRED if you are expecting libpng to
410 * update the palette for you (ie you selected such a transform above). 709 * update the palette for you (ie you selected such a transform above).
411 */ 710 */
711 png_ptr->pass = 0;
412 png_read_update_info(png_ptr, info_ptr); 712 png_read_update_info(png_ptr, info_ptr);
413 713
714 int actualTop = rect.fTop;
715
414 if (SkBitmap::kIndex8_Config == config && 1 == sampleSize) { 716 if (SkBitmap::kIndex8_Config == config && 1 == sampleSize) {
415 for (int i = 0; i < number_passes; i++) { 717 for (int i = 0; i < number_passes; i++) {
718 png_configure_decoder(png_ptr, &actualTop, i);
719 for (int j = 0; j < rect.fTop - actualTop; j++) {
720 uint8_t* bmRow = decodedBitmap.getAddr8(0, 0);
721 png_read_rows(png_ptr, &bmRow, png_bytepp_NULL, 1);
722 }
416 for (png_uint_32 y = 0; y < origHeight; y++) { 723 for (png_uint_32 y = 0; y < origHeight; y++) {
417 uint8_t* bmRow = decodedBitmap->getAddr8(0, y); 724 uint8_t* bmRow = decodedBitmap.getAddr8(0, y);
418 png_read_rows(png_ptr, &bmRow, NULL, 1); 725 png_read_rows(png_ptr, &bmRow, png_bytepp_NULL, 1);
419 } 726 }
420 } 727 }
421 } else { 728 } else {
422 SkScaledBitmapSampler::SrcConfig sc; 729 SkScaledBitmapSampler::SrcConfig sc;
423 int srcBytesPerPixel = 4; 730 int srcBytesPerPixel = 4;
424 731
425 if (colorTable != NULL) { 732 if (colorTable != NULL) {
426 sc = SkScaledBitmapSampler::kIndex; 733 sc = SkScaledBitmapSampler::kIndex;
427 srcBytesPerPixel = 1; 734 srcBytesPerPixel = 1;
428 } else if (hasAlpha) { 735 } else if (hasAlpha) {
429 sc = SkScaledBitmapSampler::kRGBA; 736 sc = SkScaledBitmapSampler::kRGBA;
430 } else { 737 } else {
431 sc = SkScaledBitmapSampler::kRGBX; 738 sc = SkScaledBitmapSampler::kRGBX;
432 } 739 }
433 740
434 /* We have to pass the colortable explicitly, since we may have one 741 /* We have to pass the colortable explicitly, since we may have one
435 even if our decodedBitmap doesn't, due to the request that we 742 even if our decodedBitmap doesn't, due to the request that we
436 upscale png's palette to a direct model 743 upscale png's palette to a direct model
437 */ 744 */
438 SkAutoLockColors ctLock(colorTable); 745 SkAutoLockColors ctLock(colorTable);
439 if (!sampler.begin(decodedBitmap, sc, doDither, ctLock.colors())) { 746 if (!sampler.begin(&decodedBitmap, sc, doDither, ctLock.colors())) {
440 return false; 747 return false;
441 } 748 }
442 const int height = decodedBitmap->height(); 749 const int height = decodedBitmap.height();
443 750
444 if (number_passes > 1) { 751 if (number_passes > 1) {
445 SkAutoMalloc storage(origWidth * origHeight * srcBytesPerPixel); 752 SkAutoMalloc storage(origWidth * origHeight * srcBytesPerPixel);
446 uint8_t* base = (uint8_t*)storage.get(); 753 uint8_t* base = (uint8_t*)storage.get();
447 size_t rb = origWidth * srcBytesPerPixel; 754 size_t rb = origWidth * srcBytesPerPixel;
448 755
449 for (int i = 0; i < number_passes; i++) { 756 for (int i = 0; i < number_passes; i++) {
757 png_configure_decoder(png_ptr, &actualTop, i);
758 for (int j = 0; j < rect.fTop - actualTop; j++) {
759 uint8_t* bmRow = (uint8_t*)decodedBitmap.getPixels();
760 png_read_rows(png_ptr, &bmRow, png_bytepp_NULL, 1);
761 }
450 uint8_t* row = base; 762 uint8_t* row = base;
451 for (png_uint_32 y = 0; y < origHeight; y++) { 763 for (int32_t y = 0; y < rect.height(); y++) {
452 uint8_t* bmRow = row; 764 uint8_t* bmRow = row;
453 png_read_rows(png_ptr, &bmRow, NULL, 1); 765 png_read_rows(png_ptr, &bmRow, png_bytepp_NULL, 1);
454 row += rb; 766 row += rb;
455 } 767 }
456 } 768 }
457 // now sample it 769 // now sample it
458 base += sampler.srcY0() * rb; 770 base += sampler.srcY0() * rb;
459 for (int y = 0; y < height; y++) { 771 for (int y = 0; y < height; y++) {
460 reallyHasAlpha |= sampler.next(base); 772 reallyHasAlpha |= sampler.next(base);
461 base += sampler.srcDY() * rb; 773 base += sampler.srcDY() * rb;
462 } 774 }
463 } else { 775 } else {
464 SkAutoMalloc storage(origWidth * srcBytesPerPixel); 776 SkAutoMalloc storage(origWidth * srcBytesPerPixel);
465 uint8_t* srcRow = (uint8_t*)storage.get(); 777 uint8_t* srcRow = (uint8_t*)storage.get();
778
779 png_configure_decoder(png_ptr, &actualTop, 0);
466 skip_src_rows(png_ptr, srcRow, sampler.srcY0()); 780 skip_src_rows(png_ptr, srcRow, sampler.srcY0());
467 781
782 for (int i = 0; i < rect.fTop - actualTop; i++) {
783 uint8_t* bmRow = (uint8_t*)decodedBitmap.getPixels();
784 png_read_rows(png_ptr, &bmRow, png_bytepp_NULL, 1);
785 }
468 for (int y = 0; y < height; y++) { 786 for (int y = 0; y < height; y++) {
469 uint8_t* tmp = srcRow; 787 uint8_t* tmp = srcRow;
470 png_read_rows(png_ptr, &tmp, NULL, 1); 788 png_read_rows(png_ptr, &tmp, png_bytepp_NULL, 1);
471 reallyHasAlpha |= sampler.next(srcRow); 789 reallyHasAlpha |= sampler.next(srcRow);
472 if (y < height - 1) { 790 if (y < height - 1) {
473 skip_src_rows(png_ptr, srcRow, sampler.srcDY() - 1); 791 skip_src_rows(png_ptr, srcRow, sampler.srcDY() - 1);
474 } 792 }
475 } 793 }
476
477 // skip the rest of the rows (if any)
478 png_uint_32 read = (height - 1) * sampler.srcDY() +
479 sampler.srcY0() + 1;
480 SkASSERT(read <= origHeight);
481 skip_src_rows(png_ptr, srcRow, origHeight - read);
482 } 794 }
483 } 795 }
484 796
485 /* read rest of file, and get additional chunks in info_ptr - REQUIRED */ 797 if (0 != theTranspColor) {
486 png_read_end(png_ptr, info_ptr); 798 reallyHasAlpha |= substituteTranspColor(&decodedBitmap, theTranspColor);
799 }
800 decodedBitmap.setIsOpaque(!reallyHasAlpha);
487 801
488 if (0 != theTranspColor) { 802 if (swapOnly) {
489 reallyHasAlpha |= substituteTranspColor(decodedBitmap, theTranspColor); 803 bm->swap(decodedBitmap);
804 } else {
805 cropBitmap(bm, &decodedBitmap, sampleSize, region.x(), region.y(),
806 region.width(), region.height(), 0, rect.y());
490 } 807 }
491 decodedBitmap->setIsOpaque(!reallyHasAlpha); 808
492 return true; 809 return true;
493 } 810 }
811 #endif
494 812
495 /////////////////////////////////////////////////////////////////////////////// 813 ///////////////////////////////////////////////////////////////////////////////
496 814
497 #include "SkColorPriv.h" 815 #include "SkColorPriv.h"
498 #include "SkUnPreMultiply.h" 816 #include "SkUnPreMultiply.h"
499 817
500 static void sk_write_fn(png_structp png_ptr, png_bytep data, png_size_t len) { 818 static void sk_write_fn(png_structp png_ptr, png_bytep data, png_size_t len) {
501 SkWStream* sk_stream = (SkWStream*)png_get_io_ptr(png_ptr); 819 SkWStream* sk_stream = (SkWStream*)png_ptr->io_ptr;
502 if (!sk_stream->write(data, len)) { 820 if (!sk_stream->write(data, len)) {
503 png_error(png_ptr, "sk_write_fn Error!"); 821 png_error(png_ptr, "sk_write_fn Error!");
504 } 822 }
505 } 823 }
506 824
507 static transform_scanline_proc choose_proc(SkBitmap::Config config, 825 static transform_scanline_proc choose_proc(SkBitmap::Config config,
508 bool hasAlpha) { 826 bool hasAlpha) {
509 // we don't care about search on alpha if we're kIndex8, since only the 827 // we don't care about search on alpha if we're kIndex8, since only the
510 // colortable packing cares about that distinction, not the pixels 828 // colortable packing cares about that distinction, not the pixels
511 if (SkBitmap::kIndex8_Config == config) { 829 if (SkBitmap::kIndex8_Config == config) {
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after
602 SkPMColor c = *colors++; 920 SkPMColor c = *colors++;
603 palette[i].red = SkGetPackedR32(c); 921 palette[i].red = SkGetPackedR32(c);
604 palette[i].green = SkGetPackedG32(c); 922 palette[i].green = SkGetPackedG32(c);
605 palette[i].blue = SkGetPackedB32(c); 923 palette[i].blue = SkGetPackedB32(c);
606 } 924 }
607 return num_trans; 925 return num_trans;
608 } 926 }
609 927
610 class SkPNGImageEncoder : public SkImageEncoder { 928 class SkPNGImageEncoder : public SkImageEncoder {
611 protected: 929 protected:
612 virtual bool onEncode(SkWStream* stream, const SkBitmap& bm, int quality); 930 virtual bool onEncode(SkWStream* stream, const SkBitmap& bm, int quality) SK _OVERRIDE;
613 private: 931 private:
614 bool doEncode(SkWStream* stream, const SkBitmap& bm, 932 bool doEncode(SkWStream* stream, const SkBitmap& bm,
615 const bool& hasAlpha, int colorType, 933 const bool& hasAlpha, int colorType,
616 int bitDepth, SkBitmap::Config config, 934 int bitDepth, SkBitmap::Config config,
617 png_color_8& sig_bit); 935 png_color_8& sig_bit);
936
937 typedef SkImageEncoder INHERITED;
618 }; 938 };
619 939
620 bool SkPNGImageEncoder::onEncode(SkWStream* stream, const SkBitmap& bitmap, 940 bool SkPNGImageEncoder::onEncode(SkWStream* stream, const SkBitmap& bitmap,
621 int /*quality*/) { 941 int /*quality*/) {
622 SkBitmap::Config config = bitmap.getConfig(); 942 SkBitmap::Config config = bitmap.getConfig();
623 943
624 const bool hasAlpha = !bitmap.isOpaque(); 944 const bool hasAlpha = !bitmap.isOpaque();
625 int colorType = PNG_COLOR_MASK_COLOR; 945 int colorType = PNG_COLOR_MASK_COLOR;
626 int bitDepth = 8; // default for color 946 int bitDepth = 8; // default for color
627 png_color_8 sig_bit; 947 png_color_8 sig_bit;
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
690 png_infop info_ptr; 1010 png_infop info_ptr;
691 1011
692 png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, sk_error_fn, 1012 png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, sk_error_fn,
693 NULL); 1013 NULL);
694 if (NULL == png_ptr) { 1014 if (NULL == png_ptr) {
695 return false; 1015 return false;
696 } 1016 }
697 1017
698 info_ptr = png_create_info_struct(png_ptr); 1018 info_ptr = png_create_info_struct(png_ptr);
699 if (NULL == info_ptr) { 1019 if (NULL == info_ptr) {
700 png_destroy_write_struct(&png_ptr, NULL); 1020 png_destroy_write_struct(&png_ptr, png_infopp_NULL);
701 return false; 1021 return false;
702 } 1022 }
703 1023
704 /* Set error handling. REQUIRED if you aren't supplying your own 1024 /* Set error handling. REQUIRED if you aren't supplying your own
705 * error handling functions in the png_create_write_struct() call. 1025 * error handling functions in the png_create_write_struct() call.
706 */ 1026 */
707 if (setjmp(png_jmpbuf(png_ptr))) { 1027 if (setjmp(png_jmpbuf(png_ptr))) {
708 png_destroy_write_struct(&png_ptr, &info_ptr); 1028 png_destroy_write_struct(&png_ptr, &info_ptr);
709 return false; 1029 return false;
710 } 1030 }
711 1031
712 png_set_write_fn(png_ptr, (void*)stream, sk_write_fn, NULL); 1032 png_set_write_fn(png_ptr, (void*)stream, sk_write_fn, png_flush_ptr_NULL);
713 1033
714 /* Set the image information here. Width and height are up to 2^31, 1034 /* Set the image information here. Width and height are up to 2^31,
715 * bit_depth is one of 1, 2, 4, 8, or 16, but valid values also depend on 1035 * bit_depth is one of 1, 2, 4, 8, or 16, but valid values also depend on
716 * the color_type selected. color_type is one of PNG_COLOR_TYPE_GRAY, 1036 * the color_type selected. color_type is one of PNG_COLOR_TYPE_GRAY,
717 * PNG_COLOR_TYPE_GRAY_ALPHA, PNG_COLOR_TYPE_PALETTE, PNG_COLOR_TYPE_RGB, 1037 * PNG_COLOR_TYPE_GRAY_ALPHA, PNG_COLOR_TYPE_PALETTE, PNG_COLOR_TYPE_RGB,
718 * or PNG_COLOR_TYPE_RGB_ALPHA. interlace is either PNG_INTERLACE_NONE or 1038 * or PNG_COLOR_TYPE_RGB_ALPHA. interlace is either PNG_INTERLACE_NONE or
719 * PNG_INTERLACE_ADAM7, and the compression_type and filter_type MUST 1039 * PNG_INTERLACE_ADAM7, and the compression_type and filter_type MUST
720 * currently be PNG_COMPRESSION_TYPE_BASE and PNG_FILTER_TYPE_BASE. REQUIRED 1040 * currently be PNG_COMPRESSION_TYPE_BASE and PNG_FILTER_TYPE_BASE. REQUIRED
721 */ 1041 */
722 1042
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
779 } 1099 }
780 return NULL; 1100 return NULL;
781 } 1101 }
782 1102
783 SkImageEncoder* sk_libpng_efactory(SkImageEncoder::Type t) { 1103 SkImageEncoder* sk_libpng_efactory(SkImageEncoder::Type t) {
784 return (SkImageEncoder::kPNG_Type == t) ? SkNEW(SkPNGImageEncoder) : NULL; 1104 return (SkImageEncoder::kPNG_Type == t) ? SkNEW(SkPNGImageEncoder) : NULL;
785 } 1105 }
786 1106
787 static SkTRegistry<SkImageEncoder*, SkImageEncoder::Type> gEReg(sk_libpng_efacto ry); 1107 static SkTRegistry<SkImageEncoder*, SkImageEncoder::Type> gEReg(sk_libpng_efacto ry);
788 static SkTRegistry<SkImageDecoder*, SkStream*> gDReg(sk_libpng_dfactory); 1108 static SkTRegistry<SkImageDecoder*, SkStream*> gDReg(sk_libpng_dfactory);
OLDNEW
« no previous file with comments | « src/images/SkImageDecoder_libico.cpp ('k') | src/images/SkImageDecoder_libwebp.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698