3
* a Python / PIL interface to the littleCMS ICC Color Management System
4
* Copyright (C) 2002-2003 Kevin Cazabon
6
* http://www.cazabon.com
7
* Adapted/reworked for PIL by Fredrik Lundh
8
* Copyright (c) 2009 Fredrik Lundh
10
* pyCMS home page: http://www.cazabon.com/pyCMS
11
* littleCMS home page: http://www.littlecms.com
12
* (littleCMS is Copyright (C) 1998-2001 Marti Maria)
14
* Originally released under LGPL. Graciously donated to PIL in
15
* March 2009, for distribution under the standard PIL license
18
#define COPYRIGHTINFO "\
20
a Python / PIL interface to the littleCMS ICC Color Management System\n\
21
Copyright (C) 2002-2003 Kevin Cazabon\n\
23
http://www.cazabon.com\n\
30
#if PY_VERSION_HEX < 0x01060000
31
#define PyObject_New PyObject_NEW
32
#define PyObject_Del PyMem_DEL
35
#if LCMS_VERSION < 117
43
#define PYCMSVERSION "0.1.0 pil"
48
0.1.0 pil integration & refactoring
49
0.0.2 alpha: Minor updates, added interfaces to littleCMS features, Jan 6, 2003
50
- fixed some memory holes in how transforms/profiles were created and passed back to Python
51
due to improper destructor setup for PyCObjects
52
- added buildProofTransformFromOpenProfiles() function
53
- eliminated some code redundancy, centralizing several common tasks with internal functions
55
0.0.1 alpha: First public release Dec 26, 2002
59
/* known to-do list with current version:
61
Verify that PILmode->littleCMStype conversion in findLCMStype is correct for all PIL modes (it probably isn't for the more obscure ones)
63
Add support for creating custom RGB profiles on the fly
64
Add support for checking presence of a specific tag in a profile
65
Add support for other littleCMS features as required
71
INTENT_RELATIVE_COLORIMETRIC 1
73
INTENT_ABSOLUTE_COLORIMETRIC 3
76
/* -------------------------------------------------------------------- */
79
/* a profile represents the ICC characteristics for a specific device */
86
staticforward PyTypeObject CmsProfile_Type;
88
#define CmsProfile_Check(op) ((op)->ob_type == &CmsProfile_Type)
91
cms_profile_new(cmsHPROFILE profile)
93
CmsProfileObject* self;
95
self = PyObject_New(CmsProfileObject, &CmsProfile_Type);
99
self->profile = profile;
101
return (PyObject*) self;
105
cms_profile_open(PyObject* self, PyObject* args)
107
cmsHPROFILE hProfile;
110
if (!PyArg_ParseTuple(args, "s:profile_open", &sProfile))
113
cmsErrorAction(LCMS_ERROR_IGNORE);
115
hProfile = cmsOpenProfileFromFile(sProfile, "r");
117
PyErr_SetString(PyExc_IOError, "cannot open profile file");
121
return cms_profile_new(hProfile);
125
cms_profile_fromstring(PyObject* self, PyObject* args)
127
cmsHPROFILE hProfile;
131
if (!PyArg_ParseTuple(args, "s#:profile_fromstring", &pProfile, &nProfile))
134
cmsErrorAction(LCMS_ERROR_IGNORE);
136
hProfile = cmsOpenProfileFromMem(pProfile, nProfile);
138
PyErr_SetString(PyExc_IOError, "cannot open profile from string");
140
return cms_profile_new(hProfile);
144
cms_profile_dealloc(CmsProfileObject* self)
146
(void) cmsCloseProfile(self->profile);
150
/* a transform represents the mapping between two profiles */
156
cmsHTRANSFORM transform;
157
} CmsTransformObject;
159
staticforward PyTypeObject CmsTransform_Type;
161
#define CmsTransform_Check(op) ((op)->ob_type == &CmsTransform_Type)
164
cms_transform_new(cmsHTRANSFORM transform, char* mode_in, char* mode_out)
166
CmsTransformObject* self;
168
self = PyObject_New(CmsTransformObject, &CmsTransform_Type);
172
self->transform = transform;
174
strcpy(self->mode_in, mode_in);
175
strcpy(self->mode_out, mode_out);
177
return (PyObject*) self;
181
cms_transform_dealloc(CmsTransformObject* self)
183
cmsDeleteTransform(self->transform);
187
/* -------------------------------------------------------------------- */
188
/* internal functions */
191
findICmode(icColorSpaceSignature cs)
194
case icSigXYZData: return "XYZ";
195
case icSigLabData: return "LAB";
196
case icSigLuvData: return "LUV";
197
case icSigYCbCrData: return "YCbCr";
198
case icSigYxyData: return "YXY";
199
case icSigRgbData: return "RGB";
200
case icSigGrayData: return "L";
201
case icSigHsvData: return "HSV";
202
case icSigHlsData: return "HLS";
203
case icSigCmykData: return "CMYK";
204
case icSigCmyData: return "CMY";
205
default: return ""; /* other TBA */
210
findLCMStype(char* PILmode)
212
if (strcmp(PILmode, "RGB") == 0) {
215
else if (strcmp(PILmode, "RGBA") == 0) {
218
else if (strcmp(PILmode, "RGBX") == 0) {
221
else if (strcmp(PILmode, "RGBA;16B") == 0) {
224
else if (strcmp(PILmode, "CMYK") == 0) {
227
else if (strcmp(PILmode, "L") == 0) {
230
else if (strcmp(PILmode, "L;16") == 0) {
233
else if (strcmp(PILmode, "L;16B") == 0) {
234
return TYPE_GRAY_16_SE;
236
else if (strcmp(PILmode, "YCCA") == 0) {
239
else if (strcmp(PILmode, "YCC") == 0) {
244
/* take a wild guess... but you probably should fail instead. */
245
return TYPE_GRAY_8; /* so there's no buffer overrun... */
250
pyCMSdoTransform(Imaging im, Imaging imOut, cmsHTRANSFORM hTransform)
254
if (im->xsize > imOut->xsize || im->ysize > imOut->ysize)
257
Py_BEGIN_ALLOW_THREADS
259
for (i = 0; i < im->ysize; i++)
260
cmsDoTransform(hTransform, im->image[i], imOut->image[i], im->xsize);
268
_buildTransform(cmsHPROFILE hInputProfile, cmsHPROFILE hOutputProfile, char *sInMode, char *sOutMode, int iRenderingIntent, DWORD cmsFLAGS)
270
cmsHTRANSFORM hTransform;
272
cmsErrorAction(LCMS_ERROR_IGNORE);
274
Py_BEGIN_ALLOW_THREADS
276
/* create the transform */
277
hTransform = cmsCreateTransform(hInputProfile,
278
findLCMStype(sInMode),
280
findLCMStype(sOutMode),
281
iRenderingIntent, cmsFLAGS);
286
PyErr_SetString(PyExc_ValueError, "cannot build transform");
288
return hTransform; /* if NULL, an exception is set */
292
_buildProofTransform(cmsHPROFILE hInputProfile, cmsHPROFILE hOutputProfile, cmsHPROFILE hProofProfile, char *sInMode, char *sOutMode, int iRenderingIntent, int iProofIntent, DWORD cmsFLAGS)
294
cmsHTRANSFORM hTransform;
296
cmsErrorAction(LCMS_ERROR_IGNORE);
298
Py_BEGIN_ALLOW_THREADS
300
/* create the transform */
301
hTransform = cmsCreateProofingTransform(hInputProfile,
302
findLCMStype(sInMode),
304
findLCMStype(sOutMode),
313
PyErr_SetString(PyExc_ValueError, "cannot build proof transform");
315
return hTransform; /* if NULL, an exception is set */
318
/* -------------------------------------------------------------------- */
319
/* Python callable functions */
322
buildTransform(PyObject *self, PyObject *args) {
323
CmsProfileObject *pInputProfile;
324
CmsProfileObject *pOutputProfile;
327
int iRenderingIntent = 0;
330
cmsHTRANSFORM transform = NULL;
332
if (!PyArg_ParseTuple(args, "O!O!ss|ii:buildTransform", &CmsProfile_Type, &pInputProfile, &CmsProfile_Type, &pOutputProfile, &sInMode, &sOutMode, &iRenderingIntent, &cmsFLAGS))
335
cmsErrorAction(LCMS_ERROR_IGNORE);
337
transform = _buildTransform(pInputProfile->profile, pOutputProfile->profile, sInMode, sOutMode, iRenderingIntent, cmsFLAGS);
342
return cms_transform_new(transform, sInMode, sOutMode);
346
buildProofTransform(PyObject *self, PyObject *args)
348
CmsProfileObject *pInputProfile;
349
CmsProfileObject *pOutputProfile;
350
CmsProfileObject *pProofProfile;
353
int iRenderingIntent = 0;
354
int iProofIntent = 0;
357
cmsHTRANSFORM transform = NULL;
359
if (!PyArg_ParseTuple(args, "O!O!O!ss|iii:buildProofTransform", &CmsProfile_Type, &pInputProfile, &CmsProfile_Type, &pOutputProfile, &CmsProfile_Type, &pProofProfile, &sInMode, &sOutMode, &iRenderingIntent, &iProofIntent, &cmsFLAGS))
362
cmsErrorAction(LCMS_ERROR_IGNORE);
364
transform = _buildProofTransform(pInputProfile->profile, pOutputProfile->profile, pProofProfile->profile, sInMode, sOutMode, iRenderingIntent, iProofIntent, cmsFLAGS);
369
return cms_transform_new(transform, sInMode, sOutMode);
374
cms_transform_apply(CmsTransformObject *self, PyObject *args)
383
if (!PyArg_ParseTuple(args, "ll:apply", &idIn, &idOut))
387
imOut = (Imaging) idOut;
389
cmsErrorAction(LCMS_ERROR_IGNORE);
391
result = pyCMSdoTransform(im, imOut, self->transform);
393
return Py_BuildValue("i", result);
396
/* -------------------------------------------------------------------- */
397
/* Python-Callable On-The-Fly profile creation functions */
400
createProfile(PyObject *self, PyObject *args)
403
cmsHPROFILE hProfile;
405
LPcmsCIExyY whitePoint = NULL;
408
if (!PyArg_ParseTuple(args, "s|i:createProfile", &sColorSpace, &iColorTemp))
411
cmsErrorAction(LCMS_ERROR_IGNORE);
413
if (strcmp(sColorSpace, "LAB") == 0) {
414
if (iColorTemp > 0) {
415
result = cmsWhitePointFromTemp(iColorTemp, whitePoint);
417
PyErr_SetString(PyExc_ValueError, "ERROR: Could not calculate white point from color temperature provided, must be integer in degrees Kelvin");
420
hProfile = cmsCreateLabProfile(whitePoint);
422
hProfile = cmsCreateLabProfile(NULL);
424
else if (strcmp(sColorSpace, "XYZ") == 0)
425
hProfile = cmsCreateXYZProfile();
426
else if (strcmp(sColorSpace, "sRGB") == 0)
427
hProfile = cmsCreate_sRGBProfile();
432
PyErr_SetString(PyExc_ValueError, "failed to create requested color space");
436
return cms_profile_new(hProfile);
439
/* -------------------------------------------------------------------- */
440
/* profile methods */
443
cms_profile_is_intent_supported(CmsProfileObject *self, PyObject *args)
449
if (!PyArg_ParseTuple(args, "ii:is_intent_supported", &intent, &direction))
452
result = cmsIsIntentSupported(self->profile, intent, direction);
454
/* printf("cmsIsIntentSupported(%p, %d, %d) => %d\n", self->profile, intent, direction, result); */
456
return PyInt_FromLong(result != 0);
461
cms_get_display_profile_win32(PyObject* self, PyObject* args)
463
char filename[MAX_PATH];
469
if (!PyArg_ParseTuple(args, "|ii:get_display_profile", &handle, &is_dc))
472
filename_size = sizeof(filename);
475
ok = GetICMProfile((HDC) handle, &filename_size, filename);
477
HDC dc = GetDC((HWND) handle);
478
ok = GetICMProfile(dc, &filename_size, filename);
479
ReleaseDC((HWND) handle, dc);
483
return PyString_FromStringAndSize(filename, filename_size-1);
490
/* -------------------------------------------------------------------- */
491
/* Python interface setup */
493
static PyMethodDef pyCMSdll_methods[] = {
495
{"profile_open", cms_profile_open, 1},
496
{"profile_fromstring", cms_profile_fromstring, 1},
498
/* profile and transform functions */
499
{"buildTransform", buildTransform, 1},
500
{"buildProofTransform", buildProofTransform, 1},
501
{"createProfile", createProfile, 1},
503
/* platform specific tools */
505
{"get_display_profile_win32", cms_get_display_profile_win32, 1},
511
static struct PyMethodDef cms_profile_methods[] = {
512
{"is_intent_supported", (PyCFunction) cms_profile_is_intent_supported, 1},
513
{NULL, NULL} /* sentinel */
517
cms_profile_getattr(CmsProfileObject* self, char* name)
519
if (!strcmp(name, "product_name"))
520
return PyString_FromString(cmsTakeProductName(self->profile));
521
if (!strcmp(name, "product_desc"))
522
return PyString_FromString(cmsTakeProductDesc(self->profile));
523
if (!strcmp(name, "product_info"))
524
return PyString_FromString(cmsTakeProductInfo(self->profile));
525
if (!strcmp(name, "rendering_intent"))
526
return PyInt_FromLong(cmsTakeRenderingIntent(self->profile));
527
if (!strcmp(name, "pcs"))
528
return PyString_FromString(findICmode(cmsGetPCS(self->profile)));
529
if (!strcmp(name, "color_space"))
530
return PyString_FromString(findICmode(cmsGetColorSpace(self->profile)));
531
/* FIXME: add more properties (creation_datetime etc) */
533
return Py_FindMethod(cms_profile_methods, (PyObject*) self, name);
536
statichere PyTypeObject CmsProfile_Type = {
537
PyObject_HEAD_INIT(NULL)
538
0, "CmsProfile", sizeof(CmsProfileObject), 0,
540
(destructor) cms_profile_dealloc, /*tp_dealloc*/
542
(getattrfunc) cms_profile_getattr, /*tp_getattr*/
547
0, /*tp_as_sequence */
548
0, /*tp_as_mapping */
552
static struct PyMethodDef cms_transform_methods[] = {
553
{"apply", (PyCFunction) cms_transform_apply, 1},
554
{NULL, NULL} /* sentinel */
558
cms_transform_getattr(CmsTransformObject* self, char* name)
560
if (!strcmp(name, "inputMode"))
561
return PyString_FromString(self->mode_in);
562
if (!strcmp(name, "outputMode"))
563
return PyString_FromString(self->mode_out);
565
return Py_FindMethod(cms_transform_methods, (PyObject*) self, name);
568
statichere PyTypeObject CmsTransform_Type = {
569
PyObject_HEAD_INIT(NULL)
570
0, "CmsTransform", sizeof(CmsTransformObject), 0,
572
(destructor) cms_transform_dealloc, /*tp_dealloc*/
574
(getattrfunc) cms_transform_getattr, /*tp_getattr*/
579
0, /*tp_as_sequence */
580
0, /*tp_as_mapping */
585
init_imagingcms(void)
591
/* Patch up object types */
592
CmsProfile_Type.ob_type = &PyType_Type;
593
CmsTransform_Type.ob_type = &PyType_Type;
595
m = Py_InitModule("_imagingcms", pyCMSdll_methods);
596
d = PyModule_GetDict(m);
598
#if PY_VERSION_HEX >= 0x02020000
599
v = PyString_FromFormat("%d.%d", LCMS_VERSION / 100, LCMS_VERSION % 100);
603
sprintf(buffer, "%d.%d", LCMS_VERSION / 100, LCMS_VERSION % 100);
604
v = PyString_FromString(buffer);
607
PyDict_SetItemString(d, "littlecms_version", v);