mirror of https://github.com/JakubMelka/PDF4QT.git
Rework of color spaces, some bugfixing of color spaces
This commit is contained in:
parent
b29791b890
commit
a2dc4e16a8
|
@ -81,6 +81,7 @@ SOURCES += \
|
|||
sources/pdfsnapper.cpp \
|
||||
sources/pdfstructuretree.cpp \
|
||||
sources/pdftextlayout.cpp \
|
||||
sources/pdftransparencyrenderer.cpp \
|
||||
sources/pdfutils.cpp \
|
||||
sources/pdfwidgettool.cpp \
|
||||
sources/pdfwidgetutils.cpp \
|
||||
|
@ -150,6 +151,7 @@ HEADERS += \
|
|||
sources/pdfsnapper.h \
|
||||
sources/pdfstructuretree.h \
|
||||
sources/pdftextlayout.h \
|
||||
sources/pdftransparencyrenderer.h \
|
||||
sources/pdfwidgettool.h \
|
||||
sources/pdfwidgetutils.h \
|
||||
sources/pdfxreftable.h \
|
||||
|
|
|
@ -48,6 +48,7 @@ public:
|
|||
virtual bool fillRGBBufferFromDeviceCMYK(const std::vector<float>& colors, RenderingIntent intent, unsigned char* outputBuffer, PDFRenderErrorReporter* reporter) const override;
|
||||
virtual bool fillRGBBufferFromXYZ(const PDFColor3& whitePoint, const std::vector<float>& colors, RenderingIntent intent, unsigned char* outputBuffer, PDFRenderErrorReporter* reporter) const override;
|
||||
virtual bool fillRGBBufferFromICC(const std::vector<float>& colors, RenderingIntent renderingIntent, unsigned char* outputBuffer, const QByteArray& iccID, const QByteArray& iccData, PDFRenderErrorReporter* reporter) const override;
|
||||
virtual bool transformColorSpace(const ColorSpaceTransformParams& params) const override;
|
||||
|
||||
private:
|
||||
void init();
|
||||
|
@ -279,6 +280,11 @@ bool PDFLittleCMS::fillRGBBufferFromICC(const std::vector<float>& colors, Render
|
|||
return false;
|
||||
}
|
||||
|
||||
bool PDFLittleCMS::transformColorSpace(const PDFCMS::ColorSpaceTransformParams& params) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
PDFLittleCMS::PDFLittleCMS(const PDFCMSManager* manager, const PDFCMSSettings& settings) :
|
||||
m_manager(manager),
|
||||
m_settings(settings),
|
||||
|
@ -410,6 +416,7 @@ QColor PDFLittleCMS::getColorFromDeviceCMYK(const PDFColor& color, RenderingInte
|
|||
|
||||
QColor PDFLittleCMS::getColorFromXYZ(const PDFColor3& whitePoint, const PDFColor3& color, RenderingIntent intent, PDFRenderErrorReporter* reporter) const
|
||||
{
|
||||
Q_UNUSED(whitePoint);
|
||||
cmsHTRANSFORM transform = getTransform(XYZ, getEffectiveRenderingIntent(intent), false);
|
||||
|
||||
if (!transform)
|
||||
|
@ -422,8 +429,10 @@ QColor PDFLittleCMS::getColorFromXYZ(const PDFColor3& whitePoint, const PDFColor
|
|||
{
|
||||
Q_ASSERT(cmsGetTransformOutputFormat(transform) == TYPE_RGB_FLT);
|
||||
|
||||
// Jakub Melka: It seems, that Adobe Acrobat Reader doesn't do the gamut remapping (whitepoint remapping).
|
||||
// so, we don't do that too.
|
||||
const cmsCIEXYZ* d50WhitePoint = cmsD50_XYZ();
|
||||
std::array<float, 3> xyzInputColor = { color[0] / whitePoint[0] * float(d50WhitePoint->X), color[1] / whitePoint[1] * float(d50WhitePoint->Y), color[2] / whitePoint[2] * float(d50WhitePoint->Z) };
|
||||
std::array<float, 3> xyzInputColor = { color[0] * float(d50WhitePoint->X), color[1] * float(d50WhitePoint->Y), color[2] * float(d50WhitePoint->Z)};
|
||||
std::array<float, 3> rgbOutputColor = { };
|
||||
cmsDoTransform(transform, xyzInputColor.data(), rgbOutputColor.data(), 1);
|
||||
return getColorFromOutputColor(rgbOutputColor);
|
||||
|
@ -933,6 +942,11 @@ bool PDFCMSGeneric::fillRGBBufferFromICC(const std::vector<float>& colors, Rende
|
|||
return false;
|
||||
}
|
||||
|
||||
bool PDFCMSGeneric::transformColorSpace(const PDFCMS::ColorSpaceTransformParams& params) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
PDFCMSManager::PDFCMSManager(QObject* parent) :
|
||||
BaseClass(parent),
|
||||
m_mutex(QMutex::Recursive)
|
||||
|
@ -1242,4 +1256,10 @@ PDFColorProfileIdentifier PDFColorProfileIdentifier::createFile(Type type, QStri
|
|||
return result;
|
||||
}
|
||||
|
||||
PDFColor3 PDFCMS::getDefaultXYZWhitepoint()
|
||||
{
|
||||
const cmsCIEXYZ* whitePoint = cmsD50_XYZ();
|
||||
return PDFColor3{ PDFColorComponent(whitePoint->X), PDFColorComponent(whitePoint->Y), PDFColorComponent(whitePoint->Z) };
|
||||
}
|
||||
|
||||
} // namespace pdf
|
||||
|
|
|
@ -127,14 +127,21 @@ public:
|
|||
/// \param Three color channel value (X,Y,Z channel)
|
||||
/// \param intent Rendering intent
|
||||
/// \param reporter Render error reporter (used, when color transform fails)
|
||||
virtual QColor getColorFromXYZ(const PDFColor3& whitePoint, const PDFColor3& color, RenderingIntent intent, PDFRenderErrorReporter* reporter) const = 0;
|
||||
virtual QColor getColorFromXYZ(const PDFColor3& whitePoint,
|
||||
const PDFColor3& color,
|
||||
RenderingIntent intent,
|
||||
PDFRenderErrorReporter* reporter) const = 0;
|
||||
|
||||
/// Computes color from ICC color profile
|
||||
/// \param color Input color
|
||||
/// \param iccID Unique ICC profile identifier
|
||||
/// \param iccData Color profile data
|
||||
/// \param reporter Render error reporter (used, when color transform fails)
|
||||
virtual QColor getColorFromICC(const PDFColor& color, RenderingIntent renderingIntent, const QByteArray& iccID, const QByteArray& iccData, PDFRenderErrorReporter* reporter) const = 0;
|
||||
virtual QColor getColorFromICC(const PDFColor& color,
|
||||
RenderingIntent renderingIntent,
|
||||
const QByteArray& iccID,
|
||||
const QByteArray& iccData,
|
||||
PDFRenderErrorReporter* reporter) const = 0;
|
||||
|
||||
/// Fills colors in Device Gray color space to the RGB buffer. If error occurs, then false is returned.
|
||||
/// Caller then should handle this - try to convert color as accurate as possible.
|
||||
|
@ -142,7 +149,10 @@ public:
|
|||
/// \param intent Rendering intent
|
||||
/// \param outputBuffer Output buffer in format RGB_888 (8-bit RGB values)
|
||||
/// \param reporter Render error reporter (used, when color transform fails)
|
||||
virtual bool fillRGBBufferFromDeviceGray(const std::vector<float>& colors, RenderingIntent intent, unsigned char* outputBuffer, PDFRenderErrorReporter* reporter) const = 0;
|
||||
virtual bool fillRGBBufferFromDeviceGray(const std::vector<float>& colors,
|
||||
RenderingIntent intent,
|
||||
unsigned char* outputBuffer,
|
||||
PDFRenderErrorReporter* reporter) const = 0;
|
||||
|
||||
/// Fills colors in Device RGB color space to RGB buffer. If error occurs, then false is returned.
|
||||
/// Caller then should handle this - try to convert color as accurate as possible.
|
||||
|
@ -150,7 +160,10 @@ public:
|
|||
/// \param intent Rendering intent
|
||||
/// \param outputBuffer Output buffer in format RGB_888 (8-bit RGB values)
|
||||
/// \param reporter Render error reporter (used, when color transform fails)
|
||||
virtual bool fillRGBBufferFromDeviceRGB(const std::vector<float>& colors, RenderingIntent intent, unsigned char* outputBuffer, PDFRenderErrorReporter* reporter) const = 0;
|
||||
virtual bool fillRGBBufferFromDeviceRGB(const std::vector<float>& colors,
|
||||
RenderingIntent intent,
|
||||
unsigned char* outputBuffer,
|
||||
PDFRenderErrorReporter* reporter) const = 0;
|
||||
|
||||
/// Fills colors in Device CMYK color space to the RGB buffer. If error occurs, then false is returned.
|
||||
/// Caller then should handle this - try to convert color as accurate as possible.
|
||||
|
@ -158,7 +171,10 @@ public:
|
|||
/// \param intent Rendering intent
|
||||
/// \param outputBuffer Output buffer in format RGB_888 (8-bit RGB values)
|
||||
/// \param reporter Render error reporter (used, when color transform fails)
|
||||
virtual bool fillRGBBufferFromDeviceCMYK(const std::vector<float>& colors, RenderingIntent intent, unsigned char* outputBuffer, PDFRenderErrorReporter* reporter) const = 0;
|
||||
virtual bool fillRGBBufferFromDeviceCMYK(const std::vector<float>& colors,
|
||||
RenderingIntent intent,
|
||||
unsigned char* outputBuffer,
|
||||
PDFRenderErrorReporter* reporter) const = 0;
|
||||
|
||||
/// Fills colors in XYZ color space to the RGB buffer. If error occurs, then false is returned.
|
||||
/// Caller then should handle this - try to convert color as accurate as possible.
|
||||
|
@ -166,14 +182,51 @@ public:
|
|||
/// \param Three color channel value (X,Y,Z channel)
|
||||
/// \param intent Rendering intent
|
||||
/// \param reporter Render error reporter (used, when color transform fails)
|
||||
virtual bool fillRGBBufferFromXYZ(const PDFColor3& whitePoint, const std::vector<float>& colors, RenderingIntent intent, unsigned char* outputBuffer, PDFRenderErrorReporter* reporter) const = 0;
|
||||
virtual bool fillRGBBufferFromXYZ(const PDFColor3& whitePoint,
|
||||
const std::vector<float>& colors,
|
||||
RenderingIntent intent,
|
||||
unsigned char* outputBuffer,
|
||||
PDFRenderErrorReporter* reporter) const = 0;
|
||||
|
||||
/// Fills RGB buffer from ICC color profile colors
|
||||
/// \param colors Input colors
|
||||
/// \param iccID Unique ICC profile identifier
|
||||
/// \param iccData Color profile data
|
||||
/// \param reporter Render error reporter (used, when color transform fails)
|
||||
virtual bool fillRGBBufferFromICC(const std::vector<float>& colors, RenderingIntent renderingIntent, unsigned char* outputBuffer, const QByteArray& iccID, const QByteArray& iccData, PDFRenderErrorReporter* reporter) const = 0;
|
||||
virtual bool fillRGBBufferFromICC(const std::vector<float>& colors,
|
||||
RenderingIntent renderingIntent,
|
||||
unsigned char* outputBuffer,
|
||||
const QByteArray& iccID,
|
||||
const QByteArray& iccData,
|
||||
PDFRenderErrorReporter* reporter) const = 0;
|
||||
|
||||
enum ColorSpaceType
|
||||
{
|
||||
Invalid,
|
||||
DeviceGray,
|
||||
DeviceRGB,
|
||||
DeviceCMYK,
|
||||
XYZ,
|
||||
ICC
|
||||
};
|
||||
|
||||
struct ColorSpaceTransformParams
|
||||
{
|
||||
ColorSpaceType sourceType = ColorSpaceType::Invalid;
|
||||
ColorSpaceType targetType = ColorSpaceType::Invalid;
|
||||
|
||||
QByteArray sourceIccId;
|
||||
QByteArray targetIccId;
|
||||
|
||||
QByteArray sourceIccData;
|
||||
QByteArray targetIccData;
|
||||
};
|
||||
|
||||
/// Transforms color between two color spaces.
|
||||
virtual bool transformColorSpace(const ColorSpaceTransformParams& params) const = 0;
|
||||
|
||||
/// Get D50 white point for XYZ color space
|
||||
static PDFColor3 getDefaultXYZWhitepoint();
|
||||
};
|
||||
|
||||
using PDFCMSPointer = QSharedPointer<PDFCMS>;
|
||||
|
@ -195,6 +248,7 @@ public:
|
|||
virtual bool fillRGBBufferFromDeviceCMYK(const std::vector<float>& colors, RenderingIntent intent, unsigned char* outputBuffer, PDFRenderErrorReporter* reporter) const override;
|
||||
virtual bool fillRGBBufferFromXYZ(const PDFColor3& whitePoint, const std::vector<float>& colors, RenderingIntent intent, unsigned char* outputBuffer, PDFRenderErrorReporter* reporter) const override;
|
||||
virtual bool fillRGBBufferFromICC(const std::vector<float>& colors, RenderingIntent renderingIntent, unsigned char* outputBuffer, const QByteArray& iccID, const QByteArray& iccData, PDFRenderErrorReporter* reporter) const override;
|
||||
virtual bool transformColorSpace(const ColorSpaceTransformParams& params) const override;
|
||||
};
|
||||
|
||||
struct PDFColorProfileIdentifier
|
||||
|
|
|
@ -31,6 +31,43 @@
|
|||
namespace pdf
|
||||
{
|
||||
|
||||
static PDFColorComponent getDeterminant(const PDFColorComponentMatrix_3x3& matrix)
|
||||
{
|
||||
const PDFColorComponent a_11 = matrix.getValue(0, 0);
|
||||
const PDFColorComponent a_12 = matrix.getValue(0, 1);
|
||||
const PDFColorComponent a_13 = matrix.getValue(0, 2);
|
||||
const PDFColorComponent a_21 = matrix.getValue(1, 0);
|
||||
const PDFColorComponent a_22 = matrix.getValue(1, 1);
|
||||
const PDFColorComponent a_23 = matrix.getValue(1, 2);
|
||||
const PDFColorComponent a_31 = matrix.getValue(2, 0);
|
||||
const PDFColorComponent a_32 = matrix.getValue(2, 1);
|
||||
const PDFColorComponent a_33 = matrix.getValue(2, 2);
|
||||
|
||||
return -a_13* a_22 * a_31 + a_12 * a_23 * a_31 + a_13 * a_21 * a_32 - a_11 * a_23 * a_32 - a_12 * a_21 * a_33 + a_11 * a_22 * a_33;
|
||||
}
|
||||
|
||||
PDFColorComponentMatrix_3x3 getInverseMatrix(const PDFColorComponentMatrix_3x3& matrix)
|
||||
{
|
||||
const PDFColorComponent a_11 = matrix.getValue(0, 0);
|
||||
const PDFColorComponent a_12 = matrix.getValue(0, 1);
|
||||
const PDFColorComponent a_13 = matrix.getValue(0, 2);
|
||||
const PDFColorComponent a_21 = matrix.getValue(1, 0);
|
||||
const PDFColorComponent a_22 = matrix.getValue(1, 1);
|
||||
const PDFColorComponent a_23 = matrix.getValue(1, 2);
|
||||
const PDFColorComponent a_31 = matrix.getValue(2, 0);
|
||||
const PDFColorComponent a_32 = matrix.getValue(2, 1);
|
||||
const PDFColorComponent a_33 = matrix.getValue(2, 2);
|
||||
|
||||
const PDFColorComponent determinant = -a_13* a_22 * a_31 + a_12 * a_23 * a_31 + a_13 * a_21 * a_32 - a_11 * a_23 * a_32 - a_12 * a_21 * a_33 + a_11 * a_22 * a_33;
|
||||
const PDFColorComponent coefficient = !qIsNull(determinant) ? 1.0 / determinant : 0.0;
|
||||
|
||||
PDFColorComponentMatrix_3x3 inversedMatrix { a_22 * a_33 - a_23 * a_32, a_13 * a_32 - a_12 * a_33, a_12 * a_23 - a_13 * a_22,
|
||||
a_23 * a_31 - a_21 * a_33, a_11 * a_33 - a_13 * a_31, a_13 * a_21 - a_11 * a_23,
|
||||
a_21 * a_32 - a_22 * a_31, a_12 * a_31 - a_11 * a_32, a_11 * a_22 - a_12 * a_21 };
|
||||
inversedMatrix.multiplyByFactor(coefficient);
|
||||
return inversedMatrix;
|
||||
}
|
||||
|
||||
QColor PDFDeviceGrayColorSpace::getDefaultColor(const PDFCMS* cms, RenderingIntent intent, PDFRenderErrorReporter* reporter) const
|
||||
{
|
||||
return getColor(PDFColor(0.0f), cms, intent, reporter, true);
|
||||
|
@ -149,6 +186,23 @@ void PDFDeviceCMYKColorSpace::fillRGBBuffer(const std::vector<float>& colors, un
|
|||
}
|
||||
}
|
||||
|
||||
bool PDFAbstractColorSpace::isBlendColorSpace() const
|
||||
{
|
||||
switch (getColorSpace())
|
||||
{
|
||||
case pdf::PDFAbstractColorSpace::ColorSpace::DeviceGray:
|
||||
case pdf::PDFAbstractColorSpace::ColorSpace::DeviceRGB:
|
||||
case pdf::PDFAbstractColorSpace::ColorSpace::DeviceCMYK:
|
||||
case pdf::PDFAbstractColorSpace::ColorSpace::CalGray:
|
||||
case pdf::PDFAbstractColorSpace::ColorSpace::CalRGB:
|
||||
case pdf::PDFAbstractColorSpace::ColorSpace::ICCBased:
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
QImage PDFAbstractColorSpace::getImage(const PDFImageData& imageData,
|
||||
const PDFImageData& softMask,
|
||||
const PDFCMS* cms,
|
||||
|
@ -582,6 +636,227 @@ PDFColor PDFAbstractColorSpace::mixColors(const PDFColor& color1, const PDFColor
|
|||
return result;
|
||||
}
|
||||
|
||||
bool PDFAbstractColorSpace::transform(const PDFAbstractColorSpace* source,
|
||||
const PDFAbstractColorSpace* target,
|
||||
const PDFCMS* cms,
|
||||
RenderingIntent intent,
|
||||
const PDFColorBuffer input,
|
||||
PDFColorBuffer output,
|
||||
PDFRenderErrorReporter* reporter)
|
||||
{
|
||||
Q_ASSERT(source);
|
||||
Q_ASSERT(target);
|
||||
Q_ASSERT(cms);
|
||||
Q_ASSERT(target->isBlendColorSpace());
|
||||
Q_ASSERT(input.size() % source->getColorComponentCount() == 0);
|
||||
|
||||
if (source->equals(target))
|
||||
{
|
||||
// Just copy input buffer to output buffer
|
||||
Q_ASSERT(input.size() == output.size());
|
||||
std::copy(input.begin(), input.end(), output.begin());
|
||||
return true;
|
||||
}
|
||||
|
||||
// We will use following algorithm to transform colors:
|
||||
// 1. Determine source color space type for cms,
|
||||
// and adjust colors to this color space type
|
||||
// 2. Prepare work output buffer of target size (can have
|
||||
// different size than real output buffer)
|
||||
// 3. Transform colors using CMS
|
||||
// 4. Transform output color buffer to target color buffer
|
||||
|
||||
PDFCMS::ColorSpaceTransformParams params;
|
||||
std::vector<PDFColorComponent> transformedInputColorsVector;
|
||||
PDFColorBuffer transformedInput = input;
|
||||
|
||||
switch (source->getColorSpace())
|
||||
{
|
||||
case ColorSpace::DeviceGray:
|
||||
params.sourceType = PDFCMS::ColorSpaceType::DeviceGray;
|
||||
break;
|
||||
|
||||
case ColorSpace::DeviceRGB:
|
||||
params.sourceType = PDFCMS::ColorSpaceType::DeviceRGB;
|
||||
break;
|
||||
|
||||
case ColorSpace::DeviceCMYK:
|
||||
params.sourceType = PDFCMS::ColorSpaceType::DeviceCMYK;
|
||||
break;
|
||||
|
||||
case ColorSpace::CalGray:
|
||||
{
|
||||
params.sourceType = PDFCMS::ColorSpaceType::XYZ;
|
||||
|
||||
// Transform gray to XYZ
|
||||
const PDFCalGrayColorSpace* calGrayColorSpace = static_cast<const PDFCalGrayColorSpace*>(source);
|
||||
const PDFColorComponent gamma = calGrayColorSpace->getGamma();
|
||||
|
||||
transformedInputColorsVector.resize(input.size() * 3, 0.0f);
|
||||
auto it = transformedInputColorsVector.begin();
|
||||
for (PDFColorComponent gray : input)
|
||||
{
|
||||
const PDFColorComponent A = clip01(gray);
|
||||
const PDFColorComponent xyzColor = std::powf(A, gamma);
|
||||
*it++ = xyzColor;
|
||||
*it++ = xyzColor;
|
||||
*it++ = xyzColor;
|
||||
}
|
||||
Q_ASSERT(it == transformedInputColorsVector.end());
|
||||
|
||||
transformedInput = PDFColorBuffer(transformedInputColorsVector.data(), transformedInputColorsVector.size());
|
||||
break;
|
||||
}
|
||||
|
||||
case ColorSpace::CalRGB:
|
||||
{
|
||||
params.sourceType = PDFCMS::ColorSpaceType::XYZ;
|
||||
|
||||
const PDFCalRGBColorSpace* calRGBColorSpace = static_cast<const PDFCalRGBColorSpace*>(source);
|
||||
const PDFColor3 gamma = calRGBColorSpace->getGamma();
|
||||
const PDFColorComponentMatrix_3x3 matrix = calRGBColorSpace->getMatrix();
|
||||
|
||||
transformedInputColorsVector.resize(input.size(), 0.0f);
|
||||
auto it = transformedInputColorsVector.begin();
|
||||
|
||||
for (auto sourceIt = input.cbegin(); sourceIt != input.cend(); sourceIt = std::next(sourceIt, 3))
|
||||
{
|
||||
const PDFColor3 ABC = { };
|
||||
ABC[0] = *sourceIt;
|
||||
ABC[1] = *std::next(sourceIt, 1);
|
||||
ABC[2] = *std::next(sourceIt, 2);
|
||||
ABC = colorPowerByFactors(ABC, gamma);
|
||||
|
||||
const PDFColor3 XYZ = matrix * ABC;
|
||||
*it++ = XYZ[0];
|
||||
*it++ = XYZ[1];
|
||||
*it++ = XYZ[2];
|
||||
}
|
||||
Q_ASSERT(it == transformedInputColorsVector.end());
|
||||
|
||||
transformedInput = PDFColorBuffer(transformedInputColorsVector.data(), transformedInputColorsVector.size());
|
||||
break;
|
||||
}
|
||||
|
||||
case ColorSpace::Lab:
|
||||
{
|
||||
params.sourceType = PDFCMS::ColorSpaceType::XYZ;
|
||||
|
||||
const PDFLabColorSpace* labColorSpace = static_cast<const PDFLabColorSpace*>(source);
|
||||
const PDFColor aMin = labColorSpace->getAMin();
|
||||
const PDFColor aMax = labColorSpace->getAMax();
|
||||
const PDFColor bMin = labColorSpace->getBMin();
|
||||
const PDFColor bMax = labColorSpace->getBMax();
|
||||
|
||||
transformedInputColorsVector.resize(input.size(), 0.0f);
|
||||
auto it = transformedInputColorsVector.begin();
|
||||
|
||||
for (auto sourceIt = input.cbegin(); sourceIt != input.cend(); sourceIt = std::next(sourceIt, 3))
|
||||
{
|
||||
PDFColorComponent LStar = qBound(0.0, interpolate(*sourceIt, 0.0, 1.0, 0.0, 100.0), 100.0);
|
||||
PDFColorComponent aStar = qBound<PDFColorComponent>(aMin, interpolate(*std::next(sourceIt, 1), 0.0, 1.0, aMin, aMax), aMax);
|
||||
PDFColorComponent bStar = qBound<PDFColorComponent>(bMin, interpolate(*std::next(sourceIt, 2), 0.0, 1.0, bMin, bMax), bMax);
|
||||
|
||||
const PDFColorComponent param1 = (LStar + 16.0f) / 116.0f;
|
||||
const PDFColorComponent param2 = aStar / 500.0f;
|
||||
const PDFColorComponent param3 = bStar / 200.0f;
|
||||
|
||||
const PDFColorComponent L = param1 + param2;
|
||||
const PDFColorComponent M = param1;
|
||||
const PDFColorComponent N = param1 - param3;
|
||||
|
||||
auto g = [](PDFColorComponent x) -> PDFColorComponent
|
||||
{
|
||||
if (x >= 6.0f / 29.0f)
|
||||
{
|
||||
return x * x * x;
|
||||
}
|
||||
else
|
||||
{
|
||||
return (108.0f / 841.0f) * (x - 4.0f / 29.0f);
|
||||
}
|
||||
};
|
||||
|
||||
const PDFColorComponent gL = g(L);
|
||||
const PDFColorComponent gM = g(M);
|
||||
const PDFColorComponent gN = g(N);
|
||||
|
||||
*it++ = gL;
|
||||
*it++ = gM;
|
||||
*it++ = gN;
|
||||
}
|
||||
Q_ASSERT(it == transformedInputColorsVector.end());
|
||||
|
||||
transformedInput = PDFColorBuffer(transformedInputColorsVector.data(), transformedInputColorsVector.size());
|
||||
break;
|
||||
}
|
||||
|
||||
case ColorSpace::ICCBased:
|
||||
{
|
||||
const PDFICCBasedColorSpace* iccBasedColorSpace = static_cast<const PDFICCBasedColorSpace*>(source);
|
||||
|
||||
params.sourceType = PDFCMS::ColorSpaceType::ICC;
|
||||
params.sourceIccId = iccBasedColorSpace->getIccProfileDataChecksum();
|
||||
params.sourceIccData = iccBasedColorSpace->getIccProfileData();
|
||||
|
||||
size_t colorComponentCount = iccBasedColorSpace->getColorComponentCount();
|
||||
const PDFICCBasedColorSpace::Ranges& ranges = iccBasedColorSpace->getRange();
|
||||
|
||||
transformedInputColorsVector.resize(input.size(), 0.0f);
|
||||
auto outputIt = transformedInputColorsVector.begin();
|
||||
for (auto inputIt = input.cbegin(); inputIt != input.cend();)
|
||||
{
|
||||
for (size_t i = 0; i < colorComponentCount; ++i)
|
||||
{
|
||||
const size_t imin = 2 * i + 0;
|
||||
const size_t imax = 2 * i + 1;
|
||||
*outputIt++ = qBound(ranges[imin], *inputIt++, ranges[imax]);
|
||||
}
|
||||
}
|
||||
|
||||
transformedInput = PDFColorBuffer(transformedInputColorsVector.data(), transformedInputColorsVector.size());
|
||||
break;
|
||||
}
|
||||
|
||||
case ColorSpace::Indexed:
|
||||
{
|
||||
const PDFIndexedColorSpace* indexedColorSpace = static_cast<const PDFIndexedColorSpace*>(source);
|
||||
|
||||
PDFColorSpacePointer baseColorSpace = indexedColorSpace->getBaseColorSpace();
|
||||
std::vector<PDFColorComponent> transformedToBaseColorSpaceInput = indexedColorSpace->transformColorsToBaseColorSpace(input);
|
||||
PDFColorBuffer transformedInputBuffer(transformedToBaseColorSpaceInput.data(), transformedToBaseColorSpaceInput.size());
|
||||
return transform(baseColorSpace.data(), target, cms, intent, transformedInputBuffer, output, reporter);
|
||||
}
|
||||
|
||||
case ColorSpace::Separation:
|
||||
{
|
||||
const PDFSeparationColorSpace* separationColorSpace = static_cast<const PDFSeparationColorSpace*>(source);
|
||||
|
||||
PDFColorSpacePointer alternateColorSpace = separationColorSpace->getAlternateColorSpace();
|
||||
std::vector<PDFColorComponent> transformedToBaseColorSpaceInput = separationColorSpace->transformColorsToBaseColorSpace(input);
|
||||
PDFColorBuffer transformedInputBuffer(transformedToBaseColorSpaceInput.data(), transformedToBaseColorSpaceInput.size());
|
||||
return transform(alternateColorSpace.data(), target, cms, intent, transformedInputBuffer, output, reporter);
|
||||
}
|
||||
|
||||
case ColorSpace::DeviceN:
|
||||
{
|
||||
const PDFDeviceNColorSpace* separationColorSpace = static_cast<const PDFDeviceNColorSpace*>(source);
|
||||
|
||||
PDFColorSpacePointer alternateColorSpace = separationColorSpace->getAlternateColorSpace();
|
||||
std::vector<PDFColorComponent> transformedToBaseColorSpaceInput = separationColorSpace->transformColorsToBaseColorSpace(input);
|
||||
PDFColorBuffer transformedInputBuffer(transformedToBaseColorSpaceInput.data(), transformedToBaseColorSpaceInput.size());
|
||||
return transform(alternateColorSpace.data(), target, cms, intent, transformedInputBuffer, output, reporter);
|
||||
}
|
||||
|
||||
case ColorSpace::Pattern:
|
||||
return false;
|
||||
|
||||
default:
|
||||
Q_ASSERT(false);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
PDFColorSpacePointer PDFAbstractColorSpace::createColorSpaceImpl(const PDFDictionary* colorSpaceDictionary,
|
||||
const PDFDocument* document,
|
||||
const PDFObject& colorSpace,
|
||||
|
@ -762,7 +1037,6 @@ PDFColor3 PDFAbstractColorSpace::convertXYZtoRGB(const PDFColor3& xyzColor)
|
|||
return matrixXYZtoRGB * xyzColor;
|
||||
}
|
||||
|
||||
|
||||
QColor PDFXYZColorSpace::getDefaultColor(const PDFCMS* cms, RenderingIntent intent, PDFRenderErrorReporter* reporter) const
|
||||
{
|
||||
PDFColor color;
|
||||
|
@ -926,9 +1200,26 @@ PDFColorSpacePointer PDFCalRGBColorSpace::createCalRGBColorSpace(const PDFDocume
|
|||
loader.readNumberArrayFromDictionary(dictionary, CAL_GAMMA, gamma.begin(), gamma.end());
|
||||
loader.readNumberArrayFromDictionary(dictionary, CAL_MATRIX, matrix.begin(), matrix.end());
|
||||
|
||||
matrix.transpose();
|
||||
|
||||
return PDFColorSpacePointer(new PDFCalRGBColorSpace(whitePoint, blackPoint, gamma, matrix));
|
||||
}
|
||||
|
||||
PDFColor3 PDFCalRGBColorSpace::getBlackPoint() const
|
||||
{
|
||||
return m_blackPoint;
|
||||
}
|
||||
|
||||
PDFColor3 PDFCalRGBColorSpace::getGamma() const
|
||||
{
|
||||
return m_gamma;
|
||||
}
|
||||
|
||||
const PDFColorComponentMatrix_3x3& PDFCalRGBColorSpace::getMatrix() const
|
||||
{
|
||||
return m_matrix;
|
||||
}
|
||||
|
||||
PDFLabColorSpace::PDFLabColorSpace(PDFColor3 whitePoint,
|
||||
PDFColor3 blackPoint,
|
||||
PDFColorComponent aMin,
|
||||
|
@ -1071,6 +1362,31 @@ PDFColorSpacePointer PDFLabColorSpace::createLabColorSpace(const PDFDocument* do
|
|||
return PDFColorSpacePointer(new PDFLabColorSpace(whitePoint, blackPoint, minMax[0], minMax[1], minMax[2], minMax[3]));
|
||||
}
|
||||
|
||||
PDFColorComponent PDFLabColorSpace::getAMin() const
|
||||
{
|
||||
return m_aMin;
|
||||
}
|
||||
|
||||
PDFColorComponent PDFLabColorSpace::getAMax() const
|
||||
{
|
||||
return m_aMax;
|
||||
}
|
||||
|
||||
PDFColorComponent PDFLabColorSpace::getBMin() const
|
||||
{
|
||||
return m_bMin;
|
||||
}
|
||||
|
||||
PDFColorComponent PDFLabColorSpace::getBMax() const
|
||||
{
|
||||
return m_bMax;
|
||||
}
|
||||
|
||||
PDFColor3 PDFLabColorSpace::getBlackPoint() const
|
||||
{
|
||||
return m_blackPoint;
|
||||
}
|
||||
|
||||
PDFICCBasedColorSpace::PDFICCBasedColorSpace(PDFColorSpacePointer alternateColorSpace, Ranges range, QByteArray iccProfileData, PDFObjectReference metadata) :
|
||||
m_alternateColorSpace(qMove(alternateColorSpace)),
|
||||
m_range(range),
|
||||
|
@ -1213,6 +1529,21 @@ PDFColorSpacePointer PDFICCBasedColorSpace::createICCBasedColorSpace(const PDFDi
|
|||
return PDFColorSpacePointer(new PDFICCBasedColorSpace(qMove(alternateColorSpace), ranges, qMove(iccProfileData), loader.readReferenceFromDictionary(dictionary, "Metadata")));
|
||||
}
|
||||
|
||||
const PDFICCBasedColorSpace::Ranges& PDFICCBasedColorSpace::getRange() const
|
||||
{
|
||||
return m_range;
|
||||
}
|
||||
|
||||
const QByteArray& PDFICCBasedColorSpace::getIccProfileData() const
|
||||
{
|
||||
return m_iccProfileData;
|
||||
}
|
||||
|
||||
const QByteArray& PDFICCBasedColorSpace::getIccProfileDataChecksum() const
|
||||
{
|
||||
return m_iccProfileDataChecksum;
|
||||
}
|
||||
|
||||
PDFIndexedColorSpace::PDFIndexedColorSpace(PDFColorSpacePointer baseColorSpace, QByteArray&& colors, int maxValue) :
|
||||
m_baseColorSpace(qMove(baseColorSpace)),
|
||||
m_colors(qMove(colors)),
|
||||
|
@ -1409,6 +1740,39 @@ PDFColorSpacePointer PDFIndexedColorSpace::createIndexedColorSpace(const PDFDict
|
|||
return PDFColorSpacePointer(new PDFIndexedColorSpace(qMove(baseColorSpace), qMove(colors), maxValue));
|
||||
}
|
||||
|
||||
PDFColorSpacePointer PDFIndexedColorSpace::getBaseColorSpace() const
|
||||
{
|
||||
return m_baseColorSpace;
|
||||
}
|
||||
|
||||
std::vector<PDFColorComponent> PDFIndexedColorSpace::transformColorsToBaseColorSpace(const PDFColorBuffer buffer) const
|
||||
{
|
||||
const std::size_t colorComponentCount = m_baseColorSpace->getColorComponentCount();
|
||||
std::vector<PDFColorComponent> result(buffer.size() * colorComponentCount, 0.0f);
|
||||
|
||||
auto outputIt = result.begin();
|
||||
for (PDFColorComponent input : buffer)
|
||||
{
|
||||
const int colorIndex = qBound(MIN_VALUE, static_cast<int>(input), m_maxValue);
|
||||
const int byteOffset = colorIndex * colorComponentCount;
|
||||
|
||||
// We must point into the array. Check first and last component.
|
||||
Q_ASSERT(byteOffset + colorComponentCount - 1 < m_colors.size());
|
||||
|
||||
const char* bytePointer = m_colors.constData() + byteOffset;
|
||||
|
||||
for (int i = 0; i < colorComponentCount; ++i)
|
||||
{
|
||||
const unsigned char value = *bytePointer++;
|
||||
const PDFColorComponent component = static_cast<PDFColorComponent>(value) / 255.0f;
|
||||
*outputIt++ = component;
|
||||
}
|
||||
}
|
||||
Q_ASSERT(outputIt == result.cend());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
PDFSeparationColorSpace::PDFSeparationColorSpace(QByteArray&& colorName, PDFColorSpacePointer alternateColorSpace, PDFFunctionPtr tintTransform) :
|
||||
m_colorName(qMove(colorName)),
|
||||
m_alternateColorSpace(qMove(alternateColorSpace)),
|
||||
|
@ -1472,6 +1836,38 @@ size_t PDFSeparationColorSpace::getColorComponentCount() const
|
|||
return 1;
|
||||
}
|
||||
|
||||
std::vector<PDFColorComponent> PDFSeparationColorSpace::transformColorsToBaseColorSpace(const PDFColorBuffer buffer) const
|
||||
{
|
||||
const std::size_t colorComponentCount = m_alternateColorSpace->getColorComponentCount();
|
||||
std::vector<PDFColorComponent> result(buffer.size() * colorComponentCount, 0.0f);
|
||||
|
||||
std::vector<double> outputColor;
|
||||
outputColor.resize(colorComponentCount, 0.0);
|
||||
|
||||
auto outputIt = result.begin();
|
||||
for (PDFColorComponent input : buffer)
|
||||
{
|
||||
// Input value
|
||||
double tint = input;
|
||||
|
||||
if (m_isAll)
|
||||
{
|
||||
const double inversedTint = qBound(0.0, 1.0 - tint, 1.0);
|
||||
std::fill(outputIt, outputIt + colorComponentCount, inversedTint);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_tintTransform->apply(&tint, &tint + 1, outputColor.data(), outputColor.data() + outputColor.size());
|
||||
std::copy(outputColor.cbegin(), outputColor.cend(), outputIt);
|
||||
}
|
||||
|
||||
outputIt = std::next(outputIt, colorComponentCount);
|
||||
}
|
||||
Q_ASSERT(outputIt == result.cend());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
PDFColorSpacePointer PDFSeparationColorSpace::createSeparationColorSpace(const PDFDictionary* colorSpaceDictionary,
|
||||
const PDFDocument* document,
|
||||
const PDFArray* array,
|
||||
|
@ -1504,6 +1900,16 @@ PDFColorSpacePointer PDFSeparationColorSpace::createSeparationColorSpace(const P
|
|||
return PDFColorSpacePointer(new PDFSeparationColorSpace(qMove(colorName), qMove(alternateColorSpace), qMove(tintTransform)));
|
||||
}
|
||||
|
||||
PDFColorSpacePointer PDFSeparationColorSpace::getAlternateColorSpace() const
|
||||
{
|
||||
return m_alternateColorSpace;
|
||||
}
|
||||
|
||||
const QByteArray& PDFSeparationColorSpace::getColorName() const
|
||||
{
|
||||
return m_colorName;
|
||||
}
|
||||
|
||||
const unsigned char* PDFImageData::getRow(unsigned int rowIndex) const
|
||||
{
|
||||
const unsigned char* data = reinterpret_cast<const unsigned char*>(m_data.constData());
|
||||
|
@ -1612,6 +2018,34 @@ size_t PDFDeviceNColorSpace::getColorComponentCount() const
|
|||
return m_colorants.size();
|
||||
}
|
||||
|
||||
std::vector<PDFColorComponent> PDFDeviceNColorSpace::transformColorsToBaseColorSpace(const PDFColorBuffer buffer) const
|
||||
{
|
||||
std::vector<PDFColorComponent> result;
|
||||
|
||||
const std::size_t colorantCount = getColorComponentCount();
|
||||
if (colorantCount > 0)
|
||||
{
|
||||
const std::size_t inputColorCount = buffer.size() / colorantCount;
|
||||
const std::size_t alternateColorSpaceComponentCount = m_alternateColorSpace->getColorComponentCount();
|
||||
result.resize(inputColorCount * alternateColorSpaceComponentCount, 0.0f);
|
||||
|
||||
std::vector<double> inputColor(colorantCount, 0.0);
|
||||
std::vector<double> outputColor(alternateColorSpaceComponentCount, 0.0);
|
||||
|
||||
auto outputIt = result.begin();
|
||||
for (auto it = buffer.begin(); it != buffer.end(); it = std::next(it, colorantCount))
|
||||
{
|
||||
std::copy(it, it + colorantCount, inputColor.begin());
|
||||
m_tintTransform->apply(inputColor.data(), inputColor.data() + inputColor.size(), outputColor.data(), outputColor.data() + outputColor.size());
|
||||
std::copy(outputColor.cbegin(), outputColor.cend(), outputIt);
|
||||
outputIt = std::next(outputIt, alternateColorSpaceComponentCount);
|
||||
}
|
||||
Q_ASSERT(outputIt == result.cend());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
PDFColorSpacePointer PDFDeviceNColorSpace::createDeviceNColorSpace(const PDFDictionary* colorSpaceDictionary,
|
||||
const PDFDocument* document,
|
||||
const PDFArray* array,
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
#include "pdfflatarray.h"
|
||||
#include "pdffunction.h"
|
||||
#include "pdfutils.h"
|
||||
|
||||
#include <QColor>
|
||||
#include <QImage>
|
||||
|
@ -43,6 +44,7 @@ class PDFRenderErrorReporter;
|
|||
using PDFColorComponent = float;
|
||||
using PDFColor = PDFFlatArray<PDFColorComponent, 4>;
|
||||
using PDFColorSpacePointer = QSharedPointer<PDFAbstractColorSpace>;
|
||||
using PDFColorBuffer = PDFBuffer<PDFColorComponent>;
|
||||
|
||||
static constexpr const int COLOR_SPACE_MAX_LEVEL_OF_RECURSION = 12;
|
||||
|
||||
|
@ -209,6 +211,34 @@ public:
|
|||
return result;
|
||||
}
|
||||
|
||||
inline PDFColorComponent getValue(size_t row, size_t column) const
|
||||
{
|
||||
return m_values[row * Cols + column];
|
||||
}
|
||||
|
||||
void transpose()
|
||||
{
|
||||
Q_ASSERT(Rows == Cols);
|
||||
|
||||
for (size_t row = 0; row < Rows; ++row)
|
||||
{
|
||||
for (size_t column = row; column < Cols; ++column)
|
||||
{
|
||||
const size_t index1 = row * Cols + column;
|
||||
const size_t index2 = column * Cols + row;
|
||||
std::swap(m_values[index1], m_values[index2]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void multiplyByFactor(PDFColorComponent factor)
|
||||
{
|
||||
for (auto it = begin(); it != end(); ++it)
|
||||
{
|
||||
*it *= factor;
|
||||
}
|
||||
}
|
||||
|
||||
inline typename std::array<PDFColorComponent, Rows * Cols>::iterator begin() { return m_values.begin(); }
|
||||
inline typename std::array<PDFColorComponent, Rows * Cols>::iterator end() { return m_values.end(); }
|
||||
|
||||
|
@ -226,6 +256,27 @@ public:
|
|||
explicit PDFAbstractColorSpace() = default;
|
||||
virtual ~PDFAbstractColorSpace() = default;
|
||||
|
||||
enum class ColorSpace
|
||||
{
|
||||
DeviceGray,
|
||||
DeviceRGB,
|
||||
DeviceCMYK,
|
||||
CalGray,
|
||||
CalRGB,
|
||||
Lab,
|
||||
ICCBased,
|
||||
Indexed,
|
||||
Separation,
|
||||
DeviceN,
|
||||
Pattern
|
||||
};
|
||||
|
||||
/// Returns color space identification
|
||||
virtual ColorSpace getColorSpace() const = 0;
|
||||
|
||||
/// Returns true, if this color space can be used for blending
|
||||
bool isBlendColorSpace() const;
|
||||
|
||||
/// Returns default color for the color space
|
||||
virtual QColor getDefaultColor(const PDFCMS* cms, RenderingIntent intent, PDFRenderErrorReporter* reporter) const = 0;
|
||||
|
||||
|
@ -320,6 +371,23 @@ public:
|
|||
/// \param ratio Mixing ratio
|
||||
static PDFColor mixColors(const PDFColor& color1, const PDFColor& color2, PDFReal ratio);
|
||||
|
||||
/// Transforms color from source color space to target color space. Target color space
|
||||
/// must be blend color space.
|
||||
/// \param source Source color space
|
||||
/// \param target Target color space (must be blend color space)
|
||||
/// \param cms Color management system
|
||||
/// \param intent Rendering intent
|
||||
/// \param input Input color buffer
|
||||
/// \param output Output color buffer, must match size of input color buffer
|
||||
/// \param reporter Error reporter
|
||||
static bool transform(const PDFAbstractColorSpace* source,
|
||||
const PDFAbstractColorSpace* target,
|
||||
const PDFCMS* cms,
|
||||
RenderingIntent intent,
|
||||
const PDFColorBuffer input,
|
||||
PDFColorBuffer output,
|
||||
PDFRenderErrorReporter* reporter);
|
||||
|
||||
protected:
|
||||
/// Clips the color component to range [0, 1]
|
||||
static constexpr PDFColorComponent clip01(PDFColorComponent component) { return qBound<PDFColorComponent>(0.0, component, 1.0); }
|
||||
|
@ -426,6 +494,7 @@ public:
|
|||
explicit PDFDeviceGrayColorSpace() = default;
|
||||
virtual ~PDFDeviceGrayColorSpace() = default;
|
||||
|
||||
virtual ColorSpace getColorSpace() const override { return ColorSpace::DeviceGray; }
|
||||
virtual QColor getDefaultColor(const PDFCMS* cms, RenderingIntent intent, PDFRenderErrorReporter* reporter) const override;
|
||||
virtual QColor getColor(const PDFColor& color, const PDFCMS* cms, RenderingIntent intent, PDFRenderErrorReporter* reporter, bool isRange01) const override;
|
||||
virtual size_t getColorComponentCount() const override;
|
||||
|
@ -438,6 +507,7 @@ public:
|
|||
explicit PDFDeviceRGBColorSpace() = default;
|
||||
virtual ~PDFDeviceRGBColorSpace() = default;
|
||||
|
||||
virtual ColorSpace getColorSpace() const override { return ColorSpace::DeviceRGB; }
|
||||
virtual QColor getDefaultColor(const PDFCMS* cms, RenderingIntent intent, PDFRenderErrorReporter* reporter) const override;
|
||||
virtual QColor getColor(const PDFColor& color, const PDFCMS* cms, RenderingIntent intent, PDFRenderErrorReporter* reporter, bool isRange01) const override;
|
||||
virtual size_t getColorComponentCount() const override;
|
||||
|
@ -450,6 +520,7 @@ public:
|
|||
explicit PDFDeviceCMYKColorSpace() = default;
|
||||
virtual ~PDFDeviceCMYKColorSpace() = default;
|
||||
|
||||
virtual ColorSpace getColorSpace() const override { return ColorSpace::DeviceCMYK; }
|
||||
virtual QColor getDefaultColor(const PDFCMS* cms, RenderingIntent intent, PDFRenderErrorReporter* reporter) const override;
|
||||
virtual QColor getColor(const PDFColor& color, const PDFCMS* cms, RenderingIntent intent, PDFRenderErrorReporter* reporter, bool isRange01) const override;
|
||||
virtual size_t getColorComponentCount() const override;
|
||||
|
@ -461,6 +532,8 @@ class PDFXYZColorSpace : public PDFAbstractColorSpace
|
|||
public:
|
||||
virtual QColor getDefaultColor(const PDFCMS* cms, RenderingIntent intent, PDFRenderErrorReporter* reporter) const override;
|
||||
|
||||
const PDFColor3& getWhitePoint() const { return m_whitePoint; }
|
||||
|
||||
protected:
|
||||
explicit PDFXYZColorSpace(PDFColor3 whitePoint);
|
||||
virtual ~PDFXYZColorSpace() = default;
|
||||
|
@ -480,10 +553,14 @@ public:
|
|||
explicit PDFCalGrayColorSpace(PDFColor3 whitePoint, PDFColor3 blackPoint, PDFColorComponent gamma);
|
||||
virtual ~PDFCalGrayColorSpace() = default;
|
||||
|
||||
virtual ColorSpace getColorSpace() const override { return ColorSpace::CalGray; }
|
||||
virtual QColor getColor(const PDFColor& color, const PDFCMS* cms, RenderingIntent intent, PDFRenderErrorReporter* reporter, bool isRange01) const override;
|
||||
virtual size_t getColorComponentCount() const override;
|
||||
virtual void fillRGBBuffer(const std::vector<float>& colors,unsigned char* outputBuffer, RenderingIntent intent, const PDFCMS* cms, PDFRenderErrorReporter* reporter) const override;
|
||||
|
||||
PDFColorComponent getGamma() const { return m_gamma; }
|
||||
PDFColor3 getBlackPoint() const { m_blackPoint; }
|
||||
|
||||
/// Creates CalGray color space from provided values.
|
||||
/// \param document Document
|
||||
/// \param dictionary Dictionary
|
||||
|
@ -500,6 +577,7 @@ public:
|
|||
explicit PDFCalRGBColorSpace(PDFColor3 whitePoint, PDFColor3 blackPoint, PDFColor3 gamma, PDFColorComponentMatrix_3x3 matrix);
|
||||
virtual ~PDFCalRGBColorSpace() = default;
|
||||
|
||||
virtual ColorSpace getColorSpace() const override { return ColorSpace::CalRGB; }
|
||||
virtual QColor getColor(const PDFColor& color, const PDFCMS* cms, RenderingIntent intent, PDFRenderErrorReporter* reporter, bool isRange01) const override;
|
||||
virtual size_t getColorComponentCount() const override;
|
||||
virtual void fillRGBBuffer(const std::vector<float>& colors,unsigned char* outputBuffer, RenderingIntent intent, const PDFCMS* cms, PDFRenderErrorReporter* reporter) const override;
|
||||
|
@ -509,6 +587,10 @@ public:
|
|||
/// \param dictionary Dictionary
|
||||
static PDFColorSpacePointer createCalRGBColorSpace(const PDFDocument* document, const PDFDictionary* dictionary);
|
||||
|
||||
PDFColor3 getBlackPoint() const;
|
||||
PDFColor3 getGamma() const;
|
||||
const PDFColorComponentMatrix_3x3& getMatrix() const;
|
||||
|
||||
private:
|
||||
PDFColor3 m_blackPoint;
|
||||
PDFColor3 m_gamma;
|
||||
|
@ -521,6 +603,7 @@ public:
|
|||
explicit PDFLabColorSpace(PDFColor3 whitePoint, PDFColor3 blackPoint, PDFColorComponent aMin, PDFColorComponent aMax, PDFColorComponent bMin, PDFColorComponent bMax);
|
||||
virtual ~PDFLabColorSpace() = default;
|
||||
|
||||
virtual ColorSpace getColorSpace() const override { return ColorSpace::Lab; }
|
||||
virtual QColor getColor(const PDFColor& color, const PDFCMS* cms, RenderingIntent intent, PDFRenderErrorReporter* reporter, bool isRange01) const override;
|
||||
virtual size_t getColorComponentCount() const override;
|
||||
virtual void fillRGBBuffer(const std::vector<float>& colors,unsigned char* outputBuffer, RenderingIntent intent, const PDFCMS* cms, PDFRenderErrorReporter* reporter) const override;
|
||||
|
@ -530,6 +613,13 @@ public:
|
|||
/// \param dictionary Dictionary
|
||||
static PDFColorSpacePointer createLabColorSpace(const PDFDocument* document, const PDFDictionary* dictionary);
|
||||
|
||||
PDFColorComponent getAMin() const;
|
||||
PDFColorComponent getAMax() const;
|
||||
PDFColorComponent getBMin() const;
|
||||
PDFColorComponent getBMax() const;
|
||||
|
||||
PDFColor3 getBlackPoint() const;
|
||||
|
||||
private:
|
||||
PDFColor3 m_blackPoint;
|
||||
PDFColorComponent m_aMin;
|
||||
|
@ -547,6 +637,7 @@ public:
|
|||
explicit PDFICCBasedColorSpace(PDFColorSpacePointer alternateColorSpace, Ranges range, QByteArray iccProfileData, PDFObjectReference metadata);
|
||||
virtual ~PDFICCBasedColorSpace() = default;
|
||||
|
||||
virtual ColorSpace getColorSpace() const override { return ColorSpace::ICCBased; }
|
||||
virtual QColor getDefaultColor(const PDFCMS* cms, RenderingIntent intent, PDFRenderErrorReporter* reporter) const override;
|
||||
virtual QColor getColor(const PDFColor& color, const PDFCMS* cms, RenderingIntent intent, PDFRenderErrorReporter* reporter, bool isRange01) const override;
|
||||
virtual size_t getColorComponentCount() const override;
|
||||
|
@ -566,6 +657,10 @@ public:
|
|||
int recursion,
|
||||
std::set<QByteArray>& usedNames);
|
||||
|
||||
const Ranges& getRange() const;
|
||||
const QByteArray& getIccProfileData() const;
|
||||
const QByteArray& getIccProfileDataChecksum() const;
|
||||
|
||||
private:
|
||||
PDFColorSpacePointer m_alternateColorSpace;
|
||||
Ranges m_range;
|
||||
|
@ -580,6 +675,7 @@ public:
|
|||
explicit PDFIndexedColorSpace(PDFColorSpacePointer baseColorSpace, QByteArray&& colors, int maxValue);
|
||||
virtual ~PDFIndexedColorSpace() = default;
|
||||
|
||||
virtual ColorSpace getColorSpace() const override { return ColorSpace::Indexed; }
|
||||
virtual QColor getDefaultColor(const PDFCMS* cms, RenderingIntent intent, PDFRenderErrorReporter* reporter) const override;
|
||||
virtual QColor getColor(const PDFColor& color, const PDFCMS* cms, RenderingIntent intent, PDFRenderErrorReporter* reporter, bool isRange01) const override;
|
||||
virtual size_t getColorComponentCount() const override;
|
||||
|
@ -601,6 +697,9 @@ public:
|
|||
int recursion,
|
||||
std::set<QByteArray>& usedNames);
|
||||
|
||||
PDFColorSpacePointer getBaseColorSpace() const;
|
||||
std::vector<PDFColorComponent> transformColorsToBaseColorSpace(const PDFColorBuffer buffer) const;
|
||||
|
||||
private:
|
||||
static constexpr const int MIN_VALUE = 0;
|
||||
static constexpr const int MAX_VALUE = 255;
|
||||
|
@ -616,6 +715,7 @@ public:
|
|||
explicit PDFSeparationColorSpace(QByteArray&& colorName, PDFColorSpacePointer alternateColorSpace, PDFFunctionPtr tintTransform);
|
||||
virtual ~PDFSeparationColorSpace() = default;
|
||||
|
||||
virtual ColorSpace getColorSpace() const override { return ColorSpace::Separation; }
|
||||
virtual QColor getDefaultColor(const PDFCMS* cms, RenderingIntent intent, PDFRenderErrorReporter* reporter) const override;
|
||||
virtual QColor getColor(const PDFColor& color, const PDFCMS* cms, RenderingIntent intent, PDFRenderErrorReporter* reporter, bool isRange01) const override;
|
||||
virtual size_t getColorComponentCount() const override;
|
||||
|
@ -623,6 +723,8 @@ public:
|
|||
bool isNone() const { return m_isNone; }
|
||||
bool isAll() const { return m_isAll; }
|
||||
|
||||
std::vector<PDFColorComponent> transformColorsToBaseColorSpace(const PDFColorBuffer buffer) const;
|
||||
|
||||
/// Creates separation color space from provided values.
|
||||
/// \param colorSpaceDictionary Color space dictionary
|
||||
/// \param document Document
|
||||
|
@ -635,6 +737,9 @@ public:
|
|||
int recursion,
|
||||
std::set<QByteArray>& usedNames);
|
||||
|
||||
PDFColorSpacePointer getAlternateColorSpace() const;
|
||||
const QByteArray& getColorName() const;
|
||||
|
||||
private:
|
||||
QByteArray m_colorName;
|
||||
PDFColorSpacePointer m_alternateColorSpace;
|
||||
|
@ -672,6 +777,7 @@ public:
|
|||
std::vector<QByteArray> processColorSpaceComponents);
|
||||
virtual ~PDFDeviceNColorSpace() = default;
|
||||
|
||||
virtual ColorSpace getColorSpace() const override { return ColorSpace::DeviceN; }
|
||||
virtual QColor getDefaultColor(const PDFCMS* cms, RenderingIntent intent, PDFRenderErrorReporter* reporter) const override;
|
||||
virtual QColor getColor(const PDFColor& color, const PDFCMS* cms, RenderingIntent intent, PDFRenderErrorReporter* reporter, bool isRange01) const override;
|
||||
virtual size_t getColorComponentCount() const override;
|
||||
|
@ -687,6 +793,8 @@ public:
|
|||
const std::vector<QByteArray>& getProcessColorSpaceComponents() const { return m_processColorSpaceComponents; }
|
||||
bool isNone() const { return m_isNone; }
|
||||
|
||||
std::vector<PDFColorComponent> transformColorsToBaseColorSpace(const PDFColorBuffer buffer) const;
|
||||
|
||||
/// Creates DeviceN color space from provided values.
|
||||
/// \param colorSpaceDictionary Color space dictionary
|
||||
/// \param document Document
|
||||
|
@ -723,6 +831,7 @@ public:
|
|||
|
||||
virtual ~PDFPatternColorSpace() override = default;
|
||||
|
||||
virtual ColorSpace getColorSpace() const override { return ColorSpace::Pattern; }
|
||||
virtual QColor getDefaultColor(const PDFCMS* cms, RenderingIntent intent, PDFRenderErrorReporter* reporter) const override;
|
||||
virtual QColor getColor(const PDFColor& color, const PDFCMS* cms, RenderingIntent intent, PDFRenderErrorReporter* reporter, bool isRange01) const override;
|
||||
virtual size_t getColorComponentCount() const override;
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
// Copyright (C) 2020 Jakub Melka
|
||||
//
|
||||
// This file is part of Pdf4Qt.
|
||||
//
|
||||
// Pdf4Qt is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Pdf4Qt is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with Pdf4Qt. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include "pdftransparencyrenderer.h"
|
||||
|
||||
namespace pdf
|
||||
{
|
||||
|
||||
PDFTransparencyRenderer::PDFTransparencyRenderer()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
} // namespace pdf
|
|
@ -0,0 +1,32 @@
|
|||
// Copyright (C) 2020 Jakub Melka
|
||||
//
|
||||
// This file is part of Pdf4Qt.
|
||||
//
|
||||
// Pdf4Qt is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Pdf4Qt is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with Pdf4Qt. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef PDFTRANSPARENCYRENDERER_H
|
||||
#define PDFTRANSPARENCYRENDERER_H
|
||||
|
||||
namespace pdf
|
||||
{
|
||||
|
||||
class PDFTransparencyRenderer
|
||||
{
|
||||
public:
|
||||
PDFTransparencyRenderer();
|
||||
};
|
||||
|
||||
} // namespace pdf
|
||||
|
||||
#endif // PDFTRANSPARENCYRENDERER_H
|
|
@ -500,6 +500,46 @@ static inline bool isFuzzyComparedPointsSame(const QPointF& p1, const QPointF& p
|
|||
return squaredDistance < squaredTolerance;
|
||||
}
|
||||
|
||||
/// View on the array
|
||||
template<typename T>
|
||||
class PDFBuffer
|
||||
{
|
||||
public:
|
||||
using value_type = T;
|
||||
using value_ptr = value_type*;
|
||||
using const_value_type = const value_type;
|
||||
using const_value_ptr = const_value_type*;
|
||||
|
||||
explicit inline PDFBuffer() :
|
||||
m_begin(nullptr),
|
||||
m_end(nullptr)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
explicit inline PDFBuffer(value_ptr value, size_t size) :
|
||||
m_begin(value),
|
||||
m_end(value + size)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
inline value_ptr begin() { return m_begin; }
|
||||
inline value_ptr end() { return m_end; }
|
||||
|
||||
inline const_value_ptr begin() const { return m_begin; }
|
||||
inline const_value_ptr end() const { return m_end; }
|
||||
|
||||
inline const_value_ptr cbegin() const { return m_begin; }
|
||||
inline const_value_ptr cend() const { return m_end; }
|
||||
|
||||
size_t size() const { return m_end - m_begin; }
|
||||
|
||||
private:
|
||||
value_ptr m_begin;
|
||||
value_ptr m_end;
|
||||
};
|
||||
|
||||
/// Storage for result of some operation. Stores, if operation was successful, or not and
|
||||
/// also error message, why operation has failed. Can be converted explicitly to bool.
|
||||
class PDFOperationResult
|
||||
|
|
Loading…
Reference in New Issue