blob: a19f040e5126cd6a5447c6e0dd9c883ac91cdd2f [file] [log] [blame]
// Copyright 2017 PDFium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
#include "core/fxge/cfx_color.h"
#include <algorithm>
#include "core/fpdfapi/parser/cpdf_array.h"
#include "core/fpdfdoc/cpdf_defaultappearance.h"
// Color types are orded by increasing number of components so we can
// choose a best color type during some conversions.
static_assert(CFX_Color::kTransparent < CFX_Color::kGray,
"color type values must be ordered");
static_assert(CFX_Color::kGray < CFX_Color::kRGB,
"color type values must be ordered");
static_assert(CFX_Color::kRGB < CFX_Color::kCMYK,
"color type values must be ordered");
namespace {
bool InRange(float comp) {
return comp >= 0.0f && comp <= 1.0f;
}
CFX_Color ConvertCMYK2GRAY(float dC, float dM, float dY, float dK) {
if (!InRange(dC) || !InRange(dM) || !InRange(dY) || !InRange(dK))
return CFX_Color(CFX_Color::kGray);
return CFX_Color(
CFX_Color::kGray,
1.0f - std::min(1.0f, 0.3f * dC + 0.59f * dM + 0.11f * dY + dK));
}
CFX_Color ConvertGRAY2CMYK(float dGray) {
if (!InRange(dGray))
return CFX_Color(CFX_Color::kCMYK);
return CFX_Color(CFX_Color::kCMYK, 0.0f, 0.0f, 0.0f, 1.0f - dGray);
}
CFX_Color ConvertGRAY2RGB(float dGray) {
if (!InRange(dGray))
return CFX_Color(CFX_Color::kRGB);
return CFX_Color(CFX_Color::kRGB, dGray, dGray, dGray);
}
CFX_Color ConvertRGB2GRAY(float dR, float dG, float dB) {
if (!InRange(dR) || !InRange(dG) || !InRange(dB))
return CFX_Color(CFX_Color::kGray);
return CFX_Color(CFX_Color::kGray, 0.3f * dR + 0.59f * dG + 0.11f * dB);
}
CFX_Color ConvertCMYK2RGB(float dC, float dM, float dY, float dK) {
if (!InRange(dC) || !InRange(dM) || !InRange(dY) || !InRange(dK))
return CFX_Color(CFX_Color::kRGB);
return CFX_Color(CFX_Color::kRGB, 1.0f - std::min(1.0f, dC + dK),
1.0f - std::min(1.0f, dM + dK),
1.0f - std::min(1.0f, dY + dK));
}
CFX_Color ConvertRGB2CMYK(float dR, float dG, float dB) {
if (!InRange(dR) || !InRange(dG) || !InRange(dB))
return CFX_Color(CFX_Color::kCMYK);
float c = 1.0f - dR;
float m = 1.0f - dG;
float y = 1.0f - dB;
return CFX_Color(CFX_Color::kCMYK, c, m, y, std::min(c, std::min(m, y)));
}
} // namespace
// Static.
CFX_Color CFX_Color::ParseColor(const CPDF_Array& array) {
CFX_Color rt;
switch (array.size()) {
case 1:
rt = CFX_Color(CFX_Color::kGray, array.GetFloatAt(0));
break;
case 3:
rt = CFX_Color(CFX_Color::kRGB, array.GetFloatAt(0), array.GetFloatAt(1),
array.GetFloatAt(2));
break;
case 4:
rt = CFX_Color(CFX_Color::kCMYK, array.GetFloatAt(0), array.GetFloatAt(1),
array.GetFloatAt(2), array.GetFloatAt(3));
break;
}
return rt;
}
// Static.
CFX_Color CFX_Color::ParseColor(const ByteString& str) {
CPDF_DefaultAppearance appearance(str);
float values[4];
Optional<CFX_Color::Type> color_type = appearance.GetColor(values);
if (!color_type || *color_type == CFX_Color::kTransparent)
return CFX_Color(CFX_Color::kTransparent);
if (*color_type == CFX_Color::kGray)
return CFX_Color(CFX_Color::kGray, values[0]);
if (*color_type == CFX_Color::kRGB)
return CFX_Color(CFX_Color::kRGB, values[0], values[1], values[2]);
if (*color_type == CFX_Color::kCMYK) {
return CFX_Color(CFX_Color::kCMYK, values[0], values[1], values[2],
values[3]);
}
NOTREACHED();
return CFX_Color(CFX_Color::kTransparent);
}
CFX_Color CFX_Color::ConvertColorType(int32_t nConvertColorType) const {
if (nColorType == nConvertColorType)
return *this;
CFX_Color ret;
switch (nColorType) {
case CFX_Color::kTransparent:
ret = *this;
ret.nColorType = CFX_Color::kTransparent;
break;
case CFX_Color::kGray:
switch (nConvertColorType) {
case CFX_Color::kRGB:
ret = ConvertGRAY2RGB(fColor1);
break;
case CFX_Color::kCMYK:
ret = ConvertGRAY2CMYK(fColor1);
break;
}
break;
case CFX_Color::kRGB:
switch (nConvertColorType) {
case CFX_Color::kGray:
ret = ConvertRGB2GRAY(fColor1, fColor2, fColor3);
break;
case CFX_Color::kCMYK:
ret = ConvertRGB2CMYK(fColor1, fColor2, fColor3);
break;
}
break;
case CFX_Color::kCMYK:
switch (nConvertColorType) {
case CFX_Color::kGray:
ret = ConvertCMYK2GRAY(fColor1, fColor2, fColor3, fColor4);
break;
case CFX_Color::kRGB:
ret = ConvertCMYK2RGB(fColor1, fColor2, fColor3, fColor4);
break;
}
break;
}
return ret;
}
FX_COLORREF CFX_Color::ToFXColor(int32_t nTransparency) const {
CFX_Color ret;
switch (nColorType) {
case CFX_Color::kTransparent: {
ret = CFX_Color(CFX_Color::kTransparent, 0, 0, 0, 0);
break;
}
case CFX_Color::kGray: {
ret = ConvertGRAY2RGB(fColor1);
ret.fColor4 = nTransparency;
break;
}
case CFX_Color::kRGB: {
ret = CFX_Color(CFX_Color::kRGB, fColor1, fColor2, fColor3);
ret.fColor4 = nTransparency;
break;
}
case CFX_Color::kCMYK: {
ret = ConvertCMYK2RGB(fColor1, fColor2, fColor3, fColor4);
ret.fColor4 = nTransparency;
break;
}
}
return ArgbEncode(ret.fColor4, static_cast<int32_t>(ret.fColor1 * 255),
static_cast<int32_t>(ret.fColor2 * 255),
static_cast<int32_t>(ret.fColor3 * 255));
}
CFX_Color CFX_Color::operator-(float fColorSub) const {
CFX_Color sRet(nColorType);
switch (nColorType) {
case CFX_Color::kTransparent:
sRet.nColorType = CFX_Color::kRGB;
sRet.fColor1 = std::max(1.0f - fColorSub, 0.0f);
sRet.fColor2 = std::max(1.0f - fColorSub, 0.0f);
sRet.fColor3 = std::max(1.0f - fColorSub, 0.0f);
break;
case CFX_Color::kRGB:
case CFX_Color::kGray:
case CFX_Color::kCMYK:
sRet.fColor1 = std::max(fColor1 - fColorSub, 0.0f);
sRet.fColor2 = std::max(fColor2 - fColorSub, 0.0f);
sRet.fColor3 = std::max(fColor3 - fColorSub, 0.0f);
sRet.fColor4 = std::max(fColor4 - fColorSub, 0.0f);
break;
}
return sRet;
}
CFX_Color CFX_Color::operator/(float fColorDivide) const {
CFX_Color sRet(nColorType);
switch (nColorType) {
case CFX_Color::kTransparent:
sRet.nColorType = CFX_Color::kRGB;
sRet.fColor1 = 1.0f / fColorDivide;
sRet.fColor2 = 1.0f / fColorDivide;
sRet.fColor3 = 1.0f / fColorDivide;
break;
case CFX_Color::kRGB:
case CFX_Color::kGray:
case CFX_Color::kCMYK:
sRet = *this;
sRet.fColor1 /= fColorDivide;
sRet.fColor2 /= fColorDivide;
sRet.fColor3 /= fColorDivide;
sRet.fColor4 /= fColorDivide;
break;
}
return sRet;
}