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

Side by Side Diff: src/codec/SkPngCodec.cpp

Issue 1918873002: Remove SkEncodedInfo kUnknown_Color and kUnknown_Alpha from public API (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Fix errors Created 4 years, 7 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
« no previous file with comments | « src/codec/SkJpegDecoderMgr.cpp ('k') | src/codec/SkRawCodec.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 * 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 "SkBitmap.h" 8 #include "SkBitmap.h"
9 #include "SkCodecPriv.h" 9 #include "SkCodecPriv.h"
10 #include "SkColorPriv.h" 10 #include "SkColorPriv.h"
(...skipping 243 matching lines...) Expand 10 before | Expand all | Expand 10 after
254 254
255 #endif // LIBPNG >= 1.6 255 #endif // LIBPNG >= 1.6
256 256
257 // Finally, what should we do if there is no color space information in the PNG? 257 // Finally, what should we do if there is no color space information in the PNG?
258 // The specification says that this indicates "gamma is unknown" and that th e 258 // The specification says that this indicates "gamma is unknown" and that th e
259 // "color is device dependent". I'm assuming we can represent this with NUL L. 259 // "color is device dependent". I'm assuming we can represent this with NUL L.
260 // But should we guess sRGB? Most images are sRGB, even if they don't speci fy. 260 // But should we guess sRGB? Most images are sRGB, even if they don't speci fy.
261 return nullptr; 261 return nullptr;
262 } 262 }
263 263
264 static int bytes_per_pixel(int bitsPerPixel) {
265 // Note that we will have to change this implementation if we start
266 // supporting outputs from libpng that are less than 8-bits per component.
267 return bitsPerPixel / 8;
268 }
269
270 // Subclass of SkPngCodec which supports scanline decoding
271 class SkPngScanlineDecoder : public SkPngCodec {
272 public:
273 SkPngScanlineDecoder(int width, int height, const SkEncodedInfo& info, SkStr eam* stream,
274 SkPngChunkReader* chunkReader, png_structp png_ptr, png_infop info_p tr, int bitDepth,
275 sk_sp<SkColorSpace> colorSpace)
276 : INHERITED(width, height, info, stream, chunkReader, png_ptr, info_ptr, bitDepth, 1,
277 colorSpace)
278 , fSrcRow(nullptr)
279 {}
280
281 Result onStartScanlineDecode(const SkImageInfo& dstInfo, const Options& opti ons,
282 SkPMColor ctable[], int* ctableCount) override {
283 if (!conversion_possible(dstInfo, this->getInfo())) {
284 return kInvalidConversion;
285 }
286
287 const Result result = this->initializeSwizzler(dstInfo, options, ctable,
288 ctableCount);
289 if (result != kSuccess) {
290 return result;
291 }
292
293 fStorage.reset(this->getInfo().width() *
294 (bytes_per_pixel(this->getEncodedInfo().bitsPerPixel())));
295 fSrcRow = fStorage.get();
296
297 return kSuccess;
298 }
299
300 int onGetScanlines(void* dst, int count, size_t rowBytes) override {
301 // Assume that an error in libpng indicates an incomplete input.
302 int row = 0;
303 if (setjmp(png_jmpbuf(this->png_ptr()))) {
304 SkCodecPrintf("setjmp long jump!\n");
305 return row;
306 }
307
308 void* dstRow = dst;
309 for (; row < count; row++) {
310 png_read_row(this->png_ptr(), fSrcRow, nullptr);
311 this->swizzler()->swizzle(dstRow, fSrcRow);
312 dstRow = SkTAddOffset<void>(dstRow, rowBytes);
313 }
314
315 return row;
316 }
317
318 bool onSkipScanlines(int count) override {
319 // Assume that an error in libpng indicates an incomplete input.
320 if (setjmp(png_jmpbuf(this->png_ptr()))) {
321 SkCodecPrintf("setjmp long jump!\n");
322 return false;
323 }
324
325 for (int row = 0; row < count; row++) {
326 png_read_row(this->png_ptr(), fSrcRow, nullptr);
327 }
328 return true;
329 }
330
331 private:
332 SkAutoTMalloc<uint8_t> fStorage;
333 uint8_t* fSrcRow;
334
335 typedef SkPngCodec INHERITED;
336 };
337
338
339 class SkPngInterlacedScanlineDecoder : public SkPngCodec {
340 public:
341 SkPngInterlacedScanlineDecoder(int width, int height, const SkEncodedInfo& i nfo,
342 SkStream* stream, SkPngChunkReader* chunkReader, png_structp png_ptr ,
343 png_infop info_ptr, int bitDepth, int numberPasses, sk_sp<SkColorSpa ce> colorSpace)
344 : INHERITED(width, height, info, stream, chunkReader, png_ptr, info_ptr, bitDepth,
345 numberPasses, colorSpace)
346 , fHeight(-1)
347 , fCanSkipRewind(false)
348 {
349 SkASSERT(numberPasses != 1);
350 }
351
352 Result onStartScanlineDecode(const SkImageInfo& dstInfo, const Options& opti ons,
353 SkPMColor ctable[], int* ctableCount) override {
354 if (!conversion_possible(dstInfo, this->getInfo())) {
355 return kInvalidConversion;
356 }
357
358 const Result result = this->initializeSwizzler(dstInfo, options, ctable,
359 ctableCount);
360 if (result != kSuccess) {
361 return result;
362 }
363
364 fHeight = dstInfo.height();
365 // FIXME: This need not be called on a second call to onStartScanlineDec ode.
366 fSrcRowBytes = this->getInfo().width() *
367 (bytes_per_pixel(this->getEncodedInfo().bitsPerPixel()));
368 fGarbageRow.reset(fSrcRowBytes);
369 fGarbageRowPtr = static_cast<uint8_t*>(fGarbageRow.get());
370 fCanSkipRewind = true;
371
372 return SkCodec::kSuccess;
373 }
374
375 int onGetScanlines(void* dst, int count, size_t dstRowBytes) override {
376 // rewind stream if have previously called onGetScanlines,
377 // since we need entire progressive image to get scanlines
378 if (fCanSkipRewind) {
379 // We already rewound in onStartScanlineDecode, so there is no reaso n to rewind.
380 // Next time onGetScanlines is called, we will need to rewind.
381 fCanSkipRewind = false;
382 } else {
383 // rewindIfNeeded resets fCurrScanline, since it assumes that start
384 // needs to be called again before scanline decoding. PNG scanline
385 // decoding is the exception, since it needs to rewind between
386 // calls to getScanlines. Keep track of fCurrScanline, to undo the
387 // reset.
388 const int currScanline = this->nextScanline();
389 // This method would never be called if currScanline is -1
390 SkASSERT(currScanline != -1);
391
392 if (!this->rewindIfNeeded()) {
393 return kCouldNotRewind;
394 }
395 this->updateCurrScanline(currScanline);
396 }
397
398 if (setjmp(png_jmpbuf(this->png_ptr()))) {
399 SkCodecPrintf("setjmp long jump!\n");
400 // FIXME (msarett): Returning 0 is pessimistic. If we can complete a single pass,
401 // we may be able to report that all of the memory has been initiali zed. Even if we
402 // fail on the first pass, we can still report than some scanlines a re initialized.
403 return 0;
404 }
405 SkAutoTMalloc<uint8_t> storage(count * fSrcRowBytes);
406 uint8_t* storagePtr = storage.get();
407 uint8_t* srcRow;
408 const int startRow = this->nextScanline();
409 for (int i = 0; i < this->numberPasses(); i++) {
410 // read rows we planned to skip into garbage row
411 for (int y = 0; y < startRow; y++){
412 png_read_row(this->png_ptr(), fGarbageRowPtr, nullptr);
413 }
414 // read rows we care about into buffer
415 srcRow = storagePtr;
416 for (int y = 0; y < count; y++) {
417 png_read_row(this->png_ptr(), srcRow, nullptr);
418 srcRow += fSrcRowBytes;
419 }
420 // read rows we don't want into garbage buffer
421 for (int y = 0; y < fHeight - startRow - count; y++) {
422 png_read_row(this->png_ptr(), fGarbageRowPtr, nullptr);
423 }
424 }
425 //swizzle the rows we care about
426 srcRow = storagePtr;
427 void* dstRow = dst;
428 for (int y = 0; y < count; y++) {
429 this->swizzler()->swizzle(dstRow, srcRow);
430 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes);
431 srcRow += fSrcRowBytes;
432 }
433
434 return count;
435 }
436
437 bool onSkipScanlines(int count) override {
438 // The non-virtual version will update fCurrScanline.
439 return true;
440 }
441
442 SkScanlineOrder onGetScanlineOrder() const override {
443 return kNone_SkScanlineOrder;
444 }
445
446 private:
447 int fHeight;
448 size_t fSrcRowBytes;
449 SkAutoMalloc fGarbageRow;
450 uint8_t* fGarbageRowPtr;
451 // FIXME: This imitates behavior in SkCodec::rewindIfNeeded. That function
452 // is called whenever some action is taken that reads the stream and
453 // therefore the next call will require a rewind. So it modifies a boolean
454 // to note that the *next* time it is called a rewind is needed.
455 // SkPngInterlacedScanlineDecoder has an extra wrinkle - calling
456 // onStartScanlineDecode followed by onGetScanlines does *not* require a
457 // rewind. Since rewindIfNeeded does not have this flexibility, we need to
458 // add another layer.
459 bool fCanSkipRewind;
460
461 typedef SkPngCodec INHERITED;
462 };
463
264 // Reads the header and initializes the output fields, if not NULL. 464 // Reads the header and initializes the output fields, if not NULL.
265 // 465 //
266 // @param stream Input data. Will be read to get enough information to properly 466 // @param stream Input data. Will be read to get enough information to properly
267 // setup the codec. 467 // setup the codec.
268 // @param chunkReader SkPngChunkReader, for reading unknown chunks. May be NULL. 468 // @param chunkReader SkPngChunkReader, for reading unknown chunks. May be NULL.
269 // If not NULL, png_ptr will hold an *unowned* pointer to it. The caller is 469 // If not NULL, png_ptr will hold an *unowned* pointer to it. The caller is
270 // expected to continue to own it for the lifetime of the png_ptr. 470 // expected to continue to own it for the lifetime of the png_ptr.
471 // @param outCodec Optional output variable. If non-NULL, will be set to a new
472 // SkPngCodec on success.
271 // @param png_ptrp Optional output variable. If non-NULL, will be set to a new 473 // @param png_ptrp Optional output variable. If non-NULL, will be set to a new
272 // png_structp on success. 474 // png_structp on success.
273 // @param info_ptrp Optional output variable. If non-NULL, will be set to a new 475 // @param info_ptrp Optional output variable. If non-NULL, will be set to a new
274 // png_infop on success; 476 // png_infop on success;
275 // @param info Optional output variable. If non-NULL, will be set to
276 // reflect the properties of the encoded image on success.
277 // @param bitDepthPtr Optional output variable. If non-NULL, will be set to the
278 // bit depth of the encoded image on success.
279 // @param numberPassesPtr Optional output variable. If non-NULL, will be set to
280 // the number_passes of the encoded image on success.
281 // @return true on success, in which case the caller is responsible for calling 477 // @return true on success, in which case the caller is responsible for calling
282 // png_destroy_read_struct(png_ptrp, info_ptrp). 478 // png_destroy_read_struct(png_ptrp, info_ptrp).
283 // If it returns false, the passed in fields (except stream) are unchanged. 479 // If it returns false, the passed in fields (except stream) are unchanged.
284 static bool read_header(SkStream* stream, SkPngChunkReader* chunkReader, 480 static bool read_header(SkStream* stream, SkPngChunkReader* chunkReader, SkCodec ** outCodec,
285 png_structp* png_ptrp, png_infop* info_ptrp, 481 png_structp* png_ptrp, png_infop* info_ptrp) {
286 int* width, int* height, SkEncodedInfo* info, int* bitDe pthPtr,
287 int* numberPassesPtr) {
288 // The image is known to be a PNG. Decode enough to know the SkImageInfo. 482 // The image is known to be a PNG. Decode enough to know the SkImageInfo.
289 png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, 483 png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr,
290 sk_error_fn, sk_warning_fn); 484 sk_error_fn, sk_warning_fn);
291 if (!png_ptr) { 485 if (!png_ptr) {
292 return false; 486 return false;
293 } 487 }
294 488
295 AutoCleanPng autoClean(png_ptr); 489 AutoCleanPng autoClean(png_ptr);
296 490
297 png_infop info_ptr = png_create_info_struct(png_ptr); 491 png_infop info_ptr = png_create_info_struct(png_ptr);
(...skipping 22 matching lines...) Expand all
320 #endif 514 #endif
321 515
322 // The call to png_read_info() gives us all of the information from the 516 // The call to png_read_info() gives us all of the information from the
323 // PNG file before the first IDAT (image data chunk). 517 // PNG file before the first IDAT (image data chunk).
324 png_read_info(png_ptr, info_ptr); 518 png_read_info(png_ptr, info_ptr);
325 png_uint_32 origWidth, origHeight; 519 png_uint_32 origWidth, origHeight;
326 int bitDepth, encodedColorType; 520 int bitDepth, encodedColorType;
327 png_get_IHDR(png_ptr, info_ptr, &origWidth, &origHeight, &bitDepth, 521 png_get_IHDR(png_ptr, info_ptr, &origWidth, &origHeight, &bitDepth,
328 &encodedColorType, nullptr, nullptr, nullptr); 522 &encodedColorType, nullptr, nullptr, nullptr);
329 523
330 if (bitDepthPtr) {
331 *bitDepthPtr = bitDepth;
332 }
333
334 // Tell libpng to strip 16 bit/color files down to 8 bits/color. 524 // Tell libpng to strip 16 bit/color files down to 8 bits/color.
335 // TODO: Should we handle this in SkSwizzler? Could this also benefit 525 // TODO: Should we handle this in SkSwizzler? Could this also benefit
336 // RAW decodes? 526 // RAW decodes?
337 if (bitDepth == 16) { 527 if (bitDepth == 16) {
338 SkASSERT(PNG_COLOR_TYPE_PALETTE != encodedColorType); 528 SkASSERT(PNG_COLOR_TYPE_PALETTE != encodedColorType);
339 png_set_strip_16(png_ptr); 529 png_set_strip_16(png_ptr);
340 } 530 }
341 531
342 // Now determine the default colorType and alphaType and set the required tr ansforms. 532 // Now determine the default colorType and alphaType and set the required tr ansforms.
343 // Often, we depend on SkSwizzler to perform any transforms that we need. H owever, we 533 // Often, we depend on SkSwizzler to perform any transforms that we need. H owever, we
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
394 alpha = SkEncodedInfo::kUnpremul_Alpha; 584 alpha = SkEncodedInfo::kUnpremul_Alpha;
395 break; 585 break;
396 default: 586 default:
397 // All the color types have been covered above. 587 // All the color types have been covered above.
398 SkASSERT(false); 588 SkASSERT(false);
399 color = SkEncodedInfo::kRGBA_Color; 589 color = SkEncodedInfo::kRGBA_Color;
400 alpha = SkEncodedInfo::kUnpremul_Alpha; 590 alpha = SkEncodedInfo::kUnpremul_Alpha;
401 } 591 }
402 592
403 int numberPasses = png_set_interlace_handling(png_ptr); 593 int numberPasses = png_set_interlace_handling(png_ptr);
404 if (numberPassesPtr) {
405 *numberPassesPtr = numberPasses;
406 }
407 594
408 if (info) {
409 *info = SkEncodedInfo::Make(color, alpha, 8);
410 }
411 if (width) {
412 *width = origWidth;
413 }
414 if (height) {
415 *height = origHeight;
416 }
417 autoClean.release(); 595 autoClean.release();
418 if (png_ptrp) { 596 if (png_ptrp) {
419 *png_ptrp = png_ptr; 597 *png_ptrp = png_ptr;
420 } 598 }
421 if (info_ptrp) { 599 if (info_ptrp) {
422 *info_ptrp = info_ptr; 600 *info_ptrp = info_ptr;
423 } 601 }
424 602
603 if (outCodec) {
604 sk_sp<SkColorSpace> colorSpace = read_color_space(png_ptr, info_ptr);
605 SkEncodedInfo info = SkEncodedInfo::Make(color, alpha, 8);
606
607 if (1 == numberPasses) {
608 *outCodec = new SkPngScanlineDecoder(origWidth, origHeight, info, st ream,
609 chunkReader, png_ptr, info_ptr, bitDepth, colorSpace);
610 } else {
611 *outCodec = new SkPngInterlacedScanlineDecoder(origWidth, origHeight , info, stream,
612 chunkReader, png_ptr, info_ptr, bitDepth, numberPasses, colo rSpace);
613 }
614 }
615
425 return true; 616 return true;
426 } 617 }
427 618
428 SkPngCodec::SkPngCodec(int width, int height, const SkEncodedInfo& info, SkStrea m* stream, 619 SkPngCodec::SkPngCodec(int width, int height, const SkEncodedInfo& info, SkStrea m* stream,
429 SkPngChunkReader* chunkReader, png_structp png_ptr, png_i nfop info_ptr, 620 SkPngChunkReader* chunkReader, png_structp png_ptr, png_i nfop info_ptr,
430 int bitDepth, int numberPasses, sk_sp<SkColorSpace> color Space) 621 int bitDepth, int numberPasses, sk_sp<SkColorSpace> color Space)
431 : INHERITED(width, height, info, stream, colorSpace) 622 : INHERITED(width, height, info, stream, colorSpace)
432 , fPngChunkReader(SkSafeRef(chunkReader)) 623 , fPngChunkReader(SkSafeRef(chunkReader))
433 , fPng_ptr(png_ptr) 624 , fPng_ptr(png_ptr)
434 , fInfo_ptr(info_ptr) 625 , fInfo_ptr(info_ptr)
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
489 bool SkPngCodec::onRewind() { 680 bool SkPngCodec::onRewind() {
490 // This sets fPng_ptr and fInfo_ptr to nullptr. If read_header 681 // This sets fPng_ptr and fInfo_ptr to nullptr. If read_header
491 // succeeds, they will be repopulated, and if it fails, they will 682 // succeeds, they will be repopulated, and if it fails, they will
492 // remain nullptr. Any future accesses to fPng_ptr and fInfo_ptr will 683 // remain nullptr. Any future accesses to fPng_ptr and fInfo_ptr will
493 // come through this function which will rewind and again attempt 684 // come through this function which will rewind and again attempt
494 // to reinitialize them. 685 // to reinitialize them.
495 this->destroyReadStruct(); 686 this->destroyReadStruct();
496 687
497 png_structp png_ptr; 688 png_structp png_ptr;
498 png_infop info_ptr; 689 png_infop info_ptr;
499 if (!read_header(this->stream(), fPngChunkReader.get(), &png_ptr, &info_ptr, 690 if (!read_header(this->stream(), fPngChunkReader.get(), nullptr, &png_ptr, & info_ptr)) {
500 nullptr, nullptr, nullptr, nullptr, nullptr)) {
501 return false; 691 return false;
502 } 692 }
503 693
504 fPng_ptr = png_ptr; 694 fPng_ptr = png_ptr;
505 fInfo_ptr = info_ptr; 695 fInfo_ptr = info_ptr;
506 return true; 696 return true;
507 } 697 }
508 698
509 static int bytes_per_pixel(int bitsPerPixel) {
510 // Note that we will have to change this implementation if we start
511 // supporting outputs from libpng that are less than 8-bits per component.
512 return bitsPerPixel / 8;
513 }
514
515 SkCodec::Result SkPngCodec::onGetPixels(const SkImageInfo& requestedInfo, void* dst, 699 SkCodec::Result SkPngCodec::onGetPixels(const SkImageInfo& requestedInfo, void* dst,
516 size_t dstRowBytes, const Options& optio ns, 700 size_t dstRowBytes, const Options& optio ns,
517 SkPMColor ctable[], int* ctableCount, 701 SkPMColor ctable[], int* ctableCount,
518 int* rowsDecoded) { 702 int* rowsDecoded) {
519 if (!conversion_possible(requestedInfo, this->getInfo())) { 703 if (!conversion_possible(requestedInfo, this->getInfo())) {
520 return kInvalidConversion; 704 return kInvalidConversion;
521 } 705 }
522 if (options.fSubset) { 706 if (options.fSubset) {
523 // Subsets are not supported. 707 // Subsets are not supported.
524 return kUnimplemented; 708 return kUnimplemented;
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after
599 } 783 }
600 784
601 uint32_t SkPngCodec::onGetFillValue(SkColorType colorType) const { 785 uint32_t SkPngCodec::onGetFillValue(SkColorType colorType) const {
602 const SkPMColor* colorPtr = get_color_ptr(fColorTable.get()); 786 const SkPMColor* colorPtr = get_color_ptr(fColorTable.get());
603 if (colorPtr) { 787 if (colorPtr) {
604 return get_color_table_fill_value(colorType, colorPtr, 0); 788 return get_color_table_fill_value(colorType, colorPtr, 0);
605 } 789 }
606 return INHERITED::onGetFillValue(colorType); 790 return INHERITED::onGetFillValue(colorType);
607 } 791 }
608 792
609 // Subclass of SkPngCodec which supports scanline decoding 793 SkCodec* SkPngCodec::NewFromStream(SkStream* stream, SkPngChunkReader* chunkRead er) {
610 class SkPngScanlineDecoder : public SkPngCodec { 794 SkAutoTDelete<SkStream> streamDeleter(stream);
611 public:
612 SkPngScanlineDecoder(int width, int height, const SkEncodedInfo& info, SkStr eam* stream,
613 SkPngChunkReader* chunkReader, png_structp png_ptr, png_infop info_p tr, int bitDepth,
614 sk_sp<SkColorSpace> colorSpace)
615 : INHERITED(width, height, info, stream, chunkReader, png_ptr, info_ptr, bitDepth, 1,
616 colorSpace)
617 , fSrcRow(nullptr)
618 {}
619 795
620 Result onStartScanlineDecode(const SkImageInfo& dstInfo, const Options& opti ons, 796 SkCodec* outCodec;
621 SkPMColor ctable[], int* ctableCount) override { 797 if (read_header(stream, chunkReader, &outCodec, nullptr, nullptr)) {
622 if (!conversion_possible(dstInfo, this->getInfo())) { 798 // Codec has taken ownership of the stream.
623 return kInvalidConversion; 799 SkASSERT(outCodec);
624 } 800 streamDeleter.release();
625 801 return outCodec;
626 const Result result = this->initializeSwizzler(dstInfo, options, ctable,
627 ctableCount);
628 if (result != kSuccess) {
629 return result;
630 }
631
632 fStorage.reset(this->getInfo().width() *
633 (bytes_per_pixel(this->getEncodedInfo().bitsPerPixel())));
634 fSrcRow = fStorage.get();
635
636 return kSuccess;
637 } 802 }
638 803
639 int onGetScanlines(void* dst, int count, size_t rowBytes) override { 804 return nullptr;
640 // Assume that an error in libpng indicates an incomplete input.
641 int row = 0;
642 if (setjmp(png_jmpbuf(this->png_ptr()))) {
643 SkCodecPrintf("setjmp long jump!\n");
644 return row;
645 }
646
647 void* dstRow = dst;
648 for (; row < count; row++) {
649 png_read_row(this->png_ptr(), fSrcRow, nullptr);
650 this->swizzler()->swizzle(dstRow, fSrcRow);
651 dstRow = SkTAddOffset<void>(dstRow, rowBytes);
652 }
653
654 return row;
655 }
656
657 bool onSkipScanlines(int count) override {
658 // Assume that an error in libpng indicates an incomplete input.
659 if (setjmp(png_jmpbuf(this->png_ptr()))) {
660 SkCodecPrintf("setjmp long jump!\n");
661 return false;
662 }
663
664 for (int row = 0; row < count; row++) {
665 png_read_row(this->png_ptr(), fSrcRow, nullptr);
666 }
667 return true;
668 }
669
670 private:
671 SkAutoTMalloc<uint8_t> fStorage;
672 uint8_t* fSrcRow;
673
674 typedef SkPngCodec INHERITED;
675 };
676
677
678 class SkPngInterlacedScanlineDecoder : public SkPngCodec {
679 public:
680 SkPngInterlacedScanlineDecoder(int width, int height, const SkEncodedInfo& i nfo,
681 SkStream* stream, SkPngChunkReader* chunkReader, png_structp png_ptr ,
682 png_infop info_ptr, int bitDepth, int numberPasses, sk_sp<SkColorSpa ce> colorSpace)
683 : INHERITED(width, height, info, stream, chunkReader, png_ptr, info_ptr, bitDepth,
684 numberPasses, colorSpace)
685 , fHeight(-1)
686 , fCanSkipRewind(false)
687 {
688 SkASSERT(numberPasses != 1);
689 }
690
691 Result onStartScanlineDecode(const SkImageInfo& dstInfo, const Options& opti ons,
692 SkPMColor ctable[], int* ctableCount) override {
693 if (!conversion_possible(dstInfo, this->getInfo())) {
694 return kInvalidConversion;
695 }
696
697 const Result result = this->initializeSwizzler(dstInfo, options, ctable,
698 ctableCount);
699 if (result != kSuccess) {
700 return result;
701 }
702
703 fHeight = dstInfo.height();
704 // FIXME: This need not be called on a second call to onStartScanlineDec ode.
705 fSrcRowBytes = this->getInfo().width() *
706 (bytes_per_pixel(this->getEncodedInfo().bitsPerPixel()));
707 fGarbageRow.reset(fSrcRowBytes);
708 fGarbageRowPtr = static_cast<uint8_t*>(fGarbageRow.get());
709 fCanSkipRewind = true;
710
711 return SkCodec::kSuccess;
712 }
713
714 int onGetScanlines(void* dst, int count, size_t dstRowBytes) override {
715 // rewind stream if have previously called onGetScanlines,
716 // since we need entire progressive image to get scanlines
717 if (fCanSkipRewind) {
718 // We already rewound in onStartScanlineDecode, so there is no reaso n to rewind.
719 // Next time onGetScanlines is called, we will need to rewind.
720 fCanSkipRewind = false;
721 } else {
722 // rewindIfNeeded resets fCurrScanline, since it assumes that start
723 // needs to be called again before scanline decoding. PNG scanline
724 // decoding is the exception, since it needs to rewind between
725 // calls to getScanlines. Keep track of fCurrScanline, to undo the
726 // reset.
727 const int currScanline = this->nextScanline();
728 // This method would never be called if currScanline is -1
729 SkASSERT(currScanline != -1);
730
731 if (!this->rewindIfNeeded()) {
732 return kCouldNotRewind;
733 }
734 this->updateCurrScanline(currScanline);
735 }
736
737 if (setjmp(png_jmpbuf(this->png_ptr()))) {
738 SkCodecPrintf("setjmp long jump!\n");
739 // FIXME (msarett): Returning 0 is pessimistic. If we can complete a single pass,
740 // we may be able to report that all of the memory has been initiali zed. Even if we
741 // fail on the first pass, we can still report than some scanlines a re initialized.
742 return 0;
743 }
744 SkAutoTMalloc<uint8_t> storage(count * fSrcRowBytes);
745 uint8_t* storagePtr = storage.get();
746 uint8_t* srcRow;
747 const int startRow = this->nextScanline();
748 for (int i = 0; i < this->numberPasses(); i++) {
749 // read rows we planned to skip into garbage row
750 for (int y = 0; y < startRow; y++){
751 png_read_row(this->png_ptr(), fGarbageRowPtr, nullptr);
752 }
753 // read rows we care about into buffer
754 srcRow = storagePtr;
755 for (int y = 0; y < count; y++) {
756 png_read_row(this->png_ptr(), srcRow, nullptr);
757 srcRow += fSrcRowBytes;
758 }
759 // read rows we don't want into garbage buffer
760 for (int y = 0; y < fHeight - startRow - count; y++) {
761 png_read_row(this->png_ptr(), fGarbageRowPtr, nullptr);
762 }
763 }
764 //swizzle the rows we care about
765 srcRow = storagePtr;
766 void* dstRow = dst;
767 for (int y = 0; y < count; y++) {
768 this->swizzler()->swizzle(dstRow, srcRow);
769 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes);
770 srcRow += fSrcRowBytes;
771 }
772
773 return count;
774 }
775
776 bool onSkipScanlines(int count) override {
777 // The non-virtual version will update fCurrScanline.
778 return true;
779 }
780
781 SkScanlineOrder onGetScanlineOrder() const override {
782 return kNone_SkScanlineOrder;
783 }
784
785 private:
786 int fHeight;
787 size_t fSrcRowBytes;
788 SkAutoMalloc fGarbageRow;
789 uint8_t* fGarbageRowPtr;
790 // FIXME: This imitates behavior in SkCodec::rewindIfNeeded. That function
791 // is called whenever some action is taken that reads the stream and
792 // therefore the next call will require a rewind. So it modifies a boolean
793 // to note that the *next* time it is called a rewind is needed.
794 // SkPngInterlacedScanlineDecoder has an extra wrinkle - calling
795 // onStartScanlineDecode followed by onGetScanlines does *not* require a
796 // rewind. Since rewindIfNeeded does not have this flexibility, we need to
797 // add another layer.
798 bool fCanSkipRewind;
799
800 typedef SkPngCodec INHERITED;
801 };
802
803 SkCodec* SkPngCodec::NewFromStream(SkStream* stream, SkPngChunkReader* chunkRead er) {
804 SkAutoTDelete<SkStream> streamDeleter(stream);
805 png_structp png_ptr;
806 png_infop info_ptr;
807 int width, height;
808 SkEncodedInfo imageInfo;
809 int bitDepth;
810 int numberPasses;
811
812 if (!read_header(stream, chunkReader, &png_ptr, &info_ptr, &width, &height, &imageInfo,
813 &bitDepth, &numberPasses)) {
814 return nullptr;
815 }
816
817 auto colorSpace = read_color_space(png_ptr, info_ptr);
818
819 if (1 == numberPasses) {
820 return new SkPngScanlineDecoder(width, height, imageInfo, streamDeleter. release(),
821 chunkReader, png_ptr, info_ptr, bitDepth , colorSpace);
822 }
823
824 return new SkPngInterlacedScanlineDecoder(width, height, imageInfo, streamDe leter.release(),
825 chunkReader, png_ptr, info_ptr, bi tDepth,
826 numberPasses, colorSpace);
827 } 805 }
OLDNEW
« no previous file with comments | « src/codec/SkJpegDecoderMgr.cpp ('k') | src/codec/SkRawCodec.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698