diff options
Diffstat (limited to 'Build/source/libs/poppler/poppler-src/poppler/GfxState.cc')
-rw-r--r-- | Build/source/libs/poppler/poppler-src/poppler/GfxState.cc | 7213 |
1 files changed, 0 insertions, 7213 deletions
diff --git a/Build/source/libs/poppler/poppler-src/poppler/GfxState.cc b/Build/source/libs/poppler/poppler-src/poppler/GfxState.cc deleted file mode 100644 index 956a214bf84..00000000000 --- a/Build/source/libs/poppler/poppler-src/poppler/GfxState.cc +++ /dev/null @@ -1,7213 +0,0 @@ -//======================================================================== -// -// GfxState.cc -// -// Copyright 1996-2003 Glyph & Cog, LLC -// -//======================================================================== - -//======================================================================== -// -// Modified under the Poppler project - http://poppler.freedesktop.org -// -// All changes made under the Poppler project to this file are licensed -// under GPL version 2 or later -// -// Copyright (C) 2005 Kristian Høgsberg <krh@redhat.com> -// Copyright (C) 2006, 2007 Jeff Muizelaar <jeff@infidigm.net> -// Copyright (C) 2006, 2010 Carlos Garcia Campos <carlosgc@gnome.org> -// Copyright (C) 2006-2018 Albert Astals Cid <aacid@kde.org> -// Copyright (C) 2009, 2012 Koji Otani <sho@bbr.jp> -// Copyright (C) 2009, 2011-2016 Thomas Freitag <Thomas.Freitag@alfa.de> -// Copyright (C) 2009 Christian Persch <chpe@gnome.org> -// Copyright (C) 2010 Paweł Wiejacha <pawel.wiejacha@gmail.com> -// Copyright (C) 2010 Christian Feuersänger <cfeuersaenger@googlemail.com> -// Copyright (C) 2011 Andrea Canciani <ranma42@gmail.com> -// Copyright (C) 2012 William Bader <williambader@hotmail.com> -// Copyright (C) 2013 Lu Wang <coolwanglu@gmail.com> -// Copyright (C) 2013 Hib Eris <hib@hiberis.nl> -// Copyright (C) 2013 Fabio D'Urso <fabiodurso@hotmail.it> -// Copyright (C) 2015 Adrian Johnson <ajohnson@redneon.com> -// Copyright (C) 2016 Marek Kasik <mkasik@redhat.com> -// Copyright (C) 2017 Oliver Sander <oliver.sander@tu-dresden.de> -// Copyright (C) 2018 Klarälvdalens Datakonsult AB, a KDAB Group company, <info@kdab.com>. Work sponsored by the LiMux project of the city of Munich -// -// To see a description of the changes please see the Changelog file that -// came with your tarball or type make ChangeLog if you are building from git -// -//======================================================================== - -#include <config.h> - -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - -#include <algorithm> -#include <memory> -#include <stddef.h> -#include <math.h> -#include <string.h> -#include "goo/gmem.h" -#include "Error.h" -#include "Object.h" -#include "Array.h" -#include "Page.h" -#include "Gfx.h" -#include "GfxState.h" -#include "GfxState_helpers.h" -#include "GfxFont.h" -#include "GlobalParams.h" -#include "PopplerCache.h" -#include "OutputDev.h" -#include "splash/SplashTypes.h" - -//------------------------------------------------------------------------ - -// Max depth of nested color spaces. This is used to catch infinite -// loops in the color space object structure. -#define colorSpaceRecursionLimit 8 - -//------------------------------------------------------------------------ - -GBool Matrix::invertTo(Matrix *other) const -{ - const double det_denominator = determinant(); - if (unlikely(det_denominator == 0)) { - *other = {1, 0, 0, 1, 0, 0}; - return gFalse; - } - - const double det = 1 / det_denominator; - other->m[0] = m[3] * det; - other->m[1] = -m[1] * det; - other->m[2] = -m[2] * det; - other->m[3] = m[0] * det; - other->m[4] = (m[2] * m[5] - m[3] * m[4]) * det; - other->m[5] = (m[1] * m[4] - m[0] * m[5]) * det; - - return gTrue; -} - -void Matrix::translate(double tx, double ty) -{ - double x0 = tx*m[0] + ty*m[2] + m[4]; - double y0 = tx*m[1] + ty*m[3] + m[5]; - m[4] = x0; - m[5] = y0; -} - -void Matrix::scale(double sx, double sy) -{ - m[0] *= sx; - m[1] *= sx; - m[2] *= sy; - m[3] *= sy; -} - -void Matrix::transform(double x, double y, double *tx, double *ty) const -{ - double temp_x, temp_y; - - temp_x = m[0] * x + m[2] * y + m[4]; - temp_y = m[1] * x + m[3] * y + m[5]; - - *tx = temp_x; - *ty = temp_y; -} - -// Matrix norm, taken from _cairo_matrix_transformed_circle_major_axis -double Matrix::norm() const -{ - double f, g, h, i, j; - - i = m[0]*m[0] + m[1]*m[1]; - j = m[2]*m[2] + m[3]*m[3]; - - f = 0.5 * (i + j); - g = 0.5 * (i - j); - h = m[0]*m[2] + m[1]*m[3]; - - return sqrt (f + hypot (g, h)); -} - -//------------------------------------------------------------------------ - -struct GfxBlendModeInfo { - const char *name; - GfxBlendMode mode; -}; - -static const GfxBlendModeInfo gfxBlendModeNames[] = { - { "Normal", gfxBlendNormal }, - { "Compatible", gfxBlendNormal }, - { "Multiply", gfxBlendMultiply }, - { "Screen", gfxBlendScreen }, - { "Overlay", gfxBlendOverlay }, - { "Darken", gfxBlendDarken }, - { "Lighten", gfxBlendLighten }, - { "ColorDodge", gfxBlendColorDodge }, - { "ColorBurn", gfxBlendColorBurn }, - { "HardLight", gfxBlendHardLight }, - { "SoftLight", gfxBlendSoftLight }, - { "Difference", gfxBlendDifference }, - { "Exclusion", gfxBlendExclusion }, - { "Hue", gfxBlendHue }, - { "Saturation", gfxBlendSaturation }, - { "Color", gfxBlendColor }, - { "Luminosity", gfxBlendLuminosity } -}; - -#define nGfxBlendModeNames \ - ((int)((sizeof(gfxBlendModeNames) / sizeof(GfxBlendModeInfo)))) - -//------------------------------------------------------------------------ -// -// NB: This must match the GfxColorSpaceMode enum defined in -// GfxState.h -static const char *gfxColorSpaceModeNames[] = { - "DeviceGray", - "CalGray", - "DeviceRGB", - "CalRGB", - "DeviceCMYK", - "Lab", - "ICCBased", - "Indexed", - "Separation", - "DeviceN", - "Pattern" -}; - -#define nGfxColorSpaceModes ((sizeof(gfxColorSpaceModeNames) / sizeof(char *))) - -#ifdef USE_CMS - -static const std::map<unsigned int, unsigned int>::size_type CMSCACHE_LIMIT = 2048; - -#include <lcms2.h> -#define LCMS_FLAGS cmsFLAGS_NOOPTIMIZE | cmsFLAGS_BLACKPOINTCOMPENSATION - -#define COLOR_PROFILE_DIR "/ColorProfiles/" -#define GLOBAL_COLOR_PROFILE_DIR POPPLER_DATADIR COLOR_PROFILE_DIR - -void GfxColorTransform::doTransform(void *in, void *out, unsigned int size) { - cmsDoTransform(transform, in, out, size); -} - -// transformA should be a cmsHTRANSFORM -GfxColorTransform::GfxColorTransform(void *transformA, int cmsIntentA, unsigned int inputPixelTypeA, unsigned int transformPixelTypeA) { - transform = transformA; - refCount = 1; - cmsIntent = cmsIntentA; - inputPixelType = inputPixelTypeA; - transformPixelType = transformPixelTypeA; -} - -GfxColorTransform::~GfxColorTransform() { - cmsDeleteTransform(transform); -} - -void GfxColorTransform::ref() { - refCount++; -} - -unsigned int GfxColorTransform::unref() { - return --refCount; -} - -static cmsHPROFILE RGBProfile = nullptr; -static GooString *displayProfileName = nullptr; // display profile file Name -static cmsHPROFILE displayProfile = nullptr; // display profile -static unsigned int displayPixelType = 0; -static GfxColorTransform *XYZ2DisplayTransform = nullptr; - -// convert color space signature to cmsColor type -static unsigned int getCMSColorSpaceType(cmsColorSpaceSignature cs); -static unsigned int getCMSNChannels(cmsColorSpaceSignature cs); -static cmsHPROFILE loadColorProfile(const char *fileName); - -void GfxColorSpace::setDisplayProfile(void *displayProfileA) { - displayProfile = displayProfileA; - if (displayProfile != nullptr) { - cmsHTRANSFORM transform; - unsigned int nChannels; - - displayPixelType = getCMSColorSpaceType(cmsGetColorSpace(displayProfile)); - nChannels = getCMSNChannels(cmsGetColorSpace(displayProfile)); - // create transform from XYZ - cmsHPROFILE XYZProfile = cmsCreateXYZProfile(); - if ((transform = cmsCreateTransform(XYZProfile, TYPE_XYZ_DBL, - displayProfile, - COLORSPACE_SH(displayPixelType) | - CHANNELS_SH(nChannels) | BYTES_SH(1), - INTENT_RELATIVE_COLORIMETRIC,LCMS_FLAGS)) == nullptr) { - error(errSyntaxWarning, -1, "Can't create Lab transform"); - } else { - XYZ2DisplayTransform = new GfxColorTransform(transform, INTENT_RELATIVE_COLORIMETRIC, PT_XYZ, displayPixelType); - } - cmsCloseProfile(XYZProfile); - } -} - -void GfxColorSpace::setDisplayProfileName(GooString *name) { - displayProfileName = name->copy(); -} - -cmsHPROFILE GfxColorSpace::getRGBProfile() { - return RGBProfile; -} - -cmsHPROFILE GfxColorSpace::getDisplayProfile() { - return displayProfile; -} - -#endif - -//------------------------------------------------------------------------ -// GfxColorSpace -//------------------------------------------------------------------------ - -GfxColorSpace::GfxColorSpace() { - overprintMask = 0x0f; - mapping = nullptr; -} - -GfxColorSpace::~GfxColorSpace() { -} - -GfxColorSpace *GfxColorSpace::parse(GfxResources *res, Object *csObj, OutputDev *out, GfxState *state, int recursion) { - GfxColorSpace *cs; - Object obj1; - - if (recursion > colorSpaceRecursionLimit) { - error(errSyntaxError, -1, "Loop detected in color space objects"); - return nullptr; - } - - cs = nullptr; - if (csObj->isName()) { - if (csObj->isName("DeviceGray") || csObj->isName("G")) { - if (res != nullptr) { - Object objCS = res->lookupColorSpace("DefaultGray"); - if (objCS.isNull()) { - cs = new GfxDeviceGrayColorSpace(); - } else { - cs = GfxColorSpace::parse(nullptr, &objCS, out, state); - } - } else { - cs = new GfxDeviceGrayColorSpace(); - } - } else if (csObj->isName("DeviceRGB") || csObj->isName("RGB")) { - if (res != nullptr) { - Object objCS = res->lookupColorSpace("DefaultRGB"); - if (objCS.isNull()) { - cs = new GfxDeviceRGBColorSpace(); - } else { - cs = GfxColorSpace::parse(nullptr, &objCS, out, state); - } - } else { - cs = new GfxDeviceRGBColorSpace(); - } - } else if (csObj->isName("DeviceCMYK") || csObj->isName("CMYK")) { - if (res != nullptr) { - Object objCS = res->lookupColorSpace("DefaultCMYK"); - if (objCS.isNull()) { - cs = new GfxDeviceCMYKColorSpace(); - } else { - cs = GfxColorSpace::parse(nullptr, &objCS, out, state); - } - } else { - cs = new GfxDeviceCMYKColorSpace(); - } - } else if (csObj->isName("Pattern")) { - cs = new GfxPatternColorSpace(nullptr); - } else { - error(errSyntaxWarning, -1, "Bad color space '{0:s}'", csObj->getName()); - } - } else if (csObj->isArray() && csObj->arrayGetLength() > 0) { - obj1 = csObj->arrayGet(0); - if (obj1.isName("DeviceGray") || obj1.isName("G")) { - if (res != nullptr) { - Object objCS = res->lookupColorSpace("DefaultGray"); - if (objCS.isNull()) { - cs = new GfxDeviceGrayColorSpace(); - } else { - cs = GfxColorSpace::parse(nullptr, &objCS, out, state); - } - } else { - cs = new GfxDeviceGrayColorSpace(); - } - } else if (obj1.isName("DeviceRGB") || obj1.isName("RGB")) { - if (res != nullptr) { - Object objCS = res->lookupColorSpace("DefaultRGB"); - if (objCS.isNull()) { - cs = new GfxDeviceRGBColorSpace(); - } else { - cs = GfxColorSpace::parse(nullptr, &objCS, out, state); - } - } else { - cs = new GfxDeviceRGBColorSpace(); - } - } else if (obj1.isName("DeviceCMYK") || obj1.isName("CMYK")) { - if (res != nullptr) { - Object objCS = res->lookupColorSpace("DefaultCMYK"); - if (objCS.isNull()) { - cs = new GfxDeviceCMYKColorSpace(); - } else { - cs = GfxColorSpace::parse(nullptr, &objCS, out, state); - } - } else { - cs = new GfxDeviceCMYKColorSpace(); - } - } else if (obj1.isName("CalGray")) { - cs = GfxCalGrayColorSpace::parse(csObj->getArray(), state); - } else if (obj1.isName("CalRGB")) { - cs = GfxCalRGBColorSpace::parse(csObj->getArray(), state); - } else if (obj1.isName("Lab")) { - cs = GfxLabColorSpace::parse(csObj->getArray(), state); - } else if (obj1.isName("ICCBased")) { - cs = GfxICCBasedColorSpace::parse(csObj->getArray(), out, state, recursion); - } else if (obj1.isName("Indexed") || obj1.isName("I")) { - cs = GfxIndexedColorSpace::parse(res, csObj->getArray(), out, state, recursion); - } else if (obj1.isName("Separation")) { - cs = GfxSeparationColorSpace::parse(res, csObj->getArray(), out, state, recursion); - } else if (obj1.isName("DeviceN")) { - cs = GfxDeviceNColorSpace::parse(res, csObj->getArray(), out, state, recursion); - } else if (obj1.isName("Pattern")) { - cs = GfxPatternColorSpace::parse(res, csObj->getArray(), out, state, recursion); - } else { - error(errSyntaxWarning, -1, "Bad color space"); - } - } else if (csObj->isDict()) { - obj1 = csObj->dictLookup("ColorSpace"); - if (obj1.isName("DeviceGray")) { - if (res != nullptr) { - Object objCS = res->lookupColorSpace("DefaultGray"); - if (objCS.isNull()) { - cs = new GfxDeviceGrayColorSpace(); - } else { - cs = GfxColorSpace::parse(nullptr, &objCS, out, state); - } - } else { - cs = new GfxDeviceGrayColorSpace(); - } - } else if (obj1.isName("DeviceRGB")) { - if (res != nullptr) { - Object objCS = res->lookupColorSpace("DefaultRGB"); - if (objCS.isNull()) { - cs = new GfxDeviceRGBColorSpace(); - } else { - cs = GfxColorSpace::parse(nullptr, &objCS, out, state); - } - } else { - cs = new GfxDeviceRGBColorSpace(); - } - } else if (obj1.isName("DeviceCMYK")) { - if (res != nullptr) { - Object objCS = res->lookupColorSpace("DefaultCMYK"); - if (objCS.isNull()) { - cs = new GfxDeviceCMYKColorSpace(); - } else { - cs = GfxColorSpace::parse(nullptr, &objCS, out, state); - } - } else { - cs = new GfxDeviceCMYKColorSpace(); - } - } else { - error(errSyntaxWarning, -1, "Bad color space dict'"); - } - } else { - error(errSyntaxWarning, -1, "Bad color space - expected name or array or dict"); - } - return cs; -} - -void GfxColorSpace::createMapping(GooList *separationList, int maxSepComps) { - return; -} - -void GfxColorSpace::getDefaultRanges(double *decodeLow, double *decodeRange, - int maxImgPixel) { - int i; - - for (i = 0; i < getNComps(); ++i) { - decodeLow[i] = 0; - decodeRange[i] = 1; - } -} - -int GfxColorSpace::getNumColorSpaceModes() { - return nGfxColorSpaceModes; -} - -const char *GfxColorSpace::getColorSpaceModeName(int idx) { - return gfxColorSpaceModeNames[idx]; -} - -#ifdef USE_CMS -cmsHPROFILE loadColorProfile(const char *fileName) -{ - cmsHPROFILE hp = nullptr; - FILE *fp; - - if (fileName[0] == '/') { - // full path - // check if open the file - if ((fp = fopen(fileName,"r")) != nullptr) { - fclose(fp); - hp = cmsOpenProfileFromFile(fileName,"r"); - } - return hp; - } - // try to load from global directory - GooString *path = new GooString(GLOBAL_COLOR_PROFILE_DIR); - path->append(fileName); - // check if open the file - if ((fp = fopen(path->getCString(),"r")) != nullptr) { - fclose(fp); - hp = cmsOpenProfileFromFile(path->getCString(),"r"); - } - delete path; - return hp; -} - -static void CMSError(cmsContext /*contextId*/, cmsUInt32Number /*ecode*/, const char *text) -{ - error(errSyntaxWarning, -1, "{0:s}", text); -} - -int GfxColorSpace::setupColorProfiles() -{ - static GBool initialized = gFalse; - cmsHTRANSFORM transform; - unsigned int nChannels; - - // do only once - if (initialized) return 0; - initialized = gTrue; - - // set error handlor - cmsSetLogErrorHandler(CMSError); - - if (displayProfile == nullptr) { - // load display profile if it was not already loaded. - if (displayProfileName == nullptr) { - displayProfile = loadColorProfile("display.icc"); - } else if (displayProfileName->getLength() > 0) { - displayProfile = loadColorProfile(displayProfileName->getCString()); - } - } - // load RGB profile - RGBProfile = loadColorProfile("RGB.icc"); - if (RGBProfile == nullptr) { - /* use built in sRGB profile */ - RGBProfile = cmsCreate_sRGBProfile(); - } - // create transforms - if (displayProfile != nullptr) { - displayPixelType = getCMSColorSpaceType(cmsGetColorSpace(displayProfile)); - nChannels = getCMSNChannels(cmsGetColorSpace(displayProfile)); - // create transform from XYZ - cmsHPROFILE XYZProfile = cmsCreateXYZProfile(); - if ((transform = cmsCreateTransform(XYZProfile, TYPE_XYZ_DBL, - displayProfile, - COLORSPACE_SH(displayPixelType) | - CHANNELS_SH(nChannels) | BYTES_SH(1), - INTENT_RELATIVE_COLORIMETRIC,LCMS_FLAGS)) == nullptr) { - error(errSyntaxWarning, -1, "Can't create Lab transform"); - } else { - XYZ2DisplayTransform = new GfxColorTransform(transform, INTENT_RELATIVE_COLORIMETRIC, PT_XYZ, displayPixelType); - } - cmsCloseProfile(XYZProfile); - } - return 0; -} - -unsigned int getCMSColorSpaceType(cmsColorSpaceSignature cs) -{ - switch (cs) { - case cmsSigXYZData: - return PT_XYZ; - break; - case cmsSigLabData: - return PT_Lab; - break; - case cmsSigLuvData: - return PT_YUV; - break; - case cmsSigYCbCrData: - return PT_YCbCr; - break; - case cmsSigYxyData: - return PT_Yxy; - break; - case cmsSigRgbData: - return PT_RGB; - break; - case cmsSigGrayData: - return PT_GRAY; - break; - case cmsSigHsvData: - return PT_HSV; - break; - case cmsSigHlsData: - return PT_HLS; - break; - case cmsSigCmykData: - return PT_CMYK; - break; - case cmsSigCmyData: - return PT_CMY; - break; - case cmsSig2colorData: - case cmsSig3colorData: - case cmsSig4colorData: - case cmsSig5colorData: - case cmsSig6colorData: - case cmsSig7colorData: - case cmsSig8colorData: - case cmsSig9colorData: - case cmsSig10colorData: - case cmsSig11colorData: - case cmsSig12colorData: - case cmsSig13colorData: - case cmsSig14colorData: - case cmsSig15colorData: - default: - break; - } - return PT_RGB; -} - -unsigned int getCMSNChannels(cmsColorSpaceSignature cs) -{ - switch (cs) { - case cmsSigXYZData: - case cmsSigLuvData: - case cmsSigLabData: - case cmsSigYCbCrData: - case cmsSigYxyData: - case cmsSigRgbData: - case cmsSigHsvData: - case cmsSigHlsData: - case cmsSigCmyData: - case cmsSig3colorData: - return 3; - break; - case cmsSigGrayData: - return 1; - break; - case cmsSigCmykData: - case cmsSig4colorData: - return 4; - break; - case cmsSig2colorData: - return 2; - break; - case cmsSig5colorData: - return 5; - break; - case cmsSig6colorData: - return 6; - break; - case cmsSig7colorData: - return 7; - break; - case cmsSig8colorData: - return 8; - break; - case cmsSig9colorData: - return 9; - break; - case cmsSig10colorData: - return 10; - break; - case cmsSig11colorData: - return 11; - break; - case cmsSig12colorData: - return 12; - break; - case cmsSig13colorData: - return 13; - break; - case cmsSig14colorData: - return 14; - break; - case cmsSig15colorData: - return 15; - default: - break; - } - return 3; -} -#endif - -//------------------------------------------------------------------------ -// GfxDeviceGrayColorSpace -//------------------------------------------------------------------------ - -GfxDeviceGrayColorSpace::GfxDeviceGrayColorSpace() { -} - -GfxDeviceGrayColorSpace::~GfxDeviceGrayColorSpace() { -} - -GfxColorSpace *GfxDeviceGrayColorSpace::copy() { - return new GfxDeviceGrayColorSpace(); -} - -void GfxDeviceGrayColorSpace::getGray(GfxColor *color, GfxGray *gray) { - *gray = clip01(color->c[0]); -} - -void GfxDeviceGrayColorSpace::getGrayLine(Guchar *in, Guchar *out, int length) { - memcpy (out, in, length); -} - -void GfxDeviceGrayColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) { - rgb->r = rgb->g = rgb->b = clip01(color->c[0]); -} - -void GfxDeviceGrayColorSpace::getRGBLine(Guchar *in, unsigned int *out, - int length) { - int i; - - for (i = 0; i < length; i++) - out[i] = (in[i] << 16) | (in[i] << 8) | (in[i] << 0); -} - -void GfxDeviceGrayColorSpace::getRGBLine(Guchar *in, Guchar *out, int length) { - for (int i = 0; i < length; i++) { - *out++ = in[i]; - *out++ = in[i]; - *out++ = in[i]; - } -} - -void GfxDeviceGrayColorSpace::getRGBXLine(Guchar *in, Guchar *out, int length) { - for (int i = 0; i < length; i++) { - *out++ = in[i]; - *out++ = in[i]; - *out++ = in[i]; - *out++ = 255; - } -} - -void GfxDeviceGrayColorSpace::getCMYKLine(Guchar *in, Guchar *out, int length) { - for (int i = 0; i < length; i++) { - *out++ = 0; - *out++ = 0; - *out++ = 0; - *out++ = in[i]; - } -} - -void GfxDeviceGrayColorSpace::getDeviceNLine(Guchar *in, Guchar *out, int length) { - for (int i = 0; i < length; i++) { - for (int j = 0; j < SPOT_NCOMPS+4; j++) - out[j] = 0; - out[4] = in[i]; - out += (SPOT_NCOMPS+4); - } -} - -void GfxDeviceGrayColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) { - cmyk->c = cmyk->m = cmyk->y = 0; - cmyk->k = clip01(gfxColorComp1 - color->c[0]); -} - -void GfxDeviceGrayColorSpace::getDeviceN(GfxColor *color, GfxColor *deviceN) { - for (int i = 0; i < gfxColorMaxComps; i++) - deviceN->c[i] = 0; - deviceN->c[3] = clip01(gfxColorComp1 - color->c[0]); -} - -void GfxDeviceGrayColorSpace::getDefaultColor(GfxColor *color) { - color->c[0] = 0; -} - -//------------------------------------------------------------------------ -// GfxCalGrayColorSpace -//------------------------------------------------------------------------ - -GfxCalGrayColorSpace::GfxCalGrayColorSpace() { - whiteX = whiteY = whiteZ = 1; - blackX = blackY = blackZ = 0; - gamma = 1; -} - -GfxCalGrayColorSpace::~GfxCalGrayColorSpace() { -#ifdef USE_CMS - if (transform != nullptr) { - if (transform->unref() == 0) delete transform; - } -#endif -} - -GfxColorSpace *GfxCalGrayColorSpace::copy() { - GfxCalGrayColorSpace *cs; - - cs = new GfxCalGrayColorSpace(); - cs->whiteX = whiteX; - cs->whiteY = whiteY; - cs->whiteZ = whiteZ; - cs->blackX = blackX; - cs->blackY = blackY; - cs->blackZ = blackZ; - cs->gamma = gamma; - cs->kr = kr; - cs->kg = kg; - cs->kb = kb; -#ifdef USE_CMS - cs->transform = transform; - if (transform != nullptr) transform->ref(); -#endif - return cs; -} - -// This is the inverse of MatrixLMN in Example 4.10 from the PostScript -// Language Reference, Third Edition. -static const double xyzrgb[3][3] = { - { 3.240449, -1.537136, -0.498531 }, - { -0.969265, 1.876011, 0.041556 }, - { 0.055643, -0.204026, 1.057229 } -}; - -GfxColorSpace *GfxCalGrayColorSpace::parse(Array *arr, GfxState *state) { - GfxCalGrayColorSpace *cs; - Object obj1, obj2; - - obj1 = arr->get(1); - if (!obj1.isDict()) { - error(errSyntaxWarning, -1, "Bad CalGray color space"); - return nullptr; - } - cs = new GfxCalGrayColorSpace(); - obj2 = obj1.dictLookup("WhitePoint"); - if (obj2.isArray() && obj2.arrayGetLength() == 3) { - Object obj3 = obj2.arrayGet(0); - if (likely(obj3.isNum())) - cs->whiteX = obj3.getNum(); - obj3 = obj2.arrayGet(1); - if (likely(obj3.isNum())) - cs->whiteY = obj3.getNum(); - obj3 = obj2.arrayGet(2); - if (likely(obj3.isNum())) - cs->whiteZ = obj3.getNum(); - } - obj2 = obj1.dictLookup("BlackPoint"); - if (obj2.isArray() && obj2.arrayGetLength() == 3) { - Object obj3 = obj2.arrayGet(0); - if (likely(obj3.isNum())) - cs->blackX = obj3.getNum(); - obj3 = obj2.arrayGet(1); - if (likely(obj3.isNum())) - cs->blackY = obj3.getNum(); - obj3 = obj2.arrayGet(2); - if (likely(obj3.isNum())) - cs->blackZ = obj3.getNum(); - } - obj2 = obj1.dictLookup("Gamma"); - if (obj2.isNum()) { - cs->gamma = obj2.getNum(); - } - - cs->kr = 1 / (xyzrgb[0][0] * cs->whiteX + - xyzrgb[0][1] * cs->whiteY + - xyzrgb[0][2] * cs->whiteZ); - cs->kg = 1 / (xyzrgb[1][0] * cs->whiteX + - xyzrgb[1][1] * cs->whiteY + - xyzrgb[1][2] * cs->whiteZ); - cs->kb = 1 / (xyzrgb[2][0] * cs->whiteX + - xyzrgb[2][1] * cs->whiteY + - xyzrgb[2][2] * cs->whiteZ); -#ifdef USE_CMS - cs->transform = (state != nullptr) ? state->getXYZ2DisplayTransform() : XYZ2DisplayTransform; - if (cs->transform != nullptr) cs->transform->ref(); -#endif - return cs; -} - -// convert CalGray to media XYZ color space -// (not multiply by the white point) -void GfxCalGrayColorSpace::getXYZ(GfxColor *color, - double *pX, double *pY, double *pZ) { - const double A = colToDbl(color->c[0]); - const double xyzColor = pow(A,gamma); - *pX = xyzColor; - *pY = xyzColor; - *pZ = xyzColor; -} - -void GfxCalGrayColorSpace::getGray(GfxColor *color, GfxGray *gray) { - GfxRGB rgb; - -#ifdef USE_CMS - if (transform != nullptr && transform->getTransformPixelType() == PT_GRAY) { - Guchar out[gfxColorMaxComps]; - double in[gfxColorMaxComps]; - double X, Y, Z; - - getXYZ(color,&X,&Y,&Z); - in[0] = clip01(X); - in[1] = clip01(Y); - in[2] = clip01(Z); - transform->doTransform(in,out,1); - *gray = byteToCol(out[0]); - return; - } -#endif - getRGB(color, &rgb); - *gray = clip01((GfxColorComp)(0.299 * rgb.r + - 0.587 * rgb.g + - 0.114 * rgb.b + 0.5)); -} - -void GfxCalGrayColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) { - double X, Y, Z; - double r, g, b; - - getXYZ(color,&X,&Y,&Z); -#ifdef USE_CMS - if (transform != nullptr && transform->getTransformPixelType() == PT_RGB) { - Guchar out[gfxColorMaxComps]; - double in[gfxColorMaxComps]; - - in[0] = clip01(X); - in[1] = clip01(Y); - in[2] = clip01(Z); - transform->doTransform(in,out,1); - rgb->r = byteToCol(out[0]); - rgb->g = byteToCol(out[1]); - rgb->b = byteToCol(out[2]); - return; - } -#endif - X *= whiteX; - Y *= whiteY; - Z *= whiteZ; - // convert XYZ to RGB, including gamut mapping and gamma correction - r = xyzrgb[0][0] * X + xyzrgb[0][1] * Y + xyzrgb[0][2] * Z; - g = xyzrgb[1][0] * X + xyzrgb[1][1] * Y + xyzrgb[1][2] * Z; - b = xyzrgb[2][0] * X + xyzrgb[2][1] * Y + xyzrgb[2][2] * Z; - rgb->r = dblToCol(sqrt(clip01(r * kr))); - rgb->g = dblToCol(sqrt(clip01(g * kg))); - rgb->b = dblToCol(sqrt(clip01(b * kb))); -} - -void GfxCalGrayColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) { - GfxRGB rgb; - GfxColorComp c, m, y, k; - -#ifdef USE_CMS - if (transform != nullptr && transform->getTransformPixelType() == PT_CMYK) { - double in[gfxColorMaxComps]; - Guchar out[gfxColorMaxComps]; - double X, Y, Z; - - getXYZ(color,&X,&Y,&Z); - in[0] = clip01(X); - in[1] = clip01(Y); - in[2] = clip01(Z); - - transform->doTransform(in,out,1); - cmyk->c = byteToCol(out[0]); - cmyk->m = byteToCol(out[1]); - cmyk->y = byteToCol(out[2]); - cmyk->k = byteToCol(out[3]); - return; - } -#endif - getRGB(color, &rgb); - c = clip01(gfxColorComp1 - rgb.r); - m = clip01(gfxColorComp1 - rgb.g); - y = clip01(gfxColorComp1 - rgb.b); - k = c; - if (m < k) { - k = m; - } - if (y < k) { - k = y; - } - cmyk->c = c - k; - cmyk->m = m - k; - cmyk->y = y - k; - cmyk->k = k; -} - -void GfxCalGrayColorSpace::getDeviceN(GfxColor *color, GfxColor *deviceN) { - GfxCMYK cmyk; - for (int i = 0; i < gfxColorMaxComps; i++) - deviceN->c[i] = 0; - getCMYK(color, &cmyk); - deviceN->c[0] = cmyk.c; - deviceN->c[1] = cmyk.m; - deviceN->c[2] = cmyk.y; - deviceN->c[3] = cmyk.k; -} - -void GfxCalGrayColorSpace::getDefaultColor(GfxColor *color) { - color->c[0] = 0; -} - -//------------------------------------------------------------------------ -// GfxDeviceRGBColorSpace -//------------------------------------------------------------------------ - -GfxDeviceRGBColorSpace::GfxDeviceRGBColorSpace() { -} - -GfxDeviceRGBColorSpace::~GfxDeviceRGBColorSpace() { -} - -GfxColorSpace *GfxDeviceRGBColorSpace::copy() { - return new GfxDeviceRGBColorSpace(); -} - -void GfxDeviceRGBColorSpace::getGray(GfxColor *color, GfxGray *gray) { - *gray = clip01((GfxColorComp)(0.3 * color->c[0] + - 0.59 * color->c[1] + - 0.11 * color->c[2] + 0.5)); -} - -void GfxDeviceRGBColorSpace::getGrayLine(Guchar *in, Guchar *out, int length) { - int i; - - for (i = 0; i < length; i++) { - out[i] = - (in[i * 3 + 0] * 19595 + - in[i * 3 + 1] * 38469 + - in[i * 3 + 2] * 7472) / 65536; - } -} - -void GfxDeviceRGBColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) { - rgb->r = clip01(color->c[0]); - rgb->g = clip01(color->c[1]); - rgb->b = clip01(color->c[2]); -} - -void GfxDeviceRGBColorSpace::getRGBLine(Guchar *in, unsigned int *out, - int length) { - Guchar *p; - int i; - - for (i = 0, p = in; i < length; i++, p += 3) - out[i] = (p[0] << 16) | (p[1] << 8) | (p[2] << 0); -} - -void GfxDeviceRGBColorSpace::getRGBLine(Guchar *in, Guchar *out, int length) { - for (int i = 0; i < length; i++) { - *out++ = *in++; - *out++ = *in++; - *out++ = *in++; - } -} - -void GfxDeviceRGBColorSpace::getRGBXLine(Guchar *in, Guchar *out, int length) { - for (int i = 0; i < length; i++) { - *out++ = *in++; - *out++ = *in++; - *out++ = *in++; - *out++ = 255; - } -} - -void GfxDeviceRGBColorSpace::getCMYKLine(Guchar *in, Guchar *out, int length) { - GfxColorComp c, m, y, k; - - for (int i = 0; i < length; i++) { - c = byteToCol(255 - *in++); - m = byteToCol(255 - *in++); - y = byteToCol(255 - *in++); - k = c; - if (m < k) { - k = m; - } - if (y < k) { - k = y; - } - *out++ = colToByte(c - k); - *out++ = colToByte(m - k); - *out++ = colToByte(y - k); - *out++ = colToByte(k); - } -} - -void GfxDeviceRGBColorSpace::getDeviceNLine(Guchar *in, Guchar *out, int length) { - GfxColorComp c, m, y, k; - - for (int i = 0; i < length; i++) { - for (int j = 0; j < SPOT_NCOMPS+4; j++) - out[j] = 0; - c = byteToCol(255 - *in++); - m = byteToCol(255 - *in++); - y = byteToCol(255 - *in++); - k = c; - if (m < k) { - k = m; - } - if (y < k) { - k = y; - } - out[0] = colToByte(c - k); - out[1] = colToByte(m - k); - out[2] = colToByte(y - k); - out[3] = colToByte(k); - out += (SPOT_NCOMPS+4); - } -} - -void GfxDeviceRGBColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) { - GfxColorComp c, m, y, k; - - c = clip01(gfxColorComp1 - color->c[0]); - m = clip01(gfxColorComp1 - color->c[1]); - y = clip01(gfxColorComp1 - color->c[2]); - k = c; - if (m < k) { - k = m; - } - if (y < k) { - k = y; - } - cmyk->c = c - k; - cmyk->m = m - k; - cmyk->y = y - k; - cmyk->k = k; -} - -void GfxDeviceRGBColorSpace::getDeviceN(GfxColor *color, GfxColor *deviceN) { - GfxCMYK cmyk; - for (int i = 0; i < gfxColorMaxComps; i++) - deviceN->c[i] = 0; - getCMYK(color, &cmyk); - deviceN->c[0] = cmyk.c; - deviceN->c[1] = cmyk.m; - deviceN->c[2] = cmyk.y; - deviceN->c[3] = cmyk.k; -} - -void GfxDeviceRGBColorSpace::getDefaultColor(GfxColor *color) { - color->c[0] = 0; - color->c[1] = 0; - color->c[2] = 0; -} - -//------------------------------------------------------------------------ -// GfxCalRGBColorSpace -//------------------------------------------------------------------------ - -GfxCalRGBColorSpace::GfxCalRGBColorSpace() { - whiteX = whiteY = whiteZ = 1; - blackX = blackY = blackZ = 0; - gammaR = gammaG = gammaB = 1; - mat[0] = 1; mat[1] = 0; mat[2] = 0; - mat[3] = 0; mat[4] = 1; mat[5] = 0; - mat[6] = 0; mat[7] = 0; mat[8] = 1; -} - -GfxCalRGBColorSpace::~GfxCalRGBColorSpace() { -#ifdef USE_CMS - if (transform != nullptr) { - if (transform->unref() == 0) delete transform; - } -#endif -} - -GfxColorSpace *GfxCalRGBColorSpace::copy() { - GfxCalRGBColorSpace *cs; - int i; - - cs = new GfxCalRGBColorSpace(); - cs->whiteX = whiteX; - cs->whiteY = whiteY; - cs->whiteZ = whiteZ; - cs->blackX = blackX; - cs->blackY = blackY; - cs->blackZ = blackZ; - cs->gammaR = gammaR; - cs->gammaG = gammaG; - cs->gammaB = gammaB; - cs->kr = kr; - cs->kg = kg; - cs->kb = kb; - for (i = 0; i < 9; ++i) { - cs->mat[i] = mat[i]; - } -#ifdef USE_CMS - cs->transform = transform; - if (transform != nullptr) transform->ref(); -#endif - return cs; -} - -GfxColorSpace *GfxCalRGBColorSpace::parse(Array *arr, GfxState *state) { - GfxCalRGBColorSpace *cs; - Object obj1, obj2; - int i; - - obj1 = arr->get(1); - if (!obj1.isDict()) { - error(errSyntaxWarning, -1, "Bad CalRGB color space"); - return nullptr; - } - cs = new GfxCalRGBColorSpace(); - obj2 = obj1.dictLookup("WhitePoint"); - if (obj2.isArray() && obj2.arrayGetLength() == 3) { - Object obj3 = obj2.arrayGet(0); - if (likely(obj3.isNum())) - cs->whiteX = obj3.getNum(); - obj3 = obj2.arrayGet(1); - if (likely(obj3.isNum())) - cs->whiteY = obj3.getNum(); - obj3 = obj2.arrayGet(2); - if (likely(obj3.isNum())) - cs->whiteZ = obj3.getNum(); - } - obj2 = obj1.dictLookup("BlackPoint"); - if (obj2.isArray() && obj2.arrayGetLength() == 3) { - Object obj3 = obj2.arrayGet(0); - if (likely(obj3.isNum())) - cs->blackX = obj3.getNum(); - obj3 = obj2.arrayGet(1); - if (likely(obj3.isNum())) - cs->blackY = obj3.getNum(); - obj3 = obj2.arrayGet(2); - if (likely(obj3.isNum())) - cs->blackZ = obj3.getNum(); - } - obj2 = obj1.dictLookup("Gamma"); - if (obj2.isArray() && obj2.arrayGetLength() == 3) { - Object obj3 = obj2.arrayGet(0); - if (likely(obj3.isNum())) - cs->gammaR = obj3.getNum(); - obj3 = obj2.arrayGet(1); - if (likely(obj3.isNum())) - cs->gammaG = obj3.getNum(); - obj3 = obj2.arrayGet(2); - if (likely(obj3.isNum())) - cs->gammaB = obj3.getNum(); - } - obj2 = obj1.dictLookup("Matrix"); - if (obj2.isArray() && obj2.arrayGetLength() == 9) { - for (i = 0; i < 9; ++i) { - Object obj3 = obj2.arrayGet(i); - if (likely(obj3.isNum())) - cs->mat[i] = obj3.getNum(); - } - } - - cs->kr = 1 / (xyzrgb[0][0] * cs->whiteX + - xyzrgb[0][1] * cs->whiteY + - xyzrgb[0][2] * cs->whiteZ); - cs->kg = 1 / (xyzrgb[1][0] * cs->whiteX + - xyzrgb[1][1] * cs->whiteY + - xyzrgb[1][2] * cs->whiteZ); - cs->kb = 1 / (xyzrgb[2][0] * cs->whiteX + - xyzrgb[2][1] * cs->whiteY + - xyzrgb[2][2] * cs->whiteZ); - -#ifdef USE_CMS - cs->transform = (state != nullptr) ? state->getXYZ2DisplayTransform() : XYZ2DisplayTransform; - if (cs->transform != nullptr) cs->transform->ref(); -#endif - return cs; -} - -// convert CalRGB to XYZ color space -void GfxCalRGBColorSpace::getXYZ(GfxColor *color, - double *pX, double *pY, double *pZ) { - double A, B, C; - - A = pow(colToDbl(color->c[0]), gammaR); - B = pow(colToDbl(color->c[1]), gammaG); - C = pow(colToDbl(color->c[2]), gammaB); - *pX = mat[0] * A + mat[3] * B + mat[6] * C; - *pY = mat[1] * A + mat[4] * B + mat[7] * C; - *pZ = mat[2] * A + mat[5] * B + mat[8] * C; -} - -void GfxCalRGBColorSpace::getGray(GfxColor *color, GfxGray *gray) { - GfxRGB rgb; - -#ifdef USE_CMS - if (transform != nullptr && transform->getTransformPixelType() == PT_GRAY) { - Guchar out[gfxColorMaxComps]; - double in[gfxColorMaxComps]; - double X, Y, Z; - - getXYZ(color,&X,&Y,&Z); - in[0] = clip01(X); - in[1] = clip01(Y); - in[2] = clip01(Z); - transform->doTransform(in,out,1); - *gray = byteToCol(out[0]); - return; - } -#endif - getRGB(color, &rgb); - *gray = clip01((GfxColorComp)(0.299 * rgb.r + - 0.587 * rgb.g + - 0.114 * rgb.b + 0.5)); -} - -void GfxCalRGBColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) { - double X, Y, Z; - double r, g, b; - - getXYZ(color,&X,&Y,&Z); -#ifdef USE_CMS - if (transform != nullptr && transform->getTransformPixelType() == PT_RGB) { - Guchar out[gfxColorMaxComps]; - double in[gfxColorMaxComps]; - - in[0] = clip01(X/whiteX); - in[1] = clip01(Y/whiteY); - in[2] = clip01(Z/whiteZ); - transform->doTransform(in,out,1); - rgb->r = byteToCol(out[0]); - rgb->g = byteToCol(out[1]); - rgb->b = byteToCol(out[2]); - return; - } -#endif - // convert XYZ to RGB, including gamut mapping and gamma correction - r = xyzrgb[0][0] * X + xyzrgb[0][1] * Y + xyzrgb[0][2] * Z; - g = xyzrgb[1][0] * X + xyzrgb[1][1] * Y + xyzrgb[1][2] * Z; - b = xyzrgb[2][0] * X + xyzrgb[2][1] * Y + xyzrgb[2][2] * Z; - rgb->r = dblToCol(sqrt(clip01(r))); - rgb->g = dblToCol(sqrt(clip01(g))); - rgb->b = dblToCol(sqrt(clip01(b))); -} - -void GfxCalRGBColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) { - GfxRGB rgb; - GfxColorComp c, m, y, k; - -#ifdef USE_CMS - if (transform != nullptr && transform->getTransformPixelType() == PT_CMYK) { - double in[gfxColorMaxComps]; - Guchar out[gfxColorMaxComps]; - double X, Y, Z; - - getXYZ(color,&X,&Y,&Z); - in[0] = clip01(X); - in[1] = clip01(Y); - in[2] = clip01(Z); - transform->doTransform(in,out,1); - cmyk->c = byteToCol(out[0]); - cmyk->m = byteToCol(out[1]); - cmyk->y = byteToCol(out[2]); - cmyk->k = byteToCol(out[3]); - return; - } -#endif - getRGB(color, &rgb); - c = clip01(gfxColorComp1 - rgb.r); - m = clip01(gfxColorComp1 - rgb.g); - y = clip01(gfxColorComp1 - rgb.b); - k = c; - if (m < k) { - k = m; - } - if (y < k) { - k = y; - } - cmyk->c = c - k; - cmyk->m = m - k; - cmyk->y = y - k; - cmyk->k = k; -} - -void GfxCalRGBColorSpace::getDeviceN(GfxColor *color, GfxColor *deviceN) { - GfxCMYK cmyk; - for (int i = 0; i < gfxColorMaxComps; i++) - deviceN->c[i] = 0; - getCMYK(color, &cmyk); - deviceN->c[0] = cmyk.c; - deviceN->c[1] = cmyk.m; - deviceN->c[2] = cmyk.y; - deviceN->c[3] = cmyk.k; -} - -void GfxCalRGBColorSpace::getDefaultColor(GfxColor *color) { - color->c[0] = 0; - color->c[1] = 0; - color->c[2] = 0; -} - -//------------------------------------------------------------------------ -// GfxDeviceCMYKColorSpace -//------------------------------------------------------------------------ - -GfxDeviceCMYKColorSpace::GfxDeviceCMYKColorSpace() { -} - -GfxDeviceCMYKColorSpace::~GfxDeviceCMYKColorSpace() { -} - -GfxColorSpace *GfxDeviceCMYKColorSpace::copy() { - return new GfxDeviceCMYKColorSpace(); -} - -void GfxDeviceCMYKColorSpace::getGray(GfxColor *color, GfxGray *gray) { - *gray = clip01((GfxColorComp)(gfxColorComp1 - color->c[3] - - 0.3 * color->c[0] - - 0.59 * color->c[1] - - 0.11 * color->c[2] + 0.5)); -} - -void GfxDeviceCMYKColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) { - double c, m, y, k, c1, m1, y1, k1, r, g, b; - - c = colToDbl(color->c[0]); - m = colToDbl(color->c[1]); - y = colToDbl(color->c[2]); - k = colToDbl(color->c[3]); - c1 = 1 - c; - m1 = 1 - m; - y1 = 1 - y; - k1 = 1 - k; - cmykToRGBMatrixMultiplication(c, m, y, k, c1, m1, y1, k1, r, g, b); - rgb->r = clip01(dblToCol(r)); - rgb->g = clip01(dblToCol(g)); - rgb->b = clip01(dblToCol(b)); -} - -static inline void GfxDeviceCMYKColorSpacegetRGBLineHelper(Guchar *&in, double &r, double &g, double &b) -{ - double c, m, y, k, c1, m1, y1, k1; - - c = byteToDbl(*in++); - m = byteToDbl(*in++); - y = byteToDbl(*in++); - k = byteToDbl(*in++); - c1 = 1 - c; - m1 = 1 - m; - y1 = 1 - y; - k1 = 1 - k; - cmykToRGBMatrixMultiplication(c, m, y, k, c1, m1, y1, k1, r, g, b); -} - -void GfxDeviceCMYKColorSpace::getRGBLine(Guchar *in, unsigned int *out, int length) -{ - double r, g, b; - for (int i = 0; i < length; i++) { - GfxDeviceCMYKColorSpacegetRGBLineHelper(in, r, g, b); - *out++ = (dblToByte(clip01(r)) << 16) | (dblToByte(clip01(g)) << 8) | dblToByte(clip01(b)); - } -} - -void GfxDeviceCMYKColorSpace::getRGBLine(Guchar *in, Guchar *out, int length) -{ - double r, g, b; - - for (int i = 0; i < length; i++) { - GfxDeviceCMYKColorSpacegetRGBLineHelper(in, r, g, b); - *out++ = dblToByte(clip01(r)); - *out++ = dblToByte(clip01(g)); - *out++ = dblToByte(clip01(b)); - } -} - -void GfxDeviceCMYKColorSpace::getRGBXLine(Guchar *in, Guchar *out, int length) -{ - double r, g, b; - - for (int i = 0; i < length; i++) { - GfxDeviceCMYKColorSpacegetRGBLineHelper(in, r, g, b); - *out++ = dblToByte(clip01(r)); - *out++ = dblToByte(clip01(g)); - *out++ = dblToByte(clip01(b)); - *out++ = 255; - } -} - -void GfxDeviceCMYKColorSpace::getCMYKLine(Guchar *in, Guchar *out, int length) -{ - for (int i = 0; i < length; i++) { - *out++ = *in++; - *out++ = *in++; - *out++ = *in++; - *out++ = *in++; - } -} - -void GfxDeviceCMYKColorSpace::getDeviceNLine(Guchar *in, Guchar *out, int length) -{ - for (int i = 0; i < length; i++) { - for (int j = 0; j < SPOT_NCOMPS+4; j++) - out[j] = 0; - out[0] = *in++; - out[1] = *in++; - out[2] = *in++; - out[3] = *in++; - out += (SPOT_NCOMPS+4); - } -} - -void GfxDeviceCMYKColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) { - cmyk->c = clip01(color->c[0]); - cmyk->m = clip01(color->c[1]); - cmyk->y = clip01(color->c[2]); - cmyk->k = clip01(color->c[3]); -} - -void GfxDeviceCMYKColorSpace::getDeviceN(GfxColor *color, GfxColor *deviceN) { - for (int i = 0; i < gfxColorMaxComps; i++) - deviceN->c[i] = 0; - deviceN->c[0] = clip01(color->c[0]); - deviceN->c[1] = clip01(color->c[1]); - deviceN->c[2] = clip01(color->c[2]); - deviceN->c[3] = clip01(color->c[3]); -} - -void GfxDeviceCMYKColorSpace::getDefaultColor(GfxColor *color) { - color->c[0] = 0; - color->c[1] = 0; - color->c[2] = 0; - color->c[3] = gfxColorComp1; -} - -//------------------------------------------------------------------------ -// GfxLabColorSpace -//------------------------------------------------------------------------ - -GfxLabColorSpace::GfxLabColorSpace() { - whiteX = whiteY = whiteZ = 1; - blackX = blackY = blackZ = 0; - aMin = bMin = -100; - aMax = bMax = 100; -} - -GfxLabColorSpace::~GfxLabColorSpace() { -#ifdef USE_CMS - if (transform != nullptr) { - if (transform->unref() == 0) delete transform; - } -#endif -} - -GfxColorSpace *GfxLabColorSpace::copy() { - GfxLabColorSpace *cs; - - cs = new GfxLabColorSpace(); - cs->whiteX = whiteX; - cs->whiteY = whiteY; - cs->whiteZ = whiteZ; - cs->blackX = blackX; - cs->blackY = blackY; - cs->blackZ = blackZ; - cs->aMin = aMin; - cs->aMax = aMax; - cs->bMin = bMin; - cs->bMax = bMax; - cs->kr = kr; - cs->kg = kg; - cs->kb = kb; -#ifdef USE_CMS - cs->transform = transform; - if (transform != nullptr) transform->ref(); -#endif - return cs; -} - -GfxColorSpace *GfxLabColorSpace::parse(Array *arr, GfxState *state) { - GfxLabColorSpace *cs; - Object obj1, obj2; - - obj1 = arr->get(1); - if (!obj1.isDict()) { - error(errSyntaxWarning, -1, "Bad Lab color space"); - return nullptr; - } - cs = new GfxLabColorSpace(); - bool ok = true; - obj2 = obj1.dictLookup("WhitePoint"); - if (obj2.isArray() && obj2.arrayGetLength() == 3) { - Object obj3 = obj2.arrayGet(0); - cs->whiteX = obj3.getNum(&ok); - obj3 = obj2.arrayGet(1); - cs->whiteY = obj3.getNum(&ok); - obj3 = obj2.arrayGet(2); - cs->whiteZ = obj3.getNum(&ok); - } - obj2 = obj1.dictLookup("BlackPoint"); - if (obj2.isArray() && obj2.arrayGetLength() == 3) { - Object obj3 = obj2.arrayGet(0); - cs->blackX = obj3.getNum(&ok); - obj3 = obj2.arrayGet(1); - cs->blackY = obj3.getNum(&ok); - obj3 = obj2.arrayGet(2); - cs->blackZ = obj3.getNum(&ok); - } - obj2 = obj1.dictLookup("Range"); - if (obj2.isArray() && obj2.arrayGetLength() == 4) { - Object obj3 = obj2.arrayGet(0); - cs->aMin = obj3.getNum(&ok); - obj3 = obj2.arrayGet(1); - cs->aMax = obj3.getNum(&ok); - obj3 = obj2.arrayGet(2); - cs->bMin = obj3.getNum(&ok); - obj3 = obj2.arrayGet(3); - cs->bMax = obj3.getNum(&ok); - } - - if (!ok) { - error(errSyntaxWarning, -1, "Bad Lab color space"); -#ifdef USE_CMS - cs->transform = nullptr; -#endif - delete cs; - return nullptr; - } - - cs->kr = 1 / (xyzrgb[0][0] * cs->whiteX + - xyzrgb[0][1] * cs->whiteY + - xyzrgb[0][2] * cs->whiteZ); - cs->kg = 1 / (xyzrgb[1][0] * cs->whiteX + - xyzrgb[1][1] * cs->whiteY + - xyzrgb[1][2] * cs->whiteZ); - cs->kb = 1 / (xyzrgb[2][0] * cs->whiteX + - xyzrgb[2][1] * cs->whiteY + - xyzrgb[2][2] * cs->whiteZ); - -#ifdef USE_CMS - cs->transform = (state != nullptr) ? state->getXYZ2DisplayTransform() : XYZ2DisplayTransform; - if (cs->transform != nullptr) cs->transform->ref(); -#endif - return cs; -} - -void GfxLabColorSpace::getGray(GfxColor *color, GfxGray *gray) { - GfxRGB rgb; - -#ifdef USE_CMS - if (transform != nullptr && transform->getTransformPixelType() == PT_GRAY) { - Guchar out[gfxColorMaxComps]; - double in[gfxColorMaxComps]; - - getXYZ(color, &in[0], &in[1], &in[2]); - transform->doTransform(in,out,1); - *gray = byteToCol(out[0]); - return; - } -#endif - getRGB(color, &rgb); - *gray = clip01((GfxColorComp)(0.299 * rgb.r + - 0.587 * rgb.g + - 0.114 * rgb.b + 0.5)); -} - -// convert L*a*b* to media XYZ color space -// (not multiply by the white point) -void GfxLabColorSpace::getXYZ(GfxColor *color, - double *pX, double *pY, double *pZ) { - double X, Y, Z; - double t1, t2; - - t1 = (colToDbl(color->c[0]) + 16) / 116; - t2 = t1 + colToDbl(color->c[1]) / 500; - if (t2 >= (6.0 / 29.0)) { - X = t2 * t2 * t2; - } else { - X = (108.0 / 841.0) * (t2 - (4.0 / 29.0)); - } - if (t1 >= (6.0 / 29.0)) { - Y = t1 * t1 * t1; - } else { - Y = (108.0 / 841.0) * (t1 - (4.0 / 29.0)); - } - t2 = t1 - colToDbl(color->c[2]) / 200; - if (t2 >= (6.0 / 29.0)) { - Z = t2 * t2 * t2; - } else { - Z = (108.0 / 841.0) * (t2 - (4.0 / 29.0)); - } - *pX = X; - *pY = Y; - *pZ = Z; -} - -void GfxLabColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) { - double X, Y, Z; - - getXYZ(color, &X, &Y, &Z); -#ifdef USE_CMS - if (transform != nullptr && transform->getTransformPixelType() == PT_RGB) { - Guchar out[gfxColorMaxComps]; - double in[gfxColorMaxComps]; - - in[0] = clip01(X); - in[1] = clip01(Y); - in[2] = clip01(Z); - transform->doTransform(in,out,1); - rgb->r = byteToCol(out[0]); - rgb->g = byteToCol(out[1]); - rgb->b = byteToCol(out[2]); - return; - } else if (transform != nullptr && transform->getTransformPixelType() == PT_CMYK) { - Guchar out[gfxColorMaxComps]; - double in[gfxColorMaxComps]; - double c, m, y, k, c1, m1, y1, k1, r, g, b; - - in[0] = clip01(X); - in[1] = clip01(Y); - in[2] = clip01(Z); - transform->doTransform(in,out,1); - c = byteToDbl(out[0]); - m = byteToDbl(out[1]); - y = byteToDbl(out[2]); - k = byteToDbl(out[3]); - c1 = 1 - c; - m1 = 1 - m; - y1 = 1 - y; - k1 = 1 - k; - cmykToRGBMatrixMultiplication(c, m, y, k, c1, m1, y1, k1, r, g, b); - rgb->r = clip01(dblToCol(r)); - rgb->g = clip01(dblToCol(g)); - rgb->b = clip01(dblToCol(b)); - return; - } -#endif - X *= whiteX; - Y *= whiteY; - Z *= whiteZ; - // convert XYZ to RGB, including gamut mapping and gamma correction - const double r = xyzrgb[0][0] * X + xyzrgb[0][1] * Y + xyzrgb[0][2] * Z; - const double g = xyzrgb[1][0] * X + xyzrgb[1][1] * Y + xyzrgb[1][2] * Z; - const double b = xyzrgb[2][0] * X + xyzrgb[2][1] * Y + xyzrgb[2][2] * Z; - rgb->r = dblToCol(sqrt(clip01(r * kr))); - rgb->g = dblToCol(sqrt(clip01(g * kg))); - rgb->b = dblToCol(sqrt(clip01(b * kb))); -} - -void GfxLabColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) { - GfxRGB rgb; - GfxColorComp c, m, y, k; - -#ifdef USE_CMS - if (transform != nullptr && transform->getTransformPixelType() == PT_CMYK) { - double in[gfxColorMaxComps]; - Guchar out[gfxColorMaxComps]; - - getXYZ(color, &in[0], &in[1], &in[2]); - transform->doTransform(in,out,1); - cmyk->c = byteToCol(out[0]); - cmyk->m = byteToCol(out[1]); - cmyk->y = byteToCol(out[2]); - cmyk->k = byteToCol(out[3]); - return; - } -#endif - getRGB(color, &rgb); - c = clip01(gfxColorComp1 - rgb.r); - m = clip01(gfxColorComp1 - rgb.g); - y = clip01(gfxColorComp1 - rgb.b); - k = c; - if (m < k) { - k = m; - } - if (y < k) { - k = y; - } - cmyk->c = c - k; - cmyk->m = m - k; - cmyk->y = y - k; - cmyk->k = k; -} - -void GfxLabColorSpace::getDeviceN(GfxColor *color, GfxColor *deviceN) { - GfxCMYK cmyk; - for (int i = 0; i < gfxColorMaxComps; i++) - deviceN->c[i] = 0; - getCMYK(color, &cmyk); - deviceN->c[0] = cmyk.c; - deviceN->c[1] = cmyk.m; - deviceN->c[2] = cmyk.y; - deviceN->c[3] = cmyk.k; -} - -void GfxLabColorSpace::getDefaultColor(GfxColor *color) { - color->c[0] = 0; - if (aMin > 0) { - color->c[1] = dblToCol(aMin); - } else if (aMax < 0) { - color->c[1] = dblToCol(aMax); - } else { - color->c[1] = 0; - } - if (bMin > 0) { - color->c[2] = dblToCol(bMin); - } else if (bMax < 0) { - color->c[2] = dblToCol(bMax); - } else { - color->c[2] = 0; - } -} - -void GfxLabColorSpace::getDefaultRanges(double *decodeLow, double *decodeRange, - int maxImgPixel) { - decodeLow[0] = 0; - decodeRange[0] = 100; - decodeLow[1] = aMin; - decodeRange[1] = aMax - aMin; - decodeLow[2] = bMin; - decodeRange[2] = bMax - bMin; -} - -//------------------------------------------------------------------------ -// GfxICCBasedColorSpace -//------------------------------------------------------------------------ - -class GfxICCBasedColorSpaceKey : public PopplerCacheKey -{ - public: - GfxICCBasedColorSpaceKey(int numA, int genA) : num(numA), gen(genA) - { - } - - bool operator==(const PopplerCacheKey &key) const override - { - const GfxICCBasedColorSpaceKey *k = static_cast<const GfxICCBasedColorSpaceKey*>(&key); - return k->num == num && k->gen == gen; - } - - int num, gen; -}; - -class GfxICCBasedColorSpaceItem : public PopplerCacheItem -{ - public: - GfxICCBasedColorSpaceItem(GfxICCBasedColorSpace *csA) - { - cs = static_cast<GfxICCBasedColorSpace*>(csA->copy()); - } - - ~GfxICCBasedColorSpaceItem() - { - delete cs; - } - - GfxICCBasedColorSpace *cs; -}; - -GfxICCBasedColorSpace::GfxICCBasedColorSpace(int nCompsA, GfxColorSpace *altA, - Ref *iccProfileStreamA) { - nComps = nCompsA; - alt = altA; - iccProfileStream = *iccProfileStreamA; - rangeMin[0] = rangeMin[1] = rangeMin[2] = rangeMin[3] = 0; - rangeMax[0] = rangeMax[1] = rangeMax[2] = rangeMax[3] = 1; -#ifdef USE_CMS - transform = nullptr; - lineTransform = nullptr; -#endif -} - -GfxICCBasedColorSpace::~GfxICCBasedColorSpace() { - delete alt; -#ifdef USE_CMS - if (transform != nullptr) { - if (transform->unref() == 0) delete transform; - } - if (lineTransform != nullptr) { - if (lineTransform->unref() == 0) delete lineTransform; - } -#endif -} - -GfxColorSpace *GfxICCBasedColorSpace::copy() { - GfxICCBasedColorSpace *cs; - int i; - - cs = new GfxICCBasedColorSpace(nComps, alt->copy(), &iccProfileStream); - for (i = 0; i < 4; ++i) { - cs->rangeMin[i] = rangeMin[i]; - cs->rangeMax[i] = rangeMax[i]; - } -#ifdef USE_CMS - cs->transform = transform; - if (transform != nullptr) transform->ref(); - cs->lineTransform = lineTransform; - if (lineTransform != nullptr) lineTransform->ref(); -#endif - return cs; -} - -GfxColorSpace *GfxICCBasedColorSpace::parse(Array *arr, OutputDev *out, GfxState *state, int recursion) { - GfxICCBasedColorSpace *cs; - Ref iccProfileStreamA; - int nCompsA; - GfxColorSpace *altA; - Dict *dict; - Object obj1, obj2, obj3; - int i; - - if (arr->getLength() < 2) { - error(errSyntaxError, -1, "Bad ICCBased color space"); - return nullptr; - } - obj1 = arr->getNF(1); - if (obj1.isRef()) { - iccProfileStreamA = obj1.getRef(); - } else { - iccProfileStreamA.num = 0; - iccProfileStreamA.gen = 0; - } -#ifdef USE_CMS - // check cache - if (out && iccProfileStreamA.num > 0) { - GfxICCBasedColorSpaceKey k(iccProfileStreamA.num, iccProfileStreamA.gen); - GfxICCBasedColorSpaceItem *item = static_cast<GfxICCBasedColorSpaceItem *>(out->getIccColorSpaceCache()->lookup(k)); - if (item != nullptr) - { - cs = static_cast<GfxICCBasedColorSpace*>(item->cs->copy()); - int transformIntent = cs->getIntent(); - int cmsIntent = INTENT_RELATIVE_COLORIMETRIC; - if (state != nullptr) { - const char *intent = state->getRenderingIntent(); - if (intent != nullptr) { - if (strcmp(intent, "AbsoluteColorimetric") == 0) { - cmsIntent = INTENT_ABSOLUTE_COLORIMETRIC; - } else if (strcmp(intent, "Saturation") == 0) { - cmsIntent = INTENT_SATURATION; - } else if (strcmp(intent, "Perceptual") == 0) { - cmsIntent = INTENT_PERCEPTUAL; - } - } - } - if (transformIntent == cmsIntent) { - return cs; - } - delete cs; - } - } -#endif - obj1 = arr->get(1); - if (!obj1.isStream()) { - error(errSyntaxWarning, -1, "Bad ICCBased color space (stream)"); - return nullptr; - } - dict = obj1.streamGetDict(); - obj2 = dict->lookup("N"); - if (!obj2.isInt()) { - error(errSyntaxWarning, -1, "Bad ICCBased color space (N)"); - return nullptr; - } - nCompsA = obj2.getInt(); - if (nCompsA > 4) { - error(errSyntaxError, -1, - "ICCBased color space with too many ({0:d} > 4) components", - nCompsA); - nCompsA = 4; - } - obj2 = dict->lookup("Alternate"); - if (obj2.isNull() || - !(altA = GfxColorSpace::parse(nullptr, &obj2, out, state, recursion + 1))) { - switch (nCompsA) { - case 1: - altA = new GfxDeviceGrayColorSpace(); - break; - case 3: - altA = new GfxDeviceRGBColorSpace(); - break; - case 4: - altA = new GfxDeviceCMYKColorSpace(); - break; - default: - error(errSyntaxWarning, -1, "Bad ICCBased color space - invalid N"); - return nullptr; - } - } - if (altA->getNComps() != nCompsA) { - error(errSyntaxWarning, -1, "Bad ICCBased color space - N doesn't match alt color space"); - delete altA; - return nullptr; - } - cs = new GfxICCBasedColorSpace(nCompsA, altA, &iccProfileStreamA); - obj2 = dict->lookup("Range"); - if (obj2.isArray() && obj2.arrayGetLength() == 2 * nCompsA) { - Object obj4; - for (i = 0; i < nCompsA; ++i) { - obj3 = obj2.arrayGet(2*i); - obj4 = obj2.arrayGet(2*i+1); - if (obj3.isNum() && obj4.isNum()) { - cs->rangeMin[i] = obj3.getNum(); - cs->rangeMax[i] = obj4.getNum(); - } - } - } - -#ifdef USE_CMS - obj1 = arr->get(1); - Guchar *profBuf; - Stream *iccStream = obj1.getStream(); - int length = 0; - - profBuf = iccStream->toUnsignedChars(&length, 65536, 65536); - cmsHPROFILE hp = cmsOpenProfileFromMem(profBuf,length); - gfree(profBuf); - if (hp == nullptr) { - error(errSyntaxWarning, -1, "read ICCBased color space profile error"); - } else { - cmsHPROFILE dhp = (state != nullptr && state->getDisplayProfile() != nullptr) ? state->getDisplayProfile() : displayProfile; - if (dhp == nullptr) { - if (unlikely(RGBProfile == nullptr)) { - GfxColorSpace::setupColorProfiles(); - } - dhp = RGBProfile; - } - unsigned int cst = getCMSColorSpaceType(cmsGetColorSpace(hp)); - unsigned int dNChannels = getCMSNChannels(cmsGetColorSpace(dhp)); - unsigned int dcst = getCMSColorSpaceType(cmsGetColorSpace(dhp)); - cmsHTRANSFORM transform; - - int cmsIntent = INTENT_RELATIVE_COLORIMETRIC; - if (state != nullptr) { - const char *intent = state->getRenderingIntent(); - if (intent != nullptr) { - if (strcmp(intent, "AbsoluteColorimetric") == 0) { - cmsIntent = INTENT_ABSOLUTE_COLORIMETRIC; - } else if (strcmp(intent, "Saturation") == 0) { - cmsIntent = INTENT_SATURATION; - } else if (strcmp(intent, "Perceptual") == 0) { - cmsIntent = INTENT_PERCEPTUAL; - } - } - } - if ((transform = cmsCreateTransform(hp, - COLORSPACE_SH(cst) |CHANNELS_SH(nCompsA) | BYTES_SH(1), - dhp, - COLORSPACE_SH(dcst) | - CHANNELS_SH(dNChannels) | BYTES_SH(1), - cmsIntent, LCMS_FLAGS)) == nullptr) { - error(errSyntaxWarning, -1, "Can't create transform"); - cs->transform = nullptr; - } else { - cs->transform = new GfxColorTransform(transform, cmsIntent, cst, dcst); - } - if (dcst == PT_RGB || dcst == PT_CMYK) { - // create line transform only when the display is RGB type color space - if ((transform = cmsCreateTransform(hp, - CHANNELS_SH(nCompsA) | BYTES_SH(1),dhp, - (dcst == PT_RGB) ? TYPE_RGB_8 : TYPE_CMYK_8, cmsIntent, LCMS_FLAGS)) == nullptr) { - error(errSyntaxWarning, -1, "Can't create transform"); - cs->lineTransform = nullptr; - } else { - cs->lineTransform = new GfxColorTransform(transform, cmsIntent, cst, dcst); - } - } - cmsCloseProfile(hp); - } - // put this colorSpace into cache - if (out && iccProfileStreamA.num > 0) { - GfxICCBasedColorSpaceKey *k = new GfxICCBasedColorSpaceKey(iccProfileStreamA.num, iccProfileStreamA.gen); - GfxICCBasedColorSpaceItem *item = new GfxICCBasedColorSpaceItem(cs); - out->getIccColorSpaceCache()->put(k, item); - } -#endif - return cs; -} - -void GfxICCBasedColorSpace::getGray(GfxColor *color, GfxGray *gray) { -#ifdef USE_CMS - if (transform != nullptr && transform->getTransformPixelType() == PT_GRAY) { - Guchar in[gfxColorMaxComps]; - Guchar out[gfxColorMaxComps]; - - if (nComps == 3 && transform->getInputPixelType() == PT_Lab) { - in[0] = colToByte(dblToCol(colToDbl(color->c[0]) / 100.0)); - in[1] = colToByte(dblToCol((colToDbl(color->c[1]) + 128.0) / 255.0)); - in[2] = colToByte(dblToCol((colToDbl(color->c[2]) + 128.0) / 255.0)); - } else { - for (int i = 0;i < nComps;i++) { - in[i] = colToByte(color->c[i]); - } - } - if (nComps <= 4) { - unsigned int key = 0; - for (int j = 0; j < nComps; j++) { - key = (key << 8) + in[j]; - } - std::map<unsigned int, unsigned int>::iterator it = cmsCache.find(key); - if (it != cmsCache.end()) { - unsigned int value = it->second; - *gray = byteToCol(value & 0xff); - return; - } - } - transform->doTransform(in,out,1); - *gray = byteToCol(out[0]); - if (nComps <= 4 && cmsCache.size() <= CMSCACHE_LIMIT) { - unsigned int key = 0; - for (int j = 0; j < nComps; j++) { - key = (key << 8) + in[j]; - } - unsigned int value = out[0]; - cmsCache.insert(std::pair<unsigned int, unsigned int>(key, value)); - } - } else { - GfxRGB rgb; - getRGB(color,&rgb); - *gray = clip01((GfxColorComp)(0.3 * rgb.r + - 0.59 * rgb.g + - 0.11 * rgb.b + 0.5)); - } -#else - alt->getGray(color, gray); -#endif -} - -void GfxICCBasedColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) { -#ifdef USE_CMS - if (transform != nullptr && transform->getTransformPixelType() == PT_RGB) { - Guchar in[gfxColorMaxComps]; - Guchar out[gfxColorMaxComps]; - - if (nComps == 3 && transform->getInputPixelType() == PT_Lab) { - in[0] = colToByte(dblToCol(colToDbl(color->c[0]) / 100.0)); - in[1] = colToByte(dblToCol((colToDbl(color->c[1]) + 128.0) / 255.0)); - in[2] = colToByte(dblToCol((colToDbl(color->c[2]) + 128.0) / 255.0)); - } else { - for (int i = 0;i < nComps;i++) { - in[i] = colToByte(color->c[i]); - } - } - if (nComps <= 4) { - unsigned int key = 0; - for (int j = 0; j < nComps; j++) { - key = (key << 8) + in[j]; - } - std::map<unsigned int, unsigned int>::iterator it = cmsCache.find(key); - if (it != cmsCache.end()) { - unsigned int value = it->second; - rgb->r = byteToCol(value >> 16); - rgb->g = byteToCol((value >> 8) & 0xff); - rgb->b = byteToCol(value & 0xff); - return; - } - } - transform->doTransform(in,out,1); - rgb->r = byteToCol(out[0]); - rgb->g = byteToCol(out[1]); - rgb->b = byteToCol(out[2]); - if (nComps <= 4 && cmsCache.size() <= CMSCACHE_LIMIT) { - unsigned int key = 0; - for (int j = 0; j < nComps; j++) { - key = (key << 8) + in[j]; - } - unsigned int value = (out[0] << 16) + (out[1] << 8) + out[2]; - cmsCache.insert(std::pair<unsigned int, unsigned int>(key, value)); - } - } else if (transform != nullptr && transform->getTransformPixelType() == PT_CMYK) { - Guchar in[gfxColorMaxComps]; - Guchar out[gfxColorMaxComps]; - double c, m, y, k, c1, m1, y1, k1, r, g, b; - - if (nComps == 3 && transform->getInputPixelType() == PT_Lab) { - in[0] = colToByte(dblToCol(colToDbl(color->c[0]) / 100.0)); - in[1] = colToByte(dblToCol((colToDbl(color->c[1]) + 128.0) / 255.0)); - in[2] = colToByte(dblToCol((colToDbl(color->c[2]) + 128.0) / 255.0)); - } else { - for (int i = 0;i < nComps;i++) { - in[i] = colToByte(color->c[i]); - } - } - if (nComps <= 4) { - unsigned int key = 0; - for (int j = 0; j < nComps; j++) { - key = (key << 8) + in[j]; - } - std::map<unsigned int, unsigned int>::iterator it = cmsCache.find(key); - if (it != cmsCache.end()) { - unsigned int value = it->second; - rgb->r = byteToCol(value >> 16); - rgb->g = byteToCol((value >> 8) & 0xff); - rgb->b = byteToCol(value & 0xff); - return; - } - } - transform->doTransform(in,out,1); - c = byteToDbl(out[0]); - m = byteToDbl(out[1]); - y = byteToDbl(out[2]); - k = byteToDbl(out[3]); - c1 = 1 - c; - m1 = 1 - m; - y1 = 1 - y; - k1 = 1 - k; - cmykToRGBMatrixMultiplication(c, m, y, k, c1, m1, y1, k1, r, g, b); - rgb->r = clip01(dblToCol(r)); - rgb->g = clip01(dblToCol(g)); - rgb->b = clip01(dblToCol(b)); - if (nComps <= 4 && cmsCache.size() <= CMSCACHE_LIMIT) { - unsigned int key = 0; - for (int j = 0; j < nComps; j++) { - key = (key << 8) + in[j]; - } - unsigned int value = (dblToByte(r) << 16) + (dblToByte(g) << 8) + dblToByte(b); - cmsCache.insert(std::pair<unsigned int, unsigned int>(key, value)); - } - } else { - alt->getRGB(color, rgb); - } -#else - alt->getRGB(color, rgb); -#endif -} - -void GfxICCBasedColorSpace::getRGBLine(Guchar *in, unsigned int *out, - int length) { -#ifdef USE_CMS - if (lineTransform != nullptr && lineTransform->getTransformPixelType() == PT_RGB) { - Guchar* tmp = (Guchar *)gmallocn(3 * length, sizeof(Guchar)); - lineTransform->doTransform(in, tmp, length); - for (int i = 0; i < length; ++i) { - Guchar *current = tmp + (i * 3); - out[i] = (current[0] << 16) | (current[1] << 8) | current[2]; - } - gfree(tmp); - } else { - alt->getRGBLine(in, out, length); - } -#else - alt->getRGBLine(in, out, length); -#endif -} - -void GfxICCBasedColorSpace::getRGBLine(Guchar *in, Guchar *out, int length) { -#ifdef USE_CMS - if (lineTransform != nullptr && lineTransform->getTransformPixelType() == PT_RGB) { - Guchar* tmp = (Guchar *)gmallocn(3 * length, sizeof(Guchar)); - lineTransform->doTransform(in, tmp, length); - Guchar *current = tmp; - for (int i = 0; i < length; ++i) { - *out++ = *current++; - *out++ = *current++; - *out++ = *current++; - } - gfree(tmp); - } else if (lineTransform != nullptr && lineTransform->getTransformPixelType() == PT_CMYK) { - Guchar* tmp = (Guchar *)gmallocn(4 * length, sizeof(Guchar)); - lineTransform->doTransform(in, tmp, length); - Guchar *current = tmp; - double c, m, y, k, c1, m1, y1, k1, r, g, b; - for (int i = 0; i < length; ++i) { - c = byteToDbl(*current++); - m = byteToDbl(*current++); - y = byteToDbl(*current++); - k = byteToDbl(*current++); - c1 = 1 - c; - m1 = 1 - m; - y1 = 1 - y; - k1 = 1 - k; - cmykToRGBMatrixMultiplication(c, m, y, k, c1, m1, y1, k1, r, g, b); - *out++ = dblToByte(r); - *out++ = dblToByte(g); - *out++ = dblToByte(b); - } - gfree(tmp); - } else { - alt->getRGBLine(in, out, length); - } -#else - alt->getRGBLine(in, out, length); -#endif -} - -void GfxICCBasedColorSpace::getRGBXLine(Guchar *in, Guchar *out, int length) { -#ifdef USE_CMS - if (lineTransform != nullptr && lineTransform->getTransformPixelType() == PT_RGB) { - Guchar* tmp = (Guchar *)gmallocn(3 * length, sizeof(Guchar)); - lineTransform->doTransform(in, tmp, length); - Guchar *current = tmp; - for (int i = 0; i < length; ++i) { - *out++ = *current++; - *out++ = *current++; - *out++ = *current++; - *out++ = 255; - } - gfree(tmp); - } else { - alt->getRGBXLine(in, out, length); - } -#else - alt->getRGBXLine(in, out, length); -#endif -} - -void GfxICCBasedColorSpace::getCMYKLine(Guchar *in, Guchar *out, int length) { -#ifdef USE_CMS - if (lineTransform != nullptr && lineTransform->getTransformPixelType() == PT_CMYK) { - transform->doTransform(in,out,length); - } else if (lineTransform != nullptr && nComps != 4) { - GfxColorComp c, m, y, k; - Guchar* tmp = (Guchar *)gmallocn(3 * length, sizeof(Guchar)); - getRGBLine(in, tmp, length); - Guchar *p = tmp; - for (int i = 0; i < length; i++) { - c = byteToCol(255 - *p++); - m = byteToCol(255 - *p++); - y = byteToCol(255 - *p++); - k = c; - if (m < k) { - k = m; - } - if (y < k) { - k = y; - } - *out++ = colToByte(c - k); - *out++ = colToByte(m - k); - *out++ = colToByte(y - k); - *out++ = colToByte(k); - } - gfree(tmp); - } else { - alt->getCMYKLine(in, out, length); - } -#else - alt->getCMYKLine(in, out, length); -#endif -} - -void GfxICCBasedColorSpace::getDeviceNLine(Guchar *in, Guchar *out, int length) { -#ifdef USE_CMS - if (lineTransform != nullptr && lineTransform->getTransformPixelType() == PT_CMYK) { - Guchar* tmp = (Guchar *)gmallocn(4 * length, sizeof(Guchar)); - transform->doTransform(in,tmp,length); - Guchar *p = tmp; - for (int i = 0; i < length; i++) { - for (int j = 0; j < 4; j++) - *out++ = *p++; - for (int j = 4; j < SPOT_NCOMPS+4; j++) - *out++ = 0; - } - gfree(tmp); - } else if (lineTransform != nullptr && nComps != 4) { - GfxColorComp c, m, y, k; - Guchar* tmp = (Guchar *)gmallocn(3 * length, sizeof(Guchar)); - getRGBLine(in, tmp, length); - Guchar *p = tmp; - for (int i = 0; i < length; i++) { - for (int j = 0; j < SPOT_NCOMPS+4; j++) - out[j] = 0; - c = byteToCol(255 - *p++); - m = byteToCol(255 - *p++); - y = byteToCol(255 - *p++); - k = c; - if (m < k) { - k = m; - } - if (y < k) { - k = y; - } - out[0] = colToByte(c - k); - out[1] = colToByte(m - k); - out[2] = colToByte(y - k); - out[3] = colToByte(k); - out += (SPOT_NCOMPS+4); - } - gfree(tmp); - } else { - alt->getDeviceNLine(in, out, length); - } -#else - alt->getDeviceNLine(in, out, length); -#endif -} - -void GfxICCBasedColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) { -#ifdef USE_CMS - if (transform != nullptr && transform->getTransformPixelType() == PT_CMYK) { - Guchar in[gfxColorMaxComps]; - Guchar out[gfxColorMaxComps]; - - if (nComps == 3 && transform->getInputPixelType() == PT_Lab) { - in[0] = colToByte(dblToCol(colToDbl(color->c[0]) / 100.0)); - in[1] = colToByte(dblToCol((colToDbl(color->c[1]) + 128.0) / 255.0)); - in[2] = colToByte(dblToCol((colToDbl(color->c[2]) + 128.0) / 255.0)); - } else { - for (int i = 0;i < nComps;i++) { - in[i] = colToByte(color->c[i]); - } - } - if (nComps <= 4) { - unsigned int key = 0; - for (int j = 0; j < nComps; j++) { - key = (key << 8) + in[j]; - } - std::map<unsigned int, unsigned int>::iterator it = cmsCache.find(key); - if (it != cmsCache.end()) { - unsigned int value = it->second; - cmyk->c = byteToCol(value >> 24); - cmyk->m = byteToCol((value >> 16) & 0xff); - cmyk->y = byteToCol((value >> 8) & 0xff); - cmyk->k = byteToCol(value & 0xff); - return; - } - } - transform->doTransform(in,out,1); - cmyk->c = byteToCol(out[0]); - cmyk->m = byteToCol(out[1]); - cmyk->y = byteToCol(out[2]); - cmyk->k = byteToCol(out[3]); - if (nComps <= 4 && cmsCache.size() <= CMSCACHE_LIMIT) { - unsigned int key = 0; - for (int j = 0; j < nComps; j++) { - key = (key << 8) + in[j]; - } - unsigned int value = (out[0] << 24) + (out[1] << 16) + (out[2] << 8) + out[3]; - cmsCache.insert(std::pair<unsigned int, unsigned int>(key, value)); - } - } else if (nComps != 4 && transform != nullptr && transform->getTransformPixelType() == PT_RGB) { - GfxRGB rgb; - GfxColorComp c, m, y, k; - - getRGB(color,&rgb); - c = clip01(gfxColorComp1 - rgb.r); - m = clip01(gfxColorComp1 - rgb.g); - y = clip01(gfxColorComp1 - rgb.b); - k = c; - if (m < k) { - k = m; - } - if (y < k) { - k = y; - } - cmyk->c = c - k; - cmyk->m = m - k; - cmyk->y = y - k; - cmyk->k = k; - } else { - alt->getCMYK(color, cmyk); - } -#else - alt->getCMYK(color, cmyk); -#endif -} - -GBool GfxICCBasedColorSpace::useGetRGBLine() { -#ifdef USE_CMS - return lineTransform != nullptr || alt->useGetRGBLine(); -#else - return alt->useGetRGBLine(); -#endif -} - -GBool GfxICCBasedColorSpace::useGetCMYKLine() { -#ifdef USE_CMS - return lineTransform != nullptr || alt->useGetCMYKLine(); -#else - return alt->useGetCMYKLine(); -#endif -} - -GBool GfxICCBasedColorSpace::useGetDeviceNLine() { -#ifdef USE_CMS - return lineTransform != nullptr || alt->useGetDeviceNLine(); -#else - return alt->useGetDeviceNLine(); -#endif -} - -void GfxICCBasedColorSpace::getDeviceN(GfxColor *color, GfxColor *deviceN) { - GfxCMYK cmyk; - for (int i = 0; i < gfxColorMaxComps; i++) - deviceN->c[i] = 0; - getCMYK(color, &cmyk); - deviceN->c[0] = cmyk.c; - deviceN->c[1] = cmyk.m; - deviceN->c[2] = cmyk.y; - deviceN->c[3] = cmyk.k; -} - -void GfxICCBasedColorSpace::getDefaultColor(GfxColor *color) { - int i; - - for (i = 0; i < nComps; ++i) { - if (rangeMin[i] > 0) { - color->c[i] = dblToCol(rangeMin[i]); - } else if (rangeMax[i] < 0) { - color->c[i] = dblToCol(rangeMax[i]); - } else { - color->c[i] = 0; - } - } -} - -void GfxICCBasedColorSpace::getDefaultRanges(double *decodeLow, - double *decodeRange, - int maxImgPixel) { - alt->getDefaultRanges(decodeLow, decodeRange, maxImgPixel); - -#if 0 - // this is nominally correct, but some PDF files don't set the - // correct ranges in the ICCBased dict - int i; - - for (i = 0; i < nComps; ++i) { - decodeLow[i] = rangeMin[i]; - decodeRange[i] = rangeMax[i] - rangeMin[i]; - } -#endif -} - -//------------------------------------------------------------------------ -// GfxIndexedColorSpace -//------------------------------------------------------------------------ - -GfxIndexedColorSpace::GfxIndexedColorSpace(GfxColorSpace *baseA, - int indexHighA) { - base = baseA; - indexHigh = indexHighA; - lookup = (Guchar *)gmallocn((indexHigh + 1) * base->getNComps(), - sizeof(Guchar)); - overprintMask = base->getOverprintMask(); -} - -GfxIndexedColorSpace::~GfxIndexedColorSpace() { - delete base; - gfree(lookup); -} - -GfxColorSpace *GfxIndexedColorSpace::copy() { - GfxIndexedColorSpace *cs; - - cs = new GfxIndexedColorSpace(base->copy(), indexHigh); - memcpy(cs->lookup, lookup, - (indexHigh + 1) * base->getNComps() * sizeof(Guchar)); - return cs; -} - -GfxColorSpace *GfxIndexedColorSpace::parse(GfxResources *res, Array *arr, OutputDev *out, GfxState *state, int recursion) { - GfxColorSpace *baseA; - int indexHighA; - Object obj1; - const char *s; - int i, j; - - if (arr->getLength() != 4) { - error(errSyntaxWarning, -1, "Bad Indexed color space"); - return nullptr; - } - obj1 = arr->get(1); - if (!(baseA = GfxColorSpace::parse(res, &obj1, out, state, recursion + 1))) { - error(errSyntaxWarning, -1, "Bad Indexed color space (base color space)"); - return nullptr; - } - obj1 = arr->get(2); - if (!obj1.isInt()) { - error(errSyntaxWarning, -1, "Bad Indexed color space (hival)"); - delete baseA; - return nullptr; - } - indexHighA = obj1.getInt(); - if (indexHighA < 0 || indexHighA > 255) { - // the PDF spec requires indexHigh to be in [0,255] -- allowing - // values larger than 255 creates a security hole: if nComps * - // indexHigh is greater than 2^31, the loop below may overwrite - // past the end of the array - int previousValue = indexHighA; - if (indexHighA < 0) indexHighA = 0; - else indexHighA = 255; - error(errSyntaxWarning, -1, "Bad Indexed color space (invalid indexHigh value, was {0:d} using {1:d} to try to recover)", previousValue, indexHighA); - } - GfxIndexedColorSpace *cs = new GfxIndexedColorSpace(baseA, indexHighA); - obj1 = arr->get(3); - const int n = baseA->getNComps(); - if (obj1.isStream()) { - obj1.streamReset(); - for (i = 0; i <= indexHighA; ++i) { - const int readChars = obj1.streamGetChars(n, &cs->lookup[i*n]); - for (j = readChars; j < n; ++j) { - error(errSyntaxWarning, -1, "Bad Indexed color space (lookup table stream too short) padding with zeroes"); - cs->lookup[i*n + j] = 0; - } - } - obj1.streamClose(); - } else if (obj1.isString()) { - if (obj1.getString()->getLength() < (indexHighA + 1) * n) { - error(errSyntaxWarning, -1, "Bad Indexed color space (lookup table string too short)"); - goto err3; - } - s = obj1.getString()->getCString(); - for (i = 0; i <= indexHighA; ++i) { - for (j = 0; j < n; ++j) { - cs->lookup[i*n + j] = (Guchar)*s++; - } - } - } else { - error(errSyntaxWarning, -1, "Bad Indexed color space (lookup table)"); - goto err3; - } - return cs; - - err3: - delete cs; - return nullptr; -} - -GfxColor *GfxIndexedColorSpace::mapColorToBase(GfxColor *color, - GfxColor *baseColor) { - Guchar *p; - double low[gfxColorMaxComps], range[gfxColorMaxComps]; - int n, i; - - n = base->getNComps(); - base->getDefaultRanges(low, range, indexHigh); - const int idx = (int)(colToDbl(color->c[0]) + 0.5) * n; - if (likely((idx + n - 1 < (indexHigh + 1) * base->getNComps()) && idx >= 0)) { - p = &lookup[idx]; - for (i = 0; i < n; ++i) { - baseColor->c[i] = dblToCol(low[i] + (p[i] / 255.0) * range[i]); - } - } else { - for (i = 0; i < n; ++i) { - baseColor->c[i] = 0; - } - } - return baseColor; -} - -void GfxIndexedColorSpace::getGray(GfxColor *color, GfxGray *gray) { - GfxColor color2; - - base->getGray(mapColorToBase(color, &color2), gray); -} - -void GfxIndexedColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) { - GfxColor color2; - - base->getRGB(mapColorToBase(color, &color2), rgb); -} - -void GfxIndexedColorSpace::getRGBLine(Guchar *in, unsigned int *out, int length) { - Guchar *line; - int i, j, n; - - n = base->getNComps(); - line = (Guchar *) gmallocn (length, n); - for (i = 0; i < length; i++) - for (j = 0; j < n; j++) - line[i * n + j] = lookup[in[i] * n + j]; - - base->getRGBLine(line, out, length); - - gfree (line); -} - -void GfxIndexedColorSpace::getRGBLine(Guchar *in, Guchar *out, int length) -{ - Guchar *line; - int i, j, n; - - n = base->getNComps(); - line = (Guchar *) gmallocn (length, n); - for (i = 0; i < length; i++) - for (j = 0; j < n; j++) - line[i * n + j] = lookup[in[i] * n + j]; - - base->getRGBLine(line, out, length); - - gfree (line); -} - -void GfxIndexedColorSpace::getRGBXLine(Guchar *in, Guchar *out, int length) -{ - Guchar *line; - int i, j, n; - - n = base->getNComps(); - line = (Guchar *) gmallocn (length, n); - for (i = 0; i < length; i++) - for (j = 0; j < n; j++) - line[i * n + j] = lookup[in[i] * n + j]; - - base->getRGBXLine(line, out, length); - - gfree (line); -} - -void GfxIndexedColorSpace::getCMYKLine(Guchar *in, Guchar *out, int length) { - Guchar *line; - int i, j, n; - - n = base->getNComps(); - line = (Guchar *) gmallocn (length, n); - for (i = 0; i < length; i++) - for (j = 0; j < n; j++) - line[i * n + j] = lookup[in[i] * n + j]; - - base->getCMYKLine(line, out, length); - - gfree (line); -} - -void GfxIndexedColorSpace::getDeviceNLine(Guchar *in, Guchar *out, int length) { - Guchar *line; - int i, j, n; - - n = base->getNComps(); - line = (Guchar *) gmallocn (length, n); - for (i = 0; i < length; i++) - for (j = 0; j < n; j++) - line[i * n + j] = lookup[in[i] * n + j]; - - base->getDeviceNLine(line, out, length); - - gfree (line); -} - -void GfxIndexedColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) { - GfxColor color2; - - base->getCMYK(mapColorToBase(color, &color2), cmyk); -} - -void GfxIndexedColorSpace::getDeviceN(GfxColor *color, GfxColor *deviceN) { - GfxColor color2; - - base->getDeviceN(mapColorToBase(color, &color2), deviceN); -} - -void GfxIndexedColorSpace::getDefaultColor(GfxColor *color) { - color->c[0] = 0; -} - -void GfxIndexedColorSpace::getDefaultRanges(double *decodeLow, - double *decodeRange, - int maxImgPixel) { - decodeLow[0] = 0; - decodeRange[0] = maxImgPixel; -} - -//------------------------------------------------------------------------ -// GfxSeparationColorSpace -//------------------------------------------------------------------------ - -GfxSeparationColorSpace::GfxSeparationColorSpace(GooString *nameA, - GfxColorSpace *altA, - Function *funcA) { - name = nameA; - alt = altA; - func = funcA; - nonMarking = !name->cmp("None"); - if (!name->cmp("Cyan")) { - overprintMask = 0x01; - } else if (!name->cmp("Magenta")) { - overprintMask = 0x02; - } else if (!name->cmp("Yellow")) { - overprintMask = 0x04; - } else if (!name->cmp("Black")) { - overprintMask = 0x08; - } else if (!name->cmp("All")) { - overprintMask = 0xffffffff; - } -} - -GfxSeparationColorSpace::GfxSeparationColorSpace(GooString *nameA, - GfxColorSpace *altA, - Function *funcA, - GBool nonMarkingA, - Guint overprintMaskA, - int *mappingA) { - name = nameA; - alt = altA; - func = funcA; - nonMarking = nonMarkingA; - overprintMask = overprintMaskA; - mapping = mappingA; -} - -GfxSeparationColorSpace::~GfxSeparationColorSpace() { - delete name; - delete alt; - delete func; - if (mapping != nullptr) - gfree(mapping); -} - -GfxColorSpace *GfxSeparationColorSpace::copy() { - int *mappingA = nullptr; - if (mapping != nullptr) { - mappingA = (int *) gmalloc(sizeof(int)); - *mappingA = *mapping; - } - return new GfxSeparationColorSpace(name->copy(), alt->copy(), func->copy(), - nonMarking, overprintMask, mappingA); -} - -//~ handle the 'All' and 'None' colorants -GfxColorSpace *GfxSeparationColorSpace::parse(GfxResources *res, Array *arr, OutputDev *out, GfxState *state, int recursion) { - GfxSeparationColorSpace *cs; - GooString *nameA; - GfxColorSpace *altA; - Function *funcA; - Object obj1; - - if (arr->getLength() != 4) { - error(errSyntaxWarning, -1, "Bad Separation color space"); - goto err1; - } - obj1 = arr->get(1); - if (!obj1.isName()) { - error(errSyntaxWarning, -1, "Bad Separation color space (name)"); - goto err1; - } - nameA = new GooString(obj1.getName()); - obj1 = arr->get(2); - if (!(altA = GfxColorSpace::parse(res, &obj1, out, state, recursion + 1))) { - error(errSyntaxWarning, -1, "Bad Separation color space (alternate color space)"); - goto err3; - } - obj1 = arr->get(3); - if (!(funcA = Function::parse(&obj1))) { - goto err4; - } - if (funcA->getInputSize() != 1) { - error(errSyntaxWarning, -1, "Bad SeparationColorSpace function"); - goto err5; - } - cs = new GfxSeparationColorSpace(nameA, altA, funcA); - return cs; - - err5: - delete funcA; - err4: - delete altA; - err3: - delete nameA; - err1: - return nullptr; -} - -void GfxSeparationColorSpace::getGray(GfxColor *color, GfxGray *gray) { - double x; - double c[gfxColorMaxComps]; - GfxColor color2; - int i; - - if (alt->getMode() == csDeviceGray && name->cmp("Black") == 0) { - *gray = clip01(gfxColorComp1 - color->c[0]); - } else { - x = colToDbl(color->c[0]); - func->transform(&x, c); - for (i = 0; i < alt->getNComps(); ++i) { - color2.c[i] = dblToCol(c[i]); - } - alt->getGray(&color2, gray); - } -} - -void GfxSeparationColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) { - double x; - double c[gfxColorMaxComps]; - GfxColor color2; - int i; - - if (alt->getMode() == csDeviceGray && name->cmp("Black") == 0) { - rgb->r = clip01(gfxColorComp1 - color->c[0]); - rgb->g = clip01(gfxColorComp1 - color->c[0]); - rgb->b = clip01(gfxColorComp1 - color->c[0]); - } else { - x = colToDbl(color->c[0]); - func->transform(&x, c); - const int altNComps = alt->getNComps(); - for (i = 0; i < altNComps; ++i) { - color2.c[i] = dblToCol(c[i]); - } - if (unlikely(altNComps > func->getOutputSize())) { - for (i = func->getOutputSize(); i < altNComps; ++i) { - color2.c[i] = 0; - } - } - alt->getRGB(&color2, rgb); - } -} - -void GfxSeparationColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) { - double x; - double c[gfxColorMaxComps]; - GfxColor color2; - int i; - - if (name->cmp("Black") == 0) { - cmyk->c = 0; - cmyk->m = 0; - cmyk->y = 0; - cmyk->k = color->c[0]; - } else if (name->cmp("Cyan") == 0) { - cmyk->c = color->c[0]; - cmyk->m = 0; - cmyk->y = 0; - cmyk->k = 0; - } else if (name->cmp("Magenta") == 0) { - cmyk->c = 0; - cmyk->m = color->c[0]; - cmyk->y = 0; - cmyk->k = 0; - } else if (name->cmp("Yellow") == 0) { - cmyk->c = 0; - cmyk->m = 0; - cmyk->y = color->c[0]; - cmyk->k = 0; - } else { - x = colToDbl(color->c[0]); - func->transform(&x, c); - for (i = 0; i < alt->getNComps(); ++i) { - color2.c[i] = dblToCol(c[i]); - } - alt->getCMYK(&color2, cmyk); - } -} - -void GfxSeparationColorSpace::getDeviceN(GfxColor *color, GfxColor *deviceN) { - for (int i = 0; i < gfxColorMaxComps; i++) - deviceN->c[i] = 0; - if (mapping == nullptr || mapping[0] == -1) { - GfxCMYK cmyk; - - getCMYK(color, &cmyk); - deviceN->c[0] = cmyk.c; - deviceN->c[1] = cmyk.m; - deviceN->c[2] = cmyk.y; - deviceN->c[3] = cmyk.k; - } else { - deviceN->c[mapping[0]] = color->c[0]; - } -} - -void GfxSeparationColorSpace::getDefaultColor(GfxColor *color) { - color->c[0] = gfxColorComp1; -} - -void GfxSeparationColorSpace::createMapping(GooList *separationList, int maxSepComps) { - if (nonMarking) - return; - mapping = (int *)gmalloc(sizeof(int)); - switch (overprintMask) { - case 0x01: - *mapping = 0; - break; - case 0x02: - *mapping = 1; - break; - case 0x04: - *mapping = 2; - break; - case 0x08: - *mapping = 3; - break; - default: - Guint newOverprintMask = 0x10; - for (int i = 0; i < separationList->getLength(); i++) { - GfxSeparationColorSpace *sepCS = (GfxSeparationColorSpace *)separationList->get(i); - if (!sepCS->getName()->cmp(name)) { - if (sepCS->getFunc()->hasDifferentResultSet(func)) { - error(errSyntaxWarning, -1, - "Different functions found for '{0:t}', convert immediately", name); - gfree(mapping); - mapping = nullptr; - return; - } - *mapping = i+4; - overprintMask = newOverprintMask; - return; - } - newOverprintMask <<=1; - } - if (separationList->getLength() == maxSepComps) { - error(errSyntaxWarning, -1, - "Too many ({0:d}) spots, convert '{1:t}' immediately", maxSepComps, name); - gfree(mapping); - mapping = nullptr; - return; - } - *mapping = separationList->getLength() + 4; - separationList->append(copy()); - overprintMask = newOverprintMask; - break; - } -} - -//------------------------------------------------------------------------ -// GfxDeviceNColorSpace -//------------------------------------------------------------------------ - -GfxDeviceNColorSpace::GfxDeviceNColorSpace(int nCompsA, - GooString **namesA, - GfxColorSpace *altA, - Function *funcA, - GooList *sepsCSA) { - int i; - - nComps = nCompsA; - alt = altA; - func = funcA; - sepsCS = sepsCSA; - nonMarking = gTrue; - overprintMask = 0; - mapping = nullptr; - for (i = 0; i < nComps; ++i) { - names[i] = namesA[i]; - if (names[i]->cmp("None")) { - nonMarking = gFalse; - } - if (!names[i]->cmp("Cyan")) { - overprintMask |= 0x01; - } else if (!names[i]->cmp("Magenta")) { - overprintMask |= 0x02; - } else if (!names[i]->cmp("Yellow")) { - overprintMask |= 0x04; - } else if (!names[i]->cmp("Black")) { - overprintMask |= 0x08; - } else if (!names[i]->cmp("All")) { - overprintMask = 0xffffffff; - } else { - overprintMask = 0x0f; - } - } -} - -GfxDeviceNColorSpace::GfxDeviceNColorSpace(int nCompsA, - GooString **namesA, - GfxColorSpace *altA, - Function *funcA, - GooList *sepsCSA, - int *mappingA, - GBool nonMarkingA, - Guint overprintMaskA) { - int i; - - nComps = nCompsA; - alt = altA; - func = funcA; - sepsCS = sepsCSA; - mapping = mappingA; - nonMarking = nonMarkingA; - overprintMask = overprintMaskA; - for (i = 0; i < nComps; ++i) { - names[i] = namesA[i]->copy(); - } -} - -GfxDeviceNColorSpace::~GfxDeviceNColorSpace() { - int i; - - for (i = 0; i < nComps; ++i) { - delete names[i]; - } - delete alt; - delete func; - deleteGooList(sepsCS, GfxSeparationColorSpace); - if (mapping != nullptr) - gfree(mapping); -} - -GfxColorSpace *GfxDeviceNColorSpace::copy() { - int i; - int *mappingA = nullptr; - - GooList *sepsCSA = new GooList(sepsCS->getLength()); - for (i = 0; i < sepsCS->getLength(); i++) { - GfxSeparationColorSpace *scs = (GfxSeparationColorSpace *) sepsCS->get(i); - if (likely(scs != nullptr)) { - sepsCSA->append(scs->copy()); - } - } - if (mapping != nullptr) { - mappingA = (int *)gmalloc(sizeof(int) * nComps); - for (i = 0; i < nComps; i++) - mappingA[i] = mapping[i]; - } - return new GfxDeviceNColorSpace(nComps, names, alt->copy(), func->copy(), - sepsCSA, mappingA, nonMarking, overprintMask); -} - -//~ handle the 'None' colorant -GfxColorSpace *GfxDeviceNColorSpace::parse(GfxResources *res, Array *arr, OutputDev *out, GfxState *state, int recursion) { - int nCompsA; - GooString *namesA[gfxColorMaxComps]; - GfxColorSpace *altA; - Function *funcA; - Object obj1; - int i; - GooList *separationList = new GooList(); - - if (arr->getLength() != 4 && arr->getLength() != 5) { - error(errSyntaxWarning, -1, "Bad DeviceN color space"); - goto err1; - } - obj1 = arr->get(1); - if (!obj1.isArray()) { - error(errSyntaxWarning, -1, "Bad DeviceN color space (names)"); - goto err1; - } - nCompsA = obj1.arrayGetLength(); - if (nCompsA > gfxColorMaxComps) { - error(errSyntaxWarning, -1, "DeviceN color space with too many ({0:d} > {1:d}) components", - nCompsA, gfxColorMaxComps); - nCompsA = gfxColorMaxComps; - } - for (i = 0; i < nCompsA; ++i) { - Object obj2 = obj1.arrayGet(i); - if (!obj2.isName()) { - error(errSyntaxWarning, -1, "Bad DeviceN color space (names)"); - nCompsA = i; - goto err3; - } - namesA[i] = new GooString(obj2.getName()); - } - obj1 = arr->get(2); - if (!(altA = GfxColorSpace::parse(res, &obj1, out, state, recursion + 1))) { - error(errSyntaxWarning, -1, "Bad DeviceN color space (alternate color space)"); - goto err3; - } - obj1 = arr->get(3); - if (!(funcA = Function::parse(&obj1))) { - goto err4; - } - if (arr->getLength() == 5) { - obj1 = arr->get(4); - if (!obj1.isDict()) { - error(errSyntaxWarning, -1, "Bad DeviceN color space (attributes)"); - goto err5; - } - Dict *attribs = obj1.getDict(); - Object obj2 = attribs->lookup("Colorants"); - if (obj2.isDict()) { - Dict *colorants = obj2.getDict(); - for (i = 0; i < colorants->getLength(); i++) { - Object obj3 = colorants->getVal(i); - if (obj3.isArray()) { - separationList->append(GfxSeparationColorSpace::parse(res, obj3.getArray(), out, state, recursion)); - } else { - error(errSyntaxWarning, -1, "Bad DeviceN color space (colorant value entry is not an Array)"); - goto err5; - } - } - } - } - return new GfxDeviceNColorSpace(nCompsA, namesA, altA, funcA, separationList); - - err5: - delete funcA; - err4: - delete altA; - err3: - for (i = 0; i < nCompsA; ++i) { - delete namesA[i]; - } - err1: - delete separationList; - return nullptr; -} - -void GfxDeviceNColorSpace::getGray(GfxColor *color, GfxGray *gray) { - double x[gfxColorMaxComps], c[gfxColorMaxComps]; - GfxColor color2; - int i; - - for (i = 0; i < nComps; ++i) { - x[i] = colToDbl(color->c[i]); - } - func->transform(x, c); - for (i = 0; i < alt->getNComps(); ++i) { - color2.c[i] = dblToCol(c[i]); - } - alt->getGray(&color2, gray); -} - -void GfxDeviceNColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) { - double x[gfxColorMaxComps], c[gfxColorMaxComps]; - GfxColor color2; - int i; - - for (i = 0; i < nComps; ++i) { - x[i] = colToDbl(color->c[i]); - } - func->transform(x, c); - for (i = 0; i < alt->getNComps(); ++i) { - color2.c[i] = dblToCol(c[i]); - } - alt->getRGB(&color2, rgb); -} - -void GfxDeviceNColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) { - double x[gfxColorMaxComps], c[gfxColorMaxComps]; - GfxColor color2; - int i; - - for (i = 0; i < nComps; ++i) { - x[i] = colToDbl(color->c[i]); - } - func->transform(x, c); - for (i = 0; i < alt->getNComps(); ++i) { - color2.c[i] = dblToCol(c[i]); - } - alt->getCMYK(&color2, cmyk); -} - -void GfxDeviceNColorSpace::getDeviceN(GfxColor *color, GfxColor *deviceN) { - for (int i = 0; i < gfxColorMaxComps; i++) - deviceN->c[i] = 0; - if (mapping == nullptr) { - GfxCMYK cmyk; - - getCMYK(color, &cmyk); - deviceN->c[0] = cmyk.c; - deviceN->c[1] = cmyk.m; - deviceN->c[2] = cmyk.y; - deviceN->c[3] = cmyk.k; - } else { - for (int j = 0; j < nComps; j++) - if (mapping[j] != -1) - deviceN->c[mapping[j]] = color->c[j]; - } -} - -void GfxDeviceNColorSpace::getDefaultColor(GfxColor *color) { - int i; - - for (i = 0; i < nComps; ++i) { - color->c[i] = gfxColorComp1; - } -} - -void GfxDeviceNColorSpace::createMapping(GooList *separationList, int maxSepComps) { - if (nonMarking) // None - return; - mapping = (int *)gmalloc(sizeof(int) * nComps); - Guint newOverprintMask = 0; - for (int i = 0; i < nComps; i++) { - if (!names[i]->cmp("None")) { - mapping[i] = -1; - } else if (!names[i]->cmp("Cyan")) { - newOverprintMask |= 0x01; - mapping[i] = 0; - } else if (!names[i]->cmp("Magenta")) { - newOverprintMask |= 0x02; - mapping[i] = 1; - } else if (!names[i]->cmp("Yellow")) { - newOverprintMask |= 0x04; - mapping[i] = 2; - } else if (!names[i]->cmp("Black")) { - newOverprintMask |= 0x08; - mapping[i] = 3; - } else { - Guint startOverprintMask = 0x10; - GBool found = gFalse; - Function *sepFunc = nullptr; - if (nComps == 1) - sepFunc = func; - else { - for (int k = 0; k < sepsCS->getLength(); k++) { - GfxSeparationColorSpace *sepCS = (GfxSeparationColorSpace *)sepsCS->get(k); - if (!sepCS->getName()->cmp(names[i])) { - sepFunc = sepCS->getFunc(); - break; - } - } - } - for (int j = 0; j < separationList->getLength(); j++) { - GfxSeparationColorSpace *sepCS = (GfxSeparationColorSpace *)separationList->get(j); - if (!sepCS->getName()->cmp(names[i])) { - if (sepFunc != nullptr && sepCS->getFunc()->hasDifferentResultSet(sepFunc)) { - error(errSyntaxWarning, -1, - "Different functions found for '{0:t}', convert immediately", names[i]); - gfree(mapping); - mapping = nullptr; - overprintMask = 0xffffffff; - return; - } - mapping[i] = j+4; - newOverprintMask |= startOverprintMask; - found = gTrue; - break; - } - startOverprintMask <<=1; - } - if (!found) { - if (separationList->getLength() == maxSepComps) { - error(errSyntaxWarning, -1, - "Too many ({0:d}) spots, convert '{1:t}' immediately", maxSepComps, names[i]); - gfree(mapping); - mapping = nullptr; - overprintMask = 0xffffffff; - return; - } - mapping[i] = separationList->getLength() + 4; - newOverprintMask |= startOverprintMask; - if (nComps == 1) - separationList->append(new GfxSeparationColorSpace(names[i]->copy(),alt->copy(), func->copy())); - else { - for (int k = 0; k < sepsCS->getLength(); k++) { - GfxSeparationColorSpace *sepCS = (GfxSeparationColorSpace *)sepsCS->get(k); - if (!sepCS->getName()->cmp(names[i])) { - found = gTrue; - separationList->append(sepCS->copy()); - break; - } - } - if(!found) { - error(errSyntaxWarning, -1, "DeviceN has no suitable colorant"); - gfree(mapping); - mapping = nullptr; - overprintMask = 0xffffffff; - return; - } - } - } - } - } - overprintMask = newOverprintMask; -} - -//------------------------------------------------------------------------ -// GfxPatternColorSpace -//------------------------------------------------------------------------ - -GfxPatternColorSpace::GfxPatternColorSpace(GfxColorSpace *underA) { - under = underA; -} - -GfxPatternColorSpace::~GfxPatternColorSpace() { - if (under) { - delete under; - } -} - -GfxColorSpace *GfxPatternColorSpace::copy() { - return new GfxPatternColorSpace(under ? under->copy() : - (GfxColorSpace *)nullptr); -} - -GfxColorSpace *GfxPatternColorSpace::parse(GfxResources *res, Array *arr, OutputDev *out, GfxState *state, int recursion) { - GfxPatternColorSpace *cs; - GfxColorSpace *underA; - Object obj1; - - if (arr->getLength() != 1 && arr->getLength() != 2) { - error(errSyntaxWarning, -1, "Bad Pattern color space"); - return nullptr; - } - underA = nullptr; - if (arr->getLength() == 2) { - obj1 = arr->get(1); - if (!(underA = GfxColorSpace::parse(res, &obj1, out, state, recursion + 1))) { - error(errSyntaxWarning, -1, "Bad Pattern color space (underlying color space)"); - return nullptr; - } - } - cs = new GfxPatternColorSpace(underA); - return cs; -} - -void GfxPatternColorSpace::getGray(GfxColor *color, GfxGray *gray) { - *gray = 0; -} - -void GfxPatternColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) { - rgb->r = rgb->g = rgb->b = 0; -} - -void GfxPatternColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) { - cmyk->c = cmyk->m = cmyk->y = 0; - cmyk->k = 1; -} - -void GfxPatternColorSpace::getDeviceN(GfxColor *color, GfxColor *deviceN) { - for (int i = 0; i < gfxColorMaxComps; i++) - deviceN->c[i] = 0; - deviceN->c[3] = 1; -} - -void GfxPatternColorSpace::getDefaultColor(GfxColor *color) { - color->c[0]=0; -} - -//------------------------------------------------------------------------ -// Pattern -//------------------------------------------------------------------------ - -GfxPattern::GfxPattern(int typeA, int patternRefNumA) - : type(typeA) - , patternRefNum(patternRefNumA) -{ - -} - -GfxPattern::~GfxPattern() { -} - -GfxPattern *GfxPattern::parse(GfxResources *res, Object *obj, OutputDev *out, GfxState *state, int patternRefNum) { - GfxPattern *pattern; - Object obj1; - - if (obj->isDict()) { - obj1 = obj->dictLookup("PatternType"); - } else if (obj->isStream()) { - obj1 = obj->streamGetDict()->lookup("PatternType"); - } else { - return nullptr; - } - pattern = nullptr; - if (obj1.isInt() && obj1.getInt() == 1) { - pattern = GfxTilingPattern::parse(obj, patternRefNum); - } else if (obj1.isInt() && obj1.getInt() == 2) { - pattern = GfxShadingPattern::parse(res, obj, out, state, patternRefNum); - } - return pattern; -} - -//------------------------------------------------------------------------ -// GfxTilingPattern -//------------------------------------------------------------------------ - -GfxTilingPattern *GfxTilingPattern::parse(Object *patObj, int patternRefNum) { - Dict *dict; - int paintTypeA, tilingTypeA; - double bboxA[4], matrixA[6]; - double xStepA, yStepA; - Object resDictA; - Object obj1; - int i; - - if (!patObj->isStream()) { - return nullptr; - } - dict = patObj->streamGetDict(); - - obj1 = dict->lookup("PaintType"); - if (obj1.isInt()) { - paintTypeA = obj1.getInt(); - } else { - paintTypeA = 1; - error(errSyntaxWarning, -1, "Invalid or missing PaintType in pattern"); - } - obj1 = dict->lookup("TilingType"); - if (obj1.isInt()) { - tilingTypeA = obj1.getInt(); - } else { - tilingTypeA = 1; - error(errSyntaxWarning, -1, "Invalid or missing TilingType in pattern"); - } - bboxA[0] = bboxA[1] = 0; - bboxA[2] = bboxA[3] = 1; - obj1 = dict->lookup("BBox"); - if (obj1.isArray() && obj1.arrayGetLength() == 4) { - for (i = 0; i < 4; ++i) { - Object obj2 = obj1.arrayGet(i); - if (obj2.isNum()) { - bboxA[i] = obj2.getNum(); - } - } - } else { - error(errSyntaxWarning, -1, "Invalid or missing BBox in pattern"); - } - obj1 = dict->lookup("XStep"); - if (obj1.isNum()) { - xStepA = obj1.getNum(); - } else { - xStepA = 1; - error(errSyntaxWarning, -1, "Invalid or missing XStep in pattern"); - } - obj1 = dict->lookup("YStep"); - if (obj1.isNum()) { - yStepA = obj1.getNum(); - } else { - yStepA = 1; - error(errSyntaxWarning, -1, "Invalid or missing YStep in pattern"); - } - resDictA = dict->lookup("Resources"); - if (!resDictA.isDict()) { - error(errSyntaxWarning, -1, "Invalid or missing Resources in pattern"); - } - matrixA[0] = 1; matrixA[1] = 0; - matrixA[2] = 0; matrixA[3] = 1; - matrixA[4] = 0; matrixA[5] = 0; - obj1 = dict->lookup("Matrix"); - if (obj1.isArray() && obj1.arrayGetLength() == 6) { - for (i = 0; i < 6; ++i) { - Object obj2 = obj1.arrayGet(i); - if (obj2.isNum()) { - matrixA[i] = obj2.getNum(); - } - } - } - - return new GfxTilingPattern(paintTypeA, tilingTypeA, bboxA, xStepA, yStepA, - &resDictA, matrixA, patObj, patternRefNum); -} - -GfxTilingPattern::GfxTilingPattern(int paintTypeA, int tilingTypeA, - double *bboxA, double xStepA, double yStepA, - Object *resDictA, double *matrixA, - Object *contentStreamA, int patternRefNumA) : - GfxPattern(1, patternRefNumA) -{ - int i; - - paintType = paintTypeA; - tilingType = tilingTypeA; - for (i = 0; i < 4; ++i) { - bbox[i] = bboxA[i]; - } - xStep = xStepA; - yStep = yStepA; - resDict = resDictA->copy(); - for (i = 0; i < 6; ++i) { - matrix[i] = matrixA[i]; - } - contentStream = contentStreamA->copy(); -} - -GfxTilingPattern::~GfxTilingPattern() { -} - -GfxPattern *GfxTilingPattern::copy() { - return new GfxTilingPattern(paintType, tilingType, bbox, xStep, yStep, - &resDict, matrix, &contentStream, getPatternRefNum()); -} - -//------------------------------------------------------------------------ -// GfxShadingPattern -//------------------------------------------------------------------------ - -GfxShadingPattern *GfxShadingPattern::parse(GfxResources *res, Object *patObj, OutputDev *out, GfxState *state, int patternRefNum) { - Dict *dict; - GfxShading *shadingA; - double matrixA[6]; - Object obj1; - int i; - - if (!patObj->isDict()) { - return nullptr; - } - dict = patObj->getDict(); - - obj1 = dict->lookup("Shading"); - shadingA = GfxShading::parse(res, &obj1, out, state); - if (!shadingA) { - return nullptr; - } - - matrixA[0] = 1; matrixA[1] = 0; - matrixA[2] = 0; matrixA[3] = 1; - matrixA[4] = 0; matrixA[5] = 0; - obj1 = dict->lookup("Matrix"); - if (obj1.isArray() && obj1.arrayGetLength() == 6) { - for (i = 0; i < 6; ++i) { - Object obj2 = obj1.arrayGet(i); - if (obj2.isNum()) { - matrixA[i] = obj2.getNum(); - } - } - } - - return new GfxShadingPattern(shadingA, matrixA, patternRefNum); -} - -GfxShadingPattern::GfxShadingPattern(GfxShading *shadingA, double *matrixA, int patternRefNumA): - GfxPattern(2, patternRefNumA) -{ - int i; - - shading = shadingA; - for (i = 0; i < 6; ++i) { - matrix[i] = matrixA[i]; - } -} - -GfxShadingPattern::~GfxShadingPattern() { - delete shading; -} - -GfxPattern *GfxShadingPattern::copy() { - return new GfxShadingPattern(shading->copy(), matrix, getPatternRefNum()); -} - -//------------------------------------------------------------------------ -// GfxShading -//------------------------------------------------------------------------ - -GfxShading::GfxShading(int typeA) { - type = typeA; - colorSpace = nullptr; -} - -GfxShading::GfxShading(GfxShading *shading) { - int i; - - type = shading->type; - colorSpace = shading->colorSpace->copy(); - for (i = 0; i < gfxColorMaxComps; ++i) { - background.c[i] = shading->background.c[i]; - } - hasBackground = shading->hasBackground; - xMin = shading->xMin; - yMin = shading->yMin; - xMax = shading->xMax; - yMax = shading->yMax; - hasBBox = shading->hasBBox; -} - -GfxShading::~GfxShading() { - if (colorSpace) { - delete colorSpace; - } -} - -GfxShading *GfxShading::parse(GfxResources *res, Object *obj, OutputDev *out, GfxState *state) { - GfxShading *shading; - Dict *dict; - int typeA; - Object obj1; - - if (obj->isDict()) { - dict = obj->getDict(); - } else if (obj->isStream()) { - dict = obj->streamGetDict(); - } else { - return nullptr; - } - - obj1 = dict->lookup("ShadingType"); - if (!obj1.isInt()) { - error(errSyntaxWarning, -1, "Invalid ShadingType in shading dictionary"); - return nullptr; - } - typeA = obj1.getInt(); - - switch (typeA) { - case 1: - shading = GfxFunctionShading::parse(res, dict, out, state); - break; - case 2: - shading = GfxAxialShading::parse(res, dict, out, state); - break; - case 3: - shading = GfxRadialShading::parse(res, dict, out, state); - break; - case 4: - if (obj->isStream()) { - shading = GfxGouraudTriangleShading::parse(res, 4, dict, obj->getStream(), out, state); - } else { - error(errSyntaxWarning, -1, "Invalid Type 4 shading object"); - goto err1; - } - break; - case 5: - if (obj->isStream()) { - shading = GfxGouraudTriangleShading::parse(res, 5, dict, obj->getStream(), out, state); - } else { - error(errSyntaxWarning, -1, "Invalid Type 5 shading object"); - goto err1; - } - break; - case 6: - if (obj->isStream()) { - shading = GfxPatchMeshShading::parse(res, 6, dict, obj->getStream(), out, state); - } else { - error(errSyntaxWarning, -1, "Invalid Type 6 shading object"); - goto err1; - } - break; - case 7: - if (obj->isStream()) { - shading = GfxPatchMeshShading::parse(res, 7, dict, obj->getStream(), out, state); - } else { - error(errSyntaxWarning, -1, "Invalid Type 7 shading object"); - goto err1; - } - break; - default: - error(errSyntaxWarning, -1, "Unimplemented shading type {0:d}", typeA); - goto err1; - } - - return shading; - - err1: - return nullptr; -} - -GBool GfxShading::init(GfxResources *res, Dict *dict, OutputDev *out, GfxState *state) { - Object obj1; - int i; - - obj1 = dict->lookup("ColorSpace"); - if (!(colorSpace = GfxColorSpace::parse(res, &obj1, out, state))) { - error(errSyntaxWarning, -1, "Bad color space in shading dictionary"); - return gFalse; - } - - for (i = 0; i < gfxColorMaxComps; ++i) { - background.c[i] = 0; - } - hasBackground = gFalse; - obj1 = dict->lookup("Background"); - if (obj1.isArray()) { - if (obj1.arrayGetLength() == colorSpace->getNComps()) { - hasBackground = gTrue; - for (i = 0; i < colorSpace->getNComps(); ++i) { - Object obj2 = obj1.arrayGet(i); - background.c[i] = dblToCol(obj2.getNum()); - } - } else { - error(errSyntaxWarning, -1, "Bad Background in shading dictionary"); - } - } - - xMin = yMin = xMax = yMax = 0; - hasBBox = gFalse; - obj1 = dict->lookup("BBox"); - if (obj1.isArray()) { - if (obj1.arrayGetLength() == 4) { - Object obj2 = obj1.arrayGet(0); - Object obj3 = obj1.arrayGet(1); - Object obj4 = obj1.arrayGet(2); - Object obj5 = obj1.arrayGet(3); - if (obj2.isNum() && obj3.isNum() && obj4.isNum() && obj5.isNum()) - { - hasBBox = gTrue; - xMin = obj2.getNum(); - yMin = obj3.getNum(); - xMax = obj4.getNum(); - yMax = obj5.getNum(); - } else { - error(errSyntaxWarning, -1, "Bad BBox in shading dictionary (Values not numbers)"); - } - } else { - error(errSyntaxWarning, -1, "Bad BBox in shading dictionary"); - } - } - - return gTrue; -} - -//------------------------------------------------------------------------ -// GfxFunctionShading -//------------------------------------------------------------------------ - -GfxFunctionShading::GfxFunctionShading(double x0A, double y0A, - double x1A, double y1A, - double *matrixA, - Function **funcsA, int nFuncsA): - GfxShading(1) -{ - int i; - - x0 = x0A; - y0 = y0A; - x1 = x1A; - y1 = y1A; - for (i = 0; i < 6; ++i) { - matrix[i] = matrixA[i]; - } - nFuncs = nFuncsA; - for (i = 0; i < nFuncs; ++i) { - funcs[i] = funcsA[i]; - } -} - -GfxFunctionShading::GfxFunctionShading(GfxFunctionShading *shading): - GfxShading(shading) -{ - int i; - - x0 = shading->x0; - y0 = shading->y0; - x1 = shading->x1; - y1 = shading->y1; - for (i = 0; i < 6; ++i) { - matrix[i] = shading->matrix[i]; - } - nFuncs = shading->nFuncs; - for (i = 0; i < nFuncs; ++i) { - funcs[i] = shading->funcs[i]->copy(); - } -} - -GfxFunctionShading::~GfxFunctionShading() { - int i; - - for (i = 0; i < nFuncs; ++i) { - delete funcs[i]; - } -} - -GfxFunctionShading *GfxFunctionShading::parse(GfxResources *res, Dict *dict, OutputDev *out, GfxState *state) { - GfxFunctionShading *shading; - double x0A, y0A, x1A, y1A; - double matrixA[6]; - Function *funcsA[gfxColorMaxComps]; - int nFuncsA; - Object obj1; - int i; - - x0A = y0A = 0; - x1A = y1A = 1; - obj1 = dict->lookup("Domain"); - if (obj1.isArray() && obj1.arrayGetLength() == 4) { - bool decodeOk = true; - Object obj2; - x0A = (obj2 = obj1.arrayGet(0), obj2.getNum(&decodeOk)); - x1A = (obj2 = obj1.arrayGet(1), obj2.getNum(&decodeOk)); - y0A = (obj2 = obj1.arrayGet(2), obj2.getNum(&decodeOk)); - y1A = (obj2 = obj1.arrayGet(3), obj2.getNum(&decodeOk)); - - if (!decodeOk) { - error(errSyntaxWarning, -1, "Invalid Domain array in function shading dictionary"); - return nullptr; - } - } - - matrixA[0] = 1; matrixA[1] = 0; - matrixA[2] = 0; matrixA[3] = 1; - matrixA[4] = 0; matrixA[5] = 0; - obj1 = dict->lookup("Matrix"); - if (obj1.isArray() && obj1.arrayGetLength() == 6) { - bool decodeOk = true; - Object obj2; - matrixA[0] = (obj2 = obj1.arrayGet(0), obj2.getNum(&decodeOk)); - matrixA[1] = (obj2 = obj1.arrayGet(1), obj2.getNum(&decodeOk)); - matrixA[2] = (obj2 = obj1.arrayGet(2), obj2.getNum(&decodeOk)); - matrixA[3] = (obj2 = obj1.arrayGet(3), obj2.getNum(&decodeOk)); - matrixA[4] = (obj2 = obj1.arrayGet(4), obj2.getNum(&decodeOk)); - matrixA[5] = (obj2 = obj1.arrayGet(5), obj2.getNum(&decodeOk)); - - if (!decodeOk) { - error(errSyntaxWarning, -1, "Invalid Matrix array in function shading dictionary"); - return nullptr; - } - } - - obj1 = dict->lookup("Function"); - if (obj1.isArray()) { - nFuncsA = obj1.arrayGetLength(); - if (nFuncsA > gfxColorMaxComps || nFuncsA <= 0) { - error(errSyntaxWarning, -1, "Invalid Function array in shading dictionary"); - return nullptr; - } - for (i = 0; i < nFuncsA; ++i) { - Object obj2 = obj1.arrayGet(i); - if (!(funcsA[i] = Function::parse(&obj2))) { - return nullptr; - } - } - } else { - nFuncsA = 1; - if (!(funcsA[0] = Function::parse(&obj1))) { - return nullptr; - } - } - - shading = new GfxFunctionShading(x0A, y0A, x1A, y1A, matrixA, - funcsA, nFuncsA); - if (!shading->init(res, dict, out, state)) { - delete shading; - return nullptr; - } - return shading; -} - -GfxShading *GfxFunctionShading::copy() { - return new GfxFunctionShading(this); -} - -void GfxFunctionShading::getColor(double x, double y, GfxColor *color) { - double in[2], out[gfxColorMaxComps]; - int i; - - // NB: there can be one function with n outputs or n functions with - // one output each (where n = number of color components) - for (i = 0; i < gfxColorMaxComps; ++i) { - out[i] = 0; - } - in[0] = x; - in[1] = y; - for (i = 0; i < nFuncs; ++i) { - funcs[i]->transform(in, &out[i]); - } - for (i = 0; i < gfxColorMaxComps; ++i) { - color->c[i] = dblToCol(out[i]); - } -} - -//------------------------------------------------------------------------ -// GfxUnivariateShading -//------------------------------------------------------------------------ - -GfxUnivariateShading::GfxUnivariateShading(int typeA, - double t0A, double t1A, - Function **funcsA, int nFuncsA, - GBool extend0A, GBool extend1A): - GfxShading(typeA) -{ - int i; - - t0 = t0A; - t1 = t1A; - nFuncs = nFuncsA; - for (i = 0; i < nFuncs; ++i) { - funcs[i] = funcsA[i]; - } - extend0 = extend0A; - extend1 = extend1A; - - cacheSize = 0; - lastMatch = 0; - cacheBounds = nullptr; - cacheCoeff = nullptr; - cacheValues = nullptr; -} - -GfxUnivariateShading::GfxUnivariateShading(GfxUnivariateShading *shading): - GfxShading(shading) -{ - int i; - - t0 = shading->t0; - t1 = shading->t1; - nFuncs = shading->nFuncs; - for (i = 0; i < nFuncs; ++i) { - funcs[i] = shading->funcs[i]->copy(); - } - extend0 = shading->extend0; - extend1 = shading->extend1; - - cacheSize = 0; - lastMatch = 0; - cacheBounds = nullptr; - cacheCoeff = nullptr; - cacheValues = nullptr; -} - -GfxUnivariateShading::~GfxUnivariateShading() { - int i; - - for (i = 0; i < nFuncs; ++i) { - delete funcs[i]; - } - - gfree (cacheBounds); -} - -int GfxUnivariateShading::getColor(double t, GfxColor *color) { - double out[gfxColorMaxComps]; - int nComps; - - if (likely(nFuncs >= 1)) { - // NB: there can be one function with n outputs or n functions with - // one output each (where n = number of color components) - nComps = nFuncs * funcs[0]->getOutputSize(); - } - - if (unlikely(nFuncs < 1 || nComps > gfxColorMaxComps)) { - for (int i = 0; i < gfxColorMaxComps; i++) - color->c[i] = 0; - return gfxColorMaxComps; - } - - if (cacheSize > 0) { - double x, ix, *l, *u, *upper; - - if (cacheBounds[lastMatch - 1] >= t) { - upper = std::lower_bound (cacheBounds, cacheBounds + lastMatch - 1, t); - lastMatch = upper - cacheBounds; - lastMatch = std::min<int>(std::max<int>(1, lastMatch), cacheSize - 1); - } else if (cacheBounds[lastMatch] < t) { - upper = std::lower_bound (cacheBounds + lastMatch + 1, cacheBounds + cacheSize, t); - lastMatch = upper - cacheBounds; - lastMatch = std::min<int>(std::max<int>(1, lastMatch), cacheSize - 1); - } - - x = (t - cacheBounds[lastMatch-1]) * cacheCoeff[lastMatch]; - ix = 1.0 - x; - u = cacheValues + lastMatch * nComps; - l = u - nComps; - - for (int i = 0; i < nComps; ++i) { - out[i] = ix * l[i] + x * u[i]; - } - } else { - for (int i = 0; i < nComps; ++i) { - out[i] = 0; - } - for (int i = 0; i < nFuncs; ++i) { - if (funcs[i]->getInputSize() != 1) { - error(errSyntaxWarning, -1, "Invalid shading function (input != 1)"); - break; - } - funcs[i]->transform(&t, &out[i]); - } - } - - for (int i = 0; i < nComps; ++i) { - color->c[i] = dblToCol(out[i]); - } - return nComps; -} - -void GfxUnivariateShading::setupCache(const Matrix *ctm, - double xMin, double yMin, - double xMax, double yMax) { - double sMin, sMax, tMin, tMax, upperBound; - int i, j, nComps, maxSize; - - gfree (cacheBounds); - cacheBounds = nullptr; - cacheSize = 0; - - if (unlikely(nFuncs < 1)) - return; - - // NB: there can be one function with n outputs or n functions with - // one output each (where n = number of color components) - nComps = nFuncs * funcs[0]->getOutputSize(); - - getParameterRange(&sMin, &sMax, xMin, yMin, xMax, yMax); - upperBound = ctm->norm() * getDistance(sMin, sMax); - maxSize = ceil(upperBound); - maxSize = std::max<int>(maxSize, 2); - - { - double x[4], y[4]; - - ctm->transform(xMin, yMin, &x[0], &y[0]); - ctm->transform(xMax, yMin, &x[1], &y[1]); - ctm->transform(xMin, yMax, &x[2], &y[2]); - ctm->transform(xMax, yMax, &x[3], &y[3]); - - xMin = xMax = x[0]; - yMin = yMax = y[0]; - for (i = 1; i < 4; i++) { - xMin = std::min<double>(xMin, x[i]); - yMin = std::min<double>(yMin, y[i]); - xMax = std::max<double>(xMax, x[i]); - yMax = std::max<double>(yMax, y[i]); - } - } - - if (maxSize > (xMax-xMin) * (yMax-yMin)) { - return; - } - - if (t0 < t1) { - tMin = t0 + sMin * (t1 - t0); - tMax = t0 + sMax * (t1 - t0); - } else { - tMin = t0 + sMax * (t1 - t0); - tMax = t0 + sMin * (t1 - t0); - } - - cacheBounds = (double *)gmallocn(maxSize, sizeof(double) * (nComps + 2)); - cacheCoeff = cacheBounds + maxSize; - cacheValues = cacheCoeff + maxSize; - - if (cacheSize != 0) { - for (j = 0; j < cacheSize; ++j) { - cacheCoeff[j] = 1 / (cacheBounds[j+1] - cacheBounds[j]); - } - } else if (tMax != tMin) { - double step = (tMax - tMin) / (maxSize - 1); - double coeff = (maxSize - 1) / (tMax - tMin); - - cacheSize = maxSize; - - for (j = 0; j < cacheSize; ++j) { - cacheBounds[j] = tMin + j * step; - cacheCoeff[j] = coeff; - - for (i = 0; i < nComps; ++i) { - cacheValues[j*nComps + i] = 0; - } - for (i = 0; i < nFuncs; ++i) { - funcs[i]->transform(&cacheBounds[j], &cacheValues[j*nComps + i]); - } - } - } - - lastMatch = 1; -} - - -//------------------------------------------------------------------------ -// GfxAxialShading -//------------------------------------------------------------------------ - -GfxAxialShading::GfxAxialShading(double x0A, double y0A, - double x1A, double y1A, - double t0A, double t1A, - Function **funcsA, int nFuncsA, - GBool extend0A, GBool extend1A): - GfxUnivariateShading(2, t0A, t1A, funcsA, nFuncsA, extend0A, extend1A) -{ - x0 = x0A; - y0 = y0A; - x1 = x1A; - y1 = y1A; -} - -GfxAxialShading::GfxAxialShading(GfxAxialShading *shading): - GfxUnivariateShading(shading) -{ - x0 = shading->x0; - y0 = shading->y0; - x1 = shading->x1; - y1 = shading->y1; -} - -GfxAxialShading::~GfxAxialShading() { -} - -GfxAxialShading *GfxAxialShading::parse(GfxResources *res, Dict *dict, OutputDev *out, GfxState *state) { - GfxAxialShading *shading; - double x0A, y0A, x1A, y1A; - double t0A, t1A; - Function *funcsA[gfxColorMaxComps]; - int nFuncsA; - GBool extend0A, extend1A; - Object obj1; - - x0A = y0A = x1A = y1A = 0; - obj1 = dict->lookup("Coords"); - if (obj1.isArray() && obj1.arrayGetLength() == 4) { - Object obj2 = obj1.arrayGet(0); - Object obj3 = obj1.arrayGet(1); - Object obj4 = obj1.arrayGet(2); - Object obj5 = obj1.arrayGet(3); - if (obj2.isNum() && obj3.isNum() && obj4.isNum() && obj5.isNum()) { - x0A = obj2.getNum(); - y0A = obj3.getNum(); - x1A = obj4.getNum(); - y1A = obj5.getNum(); - } - } else { - error(errSyntaxWarning, -1, "Missing or invalid Coords in shading dictionary"); - return nullptr; - } - - t0A = 0; - t1A = 1; - obj1 = dict->lookup("Domain"); - if (obj1.isArray() && obj1.arrayGetLength() == 2) { - Object obj2 = obj1.arrayGet(0); - Object obj3 = obj1.arrayGet(1); - if (obj2.isNum() && obj3.isNum()) { - t0A = obj2.getNum(); - t1A = obj3.getNum(); - } - } - - obj1 = dict->lookup("Function"); - if (obj1.isArray()) { - nFuncsA = obj1.arrayGetLength(); - if (nFuncsA > gfxColorMaxComps || nFuncsA == 0) { - error(errSyntaxWarning, -1, "Invalid Function array in shading dictionary"); - return nullptr; - } - for (int i = 0; i < nFuncsA; ++i) { - Object obj2 = obj1.arrayGet(i); - if (!(funcsA[i] = Function::parse(&obj2))) { - for (int j = 0; j < i; ++j) - delete funcsA[j]; - return nullptr; - } - } - } else { - nFuncsA = 1; - if (!(funcsA[0] = Function::parse(&obj1))) { - return nullptr; - } - } - - extend0A = extend1A = gFalse; - obj1 = dict->lookup("Extend"); - if (obj1.isArray() && obj1.arrayGetLength() == 2) { - Object obj2 = obj1.arrayGet(0); - if (obj2.isBool()) { - extend0A = obj2.getBool(); - } else { - error(errSyntaxWarning, -1, "Invalid axial shading extend (0)"); - } - obj2 = obj1.arrayGet(1); - if (obj2.isBool()) { - extend1A = obj2.getBool(); - } else { - error(errSyntaxWarning, -1, "Invalid axial shading extend (1)"); - } - } - - shading = new GfxAxialShading(x0A, y0A, x1A, y1A, t0A, t1A, - funcsA, nFuncsA, extend0A, extend1A); - if (!shading->init(res, dict, out, state)) { - delete shading; - shading = nullptr; - } - return shading; -} - -GfxShading *GfxAxialShading::copy() { - return new GfxAxialShading(this); -} - -double GfxAxialShading::getDistance(double sMin, double sMax) { - double xMin, yMin, xMax, yMax; - - xMin = x0 + sMin * (x1 - x0); - yMin = y0 + sMin * (y1 - y0); - xMax = x0 + sMax * (x1 - x0); - yMax = y0 + sMax * (y1 - y0); - - return hypot(xMax-xMin, yMax-yMin); -} - -void GfxAxialShading::getParameterRange(double *lower, double *upper, - double xMin, double yMin, - double xMax, double yMax) { - double pdx, pdy, invsqnorm, tdx, tdy, t, range[2]; - - // Linear gradients are orthogonal to the line passing through their - // extremes. Because of convexity, the parameter range can be - // computed as the convex hull (one the real line) of the parameter - // values of the 4 corners of the box. - // - // The parameter value t for a point (x,y) can be computed as: - // - // t = (p2 - p1) . (x,y) / |p2 - p1|^2 - // - // t0 is the t value for the top left corner - // tdx is the difference between left and right corners - // tdy is the difference between top and bottom corners - - pdx = x1 - x0; - pdy = y1 - y0; - const double invsqnorm_denominator = (pdx * pdx + pdy * pdy); - if (unlikely(invsqnorm_denominator == 0)) { - *lower = 0; - *upper = 0; - return; - } - invsqnorm = 1.0 / invsqnorm_denominator; - pdx *= invsqnorm; - pdy *= invsqnorm; - - t = (xMin - x0) * pdx + (yMin - y0) * pdy; - tdx = (xMax - xMin) * pdx; - tdy = (yMax - yMin) * pdy; - - // Because of the linearity of the t value, tdx can simply be added - // the t0 to move along the top edge. After this, *lower and *upper - // represent the parameter range for the top edge, so extending it - // to include the whole box simply requires adding tdy to the - // correct extreme. - - range[0] = range[1] = t; - if (tdx < 0) - range[0] += tdx; - else - range[1] += tdx; - - if (tdy < 0) - range[0] += tdy; - else - range[1] += tdy; - - *lower = std::max<double>(0., std::min<double>(1., range[0])); - *upper = std::max<double>(0., std::min<double>(1., range[1])); -} - -//------------------------------------------------------------------------ -// GfxRadialShading -//------------------------------------------------------------------------ - -#ifndef RADIAL_EPSILON -#define RADIAL_EPSILON (1. / 1024 / 1024) -#endif - -GfxRadialShading::GfxRadialShading(double x0A, double y0A, double r0A, - double x1A, double y1A, double r1A, - double t0A, double t1A, - Function **funcsA, int nFuncsA, - GBool extend0A, GBool extend1A): - GfxUnivariateShading(3, t0A, t1A, funcsA, nFuncsA, extend0A, extend1A) -{ - x0 = x0A; - y0 = y0A; - r0 = r0A; - x1 = x1A; - y1 = y1A; - r1 = r1A; -} - -GfxRadialShading::GfxRadialShading(GfxRadialShading *shading): - GfxUnivariateShading(shading) -{ - x0 = shading->x0; - y0 = shading->y0; - r0 = shading->r0; - x1 = shading->x1; - y1 = shading->y1; - r1 = shading->r1; -} - -GfxRadialShading::~GfxRadialShading() { -} - -GfxRadialShading *GfxRadialShading::parse(GfxResources *res, Dict *dict, OutputDev *out, GfxState *state) { - GfxRadialShading *shading; - double x0A, y0A, r0A, x1A, y1A, r1A; - double t0A, t1A; - Function *funcsA[gfxColorMaxComps]; - int nFuncsA; - GBool extend0A, extend1A; - Object obj1; - int i; - - x0A = y0A = r0A = x1A = y1A = r1A = 0; - obj1 = dict->lookup("Coords"); - if (obj1.isArray() && obj1.arrayGetLength() == 6) { - Object obj2; - bool dummy; // just so that we can use the getNum that returns 0 on obj2 not being a num instead of aborting - x0A = (obj2 = obj1.arrayGet(0), obj2.getNum(&dummy)); - y0A = (obj2 = obj1.arrayGet(1), obj2.getNum(&dummy)); - r0A = (obj2 = obj1.arrayGet(2), obj2.getNum(&dummy)); - x1A = (obj2 = obj1.arrayGet(3), obj2.getNum(&dummy)); - y1A = (obj2 = obj1.arrayGet(4), obj2.getNum(&dummy)); - r1A = (obj2 = obj1.arrayGet(5), obj2.getNum(&dummy)); - } else { - error(errSyntaxWarning, -1, "Missing or invalid Coords in shading dictionary"); - return nullptr; - } - - t0A = 0; - t1A = 1; - obj1 = dict->lookup("Domain"); - if (obj1.isArray() && obj1.arrayGetLength() == 2) { - Object obj2; - t0A = (obj2 = obj1.arrayGet(0), obj2.isNum() ? obj2.getNum() : 0); - t1A = (obj2 = obj1.arrayGet(1), obj2.isNum() ? obj2.getNum() : 1); - } - - obj1 = dict->lookup("Function"); - if (obj1.isArray()) { - nFuncsA = obj1.arrayGetLength(); - if (nFuncsA > gfxColorMaxComps) { - error(errSyntaxWarning, -1, "Invalid Function array in shading dictionary"); - return nullptr; - } - for (i = 0; i < nFuncsA; ++i) { - Object obj2 = obj1.arrayGet(i); - if (!(funcsA[i] = Function::parse(&obj2))) { - return nullptr; - } - } - } else { - nFuncsA = 1; - if (!(funcsA[0] = Function::parse(&obj1))) { - return nullptr; - } - } - - extend0A = extend1A = gFalse; - obj1 = dict->lookup("Extend"); - if (obj1.isArray() && obj1.arrayGetLength() == 2) { - Object obj2; - extend0A = (obj2 = obj1.arrayGet(0), obj2.isBool() ? obj2.getBool() : gFalse); - extend1A = (obj2 = obj1.arrayGet(1), obj2.isBool() ? obj2.getBool() : gFalse); - } - - shading = new GfxRadialShading(x0A, y0A, r0A, x1A, y1A, r1A, t0A, t1A, - funcsA, nFuncsA, extend0A, extend1A); - if (!shading->init(res, dict, out, state)) { - delete shading; - return nullptr; - } - return shading; -} - -GfxShading *GfxRadialShading::copy() { - return new GfxRadialShading(this); -} - -double GfxRadialShading::getDistance(double sMin, double sMax) { - double xMin, yMin, rMin, xMax, yMax, rMax; - - xMin = x0 + sMin * (x1 - x0); - yMin = y0 + sMin * (y1 - y0); - rMin = r0 + sMin * (r1 - r0); - - xMax = x0 + sMax * (x1 - x0); - yMax = y0 + sMax * (y1 - y0); - rMax = r0 + sMax * (r1 - r0); - - return hypot(xMax-xMin, yMax-yMin) + fabs(rMax-rMin); -} - -// extend range, adapted from cairo, radialExtendRange -static GBool -radialExtendRange (double range[2], double value, GBool valid) -{ - if (!valid) - range[0] = range[1] = value; - else if (value < range[0]) - range[0] = value; - else if (value > range[1]) - range[1] = value; - - return gTrue; -} - -inline void radialEdge(double num, double den, double delta, double lower, double upper, - double dr, double mindr, GBool &valid, double *range) -{ - if (fabs (den) >= RADIAL_EPSILON) { - double t_edge, v; - t_edge = (num) / (den); - v = t_edge * (delta); - if (t_edge * dr >= mindr && (lower) <= v && v <= (upper)) - valid = radialExtendRange (range, t_edge, valid); - } -} - -inline void radialCorner1(double x, double y, double &b, double dx, double dy, double cr, - double dr, double mindr, GBool &valid, double *range) -{ - b = (x) * dx + (y) * dy + cr * dr; - if (fabs (b) >= RADIAL_EPSILON) { - double t_corner; - double x2 = (x) * (x); - double y2 = (y) * (y); - double cr2 = (cr) * (cr); - double c = x2 + y2 - cr2; - - t_corner = 0.5 * c / b; - if (t_corner * dr >= mindr) - valid = radialExtendRange (range, t_corner, valid); - } -} - -inline void radialCorner2(double x, double y, double a, double &b, double &c, double &d, double dx, double dy, double cr, - double inva, double dr, double mindr, GBool &valid, double *range) -{ - b = (x) * dx + (y) * dy + cr * dr; - c = (x) * (x) + (y) * (y) - cr * cr; - d = b * b - a * c; - if (d >= 0) { - double t_corner; - - d = sqrt (d); - t_corner = (b + d) * inva; - if (t_corner * dr >= mindr) - valid = radialExtendRange (range, t_corner, valid); - t_corner = (b - d) * inva; - if (t_corner * dr >= mindr) - valid = radialExtendRange (range, t_corner, valid); - } -} -void GfxRadialShading::getParameterRange(double *lower, double *upper, - double xMin, double yMin, - double xMax, double yMax) { - double cx, cy, cr, dx, dy, dr; - double a, x_focus, y_focus; - double mindr, minx, miny, maxx, maxy; - double range[2]; - GBool valid; - - // A radial pattern is considered degenerate if it can be - // represented as a solid or clear pattern. This corresponds to one - // of the two cases: - // - // 1) The radii are both very small: - // |dr| < FLT_EPSILON && min (r0, r1) < FLT_EPSILON - // - // 2) The two circles have about the same radius and are very - // close to each other (approximately a cylinder gradient that - // doesn't move with the parameter): - // |dr| < FLT_EPSILON && max (|dx|, |dy|) < 2 * FLT_EPSILON - - if (xMin >= xMax || yMin >=yMax || - (fabs (r0 - r1) < RADIAL_EPSILON && - (std::min<double>(r0, r1) < RADIAL_EPSILON || - std::max<double>(fabs (x0 - x1), fabs (y0 - y1)) < 2 * RADIAL_EPSILON))) { - *lower = *upper = 0; - return; - } - - range[0] = range[1] = 0; - valid = gFalse; - - x_focus = y_focus = 0; // silence gcc - - cx = x0; - cy = y0; - cr = r0; - dx = x1 - cx; - dy = y1 - cy; - dr = r1 - cr; - - // translate by -(cx, cy) to simplify computations - xMin -= cx; - yMin -= cy; - xMax -= cx; - yMax -= cy; - - // enlarge boundaries slightly to avoid rounding problems in the - // parameter range computation - xMin -= RADIAL_EPSILON; - yMin -= RADIAL_EPSILON; - xMax += RADIAL_EPSILON; - yMax += RADIAL_EPSILON; - - // enlarge boundaries even more to avoid rounding problems when - // testing if a point belongs to the box - minx = xMin - RADIAL_EPSILON; - miny = yMin - RADIAL_EPSILON; - maxx = xMax + RADIAL_EPSILON; - maxy = yMax + RADIAL_EPSILON; - - // we dont' allow negative radiuses, so we will be checking that - // t*dr >= mindr to consider t valid - mindr = -(cr + RADIAL_EPSILON); - - // After the previous transformations, the start circle is centered - // in the origin and has radius cr. A 1-unit change in the t - // parameter corresponds to dx,dy,dr changes in the x,y,r of the - // circle (center coordinates, radius). - // - // To compute the minimum range needed to correctly draw the - // pattern, we start with an empty range and extend it to include - // the circles touching the bounding box or within it. - - // Focus, the point where the circle has radius == 0. - // - // r = cr + t * dr = 0 - // t = -cr / dr - // - // If the radius is constant (dr == 0) there is no focus (the - // gradient represents a cylinder instead of a cone). - if (fabs (dr) >= RADIAL_EPSILON) { - double t_focus; - - t_focus = -cr / dr; - x_focus = t_focus * dx; - y_focus = t_focus * dy; - if (minx <= x_focus && x_focus <= maxx && - miny <= y_focus && y_focus <= maxy) - { - valid = radialExtendRange (range, t_focus, valid); - } - } - - // Circles externally tangent to box edges. - // - // All circles have center in (dx, dy) * t - // - // If the circle is tangent to the line defined by the edge of the - // box, then at least one of the following holds true: - // - // (dx*t) + (cr + dr*t) == x0 (left edge) - // (dx*t) - (cr + dr*t) == x1 (right edge) - // (dy*t) + (cr + dr*t) == y0 (top edge) - // (dy*t) - (cr + dr*t) == y1 (bottom edge) - // - // The solution is only valid if the tangent point is actually on - // the edge, i.e. if its y coordinate is in [y0,y1] for left/right - // edges and if its x coordinate is in [x0,x1] for top/bottom edges. - // - // For the first equation: - // - // (dx + dr) * t = x0 - cr - // t = (x0 - cr) / (dx + dr) - // y = dy * t - // - // in the code this becomes: - // - // t_edge = (num) / (den) - // v = (delta) * t_edge - // - // If the denominator in t is 0, the pattern is tangent to a line - // parallel to the edge under examination. The corner-case where the - // boundary line is the same as the edge is handled by the focus - // point case and/or by the a==0 case. - - // circles tangent (externally) to left/right/top/bottom edge - radialEdge(xMin - cr, dx + dr, dy, miny, maxy, dr, mindr, valid, range); - radialEdge(xMax + cr, dx - dr, dy, miny, maxy, dr, mindr, valid, range); - radialEdge(yMin - cr, dy + dr, dx, minx, maxx, dr, mindr, valid, range); - radialEdge(yMax + cr, dy - dr, dx, minx, maxx, dr, mindr, valid, range); - - // Circles passing through a corner. - // - // A circle passing through the point (x,y) satisfies: - // - // (x-t*dx)^2 + (y-t*dy)^2 == (cr + t*dr)^2 - // - // If we set: - // a = dx^2 + dy^2 - dr^2 - // b = x*dx + y*dy + cr*dr - // c = x^2 + y^2 - cr^2 - // we have: - // a*t^2 - 2*b*t + c == 0 - - a = dx * dx + dy * dy - dr * dr; - if (fabs (a) < RADIAL_EPSILON * RADIAL_EPSILON) { - double b; - - // Ensure that gradients with both a and dr small are - // considered degenerate. - // The floating point version of the degeneracy test implemented - // in _radial_pattern_is_degenerate() is: - // - // 1) The circles are practically the same size: - // |dr| < RADIAL_EPSILON - // AND - // 2a) The circles are both very small: - // min (r0, r1) < RADIAL_EPSILON - // OR - // 2b) The circles are very close to each other: - // max (|dx|, |dy|) < 2 * RADIAL_EPSILON - // - // Assuming that the gradient is not degenerate, we want to - // show that |a| < RADIAL_EPSILON^2 implies |dr| >= RADIAL_EPSILON. - // - // If the gradient is not degenerate yet it has |dr| < - // RADIAL_EPSILON, (2b) is false, thus: - // - // max (|dx|, |dy|) >= 2*RADIAL_EPSILON - // which implies: - // 4*RADIAL_EPSILON^2 <= max (|dx|, |dy|)^2 <= dx^2 + dy^2 - // - // From the definition of a, we get: - // a = dx^2 + dy^2 - dr^2 < RADIAL_EPSILON^2 - // dx^2 + dy^2 - RADIAL_EPSILON^2 < dr^2 - // 3*RADIAL_EPSILON^2 < dr^2 - // - // which is inconsistent with the hypotheses, thus |dr| < - // RADIAL_EPSILON is false or the gradient is degenerate. - - assert (fabs (dr) >= RADIAL_EPSILON); - - // If a == 0, all the circles are tangent to a line in the - // focus point. If this line is within the box extents, we - // should add the circle with infinite radius, but this would - // make the range unbounded. We will be limiting the range to - // [0,1] anyway, so we simply add the biggest legitimate - // circle (it happens for 0 or for 1). - if (dr < 0) { - valid = radialExtendRange (range, 0, valid); - } else { - valid = radialExtendRange (range, 1, valid); - } - - // Nondegenerate, nonlimit circles passing through the corners. - // - // a == 0 && a*t^2 - 2*b*t + c == 0 - // - // t = c / (2*b) - // - // The b == 0 case has just been handled, so we only have to - // compute this if b != 0. - - // circles touching each corner - radialCorner1(xMin, yMin, b, dx, dy, cr, dr, mindr, valid, range); - radialCorner1(xMin, yMax, b, dx, dy, cr, dr, mindr, valid, range); - radialCorner1(xMax, yMin, b, dx, dy, cr, dr, mindr, valid, range); - radialCorner1(xMax, yMax, b, dx, dy, cr, dr, mindr, valid, range); - } else { - double inva, b, c, d; - - inva = 1 / a; - - // Nondegenerate, nonlimit circles passing through the corners. - // - // a != 0 && a*t^2 - 2*b*t + c == 0 - // - // t = (b +- sqrt (b*b - a*c)) / a - // - // If the argument of sqrt() is negative, then no circle - // passes through the corner. - - // circles touching each corner - radialCorner2(xMin, yMin, a, b, c, d, dx, dy, cr, inva, dr, mindr, valid, range); - radialCorner2(xMin, yMax, a, b, c, d, dx, dy, cr, inva, dr, mindr, valid, range); - radialCorner2(xMax, yMin, a, b, c, d, dx, dy, cr, inva, dr, mindr, valid, range); - radialCorner2(xMax, yMax, a, b, c, d, dx, dy, cr, inva, dr, mindr, valid, range); - } - - *lower = std::max<double>(0., std::min<double>(1., range[0])); - *upper = std::max<double>(0., std::min<double>(1., range[1])); -} - -//------------------------------------------------------------------------ -// GfxShadingBitBuf -//------------------------------------------------------------------------ - -class GfxShadingBitBuf { -public: - - GfxShadingBitBuf(Stream *strA); - ~GfxShadingBitBuf(); - GfxShadingBitBuf(const GfxShadingBitBuf &) = delete; - GfxShadingBitBuf& operator=(const GfxShadingBitBuf &) = delete; - GBool getBits(int n, Guint *val); - void flushBits(); - -private: - - Stream *str; - int bitBuf; - int nBits; -}; - -GfxShadingBitBuf::GfxShadingBitBuf(Stream *strA) { - str = strA; - str->reset(); - bitBuf = 0; - nBits = 0; -} - -GfxShadingBitBuf::~GfxShadingBitBuf() { - str->close(); -} - -GBool GfxShadingBitBuf::getBits(int n, Guint *val) { - int x; - - if (nBits >= n) { - x = (bitBuf >> (nBits - n)) & ((1 << n) - 1); - nBits -= n; - } else { - x = 0; - if (nBits > 0) { - x = bitBuf & ((1 << nBits) - 1); - n -= nBits; - nBits = 0; - } - while (n > 0) { - if ((bitBuf = str->getChar()) == EOF) { - nBits = 0; - return gFalse; - } - if (n >= 8) { - x = (x << 8) | bitBuf; - n -= 8; - } else { - x = (x << n) | (bitBuf >> (8 - n)); - nBits = 8 - n; - n = 0; - } - } - } - *val = x; - return gTrue; -} - -void GfxShadingBitBuf::flushBits() { - bitBuf = 0; - nBits = 0; -} - -//------------------------------------------------------------------------ -// GfxGouraudTriangleShading -//------------------------------------------------------------------------ - -GfxGouraudTriangleShading::GfxGouraudTriangleShading( - int typeA, - GfxGouraudVertex *verticesA, int nVerticesA, - int (*trianglesA)[3], int nTrianglesA, - Function **funcsA, int nFuncsA): - GfxShading(typeA) -{ - int i; - - vertices = verticesA; - nVertices = nVerticesA; - triangles = trianglesA; - nTriangles = nTrianglesA; - nFuncs = nFuncsA; - for (i = 0; i < nFuncs; ++i) { - funcs[i] = funcsA[i]; - } -} - -GfxGouraudTriangleShading::GfxGouraudTriangleShading( - GfxGouraudTriangleShading *shading): - GfxShading(shading) -{ - int i; - - nVertices = shading->nVertices; - vertices = (GfxGouraudVertex *)gmallocn(nVertices, sizeof(GfxGouraudVertex)); - memcpy(vertices, shading->vertices, nVertices * sizeof(GfxGouraudVertex)); - nTriangles = shading->nTriangles; - triangles = (int (*)[3])gmallocn(nTriangles * 3, sizeof(int)); - memcpy(triangles, shading->triangles, nTriangles * 3 * sizeof(int)); - nFuncs = shading->nFuncs; - for (i = 0; i < nFuncs; ++i) { - funcs[i] = shading->funcs[i]->copy(); - } -} - -GfxGouraudTriangleShading::~GfxGouraudTriangleShading() { - int i; - - gfree(vertices); - gfree(triangles); - for (i = 0; i < nFuncs; ++i) { - delete funcs[i]; - } -} - -GfxGouraudTriangleShading *GfxGouraudTriangleShading::parse(GfxResources *res, int typeA, - Dict *dict, - Stream *str, - OutputDev *out, GfxState *gfxState) { - GfxGouraudTriangleShading *shading; - Function *funcsA[gfxColorMaxComps]; - int nFuncsA; - int coordBits, compBits, flagBits, vertsPerRow, nRows; - double xMin, xMax, yMin, yMax; - double cMin[gfxColorMaxComps], cMax[gfxColorMaxComps]; - double xMul, yMul; - double cMul[gfxColorMaxComps]; - GfxGouraudVertex *verticesA; - int (*trianglesA)[3]; - int nComps, nVerticesA, nTrianglesA, vertSize, triSize; - Guint x, y, flag; - Guint c[gfxColorMaxComps]; - GfxShadingBitBuf *bitBuf; - Object obj1; - int i, j, k, state; - - obj1 = dict->lookup("BitsPerCoordinate"); - if (obj1.isInt()) { - coordBits = obj1.getInt(); - } else { - error(errSyntaxWarning, -1, "Missing or invalid BitsPerCoordinate in shading dictionary"); - return nullptr; - } - if (unlikely(coordBits <= 0)) { - error(errSyntaxWarning, -1, "Invalid BitsPerCoordinate in shading dictionary"); - return nullptr; - } - obj1 = dict->lookup("BitsPerComponent"); - if (obj1.isInt()) { - compBits = obj1.getInt(); - } else { - error(errSyntaxWarning, -1, "Missing or invalid BitsPerComponent in shading dictionary"); - return nullptr; - } - if (unlikely(compBits <= 0 || compBits > 31)) { - error(errSyntaxWarning, -1, "Invalid BitsPerComponent in shading dictionary"); - return nullptr; - } - flagBits = vertsPerRow = 0; // make gcc happy - if (typeA == 4) { - obj1 = dict->lookup("BitsPerFlag"); - if (obj1.isInt()) { - flagBits = obj1.getInt(); - } else { - error(errSyntaxWarning, -1, "Missing or invalid BitsPerFlag in shading dictionary"); - return nullptr; - } - } else { - obj1 = dict->lookup("VerticesPerRow"); - if (obj1.isInt()) { - vertsPerRow = obj1.getInt(); - } else { - error(errSyntaxWarning, -1, "Missing or invalid VerticesPerRow in shading dictionary"); - return nullptr; - } - } - obj1 = dict->lookup("Decode"); - if (obj1.isArray() && obj1.arrayGetLength() >= 6) { - Object obj2; - bool decodeOk = true; - xMin = (obj2 = obj1.arrayGet(0), obj2.getNum(&decodeOk)); - xMax = (obj2 = obj1.arrayGet(1), obj2.getNum(&decodeOk)); - xMul = (xMax - xMin) / (pow(2.0, coordBits) - 1); - yMin = (obj2 = obj1.arrayGet(2), obj2.getNum(&decodeOk)); - yMax = (obj2 = obj1.arrayGet(3), obj2.getNum(&decodeOk)); - yMul = (yMax - yMin) / (pow(2.0, coordBits) - 1); - for (i = 0; 5 + 2*i < obj1.arrayGetLength() && i < gfxColorMaxComps; ++i) { - cMin[i] = (obj2 = obj1.arrayGet(4 + 2*i), obj2.getNum(&decodeOk)); - cMax[i] = (obj2 = obj1.arrayGet(5 + 2*i), obj2.getNum(&decodeOk)); - cMul[i] = (cMax[i] - cMin[i]) / (double)((1u << compBits) - 1); - } - nComps = i; - - if (!decodeOk) { - error(errSyntaxWarning, -1, "Missing or invalid Decode array in shading dictionary"); - return nullptr; - } - } else { - error(errSyntaxWarning, -1, "Missing or invalid Decode array in shading dictionary"); - return nullptr; - } - - obj1 = dict->lookup("Function"); - if (!obj1.isNull()) { - if (obj1.isArray()) { - nFuncsA = obj1.arrayGetLength(); - if (nFuncsA > gfxColorMaxComps) { - error(errSyntaxWarning, -1, "Invalid Function array in shading dictionary"); - return nullptr; - } - for (i = 0; i < nFuncsA; ++i) { - Object obj2 = obj1.arrayGet(i); - if (!(funcsA[i] = Function::parse(&obj2))) { - return nullptr; - } - } - } else { - nFuncsA = 1; - if (!(funcsA[0] = Function::parse(&obj1))) { - return nullptr; - } - } - } else { - nFuncsA = 0; - } - - nVerticesA = nTrianglesA = 0; - verticesA = nullptr; - trianglesA = nullptr; - vertSize = triSize = 0; - state = 0; - flag = 0; // make gcc happy - bitBuf = new GfxShadingBitBuf(str); - while (1) { - if (typeA == 4) { - if (!bitBuf->getBits(flagBits, &flag)) { - break; - } - } - if (!bitBuf->getBits(coordBits, &x) || - !bitBuf->getBits(coordBits, &y)) { - break; - } - for (i = 0; i < nComps; ++i) { - if (!bitBuf->getBits(compBits, &c[i])) { - break; - } - } - if (i < nComps) { - break; - } - if (nVerticesA == vertSize) { - int oldVertSize = vertSize; - vertSize = (vertSize == 0) ? 16 : 2 * vertSize; - verticesA = (GfxGouraudVertex *) - greallocn(verticesA, vertSize, sizeof(GfxGouraudVertex)); - memset(verticesA + oldVertSize, 0, (vertSize - oldVertSize) * sizeof(GfxGouraudVertex)); - } - verticesA[nVerticesA].x = xMin + xMul * (double)x; - verticesA[nVerticesA].y = yMin + yMul * (double)y; - for (i = 0; i < nComps; ++i) { - verticesA[nVerticesA].color.c[i] = - dblToCol(cMin[i] + cMul[i] * (double)c[i]); - } - ++nVerticesA; - bitBuf->flushBits(); - if (typeA == 4) { - if (state == 0 || state == 1) { - ++state; - } else if (state == 2 || flag > 0) { - if (nTrianglesA == triSize) { - triSize = (triSize == 0) ? 16 : 2 * triSize; - trianglesA = (int (*)[3]) - greallocn(trianglesA, triSize * 3, sizeof(int)); - } - if (state == 2) { - trianglesA[nTrianglesA][0] = nVerticesA - 3; - trianglesA[nTrianglesA][1] = nVerticesA - 2; - trianglesA[nTrianglesA][2] = nVerticesA - 1; - ++state; - } else if (flag == 1) { - trianglesA[nTrianglesA][0] = trianglesA[nTrianglesA - 1][1]; - trianglesA[nTrianglesA][1] = trianglesA[nTrianglesA - 1][2]; - trianglesA[nTrianglesA][2] = nVerticesA - 1; - } else { // flag == 2 - trianglesA[nTrianglesA][0] = trianglesA[nTrianglesA - 1][0]; - trianglesA[nTrianglesA][1] = trianglesA[nTrianglesA - 1][2]; - trianglesA[nTrianglesA][2] = nVerticesA - 1; - } - ++nTrianglesA; - } else { // state == 3 && flag == 0 - state = 1; - } - } - } - delete bitBuf; - if (typeA == 5 && nVerticesA > 0 && vertsPerRow > 0) { - nRows = nVerticesA / vertsPerRow; - nTrianglesA = (nRows - 1) * 2 * (vertsPerRow - 1); - trianglesA = (int (*)[3])gmallocn_checkoverflow(nTrianglesA * 3, sizeof(int)); - if (unlikely(!trianglesA)) { - gfree(verticesA); - for (i = 0; i < nFuncsA; ++i) { - delete funcsA[i]; - } - return nullptr; - } - k = 0; - for (i = 0; i < nRows - 1; ++i) { - for (j = 0; j < vertsPerRow - 1; ++j) { - trianglesA[k][0] = i * vertsPerRow + j; - trianglesA[k][1] = i * vertsPerRow + j+1; - trianglesA[k][2] = (i+1) * vertsPerRow + j; - ++k; - trianglesA[k][0] = i * vertsPerRow + j+1; - trianglesA[k][1] = (i+1) * vertsPerRow + j; - trianglesA[k][2] = (i+1) * vertsPerRow + j+1; - ++k; - } - } - } - - shading = new GfxGouraudTriangleShading(typeA, verticesA, nVerticesA, - trianglesA, nTrianglesA, - funcsA, nFuncsA); - if (!shading->init(res, dict, out, gfxState)) { - delete shading; - return nullptr; - } - return shading; -} - -GfxShading *GfxGouraudTriangleShading::copy() { - return new GfxGouraudTriangleShading(this); -} - -void GfxGouraudTriangleShading::getTriangle( - int i, - double *x0, double *y0, GfxColor *color0, - double *x1, double *y1, GfxColor *color1, - double *x2, double *y2, GfxColor *color2) { - double in; - double out[gfxColorMaxComps]; - int v, j; - - assert(!isParameterized()); - - v = triangles[i][0]; - *x0 = vertices[v].x; - *y0 = vertices[v].y; - if (nFuncs > 0) { - in = colToDbl(vertices[v].color.c[0]); - for (j = 0; j < nFuncs; ++j) { - funcs[j]->transform(&in, &out[j]); - } - for (j = 0; j < gfxColorMaxComps; ++j) { - color0->c[j] = dblToCol(out[j]); - } - } else { - *color0 = vertices[v].color; - } - v = triangles[i][1]; - *x1 = vertices[v].x; - *y1 = vertices[v].y; - if (nFuncs > 0) { - in = colToDbl(vertices[v].color.c[0]); - for (j = 0; j < nFuncs; ++j) { - funcs[j]->transform(&in, &out[j]); - } - for (j = 0; j < gfxColorMaxComps; ++j) { - color1->c[j] = dblToCol(out[j]); - } - } else { - *color1 = vertices[v].color; - } - v = triangles[i][2]; - *x2 = vertices[v].x; - *y2 = vertices[v].y; - if (nFuncs > 0) { - in = colToDbl(vertices[v].color.c[0]); - for (j = 0; j < nFuncs; ++j) { - funcs[j]->transform(&in, &out[j]); - } - for (j = 0; j < gfxColorMaxComps; ++j) { - color2->c[j] = dblToCol(out[j]); - } - } else { - *color2 = vertices[v].color; - } -} - -void GfxGouraudTriangleShading::getParameterizedColor(double t, GfxColor *color) { - double out[gfxColorMaxComps]; - - for (int j = 0; j < nFuncs; ++j) { - funcs[j]->transform(&t, &out[j]); - } - for (int j = 0; j < gfxColorMaxComps; ++j) { - color->c[j] = dblToCol(out[j]); - } -} - -void GfxGouraudTriangleShading::getTriangle(int i, - double *x0, double *y0, double *color0, - double *x1, double *y1, double *color1, - double *x2, double *y2, double *color2) { - int v; - - assert(isParameterized()); - - v = triangles[i][0]; - if (likely(v >= 0 && v < nVertices)) { - *x0 = vertices[v].x; - *y0 = vertices[v].y; - *color0 = colToDbl(vertices[v].color.c[0]); - } - v = triangles[i][1]; - if (likely(v >= 0 && v < nVertices)) { - *x1 = vertices[v].x; - *y1 = vertices[v].y; - *color1 = colToDbl(vertices[v].color.c[0]); - } - v = triangles[i][2]; - if (likely(v >= 0 && v < nVertices)) { - *x2 = vertices[v].x; - *y2 = vertices[v].y; - *color2 = colToDbl(vertices[v].color.c[0]); - } -} - -//------------------------------------------------------------------------ -// GfxPatchMeshShading -//------------------------------------------------------------------------ - -GfxPatchMeshShading::GfxPatchMeshShading(int typeA, - GfxPatch *patchesA, int nPatchesA, - Function **funcsA, int nFuncsA): - GfxShading(typeA) -{ - int i; - - patches = patchesA; - nPatches = nPatchesA; - nFuncs = nFuncsA; - for (i = 0; i < nFuncs; ++i) { - funcs[i] = funcsA[i]; - } -} - -GfxPatchMeshShading::GfxPatchMeshShading(GfxPatchMeshShading *shading): - GfxShading(shading) -{ - int i; - - nPatches = shading->nPatches; - patches = (GfxPatch *)gmallocn(nPatches, sizeof(GfxPatch)); - memcpy(patches, shading->patches, nPatches * sizeof(GfxPatch)); - nFuncs = shading->nFuncs; - for (i = 0; i < nFuncs; ++i) { - funcs[i] = shading->funcs[i]->copy(); - } -} - -GfxPatchMeshShading::~GfxPatchMeshShading() { - int i; - - gfree(patches); - for (i = 0; i < nFuncs; ++i) { - delete funcs[i]; - } -} - -GfxPatchMeshShading *GfxPatchMeshShading::parse(GfxResources *res, int typeA, Dict *dict, - Stream *str, OutputDev *out, GfxState *state) { - GfxPatchMeshShading *shading; - Function *funcsA[gfxColorMaxComps]; - int nFuncsA; - int coordBits, compBits, flagBits; - double xMin, xMax, yMin, yMax; - double cMin[gfxColorMaxComps], cMax[gfxColorMaxComps]; - double xMul, yMul; - double cMul[gfxColorMaxComps]; - GfxPatch *patchesA, *p; - int nComps, nPatchesA, patchesSize, nPts, nColors; - Guint flag; - double x[16], y[16]; - Guint xi, yi; - double c[4][gfxColorMaxComps]; - Guint ci; - Object obj1; - int i, j; - - obj1 = dict->lookup("BitsPerCoordinate"); - if (obj1.isInt()) { - coordBits = obj1.getInt(); - } else { - error(errSyntaxWarning, -1, "Missing or invalid BitsPerCoordinate in shading dictionary"); - return nullptr; - } - if (unlikely(coordBits <= 0)) { - error(errSyntaxWarning, -1, "Invalid BitsPerCoordinate in shading dictionary"); - return nullptr; - } - obj1 = dict->lookup("BitsPerComponent"); - if (obj1.isInt()) { - compBits = obj1.getInt(); - } else { - error(errSyntaxWarning, -1, "Missing or invalid BitsPerComponent in shading dictionary"); - return nullptr; - } - if (unlikely(compBits <= 0 || compBits > 31)) { - error(errSyntaxWarning, -1, "Invalid BitsPerComponent in shading dictionary"); - return nullptr; - } - obj1 = dict->lookup("BitsPerFlag"); - if (obj1.isInt()) { - flagBits = obj1.getInt(); - } else { - error(errSyntaxWarning, -1, "Missing or invalid BitsPerFlag in shading dictionary"); - return nullptr; - } - obj1 = dict->lookup("Decode"); - if (obj1.isArray() && obj1.arrayGetLength() >= 6) { - bool decodeOk = true; - Object obj2; - xMin = (obj2 = obj1.arrayGet(0), obj2.getNum(&decodeOk)); - xMax = (obj2 = obj1.arrayGet(1), obj2.getNum(&decodeOk)); - xMul = (xMax - xMin) / (pow(2.0, coordBits) - 1); - yMin = (obj2 = obj1.arrayGet(2), obj2.getNum(&decodeOk)); - yMax = (obj2 = obj1.arrayGet(3), obj2.getNum(&decodeOk)); - yMul = (yMax - yMin) / (pow(2.0, coordBits) - 1); - for (i = 0; 5 + 2*i < obj1.arrayGetLength() && i < gfxColorMaxComps; ++i) { - cMin[i] = (obj2 = obj1.arrayGet(4 + 2*i), obj2.getNum(&decodeOk)); - cMax[i] = (obj2 = obj1.arrayGet(5 + 2*i), obj2.getNum(&decodeOk)); - cMul[i] = (cMax[i] - cMin[i]) / (double)((1u << compBits) - 1); - } - nComps = i; - - if (!decodeOk) { - error(errSyntaxWarning, -1, "Missing or invalid Decode array in shading dictionary"); - return nullptr; - } - } else { - error(errSyntaxWarning, -1, "Missing or invalid Decode array in shading dictionary"); - return nullptr; - } - - obj1 = dict->lookup("Function"); - if (!obj1.isNull()) { - if (obj1.isArray()) { - nFuncsA = obj1.arrayGetLength(); - if (nFuncsA > gfxColorMaxComps) { - error(errSyntaxWarning, -1, "Invalid Function array in shading dictionary"); - return nullptr; - } - for (i = 0; i < nFuncsA; ++i) { - Object obj2 = obj1.arrayGet(i); - if (!(funcsA[i] = Function::parse(&obj2))) { - return nullptr; - } - } - } else { - nFuncsA = 1; - if (!(funcsA[0] = Function::parse(&obj1))) { - return nullptr; - } - } - } else { - nFuncsA = 0; - } - - nPatchesA = 0; - patchesA = nullptr; - patchesSize = 0; - std::unique_ptr<GfxShadingBitBuf> bitBuf(new GfxShadingBitBuf(str)); - while (1) { - if (!bitBuf->getBits(flagBits, &flag)) { - break; - } - if (typeA == 6) { - switch (flag) { - case 0: nPts = 12; nColors = 4; break; - case 1: - case 2: - case 3: - default: nPts = 8; nColors = 2; break; - } - } else { - switch (flag) { - case 0: nPts = 16; nColors = 4; break; - case 1: - case 2: - case 3: - default: nPts = 12; nColors = 2; break; - } - } - for (i = 0; i < nPts; ++i) { - if (!bitBuf->getBits(coordBits, &xi) || - !bitBuf->getBits(coordBits, &yi)) { - break; - } - x[i] = xMin + xMul * (double)xi; - y[i] = yMin + yMul * (double)yi; - } - if (i < nPts) { - break; - } - for (i = 0; i < nColors; ++i) { - for (j = 0; j < nComps; ++j) { - if (!bitBuf->getBits(compBits, &ci)) { - break; - } - c[i][j] = cMin[j] + cMul[j] * (double)ci; - if( nFuncsA == 0 ) { - // ... and colorspace values can also be stored into doubles. - // They will be casted later. - c[i][j] = dblToCol(c[i][j]); - } - } - if (j < nComps) { - break; - } - } - if (i < nColors) { - break; - } - if (nPatchesA == patchesSize) { - int oldPatchesSize = patchesSize; - patchesSize = (patchesSize == 0) ? 16 : 2 * patchesSize; - patchesA = (GfxPatch *)greallocn(patchesA, - patchesSize, sizeof(GfxPatch)); - memset(patchesA + oldPatchesSize, 0, (patchesSize - oldPatchesSize) * sizeof(GfxPatch)); - } - p = &patchesA[nPatchesA]; - if (typeA == 6) { - switch (flag) { - case 0: - p->x[0][0] = x[0]; - p->y[0][0] = y[0]; - p->x[0][1] = x[1]; - p->y[0][1] = y[1]; - p->x[0][2] = x[2]; - p->y[0][2] = y[2]; - p->x[0][3] = x[3]; - p->y[0][3] = y[3]; - p->x[1][3] = x[4]; - p->y[1][3] = y[4]; - p->x[2][3] = x[5]; - p->y[2][3] = y[5]; - p->x[3][3] = x[6]; - p->y[3][3] = y[6]; - p->x[3][2] = x[7]; - p->y[3][2] = y[7]; - p->x[3][1] = x[8]; - p->y[3][1] = y[8]; - p->x[3][0] = x[9]; - p->y[3][0] = y[9]; - p->x[2][0] = x[10]; - p->y[2][0] = y[10]; - p->x[1][0] = x[11]; - p->y[1][0] = y[11]; - for (j = 0; j < nComps; ++j) { - p->color[0][0].c[j] = c[0][j]; - p->color[0][1].c[j] = c[1][j]; - p->color[1][1].c[j] = c[2][j]; - p->color[1][0].c[j] = c[3][j]; - } - break; - case 1: - if (nPatchesA == 0) { - gfree(patchesA); - for (int k = 0; k < nFuncsA; ++k) delete funcsA[k]; - return nullptr; - } - p->x[0][0] = patchesA[nPatchesA-1].x[0][3]; - p->y[0][0] = patchesA[nPatchesA-1].y[0][3]; - p->x[0][1] = patchesA[nPatchesA-1].x[1][3]; - p->y[0][1] = patchesA[nPatchesA-1].y[1][3]; - p->x[0][2] = patchesA[nPatchesA-1].x[2][3]; - p->y[0][2] = patchesA[nPatchesA-1].y[2][3]; - p->x[0][3] = patchesA[nPatchesA-1].x[3][3]; - p->y[0][3] = patchesA[nPatchesA-1].y[3][3]; - p->x[1][3] = x[0]; - p->y[1][3] = y[0]; - p->x[2][3] = x[1]; - p->y[2][3] = y[1]; - p->x[3][3] = x[2]; - p->y[3][3] = y[2]; - p->x[3][2] = x[3]; - p->y[3][2] = y[3]; - p->x[3][1] = x[4]; - p->y[3][1] = y[4]; - p->x[3][0] = x[5]; - p->y[3][0] = y[5]; - p->x[2][0] = x[6]; - p->y[2][0] = y[6]; - p->x[1][0] = x[7]; - p->y[1][0] = y[7]; - for (j = 0; j < nComps; ++j) { - p->color[0][0].c[j] = patchesA[nPatchesA-1].color[0][1].c[j]; - p->color[0][1].c[j] = patchesA[nPatchesA-1].color[1][1].c[j]; - p->color[1][1].c[j] = c[0][j]; - p->color[1][0].c[j] = c[1][j]; - } - break; - case 2: - if (nPatchesA == 0) { - gfree(patchesA); - for (int k = 0; k < nFuncsA; ++k) delete funcsA[k]; - return nullptr; - } - p->x[0][0] = patchesA[nPatchesA-1].x[3][3]; - p->y[0][0] = patchesA[nPatchesA-1].y[3][3]; - p->x[0][1] = patchesA[nPatchesA-1].x[3][2]; - p->y[0][1] = patchesA[nPatchesA-1].y[3][2]; - p->x[0][2] = patchesA[nPatchesA-1].x[3][1]; - p->y[0][2] = patchesA[nPatchesA-1].y[3][1]; - p->x[0][3] = patchesA[nPatchesA-1].x[3][0]; - p->y[0][3] = patchesA[nPatchesA-1].y[3][0]; - p->x[1][3] = x[0]; - p->y[1][3] = y[0]; - p->x[2][3] = x[1]; - p->y[2][3] = y[1]; - p->x[3][3] = x[2]; - p->y[3][3] = y[2]; - p->x[3][2] = x[3]; - p->y[3][2] = y[3]; - p->x[3][1] = x[4]; - p->y[3][1] = y[4]; - p->x[3][0] = x[5]; - p->y[3][0] = y[5]; - p->x[2][0] = x[6]; - p->y[2][0] = y[6]; - p->x[1][0] = x[7]; - p->y[1][0] = y[7]; - for (j = 0; j < nComps; ++j) { - p->color[0][0].c[j] = patchesA[nPatchesA-1].color[1][1].c[j]; - p->color[0][1].c[j] = patchesA[nPatchesA-1].color[1][0].c[j]; - p->color[1][1].c[j] = c[0][j]; - p->color[1][0].c[j] = c[1][j]; - } - break; - case 3: - if (nPatchesA == 0) { - gfree(patchesA); - for (int k = 0; k < nFuncsA; ++k) delete funcsA[k]; - return nullptr; - } - p->x[0][0] = patchesA[nPatchesA-1].x[3][0]; - p->y[0][0] = patchesA[nPatchesA-1].y[3][0]; - p->x[0][1] = patchesA[nPatchesA-1].x[2][0]; - p->y[0][1] = patchesA[nPatchesA-1].y[2][0]; - p->x[0][2] = patchesA[nPatchesA-1].x[1][0]; - p->y[0][2] = patchesA[nPatchesA-1].y[1][0]; - p->x[0][3] = patchesA[nPatchesA-1].x[0][0]; - p->y[0][3] = patchesA[nPatchesA-1].y[0][0]; - p->x[1][3] = x[0]; - p->y[1][3] = y[0]; - p->x[2][3] = x[1]; - p->y[2][3] = y[1]; - p->x[3][3] = x[2]; - p->y[3][3] = y[2]; - p->x[3][2] = x[3]; - p->y[3][2] = y[3]; - p->x[3][1] = x[4]; - p->y[3][1] = y[4]; - p->x[3][0] = x[5]; - p->y[3][0] = y[5]; - p->x[2][0] = x[6]; - p->y[2][0] = y[6]; - p->x[1][0] = x[7]; - p->y[1][0] = y[7]; - for (j = 0; j < nComps; ++j) { - p->color[0][0].c[j] = patchesA[nPatchesA-1].color[1][0].c[j]; - p->color[0][1].c[j] = patchesA[nPatchesA-1].color[0][0].c[j]; - p->color[1][1].c[j] = c[0][j]; - p->color[1][0].c[j] = c[1][j]; - } - break; - } - } else { - switch (flag) { - case 0: - p->x[0][0] = x[0]; - p->y[0][0] = y[0]; - p->x[0][1] = x[1]; - p->y[0][1] = y[1]; - p->x[0][2] = x[2]; - p->y[0][2] = y[2]; - p->x[0][3] = x[3]; - p->y[0][3] = y[3]; - p->x[1][3] = x[4]; - p->y[1][3] = y[4]; - p->x[2][3] = x[5]; - p->y[2][3] = y[5]; - p->x[3][3] = x[6]; - p->y[3][3] = y[6]; - p->x[3][2] = x[7]; - p->y[3][2] = y[7]; - p->x[3][1] = x[8]; - p->y[3][1] = y[8]; - p->x[3][0] = x[9]; - p->y[3][0] = y[9]; - p->x[2][0] = x[10]; - p->y[2][0] = y[10]; - p->x[1][0] = x[11]; - p->y[1][0] = y[11]; - p->x[1][1] = x[12]; - p->y[1][1] = y[12]; - p->x[1][2] = x[13]; - p->y[1][2] = y[13]; - p->x[2][2] = x[14]; - p->y[2][2] = y[14]; - p->x[2][1] = x[15]; - p->y[2][1] = y[15]; - for (j = 0; j < nComps; ++j) { - p->color[0][0].c[j] = c[0][j]; - p->color[0][1].c[j] = c[1][j]; - p->color[1][1].c[j] = c[2][j]; - p->color[1][0].c[j] = c[3][j]; - } - break; - case 1: - if (nPatchesA == 0) { - gfree(patchesA); - for (int k = 0; k < nFuncsA; ++k) delete funcsA[k]; - return nullptr; - } - p->x[0][0] = patchesA[nPatchesA-1].x[0][3]; - p->y[0][0] = patchesA[nPatchesA-1].y[0][3]; - p->x[0][1] = patchesA[nPatchesA-1].x[1][3]; - p->y[0][1] = patchesA[nPatchesA-1].y[1][3]; - p->x[0][2] = patchesA[nPatchesA-1].x[2][3]; - p->y[0][2] = patchesA[nPatchesA-1].y[2][3]; - p->x[0][3] = patchesA[nPatchesA-1].x[3][3]; - p->y[0][3] = patchesA[nPatchesA-1].y[3][3]; - p->x[1][3] = x[0]; - p->y[1][3] = y[0]; - p->x[2][3] = x[1]; - p->y[2][3] = y[1]; - p->x[3][3] = x[2]; - p->y[3][3] = y[2]; - p->x[3][2] = x[3]; - p->y[3][2] = y[3]; - p->x[3][1] = x[4]; - p->y[3][1] = y[4]; - p->x[3][0] = x[5]; - p->y[3][0] = y[5]; - p->x[2][0] = x[6]; - p->y[2][0] = y[6]; - p->x[1][0] = x[7]; - p->y[1][0] = y[7]; - p->x[1][1] = x[8]; - p->y[1][1] = y[8]; - p->x[1][2] = x[9]; - p->y[1][2] = y[9]; - p->x[2][2] = x[10]; - p->y[2][2] = y[10]; - p->x[2][1] = x[11]; - p->y[2][1] = y[11]; - for (j = 0; j < nComps; ++j) { - p->color[0][0].c[j] = patchesA[nPatchesA-1].color[0][1].c[j]; - p->color[0][1].c[j] = patchesA[nPatchesA-1].color[1][1].c[j]; - p->color[1][1].c[j] = c[0][j]; - p->color[1][0].c[j] = c[1][j]; - } - break; - case 2: - if (nPatchesA == 0) { - gfree(patchesA); - for (int k = 0; k < nFuncsA; ++k) delete funcsA[k]; - return nullptr; - } - p->x[0][0] = patchesA[nPatchesA-1].x[3][3]; - p->y[0][0] = patchesA[nPatchesA-1].y[3][3]; - p->x[0][1] = patchesA[nPatchesA-1].x[3][2]; - p->y[0][1] = patchesA[nPatchesA-1].y[3][2]; - p->x[0][2] = patchesA[nPatchesA-1].x[3][1]; - p->y[0][2] = patchesA[nPatchesA-1].y[3][1]; - p->x[0][3] = patchesA[nPatchesA-1].x[3][0]; - p->y[0][3] = patchesA[nPatchesA-1].y[3][0]; - p->x[1][3] = x[0]; - p->y[1][3] = y[0]; - p->x[2][3] = x[1]; - p->y[2][3] = y[1]; - p->x[3][3] = x[2]; - p->y[3][3] = y[2]; - p->x[3][2] = x[3]; - p->y[3][2] = y[3]; - p->x[3][1] = x[4]; - p->y[3][1] = y[4]; - p->x[3][0] = x[5]; - p->y[3][0] = y[5]; - p->x[2][0] = x[6]; - p->y[2][0] = y[6]; - p->x[1][0] = x[7]; - p->y[1][0] = y[7]; - p->x[1][1] = x[8]; - p->y[1][1] = y[8]; - p->x[1][2] = x[9]; - p->y[1][2] = y[9]; - p->x[2][2] = x[10]; - p->y[2][2] = y[10]; - p->x[2][1] = x[11]; - p->y[2][1] = y[11]; - for (j = 0; j < nComps; ++j) { - p->color[0][0].c[j] = patchesA[nPatchesA-1].color[1][1].c[j]; - p->color[0][1].c[j] = patchesA[nPatchesA-1].color[1][0].c[j]; - p->color[1][1].c[j] = c[0][j]; - p->color[1][0].c[j] = c[1][j]; - } - break; - case 3: - if (nPatchesA == 0) { - gfree(patchesA); - for (int k = 0; k < nFuncsA; ++k) delete funcsA[k]; - return nullptr; - } - p->x[0][0] = patchesA[nPatchesA-1].x[3][0]; - p->y[0][0] = patchesA[nPatchesA-1].y[3][0]; - p->x[0][1] = patchesA[nPatchesA-1].x[2][0]; - p->y[0][1] = patchesA[nPatchesA-1].y[2][0]; - p->x[0][2] = patchesA[nPatchesA-1].x[1][0]; - p->y[0][2] = patchesA[nPatchesA-1].y[1][0]; - p->x[0][3] = patchesA[nPatchesA-1].x[0][0]; - p->y[0][3] = patchesA[nPatchesA-1].y[0][0]; - p->x[1][3] = x[0]; - p->y[1][3] = y[0]; - p->x[2][3] = x[1]; - p->y[2][3] = y[1]; - p->x[3][3] = x[2]; - p->y[3][3] = y[2]; - p->x[3][2] = x[3]; - p->y[3][2] = y[3]; - p->x[3][1] = x[4]; - p->y[3][1] = y[4]; - p->x[3][0] = x[5]; - p->y[3][0] = y[5]; - p->x[2][0] = x[6]; - p->y[2][0] = y[6]; - p->x[1][0] = x[7]; - p->y[1][0] = y[7]; - p->x[1][1] = x[8]; - p->y[1][1] = y[8]; - p->x[1][2] = x[9]; - p->y[1][2] = y[9]; - p->x[2][2] = x[10]; - p->y[2][2] = y[10]; - p->x[2][1] = x[11]; - p->y[2][1] = y[11]; - for (j = 0; j < nComps; ++j) { - p->color[0][0].c[j] = patchesA[nPatchesA-1].color[1][0].c[j]; - p->color[0][1].c[j] = patchesA[nPatchesA-1].color[0][0].c[j]; - p->color[1][1].c[j] = c[0][j]; - p->color[1][0].c[j] = c[1][j]; - } - break; - } - } - ++nPatchesA; - bitBuf->flushBits(); - } - - if (typeA == 6) { - for (i = 0; i < nPatchesA; ++i) { - p = &patchesA[i]; - p->x[1][1] = (-4 * p->x[0][0] - +6 * (p->x[0][1] + p->x[1][0]) - -2 * (p->x[0][3] + p->x[3][0]) - +3 * (p->x[3][1] + p->x[1][3]) - - p->x[3][3]) / 9; - p->y[1][1] = (-4 * p->y[0][0] - +6 * (p->y[0][1] + p->y[1][0]) - -2 * (p->y[0][3] + p->y[3][0]) - +3 * (p->y[3][1] + p->y[1][3]) - - p->y[3][3]) / 9; - p->x[1][2] = (-4 * p->x[0][3] - +6 * (p->x[0][2] + p->x[1][3]) - -2 * (p->x[0][0] + p->x[3][3]) - +3 * (p->x[3][2] + p->x[1][0]) - - p->x[3][0]) / 9; - p->y[1][2] = (-4 * p->y[0][3] - +6 * (p->y[0][2] + p->y[1][3]) - -2 * (p->y[0][0] + p->y[3][3]) - +3 * (p->y[3][2] + p->y[1][0]) - - p->y[3][0]) / 9; - p->x[2][1] = (-4 * p->x[3][0] - +6 * (p->x[3][1] + p->x[2][0]) - -2 * (p->x[3][3] + p->x[0][0]) - +3 * (p->x[0][1] + p->x[2][3]) - - p->x[0][3]) / 9; - p->y[2][1] = (-4 * p->y[3][0] - +6 * (p->y[3][1] + p->y[2][0]) - -2 * (p->y[3][3] + p->y[0][0]) - +3 * (p->y[0][1] + p->y[2][3]) - - p->y[0][3]) / 9; - p->x[2][2] = (-4 * p->x[3][3] - +6 * (p->x[3][2] + p->x[2][3]) - -2 * (p->x[3][0] + p->x[0][3]) - +3 * (p->x[0][2] + p->x[2][0]) - - p->x[0][0]) / 9; - p->y[2][2] = (-4 * p->y[3][3] - +6 * (p->y[3][2] + p->y[2][3]) - -2 * (p->y[3][0] + p->y[0][3]) - +3 * (p->y[0][2] + p->y[2][0]) - - p->y[0][0]) / 9; - } - } - - shading = new GfxPatchMeshShading(typeA, patchesA, nPatchesA, - funcsA, nFuncsA); - if (!shading->init(res, dict, out, state)) { - delete shading; - return nullptr; - } - return shading; -} - -void GfxPatchMeshShading::getParameterizedColor(double t, GfxColor *color) { - double out[gfxColorMaxComps] = {}; - - for (int j = 0; j < nFuncs; ++j) { - funcs[j]->transform(&t, &out[j]); - } - for (int j = 0; j < gfxColorMaxComps; ++j) { - color->c[j] = dblToCol(out[j]); - } -} - -GfxShading *GfxPatchMeshShading::copy() { - return new GfxPatchMeshShading(this); -} - -//------------------------------------------------------------------------ -// GfxImageColorMap -//------------------------------------------------------------------------ - -GfxImageColorMap::GfxImageColorMap(int bitsA, Object *decode, - GfxColorSpace *colorSpaceA) { - GfxIndexedColorSpace *indexedCS; - GfxSeparationColorSpace *sepCS; - int maxPixel, indexHigh; - Guchar *indexedLookup; - Function *sepFunc; - double x[gfxColorMaxComps]; - double y[gfxColorMaxComps] = {}; - int i, j, k; - double mapped; - GBool useByteLookup; - - ok = gTrue; - useMatte = gFalse; - - // bits per component and color space - bits = bitsA; - maxPixel = (1 << bits) - 1; - colorSpace = colorSpaceA; - - // this is a hack to support 16 bits images, everywhere - // we assume a component fits in 8 bits, with this hack - // we treat 16 bit images as 8 bit ones until it's fixed correctly. - // The hack has another part on ImageStream::getLine - if (maxPixel > 255) maxPixel = 255; - - // initialize - for (k = 0; k < gfxColorMaxComps; ++k) { - lookup[k] = nullptr; - lookup2[k] = nullptr; - } - byte_lookup = nullptr; - - if (unlikely(bits <= 0)) - goto err1; - - // get decode map - if (decode->isNull()) { - nComps = colorSpace->getNComps(); - colorSpace->getDefaultRanges(decodeLow, decodeRange, maxPixel); - } else if (decode->isArray()) { - nComps = decode->arrayGetLength() / 2; - if (nComps < colorSpace->getNComps()) { - goto err1; - } - if (nComps > colorSpace->getNComps()) { - error(errSyntaxWarning, -1, "Too many elements in Decode array"); - nComps = colorSpace->getNComps(); - } - for (i = 0; i < nComps; ++i) { - Object obj = decode->arrayGet(2*i); - if (!obj.isNum()) { - goto err1; - } - decodeLow[i] = obj.getNum(); - obj = decode->arrayGet(2*i+1); - if (!obj.isNum()) { - goto err1; - } - decodeRange[i] = obj.getNum() - decodeLow[i]; - } - } else { - goto err1; - } - - // Construct a lookup table -- this stores pre-computed decoded - // values for each component, i.e., the result of applying the - // decode mapping to each possible image pixel component value. - for (k = 0; k < nComps; ++k) { - lookup[k] = (GfxColorComp *)gmallocn(maxPixel + 1, - sizeof(GfxColorComp)); - for (i = 0; i <= maxPixel; ++i) { - lookup[k][i] = dblToCol(decodeLow[k] + - (i * decodeRange[k]) / maxPixel); - } - } - - // Optimization: for Indexed and Separation color spaces (which have - // only one component), we pre-compute a second lookup table with - // color values - colorSpace2 = nullptr; - nComps2 = 0; - useByteLookup = gFalse; - switch (colorSpace->getMode()) { - case csIndexed: - // Note that indexHigh may not be the same as maxPixel -- - // Distiller will remove unused palette entries, resulting in - // indexHigh < maxPixel. - indexedCS = (GfxIndexedColorSpace *)colorSpace; - colorSpace2 = indexedCS->getBase(); - indexHigh = indexedCS->getIndexHigh(); - nComps2 = colorSpace2->getNComps(); - indexedLookup = indexedCS->getLookup(); - colorSpace2->getDefaultRanges(x, y, indexHigh); - if (colorSpace2->useGetGrayLine() || colorSpace2->useGetRGBLine() || colorSpace2->useGetCMYKLine() || colorSpace2->useGetDeviceNLine()) { - byte_lookup = (Guchar *)gmallocn ((maxPixel + 1), nComps2); - useByteLookup = gTrue; - } - for (k = 0; k < nComps2; ++k) { - lookup2[k] = (GfxColorComp *)gmallocn(maxPixel + 1, - sizeof(GfxColorComp)); - for (i = 0; i <= maxPixel; ++i) { - j = (int)(decodeLow[0] + (i * decodeRange[0]) / maxPixel + 0.5); - if (j < 0) { - j = 0; - } else if (j > indexHigh) { - j = indexHigh; - } - - mapped = x[k] + (indexedLookup[j*nComps2 + k] / 255.0) * y[k]; - lookup2[k][i] = dblToCol(mapped); - if (useByteLookup) - byte_lookup[i * nComps2 + k] = (Guchar) (mapped * 255); - } - } - break; - case csSeparation: - sepCS = (GfxSeparationColorSpace *)colorSpace; - colorSpace2 = sepCS->getAlt(); - nComps2 = colorSpace2->getNComps(); - sepFunc = sepCS->getFunc(); - if (colorSpace2->useGetGrayLine() || colorSpace2->useGetRGBLine() || colorSpace2->useGetCMYKLine() || colorSpace2->useGetDeviceNLine()) { - byte_lookup = (Guchar *)gmallocn ((maxPixel + 1), nComps2); - useByteLookup = gTrue; - } - for (k = 0; k < nComps2; ++k) { - lookup2[k] = (GfxColorComp *)gmallocn(maxPixel + 1, - sizeof(GfxColorComp)); - for (i = 0; i <= maxPixel; ++i) { - x[0] = decodeLow[0] + (i * decodeRange[0]) / maxPixel; - sepFunc->transform(x, y); - lookup2[k][i] = dblToCol(y[k]); - if (useByteLookup) - byte_lookup[i*nComps2 + k] = (Guchar) (y[k] * 255); - } - } - break; - default: - if (colorSpace->useGetGrayLine() || colorSpace->useGetRGBLine() || colorSpace->useGetCMYKLine() || colorSpace->useGetDeviceNLine()) { - byte_lookup = (Guchar *)gmallocn ((maxPixel + 1), nComps); - useByteLookup = gTrue; - } - for (k = 0; k < nComps; ++k) { - lookup2[k] = (GfxColorComp *)gmallocn(maxPixel + 1, - sizeof(GfxColorComp)); - for (i = 0; i <= maxPixel; ++i) { - mapped = decodeLow[k] + (i * decodeRange[k]) / maxPixel; - lookup2[k][i] = dblToCol(mapped); - if (useByteLookup) { - int byte; - - byte = (int) (mapped * 255.0 + 0.5); - if (byte < 0) - byte = 0; - else if (byte > 255) - byte = 255; - byte_lookup[i * nComps + k] = byte; - } - } - } - } - - return; - - err1: - ok = gFalse; -} - -GfxImageColorMap::GfxImageColorMap(GfxImageColorMap *colorMap) { - int n, i, k; - - colorSpace = colorMap->colorSpace->copy(); - bits = colorMap->bits; - nComps = colorMap->nComps; - nComps2 = colorMap->nComps2; - useMatte = colorMap->useMatte; - matteColor = colorMap->matteColor; - colorSpace2 = nullptr; - for (k = 0; k < gfxColorMaxComps; ++k) { - lookup[k] = nullptr; - } - n = 1 << bits; - if (colorSpace->getMode() == csIndexed) { - colorSpace2 = ((GfxIndexedColorSpace *)colorSpace)->getBase(); - for (k = 0; k < nComps2; ++k) { - lookup[k] = (GfxColorComp *)gmallocn(n, sizeof(GfxColorComp)); - memcpy(lookup[k], colorMap->lookup[k], n * sizeof(GfxColorComp)); - } - } else if (colorSpace->getMode() == csSeparation) { - colorSpace2 = ((GfxSeparationColorSpace *)colorSpace)->getAlt(); - for (k = 0; k < nComps2; ++k) { - lookup[k] = (GfxColorComp *)gmallocn(n, sizeof(GfxColorComp)); - memcpy(lookup[k], colorMap->lookup[k], n * sizeof(GfxColorComp)); - } - } else { - for (k = 0; k < nComps; ++k) { - lookup[k] = (GfxColorComp *)gmallocn(n, sizeof(GfxColorComp)); - memcpy(lookup[k], colorMap->lookup[k], n * sizeof(GfxColorComp)); - } - } - if (colorMap->byte_lookup) { - int nc = colorSpace2 ? nComps2 : nComps; - - byte_lookup = (Guchar *)gmallocn (n, nc); - memcpy(byte_lookup, colorMap->byte_lookup, n * nc); - } - for (i = 0; i < nComps; ++i) { - decodeLow[i] = colorMap->decodeLow[i]; - decodeRange[i] = colorMap->decodeRange[i]; - } - ok = gTrue; -} - -GfxImageColorMap::~GfxImageColorMap() { - int i; - - delete colorSpace; - for (i = 0; i < gfxColorMaxComps; ++i) { - gfree(lookup[i]); - gfree(lookup2[i]); - } - gfree(byte_lookup); -} - -void GfxImageColorMap::getGray(Guchar *x, GfxGray *gray) { - GfxColor color; - int i; - - if (colorSpace2) { - for (i = 0; i < nComps2; ++i) { - color.c[i] = lookup2[i][x[0]]; - } - colorSpace2->getGray(&color, gray); - } else { - for (i = 0; i < nComps; ++i) { - color.c[i] = lookup2[i][x[i]]; - } - colorSpace->getGray(&color, gray); - } -} - -void GfxImageColorMap::getRGB(Guchar *x, GfxRGB *rgb) { - GfxColor color; - int i; - - if (colorSpace2) { - for (i = 0; i < nComps2; ++i) { - color.c[i] = lookup2[i][x[0]]; - } - colorSpace2->getRGB(&color, rgb); - } else { - for (i = 0; i < nComps; ++i) { - color.c[i] = lookup2[i][x[i]]; - } - colorSpace->getRGB(&color, rgb); - } -} - -void GfxImageColorMap::getGrayLine(Guchar *in, Guchar *out, int length) { - int i, j; - Guchar *inp, *tmp_line; - - if ((colorSpace2 && !colorSpace2->useGetGrayLine ()) || - (!colorSpace2 && !colorSpace->useGetGrayLine ())) { - GfxGray gray; - - inp = in; - for (i = 0; i < length; i++) { - getGray (inp, &gray); - out[i] = colToByte(gray); - inp += nComps; - } - return; - } - - switch (colorSpace->getMode()) { - case csIndexed: - case csSeparation: - tmp_line = (Guchar *) gmallocn (length, nComps2); - for (i = 0; i < length; i++) { - for (j = 0; j < nComps2; j++) { - tmp_line[i * nComps2 + j] = byte_lookup[in[i] * nComps2 + j]; - } - } - colorSpace2->getGrayLine(tmp_line, out, length); - gfree (tmp_line); - break; - - default: - inp = in; - for (j = 0; j < length; j++) - for (i = 0; i < nComps; i++) { - *inp = byte_lookup[*inp * nComps + i]; - inp++; - } - colorSpace->getGrayLine(in, out, length); - break; - } - -} - -void GfxImageColorMap::getRGBLine(Guchar *in, unsigned int *out, int length) { - int i, j; - Guchar *inp, *tmp_line; - - if (!useRGBLine()) { - GfxRGB rgb; - - inp = in; - for (i = 0; i < length; i++) { - getRGB (inp, &rgb); - out[i] = - ((int) colToByte(rgb.r) << 16) | - ((int) colToByte(rgb.g) << 8) | - ((int) colToByte(rgb.b) << 0); - inp += nComps; - } - return; - } - - switch (colorSpace->getMode()) { - case csIndexed: - case csSeparation: - tmp_line = (Guchar *) gmallocn (length, nComps2); - for (i = 0; i < length; i++) { - for (j = 0; j < nComps2; j++) { - tmp_line[i * nComps2 + j] = byte_lookup[in[i] * nComps2 + j]; - } - } - colorSpace2->getRGBLine(tmp_line, out, length); - gfree (tmp_line); - break; - - default: - inp = in; - for (j = 0; j < length; j++) - for (i = 0; i < nComps; i++) { - *inp = byte_lookup[*inp * nComps + i]; - inp++; - } - colorSpace->getRGBLine(in, out, length); - break; - } - -} - -void GfxImageColorMap::getRGBLine(Guchar *in, Guchar *out, int length) { - int i, j; - Guchar *inp, *tmp_line; - - if (!useRGBLine()) { - GfxRGB rgb; - - inp = in; - for (i = 0; i < length; i++) { - getRGB (inp, &rgb); - *out++ = colToByte(rgb.r); - *out++ = colToByte(rgb.g); - *out++ = colToByte(rgb.b); - inp += nComps; - } - return; - } - - switch (colorSpace->getMode()) { - case csIndexed: - case csSeparation: - tmp_line = (Guchar *) gmallocn (length, nComps2); - for (i = 0; i < length; i++) { - for (j = 0; j < nComps2; j++) { - tmp_line[i * nComps2 + j] = byte_lookup[in[i] * nComps2 + j]; - } - } - colorSpace2->getRGBLine(tmp_line, out, length); - gfree (tmp_line); - break; - - default: - inp = in; - for (j = 0; j < length; j++) - for (i = 0; i < nComps; i++) { - *inp = byte_lookup[*inp * nComps + i]; - inp++; - } - colorSpace->getRGBLine(in, out, length); - break; - } - -} - -void GfxImageColorMap::getRGBXLine(Guchar *in, Guchar *out, int length) { - int i, j; - Guchar *inp, *tmp_line; - - if (!useRGBLine()) { - GfxRGB rgb; - - inp = in; - for (i = 0; i < length; i++) { - getRGB (inp, &rgb); - *out++ = colToByte(rgb.r); - *out++ = colToByte(rgb.g); - *out++ = colToByte(rgb.b); - *out++ = 255; - inp += nComps; - } - return; - } - - switch (colorSpace->getMode()) { - case csIndexed: - case csSeparation: - tmp_line = (Guchar *) gmallocn (length, nComps2); - for (i = 0; i < length; i++) { - for (j = 0; j < nComps2; j++) { - tmp_line[i * nComps2 + j] = byte_lookup[in[i] * nComps2 + j]; - } - } - colorSpace2->getRGBXLine(tmp_line, out, length); - gfree (tmp_line); - break; - - default: - inp = in; - for (j = 0; j < length; j++) - for (i = 0; i < nComps; i++) { - *inp = byte_lookup[*inp * nComps + i]; - inp++; - } - colorSpace->getRGBXLine(in, out, length); - break; - } - -} - -void GfxImageColorMap::getCMYKLine(Guchar *in, Guchar *out, int length) { - int i, j; - Guchar *inp, *tmp_line; - - if (!useCMYKLine()) { - GfxCMYK cmyk; - - inp = in; - for (i = 0; i < length; i++) { - getCMYK (inp, &cmyk); - *out++ = colToByte(cmyk.c); - *out++ = colToByte(cmyk.m); - *out++ = colToByte(cmyk.y); - *out++ = colToByte(cmyk.k); - inp += nComps; - } - return; - } - - switch (colorSpace->getMode()) { - case csIndexed: - case csSeparation: - tmp_line = (Guchar *) gmallocn (length, nComps2); - for (i = 0; i < length; i++) { - for (j = 0; j < nComps2; j++) { - tmp_line[i * nComps2 + j] = byte_lookup[in[i] * nComps2 + j]; - } - } - colorSpace2->getCMYKLine(tmp_line, out, length); - gfree (tmp_line); - break; - - default: - inp = in; - for (j = 0; j < length; j++) - for (i = 0; i < nComps; i++) { - *inp = byte_lookup[*inp * nComps + i]; - inp++; - } - colorSpace->getCMYKLine(in, out, length); - break; - } - -} - -void GfxImageColorMap::getDeviceNLine(Guchar *in, Guchar *out, int length) { - Guchar *inp, *tmp_line; - - if (!useDeviceNLine()) { - GfxColor deviceN; - - inp = in; - for (int i = 0; i < length; i++) { - getDeviceN (inp, &deviceN); - for (int j = 0; j < SPOT_NCOMPS+4; j++) - *out++ = deviceN.c[j]; - inp += nComps; - } - return; - } - - switch (colorSpace->getMode()) { - case csIndexed: - case csSeparation: - tmp_line = (Guchar *) gmallocn (length, nComps2); - for (int i = 0; i < length; i++) { - for (int j = 0; j < nComps2; j++) { - tmp_line[i * nComps2 + j] = byte_lookup[in[i] * nComps2 + j]; - } - } - colorSpace2->getDeviceNLine(tmp_line, out, length); - gfree (tmp_line); - break; - - default: - inp = in; - for (int j = 0; j < length; j++) - for (int i = 0; i < nComps; i++) { - *inp = byte_lookup[*inp * nComps + i]; - inp++; - } - colorSpace->getDeviceNLine(in, out, length); - break; - } - -} - -void GfxImageColorMap::getCMYK(Guchar *x, GfxCMYK *cmyk) { - GfxColor color; - int i; - - if (colorSpace2) { - for (i = 0; i < nComps2; ++i) { - color.c[i] = lookup2[i][x[0]]; - } - colorSpace2->getCMYK(&color, cmyk); - } else { - for (i = 0; i < nComps; ++i) { - color.c[i] = lookup[i][x[i]]; - } - colorSpace->getCMYK(&color, cmyk); - } -} - -void GfxImageColorMap::getDeviceN(Guchar *x, GfxColor *deviceN) { - GfxColor color; - int i; - - if (colorSpace2) { - for (i = 0; i < nComps2; ++i) { - color.c[i] = lookup2[i][x[0]]; - } - colorSpace2->getDeviceN(&color, deviceN); - } else { - for (i = 0; i < nComps; ++i) { - color.c[i] = lookup[i][x[i]]; - } - colorSpace->getDeviceN(&color, deviceN); - } -} - -void GfxImageColorMap::getColor(Guchar *x, GfxColor *color) { - int maxPixel, i; - - maxPixel = (1 << bits) - 1; - for (i = 0; i < nComps; ++i) { - color->c[i] = dblToCol(decodeLow[i] + (x[i] * decodeRange[i]) / maxPixel); - } -} - -//------------------------------------------------------------------------ -// GfxSubpath and GfxPath -//------------------------------------------------------------------------ - -GfxSubpath::GfxSubpath(double x1, double y1) { - size = 16; - x = (double *)gmallocn(size, sizeof(double)); - y = (double *)gmallocn(size, sizeof(double)); - curve = (GBool *)gmallocn(size, sizeof(GBool)); - n = 1; - x[0] = x1; - y[0] = y1; - curve[0] = gFalse; - closed = gFalse; -} - -GfxSubpath::~GfxSubpath() { - gfree(x); - gfree(y); - gfree(curve); -} - -// Used for copy(). -GfxSubpath::GfxSubpath(GfxSubpath *subpath) { - size = subpath->size; - n = subpath->n; - x = (double *)gmallocn(size, sizeof(double)); - y = (double *)gmallocn(size, sizeof(double)); - curve = (GBool *)gmallocn(size, sizeof(GBool)); - memcpy(x, subpath->x, n * sizeof(double)); - memcpy(y, subpath->y, n * sizeof(double)); - memcpy(curve, subpath->curve, n * sizeof(GBool)); - closed = subpath->closed; -} - -void GfxSubpath::lineTo(double x1, double y1) { - if (n >= size) { - size *= 2; - x = (double *)greallocn(x, size, sizeof(double)); - y = (double *)greallocn(y, size, sizeof(double)); - curve = (GBool *)greallocn(curve, size, sizeof(GBool)); - } - x[n] = x1; - y[n] = y1; - curve[n] = gFalse; - ++n; -} - -void GfxSubpath::curveTo(double x1, double y1, double x2, double y2, - double x3, double y3) { - if (n+3 > size) { - size *= 2; - x = (double *)greallocn(x, size, sizeof(double)); - y = (double *)greallocn(y, size, sizeof(double)); - curve = (GBool *)greallocn(curve, size, sizeof(GBool)); - } - x[n] = x1; - y[n] = y1; - x[n+1] = x2; - y[n+1] = y2; - x[n+2] = x3; - y[n+2] = y3; - curve[n] = curve[n+1] = gTrue; - curve[n+2] = gFalse; - n += 3; -} - -void GfxSubpath::close() { - if (x[n-1] != x[0] || y[n-1] != y[0]) { - lineTo(x[0], y[0]); - } - closed = gTrue; -} - -void GfxSubpath::offset(double dx, double dy) { - int i; - - for (i = 0; i < n; ++i) { - x[i] += dx; - y[i] += dy; - } -} - -GfxPath::GfxPath() { - justMoved = gFalse; - size = 16; - n = 0; - firstX = firstY = 0; - subpaths = (GfxSubpath **)gmallocn(size, sizeof(GfxSubpath *)); -} - -GfxPath::~GfxPath() { - int i; - - for (i = 0; i < n; ++i) - delete subpaths[i]; - gfree(subpaths); -} - -// Used for copy(). -GfxPath::GfxPath(GBool justMoved1, double firstX1, double firstY1, - GfxSubpath **subpaths1, int n1, int size1) { - int i; - - justMoved = justMoved1; - firstX = firstX1; - firstY = firstY1; - size = size1; - n = n1; - subpaths = (GfxSubpath **)gmallocn(size, sizeof(GfxSubpath *)); - for (i = 0; i < n; ++i) - subpaths[i] = subpaths1[i]->copy(); -} - -void GfxPath::moveTo(double x, double y) { - justMoved = gTrue; - firstX = x; - firstY = y; -} - -void GfxPath::lineTo(double x, double y) { - if (justMoved || (n > 0 && subpaths[n-1]->isClosed())) { - if (n >= size) { - size *= 2; - subpaths = (GfxSubpath **) - greallocn(subpaths, size, sizeof(GfxSubpath *)); - } - if (justMoved) { - subpaths[n] = new GfxSubpath(firstX, firstY); - } else { - subpaths[n] = new GfxSubpath(subpaths[n-1]->getLastX(), - subpaths[n-1]->getLastY()); - } - ++n; - justMoved = gFalse; - } - subpaths[n-1]->lineTo(x, y); -} - -void GfxPath::curveTo(double x1, double y1, double x2, double y2, - double x3, double y3) { - if (justMoved || (n > 0 && subpaths[n-1]->isClosed())) { - if (n >= size) { - size *= 2; - subpaths = (GfxSubpath **) - greallocn(subpaths, size, sizeof(GfxSubpath *)); - } - if (justMoved) { - subpaths[n] = new GfxSubpath(firstX, firstY); - } else { - subpaths[n] = new GfxSubpath(subpaths[n-1]->getLastX(), - subpaths[n-1]->getLastY()); - } - ++n; - justMoved = gFalse; - } - subpaths[n-1]->curveTo(x1, y1, x2, y2, x3, y3); -} - -void GfxPath::close() { - // this is necessary to handle the pathological case of - // moveto/closepath/clip, which defines an empty clipping region - if (justMoved) { - if (n >= size) { - size *= 2; - subpaths = (GfxSubpath **) - greallocn(subpaths, size, sizeof(GfxSubpath *)); - } - subpaths[n] = new GfxSubpath(firstX, firstY); - ++n; - justMoved = gFalse; - } - subpaths[n-1]->close(); -} - -void GfxPath::append(GfxPath *path) { - int i; - - if (n + path->n > size) { - size = n + path->n; - subpaths = (GfxSubpath **) - greallocn(subpaths, size, sizeof(GfxSubpath *)); - } - for (i = 0; i < path->n; ++i) { - subpaths[n++] = path->subpaths[i]->copy(); - } - justMoved = gFalse; -} - -void GfxPath::offset(double dx, double dy) { - int i; - - for (i = 0; i < n; ++i) { - subpaths[i]->offset(dx, dy); - } -} - -//------------------------------------------------------------------------ -// -//------------------------------------------------------------------------ -GfxState::ReusablePathIterator::ReusablePathIterator(GfxPath *pathA) - : path(pathA), - subPathOff(0), - coordOff(0), - numCoords(0), - curSubPath(nullptr) -{ - if( path->getNumSubpaths() ) { - curSubPath = path->getSubpath(subPathOff); - numCoords = curSubPath->getNumPoints(); - } -} - -bool GfxState::ReusablePathIterator::isEnd() const { - return coordOff >= numCoords; -} - -void GfxState::ReusablePathIterator::next() { - ++coordOff; - if (coordOff == numCoords) { - ++subPathOff; - if (subPathOff < path->getNumSubpaths()) { - coordOff = 0; - curSubPath = path->getSubpath(subPathOff); - numCoords = curSubPath->getNumPoints(); - } - } -} - -void GfxState::ReusablePathIterator::setCoord(double x, double y) { - curSubPath->setX(coordOff, x); - curSubPath->setY(coordOff, y); -} - -void GfxState::ReusablePathIterator::reset() { - coordOff = 0; - subPathOff = 0; - curSubPath = path->getSubpath(0); - numCoords = curSubPath->getNumPoints(); -} - -GfxState::GfxState(double hDPIA, double vDPIA, PDFRectangle *pageBox, - int rotateA, GBool upsideDown) { - double kx, ky; - - hDPI = hDPIA; - vDPI = vDPIA; - rotate = rotateA; - px1 = pageBox->x1; - py1 = pageBox->y1; - px2 = pageBox->x2; - py2 = pageBox->y2; - kx = hDPI / 72.0; - ky = vDPI / 72.0; - if (rotate == 90) { - ctm[0] = 0; - ctm[1] = upsideDown ? ky : -ky; - ctm[2] = kx; - ctm[3] = 0; - ctm[4] = -kx * py1; - ctm[5] = ky * (upsideDown ? -px1 : px2); - pageWidth = kx * (py2 - py1); - pageHeight = ky * (px2 - px1); - } else if (rotate == 180) { - ctm[0] = -kx; - ctm[1] = 0; - ctm[2] = 0; - ctm[3] = upsideDown ? ky : -ky; - ctm[4] = kx * px2; - ctm[5] = ky * (upsideDown ? -py1 : py2); - pageWidth = kx * (px2 - px1); - pageHeight = ky * (py2 - py1); - } else if (rotate == 270) { - ctm[0] = 0; - ctm[1] = upsideDown ? -ky : ky; - ctm[2] = -kx; - ctm[3] = 0; - ctm[4] = kx * py2; - ctm[5] = ky * (upsideDown ? px2 : -px1); - pageWidth = kx * (py2 - py1); - pageHeight = ky * (px2 - px1); - } else { - ctm[0] = kx; - ctm[1] = 0; - ctm[2] = 0; - ctm[3] = upsideDown ? -ky : ky; - ctm[4] = -kx * px1; - ctm[5] = ky * (upsideDown ? py2 : -py1); - pageWidth = kx * (px2 - px1); - pageHeight = ky * (py2 - py1); - } - - fillColorSpace = new GfxDeviceGrayColorSpace(); - strokeColorSpace = new GfxDeviceGrayColorSpace(); - fillColor.c[0] = 0; - strokeColor.c[0] = 0; - fillPattern = nullptr; - strokePattern = nullptr; - blendMode = gfxBlendNormal; - fillOpacity = 1; - strokeOpacity = 1; - fillOverprint = gFalse; - strokeOverprint = gFalse; - overprintMode = 0; - transfer[0] = transfer[1] = transfer[2] = transfer[3] = nullptr; - - lineWidth = 1; - lineDash = nullptr; - lineDashLength = 0; - lineDashStart = 0; - flatness = 1; - lineJoin = 0; - lineCap = 0; - miterLimit = 10; - strokeAdjust = gFalse; - alphaIsShape = gFalse; - textKnockout = gFalse; - - font = nullptr; - fontSize = 0; - textMat[0] = 1; textMat[1] = 0; - textMat[2] = 0; textMat[3] = 1; - textMat[4] = 0; textMat[5] = 0; - charSpace = 0; - wordSpace = 0; - horizScaling = 1; - leading = 0; - rise = 0; - render = 0; - - path = new GfxPath(); - curX = curY = 0; - lineX = lineY = 0; - - clipXMin = 0; - clipYMin = 0; - clipXMax = pageWidth; - clipYMax = pageHeight; - - renderingIntent[0] = 0; - - saved = nullptr; -#ifdef USE_CMS - GfxColorSpace::setupColorProfiles(); - XYZ2DisplayTransformRelCol = nullptr; - XYZ2DisplayTransformAbsCol = nullptr; - XYZ2DisplayTransformSat = nullptr; - XYZ2DisplayTransformPerc = nullptr; - localDisplayProfile = nullptr; - displayProfileRef = 0; -#endif -} - -GfxState::~GfxState() { - int i; - - if (fillColorSpace) { - delete fillColorSpace; - } - if (strokeColorSpace) { - delete strokeColorSpace; - } - if (fillPattern) { - delete fillPattern; - } - if (strokePattern) { - delete strokePattern; - } - for (i = 0; i < 4; ++i) { - if (transfer[i]) { - delete transfer[i]; - } - } - gfree(lineDash); - if (path) { - // this gets set to NULL by restore() - delete path; - } - if (font) { - font->decRefCnt(); - } -#ifdef USE_CMS - if (XYZ2DisplayTransformRelCol) { - if (XYZ2DisplayTransformRelCol->unref() == 0) - delete XYZ2DisplayTransformRelCol; - } - if (XYZ2DisplayTransformAbsCol) { - if (XYZ2DisplayTransformAbsCol->unref() == 0) - delete XYZ2DisplayTransformAbsCol; - } - if (XYZ2DisplayTransformSat) { - if (XYZ2DisplayTransformSat->unref() == 0) - delete XYZ2DisplayTransformSat; - } - if (XYZ2DisplayTransformPerc) { - if (XYZ2DisplayTransformPerc->unref() == 0) - delete XYZ2DisplayTransformPerc; - } - if (--displayProfileRef == 0 && localDisplayProfile != nullptr) { - cmsCloseProfile(localDisplayProfile); - } -#endif -} - -// Used for copy(); -GfxState::GfxState(GfxState *state, GBool copyPath) { - int i; - - memcpy(this, state, sizeof(GfxState)); - if (fillColorSpace) { - fillColorSpace = state->fillColorSpace->copy(); - } - if (strokeColorSpace) { - strokeColorSpace = state->strokeColorSpace->copy(); - } - if (fillPattern) { - fillPattern = state->fillPattern->copy(); - } - if (strokePattern) { - strokePattern = state->strokePattern->copy(); - } - for (i = 0; i < 4; ++i) { - if (transfer[i]) { - transfer[i] = state->transfer[i]->copy(); - } - } - if (lineDashLength > 0) { - lineDash = (double *)gmallocn(lineDashLength, sizeof(double)); - memcpy(lineDash, state->lineDash, lineDashLength * sizeof(double)); - } - if (font) - font->incRefCnt(); - - if (copyPath) { - path = state->path->copy(); - } - saved = nullptr; -#ifdef USE_CMS - if (XYZ2DisplayTransformRelCol) { - XYZ2DisplayTransformRelCol->ref(); - } - if (XYZ2DisplayTransformAbsCol) { - XYZ2DisplayTransformAbsCol->ref(); - } - if (XYZ2DisplayTransformSat) { - XYZ2DisplayTransformSat->ref(); - } - if (XYZ2DisplayTransformPerc) { - XYZ2DisplayTransformPerc->ref(); - } - if (localDisplayProfile) { - displayProfileRef++; - } -#endif -} - -#ifdef USE_CMS -void GfxState::setDisplayProfile(cmsHPROFILE localDisplayProfileA) { - if (localDisplayProfile != nullptr) { - cmsCloseProfile(localDisplayProfile); - } - localDisplayProfile = localDisplayProfileA; - if (localDisplayProfileA != nullptr) { - cmsHTRANSFORM transform; - unsigned int nChannels; - unsigned int localDisplayPixelType; - - localDisplayPixelType = getCMSColorSpaceType(cmsGetColorSpace(localDisplayProfile)); - nChannels = getCMSNChannels(cmsGetColorSpace(localDisplayProfile)); - displayProfileRef = 1; - // create transform from XYZ - cmsHPROFILE XYZProfile = cmsCreateXYZProfile(); - if ((transform = cmsCreateTransform(XYZProfile, TYPE_XYZ_DBL, - localDisplayProfile, - COLORSPACE_SH(localDisplayPixelType) | - CHANNELS_SH(nChannels) | BYTES_SH(1), - INTENT_RELATIVE_COLORIMETRIC,LCMS_FLAGS)) == nullptr) { - error(errSyntaxWarning, -1, "Can't create Lab transform"); - } else { - XYZ2DisplayTransformRelCol = new GfxColorTransform(transform, INTENT_RELATIVE_COLORIMETRIC, PT_XYZ, localDisplayPixelType); - } - if ((transform = cmsCreateTransform(XYZProfile, TYPE_XYZ_DBL, - localDisplayProfile, - COLORSPACE_SH(localDisplayPixelType) | - CHANNELS_SH(nChannels) | BYTES_SH(1), - INTENT_ABSOLUTE_COLORIMETRIC,LCMS_FLAGS)) == nullptr) { - error(errSyntaxWarning, -1, "Can't create Lab transform"); - } else { - XYZ2DisplayTransformAbsCol = new GfxColorTransform(transform, INTENT_ABSOLUTE_COLORIMETRIC, PT_XYZ, localDisplayPixelType); - } - if ((transform = cmsCreateTransform(XYZProfile, TYPE_XYZ_DBL, - localDisplayProfile, - COLORSPACE_SH(localDisplayPixelType) | - CHANNELS_SH(nChannels) | BYTES_SH(1), - INTENT_SATURATION,LCMS_FLAGS)) == nullptr) { - error(errSyntaxWarning, -1, "Can't create Lab transform"); - } else { - XYZ2DisplayTransformSat = new GfxColorTransform(transform, INTENT_SATURATION, PT_XYZ, localDisplayPixelType); - } - if ((transform = cmsCreateTransform(XYZProfile, TYPE_XYZ_DBL, - localDisplayProfile, - COLORSPACE_SH(localDisplayPixelType) | - CHANNELS_SH(nChannels) | BYTES_SH(1), - INTENT_PERCEPTUAL,LCMS_FLAGS)) == nullptr) { - error(errSyntaxWarning, -1, "Can't create Lab transform"); - } else { - XYZ2DisplayTransformPerc = new GfxColorTransform(transform, INTENT_PERCEPTUAL, PT_XYZ, localDisplayPixelType); - } - cmsCloseProfile(XYZProfile); - } -} - -GfxColorTransform *GfxState::getXYZ2DisplayTransform() { - GfxColorTransform *transform; - - transform = XYZ2DisplayTransformRelCol; - if (strcmp(renderingIntent, "AbsoluteColorimetric") == 0) { - transform = XYZ2DisplayTransformAbsCol; - } else if (strcmp(renderingIntent, "Saturation") == 0) { - transform = XYZ2DisplayTransformSat; - } else if (strcmp(renderingIntent, "Perceptual") == 0) { - transform = XYZ2DisplayTransformPerc; - } - if (transform == nullptr) { - transform = XYZ2DisplayTransform; - } - return transform; -} - -#endif - -void GfxState::setPath(GfxPath *pathA) { - delete path; - path = pathA; -} - -void GfxState::getUserClipBBox(double *xMin, double *yMin, - double *xMax, double *yMax) { - double ictm[6]; - double xMin1, yMin1, xMax1, yMax1, tx, ty; - - // invert the CTM - const double det_denominator = (ctm[0] * ctm[3] - ctm[1] * ctm[2]); - if (unlikely(det_denominator == 0)) { - *xMin = 0; - *yMin = 0; - *xMax = 0; - *yMax = 0; - return; - } - const double det = 1 / det_denominator; - ictm[0] = ctm[3] * det; - ictm[1] = -ctm[1] * det; - ictm[2] = -ctm[2] * det; - ictm[3] = ctm[0] * det; - ictm[4] = (ctm[2] * ctm[5] - ctm[3] * ctm[4]) * det; - ictm[5] = (ctm[1] * ctm[4] - ctm[0] * ctm[5]) * det; - - // transform all four corners of the clip bbox; find the min and max - // x and y values - xMin1 = xMax1 = clipXMin * ictm[0] + clipYMin * ictm[2] + ictm[4]; - yMin1 = yMax1 = clipXMin * ictm[1] + clipYMin * ictm[3] + ictm[5]; - tx = clipXMin * ictm[0] + clipYMax * ictm[2] + ictm[4]; - ty = clipXMin * ictm[1] + clipYMax * ictm[3] + ictm[5]; - if (tx < xMin1) { - xMin1 = tx; - } else if (tx > xMax1) { - xMax1 = tx; - } - if (ty < yMin1) { - yMin1 = ty; - } else if (ty > yMax1) { - yMax1 = ty; - } - tx = clipXMax * ictm[0] + clipYMin * ictm[2] + ictm[4]; - ty = clipXMax * ictm[1] + clipYMin * ictm[3] + ictm[5]; - if (tx < xMin1) { - xMin1 = tx; - } else if (tx > xMax1) { - xMax1 = tx; - } - if (ty < yMin1) { - yMin1 = ty; - } else if (ty > yMax1) { - yMax1 = ty; - } - tx = clipXMax * ictm[0] + clipYMax * ictm[2] + ictm[4]; - ty = clipXMax * ictm[1] + clipYMax * ictm[3] + ictm[5]; - if (tx < xMin1) { - xMin1 = tx; - } else if (tx > xMax1) { - xMax1 = tx; - } - if (ty < yMin1) { - yMin1 = ty; - } else if (ty > yMax1) { - yMax1 = ty; - } - - *xMin = xMin1; - *yMin = yMin1; - *xMax = xMax1; - *yMax = yMax1; -} - -double GfxState::transformWidth(double w) { - double x, y; - - x = ctm[0] + ctm[2]; - y = ctm[1] + ctm[3]; - return w * sqrt(0.5 * (x * x + y * y)); -} - -double GfxState::getTransformedFontSize() { - double x1, y1, x2, y2; - - x1 = textMat[2] * fontSize; - y1 = textMat[3] * fontSize; - x2 = ctm[0] * x1 + ctm[2] * y1; - y2 = ctm[1] * x1 + ctm[3] * y1; - return sqrt(x2 * x2 + y2 * y2); -} - -void GfxState::getFontTransMat(double *m11, double *m12, - double *m21, double *m22) { - *m11 = (textMat[0] * ctm[0] + textMat[1] * ctm[2]) * fontSize; - *m12 = (textMat[0] * ctm[1] + textMat[1] * ctm[3]) * fontSize; - *m21 = (textMat[2] * ctm[0] + textMat[3] * ctm[2]) * fontSize; - *m22 = (textMat[2] * ctm[1] + textMat[3] * ctm[3]) * fontSize; -} - -void GfxState::setCTM(double a, double b, double c, - double d, double e, double f) { - ctm[0] = a; - ctm[1] = b; - ctm[2] = c; - ctm[3] = d; - ctm[4] = e; - ctm[5] = f; -} - -void GfxState::concatCTM(double a, double b, double c, - double d, double e, double f) { - double a1 = ctm[0]; - double b1 = ctm[1]; - double c1 = ctm[2]; - double d1 = ctm[3]; - - ctm[0] = a * a1 + b * c1; - ctm[1] = a * b1 + b * d1; - ctm[2] = c * a1 + d * c1; - ctm[3] = c * b1 + d * d1; - ctm[4] = e * a1 + f * c1 + ctm[4]; - ctm[5] = e * b1 + f * d1 + ctm[5]; -} - -void GfxState::shiftCTMAndClip(double tx, double ty) { - ctm[4] += tx; - ctm[5] += ty; - clipXMin += tx; - clipYMin += ty; - clipXMax += tx; - clipYMax += ty; -} - -void GfxState::setFillColorSpace(GfxColorSpace *colorSpace) { - if (fillColorSpace) { - delete fillColorSpace; - } - fillColorSpace = colorSpace; -} - -void GfxState::setStrokeColorSpace(GfxColorSpace *colorSpace) { - if (strokeColorSpace) { - delete strokeColorSpace; - } - strokeColorSpace = colorSpace; -} - -void GfxState::setFillPattern(GfxPattern *pattern) { - if (fillPattern) { - delete fillPattern; - } - fillPattern = pattern; -} - -void GfxState::setStrokePattern(GfxPattern *pattern) { - if (strokePattern) { - delete strokePattern; - } - strokePattern = pattern; -} - -void GfxState::setFont(GfxFont *fontA, double fontSizeA) { - if (font) - font->decRefCnt(); - - font = fontA; - fontSize = fontSizeA; -} - -void GfxState::setTransfer(Function **funcs) { - int i; - - for (i = 0; i < 4; ++i) { - if (transfer[i]) { - delete transfer[i]; - } - transfer[i] = funcs[i]; - } -} - -void GfxState::setLineDash(double *dash, int length, double start) { - if (lineDash) - gfree(lineDash); - lineDash = dash; - lineDashLength = length; - lineDashStart = start; -} - -void GfxState::clearPath() { - delete path; - path = new GfxPath(); -} - -void GfxState::clip() { - double xMin, yMin, xMax, yMax, x, y; - GfxSubpath *subpath; - int i, j; - - xMin = xMax = yMin = yMax = 0; // make gcc happy - for (i = 0; i < path->getNumSubpaths(); ++i) { - subpath = path->getSubpath(i); - for (j = 0; j < subpath->getNumPoints(); ++j) { - transform(subpath->getX(j), subpath->getY(j), &x, &y); - if (i == 0 && j == 0) { - xMin = xMax = x; - yMin = yMax = y; - } else { - if (x < xMin) { - xMin = x; - } else if (x > xMax) { - xMax = x; - } - if (y < yMin) { - yMin = y; - } else if (y > yMax) { - yMax = y; - } - } - } - } - if (xMin > clipXMin) { - clipXMin = xMin; - } - if (yMin > clipYMin) { - clipYMin = yMin; - } - if (xMax < clipXMax) { - clipXMax = xMax; - } - if (yMax < clipYMax) { - clipYMax = yMax; - } -} - -void GfxState::clipToStrokePath() { - double xMin, yMin, xMax, yMax, x, y, t0, t1; - GfxSubpath *subpath; - int i, j; - - xMin = xMax = yMin = yMax = 0; // make gcc happy - for (i = 0; i < path->getNumSubpaths(); ++i) { - subpath = path->getSubpath(i); - for (j = 0; j < subpath->getNumPoints(); ++j) { - transform(subpath->getX(j), subpath->getY(j), &x, &y); - if (i == 0 && j == 0) { - xMin = xMax = x; - yMin = yMax = y; - } else { - if (x < xMin) { - xMin = x; - } else if (x > xMax) { - xMax = x; - } - if (y < yMin) { - yMin = y; - } else if (y > yMax) { - yMax = y; - } - } - } - } - - // allow for the line width - //~ miter joins can extend farther than this - t0 = fabs(ctm[0]); - t1 = fabs(ctm[2]); - if (t0 > t1) { - xMin -= 0.5 * lineWidth * t0; - xMax += 0.5 * lineWidth * t0; - } else { - xMin -= 0.5 * lineWidth * t1; - xMax += 0.5 * lineWidth * t1; - } - t0 = fabs(ctm[0]); - t1 = fabs(ctm[3]); - if (t0 > t1) { - yMin -= 0.5 * lineWidth * t0; - yMax += 0.5 * lineWidth * t0; - } else { - yMin -= 0.5 * lineWidth * t1; - yMax += 0.5 * lineWidth * t1; - } - - if (xMin > clipXMin) { - clipXMin = xMin; - } - if (yMin > clipYMin) { - clipYMin = yMin; - } - if (xMax < clipXMax) { - clipXMax = xMax; - } - if (yMax < clipYMax) { - clipYMax = yMax; - } -} - -void GfxState::clipToRect(double xMin, double yMin, double xMax, double yMax) { - double x, y, xMin1, yMin1, xMax1, yMax1; - - transform(xMin, yMin, &x, &y); - xMin1 = xMax1 = x; - yMin1 = yMax1 = y; - transform(xMax, yMin, &x, &y); - if (x < xMin1) { - xMin1 = x; - } else if (x > xMax1) { - xMax1 = x; - } - if (y < yMin1) { - yMin1 = y; - } else if (y > yMax1) { - yMax1 = y; - } - transform(xMax, yMax, &x, &y); - if (x < xMin1) { - xMin1 = x; - } else if (x > xMax1) { - xMax1 = x; - } - if (y < yMin1) { - yMin1 = y; - } else if (y > yMax1) { - yMax1 = y; - } - transform(xMin, yMax, &x, &y); - if (x < xMin1) { - xMin1 = x; - } else if (x > xMax1) { - xMax1 = x; - } - if (y < yMin1) { - yMin1 = y; - } else if (y > yMax1) { - yMax1 = y; - } - - if (xMin1 > clipXMin) { - clipXMin = xMin1; - } - if (yMin1 > clipYMin) { - clipYMin = yMin1; - } - if (xMax1 < clipXMax) { - clipXMax = xMax1; - } - if (yMax1 < clipYMax) { - clipYMax = yMax1; - } -} - -void GfxState::textShift(double tx, double ty) { - double dx, dy; - - textTransformDelta(tx, ty, &dx, &dy); - curX += dx; - curY += dy; -} - -void GfxState::shift(double dx, double dy) { - curX += dx; - curY += dy; -} - -GfxState *GfxState::save() { - GfxState *newState; - - newState = copy(); - newState->saved = this; - return newState; -} - -GfxState *GfxState::restore() { - GfxState *oldState; - - if (saved) { - oldState = saved; - - // these attributes aren't saved/restored by the q/Q operators - oldState->path = path; - oldState->curX = curX; - oldState->curY = curY; - oldState->lineX = lineX; - oldState->lineY = lineY; - - path = nullptr; - saved = nullptr; - delete this; - - } else { - oldState = this; - } - - return oldState; -} - -GBool GfxState::parseBlendMode(Object *obj, GfxBlendMode *mode) { - int i, j; - - if (obj->isName()) { - for (i = 0; i < nGfxBlendModeNames; ++i) { - if (!strcmp(obj->getName(), gfxBlendModeNames[i].name)) { - *mode = gfxBlendModeNames[i].mode; - return gTrue; - } - } - return gFalse; - } else if (obj->isArray()) { - for (i = 0; i < obj->arrayGetLength(); ++i) { - Object obj2 = obj->arrayGet(i); - if (!obj2.isName()) { - return gFalse; - } - for (j = 0; j < nGfxBlendModeNames; ++j) { - if (!strcmp(obj2.getName(), gfxBlendModeNames[j].name)) { - *mode = gfxBlendModeNames[j].mode; - return gTrue; - } - } - } - *mode = gfxBlendNormal; - return gTrue; - } else { - return gFalse; - } -} |