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 |