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

Side by Side Diff: src/core/SkColorSpace_ICC.cpp

Issue 2171623002: Revert of Refactor parsing and storage of SkGammas (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: 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 | « src/core/SkColorSpace_Base.h ('k') | tests/ColorSpaceXformTest.cpp » ('j') | 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 2016 Google Inc. 2 * Copyright 2016 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 "SkColorSpace.h" 8 #include "SkColorSpace.h"
9 #include "SkColorSpace_Base.h" 9 #include "SkColorSpace_Base.h"
10 #include "SkColorSpacePriv.h" 10 #include "SkColorSpacePriv.h"
(...skipping 220 matching lines...) Expand 10 before | Expand all | Expand 10 after
231 dst[0] = SkFixedToFloat(read_big_endian_int(src + 8)); 231 dst[0] = SkFixedToFloat(read_big_endian_int(src + 8));
232 dst[1] = SkFixedToFloat(read_big_endian_int(src + 12)); 232 dst[1] = SkFixedToFloat(read_big_endian_int(src + 12));
233 dst[2] = SkFixedToFloat(read_big_endian_int(src + 16)); 233 dst[2] = SkFixedToFloat(read_big_endian_int(src + 16));
234 SkColorSpacePrintf("XYZ %g %g %g\n", dst[0], dst[1], dst[2]); 234 SkColorSpacePrintf("XYZ %g %g %g\n", dst[0], dst[1], dst[2]);
235 return true; 235 return true;
236 } 236 }
237 237
238 static constexpr uint32_t kTAG_CurveType = SkSetFourByteTag('c', 'u', 'r', ' v'); 238 static constexpr uint32_t kTAG_CurveType = SkSetFourByteTag('c', 'u', 'r', ' v');
239 static constexpr uint32_t kTAG_ParaCurveType = SkSetFourByteTag('p', 'a', 'r', ' a'); 239 static constexpr uint32_t kTAG_ParaCurveType = SkSetFourByteTag('p', 'a', 'r', ' a');
240 240
241 static SkGammas::Type set_gamma_value(SkGammas::Data* data, float value) { 241 static bool load_gammas(SkGammaCurve* gammas, uint32_t numGammas, const uint8_t* src, size_t len) {
242 if (color_space_almost_equal(2.2f, value)) { 242 for (uint32_t i = 0; i < numGammas; i++) {
243 data->fNamed = SkColorSpace::k2Dot2Curve_GammaNamed; 243 if (len < 12) {
244 return SkGammas::Type::kNamed_Type; 244 // FIXME (msarett):
245 } 245 // We could potentially return false here after correctly parsing *s ome* of the
246 246 // gammas correctly. Should we somehow try to indicate a partial su ccess?
247 if (color_space_almost_equal(1.0f, value)) { 247 SkColorSpacePrintf("gamma tag is too small (%d bytes)", len);
248 data->fNamed = SkColorSpace::kLinear_GammaNamed; 248 return false;
249 return SkGammas::Type::kNamed_Type; 249 }
250 } 250
251 251 // We need to count the number of bytes in the tag, so we are able to mo ve to the
252 if (color_space_almost_equal(0.0f, value)) { 252 // next tag on the next loop iteration.
253 return SkGammas::Type::kNone_Type; 253 size_t tagBytes;
254 } 254
255 255 uint32_t type = read_big_endian_uint(src);
256 data->fValue = value; 256 switch (type) {
257 return SkGammas::Type::kValue_Type; 257 case kTAG_CurveType: {
258 } 258 uint32_t count = read_big_endian_uint(src + 8);
259 259
260 static float read_big_endian_16_dot_16(const uint8_t buf[4]) { 260 // tagBytes = 12 + 2 * count
261 // It just so happens that SkFixed is also 16.16! 261 // We need to do safe addition here to avoid integer overflow.
262 return SkFixedToFloat(read_big_endian_int(buf)); 262 if (!safe_add(count, count, &tagBytes) ||
263 } 263 !safe_add((size_t) 12, tagBytes, &tagBytes))
264 264 {
265 /** 265 SkColorSpacePrintf("Invalid gamma count");
266 * @param outData Set to the appropriate value on success. If we have tabl e or 266 return false;
267 * parametric gamma, it is the responsibility of the caller to set 267 }
268 * fOffset. 268
269 * @param outParams If this is a parametric gamma, this is set to the appropr iate 269 if (0 == count) {
270 * parameters on success. 270 // Some tags require a gamma curve, but the author doesn't a ctually want
271 * @param outTagBytes Will be set to the length of the tag on success. 271 // to transform the data. In this case, it is common to see a curve with
272 * @src Pointer to tag data. 272 // a count of 0.
273 * @len Length of tag data in bytes. 273 gammas[i].fNamed = SkColorSpace::kLinear_GammaNamed;
274 * 274 break;
275 * @return kNone_Type on failure, otherwise the type of the gamma ta g. 275 } else if (len < tagBytes) {
276 */ 276 SkColorSpacePrintf("gamma tag is too small (%d bytes)", len) ;
277 static SkGammas::Type parse_gamma(SkGammas::Data* outData, SkGammas::Params* out Params, 277 return false;
278 size_t* outTagBytes, const uint8_t* src, s ize_t len) { 278 }
279 if (len < 12) { 279
280 SkColorSpacePrintf("gamma tag is too small (%d bytes)", len); 280 const uint16_t* table = (const uint16_t*) (src + 12);
281 return SkGammas::Type::kNone_Type; 281 if (1 == count) {
282 } 282 // The table entry is the gamma (with a bias of 256).
283 283 float value = (read_big_endian_short((const uint8_t*) table) ) / 256.0f;
284 // In the case of consecutive gamma tags, we need to count the number of byt es in the 284 set_gamma_value(&gammas[i], value);
285 // tag, so that we can move on to the next tag. 285 SkColorSpacePrintf("gamma %g\n", value);
286 size_t tagBytes; 286 break;
287 287 }
288 uint32_t type = read_big_endian_uint(src); 288
289 // Bytes 4-7 are reserved and should be set to zero. 289 // Check for frequently occurring sRGB curves.
290 switch (type) { 290 // We do this by sampling a few values and see if they match our expectation.
291 case kTAG_CurveType: { 291 // A more robust solution would be to compare each value in this curve against
292 uint32_t count = read_big_endian_uint(src + 8); 292 // an sRGB curve to see if we remain below an error threshold. At this time,
293 293 // we haven't seen any images in the wild that make this kind of
294 // tagBytes = 12 + 2 * count 294 // calculation necessary. We encounter identical gamma curves o ver and
295 // We need to do safe addition here to avoid integer overflow. 295 // over again, but relatively few variations.
296 if (!safe_add(count, count, &tagBytes) || 296 if (1024 == count) {
297 !safe_add((size_t) 12, tagBytes, &tagBytes)) 297 // The magic values were chosen because they match a very co mmon sRGB
298 { 298 // gamma table and the less common Canon sRGB gamma table (w hich use
299 SkColorSpacePrintf("Invalid gamma count"); 299 // different rounding rules).
300 return SkGammas::Type::kNone_Type; 300 if (0 == read_big_endian_short((const uint8_t*) &table[0]) & &
301 3366 == read_big_endian_short((const uint8_t*) &tabl e[257]) &&
302 14116 == read_big_endian_short((const uint8_t*) &tab le[513]) &&
303 34318 == read_big_endian_short((const uint8_t*) &tab le[768]) &&
304 65535 == read_big_endian_short((const uint8_t*) &tab le[1023])) {
305 gammas[i].fNamed = SkColorSpace::kSRGB_GammaNamed;
306 break;
307 }
308 } else if (26 == count) {
309 // The magic values were chosen because they match a very co mmon sRGB
310 // gamma table.
311 if (0 == read_big_endian_short((const uint8_t*) &table[0]) & &
312 3062 == read_big_endian_short((const uint8_t*) &tabl e[6]) &&
313 12824 == read_big_endian_short((const uint8_t*) &tab le[12]) &&
314 31237 == read_big_endian_short((const uint8_t*) &tab le[18]) &&
315 65535 == read_big_endian_short((const uint8_t*) &tab le[25])) {
316 gammas[i].fNamed = SkColorSpace::kSRGB_GammaNamed;
317 break;
318 }
319 } else if (4096 == count) {
320 // The magic values were chosen because they match Nikon, Ep son, and
321 // LCMS sRGB gamma tables (all of which use different roundi ng rules).
322 if (0 == read_big_endian_short((const uint8_t*) &table[0]) & &
323 950 == read_big_endian_short((const uint8_t*) &table [515]) &&
324 3342 == read_big_endian_short((const uint8_t*) &tabl e[1025]) &&
325 14079 == read_big_endian_short((const uint8_t*) &tab le[2051]) &&
326 65535 == read_big_endian_short((const uint8_t*) &tab le[4095])) {
327 gammas[i].fNamed = SkColorSpace::kSRGB_GammaNamed;
328 break;
329 }
330 }
331
332 // Otherwise, fill in the interpolation table.
333 gammas[i].fTableSize = count;
334 gammas[i].fTable = std::unique_ptr<float[]>(new float[count]);
335 for (uint32_t j = 0; j < count; j++) {
336 gammas[i].fTable[j] =
337 (read_big_endian_short((const uint8_t*) &table[j])) / 65535.0f;
338 }
339 break;
301 } 340 }
302 341 case kTAG_ParaCurveType: {
303 if (len < tagBytes) { 342 enum ParaCurveType {
304 SkColorSpacePrintf("gamma tag is too small (%d bytes)", len); 343 kExponential_ParaCurveType = 0,
305 return SkGammas::Type::kNone_Type; 344 kGAB_ParaCurveType = 1,
306 } 345 kGABC_ParaCurveType = 2,
307 *outTagBytes = tagBytes; 346 kGABDE_ParaCurveType = 3,
308 347 kGABCDEF_ParaCurveType = 4,
309 if (0 == count) { 348 };
310 // Some tags require a gamma curve, but the author doesn't actua lly want 349
311 // to transform the data. In this case, it is common to see a c urve with 350 // Determine the format of the parametric curve tag.
312 // a count of 0. 351 uint16_t format = read_big_endian_short(src + 8);
313 outData->fNamed = SkColorSpace::kLinear_GammaNamed; 352 if (kExponential_ParaCurveType == format) {
314 return SkGammas::Type::kNamed_Type; 353 tagBytes = 12 + 4;
315 }
316
317 const uint16_t* table = (const uint16_t*) (src + 12);
318 if (1 == count) {
319 // The table entry is the gamma (with a bias of 256).
320 float value = (read_big_endian_short((const uint8_t*) table)) / 256.0f;
321 SkColorSpacePrintf("gamma %g\n", value);
322
323 return set_gamma_value(outData, value);
324 }
325
326 // Check for frequently occurring sRGB curves.
327 // We do this by sampling a few values and see if they match our exp ectation.
328 // A more robust solution would be to compare each value in this cur ve against
329 // an sRGB curve to see if we remain below an error threshold. At t his time,
330 // we haven't seen any images in the wild that make this kind of
331 // calculation necessary. We encounter identical gamma curves over and
332 // over again, but relatively few variations.
333 if (1024 == count) {
334 // The magic values were chosen because they match both the very common
335 // HP sRGB gamma table and the less common Canon sRGB gamma tabl e (which use
336 // different rounding rules).
337 if (0 == read_big_endian_short((const uint8_t*) &table[0]) &&
338 3366 == read_big_endian_short((const uint8_t*) &table[25 7]) &&
339 14116 == read_big_endian_short((const uint8_t*) &table[5 13]) &&
340 34318 == read_big_endian_short((const uint8_t*) &table[7 68]) &&
341 65535 == read_big_endian_short((const uint8_t*) &table[1 023])) {
342 outData->fNamed = SkColorSpace::kSRGB_GammaNamed;
343 return SkGammas::Type::kNamed_Type;
344 }
345 }
346
347 if (26 == count) {
348 // The magic values were chosen because they match a very common LCMS sRGB
349 // gamma table.
350 if (0 == read_big_endian_short((const uint8_t*) &table[0]) &&
351 3062 == read_big_endian_short((const uint8_t*) &table[6] ) &&
352 12824 == read_big_endian_short((const uint8_t*) &table[1 2]) &&
353 31237 == read_big_endian_short((const uint8_t*) &table[1 8]) &&
354 65535 == read_big_endian_short((const uint8_t*) &table[2 5])) {
355 outData->fNamed = SkColorSpace::kSRGB_GammaNamed;
356 return SkGammas::Type::kNamed_Type;
357 }
358 }
359
360 if (4096 == count) {
361 // The magic values were chosen because they match Nikon, Epson, and
362 // LCMS sRGB gamma tables (all of which use different rounding r ules).
363 if (0 == read_big_endian_short((const uint8_t*) &table[0]) &&
364 950 == read_big_endian_short((const uint8_t*) &table[515 ]) &&
365 3342 == read_big_endian_short((const uint8_t*) &table[10 25]) &&
366 14079 == read_big_endian_short((const uint8_t*) &table[2 051]) &&
367 65535 == read_big_endian_short((const uint8_t*) &table[4 095])) {
368 outData->fNamed = SkColorSpace::kSRGB_GammaNamed;
369 return SkGammas::Type::kNamed_Type;
370 }
371 }
372
373 // Otherwise, we will represent gamma with a table.
374 outData->fTable.fSize = count;
375 return SkGammas::Type::kTable_Type;
376 }
377 case kTAG_ParaCurveType: {
378 enum ParaCurveType {
379 kExponential_ParaCurveType = 0,
380 kGAB_ParaCurveType = 1,
381 kGABC_ParaCurveType = 2,
382 kGABDE_ParaCurveType = 3,
383 kGABCDEF_ParaCurveType = 4,
384 };
385
386 // Determine the format of the parametric curve tag.
387 uint16_t format = read_big_endian_short(src + 8);
388 if (format > kGABCDEF_ParaCurveType) {
389 SkColorSpacePrintf("Unsupported gamma tag type %d\n", type);
390 return SkGammas::Type::kNone_Type;
391 }
392
393 if (kExponential_ParaCurveType == format) {
394 tagBytes = 12 + 4;
395 if (len < tagBytes) {
396 SkColorSpacePrintf("gamma tag is too small (%d bytes)", len) ;
397 return SkGammas::Type::kNone_Type;
398 }
399
400 // Y = X^g
401 float g = read_big_endian_16_dot_16(src + 12);
402
403 *outTagBytes = tagBytes;
404 return set_gamma_value(outData, g);
405 }
406
407 // Here's where the real parametric gammas start. There are many
408 // permutations of the same equations.
409 //
410 // Y = (aX + b)^g + c for X >= d
411 // Y = eX + f otherwise
412 //
413 // We will fill in with zeros as necessary to always match the above form.
414 if (len < 24) {
415 SkColorSpacePrintf("gamma tag is too small (%d bytes)", len);
416 return SkGammas::Type::kNone_Type;
417 }
418 float g = read_big_endian_16_dot_16(src + 12);
419 float a = read_big_endian_16_dot_16(src + 16);
420 float b = read_big_endian_16_dot_16(src + 20);
421 float c = 0.0f, d = 0.0f, e = 0.0f, f = 0.0f;
422 switch(format) {
423 case kGAB_ParaCurveType:
424 tagBytes = 12 + 12;
425
426 // Y = (aX + b)^g for X >= -b/a
427 // Y = 0 otherwise
428 d = -b / a;
429 break;
430 case kGABC_ParaCurveType:
431 tagBytes = 12 + 16;
432 if (len < tagBytes) { 354 if (len < tagBytes) {
433 SkColorSpacePrintf("gamma tag is too small (%d bytes)", len); 355 SkColorSpacePrintf("gamma tag is too small (%d bytes)", len);
434 return SkGammas::Type::kNone_Type; 356 return false;
435 } 357 }
436 358
437 // Y = (aX + b)^g + c for X >= -b/a 359 // Y = X^g
438 // Y = c otherwise 360 int32_t g = read_big_endian_int(src + 12);
439 c = read_big_endian_16_dot_16(src + 24); 361 set_gamma_value(&gammas[i], SkFixedToFloat(g));
440 d = -b / a; 362 } else {
441 f = c; 363 // Here's where the real parametric gammas start. There are many
442 break; 364 // permutations of the same equations.
443 case kGABDE_ParaCurveType: 365 //
444 tagBytes = 12 + 20;
445 if (len < tagBytes) {
446 SkColorSpacePrintf("gamma tag is too small (%d bytes)", len);
447 return SkGammas::Type::kNone_Type;
448 }
449
450 // Y = (aX + b)^g for X >= d
451 // Y = eX otherwise
452 d = read_big_endian_16_dot_16(src + 28);
453
454 // Not a bug! We define |e| to always be the coefficient on X in the
455 // second equation. The spec calls this |c| in this particu lar equation.
456 // We don't follow their convention because then |c| would h ave a
457 // different meaning in each of our cases.
458 e = read_big_endian_16_dot_16(src + 24);
459 break;
460 case kGABCDEF_ParaCurveType:
461 tagBytes = 12 + 28;
462 if (len < tagBytes) {
463 SkColorSpacePrintf("gamma tag is too small (%d bytes)", len);
464 return SkGammas::Type::kNone_Type;
465 }
466
467 // Y = (aX + b)^g + c for X >= d 366 // Y = (aX + b)^g + c for X >= d
468 // Y = eX + f otherwise 367 // Y = eX + f otherwise
469 // NOTE: The ICC spec writes "cX" in place of "eX" but I thi nk 368 //
470 // it's a typo. 369 // We will fill in with zeros as necessary to always match t he above form.
471 c = read_big_endian_16_dot_16(src + 24); 370 float g = 0.0f, a = 0.0f, b = 0.0f, c = 0.0f, d = 0.0f, e = 0.0f, f = 0.0f;
472 d = read_big_endian_16_dot_16(src + 28); 371 switch(format) {
473 e = read_big_endian_16_dot_16(src + 32); 372 case kGAB_ParaCurveType: {
474 f = read_big_endian_16_dot_16(src + 36); 373 tagBytes = 12 + 12;
475 break; 374 if (len < tagBytes) {
476 default: 375 SkColorSpacePrintf("gamma tag is too small (%d b ytes)", len);
477 SkASSERT(false); 376 return false;
478 return SkGammas::Type::kNone_Type; 377 }
378
379 // Y = (aX + b)^g for X >= -b/a
380 // Y = 0 otherwise
381 g = SkFixedToFloat(read_big_endian_int(src + 12));
382 a = SkFixedToFloat(read_big_endian_int(src + 16));
383 if (0.0f == a) {
384 return false;
385 }
386
387 b = SkFixedToFloat(read_big_endian_int(src + 20));
388 d = -b / a;
389 break;
390 }
391 case kGABC_ParaCurveType:
392 tagBytes = 12 + 16;
393 if (len < tagBytes) {
394 SkColorSpacePrintf("gamma tag is too small (%d b ytes)", len);
395 return false;
396 }
397
398 // Y = (aX + b)^g + c for X >= -b/a
399 // Y = c otherwise
400 g = SkFixedToFloat(read_big_endian_int(src + 12));
401 a = SkFixedToFloat(read_big_endian_int(src + 16));
402 if (0.0f == a) {
403 return false;
404 }
405
406 b = SkFixedToFloat(read_big_endian_int(src + 20));
407 c = SkFixedToFloat(read_big_endian_int(src + 24));
408 d = -b / a;
409 f = c;
410 break;
411 case kGABDE_ParaCurveType:
412 tagBytes = 12 + 20;
413 if (len < tagBytes) {
414 SkColorSpacePrintf("gamma tag is too small (%d b ytes)", len);
415 return false;
416 }
417
418 // Y = (aX + b)^g for X >= d
419 // Y = cX otherwise
420 g = SkFixedToFloat(read_big_endian_int(src + 12));
421 a = SkFixedToFloat(read_big_endian_int(src + 16));
422 b = SkFixedToFloat(read_big_endian_int(src + 20));
423 d = SkFixedToFloat(read_big_endian_int(src + 28));
424 e = SkFixedToFloat(read_big_endian_int(src + 24));
425 break;
426 case kGABCDEF_ParaCurveType:
427 tagBytes = 12 + 28;
428 if (len < tagBytes) {
429 SkColorSpacePrintf("gamma tag is too small (%d b ytes)", len);
430 return false;
431 }
432
433 // Y = (aX + b)^g + c for X >= d
434 // Y = eX + f otherwise
435 // NOTE: The ICC spec writes "cX" in place of "eX" b ut I think
436 // it's a typo.
437 g = SkFixedToFloat(read_big_endian_int(src + 12));
438 a = SkFixedToFloat(read_big_endian_int(src + 16));
439 b = SkFixedToFloat(read_big_endian_int(src + 20));
440 c = SkFixedToFloat(read_big_endian_int(src + 24));
441 d = SkFixedToFloat(read_big_endian_int(src + 28));
442 e = SkFixedToFloat(read_big_endian_int(src + 32));
443 f = SkFixedToFloat(read_big_endian_int(src + 36));
444 break;
445 default:
446 SkColorSpacePrintf("Invalid parametric curve type\n" );
447 return false;
448 }
449
450 // Recognize and simplify a very common parametric represent ation of sRGB gamma.
451 if (color_space_almost_equal(0.9479f, a) &&
452 color_space_almost_equal(0.0521f, b) &&
453 color_space_almost_equal(0.0000f, c) &&
454 color_space_almost_equal(0.0405f, d) &&
455 color_space_almost_equal(0.0774f, e) &&
456 color_space_almost_equal(0.0000f, f) &&
457 color_space_almost_equal(2.4000f, g)) {
458 gammas[i].fNamed = SkColorSpace::kSRGB_GammaNamed;
459 } else {
460 // Fail on invalid gammas.
461 if (d <= 0.0f) {
462 // Y = (aX + b)^g + c for always
463 if (0.0f == a || 0.0f == g) {
464 SkColorSpacePrintf("A or G is zero, constant gam ma function "
465 "is nonsense");
466 return false;
467 }
468 } else if (d >= 1.0f) {
469 // Y = eX + f for always
470 if (0.0f == e) {
471 SkColorSpacePrintf("E is zero, constant gamma fu nction is "
472 "nonsense");
473 return false;
474 }
475 } else if ((0.0f == a || 0.0f == g) && 0.0f == e) {
476 SkColorSpacePrintf("A or G, and E are zero, constant gamma function "
477 "is nonsense");
478 return false;
479 }
480
481 gammas[i].fG = g;
482 gammas[i].fA = a;
483 gammas[i].fB = b;
484 gammas[i].fC = c;
485 gammas[i].fD = d;
486 gammas[i].fE = e;
487 gammas[i].fF = f;
488 }
489 }
490
491 break;
479 } 492 }
480 493 default:
481 // Recognize and simplify a very common parametric representation of sRGB gamma. 494 SkColorSpacePrintf("Unsupported gamma tag type %d\n", type);
482 if (color_space_almost_equal(0.9479f, a) && 495 return false;
483 color_space_almost_equal(0.0521f, b) && 496 }
484 color_space_almost_equal(0.0000f, c) && 497
485 color_space_almost_equal(0.0405f, d) && 498 // Ensure that we have successfully read a gamma representation.
486 color_space_almost_equal(0.0774f, e) && 499 SkASSERT(gammas[i].isNamed() || gammas[i].isValue() || gammas[i].isTable () ||
487 color_space_almost_equal(0.0000f, f) && 500 gammas[i].isParametric());
488 color_space_almost_equal(2.4000f, g)) { 501
489 outData->fNamed = SkColorSpace::kSRGB_GammaNamed; 502 // Adjust src and len if there is another gamma curve to load.
490 return SkGammas::Type::kNamed_Type; 503 if (i != numGammas - 1) {
504 // Each curve is padded to 4-byte alignment.
505 tagBytes = SkAlign4(tagBytes);
506 if (len < tagBytes) {
507 return false;
491 } 508 }
492 509
493 // Fail on invalid gammas. 510 src += tagBytes;
494 if (SkScalarIsNaN(d)) { 511 len -= tagBytes;
495 return SkGammas::Type::kNone_Type;
496 }
497
498 if (d <= 0.0f) {
499 // Y = (aX + b)^g + c for always
500 if (0.0f == a || 0.0f == g) {
501 SkColorSpacePrintf("A or G is zero, constant gamma function "
502 "is nonsense");
503 return SkGammas::Type::kNone_Type;
504 }
505 }
506
507 if (d >= 1.0f) {
508 // Y = eX + f for always
509 if (0.0f == e) {
510 SkColorSpacePrintf("E is zero, constant gamma function is "
511 "nonsense");
512 return SkGammas::Type::kNone_Type;
513 }
514 }
515
516 if ((0.0f == a || 0.0f == g) && 0.0f == e) {
517 SkColorSpacePrintf("A or G, and E are zero, constant gamma funct ion "
518 "is nonsense");
519 return SkGammas::Type::kNone_Type;
520 }
521
522 *outTagBytes = tagBytes;
523
524 outParams->fG = g;
525 outParams->fA = a;
526 outParams->fB = b;
527 outParams->fC = c;
528 outParams->fD = d;
529 outParams->fE = e;
530 outParams->fF = f;
531 return SkGammas::Type::kParam_Type;
532 } 512 }
533 default:
534 SkColorSpacePrintf("Unsupported gamma tag type %d\n", type);
535 return SkGammas::Type::kNone_Type;
536 } 513 }
514
515 return true;
537 } 516 }
538 517
539 /**
540 * Returns the additional size in bytes needed to store the gamma tag.
541 */
542 static size_t gamma_alloc_size(SkGammas::Type type, const SkGammas::Data& data) {
543 switch (type) {
544 case SkGammas::Type::kNamed_Type:
545 case SkGammas::Type::kValue_Type:
546 return 0;
547 case SkGammas::Type::kTable_Type:
548 return sizeof(float) * data.fTable.fSize;
549 case SkGammas::Type::kParam_Type:
550 return sizeof(SkGammas::Params);
551 default:
552 SkASSERT(false);
553 return 0;
554 }
555 }
556
557 /**
558 * Sets invalid gamma to the default value.
559 */
560 static void handle_invalid_gamma(SkGammas::Type* type, SkGammas::Data* data) {
561 if (SkGammas::Type::kNone_Type == *type) {
562 *type = SkGammas::Type::kNamed_Type;
563 data->fNamed = SkColorSpace::kSRGB_GammaNamed;
564 }
565 }
566
567 /**
568 * Finish loading the gammas, now that we have allocated memory for the SkGamma s struct.
569 *
570 * There's nothing to do for the simple cases, but for table gammas we need to actually
571 * read the table into heap memory. And for parametric gammas, we need to copy over the
572 * parameter values.
573 *
574 * @param memory Pointer to start of the SkGammas memory block
575 * @param offset Bytes of memory (after the SkGammas struct) that are already i n use.
576 * @param data In-out variable. Will fill in the offset to the table or para meters
577 * if necessary.
578 * @param params Parameters for gamma curve. Only initialized/used when we hav e a
579 * parametric gamma.
580 * @param src Pointer to start of the gamma tag.
581 *
582 * @return Additional bytes of memory that are being used by this gamma c urve.
583 */
584 static size_t load_gammas(void* memory, size_t offset, SkGammas::Type type,
585 SkGammas::Data* data, const SkGammas::Params& params,
586 const uint8_t* src) {
587 void* storage = SkTAddOffset<void>(memory, offset + sizeof(SkGammas));
588
589 switch (type) {
590 case SkGammas::Type::kNamed_Type:
591 case SkGammas::Type::kValue_Type:
592 // Nothing to do here.
593 return 0;
594 case SkGammas::Type::kTable_Type: {
595 data->fTable.fOffset = offset;
596
597 float* outTable = (float*) storage;
598 const uint16_t* inTable = (const uint16_t*) (src + 12);
599 for (int i = 0; i < data->fTable.fSize; i++) {
600 outTable[i] = read_big_endian_16_dot_16((const uint8_t*) &inTabl e[i]);
601 }
602
603 return sizeof(float) * data->fTable.fSize;
604 }
605 case SkGammas::Type::kParam_Type:
606 data->fTable.fOffset = offset;
607 memcpy(storage, &params, sizeof(SkGammas::Params));
608 return sizeof(SkGammas::Params);
609 default:
610 SkASSERT(false);
611 return 0;
612 }
613 }
614
615 static constexpr uint32_t kTAG_AtoBType = SkSetFourByteTag('m', 'A', 'B', ' '); 518 static constexpr uint32_t kTAG_AtoBType = SkSetFourByteTag('m', 'A', 'B', ' ');
616 519
617 static bool load_color_lut(SkColorLookUpTable* colorLUT, uint32_t inputChannels, 520 bool load_color_lut(SkColorLookUpTable* colorLUT, uint32_t inputChannels, uint32 _t outputChannels,
618 uint32_t outputChannels, const uint8_t* src, size_t l en) { 521 const uint8_t* src, size_t len) {
619 // 16 bytes reserved for grid points, 2 for precision, 2 for padding. 522 // 16 bytes reserved for grid points, 2 for precision, 2 for padding.
620 // The color LUT data follows after this header. 523 // The color LUT data follows after this header.
621 static constexpr uint32_t kColorLUTHeaderSize = 20; 524 static constexpr uint32_t kColorLUTHeaderSize = 20;
622 if (len < kColorLUTHeaderSize) { 525 if (len < kColorLUTHeaderSize) {
623 SkColorSpacePrintf("Color LUT tag is too small (%d bytes).", len); 526 SkColorSpacePrintf("Color LUT tag is too small (%d bytes).", len);
624 return false; 527 return false;
625 } 528 }
626 size_t dataLen = len - kColorLUTHeaderSize; 529 size_t dataLen = len - kColorLUTHeaderSize;
627 530
628 SkASSERT(3 == inputChannels && 3 == outputChannels); 531 SkASSERT(3 == inputChannels && 3 == outputChannels);
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
677 if (1 == precision) { 580 if (1 == precision) {
678 colorLUT->fTable[i] = ((float) ptr[i]) / 255.0f; 581 colorLUT->fTable[i] = ((float) ptr[i]) / 255.0f;
679 } else { 582 } else {
680 colorLUT->fTable[i] = ((float) read_big_endian_short(ptr)) / 65535.0 f; 583 colorLUT->fTable[i] = ((float) read_big_endian_short(ptr)) / 65535.0 f;
681 } 584 }
682 } 585 }
683 586
684 return true; 587 return true;
685 } 588 }
686 589
687 static bool load_matrix(SkMatrix44* toXYZ, const uint8_t* src, size_t len) { 590 bool load_matrix(SkMatrix44* toXYZ, const uint8_t* src, size_t len) {
688 if (len < 48) { 591 if (len < 48) {
689 SkColorSpacePrintf("Matrix tag is too small (%d bytes).", len); 592 SkColorSpacePrintf("Matrix tag is too small (%d bytes).", len);
690 return false; 593 return false;
691 } 594 }
692 595
693 // For this matrix to behave like our "to XYZ D50" matrices, it needs to be scaled. 596 // For this matrix to behave like our "to XYZ D50" matrices, it needs to be scaled.
694 constexpr float scale = 65535.0 / 32768.0; 597 constexpr float scale = 65535.0 / 32768.0;
695 float array[16]; 598 float array[16];
696 array[ 0] = scale * SkFixedToFloat(read_big_endian_int(src)); 599 array[ 0] = scale * SkFixedToFloat(read_big_endian_int(src));
697 array[ 1] = scale * SkFixedToFloat(read_big_endian_int(src + 4)); 600 array[ 1] = scale * SkFixedToFloat(read_big_endian_int(src + 4));
698 array[ 2] = scale * SkFixedToFloat(read_big_endian_int(src + 8)); 601 array[ 2] = scale * SkFixedToFloat(read_big_endian_int(src + 8));
699 array[ 3] = scale * SkFixedToFloat(read_big_endian_int(src + 36)); // transl ate R 602 array[ 3] = scale * SkFixedToFloat(read_big_endian_int(src + 36)); // transl ate R
700 array[ 4] = scale * SkFixedToFloat(read_big_endian_int(src + 12)); 603 array[ 4] = scale * SkFixedToFloat(read_big_endian_int(src + 12));
701 array[ 5] = scale * SkFixedToFloat(read_big_endian_int(src + 16)); 604 array[ 5] = scale * SkFixedToFloat(read_big_endian_int(src + 16));
702 array[ 6] = scale * SkFixedToFloat(read_big_endian_int(src + 20)); 605 array[ 6] = scale * SkFixedToFloat(read_big_endian_int(src + 20));
703 array[ 7] = scale * SkFixedToFloat(read_big_endian_int(src + 40)); // transl ate G 606 array[ 7] = scale * SkFixedToFloat(read_big_endian_int(src + 40)); // transl ate G
704 array[ 8] = scale * SkFixedToFloat(read_big_endian_int(src + 24)); 607 array[ 8] = scale * SkFixedToFloat(read_big_endian_int(src + 24));
705 array[ 9] = scale * SkFixedToFloat(read_big_endian_int(src + 28)); 608 array[ 9] = scale * SkFixedToFloat(read_big_endian_int(src + 28));
706 array[10] = scale * SkFixedToFloat(read_big_endian_int(src + 32)); 609 array[10] = scale * SkFixedToFloat(read_big_endian_int(src + 32));
707 array[11] = scale * SkFixedToFloat(read_big_endian_int(src + 44)); // transl ate B 610 array[11] = scale * SkFixedToFloat(read_big_endian_int(src + 44)); // transl ate B
708 array[12] = 0.0f; 611 array[12] = 0.0f;
709 array[13] = 0.0f; 612 array[13] = 0.0f;
710 array[14] = 0.0f; 613 array[14] = 0.0f;
711 array[15] = 1.0f; 614 array[15] = 1.0f;
712 toXYZ->setColMajorf(array); 615 toXYZ->setColMajorf(array);
713 return true; 616 return true;
714 } 617 }
715 618
716 static bool load_a2b0(SkColorLookUpTable* colorLUT, SkColorSpace::GammaNamed* ga mmaNamed, 619 bool load_a2b0(SkColorLookUpTable* colorLUT, SkGammaCurve* gammas, SkMatrix44* t oXYZ,
717 sk_sp<SkGammas>* gammas, SkMatrix44* toXYZ, const uint8_t* src, size_t len) { 620 const uint8_t* src, size_t len) {
718 if (len < 32) { 621 if (len < 32) {
719 SkColorSpacePrintf("A to B tag is too small (%d bytes).", len); 622 SkColorSpacePrintf("A to B tag is too small (%d bytes).", len);
720 return false; 623 return false;
721 } 624 }
722 625
723 uint32_t type = read_big_endian_uint(src); 626 uint32_t type = read_big_endian_uint(src);
724 if (kTAG_AtoBType != type) { 627 if (kTAG_AtoBType != type) {
725 // FIXME (msarett): Need to support lut8Type and lut16Type. 628 // FIXME (msarett): Need to support lut8Type and lut16Type.
726 SkColorSpacePrintf("Unsupported A to B tag type.\n"); 629 SkColorSpacePrintf("Unsupported A to B tag type.\n");
727 return false; 630 return false;
(...skipping 27 matching lines...) Expand all
755 uint32_t offsetToColorLUT = read_big_endian_int(src + 24); 658 uint32_t offsetToColorLUT = read_big_endian_int(src + 24);
756 if (0 != offsetToColorLUT && offsetToColorLUT < len) { 659 if (0 != offsetToColorLUT && offsetToColorLUT < len) {
757 if (!load_color_lut(colorLUT, inputChannels, outputChannels, src + offse tToColorLUT, 660 if (!load_color_lut(colorLUT, inputChannels, outputChannels, src + offse tToColorLUT,
758 len - offsetToColorLUT)) { 661 len - offsetToColorLUT)) {
759 SkColorSpacePrintf("Failed to read color LUT from A to B tag.\n"); 662 SkColorSpacePrintf("Failed to read color LUT from A to B tag.\n");
760 } 663 }
761 } 664 }
762 665
763 uint32_t offsetToMCurves = read_big_endian_int(src + 20); 666 uint32_t offsetToMCurves = read_big_endian_int(src + 20);
764 if (0 != offsetToMCurves && offsetToMCurves < len) { 667 if (0 != offsetToMCurves && offsetToMCurves < len) {
765 const uint8_t* rTagPtr = src + offsetToMCurves; 668 if (!load_gammas(gammas, outputChannels, src + offsetToMCurves, len - of fsetToMCurves)) {
766 size_t tagLen = len - offsetToMCurves; 669 SkColorSpacePrintf("Failed to read M curves from A to B tag. Using linear gamma.\n");
767 670 gammas[0].fNamed = SkColorSpace::kLinear_GammaNamed;
768 SkGammas::Data rData; 671 gammas[1].fNamed = SkColorSpace::kLinear_GammaNamed;
769 SkGammas::Params rParams; 672 gammas[2].fNamed = SkColorSpace::kLinear_GammaNamed;
770
771 // On an invalid first gamma, tagBytes remains set as zero. This causes the two
772 // subsequent to be treated as identical (which is what we want).
773 size_t tagBytes = 0;
774 SkGammas::Type rType = parse_gamma(&rData, &rParams, &tagBytes, rTagPtr, tagLen);
775 handle_invalid_gamma(&rType, &rData);
776 size_t alignedTagBytes = SkAlign4(tagBytes);
777
778 if ((3 * alignedTagBytes <= tagLen) &&
779 !memcmp(rTagPtr, rTagPtr + 1 * alignedTagBytes, tagBytes) &&
780 !memcmp(rTagPtr, rTagPtr + 2 * alignedTagBytes, tagBytes))
781 {
782 if (SkGammas::Type::kNamed_Type == rType) {
783 *gammaNamed = rData.fNamed;
784 } else {
785 size_t allocSize = sizeof(SkGammas) + gamma_alloc_size(rType, rD ata);
786 void* memory = sk_malloc_throw(allocSize);
787 *gammas = sk_sp<SkGammas>(new (memory) SkGammas());
788 load_gammas(memory, 0, rType, &rData, rParams, rTagPtr);
789
790 (*gammas)->fRedType = rType;
791 (*gammas)->fGreenType = rType;
792 (*gammas)->fBlueType = rType;
793
794 (*gammas)->fRedData = rData;
795 (*gammas)->fGreenData = rData;
796 (*gammas)->fBlueData = rData;
797 }
798 } else {
799 const uint8_t* gTagPtr = rTagPtr + alignedTagBytes;
800 tagLen = tagLen > alignedTagBytes ? tagLen - alignedTagBytes : 0;
801 SkGammas::Data gData;
802 SkGammas::Params gParams;
803 tagBytes = 0;
804 SkGammas::Type gType = parse_gamma(&gData, &gParams, &tagBytes, gTag Ptr,
805 tagLen);
806 handle_invalid_gamma(&gType, &gData);
807
808 alignedTagBytes = SkAlign4(tagBytes);
809 const uint8_t* bTagPtr = gTagPtr + alignedTagBytes;
810 tagLen = tagLen > alignedTagBytes ? tagLen - alignedTagBytes : 0;
811 SkGammas::Data bData;
812 SkGammas::Params bParams;
813 SkGammas::Type bType = parse_gamma(&bData, &bParams, &tagBytes, bTag Ptr,
814 tagLen);
815 handle_invalid_gamma(&bType, &bData);
816
817 size_t allocSize = sizeof(SkGammas) + gamma_alloc_size(rType, rData)
818 + gamma_alloc_size(gType, gData)
819 + gamma_alloc_size(bType, bData) ;
820 void* memory = sk_malloc_throw(allocSize);
821 *gammas = sk_sp<SkGammas>(new (memory) SkGammas());
822
823 uint32_t offset = 0;
824 (*gammas)->fRedType = rType;
825 offset += load_gammas(memory, offset, rType, &rData, rParams, rTagPt r);
826
827 (*gammas)->fGreenType = gType;
828 offset += load_gammas(memory, offset, gType, &gData, gParams, gTagPt r);
829
830 (*gammas)->fBlueType = bType;
831 load_gammas(memory, offset, bType, &bData, bParams, bTagPtr);
832
833 (*gammas)->fRedData = rData;
834 (*gammas)->fGreenData = gData;
835 (*gammas)->fBlueData = bData;
836 } 673 }
837 } 674 }
838 675
839 uint32_t offsetToMatrix = read_big_endian_int(src + 16); 676 uint32_t offsetToMatrix = read_big_endian_int(src + 16);
840 if (0 != offsetToMatrix && offsetToMatrix < len) { 677 if (0 != offsetToMatrix && offsetToMatrix < len) {
841 if (!load_matrix(toXYZ, src + offsetToMatrix, len - offsetToMatrix)) { 678 if (!load_matrix(toXYZ, src + offsetToMatrix, len - offsetToMatrix)) {
842 SkColorSpacePrintf("Failed to read matrix from A to B tag.\n"); 679 SkColorSpacePrintf("Failed to read matrix from A to B tag.\n");
843 toXYZ->setIdentity(); 680 toXYZ->setIdentity();
844 } 681 }
845 } 682 }
846 683
847 return true; 684 return true;
848 } 685 }
849 686
850 static bool tag_equals(const ICCTag* a, const ICCTag* b, const uint8_t* base) {
851 if (!a || !b) {
852 return a == b;
853 }
854
855 if (a->fLength != b->fLength) {
856 return false;
857 }
858
859 if (a->fOffset == b->fOffset) {
860 return true;
861 }
862
863 return !memcmp(a->addr(base), b->addr(base), a->fLength);
864 }
865
866 sk_sp<SkColorSpace> SkColorSpace::NewICC(const void* input, size_t len) { 687 sk_sp<SkColorSpace> SkColorSpace::NewICC(const void* input, size_t len) {
867 if (!input || len < kICCHeaderSize) { 688 if (!input || len < kICCHeaderSize) {
868 return_null("Data is null or not large enough to contain an ICC profile" ); 689 return_null("Data is null or not large enough to contain an ICC profile" );
869 } 690 }
870 691
871 // Create our own copy of the input. 692 // Create our own copy of the input.
872 void* memory = sk_malloc_throw(len); 693 void* memory = sk_malloc_throw(len);
873 memcpy(memory, input, len); 694 memcpy(memory, input, len);
874 sk_sp<SkData> data = SkData::MakeFromMalloc(memory, len); 695 sk_sp<SkData> data = SkData::MakeFromMalloc(memory, len);
875 const uint8_t* base = data->bytes(); 696 const void* base = data->data();
876 const uint8_t* ptr = base; 697 const uint8_t* ptr = (const uint8_t*) base;
877 698
878 // Read the ICC profile header and check to make sure that it is valid. 699 // Read the ICC profile header and check to make sure that it is valid.
879 ICCProfileHeader header; 700 ICCProfileHeader header;
880 header.init(ptr, len); 701 header.init(ptr, len);
881 if (!header.valid()) { 702 if (!header.valid()) {
882 return nullptr; 703 return nullptr;
883 } 704 }
884 705
885 // Adjust ptr and len before reading the tags. 706 // Adjust ptr and len before reading the tags.
886 if (len < header.fSize) { 707 if (len < header.fSize) {
(...skipping 25 matching lines...) Expand all
912 } 733 }
913 734
914 switch (header.fInputColorSpace) { 735 switch (header.fInputColorSpace) {
915 case kRGB_ColorSpace: { 736 case kRGB_ColorSpace: {
916 // Recognize the rXYZ, gXYZ, and bXYZ tags. 737 // Recognize the rXYZ, gXYZ, and bXYZ tags.
917 const ICCTag* r = ICCTag::Find(tags.get(), tagCount, kTAG_rXYZ); 738 const ICCTag* r = ICCTag::Find(tags.get(), tagCount, kTAG_rXYZ);
918 const ICCTag* g = ICCTag::Find(tags.get(), tagCount, kTAG_gXYZ); 739 const ICCTag* g = ICCTag::Find(tags.get(), tagCount, kTAG_gXYZ);
919 const ICCTag* b = ICCTag::Find(tags.get(), tagCount, kTAG_bXYZ); 740 const ICCTag* b = ICCTag::Find(tags.get(), tagCount, kTAG_bXYZ);
920 if (r && g && b) { 741 if (r && g && b) {
921 float toXYZ[9]; 742 float toXYZ[9];
922 if (!load_xyz(&toXYZ[0], r->addr(base), r->fLength) || 743 if (!load_xyz(&toXYZ[0], r->addr((const uint8_t*) base), r->fLen gth) ||
923 !load_xyz(&toXYZ[3], g->addr(base), g->fLength) || 744 !load_xyz(&toXYZ[3], g->addr((const uint8_t*) base), g->fLen gth) ||
924 !load_xyz(&toXYZ[6], b->addr(base), b->fLength)) 745 !load_xyz(&toXYZ[6], b->addr((const uint8_t*) base), b->fLen gth))
925 { 746 {
926 return_null("Need valid rgb tags for XYZ space"); 747 return_null("Need valid rgb tags for XYZ space");
927 } 748 }
928 SkMatrix44 mat(SkMatrix44::kUninitialized_Constructor); 749 SkMatrix44 mat(SkMatrix44::kUninitialized_Constructor);
929 mat.set3x3RowMajorf(toXYZ); 750 mat.set3x3RowMajorf(toXYZ);
930 751
752 // It is not uncommon to see missing or empty gamma tags. This indicates
753 // that we should use unit gamma.
754 SkGammaCurve curves[3];
931 r = ICCTag::Find(tags.get(), tagCount, kTAG_rTRC); 755 r = ICCTag::Find(tags.get(), tagCount, kTAG_rTRC);
932 g = ICCTag::Find(tags.get(), tagCount, kTAG_gTRC); 756 g = ICCTag::Find(tags.get(), tagCount, kTAG_gTRC);
933 b = ICCTag::Find(tags.get(), tagCount, kTAG_bTRC); 757 b = ICCTag::Find(tags.get(), tagCount, kTAG_bTRC);
934 758 if (!r || !load_gammas(&curves[0], 1, r->addr((const uint8_t*) b ase), r->fLength))
935 // If some, but not all, of the gamma tags are missing, assume t hat all 759 {
936 // gammas are meant to be the same. This behavior is an arbitra ry guess, 760 SkColorSpacePrintf("Failed to read R gamma tag.\n");
937 // but it simplifies the code below. 761 curves[0].fNamed = SkColorSpace::kLinear_GammaNamed;
938 if ((!r || !g || !b) && (r || g || b)) { 762 }
939 if (!r) { 763 if (!g || !load_gammas(&curves[1], 1, g->addr((const uint8_t*) b ase), g->fLength))
940 r = g ? g : b; 764 {
941 } 765 SkColorSpacePrintf("Failed to read G gamma tag.\n");
942 766 curves[1].fNamed = SkColorSpace::kLinear_GammaNamed;
943 if (!g) { 767 }
944 g = r ? r : b; 768 if (!b || !load_gammas(&curves[2], 1, b->addr((const uint8_t*) b ase), b->fLength))
945 } 769 {
946 770 SkColorSpacePrintf("Failed to read B gamma tag.\n");
947 if (!b) { 771 curves[2].fNamed = SkColorSpace::kLinear_GammaNamed;
948 b = r ? r : g;
949 }
950 } 772 }
951 773
952 GammaNamed gammaNamed = kNonStandard_GammaNamed; 774 GammaNamed gammaNamed = SkGammas::Named(curves);
953 sk_sp<SkGammas> gammas = nullptr;
954 size_t tagBytes;
955 if (r && g && b) {
956 if (tag_equals(r, g, base) && tag_equals(g, b, base)) {
957 SkGammas::Data data;
958 SkGammas::Params params;
959 SkGammas::Type Type =
960 parse_gamma(&data, &params, &tagBytes, r->addr(b ase), r->fLength);
961 handle_invalid_gamma(&Type, &data);
962
963 if (SkGammas::Type::kNamed_Type == Type) {
964 gammaNamed = data.fNamed;
965 } else {
966 size_t allocSize = sizeof(SkGammas) + gamma_alloc_si ze(Type, data);
967 void* memory = sk_malloc_throw(allocSize);
968 gammas = sk_sp<SkGammas>(new (memory) SkGammas());
969 load_gammas(memory, 0, Type, &data, params, r->addr( base));
970
971 gammas->fRedType = Type;
972 gammas->fGreenType = Type;
973 gammas->fBlueType = Type;
974
975 gammas->fRedData = data;
976 gammas->fGreenData = data;
977 gammas->fBlueData = data;
978 }
979 } else {
980 SkGammas::Data rData;
981 SkGammas::Params rParams;
982 SkGammas::Type rType =
983 parse_gamma(&rData, &rParams, &tagBytes, r->addr (base), r->fLength);
984 handle_invalid_gamma(&rType, &rData);
985
986 SkGammas::Data gData;
987 SkGammas::Params gParams;
988 SkGammas::Type gType =
989 parse_gamma(&gData, &gParams, &tagBytes, g->addr (base), g->fLength);
990 handle_invalid_gamma(&gType, &gData);
991
992 SkGammas::Data bData;
993 SkGammas::Params bParams;
994 SkGammas::Type bType =
995 parse_gamma(&bData, &bParams, &tagBytes, b->addr (base), b->fLength);
996 handle_invalid_gamma(&bType, &bData);
997
998 size_t allocSize = sizeof(SkGammas) + gamma_alloc_size(r Type, rData)
999 + gamma_alloc_size(g Type, gData)
1000 + gamma_alloc_size(b Type, bData);
1001 void* memory = sk_malloc_throw(allocSize);
1002 gammas = sk_sp<SkGammas>(new (memory) SkGammas());
1003
1004 uint32_t offset = 0;
1005 gammas->fRedType = rType;
1006 offset += load_gammas(memory, offset, rType, &rData, rPa rams,
1007 r->addr(base));
1008
1009 gammas->fGreenType = gType;
1010 offset += load_gammas(memory, offset, gType, &gData, gPa rams,
1011 g->addr(base));
1012
1013 gammas->fBlueType = bType;
1014 load_gammas(memory, offset, bType, &bData, bParams, b->a ddr(base));
1015
1016 gammas->fRedData = rData;
1017 gammas->fGreenData = gData;
1018 gammas->fBlueData = bData;
1019 }
1020 } else {
1021 gammaNamed = kLinear_GammaNamed;
1022 }
1023
1024 if (kNonStandard_GammaNamed == gammaNamed) { 775 if (kNonStandard_GammaNamed == gammaNamed) {
1025 return sk_sp<SkColorSpace>(new SkColorSpace_Base(nullptr, ga mmaNamed, 776 sk_sp<SkGammas> gammas = sk_make_sp<SkGammas>(std::move(curv es[0]),
1026 std::move(g ammas), mat, 777 std::move(curv es[1]),
1027 std::move(d ata))); 778 std::move(curv es[2]));
779 return sk_sp<SkColorSpace>(new SkColorSpace_Base(nullptr, st d::move(gammas),
780 mat, std::m ove(data)));
1028 } else { 781 } else {
1029 return SkColorSpace_Base::NewRGB(gammaNamed, mat); 782 return SkColorSpace_Base::NewRGB(gammaNamed, mat);
1030 } 783 }
1031 } 784 }
1032 785
1033 // Recognize color profile specified by A2B0 tag. 786 // Recognize color profile specified by A2B0 tag.
1034 const ICCTag* a2b0 = ICCTag::Find(tags.get(), tagCount, kTAG_A2B0); 787 const ICCTag* a2b0 = ICCTag::Find(tags.get(), tagCount, kTAG_A2B0);
1035 if (a2b0) { 788 if (a2b0) {
1036 GammaNamed gammaNamed = kNonStandard_GammaNamed;
1037 sk_sp<SkGammas> gammas = nullptr;
1038 sk_sp<SkColorLookUpTable> colorLUT = sk_make_sp<SkColorLookUpTab le>(); 789 sk_sp<SkColorLookUpTable> colorLUT = sk_make_sp<SkColorLookUpTab le>();
790 SkGammaCurve curves[3];
1039 SkMatrix44 toXYZ(SkMatrix44::kUninitialized_Constructor); 791 SkMatrix44 toXYZ(SkMatrix44::kUninitialized_Constructor);
1040 if (!load_a2b0(colorLUT.get(), &gammaNamed, &gammas, &toXYZ, a2b 0->addr(base), 792 if (!load_a2b0(colorLUT.get(), curves, &toXYZ, a2b0->addr((const uint8_t*) base),
1041 a2b0->fLength)) { 793 a2b0->fLength)) {
1042 return_null("Failed to parse A2B0 tag"); 794 return_null("Failed to parse A2B0 tag");
1043 } 795 }
1044 796
797 GammaNamed gammaNamed = SkGammas::Named(curves);
1045 colorLUT = colorLUT->fTable ? colorLUT : nullptr; 798 colorLUT = colorLUT->fTable ? colorLUT : nullptr;
1046 if (colorLUT || kNonStandard_GammaNamed == gammaNamed) { 799 if (colorLUT || kNonStandard_GammaNamed == gammaNamed) {
800 sk_sp<SkGammas> gammas = sk_make_sp<SkGammas>(std::move(curv es[0]),
801 std::move(curv es[1]),
802 std::move(curv es[2]));
803
1047 return sk_sp<SkColorSpace>(new SkColorSpace_Base(std::move(c olorLUT), 804 return sk_sp<SkColorSpace>(new SkColorSpace_Base(std::move(c olorLUT),
1048 gammaNamed, std::move(gammas), 805 std::move(g ammas), toXYZ,
1049 toXYZ, std: :move(data))); 806 std::move(d ata)));
1050 } else { 807 } else {
1051 return SkColorSpace_Base::NewRGB(gammaNamed, toXYZ); 808 return SkColorSpace_Base::NewRGB(gammaNamed, toXYZ);
1052 } 809 }
1053 } 810 }
1054 } 811 }
1055 default: 812 default:
1056 break; 813 break;
1057 } 814 }
1058 815
1059 return_null("ICC profile contains unsupported colorspace"); 816 return_null("ICC profile contains unsupported colorspace");
(...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after
1181 ptr[2] = SkEndian_SwapBE32(1); 938 ptr[2] = SkEndian_SwapBE32(1);
1182 939
1183 // Convert gamma to 16-bit fixed point. 940 // Convert gamma to 16-bit fixed point.
1184 uint16_t* ptr16 = (uint16_t*) (ptr + 3); 941 uint16_t* ptr16 = (uint16_t*) (ptr + 3);
1185 ptr16[0] = SkEndian_SwapBE16((uint16_t) (value * 256.0f)); 942 ptr16[0] = SkEndian_SwapBE16((uint16_t) (value * 256.0f));
1186 943
1187 // Pad tag with zero. 944 // Pad tag with zero.
1188 ptr16[1] = 0; 945 ptr16[1] = 0;
1189 } 946 }
1190 947
948 static float get_gamma_value(const SkGammaCurve* curve) {
949 switch (curve->fNamed) {
950 case SkColorSpace::kSRGB_GammaNamed:
951 // FIXME (msarett):
952 // kSRGB cannot be represented by a value. Here we fall through to 2.2f,
953 // which is a close guess. To be more accurate, we need to represen t sRGB
954 // gamma with a parametric curve.
955 case SkColorSpace::k2Dot2Curve_GammaNamed:
956 return 2.2f;
957 case SkColorSpace::kLinear_GammaNamed:
958 return 1.0f;
959 default:
960 SkASSERT(curve->isValue());
961 return curve->fValue;
962 }
963 }
964
1191 sk_sp<SkData> SkColorSpace_Base::writeToICC() const { 965 sk_sp<SkData> SkColorSpace_Base::writeToICC() const {
1192 // Return if this object was created from a profile, or if we have already s erialized 966 // Return if this object was created from a profile, or if we have already s erialized
1193 // the profile. 967 // the profile.
1194 if (fProfileData) { 968 if (fProfileData) {
1195 return fProfileData; 969 return fProfileData;
1196 } 970 }
1197 971
1198 // The client may create an SkColorSpace using an SkMatrix44, but currently we only 972 // The client may create an SkColorSpace using an SkMatrix44, but currently we only
1199 // support writing profiles with 3x3 matrices. 973 // support writing profiles with 3x3 matrices.
1200 // TODO (msarett): Fix this! 974 // TODO (msarett): Fix this!
(...skipping 23 matching lines...) Expand all
1224 write_xyz_tag((uint32_t*) ptr, fToXYZD50, 0); 998 write_xyz_tag((uint32_t*) ptr, fToXYZD50, 0);
1225 ptr += kTAG_XYZ_Bytes; 999 ptr += kTAG_XYZ_Bytes;
1226 write_xyz_tag((uint32_t*) ptr, fToXYZD50, 1); 1000 write_xyz_tag((uint32_t*) ptr, fToXYZD50, 1);
1227 ptr += kTAG_XYZ_Bytes; 1001 ptr += kTAG_XYZ_Bytes;
1228 write_xyz_tag((uint32_t*) ptr, fToXYZD50, 2); 1002 write_xyz_tag((uint32_t*) ptr, fToXYZD50, 2);
1229 ptr += kTAG_XYZ_Bytes; 1003 ptr += kTAG_XYZ_Bytes;
1230 1004
1231 // Write TRC tags 1005 // Write TRC tags
1232 GammaNamed gammaNamed = this->gammaNamed(); 1006 GammaNamed gammaNamed = this->gammaNamed();
1233 if (kNonStandard_GammaNamed == gammaNamed) { 1007 if (kNonStandard_GammaNamed == gammaNamed) {
1234 // FIXME (msarett): 1008 write_trc_tag((uint32_t*) ptr, get_gamma_value(&as_CSB(this)->fGammas->f Red));
1235 // Write the correct gamma representation rather than 2.2f.
1236 write_trc_tag((uint32_t*) ptr, 2.2f);
1237 ptr += SkAlign4(kTAG_TRC_Bytes); 1009 ptr += SkAlign4(kTAG_TRC_Bytes);
1238 write_trc_tag((uint32_t*) ptr, 2.2f); 1010 write_trc_tag((uint32_t*) ptr, get_gamma_value(&as_CSB(this)->fGammas->f Green));
1239 ptr += SkAlign4(kTAG_TRC_Bytes); 1011 ptr += SkAlign4(kTAG_TRC_Bytes);
1240 write_trc_tag((uint32_t*) ptr, 2.2f); 1012 write_trc_tag((uint32_t*) ptr, get_gamma_value(&as_CSB(this)->fGammas->f Blue));
1241 ptr += SkAlign4(kTAG_TRC_Bytes); 1013 ptr += SkAlign4(kTAG_TRC_Bytes);
1242 } else { 1014 } else {
1243 switch (gammaNamed) { 1015 switch (gammaNamed) {
1244 case SkColorSpace::kSRGB_GammaNamed: 1016 case SkColorSpace::kSRGB_GammaNamed:
1245 // FIXME (msarett): 1017 // FIXME (msarett):
1246 // kSRGB cannot be represented by a value. Here we fall through to 2.2f, 1018 // kSRGB cannot be represented by a value. Here we fall through to 2.2f,
1247 // which is a close guess. To be more accurate, we need to repr esent sRGB 1019 // which is a close guess. To be more accurate, we need to repr esent sRGB
1248 // gamma with a parametric curve. 1020 // gamma with a parametric curve.
1249 case SkColorSpace::k2Dot2Curve_GammaNamed: 1021 case SkColorSpace::k2Dot2Curve_GammaNamed:
1250 write_trc_tag((uint32_t*) ptr, 2.2f); 1022 write_trc_tag((uint32_t*) ptr, 2.2f);
(...skipping 28 matching lines...) Expand all
1279 ptr32[4] = SkEndian_SwapBE32(0x000116cc); 1051 ptr32[4] = SkEndian_SwapBE32(0x000116cc);
1280 ptr += kTAG_XYZ_Bytes; 1052 ptr += kTAG_XYZ_Bytes;
1281 1053
1282 // Write copyright tag 1054 // Write copyright tag
1283 memcpy(ptr, gEmptyTextTag, sizeof(gEmptyTextTag)); 1055 memcpy(ptr, gEmptyTextTag, sizeof(gEmptyTextTag));
1284 1056
1285 // TODO (msarett): Should we try to hold onto the data so we can return imme diately if 1057 // TODO (msarett): Should we try to hold onto the data so we can return imme diately if
1286 // the client calls again? 1058 // the client calls again?
1287 return SkData::MakeFromMalloc(profile.release(), kICCProfileSize); 1059 return SkData::MakeFromMalloc(profile.release(), kICCProfileSize);
1288 } 1060 }
OLDNEW
« no previous file with comments | « src/core/SkColorSpace_Base.h ('k') | tests/ColorSpaceXformTest.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698