From 5476128f0a88217414f05e6a7ee518cdb411d026 Mon Sep 17 00:00:00 2001 From: raftias Date: Thu, 1 Dec 2016 13:44:07 -0500 Subject: Added CMYK support for ICC profiles. Changed ICC parsing/SkGammas/SkColorLookUpTable to handle non-3-channel inputs. Parsed CMYK A2B ICC profiles. Integrated this with SkJpegCodec (the only file that supports CMYK) and SkColorSpaceXform_A2B to allow parsing and color xforming of ICC CMYK images. CQ_INCLUDE_TRYBOTS=skia.primary:Test-Ubuntu-GCC-GCE-CPU-AVX2-x86_64-Release-SKNX_NO_SIMD Change-Id: I11e3d17180244281be3eb43fd608609925a7f71e Reviewed-on: https://skia-review.googlesource.com/5444 Reviewed-by: Matt Sarett Commit-Queue: Matt Sarett --- src/core/SkColorSpaceXform_A2B.cpp | 81 ++++++++++++++++++++++++-------------- 1 file changed, 51 insertions(+), 30 deletions(-) (limited to 'src/core/SkColorSpaceXform_A2B.cpp') diff --git a/src/core/SkColorSpaceXform_A2B.cpp b/src/core/SkColorSpaceXform_A2B.cpp index f2f694349f..b0495cfef2 100644 --- a/src/core/SkColorSpaceXform_A2B.cpp +++ b/src/core/SkColorSpaceXform_A2B.cpp @@ -169,16 +169,33 @@ SkColorSpaceXform_A2B::SkColorSpaceXform_A2B(SkColorSpace_A2B* srcSpace, "None", "Named", "Value", "Table", "Param" }; #endif + int currentChannels = -1; + switch (srcSpace->inputColorFormat()) { + case SkColorSpace_Base::InputColorFormat::kRGB: + currentChannels = 3; + break; + case SkColorSpace_Base::InputColorFormat::kCMYK: + currentChannels = 4; + // CMYK images from JPEGs (the only format that supports it) are actually + // inverted CMYK, so we need to invert every channel. + // TransferFn is y = -x + 1 for x < 1.f, otherwise 0x + 0, ie y = 1 - x for x in [0,1] + this->addTransferFns({1.f, 0.f, 0.f, 0.f, 1.f, -1.f, 1.f}, 4); + break; + default: + SkASSERT(false); + } // add in all input color space -> PCS xforms for (int i = 0; i < srcSpace->count(); ++i) { const SkColorSpace_A2B::Element& e = srcSpace->element(i); + SkASSERT(e.inputChannels() == currentChannels); + currentChannels = e.outputChannels(); switch (e.type()) { case SkColorSpace_A2B::Element::Type::kGammaNamed: if (kLinear_SkGammaNamed != e.gammaNamed()) { SkCSXformPrintf("Gamma stage added: %s\n", debugGammaNamed[(int)e.gammaNamed()]); SkColorSpaceTransferFn fn = gammanamed_to_parametric(e.gammaNamed()); - this->addTransferFn(fn, kRGB_Channels); + this->addTransferFns(fn, currentChannels); fElementsPipeline.append(SkRasterPipeline::clamp_0); fElementsPipeline.append(SkRasterPipeline::clamp_1); @@ -187,23 +204,23 @@ SkColorSpaceXform_A2B::SkColorSpaceXform_A2B(SkColorSpace_A2B* srcSpace, case SkColorSpace_A2B::Element::Type::kGammas: { const SkGammas& gammas = e.gammas(); SkCSXformPrintf("Gamma stage added:"); - for (int channel = 0; channel < 3; ++channel) { + for (int channel = 0; channel < gammas.channels(); ++channel) { SkCSXformPrintf(" %s", debugGammas[(int)gammas.type(channel)]); } SkCSXformPrintf("\n"); bool gammaNeedsRef = false; - for (int channel = 0; channel < 3; ++channel) { + for (int channel = 0; channel < gammas.channels(); ++channel) { if (SkGammas::Type::kTable_Type == gammas.type(channel)) { SkTableTransferFn table = { gammas.table(channel), gammas.data(channel).fTable.fSize, }; - this->addTableFn(table, static_cast(channel)); + this->addTableFn(table, channel); gammaNeedsRef = true; } else { SkColorSpaceTransferFn fn = gamma_to_parametric(gammas, channel); - this->addTransferFn(fn, static_cast(channel)); + this->addTransferFn(fn, channel); } } if (gammaNeedsRef) { @@ -215,8 +232,8 @@ SkColorSpaceXform_A2B::SkColorSpaceXform_A2B(SkColorSpace_A2B* srcSpace, break; } case SkColorSpace_A2B::Element::Type::kCLUT: - SkCSXformPrintf("CLUT stage added [%d][%d][%d]\n", e.colorLUT().fGridPoints[0], - e.colorLUT().fGridPoints[1], e.colorLUT().fGridPoints[2]); + SkCSXformPrintf("CLUT (%d -> %d) stage added\n", e.colorLUT().inputChannels(), + e.colorLUT().outputChannels()); fCLUTs.push_back(sk_ref_sp(&e.colorLUT())); fElementsPipeline.append(SkRasterPipeline::color_lookup_table, fCLUTs.back().get()); @@ -230,6 +247,8 @@ SkColorSpaceXform_A2B::SkColorSpaceXform_A2B(SkColorSpace_A2B* srcSpace, } } + SkASSERT(3 == currentChannels); + // Lab PCS -> XYZ PCS if (SkColorSpace_A2B::PCS::kLAB == srcSpace->pcs()) { SkCSXformPrintf("Lab -> XYZ element added\n"); @@ -245,7 +264,7 @@ SkColorSpaceXform_A2B::SkColorSpaceXform_A2B(SkColorSpace_A2B* srcSpace, if (!fLinearDstGamma) { SkColorSpaceTransferFn fn = invert_parametric(gammanamed_to_parametric(dstSpace->gammaNamed())); - this->addTransferFn(fn, kRGB_Channels); + this->addTransferFns(fn, 3); fElementsPipeline.append(SkRasterPipeline::clamp_0); fElementsPipeline.append(SkRasterPipeline::clamp_1); } @@ -261,10 +280,10 @@ SkColorSpaceXform_A2B::SkColorSpaceXform_A2B(SkColorSpace_A2B* srcSpace, }; fTableStorage.push_front(std::move(storage)); - this->addTableFn(table, static_cast(channel)); + this->addTableFn(table, channel); } else { SkColorSpaceTransferFn fn = invert_parametric(gamma_to_parametric(gammas, channel)); - this->addTransferFn(fn, static_cast(channel)); + this->addTransferFn(fn, channel); } } @@ -273,45 +292,47 @@ SkColorSpaceXform_A2B::SkColorSpaceXform_A2B(SkColorSpace_A2B* srcSpace, } } -void SkColorSpaceXform_A2B::addTransferFn(const SkColorSpaceTransferFn& fn, Channels channels) { +void SkColorSpaceXform_A2B::addTransferFns(const SkColorSpaceTransferFn& fn, int channelCount) { + for (int i = 0; i < channelCount; ++i) { + this->addTransferFn(fn, i); + } +} + +void SkColorSpaceXform_A2B::addTransferFn(const SkColorSpaceTransferFn& fn, int channelIndex) { fTransferFns.push_front(fn); - switch (channels) { - case kRGB_Channels: - fElementsPipeline.append(SkRasterPipeline::parametric_r, &fTransferFns.front()); - fElementsPipeline.append(SkRasterPipeline::parametric_g, &fTransferFns.front()); - fElementsPipeline.append(SkRasterPipeline::parametric_b, &fTransferFns.front()); - break; - case kR_Channels: + switch (channelIndex) { + case 0: fElementsPipeline.append(SkRasterPipeline::parametric_r, &fTransferFns.front()); break; - case kG_Channels: + case 1: fElementsPipeline.append(SkRasterPipeline::parametric_g, &fTransferFns.front()); break; - case kB_Channels: + case 2: fElementsPipeline.append(SkRasterPipeline::parametric_b, &fTransferFns.front()); break; + case 3: + fElementsPipeline.append(SkRasterPipeline::parametric_a, &fTransferFns.front()); + break; default: SkASSERT(false); } } -void SkColorSpaceXform_A2B::addTableFn(const SkTableTransferFn& fn, Channels channels) { +void SkColorSpaceXform_A2B::addTableFn(const SkTableTransferFn& fn, int channelIndex) { fTableTransferFns.push_front(fn); - switch (channels) { - case kRGB_Channels: - fElementsPipeline.append(SkRasterPipeline::table_r, &fTableTransferFns.front()); - fElementsPipeline.append(SkRasterPipeline::table_g, &fTableTransferFns.front()); - fElementsPipeline.append(SkRasterPipeline::table_b, &fTableTransferFns.front()); - break; - case kR_Channels: + switch (channelIndex) { + case 0: fElementsPipeline.append(SkRasterPipeline::table_r, &fTableTransferFns.front()); break; - case kG_Channels: + case 1: fElementsPipeline.append(SkRasterPipeline::table_g, &fTableTransferFns.front()); break; - case kB_Channels: + case 2: fElementsPipeline.append(SkRasterPipeline::table_b, &fTableTransferFns.front()); break; + case 3: + fElementsPipeline.append(SkRasterPipeline::table_a, &fTableTransferFns.front()); + break; default: SkASSERT(false); } -- cgit v1.2.3