OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright 2015 Google Inc. | 2 * Copyright 2015 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #include "SkCodec_libpng.h" | 8 #include "SkCodec_libpng.h" |
9 #include "SkColorPriv.h" | 9 #include "SkColorPriv.h" |
10 #include "SkColorTable.h" | 10 #include "SkColorTable.h" |
11 #include "SkBitmap.h" | 11 #include "SkBitmap.h" |
12 #include "SkMath.h" | 12 #include "SkMath.h" |
13 #include "SkScanlineDecoder.h" | |
13 #include "SkSize.h" | 14 #include "SkSize.h" |
14 #include "SkStream.h" | 15 #include "SkStream.h" |
15 #include "SkSwizzler.h" | 16 #include "SkSwizzler.h" |
16 | 17 |
17 /////////////////////////////////////////////////////////////////////////////// | 18 /////////////////////////////////////////////////////////////////////////////// |
18 // Helper macros | 19 // Helper macros |
19 /////////////////////////////////////////////////////////////////////////////// | 20 /////////////////////////////////////////////////////////////////////////////// |
20 | 21 |
21 #ifndef png_jmpbuf | 22 #ifndef png_jmpbuf |
22 # define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf) | 23 # define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf) |
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
106 png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, NULL); | 107 png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, NULL); |
107 return num_trans > 0; | 108 return num_trans > 0; |
108 } | 109 } |
109 | 110 |
110 // Method for coverting to either an SkPMColor or a similarly packed | 111 // Method for coverting to either an SkPMColor or a similarly packed |
111 // unpremultiplied color. | 112 // unpremultiplied color. |
112 typedef uint32_t (*PackColorProc)(U8CPU a, U8CPU r, U8CPU g, U8CPU b); | 113 typedef uint32_t (*PackColorProc)(U8CPU a, U8CPU r, U8CPU g, U8CPU b); |
113 | 114 |
114 // Note: SkColorTable claims to store SkPMColors, which is not necessarily | 115 // Note: SkColorTable claims to store SkPMColors, which is not necessarily |
115 // the case here. | 116 // the case here. |
116 SkColorTable* decode_palette(png_structp png_ptr, png_infop info_ptr, | 117 bool SkPngCodec::decodePalette(bool premultiply) { |
117 bool premultiply, SkAlphaType* outAlphaType) { | |
118 SkASSERT(outAlphaType != NULL); | |
119 int numPalette; | 118 int numPalette; |
120 png_colorp palette; | 119 png_colorp palette; |
121 png_bytep trans; | 120 png_bytep trans; |
122 | 121 |
123 if (!png_get_PLTE(png_ptr, info_ptr, &palette, &numPalette)) { | 122 if (!png_get_PLTE(fPng_ptr, fInfo_ptr, &palette, &numPalette)) { |
124 return NULL; | 123 return false; |
125 } | 124 } |
126 | 125 |
127 /* BUGGY IMAGE WORKAROUND | 126 /* BUGGY IMAGE WORKAROUND |
128 | 127 |
129 We hit some images (e.g. fruit_.png) who contain bytes that are == color table_count | 128 We hit some images (e.g. fruit_.png) who contain bytes that are == color table_count |
130 which is a problem since we use the byte as an index. To work around thi s we grow | 129 which is a problem since we use the byte as an index. To work around thi s we grow |
131 the colortable by 1 (if its < 256) and duplicate the last color into tha t slot. | 130 the colortable by 1 (if its < 256) and duplicate the last color into tha t slot. |
132 */ | 131 */ |
133 const int colorCount = numPalette + (numPalette < 256); | 132 const int colorCount = numPalette + (numPalette < 256); |
134 // Note: These are not necessarily SkPMColors. | 133 // Note: These are not necessarily SkPMColors. |
135 SkPMColor colorStorage[256]; // worst-case storage | 134 SkPMColor colorStorage[256]; // worst-case storage |
136 SkPMColor* colorPtr = colorStorage; | 135 SkPMColor* colorPtr = colorStorage; |
137 | 136 |
138 int numTrans; | 137 int numTrans; |
139 if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { | 138 if (png_get_valid(fPng_ptr, fInfo_ptr, PNG_INFO_tRNS)) { |
140 png_get_tRNS(png_ptr, info_ptr, &trans, &numTrans, NULL); | 139 png_get_tRNS(fPng_ptr, fInfo_ptr, &trans, &numTrans, NULL); |
141 } else { | 140 } else { |
142 numTrans = 0; | 141 numTrans = 0; |
143 } | 142 } |
144 | 143 |
145 // check for bad images that might make us crash | 144 // check for bad images that might make us crash |
146 if (numTrans > numPalette) { | 145 if (numTrans > numPalette) { |
147 numTrans = numPalette; | 146 numTrans = numPalette; |
148 } | 147 } |
149 | 148 |
150 int index = 0; | 149 int index = 0; |
151 int transLessThanFF = 0; | 150 int transLessThanFF = 0; |
152 | 151 |
153 // Choose which function to use to create the color table. If the final dest ination's | 152 // Choose which function to use to create the color table. If the final dest ination's |
154 // colortype is unpremultiplied, the color table will store unpremultiplied colors. | 153 // colortype is unpremultiplied, the color table will store unpremultiplied colors. |
155 PackColorProc proc; | 154 PackColorProc proc; |
156 if (premultiply) { | 155 if (premultiply) { |
157 proc = &SkPreMultiplyARGB; | 156 proc = &SkPreMultiplyARGB; |
158 } else { | 157 } else { |
159 proc = &SkPackARGB32NoCheck; | 158 proc = &SkPackARGB32NoCheck; |
160 } | 159 } |
161 for (; index < numTrans; index++) { | 160 for (; index < numTrans; index++) { |
162 transLessThanFF |= (int)*trans - 0xFF; | 161 transLessThanFF |= (int)*trans - 0xFF; |
163 *colorPtr++ = proc(*trans++, palette->red, palette->green, palette->blue ); | 162 *colorPtr++ = proc(*trans++, palette->red, palette->green, palette->blue ); |
164 palette++; | 163 palette++; |
165 } | 164 } |
166 | 165 |
167 if (transLessThanFF < 0) { | 166 fReallyHasAlpha = transLessThanFF < 0; |
168 *outAlphaType = premultiply ? kPremul_SkAlphaType : kUnpremul_SkAlphaTyp e; | |
169 } else { | |
170 *outAlphaType = kOpaque_SkAlphaType; | |
171 } | |
172 | 167 |
173 for (; index < numPalette; index++) { | 168 for (; index < numPalette; index++) { |
174 *colorPtr++ = SkPackARGB32(0xFF, palette->red, palette->green, palette-> blue); | 169 *colorPtr++ = SkPackARGB32(0xFF, palette->red, palette->green, palette-> blue); |
175 palette++; | 170 palette++; |
176 } | 171 } |
177 | 172 |
178 // see BUGGY IMAGE WORKAROUND comment above | 173 // see BUGGY IMAGE WORKAROUND comment above |
179 if (numPalette < 256) { | 174 if (numPalette < 256) { |
180 *colorPtr = colorPtr[-1]; | 175 *colorPtr = colorPtr[-1]; |
181 } | 176 } |
182 | 177 |
183 return SkNEW_ARGS(SkColorTable, (colorStorage, colorCount)); | 178 fColorTable.reset(SkNEW_ARGS(SkColorTable, (colorStorage, colorCount))); |
179 return true; | |
184 } | 180 } |
185 | 181 |
186 /////////////////////////////////////////////////////////////////////////////// | 182 /////////////////////////////////////////////////////////////////////////////// |
187 // Creation | 183 // Creation |
188 /////////////////////////////////////////////////////////////////////////////// | 184 /////////////////////////////////////////////////////////////////////////////// |
189 | 185 |
190 #define PNG_BYTES_TO_CHECK 4 | 186 #define PNG_BYTES_TO_CHECK 4 |
191 | 187 |
192 bool SkPngCodec::IsPng(SkStream* stream) { | 188 bool SkPngCodec::IsPng(SkStream* stream) { |
193 char buf[PNG_BYTES_TO_CHECK]; | 189 char buf[PNG_BYTES_TO_CHECK]; |
(...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
325 | 321 |
326 // FIXME: Also need to check for sRGB (skbug.com/3471). | 322 // FIXME: Also need to check for sRGB (skbug.com/3471). |
327 | 323 |
328 SkImageInfo info = SkImageInfo::Make(origWidth, origHeight, skColorType, | 324 SkImageInfo info = SkImageInfo::Make(origWidth, origHeight, skColorType, |
329 skAlphaType); | 325 skAlphaType); |
330 SkCodec* codec = SkNEW_ARGS(SkPngCodec, (info, stream, png_ptr, info_ptr)); | 326 SkCodec* codec = SkNEW_ARGS(SkPngCodec, (info, stream, png_ptr, info_ptr)); |
331 autoClean.detach(); | 327 autoClean.detach(); |
332 return codec; | 328 return codec; |
333 } | 329 } |
334 | 330 |
331 #define INVALID_NUMBER_PASSES -1 | |
335 SkPngCodec::SkPngCodec(const SkImageInfo& info, SkStream* stream, | 332 SkPngCodec::SkPngCodec(const SkImageInfo& info, SkStream* stream, |
336 png_structp png_ptr, png_infop info_ptr) | 333 png_structp png_ptr, png_infop info_ptr) |
337 : INHERITED(info, stream) | 334 : INHERITED(info, stream) |
338 , fPng_ptr(png_ptr) | 335 , fPng_ptr(png_ptr) |
339 , fInfo_ptr(info_ptr) {} | 336 , fInfo_ptr(info_ptr) |
337 , fSc(SkSwizzler::kUnknown) | |
338 , fNumberPasses(INVALID_NUMBER_PASSES) | |
339 , fReallyHasAlpha(false) | |
340 {} | |
340 | 341 |
341 SkPngCodec::~SkPngCodec() { | 342 SkPngCodec::~SkPngCodec() { |
342 png_destroy_read_struct(&fPng_ptr, &fInfo_ptr, png_infopp_NULL); | 343 png_destroy_read_struct(&fPng_ptr, &fInfo_ptr, png_infopp_NULL); |
343 } | 344 } |
344 | 345 |
345 /////////////////////////////////////////////////////////////////////////////// | 346 /////////////////////////////////////////////////////////////////////////////// |
346 // Getting the pixels | 347 // Getting the pixels |
347 /////////////////////////////////////////////////////////////////////////////// | 348 /////////////////////////////////////////////////////////////////////////////// |
348 | 349 |
349 static bool premul_and_unpremul(SkAlphaType A, SkAlphaType B) { | 350 static bool premul_and_unpremul(SkAlphaType A, SkAlphaType B) { |
350 return kPremul_SkAlphaType == A && kUnpremul_SkAlphaType == B; | 351 return kPremul_SkAlphaType == A && kUnpremul_SkAlphaType == B; |
351 } | 352 } |
352 | 353 |
353 static bool conversion_possible(const SkImageInfo& A, const SkImageInfo& B) { | 354 static bool conversion_possible(const SkImageInfo& A, const SkImageInfo& B) { |
354 // TODO: Support other conversions | 355 // TODO: Support other conversions |
355 if (A.colorType() != B.colorType()) { | 356 if (A.colorType() != B.colorType()) { |
356 return false; | 357 return false; |
357 } | 358 } |
358 if (A.profileType() != B.profileType()) { | 359 if (A.profileType() != B.profileType()) { |
359 return false; | 360 return false; |
360 } | 361 } |
361 if (A.alphaType() == B.alphaType()) { | 362 if (A.alphaType() == B.alphaType()) { |
362 return true; | 363 return true; |
363 } | 364 } |
364 return premul_and_unpremul(A.alphaType(), B.alphaType()) | 365 return premul_and_unpremul(A.alphaType(), B.alphaType()) |
365 || premul_and_unpremul(B.alphaType(), A.alphaType()); | 366 || premul_and_unpremul(B.alphaType(), A.alphaType()); |
366 } | 367 } |
367 | 368 |
368 SkCodec::Result SkPngCodec::onGetPixels(const SkImageInfo& requestedInfo, void* dst, | 369 SkCodec::Result SkPngCodec::initializeSwizzler(const SkImageInfo& requestedInfo, void* dst, |
369 size_t rowBytes, SkPMColor ctable[], | 370 size_t rowBytes) { |
370 int* ctableCount) { | |
371 if (!this->rewindIfNeeded()) { | |
372 return kCouldNotRewind; | |
373 } | |
374 if (requestedInfo.dimensions() != this->getOriginalInfo().dimensions()) { | |
375 return kInvalidScale; | |
376 } | |
377 if (!conversion_possible(requestedInfo, this->getOriginalInfo())) { | |
378 return kInvalidConversion; | |
379 } | |
380 | |
381 SkBitmap decodedBitmap; | |
382 // If installPixels would have failed, getPixels should have failed before | |
383 // calling onGetPixels. | |
384 SkAssertResult(decodedBitmap.installPixels(requestedInfo, dst, rowBytes)); | |
385 | |
386 // Initialize all non-trivial objects before setjmp. | |
387 SkAutoTUnref<SkColorTable> colorTable; | |
388 SkAutoTDelete<SkSwizzler> swizzler; | |
389 SkAutoMalloc storage; // Scratch memory for pre-swizzled r ows. | |
390 | |
391 // FIXME: Could we use the return value of setjmp to specify the type of | 371 // FIXME: Could we use the return value of setjmp to specify the type of |
392 // error? | 372 // error? |
393 if (setjmp(png_jmpbuf(fPng_ptr))) { | 373 if (setjmp(png_jmpbuf(fPng_ptr))) { |
394 SkDebugf("setjmp long jump!\n"); | 374 SkDebugf("setjmp long jump!\n"); |
395 return kInvalidInput; | 375 return kInvalidInput; |
396 } | 376 } |
397 | 377 |
398 // FIXME: We already retrieved this information. Store it in SkPngCodec? | 378 // FIXME: We already retrieved this information. Store it in SkPngCodec? |
399 png_uint_32 origWidth, origHeight; | 379 png_uint_32 origWidth, origHeight; |
400 int bitDepth, pngColorType, interlaceType; | 380 int bitDepth, pngColorType, interlaceType; |
401 png_get_IHDR(fPng_ptr, fInfo_ptr, &origWidth, &origHeight, &bitDepth, | 381 png_get_IHDR(fPng_ptr, fInfo_ptr, &origWidth, &origHeight, &bitDepth, |
402 &pngColorType, &interlaceType, int_p_NULL, int_p_NULL); | 382 &pngColorType, &interlaceType, int_p_NULL, int_p_NULL); |
403 | 383 |
404 const int numberPasses = (interlaceType != PNG_INTERLACE_NONE) ? | 384 fNumberPasses = (interlaceType != PNG_INTERLACE_NONE) ? |
405 png_set_interlace_handling(fPng_ptr) : 1; | 385 png_set_interlace_handling(fPng_ptr) : 1; |
406 | 386 |
407 SkSwizzler::SrcConfig sc; | 387 // Set to the default before calling decodePalette, which may change it. |
408 bool reallyHasAlpha = false; | 388 fReallyHasAlpha = false; |
409 if (PNG_COLOR_TYPE_PALETTE == pngColorType) { | 389 if (PNG_COLOR_TYPE_PALETTE == pngColorType) { |
410 sc = SkSwizzler::kIndex; | 390 fSc = SkSwizzler::kIndex; |
411 SkAlphaType at = requestedInfo.alphaType(); | 391 if (!this->decodePalette(kPremul_SkAlphaType == requestedInfo.alphaType( ))) { |
412 colorTable.reset(decode_palette(fPng_ptr, fInfo_ptr, | |
413 kPremul_SkAlphaType == at, | |
414 &at)); | |
415 if (!colorTable) { | |
416 return kInvalidInput; | 392 return kInvalidInput; |
417 } | 393 } |
418 | |
419 reallyHasAlpha = (at != kOpaque_SkAlphaType); | |
420 | |
421 if (at != requestedInfo.alphaType()) { | |
422 // It turns out the image is opaque. | |
423 SkASSERT(kOpaque_SkAlphaType == at); | |
424 } | |
425 } else if (kAlpha_8_SkColorType == requestedInfo.colorType()) { | 394 } else if (kAlpha_8_SkColorType == requestedInfo.colorType()) { |
426 // Note: we check the destination, since otherwise we would have | 395 // Note: we check the destination, since otherwise we would have |
427 // told png to upscale. | 396 // told png to upscale. |
428 SkASSERT(PNG_COLOR_TYPE_GRAY == pngColorType); | 397 SkASSERT(PNG_COLOR_TYPE_GRAY == pngColorType); |
429 sc = SkSwizzler::kGray; | 398 fSc = SkSwizzler::kGray; |
430 } else if (this->getOriginalInfo().alphaType() == kOpaque_SkAlphaType) { | 399 } else if (this->getOriginalInfo().alphaType() == kOpaque_SkAlphaType) { |
431 sc = SkSwizzler::kRGBX; | 400 fSc = SkSwizzler::kRGBX; |
432 } else { | 401 } else { |
433 sc = SkSwizzler::kRGBA; | 402 fSc = SkSwizzler::kRGBA; |
434 } | 403 } |
435 const SkPMColor* colors = colorTable ? colorTable->readColors() : NULL; | 404 const SkPMColor* colors = fColorTable ? fColorTable->readColors() : NULL; |
436 // TODO: Support skipZeroes. | 405 // TODO: Support skipZeroes. |
437 swizzler.reset(SkSwizzler::CreateSwizzler(sc, colors, requestedInfo, | 406 fSwizzler.reset(SkSwizzler::CreateSwizzler(fSc, colors, requestedInfo, |
438 dst, rowBytes, false)); | 407 dst, rowBytes, false)); |
439 if (!swizzler) { | 408 if (!fSwizzler) { |
440 // FIXME: CreateSwizzler could fail for another reason. | 409 // FIXME: CreateSwizzler could fail for another reason. |
441 return kUnimplemented; | 410 return kUnimplemented; |
442 } | 411 } |
443 | 412 |
444 // FIXME: Here is where we should likely insert some of the modifications | 413 // FIXME: Here is where we should likely insert some of the modifications |
445 // made in the factory. | 414 // made in the factory. |
446 png_read_update_info(fPng_ptr, fInfo_ptr); | 415 png_read_update_info(fPng_ptr, fInfo_ptr); |
447 | 416 |
448 if (numberPasses > 1) { | 417 return kSuccess; |
418 } | |
419 | |
420 SkCodec::Result SkPngCodec::onGetPixels(const SkImageInfo& requestedInfo, void* dst, | |
421 size_t rowBytes, SkPMColor ctable[], | |
422 int* ctableCount) { | |
423 if (!this->rewindIfNeeded()) { | |
424 return kCouldNotRewind; | |
425 } | |
426 if (requestedInfo.dimensions() != this->getOriginalInfo().dimensions()) { | |
427 return kInvalidScale; | |
428 } | |
429 if (!conversion_possible(requestedInfo, this->getOriginalInfo())) { | |
430 return kInvalidConversion; | |
431 } | |
432 | |
433 const Result result = this->initializeSwizzler(requestedInfo, dst, rowBytes) ; | |
434 if (result != kSuccess) { | |
435 return result; | |
436 } | |
437 | |
438 // FIXME: Could we use the return value of setjmp to specify the type of | |
439 // error? | |
440 if (setjmp(png_jmpbuf(fPng_ptr))) { | |
441 SkDebugf("setjmp long jump!\n"); | |
442 return kInvalidInput; | |
443 } | |
444 | |
445 SkASSERT(fNumberPasses != INVALID_NUMBER_PASSES); | |
446 SkAutoMalloc storage; | |
447 if (fNumberPasses > 1) { | |
449 const int width = requestedInfo.width(); | 448 const int width = requestedInfo.width(); |
450 const int height = requestedInfo.height(); | 449 const int height = requestedInfo.height(); |
451 const int bpp = SkSwizzler::BytesPerPixel(sc); | 450 const int bpp = SkSwizzler::BytesPerPixel(fSc); |
452 const size_t rowBytes = width * bpp; | 451 const size_t rowBytes = width * bpp; |
453 | 452 |
454 storage.reset(width * height * bpp); | 453 storage.reset(width * height * bpp); |
455 uint8_t* const base = static_cast<uint8_t*>(storage.get()); | 454 uint8_t* const base = static_cast<uint8_t*>(storage.get()); |
456 | 455 |
457 for (int i = 0; i < numberPasses; i++) { | 456 for (int i = 0; i < fNumberPasses; i++) { |
458 uint8_t* row = base; | 457 uint8_t* row = base; |
459 for (int y = 0; y < height; y++) { | 458 for (int y = 0; y < height; y++) { |
460 uint8_t* bmRow = row; | 459 uint8_t* bmRow = row; |
461 png_read_rows(fPng_ptr, &bmRow, png_bytepp_NULL, 1); | 460 png_read_rows(fPng_ptr, &bmRow, png_bytepp_NULL, 1); |
462 row += rowBytes; | 461 row += rowBytes; |
463 } | 462 } |
464 } | 463 } |
465 | 464 |
466 // Now swizzle it. | 465 // Now swizzle it. |
467 uint8_t* row = base; | 466 uint8_t* row = base; |
468 for (int y = 0; y < height; y++) { | 467 for (int y = 0; y < height; y++) { |
469 reallyHasAlpha |= swizzler->next(row); | 468 fReallyHasAlpha |= fSwizzler->next(row); |
470 row += rowBytes; | 469 row += rowBytes; |
471 } | 470 } |
472 } else { | 471 } else { |
473 storage.reset(requestedInfo.width() * SkSwizzler::BytesPerPixel(sc)); | 472 storage.reset(requestedInfo.width() * SkSwizzler::BytesPerPixel(fSc)); |
474 uint8_t* srcRow = static_cast<uint8_t*>(storage.get()); | 473 uint8_t* srcRow = static_cast<uint8_t*>(storage.get()); |
475 for (int y = 0; y < requestedInfo.height(); y++) { | 474 for (int y = 0; y < requestedInfo.height(); y++) { |
476 png_read_rows(fPng_ptr, &srcRow, png_bytepp_NULL, 1); | 475 png_read_rows(fPng_ptr, &srcRow, png_bytepp_NULL, 1); |
477 reallyHasAlpha |= swizzler->next(srcRow); | 476 fReallyHasAlpha |= fSwizzler->next(srcRow); |
478 } | 477 } |
479 } | 478 } |
480 | 479 |
480 // FIXME: do we need substituteTranspColor? Note that we cannot do it for | |
481 // scanline decoding, but we could do it here. Alternatively, we could do | |
482 // it as we go, instead of in post-processing like SkPNGImageDecoder. | |
483 | |
484 return this->finish(); | |
485 } | |
486 | |
487 SkImageGenerator::Result SkPngCodec::finish() { | |
488 // FIXME: Maybe these should return incomplete? | |
489 if (setjmp(png_jmpbuf(fPng_ptr))) { | |
490 SkDebugf("setjmp long jump!\n"); | |
491 return kInvalidInput; | |
492 } | |
481 /* read rest of file, and get additional chunks in info_ptr - REQUIRED */ | 493 /* read rest of file, and get additional chunks in info_ptr - REQUIRED */ |
482 png_read_end(fPng_ptr, fInfo_ptr); | 494 png_read_end(fPng_ptr, fInfo_ptr); |
483 | 495 |
484 // FIXME: do we need substituteTranspColor? | |
485 | |
486 if (reallyHasAlpha && requestedInfo.alphaType() != kOpaque_SkAlphaType) { | |
487 // FIXME: We want to alert the caller. Is this the right way? | |
488 SkImageInfo* modInfo = const_cast<SkImageInfo*>(&requestedInfo); | |
489 *modInfo = requestedInfo.makeAlphaType(kOpaque_SkAlphaType); | |
490 } | |
491 return kSuccess; | 496 return kSuccess; |
492 } | 497 } |
498 | |
499 class SkPngScanlineDecoder : public SkScanlineDecoder { | |
500 public: | |
501 // FIXME: Need to support subsets... | |
502 SkPngScanlineDecoder(const SkImageInfo& origInfo, const SkImageInfo& dstInfo , | |
503 SkPngCodec* codec) | |
504 // FIXME: Does SkScanlineDecoder need origInfo? Maybe for subsets? | |
505 : INHERITED(origInfo, dstInfo) | |
506 , fDstInfo(dstInfo) | |
507 , fCodec(codec) | |
508 , fHasAlpha(false) | |
509 { | |
510 fStorage.reset(dstInfo.width() * SkSwizzler::BytesPerPixel(fCodec->fSc)) ; | |
511 fSrcRow = static_cast<uint8_t*>(fStorage.get()); | |
512 } | |
513 | |
514 SkImageGenerator::Result onGetNextScanline(void* dst) SK_OVERRIDE { | |
reed1
2015/03/19 15:31:39
Is it easy to override the N-scanlines method here
scroggo
2015/03/19 17:59:19
Yes.
| |
515 // FIXME: Could we use the return value of setjmp to specify the type of | |
516 // error? | |
517 if (setjmp(png_jmpbuf(fCodec->fPng_ptr))) { | |
518 SkDebugf("setjmp long jump!\n"); | |
519 return SkImageGenerator::kInvalidInput; | |
520 } | |
521 | |
522 png_read_rows(fCodec->fPng_ptr, &fSrcRow, png_bytepp_NULL, 1); | |
523 fCodec->fSwizzler->setDstRow(dst); | |
524 fHasAlpha |= fCodec->fSwizzler->next(fSrcRow); | |
525 return SkImageGenerator::kSuccess; | |
526 } | |
527 | |
528 SkImageGenerator::Result onFinish() SK_OVERRIDE { | |
529 return fCodec->finish(); | |
530 } | |
531 | |
532 bool onReallyHasAlpha() const SK_OVERRIDE { return fHasAlpha; } | |
533 | |
534 private: | |
535 const SkImageInfo& fDstInfo; | |
536 SkPngCodec* fCodec; // Unowned. | |
537 bool fHasAlpha; | |
538 SkAutoMalloc fStorage; | |
539 uint8_t* fSrcRow; | |
540 | |
541 typedef SkScanlineDecoder INHERITED; | |
542 }; | |
543 | |
544 SkScanlineDecoder* SkPngCodec::onGetScanlineDecoder(const SkImageInfo& dstInfo, | |
545 const SkIRect& origSubset) { | |
546 // Check to see if scaling was requested. | |
547 if (dstInfo.dimensions() != origSubset.size()) { | |
548 SkDebugf("Scaling not supported: dimensions: %d %d\toriginal: %d %d\n", | |
549 dstInfo.width(), dstInfo.height(), | |
550 origSubset.width(), origSubset.height()); | |
551 return NULL; | |
552 } | |
553 | |
554 if (!conversion_possible(dstInfo, this->getOriginalInfo())) { | |
555 SkDebugf("no conversion possible\n"); | |
556 return NULL; | |
557 } | |
558 | |
559 // Note: We set dst to NULL since we do not know it yet. rowBytes is not nee ded, | |
560 // since we'll be manually updating the dstRow, but the SkSwizzler requires it to | |
561 // be at least dstInfo.minRowBytes. | |
562 if (this->initializeSwizzler(dstInfo, NULL, dstInfo.minRowBytes()) != kSucce ss) { | |
563 SkDebugf("failed to initialize the swizzler.\n"); | |
564 return NULL; | |
565 } | |
566 | |
567 SkASSERT(fNumberPasses != INVALID_NUMBER_PASSES); | |
568 if (fNumberPasses > 1) { | |
569 // We cannot efficiently do scanline decoding. | |
570 return NULL; | |
571 } | |
572 | |
573 return SkNEW_ARGS(SkPngScanlineDecoder, (this->getOriginalInfo(), dstInfo, t his)); | |
574 } | |
575 | |
OLD | NEW |