diff options
author | msarett <msarett@google.com> | 2016-07-21 13:19:03 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2016-07-21 13:19:04 -0700 |
commit | 959d45b43357a40854938586c303177c6aa53220 (patch) | |
tree | dd94f8f9daf6c408deb66ca885c7d872635f064d /src/core/SkColorSpace_ICC.cpp | |
parent | 4eaa320d5718d6b4ba45341c2f2e5206660fdf94 (diff) |
Miscellaneous color space refactors
(1) Use float matrix[16] everywhere (enables future code
sharing).
(2) SkColorLookUpTable refactors
*** Store in a single allocation (like SkGammas)
*** Eliminate fOutputChannels (we always require 3,
and probably always will)
(3) Change names of read_big_endian_* helpers
BUG=skia:
GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2166093003
CQ_INCLUDE_TRYBOTS=master.client.skia:Test-Ubuntu-GCC-GCE-CPU-AVX2-x86_64-Release-SKNX_NO_SIMD-Trybot
Review-Url: https://codereview.chromium.org/2166093003
Diffstat (limited to 'src/core/SkColorSpace_ICC.cpp')
-rw-r--r-- | src/core/SkColorSpace_ICC.cpp | 136 |
1 files changed, 70 insertions, 66 deletions
diff --git a/src/core/SkColorSpace_ICC.cpp b/src/core/SkColorSpace_ICC.cpp index 710558286c..cbb974f1f1 100644 --- a/src/core/SkColorSpace_ICC.cpp +++ b/src/core/SkColorSpace_ICC.cpp @@ -26,16 +26,16 @@ return nullptr; \ } while (0) -static uint16_t read_big_endian_short(const uint8_t* ptr) { +static uint16_t read_big_endian_u16(const uint8_t* ptr) { return ptr[0] << 8 | ptr[1]; } -static uint32_t read_big_endian_uint(const uint8_t* ptr) { +static uint32_t read_big_endian_u32(const uint8_t* ptr) { return ptr[0] << 24 | ptr[1] << 16 | ptr[2] << 8 | ptr[3]; } -static int32_t read_big_endian_int(const uint8_t* ptr) { - return (int32_t) read_big_endian_uint(ptr); +static int32_t read_big_endian_i32(const uint8_t* ptr) { + return (int32_t) read_big_endian_u32(ptr); } // This is equal to the header size according to the ICC specification (128) @@ -105,7 +105,7 @@ struct ICCProfileHeader { uint32_t* dst = (uint32_t*) this; for (uint32_t i = 0; i < kICCHeaderSize / 4; i++, src+=4) { - dst[i] = read_big_endian_uint(src); + dst[i] = read_big_endian_u32(src); } } @@ -186,9 +186,9 @@ struct ICCTag { uint32_t fLength; const uint8_t* init(const uint8_t* src) { - fSignature = read_big_endian_uint(src); - fOffset = read_big_endian_uint(src + 4); - fLength = read_big_endian_uint(src + 8); + fSignature = read_big_endian_u32(src); + fOffset = read_big_endian_u32(src + 4); + fLength = read_big_endian_u32(src + 8); return src + 12; } @@ -228,9 +228,9 @@ static bool load_xyz(float dst[3], const uint8_t* src, size_t len) { return false; } - dst[0] = SkFixedToFloat(read_big_endian_int(src + 8)); - dst[1] = SkFixedToFloat(read_big_endian_int(src + 12)); - dst[2] = SkFixedToFloat(read_big_endian_int(src + 16)); + dst[0] = SkFixedToFloat(read_big_endian_i32(src + 8)); + dst[1] = SkFixedToFloat(read_big_endian_i32(src + 12)); + dst[2] = SkFixedToFloat(read_big_endian_i32(src + 16)); SkColorSpacePrintf("XYZ %g %g %g\n", dst[0], dst[1], dst[2]); return true; } @@ -259,7 +259,7 @@ static SkGammas::Type set_gamma_value(SkGammas::Data* data, float value) { static float read_big_endian_16_dot_16(const uint8_t buf[4]) { // It just so happens that SkFixed is also 16.16! - return SkFixedToFloat(read_big_endian_int(buf)); + return SkFixedToFloat(read_big_endian_i32(buf)); } /** @@ -285,11 +285,11 @@ static SkGammas::Type parse_gamma(SkGammas::Data* outData, SkGammas::Params* out // tag, so that we can move on to the next tag. size_t tagBytes; - uint32_t type = read_big_endian_uint(src); + uint32_t type = read_big_endian_u32(src); // Bytes 4-7 are reserved and should be set to zero. switch (type) { case kTAG_CurveType: { - uint32_t count = read_big_endian_uint(src + 8); + uint32_t count = read_big_endian_u32(src + 8); // tagBytes = 12 + 2 * count // We need to do safe addition here to avoid integer overflow. @@ -317,7 +317,7 @@ static SkGammas::Type parse_gamma(SkGammas::Data* outData, SkGammas::Params* out const uint16_t* table = (const uint16_t*) (src + 12); if (1 == count) { // The table entry is the gamma (with a bias of 256). - float value = (read_big_endian_short((const uint8_t*) table)) / 256.0f; + float value = (read_big_endian_u16((const uint8_t*) table)) / 256.0f; SkColorSpacePrintf("gamma %g\n", value); return set_gamma_value(outData, value); @@ -334,11 +334,11 @@ static SkGammas::Type parse_gamma(SkGammas::Data* outData, SkGammas::Params* out // The magic values were chosen because they match both the very common // HP sRGB gamma table and the less common Canon sRGB gamma table (which use // different rounding rules). - if (0 == read_big_endian_short((const uint8_t*) &table[0]) && - 3366 == read_big_endian_short((const uint8_t*) &table[257]) && - 14116 == read_big_endian_short((const uint8_t*) &table[513]) && - 34318 == read_big_endian_short((const uint8_t*) &table[768]) && - 65535 == read_big_endian_short((const uint8_t*) &table[1023])) { + if (0 == read_big_endian_u16((const uint8_t*) &table[0]) && + 3366 == read_big_endian_u16((const uint8_t*) &table[257]) && + 14116 == read_big_endian_u16((const uint8_t*) &table[513]) && + 34318 == read_big_endian_u16((const uint8_t*) &table[768]) && + 65535 == read_big_endian_u16((const uint8_t*) &table[1023])) { outData->fNamed = SkColorSpace::kSRGB_GammaNamed; return SkGammas::Type::kNamed_Type; } @@ -347,11 +347,11 @@ static SkGammas::Type parse_gamma(SkGammas::Data* outData, SkGammas::Params* out if (26 == count) { // The magic values were chosen because they match a very common LCMS sRGB // gamma table. - if (0 == read_big_endian_short((const uint8_t*) &table[0]) && - 3062 == read_big_endian_short((const uint8_t*) &table[6]) && - 12824 == read_big_endian_short((const uint8_t*) &table[12]) && - 31237 == read_big_endian_short((const uint8_t*) &table[18]) && - 65535 == read_big_endian_short((const uint8_t*) &table[25])) { + if (0 == read_big_endian_u16((const uint8_t*) &table[0]) && + 3062 == read_big_endian_u16((const uint8_t*) &table[6]) && + 12824 == read_big_endian_u16((const uint8_t*) &table[12]) && + 31237 == read_big_endian_u16((const uint8_t*) &table[18]) && + 65535 == read_big_endian_u16((const uint8_t*) &table[25])) { outData->fNamed = SkColorSpace::kSRGB_GammaNamed; return SkGammas::Type::kNamed_Type; } @@ -360,11 +360,11 @@ static SkGammas::Type parse_gamma(SkGammas::Data* outData, SkGammas::Params* out if (4096 == count) { // The magic values were chosen because they match Nikon, Epson, and // LCMS sRGB gamma tables (all of which use different rounding rules). - if (0 == read_big_endian_short((const uint8_t*) &table[0]) && - 950 == read_big_endian_short((const uint8_t*) &table[515]) && - 3342 == read_big_endian_short((const uint8_t*) &table[1025]) && - 14079 == read_big_endian_short((const uint8_t*) &table[2051]) && - 65535 == read_big_endian_short((const uint8_t*) &table[4095])) { + if (0 == read_big_endian_u16((const uint8_t*) &table[0]) && + 950 == read_big_endian_u16((const uint8_t*) &table[515]) && + 3342 == read_big_endian_u16((const uint8_t*) &table[1025]) && + 14079 == read_big_endian_u16((const uint8_t*) &table[2051]) && + 65535 == read_big_endian_u16((const uint8_t*) &table[4095])) { outData->fNamed = SkColorSpace::kSRGB_GammaNamed; return SkGammas::Type::kNamed_Type; } @@ -384,7 +384,7 @@ static SkGammas::Type parse_gamma(SkGammas::Data* outData, SkGammas::Params* out }; // Determine the format of the parametric curve tag. - uint16_t format = read_big_endian_short(src + 8); + uint16_t format = read_big_endian_u16(src + 8); if (format > kGABCDEF_ParaCurveType) { SkColorSpacePrintf("Unsupported gamma tag type %d\n", type); return SkGammas::Type::kNone_Type; @@ -597,7 +597,7 @@ static size_t load_gammas(void* memory, size_t offset, SkGammas::Type type, float* outTable = (float*) storage; const uint16_t* inTable = (const uint16_t*) (src + 12); for (int i = 0; i < data->fTable.fSize; i++) { - outTable[i] = (read_big_endian_short((const uint8_t*) &inTable[i])) / 65535.0f; + outTable[i] = (read_big_endian_u16((const uint8_t*) &inTable[i])) / 65535.0f; } return sizeof(float) * data->fTable.fSize; @@ -614,8 +614,8 @@ static size_t load_gammas(void* memory, size_t offset, SkGammas::Type type, static constexpr uint32_t kTAG_AtoBType = SkSetFourByteTag('m', 'A', 'B', ' '); -static bool load_color_lut(SkColorLookUpTable* colorLUT, uint32_t inputChannels, - uint32_t outputChannels, const uint8_t* src, size_t len) { +static bool load_color_lut(sk_sp<SkColorLookUpTable>* colorLUT, uint32_t inputChannels, + const uint8_t* src, size_t len) { // 16 bytes reserved for grid points, 2 for precision, 2 for padding. // The color LUT data follows after this header. static constexpr uint32_t kColorLUTHeaderSize = 20; @@ -625,12 +625,11 @@ static bool load_color_lut(SkColorLookUpTable* colorLUT, uint32_t inputChannels, } size_t dataLen = len - kColorLUTHeaderSize; - SkASSERT(3 == inputChannels && 3 == outputChannels); - colorLUT->fInputChannels = inputChannels; - colorLUT->fOutputChannels = outputChannels; + SkASSERT(3 == inputChannels); + uint8_t gridPoints[3]; uint32_t numEntries = 1; for (uint32_t i = 0; i < inputChannels; i++) { - colorLUT->fGridPoints[i] = src[i]; + gridPoints[i] = src[i]; if (0 == src[i]) { SkColorSpacePrintf("Each input channel must have at least one grid point."); return false; @@ -642,7 +641,7 @@ static bool load_color_lut(SkColorLookUpTable* colorLUT, uint32_t inputChannels, } } - if (!safe_mul(numEntries, outputChannels, &numEntries)) { + if (!safe_mul(numEntries, SkColorLookUpTable::kOutputChannels, &numEntries)) { SkColorSpacePrintf("Too many entries in Color LUT."); return false; } @@ -671,13 +670,17 @@ static bool load_color_lut(SkColorLookUpTable* colorLUT, uint32_t inputChannels, } // Movable struct colorLUT has ownership of fTable. - colorLUT->fTable = std::unique_ptr<float[]>(new float[numEntries]); + void* memory = sk_malloc_throw(sizeof(SkColorLookUpTable) + sizeof(float) * numEntries); + *colorLUT = sk_sp<SkColorLookUpTable>(new (memory) SkColorLookUpTable(inputChannels, + gridPoints)); + + float* table = SkTAddOffset<float>(memory, sizeof(SkColorLookUpTable)); const uint8_t* ptr = src + kColorLUTHeaderSize; for (uint32_t i = 0; i < numEntries; i++, ptr += precision) { if (1 == precision) { - colorLUT->fTable[i] = ((float) ptr[i]) / 255.0f; + table[i] = ((float) ptr[i]) / 255.0f; } else { - colorLUT->fTable[i] = ((float) read_big_endian_short(ptr)) / 65535.0f; + table[i] = ((float) read_big_endian_u16(ptr)) / 65535.0f; } } @@ -693,18 +696,18 @@ static bool load_matrix(SkMatrix44* toXYZ, const uint8_t* src, size_t len) { // For this matrix to behave like our "to XYZ D50" matrices, it needs to be scaled. constexpr float scale = 65535.0 / 32768.0; float array[16]; - array[ 0] = scale * SkFixedToFloat(read_big_endian_int(src)); - array[ 1] = scale * SkFixedToFloat(read_big_endian_int(src + 4)); - array[ 2] = scale * SkFixedToFloat(read_big_endian_int(src + 8)); - array[ 3] = scale * SkFixedToFloat(read_big_endian_int(src + 36)); // translate R - array[ 4] = scale * SkFixedToFloat(read_big_endian_int(src + 12)); - array[ 5] = scale * SkFixedToFloat(read_big_endian_int(src + 16)); - array[ 6] = scale * SkFixedToFloat(read_big_endian_int(src + 20)); - array[ 7] = scale * SkFixedToFloat(read_big_endian_int(src + 40)); // translate G - array[ 8] = scale * SkFixedToFloat(read_big_endian_int(src + 24)); - array[ 9] = scale * SkFixedToFloat(read_big_endian_int(src + 28)); - array[10] = scale * SkFixedToFloat(read_big_endian_int(src + 32)); - array[11] = scale * SkFixedToFloat(read_big_endian_int(src + 44)); // translate B + array[ 0] = scale * SkFixedToFloat(read_big_endian_i32(src)); + array[ 1] = scale * SkFixedToFloat(read_big_endian_i32(src + 4)); + array[ 2] = scale * SkFixedToFloat(read_big_endian_i32(src + 8)); + array[ 3] = scale * SkFixedToFloat(read_big_endian_i32(src + 36)); // translate R + array[ 4] = scale * SkFixedToFloat(read_big_endian_i32(src + 12)); + array[ 5] = scale * SkFixedToFloat(read_big_endian_i32(src + 16)); + array[ 6] = scale * SkFixedToFloat(read_big_endian_i32(src + 20)); + array[ 7] = scale * SkFixedToFloat(read_big_endian_i32(src + 40)); // translate G + array[ 8] = scale * SkFixedToFloat(read_big_endian_i32(src + 24)); + array[ 9] = scale * SkFixedToFloat(read_big_endian_i32(src + 28)); + array[10] = scale * SkFixedToFloat(read_big_endian_i32(src + 32)); + array[11] = scale * SkFixedToFloat(read_big_endian_i32(src + 44)); // translate B array[12] = 0.0f; array[13] = 0.0f; array[14] = 0.0f; @@ -713,14 +716,14 @@ static bool load_matrix(SkMatrix44* toXYZ, const uint8_t* src, size_t len) { return true; } -static bool load_a2b0(SkColorLookUpTable* colorLUT, SkColorSpace::GammaNamed* gammaNamed, +static bool load_a2b0(sk_sp<SkColorLookUpTable>* colorLUT, SkColorSpace::GammaNamed* gammaNamed, sk_sp<SkGammas>* gammas, SkMatrix44* toXYZ, const uint8_t* src, size_t len) { if (len < 32) { SkColorSpacePrintf("A to B tag is too small (%d bytes).", len); return false; } - uint32_t type = read_big_endian_uint(src); + uint32_t type = read_big_endian_u32(src); if (kTAG_AtoBType != type) { // FIXME (msarett): Need to support lut8Type and lut16Type. SkColorSpacePrintf("Unsupported A to B tag type.\n"); @@ -731,9 +734,11 @@ static bool load_a2b0(SkColorLookUpTable* colorLUT, SkColorSpace::GammaNamed* ga // must be zero. uint8_t inputChannels = src[8]; uint8_t outputChannels = src[9]; - if (3 != inputChannels || 3 != outputChannels) { + if (3 != inputChannels || SkColorLookUpTable::kOutputChannels != outputChannels) { // We only handle (supposedly) RGB inputs and RGB outputs. The numbers of input // channels and output channels both must be 3. + // TODO (msarett): + // Support different numbers of input channels. Ex: CMYK (4). SkColorSpacePrintf("Input and output channels must equal 3 in A to B tag.\n"); return false; } @@ -742,8 +747,8 @@ static bool load_a2b0(SkColorLookUpTable* colorLUT, SkColorSpace::GammaNamed* ga // B curves (which we do not yet support), we will handle these elements in the order in // which they should be applied (rather than the order in which they occur in the tag). // If the offset is non-zero it indicates that the element is present. - uint32_t offsetToACurves = read_big_endian_int(src + 28); - uint32_t offsetToBCurves = read_big_endian_int(src + 12); + uint32_t offsetToACurves = read_big_endian_i32(src + 28); + uint32_t offsetToBCurves = read_big_endian_i32(src + 12); if ((0 != offsetToACurves) || (0 != offsetToBCurves)) { // FIXME (msarett): Handle A and B curves. // Note that the A curve is technically required in order to have a color LUT. @@ -752,15 +757,15 @@ static bool load_a2b0(SkColorLookUpTable* colorLUT, SkColorSpace::GammaNamed* ga SkColorSpacePrintf("Ignoring A and/or B curve. Output may be wrong.\n"); } - uint32_t offsetToColorLUT = read_big_endian_int(src + 24); + uint32_t offsetToColorLUT = read_big_endian_i32(src + 24); if (0 != offsetToColorLUT && offsetToColorLUT < len) { - if (!load_color_lut(colorLUT, inputChannels, outputChannels, src + offsetToColorLUT, + if (!load_color_lut(colorLUT, inputChannels, src + offsetToColorLUT, len - offsetToColorLUT)) { SkColorSpacePrintf("Failed to read color LUT from A to B tag.\n"); } } - uint32_t offsetToMCurves = read_big_endian_int(src + 20); + uint32_t offsetToMCurves = read_big_endian_i32(src + 20); if (0 != offsetToMCurves && offsetToMCurves < len) { const uint8_t* rTagPtr = src + offsetToMCurves; size_t tagLen = len - offsetToMCurves; @@ -836,7 +841,7 @@ static bool load_a2b0(SkColorLookUpTable* colorLUT, SkColorSpace::GammaNamed* ga } } - uint32_t offsetToMatrix = read_big_endian_int(src + 16); + uint32_t offsetToMatrix = read_big_endian_i32(src + 16); if (0 != offsetToMatrix && offsetToMatrix < len) { if (!load_matrix(toXYZ, src + offsetToMatrix, len - offsetToMatrix)) { SkColorSpacePrintf("Failed to read matrix from A to B tag.\n"); @@ -1035,14 +1040,13 @@ sk_sp<SkColorSpace> SkColorSpace::NewICC(const void* input, size_t len) { if (a2b0) { GammaNamed gammaNamed = kNonStandard_GammaNamed; sk_sp<SkGammas> gammas = nullptr; - sk_sp<SkColorLookUpTable> colorLUT = sk_make_sp<SkColorLookUpTable>(); + sk_sp<SkColorLookUpTable> colorLUT = nullptr; SkMatrix44 toXYZ(SkMatrix44::kUninitialized_Constructor); - if (!load_a2b0(colorLUT.get(), &gammaNamed, &gammas, &toXYZ, a2b0->addr(base), + if (!load_a2b0(&colorLUT, &gammaNamed, &gammas, &toXYZ, a2b0->addr(base), a2b0->fLength)) { return_null("Failed to parse A2B0 tag"); } - colorLUT = colorLUT->fTable ? colorLUT : nullptr; if (colorLUT || kNonStandard_GammaNamed == gammaNamed) { return sk_sp<SkColorSpace>(new SkColorSpace_Base(std::move(colorLUT), gammaNamed, std::move(gammas), |