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

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

Issue 2180483003: Convert XYZ values from PNGs to D50 (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Preemptively fix windows Created 4 years, 5 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 | « no previous file | no next file » | 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"
11 #include "SkColorSpace_Base.h" 11 #include "SkColorSpace_Base.h"
12 #include "SkColorTable.h" 12 #include "SkColorTable.h"
13 #include "SkMath.h" 13 #include "SkMath.h"
14 #include "SkOpts.h" 14 #include "SkOpts.h"
15 #include "SkPngCodec.h" 15 #include "SkPngCodec.h"
16 #include "SkPoint3.h"
16 #include "SkSize.h" 17 #include "SkSize.h"
17 #include "SkStream.h" 18 #include "SkStream.h"
18 #include "SkSwizzler.h" 19 #include "SkSwizzler.h"
19 #include "SkTemplates.h" 20 #include "SkTemplates.h"
20 #include "SkUtils.h" 21 #include "SkUtils.h"
21 22
22 /////////////////////////////////////////////////////////////////////////////// 23 ///////////////////////////////////////////////////////////////////////////////
23 // Callback functions 24 // Callback functions
24 /////////////////////////////////////////////////////////////////////////////// 25 ///////////////////////////////////////////////////////////////////////////////
25 26
(...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after
171 // This is necessary because the gAMA chunk actually stores 1/gamma. 172 // This is necessary because the gAMA chunk actually stores 1/gamma.
172 return 1.0f / png_fixed_point_to_float(x); 173 return 1.0f / png_fixed_point_to_float(x);
173 } 174 }
174 175
175 static constexpr float gSRGB_toXYZD50[] { 176 static constexpr float gSRGB_toXYZD50[] {
176 0.4358f, 0.2224f, 0.0139f, // * R 177 0.4358f, 0.2224f, 0.0139f, // * R
177 0.3853f, 0.7170f, 0.0971f, // * G 178 0.3853f, 0.7170f, 0.0971f, // * G
178 0.1430f, 0.0606f, 0.7139f, // * B 179 0.1430f, 0.0606f, 0.7139f, // * B
179 }; 180 };
180 181
182 static bool convert_to_D50(SkMatrix44* toXYZD50, float toXYZ[9], float whitePoin t[2]) {
183 float wX = whitePoint[0];
184 float wY = whitePoint[1];
185 if (wX < 0.0f || wY < 0.0f || (wX + wY > 1.0f)) {
186 return false;
187 }
188
189 // Calculate the XYZ illuminant. Call this the src illuminant.
190 float wZ = 1.0f - wX - wY;
191 float scale = 1.0f / wY;
192 // TODO (msarett):
193 // What are common src illuminants? I'm guessing we will almost always see D65. Should
194 // we go ahead and save a precomputed D65->D50 Bradford matrix? Should we e xit early if
195 // if the src illuminant is D50?
196 SkVector3 srcXYZ = SkVector3::Make(wX * scale, 1.0f, wZ * scale);
197
198 // The D50 illuminant.
199 SkVector3 dstXYZ = SkVector3::Make(0.96422f, 1.0f, 0.82521f);
200
201 // Calculate the chromatic adaptation matrix. We will use the Bradford meth od, thus
202 // the matrices below. The Bradford method is used by Adobe and is widely c onsidered
203 // to be the best.
204 // http://www.brucelindbloom.com/index.html?Eqn_ChromAdapt.html
205 SkMatrix mA, mAInv;
206 mA.setAll(0.8951f, 0.2664f, -0.1614f, -0.7502f, 1.7135f, 0.0367f, 0.0389f, - 0.0685f, 1.0296f);
207 mAInv.setAll(0.9869929f, -0.1470543f, 0.1599627f, 0.4323053f, 0.5183603f, 0. 0492912f,
208 -0.0085287f, 0.0400428f, 0.9684867f);
209
210 // Map illuminant into cone response domain.
211 SkVector3 srcCone;
212 srcCone.fX = mA[0] * srcXYZ.fX + mA[1] * srcXYZ.fY + mA[2] * srcXYZ.fZ;
213 srcCone.fY = mA[3] * srcXYZ.fX + mA[4] * srcXYZ.fY + mA[5] * srcXYZ.fZ;
214 srcCone.fZ = mA[6] * srcXYZ.fX + mA[7] * srcXYZ.fY + mA[8] * srcXYZ.fZ;
215 SkVector3 dstCone;
216 dstCone.fX = mA[0] * dstXYZ.fX + mA[1] * dstXYZ.fY + mA[2] * dstXYZ.fZ;
217 dstCone.fY = mA[3] * dstXYZ.fX + mA[4] * dstXYZ.fY + mA[5] * dstXYZ.fZ;
218 dstCone.fZ = mA[6] * dstXYZ.fX + mA[7] * dstXYZ.fY + mA[8] * dstXYZ.fZ;
219
220 SkMatrix DXToD50;
221 DXToD50.setIdentity();
222 DXToD50[0] = dstCone.fX / srcCone.fX;
223 DXToD50[4] = dstCone.fY / srcCone.fY;
224 DXToD50[8] = dstCone.fZ / srcCone.fZ;
225 DXToD50.postConcat(mAInv);
226 DXToD50.preConcat(mA);
227
228 SkMatrix toXYZ3x3;
229 toXYZ3x3.setAll(toXYZ[0], toXYZ[3], toXYZ[6], toXYZ[1], toXYZ[4], toXYZ[7], toXYZ[2], toXYZ[5],
230 toXYZ[8]);
231 toXYZ3x3.postConcat(DXToD50);
232
233 toXYZD50->set3x3(toXYZ3x3[0], toXYZ3x3[1], toXYZ3x3[2], toXYZ3x3[3], toXYZ3x 3[4], toXYZ3x3[5],
234 toXYZ3x3[6], toXYZ3x3[7], toXYZ3x3[8]);
235 return true;
236 }
237
181 // Returns a colorSpace object that represents any color space information in 238 // Returns a colorSpace object that represents any color space information in
182 // the encoded data. If the encoded data contains no color space, this will 239 // the encoded data. If the encoded data contains no color space, this will
183 // return NULL. 240 // return NULL.
184 sk_sp<SkColorSpace> read_color_space(png_structp png_ptr, png_infop info_ptr) { 241 sk_sp<SkColorSpace> read_color_space(png_structp png_ptr, png_infop info_ptr) {
185 242
186 #if (PNG_LIBPNG_VER_MAJOR > 1) || (PNG_LIBPNG_VER_MAJOR == 1 && PNG_LIBPNG_VER_M INOR >= 6) 243 #if (PNG_LIBPNG_VER_MAJOR > 1) || (PNG_LIBPNG_VER_MAJOR == 1 && PNG_LIBPNG_VER_M INOR >= 6)
187 244
188 // First check for an ICC profile 245 // First check for an ICC profile
189 png_bytep profile; 246 png_bytep profile;
190 png_uint_32 length; 247 png_uint_32 length;
(...skipping 15 matching lines...) Expand all
206 263
207 // sRGB chunks also store a rendering intent: Absolute, Relative, 264 // sRGB chunks also store a rendering intent: Absolute, Relative,
208 // Perceptual, and Saturation. 265 // Perceptual, and Saturation.
209 // FIXME (msarett): Extract this information from the sRGB chunk once 266 // FIXME (msarett): Extract this information from the sRGB chunk once
210 // we are able to handle this information in 267 // we are able to handle this information in
211 // SkColorSpace. 268 // SkColorSpace.
212 return SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named); 269 return SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named);
213 } 270 }
214 271
215 // Next, check for chromaticities. 272 // Next, check for chromaticities.
216 png_fixed_point XYZ[9]; 273 png_fixed_point toXYZFixed[9];
217 float toXYZD50[9]; 274 float toXYZ[9];
275 png_fixed_point whitePointFixed[2];
276 float whitePoint[2];
218 png_fixed_point gamma; 277 png_fixed_point gamma;
219 float gammas[3]; 278 float gammas[3];
220 if (png_get_cHRM_XYZ_fixed(png_ptr, info_ptr, &XYZ[0], &XYZ[1], &XYZ[2], &XY Z[3], &XYZ[4], 279 if (png_get_cHRM_XYZ_fixed(png_ptr, info_ptr, &toXYZFixed[0], &toXYZFixed[1] , &toXYZFixed[2],
221 &XYZ[5], &XYZ[6], &XYZ[7], &XYZ[8])) { 280 &toXYZFixed[3], &toXYZFixed[4], &toXYZFixed[5], & toXYZFixed[6],
281 &toXYZFixed[7], &toXYZFixed[8]) &&
282 png_get_cHRM_fixed(png_ptr, info_ptr, &whitePointFixed[0], &whitePointFi xed[1], nullptr,
283 nullptr, nullptr, nullptr, nullptr, nullptr))
284 {
285 for (int i = 0; i < 9; i++) {
286 toXYZ[i] = png_fixed_point_to_float(toXYZFixed[i]);
287 }
288 whitePoint[0] = png_fixed_point_to_float(whitePointFixed[0]);
289 whitePoint[1] = png_fixed_point_to_float(whitePointFixed[1]);
222 290
223 // FIXME (msarett): Here we are treating XYZ values as D50 even though t he color 291 SkMatrix44 toXYZD50(SkMatrix44::kUninitialized_Constructor);
224 // temperature is unspecified. I suspect that this ass umption 292 if (!convert_to_D50(&toXYZD50, toXYZ, whitePoint)) {
225 // is most often ok, but we could also calculate the co lor 293 toXYZD50.set3x3RowMajorf(gSRGB_toXYZD50);
226 // temperature (D value) and then convert the XYZ to D5 0. Maybe
227 // we should add a new constructor to SkColorSpace that accepts
228 // XYZ with D-Unkown?
229 for (int i = 0; i < 9; i++) {
230 toXYZD50[i] = png_fixed_point_to_float(XYZ[i]);
231 } 294 }
232 SkMatrix44 mat(SkMatrix44::kUninitialized_Constructor);
233 mat.set3x3RowMajorf(toXYZD50);
234 295
235 if (PNG_INFO_gAMA == png_get_gAMA_fixed(png_ptr, info_ptr, &gamma)) { 296 if (PNG_INFO_gAMA == png_get_gAMA_fixed(png_ptr, info_ptr, &gamma)) {
236 float value = png_inverted_fixed_point_to_float(gamma); 297 float value = png_inverted_fixed_point_to_float(gamma);
237 gammas[0] = value; 298 gammas[0] = value;
238 gammas[1] = value; 299 gammas[1] = value;
239 gammas[2] = value; 300 gammas[2] = value;
240 301
241 return SkColorSpace_Base::NewRGB(gammas, mat); 302 return SkColorSpace_Base::NewRGB(gammas, toXYZD50);
242 } 303 }
243 304
244 // Default to sRGB gamma if the image has color space information, 305 // Default to sRGB gamma if the image has color space information,
245 // but does not specify gamma. 306 // but does not specify gamma.
246 return SkColorSpace::NewRGB(SkColorSpace::kSRGB_GammaNamed, mat); 307 return SkColorSpace::NewRGB(SkColorSpace::kSRGB_GammaNamed, toXYZD50);
247 } 308 }
248 309
249 // Last, check for gamma. 310 // Last, check for gamma.
250 if (PNG_INFO_gAMA == png_get_gAMA_fixed(png_ptr, info_ptr, &gamma)) { 311 if (PNG_INFO_gAMA == png_get_gAMA_fixed(png_ptr, info_ptr, &gamma)) {
251 312
252 // Set the gammas. 313 // Set the gammas.
253 float value = png_inverted_fixed_point_to_float(gamma); 314 float value = png_inverted_fixed_point_to_float(gamma);
254 gammas[0] = value; 315 gammas[0] = value;
255 gammas[1] = value; 316 gammas[1] = value;
256 gammas[2] = value; 317 gammas[2] = value;
257 318
258 // Since there is no cHRM, we will guess sRGB gamut. 319 // Since there is no cHRM, we will guess sRGB gamut.
259 SkMatrix44 mat(SkMatrix44::kUninitialized_Constructor); 320 SkMatrix44 toXYZD50(SkMatrix44::kUninitialized_Constructor);
260 mat.set3x3RowMajorf(gSRGB_toXYZD50); 321 toXYZD50.set3x3RowMajorf(gSRGB_toXYZD50);
261 322
262 return SkColorSpace_Base::NewRGB(gammas, mat); 323 return SkColorSpace_Base::NewRGB(gammas, toXYZD50);
263 } 324 }
264 325
265 #endif // LIBPNG >= 1.6 326 #endif // LIBPNG >= 1.6
266 327
267 // Report that there is no color space information in the PNG. SkPngCodec i s currently 328 // Report that there is no color space information in the PNG. SkPngCodec i s currently
268 // implemented to guess sRGB in this case. 329 // implemented to guess sRGB in this case.
269 return nullptr; 330 return nullptr;
270 } 331 }
271 332
272 static int bytes_per_pixel(int bitsPerPixel) { 333 static int bytes_per_pixel(int bitsPerPixel) {
(...skipping 536 matching lines...) Expand 10 before | Expand all | Expand 10 after
809 SkCodec* outCodec; 870 SkCodec* outCodec;
810 if (read_header(stream, chunkReader, &outCodec, nullptr, nullptr)) { 871 if (read_header(stream, chunkReader, &outCodec, nullptr, nullptr)) {
811 // Codec has taken ownership of the stream. 872 // Codec has taken ownership of the stream.
812 SkASSERT(outCodec); 873 SkASSERT(outCodec);
813 streamDeleter.release(); 874 streamDeleter.release();
814 return outCodec; 875 return outCodec;
815 } 876 }
816 877
817 return nullptr; 878 return nullptr;
818 } 879 }
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698