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

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

Issue 1726823002: Set SkColorSpace object for PNGs and parse ICC profiles (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Add fColorProfile to SkCodec Created 4 years, 10 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
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 "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
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
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
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
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
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
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 }
OLDNEW
« include/codec/SkCodec.h ('K') | « src/codec/SkPngCodec.h ('k') | src/core/SkColorSpace.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698