123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563 |
- /*
- * pyCMS
- * a Python / PIL interface to the littleCMS ICC Color Management System
- * Copyright (C) 2002-2003 Kevin Cazabon
- * kevin@cazabon.com
- * https://www.cazabon.com
- * Adapted/reworked for PIL by Fredrik Lundh
- * Copyright (c) 2009 Fredrik Lundh
- * Updated to LCMS2
- * Copyright (c) 2013 Eric Soroos
- *
- * pyCMS home page: https://www.cazabon.com/pyCMS
- * littleCMS home page: https://www.littlecms.com
- * (littleCMS is Copyright (C) 1998-2001 Marti Maria)
- *
- * Originally released under LGPL. Graciously donated to PIL in
- * March 2009, for distribution under the standard PIL license
- */
- #define COPYRIGHTINFO \
- "\
- pyCMS\n\
- a Python / PIL interface to the littleCMS ICC Color Management System\n\
- Copyright (C) 2002-2003 Kevin Cazabon\n\
- kevin@cazabon.com\n\
- https://www.cazabon.com\n\
- "
- #define PY_SSIZE_T_CLEAN
- #include "Python.h" // Include before wchar.h so _GNU_SOURCE is set
- #include "wchar.h"
- #include "datetime.h"
- #include "lcms2.h"
- #include "libImaging/Imaging.h"
- #define PYCMSVERSION "1.0.0 pil"
- /* version history */
- /*
- 1.0.0 pil Integrating littleCMS2
- 0.1.0 pil integration & refactoring
- 0.0.2 alpha: Minor updates, added interfaces to littleCMS features, Jan 6, 2003
- - fixed some memory holes in how transforms/profiles were created and passed back to
- Python due to improper destructor setup for PyCObjects
- - added buildProofTransformFromOpenProfiles() function
- - eliminated some code redundancy, centralizing several common tasks with internal
- functions
- 0.0.1 alpha: First public release Dec 26, 2002
- */
- /* known to-do list with current version:
- Verify that PILmode->littleCMStype conversion in findLCMStype is correct for all
- PIL modes (it probably isn't for the more obscure ones)
- Add support for creating custom RGB profiles on the fly
- Add support for checking presence of a specific tag in a profile
- Add support for other littleCMS features as required
- */
- /*
- INTENT_PERCEPTUAL 0
- INTENT_RELATIVE_COLORIMETRIC 1
- INTENT_SATURATION 2
- INTENT_ABSOLUTE_COLORIMETRIC 3
- */
- /* -------------------------------------------------------------------- */
- /* wrapper classes */
- /* a profile represents the ICC characteristics for a specific device */
- typedef struct {
- PyObject_HEAD cmsHPROFILE profile;
- } CmsProfileObject;
- static PyTypeObject CmsProfile_Type;
- #define CmsProfile_Check(op) (Py_TYPE(op) == &CmsProfile_Type)
- static PyObject *
- cms_profile_new(cmsHPROFILE profile) {
- CmsProfileObject *self;
- self = PyObject_New(CmsProfileObject, &CmsProfile_Type);
- if (!self) {
- return NULL;
- }
- self->profile = profile;
- return (PyObject *)self;
- }
- static PyObject *
- cms_profile_open(PyObject *self, PyObject *args) {
- cmsHPROFILE hProfile;
- char *sProfile;
- if (!PyArg_ParseTuple(args, "s:profile_open", &sProfile)) {
- return NULL;
- }
- hProfile = cmsOpenProfileFromFile(sProfile, "r");
- if (!hProfile) {
- PyErr_SetString(PyExc_OSError, "cannot open profile file");
- return NULL;
- }
- return cms_profile_new(hProfile);
- }
- static PyObject *
- cms_profile_frombytes(PyObject *self, PyObject *args) {
- cmsHPROFILE hProfile;
- char *pProfile;
- Py_ssize_t nProfile;
- if (!PyArg_ParseTuple(args, "y#:profile_frombytes", &pProfile, &nProfile)) {
- return NULL;
- }
- hProfile = cmsOpenProfileFromMem(pProfile, nProfile);
- if (!hProfile) {
- PyErr_SetString(PyExc_OSError, "cannot open profile from string");
- return NULL;
- }
- return cms_profile_new(hProfile);
- }
- static PyObject *
- cms_profile_tobytes(PyObject *self, PyObject *args) {
- char *pProfile = NULL;
- cmsUInt32Number nProfile;
- PyObject *CmsProfile;
- cmsHPROFILE *profile;
- PyObject *ret;
- if (!PyArg_ParseTuple(args, "O", &CmsProfile)) {
- return NULL;
- }
- profile = ((CmsProfileObject *)CmsProfile)->profile;
- if (!cmsSaveProfileToMem(profile, pProfile, &nProfile)) {
- PyErr_SetString(PyExc_OSError, "Could not determine profile size");
- return NULL;
- }
- pProfile = (char *)malloc(nProfile);
- if (!pProfile) {
- PyErr_SetString(PyExc_OSError, "Out of Memory");
- return NULL;
- }
- if (!cmsSaveProfileToMem(profile, pProfile, &nProfile)) {
- PyErr_SetString(PyExc_OSError, "Could not get profile");
- free(pProfile);
- return NULL;
- }
- ret = PyBytes_FromStringAndSize(pProfile, (Py_ssize_t)nProfile);
- free(pProfile);
- return ret;
- }
- static void
- cms_profile_dealloc(CmsProfileObject *self) {
- (void)cmsCloseProfile(self->profile);
- PyObject_Del(self);
- }
- /* a transform represents the mapping between two profiles */
- typedef struct {
- PyObject_HEAD char mode_in[8];
- char mode_out[8];
- cmsHTRANSFORM transform;
- } CmsTransformObject;
- static PyTypeObject CmsTransform_Type;
- #define CmsTransform_Check(op) (Py_TYPE(op) == &CmsTransform_Type)
- static PyObject *
- cms_transform_new(cmsHTRANSFORM transform, char *mode_in, char *mode_out) {
- CmsTransformObject *self;
- self = PyObject_New(CmsTransformObject, &CmsTransform_Type);
- if (!self) {
- return NULL;
- }
- self->transform = transform;
- strcpy(self->mode_in, mode_in);
- strcpy(self->mode_out, mode_out);
- return (PyObject *)self;
- }
- static void
- cms_transform_dealloc(CmsTransformObject *self) {
- cmsDeleteTransform(self->transform);
- PyObject_Del(self);
- }
- /* -------------------------------------------------------------------- */
- /* internal functions */
- static cmsUInt32Number
- findLCMStype(char *PILmode) {
- if (strcmp(PILmode, "RGB") == 0) {
- return TYPE_RGBA_8;
- } else if (strcmp(PILmode, "RGBA") == 0) {
- return TYPE_RGBA_8;
- } else if (strcmp(PILmode, "RGBX") == 0) {
- return TYPE_RGBA_8;
- } else if (strcmp(PILmode, "RGBA;16B") == 0) {
- return TYPE_RGBA_16;
- } else if (strcmp(PILmode, "CMYK") == 0) {
- return TYPE_CMYK_8;
- } else if (strcmp(PILmode, "L") == 0) {
- return TYPE_GRAY_8;
- } else if (strcmp(PILmode, "L;16") == 0) {
- return TYPE_GRAY_16;
- } else if (strcmp(PILmode, "L;16B") == 0) {
- return TYPE_GRAY_16_SE;
- } else if (strcmp(PILmode, "YCCA") == 0) {
- return TYPE_YCbCr_8;
- } else if (strcmp(PILmode, "YCC") == 0) {
- return TYPE_YCbCr_8;
- } else if (strcmp(PILmode, "LAB") == 0) {
- // LabX equivalent like ALab, but not reversed -- no #define in lcms2
- return (COLORSPACE_SH(PT_LabV2) | CHANNELS_SH(3) | BYTES_SH(1) | EXTRA_SH(1));
- }
- else {
- /* take a wild guess... but you probably should fail instead. */
- return TYPE_GRAY_8; /* so there's no buffer overrun... */
- }
- }
- #define Cms_Min(a, b) ((a) < (b) ? (a) : (b))
- static int
- pyCMSgetAuxChannelChannel(cmsUInt32Number format, int auxChannelNdx) {
- int numColors = T_CHANNELS(format);
- int numExtras = T_EXTRA(format);
- if (T_SWAPFIRST(format) && T_DOSWAP(format)) {
- // reverse order, before anything but last extra is shifted last
- if (auxChannelNdx == numExtras - 1) {
- return numColors + numExtras - 1;
- } else {
- return numExtras - 2 - auxChannelNdx;
- }
- } else if (T_SWAPFIRST(format)) {
- // in order, after color channels, but last extra is shifted to first
- if (auxChannelNdx == numExtras - 1) {
- return 0;
- } else {
- return numColors + 1 + auxChannelNdx;
- }
- } else if (T_DOSWAP(format)) {
- // reverse order, before anything
- return numExtras - 1 - auxChannelNdx;
- } else {
- // in order, after color channels
- return numColors + auxChannelNdx;
- }
- }
- static void
- pyCMScopyAux(cmsHTRANSFORM hTransform, Imaging imDst, const Imaging imSrc) {
- cmsUInt32Number dstLCMSFormat;
- cmsUInt32Number srcLCMSFormat;
- int numSrcExtras;
- int numDstExtras;
- int numExtras;
- int ySize;
- int xSize;
- int channelSize;
- int srcChunkSize;
- int dstChunkSize;
- int e;
- // trivially copied
- if (imDst == imSrc) {
- return;
- }
- dstLCMSFormat = cmsGetTransformOutputFormat(hTransform);
- srcLCMSFormat = cmsGetTransformInputFormat(hTransform);
- // currently, all Pillow formats are chunky formats, but check it anyway
- if (T_PLANAR(dstLCMSFormat) || T_PLANAR(srcLCMSFormat)) {
- return;
- }
- // copy only if channel format is identical, except OPTIMIZED is ignored as it
- // does not affect the aux channel
- if (T_FLOAT(dstLCMSFormat) != T_FLOAT(srcLCMSFormat) ||
- T_FLAVOR(dstLCMSFormat) != T_FLAVOR(srcLCMSFormat) ||
- T_ENDIAN16(dstLCMSFormat) != T_ENDIAN16(srcLCMSFormat) ||
- T_BYTES(dstLCMSFormat) != T_BYTES(srcLCMSFormat)) {
- return;
- }
- numSrcExtras = T_EXTRA(srcLCMSFormat);
- numDstExtras = T_EXTRA(dstLCMSFormat);
- numExtras = Cms_Min(numSrcExtras, numDstExtras);
- ySize = Cms_Min(imSrc->ysize, imDst->ysize);
- xSize = Cms_Min(imSrc->xsize, imDst->xsize);
- channelSize = T_BYTES(dstLCMSFormat);
- srcChunkSize = (T_CHANNELS(srcLCMSFormat) + T_EXTRA(srcLCMSFormat)) * channelSize;
- dstChunkSize = (T_CHANNELS(dstLCMSFormat) + T_EXTRA(dstLCMSFormat)) * channelSize;
- for (e = 0; e < numExtras; ++e) {
- int y;
- int dstChannel = pyCMSgetAuxChannelChannel(dstLCMSFormat, e);
- int srcChannel = pyCMSgetAuxChannelChannel(srcLCMSFormat, e);
- for (y = 0; y < ySize; y++) {
- int x;
- char *pDstExtras = imDst->image[y] + dstChannel * channelSize;
- const char *pSrcExtras = imSrc->image[y] + srcChannel * channelSize;
- for (x = 0; x < xSize; x++) {
- memcpy(
- pDstExtras + x * dstChunkSize,
- pSrcExtras + x * srcChunkSize,
- channelSize);
- }
- }
- }
- }
- static int
- pyCMSdoTransform(Imaging im, Imaging imOut, cmsHTRANSFORM hTransform) {
- int i;
- if (im->xsize > imOut->xsize || im->ysize > imOut->ysize) {
- return -1;
- }
- Py_BEGIN_ALLOW_THREADS
- // transform color channels only
- for (i = 0; i < im->ysize; i++) {
- cmsDoTransform(hTransform, im->image[i], imOut->image[i], im->xsize);
- }
- // lcms by default does nothing to the auxiliary channels leaving those
- // unchanged. To do "the right thing" here, i.e. maintain identical results
- // with and without inPlace, we replicate those channels to the output.
- //
- // As of lcms 2.8, a new cmsFLAGS_COPY_ALPHA flag is introduced which would
- // do the same thing automagically. Unfortunately, lcms2.8 is not yet widely
- // enough available on all platforms, so we polyfill it here for now.
- pyCMScopyAux(hTransform, imOut, im);
- Py_END_ALLOW_THREADS
- return 0;
- }
- static cmsHTRANSFORM
- _buildTransform(
- cmsHPROFILE hInputProfile,
- cmsHPROFILE hOutputProfile,
- char *sInMode,
- char *sOutMode,
- int iRenderingIntent,
- cmsUInt32Number cmsFLAGS) {
- cmsHTRANSFORM hTransform;
- Py_BEGIN_ALLOW_THREADS
- /* create the transform */
- hTransform = cmsCreateTransform(
- hInputProfile,
- findLCMStype(sInMode),
- hOutputProfile,
- findLCMStype(sOutMode),
- iRenderingIntent,
- cmsFLAGS);
- Py_END_ALLOW_THREADS
- if (!hTransform) {
- PyErr_SetString(PyExc_ValueError, "cannot build transform");
- }
- return hTransform; /* if NULL, an exception is set */
- }
- static cmsHTRANSFORM
- _buildProofTransform(
- cmsHPROFILE hInputProfile,
- cmsHPROFILE hOutputProfile,
- cmsHPROFILE hProofProfile,
- char *sInMode,
- char *sOutMode,
- int iRenderingIntent,
- int iProofIntent,
- cmsUInt32Number cmsFLAGS) {
- cmsHTRANSFORM hTransform;
- Py_BEGIN_ALLOW_THREADS
- /* create the transform */
- hTransform = cmsCreateProofingTransform(
- hInputProfile,
- findLCMStype(sInMode),
- hOutputProfile,
- findLCMStype(sOutMode),
- hProofProfile,
- iRenderingIntent,
- iProofIntent,
- cmsFLAGS);
- Py_END_ALLOW_THREADS
- if (!hTransform) {
- PyErr_SetString(PyExc_ValueError, "cannot build proof transform");
- }
- return hTransform; /* if NULL, an exception is set */
- }
- /* -------------------------------------------------------------------- */
- /* Python callable functions */
- static PyObject *
- buildTransform(PyObject *self, PyObject *args) {
- CmsProfileObject *pInputProfile;
- CmsProfileObject *pOutputProfile;
- char *sInMode;
- char *sOutMode;
- int iRenderingIntent = 0;
- int cmsFLAGS = 0;
- cmsHTRANSFORM transform = NULL;
- if (!PyArg_ParseTuple(
- args,
- "O!O!ss|ii:buildTransform",
- &CmsProfile_Type,
- &pInputProfile,
- &CmsProfile_Type,
- &pOutputProfile,
- &sInMode,
- &sOutMode,
- &iRenderingIntent,
- &cmsFLAGS)) {
- return NULL;
- }
- transform = _buildTransform(
- pInputProfile->profile,
- pOutputProfile->profile,
- sInMode,
- sOutMode,
- iRenderingIntent,
- cmsFLAGS);
- if (!transform) {
- return NULL;
- }
- return cms_transform_new(transform, sInMode, sOutMode);
- }
- static PyObject *
- buildProofTransform(PyObject *self, PyObject *args) {
- CmsProfileObject *pInputProfile;
- CmsProfileObject *pOutputProfile;
- CmsProfileObject *pProofProfile;
- char *sInMode;
- char *sOutMode;
- int iRenderingIntent = 0;
- int iProofIntent = 0;
- int cmsFLAGS = 0;
- cmsHTRANSFORM transform = NULL;
- if (!PyArg_ParseTuple(
- args,
- "O!O!O!ss|iii:buildProofTransform",
- &CmsProfile_Type,
- &pInputProfile,
- &CmsProfile_Type,
- &pOutputProfile,
- &CmsProfile_Type,
- &pProofProfile,
- &sInMode,
- &sOutMode,
- &iRenderingIntent,
- &iProofIntent,
- &cmsFLAGS)) {
- return NULL;
- }
- transform = _buildProofTransform(
- pInputProfile->profile,
- pOutputProfile->profile,
- pProofProfile->profile,
- sInMode,
- sOutMode,
- iRenderingIntent,
- iProofIntent,
- cmsFLAGS);
- if (!transform) {
- return NULL;
- }
- return cms_transform_new(transform, sInMode, sOutMode);
- }
- static PyObject *
- cms_transform_apply(CmsTransformObject *self, PyObject *args) {
- Py_ssize_t idIn;
- Py_ssize_t idOut;
- Imaging im;
- Imaging imOut;
- int result;
- if (!PyArg_ParseTuple(args, "nn:apply", &idIn, &idOut)) {
- return NULL;
- }
- im = (Imaging)idIn;
- imOut = (Imaging)idOut;
- result = pyCMSdoTransform(im, imOut, self->transform);
- return Py_BuildValue("i", result);
- }
- /* -------------------------------------------------------------------- */
- /* Python-Callable On-The-Fly profile creation functions */
- static PyObject *
- createProfile(PyObject *self, PyObject *args) {
- char *sColorSpace;
- cmsHPROFILE hProfile;
- cmsFloat64Number dColorTemp = 0.0;
- cmsCIExyY whitePoint;
- cmsBool result;
- if (!PyArg_ParseTuple(args, "s|d:createProfile", &sColorSpace, &dColorTemp)) {
- return NULL;
- }
- if (strcmp(sColorSpace, "LAB") == 0) {
- if (dColorTemp > 0.0) {
- result = cmsWhitePointFromTemp(&whitePoint, dColorTemp);
- if (!result) {
- PyErr_SetString(
- PyExc_ValueError,
- "ERROR: Could not calculate white point from color temperature "
- "provided, must be float in degrees Kelvin");
- return NULL;
- }
- hProfile = cmsCreateLab2Profile(&whitePoint);
- } else {
- hProfile = cmsCreateLab2Profile(NULL);
- }
- } else if (strcmp(sColorSpace, "XYZ") == 0) {
- hProfile = cmsCreateXYZProfile();
- } else if (strcmp(sColorSpace, "sRGB") == 0) {
- hProfile = cmsCreate_sRGBProfile();
- } else {
- hProfile = NULL;
- }
- if (!hProfile) {
- PyErr_SetString(PyExc_ValueError, "failed to create requested color space");
- return NULL;
- }
- return cms_profile_new(hProfile);
- }
- /* -------------------------------------------------------------------- */
- /* profile methods */
- static PyObject *
- cms_profile_is_intent_supported(CmsProfileObject *self, PyObject *args) {
- cmsBool result;
- int intent;
- int direction;
- if (!PyArg_ParseTuple(args, "ii:is_intent_supported", &intent, &direction)) {
- return NULL;
- }
- result = cmsIsIntentSupported(self->profile, intent, direction);
- /* printf("cmsIsIntentSupported(%p, %d, %d) => %d\n", self->profile, intent,
- * direction, result); */
- return PyLong_FromLong(result != 0);
- }
- #ifdef _WIN32
- #ifdef _WIN64
- #define F_HANDLE "K"
- #else
- #define F_HANDLE "k"
- #endif
- static PyObject *
- cms_get_display_profile_win32(PyObject *self, PyObject *args) {
- char filename[MAX_PATH];
- cmsUInt32Number filename_size;
- BOOL ok;
- HANDLE handle = 0;
- int is_dc = 0;
- if (!PyArg_ParseTuple(
- args, "|" F_HANDLE "i:get_display_profile", &handle, &is_dc)) {
- return NULL;
- }
- filename_size = sizeof(filename);
- if (is_dc) {
- ok = GetICMProfile((HDC)handle, &filename_size, filename);
- } else {
- HDC dc = GetDC((HWND)handle);
- ok = GetICMProfile(dc, &filename_size, filename);
- ReleaseDC((HWND)handle, dc);
- }
- if (ok) {
- return PyUnicode_FromStringAndSize(filename, filename_size - 1);
- }
- Py_INCREF(Py_None);
- return Py_None;
- }
- #endif
- /* -------------------------------------------------------------------- */
- /* Helper functions. */
- static PyObject *
- _profile_read_mlu(CmsProfileObject *self, cmsTagSignature info) {
- PyObject *uni;
- char *lc = "en";
- char *cc = cmsNoCountry;
- cmsMLU *mlu;
- cmsUInt32Number len;
- wchar_t *buf;
- if (!cmsIsTag(self->profile, info)) {
- Py_INCREF(Py_None);
- return Py_None;
- }
- mlu = cmsReadTag(self->profile, info);
- if (!mlu) {
- Py_INCREF(Py_None);
- return Py_None;
- }
- len = cmsMLUgetWide(mlu, lc, cc, NULL, 0);
- if (len == 0) {
- Py_INCREF(Py_None);
- return Py_None;
- }
- buf = malloc(len);
- if (!buf) {
- PyErr_SetString(PyExc_OSError, "Out of Memory");
- return NULL;
- }
- /* Just in case the next call fails. */
- buf[0] = '\0';
- cmsMLUgetWide(mlu, lc, cc, buf, len);
- // buf contains additional junk after \0
- uni = PyUnicode_FromWideChar(buf, wcslen(buf));
- free(buf);
- return uni;
- }
- static PyObject *
- _profile_read_int_as_string(cmsUInt32Number nr) {
- PyObject *ret;
- char buf[5];
- buf[0] = (char)((nr >> 24) & 0xff);
- buf[1] = (char)((nr >> 16) & 0xff);
- buf[2] = (char)((nr >> 8) & 0xff);
- buf[3] = (char)(nr & 0xff);
- buf[4] = 0;
- ret = PyUnicode_DecodeASCII(buf, 4, NULL);
- return ret;
- }
- static PyObject *
- _profile_read_signature(CmsProfileObject *self, cmsTagSignature info) {
- unsigned int *sig;
- if (!cmsIsTag(self->profile, info)) {
- Py_INCREF(Py_None);
- return Py_None;
- }
- sig = (unsigned int *)cmsReadTag(self->profile, info);
- if (!sig) {
- Py_INCREF(Py_None);
- return Py_None;
- }
- return _profile_read_int_as_string(*sig);
- }
- static PyObject *
- _xyz_py(cmsCIEXYZ *XYZ) {
- cmsCIExyY xyY;
- cmsXYZ2xyY(&xyY, XYZ);
- return Py_BuildValue(
- "((d,d,d),(d,d,d))", XYZ->X, XYZ->Y, XYZ->Z, xyY.x, xyY.y, xyY.Y);
- }
- static PyObject *
- _xyz3_py(cmsCIEXYZ *XYZ) {
- cmsCIExyY xyY[3];
- cmsXYZ2xyY(&xyY[0], &XYZ[0]);
- cmsXYZ2xyY(&xyY[1], &XYZ[1]);
- cmsXYZ2xyY(&xyY[2], &XYZ[2]);
- return Py_BuildValue(
- "(((d,d,d),(d,d,d),(d,d,d)),((d,d,d),(d,d,d),(d,d,d)))",
- XYZ[0].X,
- XYZ[0].Y,
- XYZ[0].Z,
- XYZ[1].X,
- XYZ[1].Y,
- XYZ[1].Z,
- XYZ[2].X,
- XYZ[2].Y,
- XYZ[2].Z,
- xyY[0].x,
- xyY[0].y,
- xyY[0].Y,
- xyY[1].x,
- xyY[1].y,
- xyY[1].Y,
- xyY[2].x,
- xyY[2].y,
- xyY[2].Y);
- }
- static PyObject *
- _profile_read_ciexyz(CmsProfileObject *self, cmsTagSignature info, int multi) {
- cmsCIEXYZ *XYZ;
- if (!cmsIsTag(self->profile, info)) {
- Py_INCREF(Py_None);
- return Py_None;
- }
- XYZ = (cmsCIEXYZ *)cmsReadTag(self->profile, info);
- if (!XYZ) {
- Py_INCREF(Py_None);
- return Py_None;
- }
- if (multi) {
- return _xyz3_py(XYZ);
- } else {
- return _xyz_py(XYZ);
- }
- }
- static PyObject *
- _profile_read_ciexyy_triple(CmsProfileObject *self, cmsTagSignature info) {
- cmsCIExyYTRIPLE *triple;
- if (!cmsIsTag(self->profile, info)) {
- Py_INCREF(Py_None);
- return Py_None;
- }
- triple = (cmsCIExyYTRIPLE *)cmsReadTag(self->profile, info);
- if (!triple) {
- Py_INCREF(Py_None);
- return Py_None;
- }
- /* Note: lcms does all the heavy lifting and error checking (nr of
- channels == 3). */
- return Py_BuildValue(
- "((d,d,d),(d,d,d),(d,d,d)),",
- triple->Red.x,
- triple->Red.y,
- triple->Red.Y,
- triple->Green.x,
- triple->Green.y,
- triple->Green.Y,
- triple->Blue.x,
- triple->Blue.y,
- triple->Blue.Y);
- }
- static PyObject *
- _profile_read_named_color_list(CmsProfileObject *self, cmsTagSignature info) {
- cmsNAMEDCOLORLIST *ncl;
- int i, n;
- char name[cmsMAX_PATH];
- PyObject *result;
- if (!cmsIsTag(self->profile, info)) {
- Py_INCREF(Py_None);
- return Py_None;
- }
- ncl = (cmsNAMEDCOLORLIST *)cmsReadTag(self->profile, info);
- if (ncl == NULL) {
- Py_INCREF(Py_None);
- return Py_None;
- }
- n = cmsNamedColorCount(ncl);
- result = PyList_New(n);
- if (!result) {
- Py_INCREF(Py_None);
- return Py_None;
- }
- for (i = 0; i < n; i++) {
- PyObject *str;
- cmsNamedColorInfo(ncl, i, name, NULL, NULL, NULL, NULL);
- str = PyUnicode_FromString(name);
- if (str == NULL) {
- Py_DECREF(result);
- Py_INCREF(Py_None);
- return Py_None;
- }
- PyList_SET_ITEM(result, i, str);
- }
- return result;
- }
- static cmsBool
- _calculate_rgb_primaries(CmsProfileObject *self, cmsCIEXYZTRIPLE *result) {
- double input[3][3] = {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}};
- cmsHPROFILE hXYZ;
- cmsHTRANSFORM hTransform;
- /* https://littlecms2.blogspot.com/2009/07/less-is-more.html */
- // double array of RGB values with max on each identity
- hXYZ = cmsCreateXYZProfile();
- if (hXYZ == NULL) {
- return 0;
- }
- // transform from our profile to XYZ using doubles for highest precision
- hTransform = cmsCreateTransform(
- self->profile,
- TYPE_RGB_DBL,
- hXYZ,
- TYPE_XYZ_DBL,
- INTENT_RELATIVE_COLORIMETRIC,
- cmsFLAGS_NOCACHE | cmsFLAGS_NOOPTIMIZE);
- cmsCloseProfile(hXYZ);
- if (hTransform == NULL) {
- return 0;
- }
- cmsDoTransform(hTransform, (void *)input, result, 3);
- cmsDeleteTransform(hTransform);
- return 1;
- }
- static cmsBool
- _check_intent(
- int clut,
- cmsHPROFILE hProfile,
- cmsUInt32Number Intent,
- cmsUInt32Number UsedDirection) {
- if (clut) {
- return cmsIsCLUT(hProfile, Intent, UsedDirection);
- } else {
- return cmsIsIntentSupported(hProfile, Intent, UsedDirection);
- }
- }
- #define INTENTS 200
- static PyObject *
- _is_intent_supported(CmsProfileObject *self, int clut) {
- PyObject *result;
- int n;
- int i;
- cmsUInt32Number intent_ids[INTENTS];
- char *intent_descs[INTENTS];
- result = PyDict_New();
- if (result == NULL) {
- Py_INCREF(Py_None);
- return Py_None;
- }
- n = cmsGetSupportedIntents(INTENTS, intent_ids, intent_descs);
- for (i = 0; i < n; i++) {
- int intent = (int)intent_ids[i];
- PyObject *id;
- PyObject *entry;
- /* Only valid for ICC Intents (otherwise we read invalid memory in lcms
- * cmsio1.c). */
- if (!(intent == INTENT_PERCEPTUAL || intent == INTENT_RELATIVE_COLORIMETRIC ||
- intent == INTENT_SATURATION || intent == INTENT_ABSOLUTE_COLORIMETRIC)) {
- continue;
- }
- id = PyLong_FromLong((long)intent);
- entry = Py_BuildValue(
- "(OOO)",
- _check_intent(clut, self->profile, intent, LCMS_USED_AS_INPUT) ? Py_True
- : Py_False,
- _check_intent(clut, self->profile, intent, LCMS_USED_AS_OUTPUT) ? Py_True
- : Py_False,
- _check_intent(clut, self->profile, intent, LCMS_USED_AS_PROOF) ? Py_True
- : Py_False);
- if (id == NULL || entry == NULL) {
- Py_XDECREF(id);
- Py_XDECREF(entry);
- Py_XDECREF(result);
- Py_INCREF(Py_None);
- return Py_None;
- }
- PyDict_SetItem(result, id, entry);
- Py_DECREF(id);
- Py_DECREF(entry);
- }
- return result;
- }
- /* -------------------------------------------------------------------- */
- /* Python interface setup */
- static PyMethodDef pyCMSdll_methods[] = {
- {"profile_open", cms_profile_open, METH_VARARGS},
- {"profile_frombytes", cms_profile_frombytes, METH_VARARGS},
- {"profile_tobytes", cms_profile_tobytes, METH_VARARGS},
- /* profile and transform functions */
- {"buildTransform", buildTransform, METH_VARARGS},
- {"buildProofTransform", buildProofTransform, METH_VARARGS},
- {"createProfile", createProfile, METH_VARARGS},
- /* platform specific tools */
- #ifdef _WIN32
- {"get_display_profile_win32", cms_get_display_profile_win32, METH_VARARGS},
- #endif
- {NULL, NULL}};
- static struct PyMethodDef cms_profile_methods[] = {
- {"is_intent_supported", (PyCFunction)cms_profile_is_intent_supported, METH_VARARGS},
- {NULL, NULL} /* sentinel */
- };
- static PyObject *
- cms_profile_getattr_rendering_intent(CmsProfileObject *self, void *closure) {
- return PyLong_FromLong(cmsGetHeaderRenderingIntent(self->profile));
- }
- /* New-style unicode interfaces. */
- static PyObject *
- cms_profile_getattr_copyright(CmsProfileObject *self, void *closure) {
- return _profile_read_mlu(self, cmsSigCopyrightTag);
- }
- static PyObject *
- cms_profile_getattr_target(CmsProfileObject *self, void *closure) {
- return _profile_read_mlu(self, cmsSigCharTargetTag);
- }
- static PyObject *
- cms_profile_getattr_manufacturer(CmsProfileObject *self, void *closure) {
- return _profile_read_mlu(self, cmsSigDeviceMfgDescTag);
- }
- static PyObject *
- cms_profile_getattr_model(CmsProfileObject *self, void *closure) {
- return _profile_read_mlu(self, cmsSigDeviceModelDescTag);
- }
- static PyObject *
- cms_profile_getattr_profile_description(CmsProfileObject *self, void *closure) {
- return _profile_read_mlu(self, cmsSigProfileDescriptionTag);
- }
- static PyObject *
- cms_profile_getattr_screening_description(CmsProfileObject *self, void *closure) {
- return _profile_read_mlu(self, cmsSigScreeningDescTag);
- }
- static PyObject *
- cms_profile_getattr_viewing_condition(CmsProfileObject *self, void *closure) {
- return _profile_read_mlu(self, cmsSigViewingCondDescTag);
- }
- static PyObject *
- cms_profile_getattr_creation_date(CmsProfileObject *self, void *closure) {
- cmsBool result;
- struct tm ct;
- result = cmsGetHeaderCreationDateTime(self->profile, &ct);
- if (!result) {
- Py_INCREF(Py_None);
- return Py_None;
- }
- return PyDateTime_FromDateAndTime(
- 1900 + ct.tm_year, ct.tm_mon, ct.tm_mday, ct.tm_hour, ct.tm_min, ct.tm_sec, 0);
- }
- static PyObject *
- cms_profile_getattr_version(CmsProfileObject *self, void *closure) {
- cmsFloat64Number version = cmsGetProfileVersion(self->profile);
- return PyFloat_FromDouble(version);
- }
- static PyObject *
- cms_profile_getattr_icc_version(CmsProfileObject *self, void *closure) {
- return PyLong_FromLong((long)cmsGetEncodedICCversion(self->profile));
- }
- static PyObject *
- cms_profile_getattr_attributes(CmsProfileObject *self, void *closure) {
- cmsUInt64Number attr;
- cmsGetHeaderAttributes(self->profile, &attr);
- /* This works just as well on Windows (LLP64), 32-bit Linux
- (ILP32) and 64-bit Linux (LP64) systems. */
- return PyLong_FromUnsignedLongLong((unsigned long long)attr);
- }
- static PyObject *
- cms_profile_getattr_header_flags(CmsProfileObject *self, void *closure) {
- cmsUInt32Number flags = cmsGetHeaderFlags(self->profile);
- return PyLong_FromLong(flags);
- }
- static PyObject *
- cms_profile_getattr_header_manufacturer(CmsProfileObject *self, void *closure) {
- return _profile_read_int_as_string(cmsGetHeaderManufacturer(self->profile));
- }
- static PyObject *
- cms_profile_getattr_header_model(CmsProfileObject *self, void *closure) {
- return _profile_read_int_as_string(cmsGetHeaderModel(self->profile));
- }
- static PyObject *
- cms_profile_getattr_device_class(CmsProfileObject *self, void *closure) {
- return _profile_read_int_as_string(cmsGetDeviceClass(self->profile));
- }
- static PyObject *
- cms_profile_getattr_connection_space(CmsProfileObject *self, void *closure) {
- return _profile_read_int_as_string(cmsGetPCS(self->profile));
- }
- static PyObject *
- cms_profile_getattr_xcolor_space(CmsProfileObject *self, void *closure) {
- return _profile_read_int_as_string(cmsGetColorSpace(self->profile));
- }
- static PyObject *
- cms_profile_getattr_profile_id(CmsProfileObject *self, void *closure) {
- cmsUInt8Number id[16];
- cmsGetHeaderProfileID(self->profile, id);
- return PyBytes_FromStringAndSize((char *)id, 16);
- }
- static PyObject *
- cms_profile_getattr_is_matrix_shaper(CmsProfileObject *self, void *closure) {
- return PyBool_FromLong((long)cmsIsMatrixShaper(self->profile));
- }
- static PyObject *
- cms_profile_getattr_technology(CmsProfileObject *self, void *closure) {
- return _profile_read_signature(self, cmsSigTechnologyTag);
- }
- static PyObject *
- cms_profile_getattr_colorimetric_intent(CmsProfileObject *self, void *closure) {
- return _profile_read_signature(self, cmsSigColorimetricIntentImageStateTag);
- }
- static PyObject *
- cms_profile_getattr_perceptual_rendering_intent_gamut(
- CmsProfileObject *self, void *closure) {
- return _profile_read_signature(self, cmsSigPerceptualRenderingIntentGamutTag);
- }
- static PyObject *
- cms_profile_getattr_saturation_rendering_intent_gamut(
- CmsProfileObject *self, void *closure) {
- return _profile_read_signature(self, cmsSigSaturationRenderingIntentGamutTag);
- }
- static PyObject *
- cms_profile_getattr_red_colorant(CmsProfileObject *self, void *closure) {
- if (!cmsIsMatrixShaper(self->profile)) {
- Py_INCREF(Py_None);
- return Py_None;
- }
- return _profile_read_ciexyz(self, cmsSigRedColorantTag, 0);
- }
- static PyObject *
- cms_profile_getattr_green_colorant(CmsProfileObject *self, void *closure) {
- if (!cmsIsMatrixShaper(self->profile)) {
- Py_INCREF(Py_None);
- return Py_None;
- }
- return _profile_read_ciexyz(self, cmsSigGreenColorantTag, 0);
- }
- static PyObject *
- cms_profile_getattr_blue_colorant(CmsProfileObject *self, void *closure) {
- if (!cmsIsMatrixShaper(self->profile)) {
- Py_INCREF(Py_None);
- return Py_None;
- }
- return _profile_read_ciexyz(self, cmsSigBlueColorantTag, 0);
- }
- static PyObject *
- cms_profile_getattr_media_white_point_temperature(
- CmsProfileObject *self, void *closure) {
- cmsCIEXYZ *XYZ;
- cmsCIExyY xyY;
- cmsFloat64Number tempK;
- cmsTagSignature info = cmsSigMediaWhitePointTag;
- cmsBool result;
- if (!cmsIsTag(self->profile, info)) {
- Py_INCREF(Py_None);
- return Py_None;
- }
- XYZ = (cmsCIEXYZ *)cmsReadTag(self->profile, info);
- if (XYZ == NULL || XYZ->X == 0) {
- Py_INCREF(Py_None);
- return Py_None;
- }
- cmsXYZ2xyY(&xyY, XYZ);
- result = cmsTempFromWhitePoint(&tempK, &xyY);
- if (!result) {
- Py_INCREF(Py_None);
- return Py_None;
- }
- return PyFloat_FromDouble(tempK);
- }
- static PyObject *
- cms_profile_getattr_media_white_point(CmsProfileObject *self, void *closure) {
- return _profile_read_ciexyz(self, cmsSigMediaWhitePointTag, 0);
- }
- static PyObject *
- cms_profile_getattr_media_black_point(CmsProfileObject *self, void *closure) {
- return _profile_read_ciexyz(self, cmsSigMediaBlackPointTag, 0);
- }
- static PyObject *
- cms_profile_getattr_luminance(CmsProfileObject *self, void *closure) {
- return _profile_read_ciexyz(self, cmsSigLuminanceTag, 0);
- }
- static PyObject *
- cms_profile_getattr_chromatic_adaptation(CmsProfileObject *self, void *closure) {
- return _profile_read_ciexyz(self, cmsSigChromaticAdaptationTag, 1);
- }
- static PyObject *
- cms_profile_getattr_chromaticity(CmsProfileObject *self, void *closure) {
- return _profile_read_ciexyy_triple(self, cmsSigChromaticityTag);
- }
- static PyObject *
- cms_profile_getattr_red_primary(CmsProfileObject *self, void *closure) {
- cmsBool result = 0;
- cmsCIEXYZTRIPLE primaries;
- if (cmsIsMatrixShaper(self->profile)) {
- result = _calculate_rgb_primaries(self, &primaries);
- }
- if (!result) {
- Py_INCREF(Py_None);
- return Py_None;
- }
- return _xyz_py(&primaries.Red);
- }
- static PyObject *
- cms_profile_getattr_green_primary(CmsProfileObject *self, void *closure) {
- cmsBool result = 0;
- cmsCIEXYZTRIPLE primaries;
- if (cmsIsMatrixShaper(self->profile)) {
- result = _calculate_rgb_primaries(self, &primaries);
- }
- if (!result) {
- Py_INCREF(Py_None);
- return Py_None;
- }
- return _xyz_py(&primaries.Green);
- }
- static PyObject *
- cms_profile_getattr_blue_primary(CmsProfileObject *self, void *closure) {
- cmsBool result = 0;
- cmsCIEXYZTRIPLE primaries;
- if (cmsIsMatrixShaper(self->profile)) {
- result = _calculate_rgb_primaries(self, &primaries);
- }
- if (!result) {
- Py_INCREF(Py_None);
- return Py_None;
- }
- return _xyz_py(&primaries.Blue);
- }
- static PyObject *
- cms_profile_getattr_colorant_table(CmsProfileObject *self, void *closure) {
- return _profile_read_named_color_list(self, cmsSigColorantTableTag);
- }
- static PyObject *
- cms_profile_getattr_colorant_table_out(CmsProfileObject *self, void *closure) {
- return _profile_read_named_color_list(self, cmsSigColorantTableOutTag);
- }
- static PyObject *
- cms_profile_getattr_is_intent_supported(CmsProfileObject *self, void *closure) {
- return _is_intent_supported(self, 0);
- }
- static PyObject *
- cms_profile_getattr_is_clut(CmsProfileObject *self, void *closure) {
- return _is_intent_supported(self, 1);
- }
- static const char *
- _illu_map(int i) {
- switch (i) {
- case 0:
- return "unknown";
- case 1:
- return "D50";
- case 2:
- return "D65";
- case 3:
- return "D93";
- case 4:
- return "F2";
- case 5:
- return "D55";
- case 6:
- return "A";
- case 7:
- return "E";
- case 8:
- return "F8";
- default:
- return NULL;
- }
- }
- static PyObject *
- cms_profile_getattr_icc_measurement_condition(CmsProfileObject *self, void *closure) {
- cmsICCMeasurementConditions *mc;
- cmsTagSignature info = cmsSigMeasurementTag;
- const char *geo;
- if (!cmsIsTag(self->profile, info)) {
- Py_INCREF(Py_None);
- return Py_None;
- }
- mc = (cmsICCMeasurementConditions *)cmsReadTag(self->profile, info);
- if (!mc) {
- Py_INCREF(Py_None);
- return Py_None;
- }
- if (mc->Geometry == 1) {
- geo = "45/0, 0/45";
- } else if (mc->Geometry == 2) {
- geo = "0d, d/0";
- } else {
- geo = "unknown";
- }
- return Py_BuildValue(
- "{s:i,s:(ddd),s:s,s:d,s:s}",
- "observer",
- mc->Observer,
- "backing",
- mc->Backing.X,
- mc->Backing.Y,
- mc->Backing.Z,
- "geo",
- geo,
- "flare",
- mc->Flare,
- "illuminant_type",
- _illu_map(mc->IlluminantType));
- }
- static PyObject *
- cms_profile_getattr_icc_viewing_condition(CmsProfileObject *self, void *closure) {
- cmsICCViewingConditions *vc;
- cmsTagSignature info = cmsSigViewingConditionsTag;
- if (!cmsIsTag(self->profile, info)) {
- Py_INCREF(Py_None);
- return Py_None;
- }
- vc = (cmsICCViewingConditions *)cmsReadTag(self->profile, info);
- if (!vc) {
- Py_INCREF(Py_None);
- return Py_None;
- }
- return Py_BuildValue(
- "{s:(ddd),s:(ddd),s:s}",
- "illuminant",
- vc->IlluminantXYZ.X,
- vc->IlluminantXYZ.Y,
- vc->IlluminantXYZ.Z,
- "surround",
- vc->SurroundXYZ.X,
- vc->SurroundXYZ.Y,
- vc->SurroundXYZ.Z,
- "illuminant_type",
- _illu_map(vc->IlluminantType));
- }
- static struct PyGetSetDef cms_profile_getsetters[] = {
- /* New style interfaces. */
- {"rendering_intent", (getter)cms_profile_getattr_rendering_intent},
- {"creation_date", (getter)cms_profile_getattr_creation_date},
- {"copyright", (getter)cms_profile_getattr_copyright},
- {"target", (getter)cms_profile_getattr_target},
- {"manufacturer", (getter)cms_profile_getattr_manufacturer},
- {"model", (getter)cms_profile_getattr_model},
- {"profile_description", (getter)cms_profile_getattr_profile_description},
- {"screening_description", (getter)cms_profile_getattr_screening_description},
- {"viewing_condition", (getter)cms_profile_getattr_viewing_condition},
- {"version", (getter)cms_profile_getattr_version},
- {"icc_version", (getter)cms_profile_getattr_icc_version},
- {"attributes", (getter)cms_profile_getattr_attributes},
- {"header_flags", (getter)cms_profile_getattr_header_flags},
- {"header_manufacturer", (getter)cms_profile_getattr_header_manufacturer},
- {"header_model", (getter)cms_profile_getattr_header_model},
- {"device_class", (getter)cms_profile_getattr_device_class},
- {"connection_space", (getter)cms_profile_getattr_connection_space},
- {"xcolor_space", (getter)cms_profile_getattr_xcolor_space},
- {"profile_id", (getter)cms_profile_getattr_profile_id},
- {"is_matrix_shaper", (getter)cms_profile_getattr_is_matrix_shaper},
- {"technology", (getter)cms_profile_getattr_technology},
- {"colorimetric_intent", (getter)cms_profile_getattr_colorimetric_intent},
- {"perceptual_rendering_intent_gamut",
- (getter)cms_profile_getattr_perceptual_rendering_intent_gamut},
- {"saturation_rendering_intent_gamut",
- (getter)cms_profile_getattr_saturation_rendering_intent_gamut},
- {"red_colorant", (getter)cms_profile_getattr_red_colorant},
- {"green_colorant", (getter)cms_profile_getattr_green_colorant},
- {"blue_colorant", (getter)cms_profile_getattr_blue_colorant},
- {"red_primary", (getter)cms_profile_getattr_red_primary},
- {"green_primary", (getter)cms_profile_getattr_green_primary},
- {"blue_primary", (getter)cms_profile_getattr_blue_primary},
- {"media_white_point_temperature",
- (getter)cms_profile_getattr_media_white_point_temperature},
- {"media_white_point", (getter)cms_profile_getattr_media_white_point},
- {"media_black_point", (getter)cms_profile_getattr_media_black_point},
- {"luminance", (getter)cms_profile_getattr_luminance},
- {"chromatic_adaptation", (getter)cms_profile_getattr_chromatic_adaptation},
- {"chromaticity", (getter)cms_profile_getattr_chromaticity},
- {"colorant_table", (getter)cms_profile_getattr_colorant_table},
- {"colorant_table_out", (getter)cms_profile_getattr_colorant_table_out},
- {"intent_supported", (getter)cms_profile_getattr_is_intent_supported},
- {"clut", (getter)cms_profile_getattr_is_clut},
- {"icc_measurement_condition",
- (getter)cms_profile_getattr_icc_measurement_condition},
- {"icc_viewing_condition", (getter)cms_profile_getattr_icc_viewing_condition},
- {NULL}};
- static PyTypeObject CmsProfile_Type = {
- PyVarObject_HEAD_INIT(NULL, 0) "PIL._imagingcms.CmsProfile", /*tp_name*/
- sizeof(CmsProfileObject), /*tp_basicsize*/
- 0, /*tp_itemsize*/
- /* methods */
- (destructor)cms_profile_dealloc, /*tp_dealloc*/
- 0, /*tp_vectorcall_offset*/
- 0, /*tp_getattr*/
- 0, /*tp_setattr*/
- 0, /*tp_as_async*/
- 0, /*tp_repr*/
- 0, /*tp_as_number*/
- 0, /*tp_as_sequence*/
- 0, /*tp_as_mapping*/
- 0, /*tp_hash*/
- 0, /*tp_call*/
- 0, /*tp_str*/
- 0, /*tp_getattro*/
- 0, /*tp_setattro*/
- 0, /*tp_as_buffer*/
- Py_TPFLAGS_DEFAULT, /*tp_flags*/
- 0, /*tp_doc*/
- 0, /*tp_traverse*/
- 0, /*tp_clear*/
- 0, /*tp_richcompare*/
- 0, /*tp_weaklistoffset*/
- 0, /*tp_iter*/
- 0, /*tp_iternext*/
- cms_profile_methods, /*tp_methods*/
- 0, /*tp_members*/
- cms_profile_getsetters, /*tp_getset*/
- };
- static struct PyMethodDef cms_transform_methods[] = {
- {"apply", (PyCFunction)cms_transform_apply, 1}, {NULL, NULL} /* sentinel */
- };
- static PyObject *
- cms_transform_getattr_inputMode(CmsTransformObject *self, void *closure) {
- return PyUnicode_FromString(self->mode_in);
- }
- static PyObject *
- cms_transform_getattr_outputMode(CmsTransformObject *self, void *closure) {
- return PyUnicode_FromString(self->mode_out);
- }
- static struct PyGetSetDef cms_transform_getsetters[] = {
- {"inputMode", (getter)cms_transform_getattr_inputMode},
- {"outputMode", (getter)cms_transform_getattr_outputMode},
- {NULL}};
- static PyTypeObject CmsTransform_Type = {
- PyVarObject_HEAD_INIT(NULL, 0) "CmsTransform", /*tp_name*/
- sizeof(CmsTransformObject), /*tp_basicsize*/
- 0, /*tp_itemsize*/
- /* methods */
- (destructor)cms_transform_dealloc, /*tp_dealloc*/
- 0, /*tp_vectorcall_offset*/
- 0, /*tp_getattr*/
- 0, /*tp_setattr*/
- 0, /*tp_as_async*/
- 0, /*tp_repr*/
- 0, /*tp_as_number*/
- 0, /*tp_as_sequence*/
- 0, /*tp_as_mapping*/
- 0, /*tp_hash*/
- 0, /*tp_call*/
- 0, /*tp_str*/
- 0, /*tp_getattro*/
- 0, /*tp_setattro*/
- 0, /*tp_as_buffer*/
- Py_TPFLAGS_DEFAULT, /*tp_flags*/
- 0, /*tp_doc*/
- 0, /*tp_traverse*/
- 0, /*tp_clear*/
- 0, /*tp_richcompare*/
- 0, /*tp_weaklistoffset*/
- 0, /*tp_iter*/
- 0, /*tp_iternext*/
- cms_transform_methods, /*tp_methods*/
- 0, /*tp_members*/
- cms_transform_getsetters, /*tp_getset*/
- };
- static int
- setup_module(PyObject *m) {
- PyObject *d;
- PyObject *v;
- int vn;
- CmsProfile_Type.tp_new = PyType_GenericNew;
- /* Ready object types */
- PyType_Ready(&CmsProfile_Type);
- PyType_Ready(&CmsTransform_Type);
- Py_INCREF(&CmsProfile_Type);
- PyModule_AddObject(m, "CmsProfile", (PyObject *)&CmsProfile_Type);
- d = PyModule_GetDict(m);
- /* this check is also in PIL.features.pilinfo() */
- #if LCMS_VERSION < 2070
- vn = LCMS_VERSION;
- #else
- vn = cmsGetEncodedCMMversion();
- #endif
- if (vn % 10) {
- v = PyUnicode_FromFormat("%d.%d.%d", vn / 1000, (vn / 10) % 100, vn % 10);
- } else {
- v = PyUnicode_FromFormat("%d.%d", vn / 1000, (vn / 10) % 100);
- }
- PyDict_SetItemString(d, "littlecms_version", v ? v : Py_None);
- Py_XDECREF(v);
- return 0;
- }
- PyMODINIT_FUNC
- PyInit__imagingcms(void) {
- PyObject *m;
- static PyModuleDef module_def = {
- PyModuleDef_HEAD_INIT,
- "_imagingcms", /* m_name */
- NULL, /* m_doc */
- -1, /* m_size */
- pyCMSdll_methods, /* m_methods */
- };
- m = PyModule_Create(&module_def);
- if (setup_module(m) < 0) {
- return NULL;
- }
- PyDateTime_IMPORT;
- return m;
- }
|