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

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

Issue 2166093003: Miscellaneous color space refactors (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Tweak SkColorLookUpTable constructor 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
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"
11 #include "SkEndian.h" 11 #include "SkEndian.h"
12 #include "SkFixed.h" 12 #include "SkFixed.h"
13 #include "SkTemplates.h" 13 #include "SkTemplates.h"
14 14
15 #define return_if_false(pred, msg) \ 15 #define return_if_false(pred, msg) \
16 do { \ 16 do { \
17 if (!(pred)) { \ 17 if (!(pred)) { \
18 SkColorSpacePrintf("Invalid ICC Profile: %s.\n", (msg)); \ 18 SkColorSpacePrintf("Invalid ICC Profile: %s.\n", (msg)); \
19 return false; \ 19 return false; \
20 } \ 20 } \
21 } while (0) 21 } while (0)
22 22
23 #define return_null(msg) \ 23 #define return_null(msg) \
24 do { \ 24 do { \
25 SkColorSpacePrintf("Invalid ICC Profile: %s.\n", (msg)); \ 25 SkColorSpacePrintf("Invalid ICC Profile: %s.\n", (msg)); \
26 return nullptr; \ 26 return nullptr; \
27 } while (0) 27 } while (0)
28 28
29 static uint16_t read_big_endian_short(const uint8_t* ptr) { 29 static uint16_t read_big_endian_u16(const uint8_t* ptr) {
30 return ptr[0] << 8 | ptr[1]; 30 return ptr[0] << 8 | ptr[1];
31 } 31 }
32 32
33 static uint32_t read_big_endian_uint(const uint8_t* ptr) { 33 static uint32_t read_big_endian_u32(const uint8_t* ptr) {
34 return ptr[0] << 24 | ptr[1] << 16 | ptr[2] << 8 | ptr[3]; 34 return ptr[0] << 24 | ptr[1] << 16 | ptr[2] << 8 | ptr[3];
35 } 35 }
36 36
37 static int32_t read_big_endian_int(const uint8_t* ptr) { 37 static int32_t read_big_endian_i32(const uint8_t* ptr) {
38 return (int32_t) read_big_endian_uint(ptr); 38 return (int32_t) read_big_endian_u32(ptr);
39 } 39 }
40 40
41 // This is equal to the header size according to the ICC specification (128) 41 // This is equal to the header size according to the ICC specification (128)
42 // plus the size of the tag count (4). We include the tag count since we 42 // plus the size of the tag count (4). We include the tag count since we
43 // always require it to be present anyway. 43 // always require it to be present anyway.
44 static constexpr size_t kICCHeaderSize = 132; 44 static constexpr size_t kICCHeaderSize = 132;
45 45
46 // Contains a signature (4), offset (4), and size (4). 46 // Contains a signature (4), offset (4), and size (4).
47 static constexpr size_t kICCTagTableEntrySize = 12; 47 static constexpr size_t kICCTagTableEntrySize = 12;
48 48
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
98 // Reserved for future use. 98 // Reserved for future use.
99 uint32_t fReserved_ignored[7]; 99 uint32_t fReserved_ignored[7];
100 100
101 uint32_t fTagCount; 101 uint32_t fTagCount;
102 102
103 void init(const uint8_t* src, size_t len) { 103 void init(const uint8_t* src, size_t len) {
104 SkASSERT(kICCHeaderSize == sizeof(*this)); 104 SkASSERT(kICCHeaderSize == sizeof(*this));
105 105
106 uint32_t* dst = (uint32_t*) this; 106 uint32_t* dst = (uint32_t*) this;
107 for (uint32_t i = 0; i < kICCHeaderSize / 4; i++, src+=4) { 107 for (uint32_t i = 0; i < kICCHeaderSize / 4; i++, src+=4) {
108 dst[i] = read_big_endian_uint(src); 108 dst[i] = read_big_endian_u32(src);
109 } 109 }
110 } 110 }
111 111
112 bool valid() const { 112 bool valid() const {
113 return_if_false(fSize >= kICCHeaderSize, "Size is too small"); 113 return_if_false(fSize >= kICCHeaderSize, "Size is too small");
114 114
115 uint8_t majorVersion = fVersion >> 24; 115 uint8_t majorVersion = fVersion >> 24;
116 return_if_false(majorVersion <= 4, "Unsupported version"); 116 return_if_false(majorVersion <= 4, "Unsupported version");
117 117
118 // These are the four basic classes of profiles that we might expect to see embedded 118 // These are the four basic classes of profiles that we might expect to see embedded
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
179 *result = product32; 179 *result = product32;
180 return true; 180 return true;
181 } 181 }
182 182
183 struct ICCTag { 183 struct ICCTag {
184 uint32_t fSignature; 184 uint32_t fSignature;
185 uint32_t fOffset; 185 uint32_t fOffset;
186 uint32_t fLength; 186 uint32_t fLength;
187 187
188 const uint8_t* init(const uint8_t* src) { 188 const uint8_t* init(const uint8_t* src) {
189 fSignature = read_big_endian_uint(src); 189 fSignature = read_big_endian_u32(src);
190 fOffset = read_big_endian_uint(src + 4); 190 fOffset = read_big_endian_u32(src + 4);
191 fLength = read_big_endian_uint(src + 8); 191 fLength = read_big_endian_u32(src + 8);
192 return src + 12; 192 return src + 12;
193 } 193 }
194 194
195 bool valid(size_t len) { 195 bool valid(size_t len) {
196 size_t tagEnd; 196 size_t tagEnd;
197 return_if_false(safe_add(fOffset, fLength, &tagEnd), 197 return_if_false(safe_add(fOffset, fLength, &tagEnd),
198 "Tag too large, overflows integer addition"); 198 "Tag too large, overflows integer addition");
199 return_if_false(tagEnd <= len, "Tag too large for ICC profile"); 199 return_if_false(tagEnd <= len, "Tag too large for ICC profile");
200 return true; 200 return true;
201 } 201 }
(...skipping 19 matching lines...) Expand all
221 static constexpr uint32_t kTAG_gTRC = SkSetFourByteTag('g', 'T', 'R', 'C'); 221 static constexpr uint32_t kTAG_gTRC = SkSetFourByteTag('g', 'T', 'R', 'C');
222 static constexpr uint32_t kTAG_bTRC = SkSetFourByteTag('b', 'T', 'R', 'C'); 222 static constexpr uint32_t kTAG_bTRC = SkSetFourByteTag('b', 'T', 'R', 'C');
223 static constexpr uint32_t kTAG_A2B0 = SkSetFourByteTag('A', '2', 'B', '0'); 223 static constexpr uint32_t kTAG_A2B0 = SkSetFourByteTag('A', '2', 'B', '0');
224 224
225 static bool load_xyz(float dst[3], const uint8_t* src, size_t len) { 225 static bool load_xyz(float dst[3], const uint8_t* src, size_t len) {
226 if (len < 20) { 226 if (len < 20) {
227 SkColorSpacePrintf("XYZ tag is too small (%d bytes)", len); 227 SkColorSpacePrintf("XYZ tag is too small (%d bytes)", len);
228 return false; 228 return false;
229 } 229 }
230 230
231 dst[0] = SkFixedToFloat(read_big_endian_int(src + 8)); 231 dst[0] = SkFixedToFloat(read_big_endian_i32(src + 8));
232 dst[1] = SkFixedToFloat(read_big_endian_int(src + 12)); 232 dst[1] = SkFixedToFloat(read_big_endian_i32(src + 12));
233 dst[2] = SkFixedToFloat(read_big_endian_int(src + 16)); 233 dst[2] = SkFixedToFloat(read_big_endian_i32(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 SkGammas::Type set_gamma_value(SkGammas::Data* data, float value) {
242 if (color_space_almost_equal(2.2f, value)) { 242 if (color_space_almost_equal(2.2f, value)) {
243 data->fNamed = SkColorSpace::k2Dot2Curve_GammaNamed; 243 data->fNamed = SkColorSpace::k2Dot2Curve_GammaNamed;
244 return SkGammas::Type::kNamed_Type; 244 return SkGammas::Type::kNamed_Type;
245 } 245 }
246 246
247 if (color_space_almost_equal(1.0f, value)) { 247 if (color_space_almost_equal(1.0f, value)) {
248 data->fNamed = SkColorSpace::kLinear_GammaNamed; 248 data->fNamed = SkColorSpace::kLinear_GammaNamed;
249 return SkGammas::Type::kNamed_Type; 249 return SkGammas::Type::kNamed_Type;
250 } 250 }
251 251
252 if (color_space_almost_equal(0.0f, value)) { 252 if (color_space_almost_equal(0.0f, value)) {
253 return SkGammas::Type::kNone_Type; 253 return SkGammas::Type::kNone_Type;
254 } 254 }
255 255
256 data->fValue = value; 256 data->fValue = value;
257 return SkGammas::Type::kValue_Type; 257 return SkGammas::Type::kValue_Type;
258 } 258 }
259 259
260 static float read_big_endian_16_dot_16(const uint8_t buf[4]) { 260 static float read_big_endian_16_dot_16(const uint8_t buf[4]) {
261 // It just so happens that SkFixed is also 16.16! 261 // It just so happens that SkFixed is also 16.16!
262 return SkFixedToFloat(read_big_endian_int(buf)); 262 return SkFixedToFloat(read_big_endian_i32(buf));
263 } 263 }
264 264
265 /** 265 /**
266 * @param outData Set to the appropriate value on success. If we have tabl e or 266 * @param outData Set to the appropriate value on success. If we have tabl e or
267 * parametric gamma, it is the responsibility of the caller to set 267 * parametric gamma, it is the responsibility of the caller to set
268 * fOffset. 268 * fOffset.
269 * @param outParams If this is a parametric gamma, this is set to the appropr iate 269 * @param outParams If this is a parametric gamma, this is set to the appropr iate
270 * parameters on success. 270 * parameters on success.
271 * @param outTagBytes Will be set to the length of the tag on success. 271 * @param outTagBytes Will be set to the length of the tag on success.
272 * @src Pointer to tag data. 272 * @src Pointer to tag data.
273 * @len Length of tag data in bytes. 273 * @len Length of tag data in bytes.
274 * 274 *
275 * @return kNone_Type on failure, otherwise the type of the gamma ta g. 275 * @return kNone_Type on failure, otherwise the type of the gamma ta g.
276 */ 276 */
277 static SkGammas::Type parse_gamma(SkGammas::Data* outData, SkGammas::Params* out Params, 277 static SkGammas::Type parse_gamma(SkGammas::Data* outData, SkGammas::Params* out Params,
278 size_t* outTagBytes, const uint8_t* src, s ize_t len) { 278 size_t* outTagBytes, const uint8_t* src, s ize_t len) {
279 if (len < 12) { 279 if (len < 12) {
280 SkColorSpacePrintf("gamma tag is too small (%d bytes)", len); 280 SkColorSpacePrintf("gamma tag is too small (%d bytes)", len);
281 return SkGammas::Type::kNone_Type; 281 return SkGammas::Type::kNone_Type;
282 } 282 }
283 283
284 // In the case of consecutive gamma tags, we need to count the number of byt es in the 284 // In the case of consecutive gamma tags, we need to count the number of byt es in the
285 // tag, so that we can move on to the next tag. 285 // tag, so that we can move on to the next tag.
286 size_t tagBytes; 286 size_t tagBytes;
287 287
288 uint32_t type = read_big_endian_uint(src); 288 uint32_t type = read_big_endian_u32(src);
289 // Bytes 4-7 are reserved and should be set to zero. 289 // Bytes 4-7 are reserved and should be set to zero.
290 switch (type) { 290 switch (type) {
291 case kTAG_CurveType: { 291 case kTAG_CurveType: {
292 uint32_t count = read_big_endian_uint(src + 8); 292 uint32_t count = read_big_endian_u32(src + 8);
293 293
294 // tagBytes = 12 + 2 * count 294 // tagBytes = 12 + 2 * count
295 // We need to do safe addition here to avoid integer overflow. 295 // We need to do safe addition here to avoid integer overflow.
296 if (!safe_add(count, count, &tagBytes) || 296 if (!safe_add(count, count, &tagBytes) ||
297 !safe_add((size_t) 12, tagBytes, &tagBytes)) 297 !safe_add((size_t) 12, tagBytes, &tagBytes))
298 { 298 {
299 SkColorSpacePrintf("Invalid gamma count"); 299 SkColorSpacePrintf("Invalid gamma count");
300 return SkGammas::Type::kNone_Type; 300 return SkGammas::Type::kNone_Type;
301 } 301 }
302 302
303 if (len < tagBytes) { 303 if (len < tagBytes) {
304 SkColorSpacePrintf("gamma tag is too small (%d bytes)", len); 304 SkColorSpacePrintf("gamma tag is too small (%d bytes)", len);
305 return SkGammas::Type::kNone_Type; 305 return SkGammas::Type::kNone_Type;
306 } 306 }
307 *outTagBytes = tagBytes; 307 *outTagBytes = tagBytes;
308 308
309 if (0 == count) { 309 if (0 == count) {
310 // Some tags require a gamma curve, but the author doesn't actua lly want 310 // Some tags require a gamma curve, but the author doesn't actua lly want
311 // to transform the data. In this case, it is common to see a c urve with 311 // to transform the data. In this case, it is common to see a c urve with
312 // a count of 0. 312 // a count of 0.
313 outData->fNamed = SkColorSpace::kLinear_GammaNamed; 313 outData->fNamed = SkColorSpace::kLinear_GammaNamed;
314 return SkGammas::Type::kNamed_Type; 314 return SkGammas::Type::kNamed_Type;
315 } 315 }
316 316
317 const uint16_t* table = (const uint16_t*) (src + 12); 317 const uint16_t* table = (const uint16_t*) (src + 12);
318 if (1 == count) { 318 if (1 == count) {
319 // The table entry is the gamma (with a bias of 256). 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; 320 float value = (read_big_endian_u16((const uint8_t*) table)) / 25 6.0f;
321 SkColorSpacePrintf("gamma %g\n", value); 321 SkColorSpacePrintf("gamma %g\n", value);
322 322
323 return set_gamma_value(outData, value); 323 return set_gamma_value(outData, value);
324 } 324 }
325 325
326 // Check for frequently occurring sRGB curves. 326 // Check for frequently occurring sRGB curves.
327 // We do this by sampling a few values and see if they match our exp ectation. 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 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, 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 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 331 // calculation necessary. We encounter identical gamma curves over and
332 // over again, but relatively few variations. 332 // over again, but relatively few variations.
333 if (1024 == count) { 333 if (1024 == count) {
334 // The magic values were chosen because they match both the very common 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 335 // HP sRGB gamma table and the less common Canon sRGB gamma tabl e (which use
336 // different rounding rules). 336 // different rounding rules).
337 if (0 == read_big_endian_short((const uint8_t*) &table[0]) && 337 if (0 == read_big_endian_u16((const uint8_t*) &table[0]) &&
338 3366 == read_big_endian_short((const uint8_t*) &table[25 7]) && 338 3366 == read_big_endian_u16((const uint8_t*) &table[257] ) &&
339 14116 == read_big_endian_short((const uint8_t*) &table[5 13]) && 339 14116 == read_big_endian_u16((const uint8_t*) &table[513 ]) &&
340 34318 == read_big_endian_short((const uint8_t*) &table[7 68]) && 340 34318 == read_big_endian_u16((const uint8_t*) &table[768 ]) &&
341 65535 == read_big_endian_short((const uint8_t*) &table[1 023])) { 341 65535 == read_big_endian_u16((const uint8_t*) &table[102 3])) {
342 outData->fNamed = SkColorSpace::kSRGB_GammaNamed; 342 outData->fNamed = SkColorSpace::kSRGB_GammaNamed;
343 return SkGammas::Type::kNamed_Type; 343 return SkGammas::Type::kNamed_Type;
344 } 344 }
345 } 345 }
346 346
347 if (26 == count) { 347 if (26 == count) {
348 // The magic values were chosen because they match a very common LCMS sRGB 348 // The magic values were chosen because they match a very common LCMS sRGB
349 // gamma table. 349 // gamma table.
350 if (0 == read_big_endian_short((const uint8_t*) &table[0]) && 350 if (0 == read_big_endian_u16((const uint8_t*) &table[0]) &&
351 3062 == read_big_endian_short((const uint8_t*) &table[6] ) && 351 3062 == read_big_endian_u16((const uint8_t*) &table[6]) &&
352 12824 == read_big_endian_short((const uint8_t*) &table[1 2]) && 352 12824 == read_big_endian_u16((const uint8_t*) &table[12] ) &&
353 31237 == read_big_endian_short((const uint8_t*) &table[1 8]) && 353 31237 == read_big_endian_u16((const uint8_t*) &table[18] ) &&
354 65535 == read_big_endian_short((const uint8_t*) &table[2 5])) { 354 65535 == read_big_endian_u16((const uint8_t*) &table[25] )) {
355 outData->fNamed = SkColorSpace::kSRGB_GammaNamed; 355 outData->fNamed = SkColorSpace::kSRGB_GammaNamed;
356 return SkGammas::Type::kNamed_Type; 356 return SkGammas::Type::kNamed_Type;
357 } 357 }
358 } 358 }
359 359
360 if (4096 == count) { 360 if (4096 == count) {
361 // The magic values were chosen because they match Nikon, Epson, and 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). 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]) && 363 if (0 == read_big_endian_u16((const uint8_t*) &table[0]) &&
364 950 == read_big_endian_short((const uint8_t*) &table[515 ]) && 364 950 == read_big_endian_u16((const uint8_t*) &table[515]) &&
365 3342 == read_big_endian_short((const uint8_t*) &table[10 25]) && 365 3342 == read_big_endian_u16((const uint8_t*) &table[1025 ]) &&
366 14079 == read_big_endian_short((const uint8_t*) &table[2 051]) && 366 14079 == read_big_endian_u16((const uint8_t*) &table[205 1]) &&
367 65535 == read_big_endian_short((const uint8_t*) &table[4 095])) { 367 65535 == read_big_endian_u16((const uint8_t*) &table[409 5])) {
368 outData->fNamed = SkColorSpace::kSRGB_GammaNamed; 368 outData->fNamed = SkColorSpace::kSRGB_GammaNamed;
369 return SkGammas::Type::kNamed_Type; 369 return SkGammas::Type::kNamed_Type;
370 } 370 }
371 } 371 }
372 372
373 // Otherwise, we will represent gamma with a table. 373 // Otherwise, we will represent gamma with a table.
374 outData->fTable.fSize = count; 374 outData->fTable.fSize = count;
375 return SkGammas::Type::kTable_Type; 375 return SkGammas::Type::kTable_Type;
376 } 376 }
377 case kTAG_ParaCurveType: { 377 case kTAG_ParaCurveType: {
378 enum ParaCurveType { 378 enum ParaCurveType {
379 kExponential_ParaCurveType = 0, 379 kExponential_ParaCurveType = 0,
380 kGAB_ParaCurveType = 1, 380 kGAB_ParaCurveType = 1,
381 kGABC_ParaCurveType = 2, 381 kGABC_ParaCurveType = 2,
382 kGABDE_ParaCurveType = 3, 382 kGABDE_ParaCurveType = 3,
383 kGABCDEF_ParaCurveType = 4, 383 kGABCDEF_ParaCurveType = 4,
384 }; 384 };
385 385
386 // Determine the format of the parametric curve tag. 386 // Determine the format of the parametric curve tag.
387 uint16_t format = read_big_endian_short(src + 8); 387 uint16_t format = read_big_endian_u16(src + 8);
388 if (format > kGABCDEF_ParaCurveType) { 388 if (format > kGABCDEF_ParaCurveType) {
389 SkColorSpacePrintf("Unsupported gamma tag type %d\n", type); 389 SkColorSpacePrintf("Unsupported gamma tag type %d\n", type);
390 return SkGammas::Type::kNone_Type; 390 return SkGammas::Type::kNone_Type;
391 } 391 }
392 392
393 if (kExponential_ParaCurveType == format) { 393 if (kExponential_ParaCurveType == format) {
394 tagBytes = 12 + 4; 394 tagBytes = 12 + 4;
395 if (len < tagBytes) { 395 if (len < tagBytes) {
396 SkColorSpacePrintf("gamma tag is too small (%d bytes)", len) ; 396 SkColorSpacePrintf("gamma tag is too small (%d bytes)", len) ;
397 return SkGammas::Type::kNone_Type; 397 return SkGammas::Type::kNone_Type;
(...skipping 192 matching lines...) Expand 10 before | Expand all | Expand 10 after
590 case SkGammas::Type::kNamed_Type: 590 case SkGammas::Type::kNamed_Type:
591 case SkGammas::Type::kValue_Type: 591 case SkGammas::Type::kValue_Type:
592 // Nothing to do here. 592 // Nothing to do here.
593 return 0; 593 return 0;
594 case SkGammas::Type::kTable_Type: { 594 case SkGammas::Type::kTable_Type: {
595 data->fTable.fOffset = offset; 595 data->fTable.fOffset = offset;
596 596
597 float* outTable = (float*) storage; 597 float* outTable = (float*) storage;
598 const uint16_t* inTable = (const uint16_t*) (src + 12); 598 const uint16_t* inTable = (const uint16_t*) (src + 12);
599 for (int i = 0; i < data->fTable.fSize; i++) { 599 for (int i = 0; i < data->fTable.fSize; i++) {
600 outTable[i] = (read_big_endian_short((const uint8_t*) &inTable[i ])) / 65535.0f; 600 outTable[i] = (read_big_endian_u16((const uint8_t*) &inTable[i]) ) / 65535.0f;
601 } 601 }
602 602
603 return sizeof(float) * data->fTable.fSize; 603 return sizeof(float) * data->fTable.fSize;
604 } 604 }
605 case SkGammas::Type::kParam_Type: 605 case SkGammas::Type::kParam_Type:
606 data->fTable.fOffset = offset; 606 data->fTable.fOffset = offset;
607 memcpy(storage, &params, sizeof(SkGammas::Params)); 607 memcpy(storage, &params, sizeof(SkGammas::Params));
608 return sizeof(SkGammas::Params); 608 return sizeof(SkGammas::Params);
609 default: 609 default:
610 SkASSERT(false); 610 SkASSERT(false);
611 return 0; 611 return 0;
612 } 612 }
613 } 613 }
614 614
615 static constexpr uint32_t kTAG_AtoBType = SkSetFourByteTag('m', 'A', 'B', ' '); 615 static constexpr uint32_t kTAG_AtoBType = SkSetFourByteTag('m', 'A', 'B', ' ');
616 616
617 static bool load_color_lut(SkColorLookUpTable* colorLUT, uint32_t inputChannels, 617 static bool load_color_lut(sk_sp<SkColorLookUpTable>* colorLUT, uint32_t inputCh annels,
618 uint32_t outputChannels, const uint8_t* src, size_t l en) { 618 const uint8_t* src, size_t len) {
619 // 16 bytes reserved for grid points, 2 for precision, 2 for padding. 619 // 16 bytes reserved for grid points, 2 for precision, 2 for padding.
620 // The color LUT data follows after this header. 620 // The color LUT data follows after this header.
621 static constexpr uint32_t kColorLUTHeaderSize = 20; 621 static constexpr uint32_t kColorLUTHeaderSize = 20;
622 if (len < kColorLUTHeaderSize) { 622 if (len < kColorLUTHeaderSize) {
623 SkColorSpacePrintf("Color LUT tag is too small (%d bytes).", len); 623 SkColorSpacePrintf("Color LUT tag is too small (%d bytes).", len);
624 return false; 624 return false;
625 } 625 }
626 size_t dataLen = len - kColorLUTHeaderSize; 626 size_t dataLen = len - kColorLUTHeaderSize;
627 627
628 SkASSERT(3 == inputChannels && 3 == outputChannels); 628 SkASSERT(3 == inputChannels);
629 colorLUT->fInputChannels = inputChannels; 629 uint8_t gridPoints[3];
630 colorLUT->fOutputChannels = outputChannels;
631 uint32_t numEntries = 1; 630 uint32_t numEntries = 1;
632 for (uint32_t i = 0; i < inputChannels; i++) { 631 for (uint32_t i = 0; i < inputChannels; i++) {
633 colorLUT->fGridPoints[i] = src[i]; 632 gridPoints[i] = src[i];
634 if (0 == src[i]) { 633 if (0 == src[i]) {
635 SkColorSpacePrintf("Each input channel must have at least one grid p oint."); 634 SkColorSpacePrintf("Each input channel must have at least one grid p oint.");
636 return false; 635 return false;
637 } 636 }
638 637
639 if (!safe_mul(numEntries, src[i], &numEntries)) { 638 if (!safe_mul(numEntries, src[i], &numEntries)) {
640 SkColorSpacePrintf("Too many entries in Color LUT."); 639 SkColorSpacePrintf("Too many entries in Color LUT.");
641 return false; 640 return false;
642 } 641 }
643 } 642 }
644 643
645 if (!safe_mul(numEntries, outputChannels, &numEntries)) { 644 if (!safe_mul(numEntries, SkColorLookUpTable::kOutputChannels, &numEntries)) {
646 SkColorSpacePrintf("Too many entries in Color LUT."); 645 SkColorSpacePrintf("Too many entries in Color LUT.");
647 return false; 646 return false;
648 } 647 }
649 648
650 // Space is provided for a maximum of the 16 input channels. Now we determi ne the precision 649 // Space is provided for a maximum of the 16 input channels. Now we determi ne the precision
651 // of the table values. 650 // of the table values.
652 uint8_t precision = src[16]; 651 uint8_t precision = src[16];
653 switch (precision) { 652 switch (precision) {
654 case 1: // 8-bit data 653 case 1: // 8-bit data
655 case 2: // 16-bit data 654 case 2: // 16-bit data
656 break; 655 break;
657 default: 656 default:
658 SkColorSpacePrintf("Color LUT precision must be 8-bit or 16-bit.\n") ; 657 SkColorSpacePrintf("Color LUT precision must be 8-bit or 16-bit.\n") ;
659 return false; 658 return false;
660 } 659 }
661 660
662 uint32_t clutBytes; 661 uint32_t clutBytes;
663 if (!safe_mul(numEntries, precision, &clutBytes)) { 662 if (!safe_mul(numEntries, precision, &clutBytes)) {
664 SkColorSpacePrintf("Too many entries in Color LUT."); 663 SkColorSpacePrintf("Too many entries in Color LUT.");
665 return false; 664 return false;
666 } 665 }
667 666
668 if (dataLen < clutBytes) { 667 if (dataLen < clutBytes) {
669 SkColorSpacePrintf("Color LUT tag is too small (%d bytes).", len); 668 SkColorSpacePrintf("Color LUT tag is too small (%d bytes).", len);
670 return false; 669 return false;
671 } 670 }
672 671
673 // Movable struct colorLUT has ownership of fTable. 672 // Movable struct colorLUT has ownership of fTable.
674 colorLUT->fTable = std::unique_ptr<float[]>(new float[numEntries]); 673 void* memory = sk_malloc_throw(sizeof(SkColorLookUpTable) + sizeof(float) * numEntries);
674 *colorLUT = sk_sp<SkColorLookUpTable>(new (memory) SkColorLookUpTable(inputC hannels,
675 gridPo ints));
676
677 float* table = SkTAddOffset<float>(memory, sizeof(SkColorLookUpTable));
675 const uint8_t* ptr = src + kColorLUTHeaderSize; 678 const uint8_t* ptr = src + kColorLUTHeaderSize;
676 for (uint32_t i = 0; i < numEntries; i++, ptr += precision) { 679 for (uint32_t i = 0; i < numEntries; i++, ptr += precision) {
677 if (1 == precision) { 680 if (1 == precision) {
678 colorLUT->fTable[i] = ((float) ptr[i]) / 255.0f; 681 table[i] = ((float) ptr[i]) / 255.0f;
679 } else { 682 } else {
680 colorLUT->fTable[i] = ((float) read_big_endian_short(ptr)) / 65535.0 f; 683 table[i] = ((float) read_big_endian_u16(ptr)) / 65535.0f;
681 } 684 }
682 } 685 }
683 686
684 return true; 687 return true;
685 } 688 }
686 689
687 static bool load_matrix(SkMatrix44* toXYZ, const uint8_t* src, size_t len) { 690 static bool load_matrix(SkMatrix44* toXYZ, const uint8_t* src, size_t len) {
688 if (len < 48) { 691 if (len < 48) {
689 SkColorSpacePrintf("Matrix tag is too small (%d bytes).", len); 692 SkColorSpacePrintf("Matrix tag is too small (%d bytes).", len);
690 return false; 693 return false;
691 } 694 }
692 695
693 // For this matrix to behave like our "to XYZ D50" matrices, it needs to be scaled. 696 // For this matrix to behave like our "to XYZ D50" matrices, it needs to be scaled.
694 constexpr float scale = 65535.0 / 32768.0; 697 constexpr float scale = 65535.0 / 32768.0;
695 float array[16]; 698 float array[16];
696 array[ 0] = scale * SkFixedToFloat(read_big_endian_int(src)); 699 array[ 0] = scale * SkFixedToFloat(read_big_endian_i32(src));
697 array[ 1] = scale * SkFixedToFloat(read_big_endian_int(src + 4)); 700 array[ 1] = scale * SkFixedToFloat(read_big_endian_i32(src + 4));
698 array[ 2] = scale * SkFixedToFloat(read_big_endian_int(src + 8)); 701 array[ 2] = scale * SkFixedToFloat(read_big_endian_i32(src + 8));
699 array[ 3] = scale * SkFixedToFloat(read_big_endian_int(src + 36)); // transl ate R 702 array[ 3] = scale * SkFixedToFloat(read_big_endian_i32(src + 36)); // transl ate R
700 array[ 4] = scale * SkFixedToFloat(read_big_endian_int(src + 12)); 703 array[ 4] = scale * SkFixedToFloat(read_big_endian_i32(src + 12));
701 array[ 5] = scale * SkFixedToFloat(read_big_endian_int(src + 16)); 704 array[ 5] = scale * SkFixedToFloat(read_big_endian_i32(src + 16));
702 array[ 6] = scale * SkFixedToFloat(read_big_endian_int(src + 20)); 705 array[ 6] = scale * SkFixedToFloat(read_big_endian_i32(src + 20));
703 array[ 7] = scale * SkFixedToFloat(read_big_endian_int(src + 40)); // transl ate G 706 array[ 7] = scale * SkFixedToFloat(read_big_endian_i32(src + 40)); // transl ate G
704 array[ 8] = scale * SkFixedToFloat(read_big_endian_int(src + 24)); 707 array[ 8] = scale * SkFixedToFloat(read_big_endian_i32(src + 24));
705 array[ 9] = scale * SkFixedToFloat(read_big_endian_int(src + 28)); 708 array[ 9] = scale * SkFixedToFloat(read_big_endian_i32(src + 28));
706 array[10] = scale * SkFixedToFloat(read_big_endian_int(src + 32)); 709 array[10] = scale * SkFixedToFloat(read_big_endian_i32(src + 32));
707 array[11] = scale * SkFixedToFloat(read_big_endian_int(src + 44)); // transl ate B 710 array[11] = scale * SkFixedToFloat(read_big_endian_i32(src + 44)); // transl ate B
708 array[12] = 0.0f; 711 array[12] = 0.0f;
709 array[13] = 0.0f; 712 array[13] = 0.0f;
710 array[14] = 0.0f; 713 array[14] = 0.0f;
711 array[15] = 1.0f; 714 array[15] = 1.0f;
712 toXYZ->setColMajorf(array); 715 toXYZ->setColMajorf(array);
713 return true; 716 return true;
714 } 717 }
715 718
716 static bool load_a2b0(SkColorLookUpTable* colorLUT, SkColorSpace::GammaNamed* ga mmaNamed, 719 static bool load_a2b0(sk_sp<SkColorLookUpTable>* colorLUT, SkColorSpace::GammaNa med* gammaNamed,
717 sk_sp<SkGammas>* gammas, SkMatrix44* toXYZ, const uint8_t* src, size_t len) { 720 sk_sp<SkGammas>* gammas, SkMatrix44* toXYZ, const uint8_t* src, size_t len) {
718 if (len < 32) { 721 if (len < 32) {
719 SkColorSpacePrintf("A to B tag is too small (%d bytes).", len); 722 SkColorSpacePrintf("A to B tag is too small (%d bytes).", len);
720 return false; 723 return false;
721 } 724 }
722 725
723 uint32_t type = read_big_endian_uint(src); 726 uint32_t type = read_big_endian_u32(src);
724 if (kTAG_AtoBType != type) { 727 if (kTAG_AtoBType != type) {
725 // FIXME (msarett): Need to support lut8Type and lut16Type. 728 // FIXME (msarett): Need to support lut8Type and lut16Type.
726 SkColorSpacePrintf("Unsupported A to B tag type.\n"); 729 SkColorSpacePrintf("Unsupported A to B tag type.\n");
727 return false; 730 return false;
728 } 731 }
729 732
730 // Read the number of channels. The four bytes that we skipped are reserved and 733 // Read the number of channels. The four bytes that we skipped are reserved and
731 // must be zero. 734 // must be zero.
732 uint8_t inputChannels = src[8]; 735 uint8_t inputChannels = src[8];
733 uint8_t outputChannels = src[9]; 736 uint8_t outputChannels = src[9];
734 if (3 != inputChannels || 3 != outputChannels) { 737 if (3 != inputChannels || SkColorLookUpTable::kOutputChannels != outputChann els) {
735 // We only handle (supposedly) RGB inputs and RGB outputs. The numbers of input 738 // We only handle (supposedly) RGB inputs and RGB outputs. The numbers of input
736 // channels and output channels both must be 3. 739 // channels and output channels both must be 3.
740 // TODO (msarett):
741 // Support different numbers of input channels. Ex: CMYK (4).
737 SkColorSpacePrintf("Input and output channels must equal 3 in A to B tag .\n"); 742 SkColorSpacePrintf("Input and output channels must equal 3 in A to B tag .\n");
738 return false; 743 return false;
739 } 744 }
740 745
741 // Read the offsets of each element in the A to B tag. With the exception o f A curves and 746 // Read the offsets of each element in the A to B tag. With the exception o f A curves and
742 // B curves (which we do not yet support), we will handle these elements in the order in 747 // B curves (which we do not yet support), we will handle these elements in the order in
743 // which they should be applied (rather than the order in which they occur i n the tag). 748 // which they should be applied (rather than the order in which they occur i n the tag).
744 // If the offset is non-zero it indicates that the element is present. 749 // If the offset is non-zero it indicates that the element is present.
745 uint32_t offsetToACurves = read_big_endian_int(src + 28); 750 uint32_t offsetToACurves = read_big_endian_i32(src + 28);
746 uint32_t offsetToBCurves = read_big_endian_int(src + 12); 751 uint32_t offsetToBCurves = read_big_endian_i32(src + 12);
747 if ((0 != offsetToACurves) || (0 != offsetToBCurves)) { 752 if ((0 != offsetToACurves) || (0 != offsetToBCurves)) {
748 // FIXME (msarett): Handle A and B curves. 753 // FIXME (msarett): Handle A and B curves.
749 // Note that the A curve is technically required in order to have a colo r LUT. 754 // Note that the A curve is technically required in order to have a colo r LUT.
750 // However, all the A curves I have seen so far have are just placeholde rs that 755 // However, all the A curves I have seen so far have are just placeholde rs that
751 // don't actually transform the data. 756 // don't actually transform the data.
752 SkColorSpacePrintf("Ignoring A and/or B curve. Output may be wrong.\n") ; 757 SkColorSpacePrintf("Ignoring A and/or B curve. Output may be wrong.\n") ;
753 } 758 }
754 759
755 uint32_t offsetToColorLUT = read_big_endian_int(src + 24); 760 uint32_t offsetToColorLUT = read_big_endian_i32(src + 24);
756 if (0 != offsetToColorLUT && offsetToColorLUT < len) { 761 if (0 != offsetToColorLUT && offsetToColorLUT < len) {
757 if (!load_color_lut(colorLUT, inputChannels, outputChannels, src + offse tToColorLUT, 762 if (!load_color_lut(colorLUT, inputChannels, src + offsetToColorLUT,
758 len - offsetToColorLUT)) { 763 len - offsetToColorLUT)) {
759 SkColorSpacePrintf("Failed to read color LUT from A to B tag.\n"); 764 SkColorSpacePrintf("Failed to read color LUT from A to B tag.\n");
760 } 765 }
761 } 766 }
762 767
763 uint32_t offsetToMCurves = read_big_endian_int(src + 20); 768 uint32_t offsetToMCurves = read_big_endian_i32(src + 20);
764 if (0 != offsetToMCurves && offsetToMCurves < len) { 769 if (0 != offsetToMCurves && offsetToMCurves < len) {
765 const uint8_t* rTagPtr = src + offsetToMCurves; 770 const uint8_t* rTagPtr = src + offsetToMCurves;
766 size_t tagLen = len - offsetToMCurves; 771 size_t tagLen = len - offsetToMCurves;
767 772
768 SkGammas::Data rData; 773 SkGammas::Data rData;
769 SkGammas::Params rParams; 774 SkGammas::Params rParams;
770 775
771 // On an invalid first gamma, tagBytes remains set as zero. This causes the two 776 // 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). 777 // subsequent to be treated as identical (which is what we want).
773 size_t tagBytes = 0; 778 size_t tagBytes = 0;
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
829 834
830 (*gammas)->fBlueType = bType; 835 (*gammas)->fBlueType = bType;
831 load_gammas(memory, offset, bType, &bData, bParams, bTagPtr); 836 load_gammas(memory, offset, bType, &bData, bParams, bTagPtr);
832 837
833 (*gammas)->fRedData = rData; 838 (*gammas)->fRedData = rData;
834 (*gammas)->fGreenData = gData; 839 (*gammas)->fGreenData = gData;
835 (*gammas)->fBlueData = bData; 840 (*gammas)->fBlueData = bData;
836 } 841 }
837 } 842 }
838 843
839 uint32_t offsetToMatrix = read_big_endian_int(src + 16); 844 uint32_t offsetToMatrix = read_big_endian_i32(src + 16);
840 if (0 != offsetToMatrix && offsetToMatrix < len) { 845 if (0 != offsetToMatrix && offsetToMatrix < len) {
841 if (!load_matrix(toXYZ, src + offsetToMatrix, len - offsetToMatrix)) { 846 if (!load_matrix(toXYZ, src + offsetToMatrix, len - offsetToMatrix)) {
842 SkColorSpacePrintf("Failed to read matrix from A to B tag.\n"); 847 SkColorSpacePrintf("Failed to read matrix from A to B tag.\n");
843 toXYZ->setIdentity(); 848 toXYZ->setIdentity();
844 } 849 }
845 } 850 }
846 851
847 return true; 852 return true;
848 } 853 }
849 854
(...skipping 178 matching lines...) Expand 10 before | Expand all | Expand 10 after
1028 } else { 1033 } else {
1029 return SkColorSpace_Base::NewRGB(gammaNamed, mat); 1034 return SkColorSpace_Base::NewRGB(gammaNamed, mat);
1030 } 1035 }
1031 } 1036 }
1032 1037
1033 // Recognize color profile specified by A2B0 tag. 1038 // Recognize color profile specified by A2B0 tag.
1034 const ICCTag* a2b0 = ICCTag::Find(tags.get(), tagCount, kTAG_A2B0); 1039 const ICCTag* a2b0 = ICCTag::Find(tags.get(), tagCount, kTAG_A2B0);
1035 if (a2b0) { 1040 if (a2b0) {
1036 GammaNamed gammaNamed = kNonStandard_GammaNamed; 1041 GammaNamed gammaNamed = kNonStandard_GammaNamed;
1037 sk_sp<SkGammas> gammas = nullptr; 1042 sk_sp<SkGammas> gammas = nullptr;
1038 sk_sp<SkColorLookUpTable> colorLUT = sk_make_sp<SkColorLookUpTab le>(); 1043 sk_sp<SkColorLookUpTable> colorLUT = nullptr;
1039 SkMatrix44 toXYZ(SkMatrix44::kUninitialized_Constructor); 1044 SkMatrix44 toXYZ(SkMatrix44::kUninitialized_Constructor);
1040 if (!load_a2b0(colorLUT.get(), &gammaNamed, &gammas, &toXYZ, a2b 0->addr(base), 1045 if (!load_a2b0(&colorLUT, &gammaNamed, &gammas, &toXYZ, a2b0->ad dr(base),
1041 a2b0->fLength)) { 1046 a2b0->fLength)) {
1042 return_null("Failed to parse A2B0 tag"); 1047 return_null("Failed to parse A2B0 tag");
1043 } 1048 }
1044 1049
1045 colorLUT = colorLUT->fTable ? colorLUT : nullptr;
1046 if (colorLUT || kNonStandard_GammaNamed == gammaNamed) { 1050 if (colorLUT || kNonStandard_GammaNamed == gammaNamed) {
1047 return sk_sp<SkColorSpace>(new SkColorSpace_Base(std::move(c olorLUT), 1051 return sk_sp<SkColorSpace>(new SkColorSpace_Base(std::move(c olorLUT),
1048 gammaNamed, std::move(gammas), 1052 gammaNamed, std::move(gammas),
1049 toXYZ, std: :move(data))); 1053 toXYZ, std: :move(data)));
1050 } else { 1054 } else {
1051 return SkColorSpace_Base::NewRGB(gammaNamed, toXYZ); 1055 return SkColorSpace_Base::NewRGB(gammaNamed, toXYZ);
1052 } 1056 }
1053 } 1057 }
1054 } 1058 }
1055 default: 1059 default:
(...skipping 223 matching lines...) Expand 10 before | Expand all | Expand 10 after
1279 ptr32[4] = SkEndian_SwapBE32(0x000116cc); 1283 ptr32[4] = SkEndian_SwapBE32(0x000116cc);
1280 ptr += kTAG_XYZ_Bytes; 1284 ptr += kTAG_XYZ_Bytes;
1281 1285
1282 // Write copyright tag 1286 // Write copyright tag
1283 memcpy(ptr, gEmptyTextTag, sizeof(gEmptyTextTag)); 1287 memcpy(ptr, gEmptyTextTag, sizeof(gEmptyTextTag));
1284 1288
1285 // TODO (msarett): Should we try to hold onto the data so we can return imme diately if 1289 // TODO (msarett): Should we try to hold onto the data so we can return imme diately if
1286 // the client calls again? 1290 // the client calls again?
1287 return SkData::MakeFromMalloc(profile.release(), kICCProfileSize); 1291 return SkData::MakeFromMalloc(profile.release(), kICCProfileSize);
1288 } 1292 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698