Skip to content

Commit

Permalink
ICC profile color translations
Browse files Browse the repository at this point in the history
Uses QCMS to translate colors to/from ICC profile-based color spaces.

BUG=622133

Review-Url: https://codereview.chromium.org/2203213002
Cr-Commit-Position: refs/heads/master@{#409954}
  • Loading branch information
hubbe authored and Commit bot committed Aug 5, 2016
1 parent d208e13 commit c289ee4
Show file tree
Hide file tree
Showing 11 changed files with 403 additions and 21 deletions.
3 changes: 1 addition & 2 deletions third_party/qcms/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@ config("qcms_config") {
include_dirs = [ "src" ]
}

# Do not build QCMS on Android or iOS. (See http://crbug.com/577155)
disable_qcms = is_android || is_ios
disable_qcms = false

static_library("qcms") {
if (disable_qcms) {
Expand Down
9 changes: 1 addition & 8 deletions third_party/qcms/qcms.gyp
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,7 @@

{
'variables': {
'conditions': [
# Do not build QCMS on Android or iOS. (See http://crbug.com/577155)
['OS == "android" or OS == "ios"', {
'disable_qcms%': 1,
}, {
'disable_qcms%': 0,
}],
],
'disable_qcms%': 0,
},
'targets': [
{
Expand Down
1 change: 1 addition & 0 deletions ui/gfx/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,7 @@ component("gfx") {
"//skia",
"//third_party/harfbuzz-ng",
"//third_party/libpng",
"//third_party/qcms",
"//third_party/zlib",
]

Expand Down
1 change: 1 addition & 0 deletions ui/gfx/DEPS
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ include_rules = [
"+skia/ext",
"+third_party/harfbuzz-ng",
"+third_party/skia",
"+third_party/qcms",
"+ui/ios",

"-testing/gmock",
Expand Down
108 changes: 103 additions & 5 deletions ui/gfx/color_transform.cc
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,15 @@

#include "base/logging.h"
#include "ui/gfx/color_space.h"
#include "ui/gfx/icc_profile.h"
#include "ui/gfx/transform.h"
#include "third_party/qcms/src/qcms.h"

#ifndef THIS_MUST_BE_INCLUDED_AFTER_QCMS_H
extern "C" {
#include "third_party/qcms/src/chain.h"
};
#endif

namespace gfx {

Expand Down Expand Up @@ -178,7 +186,7 @@ GFX_EXPORT Transform GetPrimaryMatrix(ColorSpace::PrimaryID id) {
dest_response.y() / source_response.y(),
dest_response.z() / source_response.z());

return bradford * adapter * Invert(bradford) * ret;
return Invert(bradford) * adapter * bradford * ret;
}

GFX_EXPORT float FromLinear(ColorSpace::TransferID id, float v) {
Expand Down Expand Up @@ -547,14 +555,104 @@ class ColorSpaceToColorSpaceTransform : public ColorTransform {
Transform c_;
};

class QCMSColorTransform : public ColorTransform {
public:
// Takes ownership of the profiles
QCMSColorTransform(qcms_profile* from, qcms_profile* to)
: from_(from), to_(to) {}
~QCMSColorTransform() {
qcms_profile_release(from_);
qcms_profile_release(to_);
}
void transform(TriStim* colors, size_t num) override {
CHECK(sizeof(TriStim) == sizeof(float[3]));
// QCMS doesn't like numbers outside 0..1
for (size_t i = 0; i < num; i++) {
colors[i].set_x(fmin(1.0f, fmax(0.0f, colors[i].x())));
colors[i].set_y(fmin(1.0f, fmax(0.0f, colors[i].y())));
colors[i].set_z(fmin(1.0f, fmax(0.0f, colors[i].z())));
}
qcms_chain_transform(from_, to_, reinterpret_cast<float*>(colors),
reinterpret_cast<float*>(colors), num * 3);
}

private:
qcms_profile *from_, *to_;
};

class ChainColorTransform : public ColorTransform {
public:
ChainColorTransform(std::unique_ptr<ColorTransform> a,
std::unique_ptr<ColorTransform> b)
: a_(std::move(a)), b_(std::move(b)) {}

private:
void transform(TriStim* colors, size_t num) override {
a_->transform(colors, num);
b_->transform(colors, num);
}
std::unique_ptr<ColorTransform> a_;
std::unique_ptr<ColorTransform> b_;
};

qcms_profile* GetQCMSProfileIfAvailable(const ColorSpace& color_space) {
ICCProfile icc_profile = ICCProfile::FromColorSpace(color_space);
if (icc_profile.GetData().empty())
return nullptr;
return qcms_profile_from_memory(icc_profile.GetData().data(),
icc_profile.GetData().size());
}

qcms_profile* GetXYZD50Profile() {
// QCMS is trixy, it has a datatype called qcms_CIE_xyY, but what it expects
// is in fact not xyY color coordinates, it just wants the x/y values of the
// primaries with Y equal to 1.0.
qcms_CIE_xyYTRIPLE xyz;
qcms_CIE_xyY w;
xyz.red.x = 1.0f;
xyz.red.y = 0.0f;
xyz.red.Y = 1.0f;
xyz.green.x = 0.0f;
xyz.green.y = 1.0f;
xyz.green.Y = 1.0f;
xyz.blue.x = 0.0f;
xyz.blue.y = 0.0f;
xyz.blue.Y = 1.0f;
w.x = 0.34567f;
w.y = 0.35850f;
w.Y = 1.0f;
return qcms_profile_create_rgb_with_gamma(w, xyz, 1.0f);
}

std::unique_ptr<ColorTransform> ColorTransform::NewColorTransform(
const ColorSpace& from,
const ColorSpace& to,
Intent intent) {
// TODO(Hubbe): Check if from and/or to can be mapped to ICC profiles and
// provide better transforms in those cases.
return std::unique_ptr<ColorTransform>(
new ColorSpaceToColorSpaceTransform(from, to, intent));
qcms_profile* from_profile = GetQCMSProfileIfAvailable(from);
qcms_profile* to_profile = GetQCMSProfileIfAvailable(to);
if (from_profile) {
if (to_profile) {
return std::unique_ptr<ColorTransform>(
new QCMSColorTransform(from_profile, to_profile));
} else {
return std::unique_ptr<ColorTransform>(new ChainColorTransform(
std::unique_ptr<ColorTransform>(
new QCMSColorTransform(from_profile, GetXYZD50Profile())),
std::unique_ptr<ColorTransform>(new ColorSpaceToColorSpaceTransform(
ColorSpace::CreateXYZD50(), to, intent))));
}
} else {
if (to_profile) {
return std::unique_ptr<ColorTransform>(new ChainColorTransform(
std::unique_ptr<ColorTransform>(new ColorSpaceToColorSpaceTransform(
from, ColorSpace::CreateXYZD50(), intent)),
std::unique_ptr<ColorTransform>(
new QCMSColorTransform(GetXYZD50Profile(), to_profile))));
} else {
return std::unique_ptr<ColorTransform>(
new ColorSpaceToColorSpaceTransform(from, to, intent));
}
}
}

} // namespace gfx
Loading

0 comments on commit c289ee4

Please sign in to comment.