Simplify SkColorSpace::MakeICC

Rather than restricting the supported ICC types in MakeICC, create any
ICC type that we support, and make the client reject them as necessary
by querying the SkColorSpace::Type.

Remove ICCTypeFlag and replace uses of it with SkColorSpace::Type.

This depends on a change in Chromium
(https://chromium-review.googlesource.com/c/chromium/src/+/741843).
Without that, this change will start allowing non-CMYK images to use
CMYK profiles.

Bug: 727128
Change-Id: I085b4665e49bc80083264496d864cc4cd62ae914
Reviewed-on: https://skia-review.googlesource.com/64841
Commit-Queue: Leon Scroggins <scroggo@google.com>
Reviewed-by: Mike Klein <mtklein@chromium.org>
This commit is contained in:
Leon Scroggins III 2017-10-31 13:49:14 -04:00 committed by Skia Commit-Bot
parent e7ac58c0d5
commit f78b55cb94
11 changed files with 58 additions and 72 deletions

View File

@ -11,7 +11,6 @@
#include "SkCodec.h"
#include "SkCodecPriv.h"
#include "SkColorData.h"
#include "SkColorSpace_Base.h"
#include "SkEndian.h"
#include "SkStream.h"
#include "SkHeifCodec.h"
@ -140,11 +139,10 @@ std::unique_ptr<SkCodec> SkHeifCodec::MakeFromStream(
sk_sp<SkColorSpace> colorSpace = nullptr;
if ((frameInfo.mIccSize > 0) && (frameInfo.mIccData != nullptr)) {
SkColorSpace_Base::ICCTypeFlag iccType = SkColorSpace_Base::kRGB_ICCTypeFlag;
colorSpace = SkColorSpace_Base::MakeICC(
frameInfo.mIccData.get(), frameInfo.mIccSize, iccType);
colorSpace = SkColorSpace::MakeICC(frameInfo.mIccData.get(),
frameInfo.mIccSize);
}
if (!colorSpace) {
if (!colorSpace || colorSpace->type() != SkColorSpace::kRGB_Type) {
colorSpace = SkColorSpace::MakeSRGB();
}

View File

@ -122,7 +122,7 @@ static bool is_icc_marker(jpeg_marker_struct* marker) {
* (1) Discover all ICC profile markers and verify that they are numbered properly.
* (2) Copy the data from each marker into a contiguous ICC profile.
*/
static sk_sp<SkData> get_icc_profile(jpeg_decompress_struct* dinfo) {
static sk_sp<SkColorSpace> read_color_space(jpeg_decompress_struct* dinfo) {
// Note that 256 will be enough storage space since each markerIndex is stored in 8-bits.
jpeg_marker_struct* markerSequence[256];
memset(markerSequence, 0, sizeof(markerSequence));
@ -182,7 +182,7 @@ static sk_sp<SkData> get_icc_profile(jpeg_decompress_struct* dinfo) {
dst = SkTAddOffset<void>(dst, bytes);
}
return iccData;
return SkColorSpace::MakeICC(iccData->data(), iccData->size());
}
SkCodec::Result SkJpegCodec::ReadHeader(SkStream* stream, SkCodec** codecOut,
@ -228,23 +228,27 @@ SkCodec::Result SkJpegCodec::ReadHeader(SkStream* stream, SkCodec** codecOut,
SkEncodedInfo info = SkEncodedInfo::Make(color, SkEncodedInfo::kOpaque_Alpha, 8);
SkEncodedOrigin orientation = get_exif_orientation(decoderMgr->dinfo());
sk_sp<SkData> iccData = get_icc_profile(decoderMgr->dinfo());
sk_sp<SkColorSpace> colorSpace = nullptr;
if (iccData) {
SkColorSpace_Base::ICCTypeFlag iccType = SkColorSpace_Base::kRGB_ICCTypeFlag;
sk_sp<SkColorSpace> colorSpace = read_color_space(decoderMgr->dinfo());
if (colorSpace) {
switch (decoderMgr->dinfo()->jpeg_color_space) {
case JCS_CMYK:
case JCS_YCCK:
iccType = SkColorSpace_Base::kCMYK_ICCTypeFlag;
if (colorSpace->type() != SkColorSpace::kCMYK_Type) {
colorSpace = nullptr;
}
break;
case JCS_GRAYSCALE:
// Note the "or equals". We will accept gray or rgb profiles for gray images.
iccType |= SkColorSpace_Base::kGray_ICCTypeFlag;
break;
if (colorSpace->type() != SkColorSpace::kGray_Type &&
colorSpace->type() != SkColorSpace::kRGB_Type)
{
colorSpace = nullptr;
}
default:
if (colorSpace->type() != SkColorSpace::kRGB_Type) {
colorSpace = nullptr;
}
break;
}
colorSpace = SkColorSpace_Base::MakeICC(iccData->data(), iccData->size(), iccType);
}
if (!colorSpace) {
colorSpace = defaultColorSpace;

View File

@ -343,8 +343,7 @@ static float png_inverted_fixed_point_to_float(png_fixed_point x) {
// Returns a colorSpace object that represents any color space information in
// the encoded data. If the encoded data contains an invalid/unsupported color space,
// this will return NULL. If there is no color space information, it will guess sRGB
sk_sp<SkColorSpace> read_color_space(png_structp png_ptr, png_infop info_ptr,
SkColorSpace_Base::ICCTypeFlag iccType) {
sk_sp<SkColorSpace> read_color_space(png_structp png_ptr, png_infop info_ptr) {
#if (PNG_LIBPNG_VER_MAJOR > 1) || (PNG_LIBPNG_VER_MAJOR == 1 && PNG_LIBPNG_VER_MINOR >= 6)
@ -361,7 +360,7 @@ sk_sp<SkColorSpace> read_color_space(png_structp png_ptr, png_infop info_ptr,
int compression;
if (PNG_INFO_iCCP == png_get_iCCP(png_ptr, info_ptr, &name, &compression, &profile,
&length)) {
return SkColorSpace_Base::MakeICC(profile, length, iccType);
return SkColorSpace::MakeICC(profile, length);
}
// Second, check for sRGB.
@ -911,11 +910,23 @@ void AutoCleanPng::infoCallback(size_t idatLength) {
if (fOutCodec) {
SkASSERT(nullptr == *fOutCodec);
SkColorSpace_Base::ICCTypeFlag iccType = SkColorSpace_Base::kRGB_ICCTypeFlag;
if (SkEncodedInfo::kGray_Color == color || SkEncodedInfo::kGrayAlpha_Color == color) {
iccType |= SkColorSpace_Base::kGray_ICCTypeFlag;
sk_sp<SkColorSpace> colorSpace = read_color_space(fPng_ptr, fInfo_ptr);
if (colorSpace) {
switch (colorSpace->type()) {
case SkColorSpace::kCMYK_Type:
colorSpace = nullptr;
break;
case SkColorSpace::kGray_Type:
if (SkEncodedInfo::kGray_Color != color &&
SkEncodedInfo::kGrayAlpha_Color != color)
{
colorSpace = nullptr;
}
break;
case SkColorSpace::kRGB_Type:
break;
}
}
sk_sp<SkColorSpace> colorSpace = read_color_space(fPng_ptr, fInfo_ptr, iccType);
if (!colorSpace) {
// Treat unsupported/invalid color spaces as sRGB.
colorSpace = SkColorSpace::MakeSRGB();

View File

@ -97,7 +97,7 @@ std::unique_ptr<SkCodec> SkWebpCodec::MakeFromStream(std::unique_ptr<SkStream> s
if (WebPDemuxGetChunk(demux, "ICCP", 1, &chunkIterator)) {
colorSpace = SkColorSpace::MakeICC(chunkIterator.chunk.bytes, chunkIterator.chunk.size);
}
if (!colorSpace) {
if (!colorSpace || colorSpace->type() != SkColorSpace::kRGB_Type) {
colorSpace = SkColorSpace::MakeSRGB();
}

View File

@ -112,10 +112,10 @@ SkColorSpaceXform_A2B::SkColorSpaceXform_A2B(SkColorSpace_A2B* srcSpace,
#endif
int currentChannels;
switch (srcSpace->iccType()) {
case SkColorSpace_Base::kRGB_ICCTypeFlag:
case SkColorSpace::kRGB_Type:
currentChannels = 3;
break;
case SkColorSpace_Base::kCMYK_ICCTypeFlag: {
case SkColorSpace::kCMYK_Type: {
currentChannels = 4;
// CMYK images from JPEGs (the only format that supports it) are actually
// inverted CMYK, so we need to invert every channel.

View File

@ -7,12 +7,12 @@
#include "SkColorSpace_A2B.h"
SkColorSpace_A2B::SkColorSpace_A2B(ICCTypeFlag iccType, std::vector<Element> elements,
SkColorSpace_A2B::SkColorSpace_A2B(SkColorSpace::Type iccType, std::vector<Element> elements,
PCS pcs, sk_sp<SkData> profileData)
: INHERITED(std::move(profileData))
, fICCType(iccType)
, fElements(std::move(elements))
, fPCS(pcs)
{
SkASSERT(kRGB_ICCTypeFlag == iccType || kCMYK_ICCTypeFlag == iccType);
SkASSERT(SkColorSpace::kRGB_Type == iccType || SkColorSpace::kCMYK_Type == iccType);
}

View File

@ -52,7 +52,7 @@ public:
bool onGammaIsLinear() const override { return false; }
bool onIsNumericalTransferFn(SkColorSpaceTransferFn* coeffs) const override { return false; }
bool onIsCMYK() const override { return kCMYK_ICCTypeFlag == fICCType; }
bool onIsCMYK() const override { return SkColorSpace::kCMYK_Type == fICCType; }
sk_sp<SkColorSpace> makeLinearGamma() const override {
// TODO: Analyze the extrema of our projection into XYZ and use suitable primaries?
@ -161,13 +161,13 @@ public:
PCS pcs() const { return fPCS; }
ICCTypeFlag iccType() const { return fICCType; }
SkColorSpace::Type iccType() const { return fICCType; }
SkColorSpace_A2B(ICCTypeFlag iccType, std::vector<Element> elements, PCS pcs,
SkColorSpace_A2B(SkColorSpace::Type iccType, std::vector<Element> elements, PCS pcs,
sk_sp<SkData> profileData);
private:
ICCTypeFlag fICCType;
SkColorSpace::Type fICCType;
std::vector<Element> fElements;
PCS fPCS;

View File

@ -187,13 +187,6 @@ public:
virtual Type type() const = 0;
typedef uint8_t ICCTypeFlag;
static constexpr ICCTypeFlag kRGB_ICCTypeFlag = 1 << 0;
static constexpr ICCTypeFlag kCMYK_ICCTypeFlag = 1 << 1;
static constexpr ICCTypeFlag kGray_ICCTypeFlag = 1 << 2;
static sk_sp<SkColorSpace> MakeICC(const void* input, size_t len, ICCTypeFlag type);
static sk_sp<SkColorSpace> MakeRGB(SkGammaNamed gammaNamed, const SkMatrix44& toXYZD50);
enum Named : uint8_t {

View File

@ -1180,11 +1180,11 @@ bool load_a2b0_lutn_type(std::vector<SkColorSpace_A2B::Element>* elements, const
return true;
}
static inline int icf_channels(SkColorSpace_Base::ICCTypeFlag iccType) {
static inline int icf_channels(SkColorSpace::Type iccType) {
switch (iccType) {
case SkColorSpace_Base::kRGB_ICCTypeFlag:
case SkColorSpace::kRGB_Type:
return 3;
case SkColorSpace_Base::kCMYK_ICCTypeFlag:
case SkColorSpace::kCMYK_Type:
return 4;
default:
SkASSERT(false);
@ -1194,7 +1194,7 @@ static inline int icf_channels(SkColorSpace_Base::ICCTypeFlag iccType) {
static bool load_a2b0(std::vector<SkColorSpace_A2B::Element>* elements, const uint8_t* src,
size_t len, SkColorSpace_A2B::PCS pcs,
SkColorSpace_Base::ICCTypeFlag iccType) {
SkColorSpace::Type iccType) {
if (len < 4) {
return false;
}
@ -1472,7 +1472,7 @@ static sk_sp<SkColorSpace> make_gray(const ICCProfileHeader& header, ICCTag* tag
toXYZD50, std::move(profileData)));
}
static sk_sp<SkColorSpace> make_a2b(SkColorSpace_Base::ICCTypeFlag iccType,
static sk_sp<SkColorSpace> make_a2b(SkColorSpace::Type iccType,
const ICCProfileHeader& header, ICCTag* tags, int tagCount,
const uint8_t* base, sk_sp<SkData> profileData) {
const ICCTag* a2b0 = ICCTag::Find(tags, tagCount, kTAG_A2B0);
@ -1491,11 +1491,6 @@ static sk_sp<SkColorSpace> make_a2b(SkColorSpace_Base::ICCTypeFlag iccType,
}
sk_sp<SkColorSpace> SkColorSpace::MakeICC(const void* input, size_t len) {
return SkColorSpace_Base::MakeICC(input, len, SkColorSpace_Base::kRGB_ICCTypeFlag);
}
sk_sp<SkColorSpace> SkColorSpace_Base::MakeICC(const void* input, size_t len,
ICCTypeFlag desiredType) {
if (!input || len < kICCHeaderSize) {
return_null("Data is null or not large enough to contain an ICC profile");
}
@ -1543,38 +1538,25 @@ sk_sp<SkColorSpace> SkColorSpace_Base::MakeICC(const void* input, size_t len,
}
}
Type a2b_type = kRGB_Type;
switch (header.fInputColorSpace) {
case kRGB_ColorSpace: {
if (!(kRGB_ICCTypeFlag & desiredType)) {
return_null("Provided input color format (RGB) does not match profile.");
}
sk_sp<SkColorSpace> colorSpace =
make_xyz(header, tags.get(), tagCount, base, profileData);
if (colorSpace) {
return colorSpace;
}
desiredType = kRGB_ICCTypeFlag;
break;
}
case kGray_ColorSpace: {
if (!(kGray_ICCTypeFlag & desiredType)) {
return_null("Provided input color format (Gray) does not match profile.");
}
return make_gray(header, tags.get(), tagCount, base, profileData);
}
case kCMYK_ColorSpace:
if (!(kCMYK_ICCTypeFlag & desiredType)) {
return_null("Provided input color format (CMYK) does not match profile.");
}
desiredType = kCMYK_ICCTypeFlag;
a2b_type = kCMYK_Type;
break;
default:
return_null("ICC profile contains unsupported colorspace");
}
return make_a2b(desiredType, header, tags.get(), tagCount, base, profileData);
return make_a2b(a2b_type, header, tags.get(), tagCount, base, profileData);
}

View File

@ -50,7 +50,6 @@ public:
srcElements.push_back(SkColorSpace_A2B::Element(arbitraryMatrix));
auto srcSpace =
ColorSpaceXformTest::CreateA2BSpace(SkColorSpace_A2B::PCS::kXYZ,
SkColorSpace_Base::kRGB_ICCTypeFlag,
std::move(srcElements));
sk_sp<SkColorSpace> dstSpace(new SkColorSpace_XYZ(gammaNamed, gammas, arbitraryMatrix,
nullptr));
@ -60,9 +59,9 @@ public:
}
static sk_sp<SkColorSpace> CreateA2BSpace(SkColorSpace_A2B::PCS pcs,
SkColorSpace_Base::ICCTypeFlag iccType,
std::vector<SkColorSpace_A2B::Element> elements) {
return sk_sp<SkColorSpace>(new SkColorSpace_A2B(iccType, std::move(elements),
return sk_sp<SkColorSpace>(new SkColorSpace_A2B(SkColorSpace::kRGB_Type,
std::move(elements),
pcs, nullptr));
}
};
@ -309,7 +308,6 @@ DEF_TEST(ColorSpaceXform_A2BCLUT, r) {
std::vector<SkColorSpace_A2B::Element> srcElements;
srcElements.push_back(SkColorSpace_A2B::Element(std::move(colorLUT)));
auto srcSpace = ColorSpaceXformTest::CreateA2BSpace(SkColorSpace_A2B::PCS::kXYZ,
SkColorSpace_Base::kRGB_ICCTypeFlag,
std::move(srcElements));
// dst space is entirely identity
auto dstSpace = SkColorSpace::MakeRGB(SkColorSpace::kLinear_RenderTargetGamma, SkMatrix44::I());

View File

@ -565,13 +565,13 @@ int main(int argc, char** argv) {
SkColorSpace_A2B* a2b = static_cast<SkColorSpace_A2B*>(colorSpace.get());
SkDebugf("Conversion type: ");
switch (a2b->iccType()) {
case SkColorSpace_Base::kRGB_ICCTypeFlag:
case SkColorSpace::kRGB_Type:
SkDebugf("RGB");
break;
case SkColorSpace_Base::kCMYK_ICCTypeFlag:
case SkColorSpace::kCMYK_Type:
SkDebugf("CMYK");
break;
case SkColorSpace_Base::kGray_ICCTypeFlag:
case SkColorSpace::kGray_Type:
SkDebugf("Gray");
break;
default: