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

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: Response to comments / adds code to parse icc profiles Created 4 years, 9 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 147 matching lines...) Expand 10 before | Expand all | Expand 10 after
158 } 158 }
159 159
160 /////////////////////////////////////////////////////////////////////////////// 160 ///////////////////////////////////////////////////////////////////////////////
161 // Creation 161 // Creation
162 /////////////////////////////////////////////////////////////////////////////// 162 ///////////////////////////////////////////////////////////////////////////////
163 163
164 bool SkPngCodec::IsPng(const char* buf, size_t bytesRead) { 164 bool SkPngCodec::IsPng(const char* buf, size_t bytesRead) {
165 return !png_sig_cmp((png_bytep) buf, (png_size_t)0, bytesRead); 165 return !png_sig_cmp((png_bytep) buf, (png_size_t)0, bytesRead);
166 } 166 }
167 167
168 // Returns a colorSpace object that represents any color space information in
169 // the encoded data. If the encoded data contains no color space, this will
170 // return NULL.
171 SkColorSpace* read_color_space(png_structp png_ptr, png_infop info_ptr) {
172
173 // First check for an ICC profile
174 png_bytep profile;
175 png_uint_32 length;
176 // The below variables are unused, however, we need to pass them in anyway o r
177 // png_get_iCCP() will return nothing.
178 // Could knowing the |name| of the profile ever be interesting? Maybe for d ebugging?
179 png_charp name;
180 // The |compression| is uninteresting since:
181 // (1) libpng has already decompressed the profile for us.
182 // (2) "deflate" is the only mode of decompression that libpng supports.
183 int compression;
184 if (PNG_INFO_iCCP == png_get_iCCP(png_ptr, info_ptr, &name, &compression, &p rofile,
185 &length)) {
186 return SkColorSpace::NewICC(profile, length);
187 }
188
189 // Second, check for sRGB.
190 if (png_get_valid(png_ptr, info_ptr, PNG_INFO_sRGB)) {
191
192 // sRGB chunks also store a rendering intent: Absolute, Relative,
193 // Perceptual, and Saturation.
194 // FIXME (msarett): Extract this information from the sRGB chunk once
195 // we are able to handle this information in
196 // SkColorSpace.
197 return SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named);
198 }
199
200 // Next, check for chromaticities.
201 png_fixed_point XYZ[9];
202 SkFloat3x3 toXYZD50;
203 png_fixed_point gamma;
204 SkFloat3 gammas;
205 if (png_get_cHRM_XYZ_fixed(png_ptr, info_ptr, &XYZ[0], &XYZ[1], &XYZ[2], &XY Z[3], &XYZ[4],
206 &XYZ[5], &XYZ[6], &XYZ[7], &XYZ[8])) {
207
208 // FIXME (msarett): Here we are treating XYZ values as D50 even though t he color
209 // temperature is unspecified. I suspect that this ass umption
210 // is most often ok, but we could also calculate the co lor
211 // temperature (D value) and then convert the XYZ to D5 0. Maybe
212 // we should add a new constructor to SkColorSpace that accepts
213 // XYZ with D-Unkown?
214 for (int i = 0; i < 9; i++) {
215
216 // This is identical libpng's fixed point -> double conversion (exce pt that
scroggo 2016/02/29 22:18:49 nit: identical to* ?
msarett 2016/03/01 00:39:35 Done.
217 // we are converting to floats). We choose to do the conversion our selves
218 // rather than convert fixed point -> double -> float.
219 toXYZD50.fMat[i] = ((float) XYZ[i]) * 0.00001f;
220 }
221
222 if (!(PNG_INFO_gAMA == png_get_gAMA_fixed(png_ptr, info_ptr, &gamma))) {
223
224 // If the image does not specify gamma, let's choose linear. Should we default
225 // to sRGB? Most images are intended to be sRGB (gamma = 2.2f).
226 gamma = PNG_GAMMA_LINEAR;
227 }
228 gammas.fVec[0] = gammas.fVec[1] = gammas.fVec[2] = ((float) gamma) * 0.0 0001f;
229
230 return SkColorSpace::NewRGB(toXYZD50, gammas);
231 }
232
233 // Last, check for gamma.
234 if (PNG_INFO_gAMA == png_get_gAMA_fixed(png_ptr, info_ptr, &gamma)) {
235
236 // Guess a default value for cHRM? Or should we just give up?
237 // Here we use the identity matrix as a default.
238 // FIXME (msarett): Should SkFloat3x3 have a method to set the identity matrix?
239 memset(toXYZD50.fMat, 0, 9 * sizeof(float));
240 toXYZD50.fMat[0] = toXYZD50.fMat[4] = toXYZD50.fMat[8] = 1.0f;
241
242 // Set the gammas.
243 gammas.fVec[0] = gammas.fVec[1] = gammas.fVec[2] = ((float) gamma) * 0.0 0001f;
scroggo 2016/02/29 22:18:49 Should this be a function? (Perhaps a static funct
msarett 2016/03/01 00:39:34 Yes that's a little clearer.
scroggo 2016/03/01 14:42:29 Much clearer, thanks!
244
245 return SkColorSpace::NewRGB(toXYZD50, gammas);
246 }
247
248 // Finally, what should we do if there is no color space information in the PNG?
249 // The specification says that this indicates "gamma is unknown" and that th e
250 // "color is device dependent". I'm assuming we can represent this with NUL L.
251 // But should we guess sRGB? Most images are sRGB, even if they don't speci fy.
252 return nullptr;
253 }
254
168 // Reads the header and initializes the output fields, if not NULL. 255 // Reads the header and initializes the output fields, if not NULL.
169 // 256 //
170 // @param stream Input data. Will be read to get enough information to properly 257 // @param stream Input data. Will be read to get enough information to properly
171 // setup the codec. 258 // setup the codec.
172 // @param chunkReader SkPngChunkReader, for reading unknown chunks. May be NULL. 259 // @param chunkReader SkPngChunkReader, for reading unknown chunks. May be NULL.
173 // If not NULL, png_ptr will hold an *unowned* pointer to it. The caller is 260 // If not NULL, png_ptr will hold an *unowned* pointer to it. The caller is
174 // expected to continue to own it for the lifetime of the png_ptr. 261 // expected to continue to own it for the lifetime of the png_ptr.
175 // @param png_ptrp Optional output variable. If non-NULL, will be set to a new 262 // @param png_ptrp Optional output variable. If non-NULL, will be set to a new
176 // png_structp on success. 263 // png_structp on success.
177 // @param info_ptrp Optional output variable. If non-NULL, will be set to a new 264 // @param info_ptrp Optional output variable. If non-NULL, will be set to a new
(...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after
323 *png_ptrp = png_ptr; 410 *png_ptrp = png_ptr;
324 } 411 }
325 if (info_ptrp) { 412 if (info_ptrp) {
326 *info_ptrp = info_ptr; 413 *info_ptrp = info_ptr;
327 } 414 }
328 415
329 return true; 416 return true;
330 } 417 }
331 418
332 SkPngCodec::SkPngCodec(const SkImageInfo& info, SkStream* stream, SkPngChunkRead er* chunkReader, 419 SkPngCodec::SkPngCodec(const SkImageInfo& info, SkStream* stream, SkPngChunkRead er* chunkReader,
333 png_structp png_ptr, png_infop info_ptr, int bitDepth, in t numberPasses) 420 png_structp png_ptr, png_infop info_ptr, int bitDepth, in t numberPasses,
334 : INHERITED(info, stream) 421 SkColorSpace* colorSpace)
422 : INHERITED(info, stream, colorSpace)
335 , fPngChunkReader(SkSafeRef(chunkReader)) 423 , fPngChunkReader(SkSafeRef(chunkReader))
336 , fPng_ptr(png_ptr) 424 , fPng_ptr(png_ptr)
337 , fInfo_ptr(info_ptr) 425 , fInfo_ptr(info_ptr)
338 , fSrcConfig(SkSwizzler::kUnknown) 426 , fSrcConfig(SkSwizzler::kUnknown)
339 , fNumberPasses(numberPasses) 427 , fNumberPasses(numberPasses)
340 , fBitDepth(bitDepth) 428 , fBitDepth(bitDepth)
341 {} 429 {}
342 430
343 SkPngCodec::~SkPngCodec() { 431 SkPngCodec::~SkPngCodec() {
344 this->destroyReadStruct(); 432 this->destroyReadStruct();
(...skipping 189 matching lines...) Expand 10 before | Expand all | Expand 10 after
534 if (colorPtr) { 622 if (colorPtr) {
535 return get_color_table_fill_value(colorType, colorPtr, 0); 623 return get_color_table_fill_value(colorType, colorPtr, 0);
536 } 624 }
537 return INHERITED::onGetFillValue(colorType); 625 return INHERITED::onGetFillValue(colorType);
538 } 626 }
539 627
540 // Subclass of SkPngCodec which supports scanline decoding 628 // Subclass of SkPngCodec which supports scanline decoding
541 class SkPngScanlineDecoder : public SkPngCodec { 629 class SkPngScanlineDecoder : public SkPngCodec {
542 public: 630 public:
543 SkPngScanlineDecoder(const SkImageInfo& srcInfo, SkStream* stream, 631 SkPngScanlineDecoder(const SkImageInfo& srcInfo, SkStream* stream,
544 SkPngChunkReader* chunkReader, png_structp png_ptr, png_infop info_p tr, int bitDepth) 632 SkPngChunkReader* chunkReader, png_structp png_ptr, png_infop info_p tr, int bitDepth,
545 : INHERITED(srcInfo, stream, chunkReader, png_ptr, info_ptr, bitDepth, 1 ) 633 SkColorSpace* colorSpace)
634 : INHERITED(srcInfo, stream, chunkReader, png_ptr, info_ptr, bitDepth, 1 , colorSpace)
546 , fSrcRow(nullptr) 635 , fSrcRow(nullptr)
547 {} 636 {}
548 637
549 Result onStartScanlineDecode(const SkImageInfo& dstInfo, const Options& opti ons, 638 Result onStartScanlineDecode(const SkImageInfo& dstInfo, const Options& opti ons,
550 SkPMColor ctable[], int* ctableCount) override { 639 SkPMColor ctable[], int* ctableCount) override {
551 if (!conversion_possible(dstInfo, this->getInfo())) { 640 if (!conversion_possible(dstInfo, this->getInfo())) {
552 return kInvalidConversion; 641 return kInvalidConversion;
553 } 642 }
554 643
555 const Result result = this->initializeSwizzler(dstInfo, options, ctable, 644 const Result result = this->initializeSwizzler(dstInfo, options, ctable,
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
600 uint8_t* fSrcRow; 689 uint8_t* fSrcRow;
601 690
602 typedef SkPngCodec INHERITED; 691 typedef SkPngCodec INHERITED;
603 }; 692 };
604 693
605 694
606 class SkPngInterlacedScanlineDecoder : public SkPngCodec { 695 class SkPngInterlacedScanlineDecoder : public SkPngCodec {
607 public: 696 public:
608 SkPngInterlacedScanlineDecoder(const SkImageInfo& srcInfo, SkStream* stream, 697 SkPngInterlacedScanlineDecoder(const SkImageInfo& srcInfo, SkStream* stream,
609 SkPngChunkReader* chunkReader, png_structp png_ptr, png_infop info_p tr, 698 SkPngChunkReader* chunkReader, png_structp png_ptr, png_infop info_p tr,
610 int bitDepth, int numberPasses) 699 int bitDepth, int numberPasses, SkColorSpace* colorSpace)
611 : INHERITED(srcInfo, stream, chunkReader, png_ptr, info_ptr, bitDepth, n umberPasses) 700 : INHERITED(srcInfo, stream, chunkReader, png_ptr, info_ptr, bitDepth, n umberPasses,
701 colorSpace)
612 , fHeight(-1) 702 , fHeight(-1)
613 , fCanSkipRewind(false) 703 , fCanSkipRewind(false)
614 { 704 {
615 SkASSERT(numberPasses != 1); 705 SkASSERT(numberPasses != 1);
616 } 706 }
617 707
618 Result onStartScanlineDecode(const SkImageInfo& dstInfo, const Options& opti ons, 708 Result onStartScanlineDecode(const SkImageInfo& dstInfo, const Options& opti ons,
619 SkPMColor ctable[], int* ctableCount) override { 709 SkPMColor ctable[], int* ctableCount) override {
620 if (!conversion_possible(dstInfo, this->getInfo())) { 710 if (!conversion_possible(dstInfo, this->getInfo())) {
621 return kInvalidConversion; 711 return kInvalidConversion;
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after
732 png_infop info_ptr; 822 png_infop info_ptr;
733 SkImageInfo imageInfo; 823 SkImageInfo imageInfo;
734 int bitDepth; 824 int bitDepth;
735 int numberPasses; 825 int numberPasses;
736 826
737 if (!read_header(stream, chunkReader, &png_ptr, &info_ptr, &imageInfo, &bitD epth, 827 if (!read_header(stream, chunkReader, &png_ptr, &info_ptr, &imageInfo, &bitD epth,
738 &numberPasses)) { 828 &numberPasses)) {
739 return nullptr; 829 return nullptr;
740 } 830 }
741 831
832 SkColorSpace* colorSpace = read_color_space(png_ptr, info_ptr);
833
742 if (1 == numberPasses) { 834 if (1 == numberPasses) {
743 return new SkPngScanlineDecoder(imageInfo, streamDeleter.detach(), chunk Reader, 835 return new SkPngScanlineDecoder(imageInfo, streamDeleter.detach(), chunk Reader,
744 png_ptr, info_ptr, bitDepth); 836 png_ptr, info_ptr, bitDepth, colorSpace) ;
745 } 837 }
746 838
747 return new SkPngInterlacedScanlineDecoder(imageInfo, streamDeleter.detach(), chunkReader, 839 return new SkPngInterlacedScanlineDecoder(imageInfo, streamDeleter.detach(), chunkReader,
748 png_ptr, info_ptr, bitDepth, numbe rPasses); 840 png_ptr, info_ptr, bitDepth, numbe rPasses,
841 colorSpace);
749 } 842 }
OLDNEW
« no previous file with comments | « src/codec/SkPngCodec.h ('k') | src/core/SkColorSpace.h » ('j') | src/core/SkColorSpace.cpp » ('J')

Powered by Google App Engine
This is Rietveld 408576698