Chromium Code Reviews| 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 "SkCodecPriv.h" | 8 #include "SkCodecPriv.h" |
| 9 #include "SkColorPriv.h" | 9 #include "SkColorPriv.h" |
| 10 #include "SkColorTable.h" | 10 #include "SkColorTable.h" |
| (...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 180 // reflect the properties of the encoded image on success. | 180 // reflect the properties of the encoded image on success. |
| 181 // @param bitDepthPtr Optional output variable. If non-NULL, will be set to the | 181 // @param bitDepthPtr Optional output variable. If non-NULL, will be set to the |
| 182 // bit depth of the encoded image on success. | 182 // bit depth of the encoded image on success. |
| 183 // @param numberPassesPtr Optional output variable. If non-NULL, will be set to | 183 // @param numberPassesPtr Optional output variable. If non-NULL, will be set to |
| 184 // the number_passes of the encoded image on success. | 184 // the number_passes of the encoded image on success. |
| 185 // @return true on success, in which case the caller is responsible for calling | 185 // @return true on success, in which case the caller is responsible for calling |
| 186 // png_destroy_read_struct(png_ptrp, info_ptrp). | 186 // png_destroy_read_struct(png_ptrp, info_ptrp). |
| 187 // If it returns false, the passed in fields (except stream) are unchanged. | 187 // If it returns false, the passed in fields (except stream) are unchanged. |
| 188 static bool read_header(SkStream* stream, SkPngChunkReader* chunkReader, | 188 static bool read_header(SkStream* stream, SkPngChunkReader* chunkReader, |
| 189 png_structp* png_ptrp, png_infop* info_ptrp, | 189 png_structp* png_ptrp, png_infop* info_ptrp, |
| 190 SkImageInfo* imageInfo, int* bitDepthPtr, int* numberPas sesPtr) { | 190 SkImageInfo* imageInfo, int* bitDepthPtr, int* numberPas sesPtr, |
| 191 SkColorSpace** colorSpace) { | |
|
scroggo
2016/02/24 13:58:12
add a comment for colorSpace?
msarett
2016/02/24 17:32:35
Done.
| |
| 191 // The image is known to be a PNG. Decode enough to know the SkImageInfo. | 192 // The image is known to be a PNG. Decode enough to know the SkImageInfo. |
| 192 png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, | 193 png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, |
| 193 sk_error_fn, sk_warning_fn); | 194 sk_error_fn, sk_warning_fn); |
| 194 if (!png_ptr) { | 195 if (!png_ptr) { |
| 195 return false; | 196 return false; |
| 196 } | 197 } |
| 197 | 198 |
| 198 AutoCleanPng autoClean(png_ptr); | 199 AutoCleanPng autoClean(png_ptr); |
| 199 | 200 |
| 200 png_infop info_ptr = png_create_info_struct(png_ptr); | 201 png_infop info_ptr = png_create_info_struct(png_ptr); |
| (...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 303 default: | 304 default: |
| 304 // All the color types have been covered above. | 305 // All the color types have been covered above. |
| 305 SkASSERT(false); | 306 SkASSERT(false); |
| 306 } | 307 } |
| 307 | 308 |
| 308 int numberPasses = png_set_interlace_handling(png_ptr); | 309 int numberPasses = png_set_interlace_handling(png_ptr); |
| 309 if (numberPassesPtr) { | 310 if (numberPassesPtr) { |
| 310 *numberPassesPtr = numberPasses; | 311 *numberPassesPtr = numberPasses; |
| 311 } | 312 } |
| 312 | 313 |
| 314 // iCCP variables | |
|
scroggo
2016/02/24 13:58:12
Can you move these variables closer to where they'
msarett
2016/02/24 17:32:35
Done.
| |
| 315 png_charp name; | |
| 316 int compression; | |
| 317 png_bytep profile; | |
| 318 png_uint_32 length; | |
| 319 | |
| 320 // cHRM variables | |
| 321 png_fixed_point XYZ[9]; | |
| 322 SkFloat3x3 toXYZD50; | |
| 323 | |
| 324 // gAMA variables | |
| 325 png_fixed_point gamma; | |
| 326 SkFloat3 gammas; | |
| 327 | |
| 328 if (colorSpace) { | |
| 329 // First check for an ICC profile | |
| 330 if (PNG_INFO_iCCP == png_get_iCCP(png_ptr, info_ptr, &name, &compression , &profile, | |
| 331 &length)) { | |
| 332 | |
| 333 // Compression can only ever be "deflate", so this is uninteresting. | |
| 334 // Could knowing the name of the profile ever be interesting? Maybe for debugging? | |
| 335 *colorSpace = SkColorSpace::NewICC(profile, length); | |
| 336 | |
| 337 // Second, check for sRGB. | |
| 338 } else if (png_get_valid(png_ptr, info_ptr, PNG_INFO_sRGB)) { | |
| 339 | |
| 340 // Here we are ignoring the sRGB "intent". Should we use the "inten t"? | |
| 341 *colorSpace = SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named); | |
| 342 | |
| 343 // Next, check for chromaticities. | |
| 344 } else if (png_get_cHRM_XYZ_fixed(png_ptr, info_ptr, &XYZ[0], &XYZ[1], & XYZ[2], &XYZ[3], | |
| 345 &XYZ[4], &XYZ[5], &XYZ[6], &XYZ[7], &XYZ[8])) { | |
| 346 | |
| 347 // This could be wrong. I don't see any guarantee from the PNG spec ification that | |
| 348 // these XYZ values will be D50. In fact, libpng will set its XYZ v alues to D65 | |
| 349 // values if it sees an sRGB chunk. | |
| 350 for (int i = 0; i < 9; i++) { | |
| 351 toXYZD50.fMat[i] = ((float) XYZ[i]) * 0.00001f; | |
| 352 } | |
| 353 | |
| 354 if (!(PNG_INFO_gAMA == png_get_gAMA_fixed(png_ptr, info_ptr, &gamma) )) { | |
| 355 // If the image does not specify gamma, let's choose our own def ault. | |
| 356 // What should the default be? Instead of choosing a default, s hould | |
| 357 // we just give up on the color profile? | |
| 358 gamma = 0; | |
|
msarett
2016/02/24 01:01:11
I need to figure out the gamma value that means "l
| |
| 359 } | |
| 360 gammas.fVec[0] = gammas.fVec[1] = gammas.fVec[2] = ((float) gamma) * 0.00001f; | |
| 361 | |
| 362 *colorSpace = SkColorSpace::NewRGB(toXYZD50, gammas); | |
| 363 | |
| 364 // Last, check for gamma. | |
| 365 } else if (PNG_INFO_gAMA == png_get_gAMA_fixed(png_ptr, info_ptr, &gamma )) { | |
| 366 | |
| 367 // Guess a default value for cHRM? Or should we just give up? | |
| 368 for (int i = 0; i < 9; i++) { | |
| 369 toXYZD50.fMat[i] = 0.0f; | |
|
msarett
2016/02/24 01:01:11
I need to figure out a default for cHRM.
| |
| 370 } | |
| 371 | |
| 372 // Set the gammas. | |
| 373 gammas.fVec[0] = gammas.fVec[1] = gammas.fVec[2] = ((float) gamma) * 0.00001f; | |
| 374 | |
| 375 *colorSpace = SkColorSpace::NewRGB(toXYZD50, gammas); | |
| 376 } | |
| 377 | |
| 378 // Finally, what should we do if there is no color space information in the PNG? | |
| 379 // The specification says that this indicates "gamma is unknown" and tha t the | |
| 380 // "color is device dependent". I'm assuming we can represent this with NULL. | |
| 381 // But should we guess sRGB? Are most images intended to be sRGB? | |
|
scroggo
2016/02/24 13:58:12
According to the W3C, "untagged" images should be
msarett
2016/02/24 17:32:35
I'm leaving this as is, in case we want to treat t
| |
| 382 } | |
| 383 | |
| 313 SkColorProfileType profileType = kLinear_SkColorProfileType; | 384 SkColorProfileType profileType = kLinear_SkColorProfileType; |
| 314 if (png_get_valid(png_ptr, info_ptr, PNG_INFO_sRGB)) { | 385 if (png_get_valid(png_ptr, info_ptr, PNG_INFO_sRGB)) { |
| 315 profileType = kSRGB_SkColorProfileType; | 386 profileType = kSRGB_SkColorProfileType; |
| 316 } | 387 } |
| 317 | 388 |
| 318 if (imageInfo) { | 389 if (imageInfo) { |
| 319 *imageInfo = SkImageInfo::Make(origWidth, origHeight, colorType, alphaTy pe, profileType); | 390 *imageInfo = SkImageInfo::Make(origWidth, origHeight, colorType, alphaTy pe, profileType); |
| 320 } | 391 } |
| 321 autoClean.detach(); | 392 autoClean.detach(); |
| 322 if (png_ptrp) { | 393 if (png_ptrp) { |
| 323 *png_ptrp = png_ptr; | 394 *png_ptrp = png_ptr; |
| 324 } | 395 } |
| 325 if (info_ptrp) { | 396 if (info_ptrp) { |
| 326 *info_ptrp = info_ptr; | 397 *info_ptrp = info_ptr; |
| 327 } | 398 } |
| 328 | 399 |
| 329 return true; | 400 return true; |
| 330 } | 401 } |
| 331 | 402 |
| 332 SkPngCodec::SkPngCodec(const SkImageInfo& info, SkStream* stream, SkPngChunkRead er* chunkReader, | 403 SkPngCodec::SkPngCodec(const SkImageInfo& info, SkStream* stream, SkPngChunkRead er* chunkReader, |
| 333 png_structp png_ptr, png_infop info_ptr, int bitDepth, in t numberPasses) | 404 png_structp png_ptr, png_infop info_ptr, int bitDepth, in t numberPasses, |
| 334 : INHERITED(info, stream) | 405 SkColorSpace* colorSpace) |
| 406 : INHERITED(info, stream, colorSpace) | |
| 335 , fPngChunkReader(SkSafeRef(chunkReader)) | 407 , fPngChunkReader(SkSafeRef(chunkReader)) |
| 336 , fPng_ptr(png_ptr) | 408 , fPng_ptr(png_ptr) |
| 337 , fInfo_ptr(info_ptr) | 409 , fInfo_ptr(info_ptr) |
| 338 , fSrcConfig(SkSwizzler::kUnknown) | 410 , fSrcConfig(SkSwizzler::kUnknown) |
| 339 , fNumberPasses(numberPasses) | 411 , fNumberPasses(numberPasses) |
| 340 , fBitDepth(bitDepth) | 412 , fBitDepth(bitDepth) |
| 341 {} | 413 {} |
| 342 | 414 |
| 343 SkPngCodec::~SkPngCodec() { | 415 SkPngCodec::~SkPngCodec() { |
| 344 this->destroyReadStruct(); | 416 this->destroyReadStruct(); |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 427 // This sets fPng_ptr and fInfo_ptr to nullptr. If read_header | 499 // This sets fPng_ptr and fInfo_ptr to nullptr. If read_header |
| 428 // succeeds, they will be repopulated, and if it fails, they will | 500 // succeeds, they will be repopulated, and if it fails, they will |
| 429 // remain nullptr. Any future accesses to fPng_ptr and fInfo_ptr will | 501 // remain nullptr. Any future accesses to fPng_ptr and fInfo_ptr will |
| 430 // come through this function which will rewind and again attempt | 502 // come through this function which will rewind and again attempt |
| 431 // to reinitialize them. | 503 // to reinitialize them. |
| 432 this->destroyReadStruct(); | 504 this->destroyReadStruct(); |
| 433 | 505 |
| 434 png_structp png_ptr; | 506 png_structp png_ptr; |
| 435 png_infop info_ptr; | 507 png_infop info_ptr; |
| 436 if (!read_header(this->stream(), fPngChunkReader.get(), &png_ptr, &info_ptr, | 508 if (!read_header(this->stream(), fPngChunkReader.get(), &png_ptr, &info_ptr, |
| 437 nullptr, nullptr, nullptr)) { | 509 nullptr, nullptr, nullptr, nullptr)) { |
| 438 return false; | 510 return false; |
| 439 } | 511 } |
| 440 | 512 |
| 441 fPng_ptr = png_ptr; | 513 fPng_ptr = png_ptr; |
| 442 fInfo_ptr = info_ptr; | 514 fInfo_ptr = info_ptr; |
| 443 return true; | 515 return true; |
| 444 } | 516 } |
| 445 | 517 |
| 446 SkCodec::Result SkPngCodec::onGetPixels(const SkImageInfo& requestedInfo, void* dst, | 518 SkCodec::Result SkPngCodec::onGetPixels(const SkImageInfo& requestedInfo, void* dst, |
| 447 size_t dstRowBytes, const Options& optio ns, | 519 size_t dstRowBytes, const Options& optio ns, |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 534 if (colorPtr) { | 606 if (colorPtr) { |
| 535 return get_color_table_fill_value(colorType, colorPtr, 0); | 607 return get_color_table_fill_value(colorType, colorPtr, 0); |
| 536 } | 608 } |
| 537 return INHERITED::onGetFillValue(colorType); | 609 return INHERITED::onGetFillValue(colorType); |
| 538 } | 610 } |
| 539 | 611 |
| 540 // Subclass of SkPngCodec which supports scanline decoding | 612 // Subclass of SkPngCodec which supports scanline decoding |
| 541 class SkPngScanlineDecoder : public SkPngCodec { | 613 class SkPngScanlineDecoder : public SkPngCodec { |
| 542 public: | 614 public: |
| 543 SkPngScanlineDecoder(const SkImageInfo& srcInfo, SkStream* stream, | 615 SkPngScanlineDecoder(const SkImageInfo& srcInfo, SkStream* stream, |
| 544 SkPngChunkReader* chunkReader, png_structp png_ptr, png_infop info_p tr, int bitDepth) | 616 SkPngChunkReader* chunkReader, png_structp png_ptr, png_infop info_p tr, int bitDepth, |
| 545 : INHERITED(srcInfo, stream, chunkReader, png_ptr, info_ptr, bitDepth, 1 ) | 617 SkColorSpace* colorSpace) |
| 618 : INHERITED(srcInfo, stream, chunkReader, png_ptr, info_ptr, bitDepth, 1 , colorSpace) | |
| 546 , fSrcRow(nullptr) | 619 , fSrcRow(nullptr) |
| 547 {} | 620 {} |
| 548 | 621 |
| 549 Result onStartScanlineDecode(const SkImageInfo& dstInfo, const Options& opti ons, | 622 Result onStartScanlineDecode(const SkImageInfo& dstInfo, const Options& opti ons, |
| 550 SkPMColor ctable[], int* ctableCount) override { | 623 SkPMColor ctable[], int* ctableCount) override { |
| 551 if (!conversion_possible(dstInfo, this->getInfo())) { | 624 if (!conversion_possible(dstInfo, this->getInfo())) { |
| 552 return kInvalidConversion; | 625 return kInvalidConversion; |
| 553 } | 626 } |
| 554 | 627 |
| 555 const Result result = this->initializeSwizzler(dstInfo, options, ctable, | 628 const Result result = this->initializeSwizzler(dstInfo, options, ctable, |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 600 uint8_t* fSrcRow; | 673 uint8_t* fSrcRow; |
| 601 | 674 |
| 602 typedef SkPngCodec INHERITED; | 675 typedef SkPngCodec INHERITED; |
| 603 }; | 676 }; |
| 604 | 677 |
| 605 | 678 |
| 606 class SkPngInterlacedScanlineDecoder : public SkPngCodec { | 679 class SkPngInterlacedScanlineDecoder : public SkPngCodec { |
| 607 public: | 680 public: |
| 608 SkPngInterlacedScanlineDecoder(const SkImageInfo& srcInfo, SkStream* stream, | 681 SkPngInterlacedScanlineDecoder(const SkImageInfo& srcInfo, SkStream* stream, |
| 609 SkPngChunkReader* chunkReader, png_structp png_ptr, png_infop info_p tr, | 682 SkPngChunkReader* chunkReader, png_structp png_ptr, png_infop info_p tr, |
| 610 int bitDepth, int numberPasses) | 683 int bitDepth, int numberPasses, SkColorSpace* colorSpace) |
| 611 : INHERITED(srcInfo, stream, chunkReader, png_ptr, info_ptr, bitDepth, n umberPasses) | 684 : INHERITED(srcInfo, stream, chunkReader, png_ptr, info_ptr, bitDepth, n umberPasses, |
| 685 colorSpace) | |
| 612 , fHeight(-1) | 686 , fHeight(-1) |
| 613 , fCanSkipRewind(false) | 687 , fCanSkipRewind(false) |
| 614 { | 688 { |
| 615 SkASSERT(numberPasses != 1); | 689 SkASSERT(numberPasses != 1); |
| 616 } | 690 } |
| 617 | 691 |
| 618 Result onStartScanlineDecode(const SkImageInfo& dstInfo, const Options& opti ons, | 692 Result onStartScanlineDecode(const SkImageInfo& dstInfo, const Options& opti ons, |
| 619 SkPMColor ctable[], int* ctableCount) override { | 693 SkPMColor ctable[], int* ctableCount) override { |
| 620 if (!conversion_possible(dstInfo, this->getInfo())) { | 694 if (!conversion_possible(dstInfo, this->getInfo())) { |
| 621 return kInvalidConversion; | 695 return kInvalidConversion; |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 726 typedef SkPngCodec INHERITED; | 800 typedef SkPngCodec INHERITED; |
| 727 }; | 801 }; |
| 728 | 802 |
| 729 SkCodec* SkPngCodec::NewFromStream(SkStream* stream, SkPngChunkReader* chunkRead er) { | 803 SkCodec* SkPngCodec::NewFromStream(SkStream* stream, SkPngChunkReader* chunkRead er) { |
| 730 SkAutoTDelete<SkStream> streamDeleter(stream); | 804 SkAutoTDelete<SkStream> streamDeleter(stream); |
| 731 png_structp png_ptr; | 805 png_structp png_ptr; |
| 732 png_infop info_ptr; | 806 png_infop info_ptr; |
| 733 SkImageInfo imageInfo; | 807 SkImageInfo imageInfo; |
| 734 int bitDepth; | 808 int bitDepth; |
| 735 int numberPasses; | 809 int numberPasses; |
| 810 SkColorSpace* colorSpace = nullptr; | |
| 736 | 811 |
| 737 if (!read_header(stream, chunkReader, &png_ptr, &info_ptr, &imageInfo, &bitD epth, | 812 if (!read_header(stream, chunkReader, &png_ptr, &info_ptr, &imageInfo, &bitD epth, |
| 738 &numberPasses)) { | 813 &numberPasses, &colorSpace)) { |
| 739 return nullptr; | 814 return nullptr; |
| 740 } | 815 } |
| 741 | 816 |
| 742 if (1 == numberPasses) { | 817 if (1 == numberPasses) { |
| 743 return new SkPngScanlineDecoder(imageInfo, streamDeleter.detach(), chunk Reader, | 818 return new SkPngScanlineDecoder(imageInfo, streamDeleter.detach(), chunk Reader, |
| 744 png_ptr, info_ptr, bitDepth); | 819 png_ptr, info_ptr, bitDepth, colorSpace) ; |
| 745 } | 820 } |
| 746 | 821 |
| 747 return new SkPngInterlacedScanlineDecoder(imageInfo, streamDeleter.detach(), chunkReader, | 822 return new SkPngInterlacedScanlineDecoder(imageInfo, streamDeleter.detach(), chunkReader, |
| 748 png_ptr, info_ptr, bitDepth, numbe rPasses); | 823 png_ptr, info_ptr, bitDepth, numbe rPasses, |
| 824 colorSpace); | |
| 749 } | 825 } |
| OLD | NEW |