Index: setup.py =================================================================== --- setup.py (.../trunk/sK1) (revision 560) +++ setup.py (.../branches/hackontest/sK1) (revision 560) @@ -188,6 +188,14 @@ libraries=['freetype'], extra_compile_args=["-Wall"]) + pycms_src=src_path+'extentions/pycms/' + pycms_module = Extension('sk1.app.modules.pyCMSdll', + define_macros = [('MAJOR_VERSION', '0'), + ('MINOR_VERSION', '1')], + sources = [pycms_src+'pyCMSdll.c'], + libraries=['lcms'], + extra_compile_args=["-Wall"]) + pax_src=src_path+'extentions/pax/' pax_include_dirs=['/usr/include/cairo'] pax_include_dirs.extend(tcl_include_dirs) @@ -294,7 +302,7 @@ ext_modules = [filter_module, type1mod_module, skread_module, pstokenize_module, skmod_module, paxtkinter_module, - pax_module, tkpng_module, ft2_module]) + pax_module, tkpng_module, ft2_module, pycms_module]) Index: src/app/plugins/Filters/sk1saver.py =================================================================== --- src/app/plugins/Filters/sk1saver.py (.../trunk/sK1) (revision 560) +++ src/app/plugins/Filters/sk1saver.py (.../branches/hackontest/sK1) (revision 560) @@ -537,7 +537,7 @@ from streamfilter import Base64Encode write('bm(%d)\n' % id(image)) file = Base64Encode(self.file) - image.image.save(file, 'PPM') + image.orig_image.save(file, 'IM') file.close() write('-\n') else: Index: src/app/managers/colormanager.py =================================================================== --- src/app/managers/colormanager.py (.../trunk/sK1) (revision 560) +++ src/app/managers/colormanager.py (.../branches/hackontest/sK1) (revision 560) @@ -19,6 +19,8 @@ import sys print "Cannot find Python binding for LittleCMS!" sys.exit(1) + +import pyCMS class ColorManager: rgb_monitor=None @@ -30,6 +32,7 @@ hCMYK=None hMONITOR=None colors_pool=[] + image_pool=[] def __init__(self): self.refresh_profiles() @@ -37,13 +40,23 @@ def add_to_pool(self,color): self.colors_pool.append(color) + def add_to_image_pool(self,image): + self.image_pool.append(image) + def remove_from_pool(self,color): self.colors_pool.remove(color) + def remove_from_image_pool(self,image): + self.image_pool.remove(image) + def update(self): for color in self.colors_pool: color.update() + + for image in self.image_pool: + image.update() + def refresh_profiles(self): if app.config.preferences.user_rgb_profile and os.path.isfile(app.config.preferences.user_rgb_profile): rgb_file=app.config.user_rgb_profile @@ -160,7 +173,15 @@ cmsCloseProfile(self.hRGB) cmsCloseProfile(self.hMONITOR) + def ImageRGBtoCMYK(self, image): + rgb_profile=os.path.join(app.config.sk_icc,app.config.preferences.default_rgb_profile) + cmyk_profile=os.path.join(app.config.sk_icc,app.config.preferences.default_cmyk_profile) + return pyCMS.profileToProfile(image, rgb_profile, cmyk_profile, outputMode = "CMYK") + def ImageCMYKtoRGB(self, image): + rgb_profile=os.path.join(app.config.sk_icc,app.config.preferences.default_rgb_profile) + cmyk_profile=os.path.join(app.config.sk_icc,app.config.preferences.default_cmyk_profile) + return pyCMS.profileToProfile(image, cmyk_profile, rgb_profile, outputMode = "RGB") @@ -169,5 +190,4 @@ - \ No newline at end of file Index: src/app/managers/pyCMS.py =================================================================== --- src/app/managers/pyCMS.py (.../trunk/sK1) (revision 0) +++ src/app/managers/pyCMS.py (.../branches/hackontest/sK1) (revision 560) @@ -0,0 +1,825 @@ +""" +pyCMS + + a Python / PIL interface to the littleCMS ICC Color Management System + Copyright (C) 2002-2003 Kevin Cazabon + kevin@cazabon.com + http://www.cazabon.com + + pyCMS home page: http://www.cazabon.com/pyCMS + littleCMS home page: http://www.littlecms.com + (littleCMS is Copyright (C) 1998-2001 Marti Maria) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + + The pyCMS.py module provides a "clean" interface between Python/PIL and + pyCMSdll, taking care of some of the more complex handling of the direct + pyCMSdll functions, as well as error-checking and making sure that all + relevant data is kept together. + + While it is possible to call pyCMSdll functions directly, it's not highly + recommended. + + + Version History: + 0.0.2 alpha Jan 6, 2002 + + Added try/except statements arount type() checks of + potential CObjects... Python won't let you use type() + on them, and raises a TypeError (stupid, if you ask me!) + + Added buildProofTransformFromOpenProfiles() function. + Additional fixes in DLL, see DLL code for details. + + 0.0.1 alpha first public release, Dec. 26, 2002 + + Known to-do list with current version (of Python interface, not pyCMSdll): + + none + +""" + +####################################################################### +# version +####################################################################### +VERSION = "0.0.2 alpha" + + +####################################################################### +# imports +####################################################################### +import pyCMSdll +import os +import Image + +####################################################################### +# constants +####################################################################### +TRUE = 1 +FALSE = None + +INTENT_PERCEPTUAL = 0 +INTENT_RELATIVE_COLORIMETRIC = 1 +INTENT_SATURATION = 2 +INTENT_ABSOLUTE_COLORIMETRIC = 3 + +DIRECTION_INPUT = 0 +DIRECTION_OUTPUT = 1 +DIRECTION_PROOF = 2 + +####################################################################### +# classes +####################################################################### +# classes are used for PyCMSTransform and PyCMSProfile so that data +# such as input and output mode can follow the object after creation, +# and be easily retrieved when needed. + +class PyCMSError(Exception): + pass + +class PyCMSTransform: + def __init__(self, transform = None, inputMode = None, outputMode = None): + self.transform = transform + self.inputMode = inputMode + self.outputMode = outputMode + +class PyCMSProfile: + def __init__(self, profile = None): + self.profile = profile + + +####################################################################### +# functions +####################################################################### +def versions (): + """ + pyCMS.versions() + + Returns a tuple of (pyCMSVersion, littleCMSVersion, pythonVersion, + PILVersion). + + However, don't trust these values 100%, because they're currently + configured manually in pyCMSdll.c before building the DLL. + """ + + return pyCMSdll.versions() + +def about (): + """ + pyCMS.about() + + Returns a string containing information about pyCMSdll.dll, including + copyright and license information. + """ + + return pyCMSdll.about() + +def copyright (): + """ + pyCMS.copyright() + + Returns a string containing information about pyCMSdll.dll, including + copyright and license information. + """ + + return pyCMSdll.copyright() + +def profileToProfile (im, inputProfile, outputProfile, renderingIntent = INTENT_PERCEPTUAL, outputMode = None, inPlace = FALSE): + """ + pyCMS.profileToProfile(im, inputProfile, outputProfile, + [renderingIntent], [outputMode], [inPlace]) + + Returns either None or a new PIL image object, depending on value of + inPlace (see below). + + im = an open PIL image object (i.e. Image.new(...) or + Image.open(...), etc.) + inputProfile = string, as a valid filename path to the ICC input + profile you wish to use for this image + outputProfile = string, as a valid filename path to the ICC output + profile you wish to use for this image + renderingIntent = integer (0-3) specifying the rendering intent you + wish to use for the transform + INTENT_PERCEPTUAL = 0 (DEFAULT) (pyCMS.INTENT_PERCEPTUAL) + INTENT_RELATIVE_COLORIMETRIC =1 (pyCMS.INTENT_RELATIVE_COLORIMETRIC) + INTENT_SATURATION = 2 (pyCMS.INTENT_SATURATION) + INTENT_ABSOLUTE_COLORIMETRIC =3 (pyCMS.INTENT_ABSOLUTE_COLORIMETRIC) + + see the pyCMS documentation for details on rendering intents and + what they do. + outputMode = a valid PIL mode for the output image (i.e. "RGB", "CMYK", + etc.). Note: if rendering the image "inPlace", outputMode MUST be + the same mode as the input, or omitted completely. If omitted, the + outputMode will be the same as the mode of the input image (im.mode) + inPlace = BOOL (1 = TRUE, None or 0 = FALSE). If TRUE, the original + image is modified in-place, and None is returned. If FALSE + (default), a new Image object is returned with the transform + applied. + + If the input or output profiles specified are not valid filenames, a + PyCMSError will be raised. If inPlace == TRUE and outputMode != im.mode, + a PyCMSError will be raised. If an error occurs during application of + the profiles, a PyCMSError will be raised. If outputMode is not a mode + supported by the outputProfile (or by pyCMS), a PyCMSError will be + raised. + + This function applies an ICC transformation to im from inputProfile's + color space to outputProfile's color space using the specified rendering + intent to decide how to handle out-of-gamut colors. + + OutputMode can be used to specify that a color mode conversion is to + be done using these profiles, but the specified profiles must be able + to handle that mode. I.e., if converting im from RGB to CMYK using + profiles, the input profile must handle RGB data, and the output + profile must handle CMYK data. + + """ + if not os.path.isfile(inputProfile): + raise PyCMSError, "Invalid input profile path provided: %s" %inputProfile + if not os.path.isfile(outputProfile): + raise PyCMSError, "Invalid output profile path provided: %s" %outputProfile + + if outputMode == None: + outputMode = im.mode + + if type(renderingIntent) != type(1) or not (0 <= renderingIntent <=3): + raise PyCMSError, "renderingIntent must be an integer between 0 and 3" + + if inPlace == TRUE and im.mode != outputMode: + raise PyCMSError, "Cannot transform image in place, im.mode and output mode are different (%s vs. %s)" %(im.mode, outputMode) + + if inPlace == TRUE: + imOut = im + else: + imOut = Image.new(outputMode, im.size) + + im.load() #make sure it's loaded, or it may not have a .im attribute! + + result = pyCMSdll.profileToProfile(im.im.id, imOut.im.id, inputProfile, outputProfile, renderingIntent) + + if result == 0: + if inPlace == TRUE: + return None + else: + return imOut + + elif result == -1: + raise PyCMSError, "Error occurred in pyCMSdll.profileToProfile()" + + else: + raise PyCMSError, result + +def getOpenProfile (profileFilename): + """ + pyCMS.getOpenProfile(profileFilename) + + Returns a PyCMSProfile class object. + + profileFilename = string, as a valid filename path to the ICC profile + you wish to open + + The PyCMSProfile object can be passed back into pyCMS for use in creating + transforms and such (as in pyCMS.buildTransformFromOpenProfiles()). + + If profileFilename is not a vaild filename for an ICC profile, a + PyCMSError will be raised. + + """ + if not os.path.isfile(profileFilename): + raise PyCMSError, "Invalid profile path provided: %s" %profileFilename + + result = pyCMSdll.getOpenProfile (profileFilename) + + try: + if type(result) == type("string"): + raise PyCMSError, result + except TypeError: + pass + + return PyCMSProfile(result) + +def buildTransform (inputProfile, outputProfile, inMode, outMode, renderingIntent = INTENT_PERCEPTUAL): + """ + pyCMS.buildTransform(inputProfile, outputProfile, inMode, outMode, + [renderingIntent]) + + Returns a PyCMSTransform class object. + + inputProfile = string, as a valid filename path to the ICC input + profile you wish to use for this transform + outputProfile = string, as a valid filename path to the ICC output + profile you wish to use for this transform + inMode = string, as a valid PIL mode that the appropriate profile also + supports (i.e. "RGB", "RGBA", "CMYK", etc.) + outMode = string, as a valid PIL mode that the appropriate profile also + supports (i.e. "RGB", "RGBA", "CMYK", etc.) + renderingIntent = integer (0-3) specifying the rendering intent you + wish to use for the transform + INTENT_PERCEPTUAL = 0 (DEFAULT) (pyCMS.INTENT_PERCEPTUAL) + INTENT_RELATIVE_COLORIMETRIC =1 (pyCMS.INTENT_RELATIVE_COLORIMETRIC) + INTENT_SATURATION = 2 (pyCMS.INTENT_SATURATION) + INTENT_ABSOLUTE_COLORIMETRIC =3 (pyCMS.INTENT_ABSOLUTE_COLORIMETRIC) + see the pyCMS documentation for details on rendering intents and + what they do. + + If the input or output profiles specified are not valid filenames, a + PyCMSError will be raised. If an error occurs during creation of the + transform, a PyCMSError will be raised. + + If inMode or outMode are not a mode supported by the outputProfile (or + by pyCMS), a PyCMSError will be raised. + + This function builds and returns an ICC transform from the inputProfile + to the outputProfile using the renderingIntent to determine what to do + with out-of-gamut colors. It will ONLY work for converting images that + are in inMode to images that are in outMode color format (PIL mode, + i.e. "RGB", "RGBA", "CMYK", etc.). + + Building the transform is a fair part of the overhead in + pyCMS.profileToProfile(), so if you're planning on converting multiple + images using the same input/output settings, this can save you time. + Once you have a transform object, it can be used with + pyCMS.applyProfile() to convert images without the need to re-compute + the lookup table for the transform. + + The reason pyCMS returns a class object rather than a handle directly + to the transform is that it needs to keep track of the PIL input/output + modes that the transform is meant for. These attributes are stored in + the "inMode" and "outMode" attributes of the object (which can be + manually overridden if you really want to, but I don't know of any + time that would be of use, or would even work). + + """ + if not os.path.isfile(inputProfile): + raise PyCMSError, "Invalid input profile path provided: %s" %inputProfile + if not os.path.isfile(outputProfile): + raise PyCMSError, "Invalid output profile path provided: %s" %outputProfile + + if type(renderingIntent) != type(1) or not (0 <= renderingIntent <=3): + raise PyCMSError, "renderingIntent must be an integer between 0 and 3" + + result = pyCMSdll.buildTransform (inputProfile, outputProfile, inMode, outMode, renderingIntent) + + try: + if type(result) == type("string"): + raise PyCMSError, result + except TypeError: + pass + + return PyCMSTransform(result, inMode, outMode) + +def buildProofTransform (inputProfile, outputProfile, displayProfile, inMode, outMode, renderingIntent = INTENT_PERCEPTUAL, displayRenderingIntent = INTENT_PERCEPTUAL): + """ + pyCMS.buildProofTransform(inputProfile, outputProfile, displayProfile, + inMode, outMode, [renderingIntent], [displayRenderingIntent]) + + Returns a PyCMSTransform class object. + + inputProfile = string, as a valid filename path to the ICC input + profile you wish to use for this transform + outputProfile = string, as a valid filename path to the ICC output + profile you wish to use for this transform + displayProfile = string, as a valid filename path to the ICC display + (monitor, usually) profile you wish to use for this transform + inMode = string, as a valid PIL mode that the appropriate profile also + supports (i.e. "RGB", "RGBA", "CMYK", etc.) + outMode = string, as a valid PIL mode that the appropriate profile also + supports (i.e. "RGB", "RGBA", "CMYK", etc.) + renderingIntent = integer (0-3) specifying the rendering intent you + wish to use for the input->output (simulated) transform + INTENT_PERCEPTUAL = 0 (DEFAULT) (pyCMS.INTENT_PERCEPTUAL) + INTENT_RELATIVE_COLORIMETRIC =1 (pyCMS.INTENT_RELATIVE_COLORIMETRIC) + INTENT_SATURATION = 2 (pyCMS.INTENT_SATURATION) + INTENT_ABSOLUTE_COLORIMETRIC =3 (pyCMS.INTENT_ABSOLUTE_COLORIMETRIC) + see the pyCMS documentation for details on rendering intents and + what they do. + displayRenderingIntent = integer (0-3) specifying the rendering intent + you wish to use for (input/output simulation)->display transform + INTENT_PERCEPTUAL = 0 (DEFAULT) (pyCMS.INTENT_PERCEPTUAL) + INTENT_RELATIVE_COLORIMETRIC =1 (pyCMS.INTENT_RELATIVE_COLORIMETRIC) + INTENT_SATURATION = 2 (pyCMS.INTENT_SATURATION) + INTENT_ABSOLUTE_COLORIMETRIC =3 (pyCMS.INTENT_ABSOLUTE_COLORIMETRIC) + see the pyCMS documentation for details on rendering intents and + what they do. + + If the input, output, or display profiles specified are not valid + filenames, a PyCMSError will be raised. + + If an error occurs during creation of the transform, a PyCMSError will + be raised. + + If inMode or outMode are not a mode supported by the outputProfile + (or by pyCMS), a PyCMSError will be raised. + + This function builds and returns an ICC transform from the inputProfile + to the displayProfile, but tries to simulate the result that would be + obtained on the outputProfile device using renderingIntent and + displayRenderingIntent to determine what to do with out-of-gamut + colors. This is known as "soft-proofing". It will ONLY work for + converting images that are in inMode to images that are in outMode + color format (PIL mode, i.e. "RGB", "RGBA", "CMYK", etc.). + + Usage of the resulting transform object is exactly the same as with + pyCMS.buildTransform(). + + Proof profiling is generally used when using a "proof" device to get a + good idea of what the final printed/displayed image would look like on + the outputProfile device when it's quicker and easier to use the + display device for judging color. Generally, this means that + displayDevice is a monitor, or a dye-sub printer (etc.), and the output + device is something more expensive, complicated, or time consuming + (making it difficult to make a real print for color judgement purposes). + + Soft-proofing basically functions by limiting the color gamut on the + display device to the gamut availabile on the output device. However, + when the final output device has a much wider gamut than the display + device, you may obtain marginal results. + + """ + if not os.path.isfile(inputProfile): + raise PyCMSError, "Invalid input profile path provided: %s" %inputProfile + if not os.path.isfile(outputProfile): + raise PyCMSError, "Invalid output profile path provided: %s" %outputProfile + if not os.path.isfile(displayProfile): + raise PyCMSError, "Invalid display profile path provided: %s" %displayProfile + + if type(renderingIntent) != type(1) or not (0 <= renderingIntent <=3): + raise PyCMSError, "renderingIntent must be an integer between 0 and 3" + + result = pyCMSdll.buildProofTransform (inputProfile, outputProfile, displayProfile, inMode, outMode, renderingIntent, displayRenderingIntent) + + try: + if type(result) == type("string"): + raise PyCMSError, result + except TypeError: + pass + + return PyCMSTransform(result, inMode, outMode) + +def buildTransformFromOpenProfiles (inputProfile, outputProfile, inMode, outMode, renderingIntent = INTENT_PERCEPTUAL): + """ + pyCMS.buildTransformFromOpenProfiles(inputProfile, outputProfile, + inMode, outMode, [renderingIntent]) + + Returns a PyCMSTransform class object + + inputProfile = a valid PyCMSProfile class object + outputProfile = a valid PyCMSProfile class object + inMode = string, as a valid PIL mode that the appropriate profile also + supports (i.e. "RGB", "RGBA", "CMYK", etc.) + outMode = string, as a valid PIL mode that the appropriate profile also + supports (i.e. "RGB", "RGBA", "CMYK", etc.) + renderingIntent = integer (0-3) specifying the rendering intent you + wish to use for the transform + INTENT_PERCEPTUAL = 0 (DEFAULT) (pyCMS.INTENT_PERCEPTUAL) + INTENT_RELATIVE_COLORIMETRIC =1 (pyCMS.INTENT_RELATIVE_COLORIMETRIC) + INTENT_SATURATION = 2 (pyCMS.INTENT_SATURATION) + INTENT_ABSOLUTE_COLORIMETRIC =3 (pyCMS.INTENT_ABSOLUTE_COLORIMETRIC) + see the pyCMS documentation for details on rendering intents and + what they do. + + This function operates exactly the same as pyCMS.buildTransform() + except that the inputProfile and outputProfile arguments must be valid + PyCMSProfile objects rather than filenames. Use this function to + create pre-calculated transforms from open PyCMSProfiles (such as + profiles created on-the-fly using pyCMS.createProfile(), or [in the + future] profiles extracted from image files. + + """ + + if type(renderingIntent) != type(1) or not (0 <= renderingIntent <=3): + raise PyCMSError, "renderingIntent must be an integer between 0 and 3" + + result = pyCMSdll.buildTransformFromOpenProfiles (inputProfile.profile, outputProfile.profile, inMode, outMode, renderingIntent) + + try: + if type(result) == type("string"): + raise PyCMSError, result + except TypeError: + pass + + return PyCMSTransform(result, inMode, outMode) + +def buildProofTransformFromOpenProfiles (inputProfile, outputProfile, displayProfile, inMode, outMode, renderingIntent = INTENT_PERCEPTUAL, displayRenderingIntent = INTENT_PERCEPTUAL): + """ + pyCMS.buildProofTransformFromOpenProfiles(inputProfile, outputProfile, + displayProfile, inMode, outMode, [renderingIntent], + [displayRenderingIntent]) + + Returns a PyCMSTransform class object + + inputProfile = a valid PyCMSProfile class object + outputProfile = a valid PyCMSProfile class object + displayProfile = a valid PyCMSProfile class object + inMode = string, as a valid PIL mode that the appropriate profile also + supports (i.e. "RGB", "RGBA", "CMYK", etc.) + outMode = string, as a valid PIL mode that the appropriate profile also + supports (i.e. "RGB", "RGBA", "CMYK", etc.) + renderingIntent = integer (0-3) specifying the rendering intent you + wish to use for the transform + INTENT_PERCEPTUAL = 0 (DEFAULT) (pyCMS.INTENT_PERCEPTUAL) + INTENT_RELATIVE_COLORIMETRIC =1 (pyCMS.INTENT_RELATIVE_COLORIMETRIC) + INTENT_SATURATION = 2 (pyCMS.INTENT_SATURATION) + INTENT_ABSOLUTE_COLORIMETRIC =3 (pyCMS.INTENT_ABSOLUTE_COLORIMETRIC) + see the pyCMS documentation for details on rendering intents and + what they do. + displayRenderingIntent = integer (0-3) specifying the rendering intent you + wish to use for the transform + INTENT_PERCEPTUAL = 0 (DEFAULT) (pyCMS.INTENT_PERCEPTUAL) + INTENT_RELATIVE_COLORIMETRIC =1 (pyCMS.INTENT_RELATIVE_COLORIMETRIC) + INTENT_SATURATION = 2 (pyCMS.INTENT_SATURATION) + INTENT_ABSOLUTE_COLORIMETRIC =3 (pyCMS.INTENT_ABSOLUTE_COLORIMETRIC) + see the pyCMS documentation for details on rendering intents and + what they do. + This function operates exactly the same as pyCMS.buildProofTransform() + except that the profile arguments must be valid + PyCMSProfile objects rather than filenames. Use this function to + create pre-calculated proof transforms from open PyCMSProfiles (such as + profiles created on-the-fly using pyCMS.createProfile(), or [in the + future] profiles extracted from image files. + + """ + + if type(renderingIntent) != type(1) or not (0 <= renderingIntent <=3) or type(displayRenderingIntent) != type(1) or not (0 <= displayRenderingIntent <=3): + raise PyCMSError, "renderingIntent must be an integer between 0 and 3" + + result = pyCMSdll.buildProofTransformFromOpenProfiles (inputProfile.profile, outputProfile.profile, displayProfile.profile, inMode, outMode, renderingIntent, displayRenderingIntent) + + try: + if type(result) == type("string"): + raise PyCMSError, result + + except TypeError: + pass + + return PyCMSTransform(result, inMode, outMode) + +def applyTransform (im, transform, inPlace = FALSE): + """ + pyCMS.applyTransform(im, transform, [inPlace]) + + Returns either None, or a new PIL Image object, depending on the value + of inPlace (see below) + + im = a PIL Image object, and im.mode must be the same as the inMode + supported by the transform. + transform = a valid PyCMSTransform class object + inPlace = BOOL (1 == TRUE, 0 or None == FALSE). If TRUE, im is + modified in place and None is returned, if FALSE, a new Image + object with the transform applied is returned (and im is not + changed). The default is FALSE. + + If im.mode != transform.inMode, a PyCMSError is raised. + + If inPlace == TRUE and transform.inMode != transform.outMode, a + PyCMSError is raised. + + If im.mode, transfer.inMode, or transfer.outMode is not supported by + pyCMSdll or the profiles you used for the transform, a PyCMSError is + raised. + + If an error occurs while the transform is being applied, a PyCMSError + is raised. + + This function applies a pre-calculated transform (from + pyCMS.buildTransform() or pyCMS.buildTransformFromOpenProfiles()) to an + image. The transform can be used for multiple images, saving + considerable calcuation time if doing the same conversion multiple times. + + If you want to modify im in-place instead of receiving a new image as + the return value, set inPlace to TRUE. This can only be done if + transform.inMode and transform.outMode are the same, because we can't + change the mode in-place (the buffer sizes for some modes are + different). The default behavior is to return a new Image object of + the same dimensions in mode transform.outMode. + + """ + if im.mode != transform.inputMode: + raise PyCMSError, "Image mode does not match profile input mode (%s vs %s)" %(im.mode, transform.inMode) + + if inPlace == TRUE: + if transform.inputMode != transform.outputMode: + raise PyCMSError, "Cannot transform image in place, input mode and output mode are different (%s vs. %s)" %(transform.inMode, transform.outMode) + imOut = im + else: + imOut = Image.new(transform.outputMode, im.size) + + im.load() #make sure it's loaded, or it may not have an .im attribute! + + result = pyCMSdll.applyTransform (im.im.id, imOut.im.id, transform.transform) + + if result == 0: + if inPlace == TRUE: + return None + else: + return imOut + + elif result == -1: + raise PyCMSError, "Error occurred in pyCMSdll.applyTransform()" + + else: + raise PyCMSError, result + +def createProfile (colorSpace, colorTemp = -1): + """ + pyCMS.createProfile(colorSpace, [colorTemp]) + + Returns a PyCMSProfile class object + + colorSpace = string, the color space of the profile you wish to create. + Currently only "LAB", "XYZ", and "sRGB" are supported. + colorTemp = positive integer for the white point for the profile, in + degrees Kelvin (i.e. 5000, 6500, 9600, etc.). The default is for + D50 illuminant if omitted (5000k). colorTemp is ONLY applied to + LAB profiles, and is ignored for XYZ and sRGB. + + If colorSpace not in ["LAB", "XYZ", "sRGB"], a PyCMSError is raised + + If using LAB and colorTemp != a positive integer, a PyCMSError is raised. + + If an error occurs while creating the profile, a PyCMSError is raised. + + Use this function to create common profiles on-the-fly instead of + having to supply a profile on disk and knowing the path to it. It + returns a normal PyCMSProfile object that can be passed to + pyCMS.buildTransformFromOpenProfiles() to create a transform to apply + to images. + + """ + if colorSpace not in ["LAB", "XYZ", "sRGB"]: + raise PyCMSError, "Color space not supported for on-the-fly profile creation (%s)" %colorSpace + + if colorSpace == "LAB": + if type(colorTemp) == type(5000.0): + colorTemp = int(colorTemp + 0.5) + if type (colorTemp) != type (5000): + raise PyCMSError, "Color temperature must be a positive integer, \"%s\" not valid" %colorTemp + + result = pyCMSdll.createProfile (colorSpace, colorTemp) + + try: + if type(result) == type("string"): + raise PyCMSError, result + + else: + return PyCMSProfile(result) + except TypeError: + # you can't use type() on a PyCObject... argh! + return PyCMSProfile(result) + +def getProfileName (profile): + """ + pyCMS.getProfileName(profile) + + Returns a string containing the internal name of the profile as stored + in an ICC tag. + + profile = EITHER a valid PyCMSProfile object, OR a string of the + filename of an ICC profile. + + If profile isn't a valid PyCMSProfile object or filename to a profile, + a PyCMSError is raised If an error occurs while trying to obtain the + name tag, a PyCMSError is raised. + + Use this function to obtain the INTERNAL name of the profile (stored + in an ICC tag in the profile itself), usually the one used when the + profile was originally created. Sometimes this tag also contains + additional information supplied by the creator. + + """ + try: + if type(profile) != type("string"): + profile = profile.profile + elif (not os.path.isfile(profile)): + raise PyCMSError, "Invalid profile path provided: %s" %profile + + except TypeError: + # you can't use type() on a PyCObject... argh! + profile = profile.profile + + result = pyCMSdll.getProfileName(profile) + + if len(result) > 7 and result[:7] == "ERROR: ": + raise PyCMSError, result + + else: + return result + +def getProfileInfo (profile): + """ + pyCMS.getProfileInfo(profile) + + Returns a string containing the internal profile information stored in + an ICC tag. + + profile = EITHER a valid PyCMSProfile object, OR a string of the + filename of an ICC profile. + + If profile isn't a valid PyCMSProfile object or filename to a profile, + a PyCMSError is raised. + + If an error occurs while trying to obtain the info tag, a PyCMSError + is raised + + Use this function to obtain the information stored in the profile's + info tag. This often contains details about the profile, and how it + was created, as supplied by the creator. + + """ + try: + if type(profile) != type("string"): + profile = profile.profile + elif (not os.path.isfile(profile)): + raise PyCMSError, "Invalid profile path provided: %s" %profile + + except TypeError: + # you can't use type() on a PyCObject... argh! + profile = profile.profile + + result = pyCMSdll.getProfileInfo(profile) + + if len(result) > 7 and result[:7] == "ERROR: ": + raise PyCMSError, result + + else: + return result + +def getDefaultIntent (profile): + """ + pyCMS.getDefaultIntent(profile) + + Returns integer 0-3 specifying the default rendering intent for this + profile. + INTENT_PERCEPTUAL = 0 (DEFAULT) (pyCMS.INTENT_PERCEPTUAL) + INTENT_RELATIVE_COLORIMETRIC =1 (pyCMS.INTENT_RELATIVE_COLORIMETRIC) + INTENT_SATURATION = 2 (pyCMS.INTENT_SATURATION) + INTENT_ABSOLUTE_COLORIMETRIC =3 (pyCMS.INTENT_ABSOLUTE_COLORIMETRIC) + see the pyCMS documentation for details on rendering intents and + what they do. + + profile = EITHER a valid PyCMSProfile object, OR a string of the + filename of an ICC profile. + + If profile isn't a valid PyCMSProfile object or filename to a profile, + a PyCMSError is raised. + + If an error occurs while trying to obtain the default intent, a + PyCMSError is raised. + + Use this function to determine the default (and usually best optomized) + rendering intent for this profile. Most profiles support multiple + rendering intents, but are intended mostly for one type of conversion. + If you wish to use a different intent than returned, use + pyCMS.isIntentSupported() to verify it will work first. + """ + try: + if type(profile) != type("string"): + profile = profile.profile + elif (not os.path.isfile(profile)): + raise PyCMSError, "Invalid profile path provided: %s" %profile + + except TypeError: + # you can't use type() on a PyCObject... argh! + profile = profile.profile + + result = pyCMSdll.getDefaultIntent(profile) + + try: + if type(result) == type("string"): + raise PyCMSError, result + else: + return result + + except TypeError: + # you can't use type() on a PyCObject... argh! + return result + +def isIntentSupported (profile, intent, direction): + """ + pyCMS.isIntentSupported(profile, intent, direction) + + Returns 1 if the intent/direction are supported, -1 if they are not. + + profile = EITHER a valid PyCMSProfile object, OR a string of the + filename of an ICC profile. + intent = integer (0-3) specifying the rendering intent you wish to use + with this profile + INTENT_PERCEPTUAL = 0 (DEFAULT) (pyCMS.INTENT_PERCEPTUAL) + INTENT_RELATIVE_COLORIMETRIC =1 (pyCMS.INTENT_RELATIVE_COLORIMETRIC) + INTENT_SATURATION = 2 (pyCMS.INTENT_SATURATION) + INTENT_ABSOLUTE_COLORIMETRIC =3 (pyCMS.INTENT_ABSOLUTE_COLORIMETRIC) + see the pyCMS documentation for details on rendering intents and + what they do. + direction = integer specifing if the profile is to be used for input, + output, or display/proof + INPUT = 0 (or use pyCMS.DIRECTION_INPUT) + OUTPUT = 1 (or use pyCMS.DIRECTION_OUTPUT) + PROOF (or display) = 2 (or use pyCMS.DIRECTION_PROOF) + + Use this function to verify that you can use your desired + renderingIntent with profile, and that profile can be used for the + input/output/display profile as you desire. + + Some profiles are created specifically for one "direction", can cannot + be used for others. Some profiles can only be used for certain + rendering intents... so it's best to either verify this before trying + to create a transform with them (using this function), or catch the + potential PyCMSError that will occur if they don't support the modes + you select. + + """ + try: + if type(profile) != type("string"): + profile = profile.profile + elif (not os.path.isfile(profile)): + raise PyCMSError, "Invalid profile path provided: %s" %profile + + except TypeError: + # you can't use type() on a PyCObject... argh! + profile = profile.profile + + result = pyCMSdll.isIntentSupported(profile, intent, direction) + + try: + if type(result) == type("string"): + raise PyCMSError, result + + else: + return result + + except TypeError: + # you can't use type() on a PyCObject... argh! + return result + +if __name__ == "__main__": + # create a cheap manual from the __doc__ strings for the functions above + + import pyCMS + import string + print __doc__ + + for f in dir(pyCMS): + print "="*80 + print "%s" %f + + try: + exec ("doc = pyCMS.%s.__doc__" %(f)) + if string.find(doc, "pyCMS") >= 0: + # so we don't get the __doc__ string for imported modules + print doc + except AttributeError: + pass + \ No newline at end of file Index: src/app/Graphics/document.py =================================================================== --- src/app/Graphics/document.py (.../trunk/sK1) (revision 560) +++ src/app/Graphics/document.py (.../branches/hackontest/sK1) (revision 560) @@ -1973,18 +1973,19 @@ return self.selection.GetObjectMethod(aclass, method) def CurrentObjectCompatible(self, aclass): - obj = self.CurrentObject() + obj = self.CurrentObject() if obj is not None: if aclass.is_Editor: - return isinstance(obj, aclass.EditedClass) + return obj.__class__.__name__== aclass.EditedClass.__name__ else: - return isinstance(obj, aclass) + return obj.__class__.__name__== aclass.__name__ return 0 # XXX the following methods for blend groups, path text, clones and # bezier objects should perhaps be implemented in their respective # modules (and then somehow grafted onto the document class?) + def CanBlend(self): info = self.selection.GetInfo() if len(info) == 2: @@ -2210,8 +2211,79 @@ self.abort_transaction() finally: self.end_transaction() + # + # IMAGES MANAGMENT + # + +############ + def CanBeRGB(self): + from image import RGB_IMAGE, RGBA_IMAGE + obj = self.CurrentObject() + if obj: + if obj.is_Image: + if obj.data.image_mode==RGB_IMAGE or obj.data.image_mode==RGBA_IMAGE: + return 0 + else: + return 1 + return 0 + def CanBeCMYK(self): + from image import CMYK_IMAGE + obj = self.CurrentObject() + if obj: + if obj.is_Image and not obj.data.image_mode==CMYK_IMAGE: + return 1 + return 0 + def CanBeGrayscale(self): + from image import GRAYSCALE_IMAGE + obj = self.CurrentObject() + if obj: + if obj.is_Image and not obj.data.image_mode==GRAYSCALE_IMAGE: + return 1 + return 0 + + def CanBeBW(self): + from image import BW_IMAGE + obj = self.CurrentObject() + if obj: + if obj.is_Image and not obj.data.image_mode==BW_IMAGE: + return 1 + return 0 + + def ConvertImage(self, mode): + obj = self.CurrentObject() + self.CallObjectMethod(obj.__class__, _("Convert Image"), 'Convert', mode) +# obj.Convert(mode) + self.SelectNone() + self.SelectObject(obj) + + def CanEmbed(self): + obj = self.CurrentObject() + if obj: + if obj.is_Image and obj.CanEmbed(): + return obj.CanEmbed() + return 0 + + def Embed(self): + obj = self.CurrentObject() + obj.Embed() + self.SelectNone() + self.SelectObject(obj) + + def CanInvert(self): + obj = self.CurrentObject() + if obj: + if obj.is_Image and obj.IsEmbedded(): + return 1 + return 0 + + def Invert(self): + obj = self.CurrentObject() + self.CallObjectMethod(obj.__class__, _("Invert Image"), 'InvertImage') + app.mw.canvas.ForceRedraw() + + # # PAGES MANAGMENT # Index: src/app/Graphics/color.py =================================================================== --- src/app/Graphics/color.py (.../trunk/sK1) (revision 560) +++ src/app/Graphics/color.py (.../branches/hackontest/sK1) (revision 560) @@ -98,7 +98,6 @@ def __del__(self): if colormanager is not None: colormanager.remove_from_pool(self) - print "REMOVED" def getScreenColor(self): pass Index: src/app/Graphics/image.py =================================================================== --- src/app/Graphics/image.py (.../trunk/sK1) (revision 560) +++ src/app/Graphics/image.py (.../branches/hackontest/sK1) (revision 560) @@ -21,41 +21,85 @@ # memory. # -import os +import os, app from types import StringType import PIL.Image, PIL.ImageChops -from app import _, RegisterCommands +from app import _, RegisterCommands, colormanager from app.UI.command import AddCmd from external import ExternalData, get_cached, ExternalGraphics +RGB_IMAGE=_('RGB') +RGBA_IMAGE=_('RGBA') +GRAYSCALE_IMAGE=_('Greyscale') +CMYK_IMAGE=_('CMYK') +BW_IMAGE=_('Monochrome') +UNSUPPORTED=_('UNSUPPORTED') + class ImageData(ExternalData): attributes = {'mode':0, 'size':0, 'im':0, 'info':0} + cached =0 + + def __init__(self, image, filename = '', cache = 1): + self.orig_image=image.copy() - def __init__(self, image, filename = '', cache = 1): - # convert image to mode 'L' or 'RGB' if necessary - if image.mode not in ('RGB', 'RGBA', 'L'): - if image.mode == '1': - mode = 'L' - else: - mode = 'RGB' - image = image.convert(mode) + if image.mode=='1': + self.image_mode=BW_IMAGE + elif image.mode=='L': + self.image_mode=GRAYSCALE_IMAGE + elif image.mode=='RGB': + self.image_mode=RGB_IMAGE + elif image.mode=='RGBA': + self.image_mode=RGBA_IMAGE + elif image.mode=='CMYK': + self.image_mode=CMYK_IMAGE + colormanager.add_to_image_pool(self) + self.cached=1 else: + self.image_mode=UNSUPPORTED + + if image.mode not in ('RGB', 'RGBA'): + if image.mode=='CMYK': + if app.config.preferences.use_cms: + self.image=colormanager.ImageCMYKtoRGB(image) + else: + self.image = image.convert('RGB') + else: + self.image = image.convert('RGB') + else: image.load() - self.image = image + self.image = image + + if self.image_mode==UNSUPPORTED: + self.orig_image=self.image.copy() + self.image_mode=RGB_IMAGE + ExternalData.__init__(self, filename, cache) + + def __del__(self): + if self.cached and colormanager is not None: + colormanager.remove_from_image_pool(self) def __getattr__(self, attr): if self.attributes.has_key(attr): return getattr(self.image, attr) raise AttributeError, attr + + def update(self): + if app.config.preferences.use_cms: + if self.image_mode==CMYK_IMAGE: + self.image=colormanager.ImageCMYKtoRGB(self.orig_image) + else: + self.image = self.orig_image.convert('RGB') + else: + self.image = self.orig_image.convert('RGB') def AsEmbedded(self): if self.filename: - return ImageData(self.image) + return ImageData(self.orig_image) else: return self @@ -66,16 +110,23 @@ return self.size def Image(self): - return self.image + print 'Image provided' + return self.orig_image def Convert(self, mode): - if mode != self.image.mode: - return ImageData(self.image.convert(mode)) + if mode != self.orig_image.mode: + if app.config.preferences.use_cms: + if mode=='RGB'and self.orig_image.mode=='CMYK': + return ImageData(colormanager.ImageCMYKtoRGB(self.orig_image)) + if mode=='CMYK'and self.orig_image.mode=='RGB': + return ImageData(colormanager.ImageRGBtoCMYK(self.orig_image)) + else: + return ImageData(self.orig_image.convert(mode)) else: return self def Invert(self): - return ImageData(PIL.ImageChops.invert(self.image)) + return ImageData(PIL.ImageChops.invert(self.orig_image)) @@ -96,30 +147,25 @@ commands = ExternalGraphics.commands[:] - def __init__(self, image = None, imagefile = '', trafo = None, - duplicate = None): + def __init__(self, image = None, imagefile = '', trafo = None, duplicate = None): if duplicate is None: if not image: if not imagefile: raise ValueError, 'Image must be instantiated with'\ ' either image or imagefile' image = load_image(imagefile) - ExternalGraphics.__init__(self, image, trafo, - duplicate = duplicate) + ExternalGraphics.__init__(self, image, trafo, duplicate = duplicate) + self.Embed() def DrawShape(self, device, rect = None, clip = 0): device.DrawImage(self.data, self.trafo, clip) def Info(self): + mode=self.data.image_mode width, height = self.data.Size() x, y = self.trafo.offset() - if self.IsEmbedded(): - return _("Embedded Image %(width)d x %(height)d " - "at (%(x)d, %(y)d)") % locals() - else: - filename = os.path.basename(self.data.Filename()) - return _("Linked Image `%(filename)s' %(width)d x %(height)d " - "at (%(x)d, %(y)d)") % locals() + return _("Embedded %(mode)s image %(width)d x %(height)d " + "at (%(x)d, %(y)d)") % locals() def SaveToFile(self, file): file.Image(self.data, self.trafo) @@ -132,20 +178,28 @@ def Embed(self): return self.SetData(self.data.AsEmbedded()) - AddCmd(commands, 'EmbedImage', _("Embed Image"), Embed, - sensitive_cb = 'CanEmbed') + + def InvertImage(self): + return self.SetData(self.data.Invert()) + + def Convert(self, image_mode): + undo = (self.SetData, self.data) + if image_mode==RGB_IMAGE: + self.SetData(self.data.Convert('RGB')) + if image_mode==RGBA_IMAGE: + self.SetData(self.data.Convert('RGB')) + if image_mode==GRAYSCALE_IMAGE: + self.SetData(self.data.Convert('L')) + if image_mode==CMYK_IMAGE: + self.SetData(self.data.Convert('CMYK')) + if image_mode==BW_IMAGE: + self.SetData(self.data.Convert('1')) + return undo def CallImageFunction(self, function, args = ()): if type(args) != type(()): args = (args,) data = apply(getattr(self.data, function), args) return self.SetData(data) - AddCmd(commands, 'GrayscaleImage', _("Grayscale Image"), - CallImageFunction, args = ('Convert', 'L')) - AddCmd(commands, 'InvertImage', _("Invert Image"), CallImageFunction, - args = 'Invert') - context_commands = ('EmbedImage', 'GrayscaleImage', 'InvertImage') -RegisterCommands(Image) - Index: src/app/UI/pluginpanels/find_replace_plugin.py =================================================================== --- src/app/UI/pluginpanels/find_replace_plugin.py (.../trunk/sK1) (revision 0) +++ src/app/UI/pluginpanels/find_replace_plugin.py (.../branches/hackontest/sK1) (revision 560) @@ -0,0 +1,143 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2008 by Darya Shumilina +# +# This library is covered by GNU Library General Public License. +# For more info see COPYRIGHTS file in sK1 root directory. + +import re + +from ppanel import PluginPanel + +from app import _ +import app +from app.Graphics import document, text + +from Ttk import LabelFrame, TFrame, TLabel, TCheckbutton, TButton +from app.UI.ttk_ext import TEntryExt +from Tkinter import RIGHT, BOTTOM, BOTH, TOP, X, E, W, Y, LEFT, StringVar, BooleanVar, DISABLED, NORMAL + +from app.UI.lengthvar import create_length_entry + +class FindReplacePanel(PluginPanel): + name='Find and Replace' + title = _("Find and Replace") + + def init(self, master): + PluginPanel.init(self, master) + top = self.panel + + top = TFrame(top, borderwidth=2, style='FlatFrame') + top.pack(side = TOP, expand = 1, fill = X) + + button_frame = TFrame(top, borderwidth=2, style='FlatFrame') + button_frame.pack(side = BOTTOM, fill = BOTH, expand = 1) + + button=TButton(button_frame,text=_('Apply'), command=self.replace) + button.pack(side = TOP) + + #---------------------------------------------------------- + main_frame = TFrame(top, style='FlatFrame', borderwidth=3) + main_frame.pack(side = TOP, fill=X) + + self.find_var = StringVar(top); + self.find_var.set('') + findField = TEntryExt(main_frame, textvariable=self.find_var) + findField.pack(side = RIGHT) + + label = TLabel(main_frame, style='FlatLabel', text = _("Find: ")) + label.pack(side = RIGHT, anchor = E) + #--------------------------------------------------------- + main_frame = TFrame(top, style='FlatFrame', borderwidth=3) + main_frame.pack(side = TOP, fill=X) + + + self.replace_var = StringVar(top); + self.replace_var.set('') + replaceField = TEntryExt(main_frame, textvariable=self.replace_var) + replaceField.pack(side = RIGHT) + + label = TLabel(main_frame, style='FlatLabel', text = _("Replace to: ")) + label.pack(side = RIGHT, anchor = E) + + main_frame = TFrame(top, style='FlatFrame', borderwidth=3) + main_frame.pack(side = TOP) + #--------------------------------------------------------- + parametersFrameLabel=LabelFrame(top, text=' Parameters ', borderwidth=2, relief='groove', pady=4, padx=4) + + parametersFrameLabel.pack(side = TOP, fill=X, pady=4, padx=2) + + parametersFrame = TFrame(parametersFrameLabel, style='FlatFrame') + + self.var_case_sensitive = BooleanVar(top) + self.case_sensitive_check = TCheckbutton(parametersFrame, text = _("Case sensitive"), variable = self.var_case_sensitive) + self.case_sensitive_check.pack(side = TOP, anchor=W, padx=5) + + self.var_whole_word = BooleanVar(top) + self.whole_word_check = TCheckbutton(parametersFrame, text = _("Whole word"), variable = self.var_whole_word) + self.whole_word_check.pack(side = TOP, anchor=W, padx=5) + + self.var_regexp = BooleanVar(top) + self.regexpCheck = TCheckbutton(parametersFrame, text = _("RegExp search"), variable = self.var_regexp, command=self.disable_enable_action) + self.regexpCheck.pack(side = TOP, anchor=W, padx=5) + + parametersFrame.pack(side=TOP, fill=X, pady=2) +################################################################ + def replace_text(self,objects, toReplace, replaceTo): + for object in objects: + if object.is_Text: + + if self.var_regexp.get(): + p=re.compile(toReplace) + text=p.sub(replaceTo, object.text) + app.mw.document.SelectObject(object) + app.mw.document.CallObjectMethod(object.__class__,_('Text Replace'),'SetText',text) + continue + + if self.var_whole_word.get(): + if not self.var_case_sensitive.get(): + if object.text.lower()==toReplace.lower(): + text=replaceTo + app.mw.document.SelectObject(object) + app.mw.document.CallObjectMethod(object.__class__,_('Text Replace'),'SetText',text) + else: + if object.text==toReplace: + text=replaceTo + app.mw.document.SelectObject(object) + app.mw.document.CallObjectMethod(object.__class__,_('Text Replace'),'SetText',text) + + else: + if object.text.lower().find(toReplace.lower(), 0, len(object.text)) != -1: + if not self.var_case_sensitive.get(): + text=object.text.lower().replace(toReplace.lower(), replaceTo) + else: + text=object.text.replace(toReplace, replaceTo) + app.mw.document.SelectObject(object) + app.mw.document.CallObjectMethod(object.__class__,_('Text Replace'),'SetText',text) + + if object.is_Group: + self.replace_text(object.objects) +################################################################ + def replace(self): + textObjects=[] + textToReplace=self.find_var.get().decode('utf-8') + replaceTo=self.replace_var.get().decode('utf-8') + + for layer in app.mw.document.layers: + self.replace_text(layer.objects, textToReplace, replaceTo) + app.mw.canvas.ForceRedraw() +################################################################ + def disable_enable_action(self): + if self.case_sensitive_check['state'] != DISABLED and self.whole_word_check['state'] != DISABLED: + self.case_sensitive_check['state'] = DISABLED + self.whole_word_check['state'] = DISABLED + else: + self.case_sensitive_check['state'] = NORMAL + self.whole_word_check['state'] = NORMAL +################################################################ + def whole_word_action(self): + pass +################################################################ + +instance=FindReplacePanel() +app.extentions_plugins.append(instance) Index: src/app/UI/pluginpanels/__init__.py =================================================================== --- src/app/UI/pluginpanels/__init__.py (.../trunk/sK1) (revision 560) +++ src/app/UI/pluginpanels/__init__.py (.../branches/hackontest/sK1) (revision 560) @@ -1,3 +1,4 @@ import align_plugin import grid_plugin, guidelines_plugin -import resize_plugin, move_plugin, rotate_plugin \ No newline at end of file +import resize_plugin, move_plugin, rotate_plugin +import find_replace_plugin \ No newline at end of file Index: src/app/UI/pluginpanels/ppanel.py =================================================================== --- src/app/UI/pluginpanels/ppanel.py (.../trunk/sK1) (revision 560) +++ src/app/UI/pluginpanels/ppanel.py (.../branches/hackontest/sK1) (revision 560) @@ -87,26 +87,11 @@ return self.document.HasSelection() def subscribe_receivers(self): - for info in self.receivers: - apply(self.document.Subscribe, - (info[0], getattr(self, info[1])) + info[2:]) + pass def unsubscribe_receivers(self): - for info in self.receivers: - apply(self.document.Unsubscribe, - (info[0], getattr(self, info[1])) + info[2:]) - + pass - def subscribe_receivers(self): - for info in self.receivers: - apply(self.document.Subscribe, - (info[0], getattr(self, info[1])) + info[2:]) - - def unsubscribe_receivers(self): - for info in self.receivers: - apply(self.document.Unsubscribe, - (info[0], getattr(self, info[1])) + info[2:]) - def SetDocument(self, doc): if self.document: self.unsubscribe_receivers() Index: src/app/UI/canvas.py =================================================================== --- src/app/UI/canvas.py (.../trunk/sK1) (revision 560) +++ src/app/UI/canvas.py (.../branches/hackontest/sK1) (revision 560) @@ -304,8 +304,8 @@ if self.context_menu_items[-1] != None: # insert a separator if necessary self.context_menu_items.append(None) - self.context_menu_items = self.context_menu_items \ - + list(aclass.context_commands) +# self.context_menu_items = self.context_menu_items \ +# + list(aclass.context_commands) self.commands = cmds self.object_keymap = None @@ -720,7 +720,6 @@ x, y, button, state) if self.context_commands is None: self.build_context_commands() - items = [] last = None for cmd in self.context_commands: Index: src/app/UI/command.py =================================================================== --- src/app/UI/command.py (.../trunk/sK1) (revision 560) +++ src/app/UI/command.py (.../branches/hackontest/sK1) (revision 560) @@ -72,7 +72,6 @@ return changed def get_sensitive(self): - #print 'get_sensitive', self if self.sensitive_cb: method = self.get_method(self.sensitive_cb) if method: Index: src/app/UI/context/image_panel.py =================================================================== --- src/app/UI/context/image_panel.py (.../trunk/sK1) (revision 0) +++ src/app/UI/context/image_panel.py (.../branches/hackontest/sK1) (revision 560) @@ -0,0 +1,53 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2008 by Igor E. Novikov +# +# This library is covered by GNU Library General Public License. +# For more info see COPYRIGHTS file in sK1 root directory. + + +from app.UI.tkext import ToolbarButton +from app.conf.const import CHANGED +from Tkinter import LEFT, DoubleVar, StringVar, RIGHT +from subpanel import CtxSubPanel +from app import _, config, PolyBezier, CreatePath, Point +import tooltips +from app.UI.lengthvar import LengthVar +from app.conf.const import SELECTION + +class ImagePanel(CtxSubPanel): + + name='ImagePanel' + + def __init__(self, parent): + CtxSubPanel.__init__(self, parent) + self.builded=0 + self.doc.Subscribe(SELECTION, self.update) + + def build_dlg(self): + if not self.builded: + cmds = self.mw.commands + + b = ToolbarButton(self.panel, command=cmds.Convert_to_CMYK, style='Toolbutton', image='context_image_cmyk') + tooltips.AddDescription(b, _('Convert to CMYK')) + b.pack(side = LEFT) + + b = ToolbarButton(self.panel, command=cmds.Convert_to_RGB, style='Toolbutton', image='context_image_rgb') + tooltips.AddDescription(b, _('Convert to RGB')) + b.pack(side = LEFT) + + b = ToolbarButton(self.panel, command=cmds.Convert_to_Grayscale, style='Toolbutton', image='context_image_gray') + tooltips.AddDescription(b, _('Convert to Grayscale')) + b.pack(side = LEFT) + + b = ToolbarButton(self.panel, command=cmds.Convert_to_BW, style='Toolbutton', image='context_image_bw') + tooltips.AddDescription(b, _('Convert to B&W')) + b.pack(side = LEFT) + + self.builded=1 + + def update(self,*arg): + if not self.mw.canvas is None: + self.build_dlg() + + Index: src/app/UI/context/ctxPanel.py =================================================================== --- src/app/UI/context/ctxPanel.py (.../trunk/sK1) (revision 560) +++ src/app/UI/context/ctxPanel.py (.../branches/hackontest/sK1) (revision 560) @@ -16,6 +16,7 @@ from unit_panel import UnitPanel from jump_panel import JumpPanel from page_panel import PagePanel +from image_panel import ImagePanel from group_panel import GroupPanel, CombinePanel, ToCurvePanel from text_prop_panel import TextPropPanel from textalign_panel import TextAlignPanel @@ -40,6 +41,7 @@ forSimpleText=['TextPropPanel','FontPanel','TextAlignPanel','ToCurvePanel'] forGroup=['ResizePanel','UnitPanel','FlipPanel', 'RotatePanel', 'GroupPanel', 'CombinePanel', 'ToCurvePanel'] forNodes=['ResizePanel','UnitPanel', 'CombinePanel','NodeEditPanel'] +forImage=['ResizePanel','UnitPanel','FlipPanel', 'RotatePanel', 'ImagePanel'] class ContexPanel(Publisher): @@ -100,6 +102,8 @@ self.changeContent(forGroup) elif obj_type==SIMPLE_TEXT: self.changeContent(forSimpleText) + elif obj_type==IMAGE: + self.changeContent(forImage) else: self.changeContent(forObject) else: @@ -109,6 +113,8 @@ self.changeContent(forSimpleText) elif obj_type==BEZIER: self.changeContent(forNodes) + elif obj_type==IMAGE: + self.changeContent(forImage) else: self.changeContent(forObject) else: @@ -134,4 +140,4 @@ PanelList=[PagePanel, ResizePanel, GuidesPanel, RotatePanel, JumpPanel, TextPropPanel, TextAlignPanel, FlipPanel, UnitPanel, GroupPanel, - FontPanel,CombinePanel, ToCurvePanel, NodeEditPanel] \ No newline at end of file + FontPanel,CombinePanel, ToCurvePanel, NodeEditPanel, ImagePanel] \ No newline at end of file Index: src/app/UI/tkext.py =================================================================== --- src/app/UI/tkext.py (.../trunk/sK1) (revision 560) +++ src/app/UI/tkext.py (.../branches/hackontest/sK1) (revision 560) @@ -196,7 +196,7 @@ # self['image']=self.image # else: # self['image']='menu_icon_mask' - AutoUpdate.SetSensitive(self, on) + AutoUpdate.SetSensitive(self, on) def clean_up(self): Index: src/app/UI/mainwindow.py =================================================================== --- src/app/UI/mainwindow.py (.../trunk/sK1) (revision 560) +++ src/app/UI/mainwindow.py (.../branches/hackontest/sK1) (revision 560) @@ -39,6 +39,7 @@ UpdatedTButton import tkext from context import ctxPanel +from app.Graphics.image import RGB_IMAGE, RGBA_IMAGE, GRAYSCALE_IMAGE, CMYK_IMAGE,BW_IMAGE from command import CommandClass, Keymap, Commands from math import floor, ceil @@ -885,7 +886,17 @@ AddDocCmd('FillNone', _("No Fill"), 'AddStyle', args = EmptyFillStyle) AddDocCmd('LineNone', _("No Line"), 'AddStyle', args = EmptyLineStyle) AddDocCmd('UpdateStyle', _("Update Style"), 'UpdateDynamicStyleSel') + + + AddDocCmd('Convert_to_CMYK', _("Convert to CMYK"), 'ConvertImage', args = CMYK_IMAGE, sensitive_cb ='CanBeCMYK') + AddDocCmd('Convert_to_RGB', _("Convert to RGB"), 'ConvertImage', args = RGB_IMAGE, sensitive_cb ='CanBeRGB') + AddDocCmd('Convert_to_Grayscale', _("Convert to Grayscale"), 'ConvertImage', args = GRAYSCALE_IMAGE, sensitive_cb ='CanBeGrayscale') + AddDocCmd('Convert_to_BW', _("Convert to B&W"), 'ConvertImage', args = BW_IMAGE, sensitive_cb ='CanBeBW') + + AddDocCmd('Invert', _("Invert Image"), 'Invert', sensitive_cb ='CanInvert') + AddDocCmd('Embed', _("Embed Image"), 'Embed', sensitive_cb ='CanEmbed') + ################### Menu build ############################ def build_menu(self): mbar = self.mbar @@ -895,6 +906,7 @@ AppendMenu(mbar, _("Layout"), self.make_layout_menu(), 0) AppendMenu(mbar, _("Arrange"), self.make_arrange_menu(), 0) AppendMenu(mbar, _("Effects"), self.make_effects_menu(), 4) + AppendMenu(mbar, _("Bitmaps"), self.make_bitmaps_menu(), 0) # AppendMenu(mbar, _("Curve"), self.make_curve_menu(), 1) AppendMenu(mbar, _("Style"), self.make_style_menu(), 1) # AppendMenu(mbar, _("Script"), self.make_script_menu(), 0) @@ -1099,6 +1111,18 @@ None, self.commands.ConvertToCurve]) + def make_bitmaps_menu(self): + cmds = self.commands + return map(MakeCommand, + [cmds.Convert_to_CMYK, + cmds.Convert_to_RGB, + cmds.Convert_to_Grayscale, + cmds.Convert_to_BW, + None, + cmds.Invert, + None, + cmds.Embed]) + def make_style_menu(self): return map(MakeCommand, [self.commands.FillNone, @@ -1453,7 +1477,7 @@ is_eps = eps.IsEpsFileStart(file.read(256)) file.close() dir, name = os.path.split(filename) - config.preferences.image_dir = dir + config.preferences.dir_for_bitmap_import = dir if is_eps: imageobj = eps.EpsImage(filename = sysfilename) else: Index: src/extentions/pycms/ImPlatform.h =================================================================== --- src/extentions/pycms/ImPlatform.h (.../trunk/sK1) (revision 0) +++ src/extentions/pycms/ImPlatform.h (.../branches/hackontest/sK1) (revision 560) @@ -0,0 +1,72 @@ +/* + * The Python Imaging Library + * $Id: ImPlatform.h 2134 2004-10-06 08:55:20Z fredrik $ + * + * platform declarations for the imaging core library + * + * Copyright (c) Fredrik Lundh 1995-2003. + */ + +#include "Python.h" + +/* Check that we have an ANSI compliant compiler */ +#ifndef HAVE_PROTOTYPES +#error Sorry, this library requires support for ANSI prototypes. +#endif +#ifndef STDC_HEADERS +#error Sorry, this library requires ANSI header files. +#endif + +#if defined(_MSC_VER) +#ifndef WIN32 +#define WIN32 +#endif +/* VC++ 4.0 is a bit annoying when it comes to precision issues (like + claiming that "float a = 0.0;" would lead to loss of precision). I + don't like to see warnings from my code, but since I still want to + keep it readable, I simply switch off a few warnings instead of adding + the tons of casts that VC++ seem to require. This code is compiled + with numerous other compilers as well, so any real errors are likely + to be catched anyway. */ +#pragma warning(disable: 4244) /* conversion from 'float' to 'int' */ +#endif + +#if defined(_MSC_VER) +#define inline __inline +#elif !defined(USE_INLINE) +#define inline +#endif + +#if SIZEOF_SHORT == 2 +#define INT16 short +#elif SIZEOF_INT == 2 +#define INT16 int +#else +#define INT16 short /* most things works just fine anyway... */ +#endif + +#if SIZEOF_SHORT == 4 +#define INT32 short +#elif SIZEOF_INT == 4 +#define INT32 int +#elif SIZEOF_LONG == 4 +#define INT32 long +#else +#error Cannot find required 32-bit integer type +#endif + +#if SIZEOF_LONG == 8 +#define INT64 long +#elif SIZEOF_LONG_LONG == 8 +#define INT64 long +#endif + +/* assume IEEE; tweak if necessary (patches are welcome) */ +#define FLOAT32 float +#define FLOAT64 double + +#define INT8 signed char +#define UINT8 unsigned char + +#define UINT16 unsigned INT16 +#define UINT32 unsigned INT32 Property changes on: src/extentions/pycms/ImPlatform.h ___________________________________________________________________ Name: svn:eol-style + native Index: src/extentions/pycms/Imaging.h =================================================================== --- src/extentions/pycms/Imaging.h (.../trunk/sK1) (revision 0) +++ src/extentions/pycms/Imaging.h (.../branches/hackontest/sK1) (revision 560) @@ -0,0 +1,493 @@ +/* + * The Python Imaging Library + * $Id: Imaging.h 2308 2005-03-02 12:00:55Z fredrik $ + * + * declarations for the imaging core library + * + * Copyright (c) 1997-2003 by Secret Labs AB + * Copyright (c) 1995-2003 by Fredrik Lundh + * + * See the README file for information on usage and redistribution. + */ + + +#include "ImPlatform.h" + + +#if defined(__cplusplus) +extern "C" { +#endif + + +#ifndef M_PI +#define M_PI 3.14159265359 +#endif + + +/* -------------------------------------------------------------------- */ + +/* + * Image data organization: + * + * mode bytes byte order + * ------------------------------- + * 1 1 1 + * L 1 L + * P 1 P + * I 4 I (32-bit integer, native byte order) + * F 4 F (32-bit IEEE float, native byte order) + * RGB 4 R, G, B, - + * RGBA 4 R, G, B, A + * CMYK 4 C, M, Y, K + * YCbCr 4 Y, Cb, Cr, - + * + * experimental modes (incomplete): + * LA 4 L, -, -, A + * PA 4 P, -, -, A + * I;16 2 I (16-bit integer, native byte order) + * + * "P" is an 8-bit palette mode, which should be mapped through the + * palette member to get an output image. Check palette->mode to + * find the corresponding "real" mode. + * + * For information on how to access Imaging objects from your own C + * extensions, see http://www.effbot.org/zone/pil-extending.htm + */ + +/* Handles */ + +typedef struct ImagingMemoryInstance* Imaging; +typedef struct ImagingAccessInstance* ImagingAccess; +typedef struct ImagingHistogramInstance* ImagingHistogram; +typedef struct ImagingOutlineInstance* ImagingOutline; +typedef struct ImagingPaletteInstance* ImagingPalette; + +/* handle magics (used with PyCObject). */ +#define IMAGING_MAGIC "PIL Imaging" +#define IMAGING_ACCESS_MAGIC "PIL ImagingAccess" + +/* pixel types */ +#define IMAGING_TYPE_UINT8 0 +#define IMAGING_TYPE_INT32 1 +#define IMAGING_TYPE_FLOAT32 2 +#define IMAGING_TYPE_SPECIAL 3 /* check mode for details */ + +struct ImagingMemoryInstance { + + /* Format */ + char mode[4+1]; /* Band names ("1", "L", "P", "RGB", "RGBA", "CMYK") */ + int type; /* Data type (IMAGING_TYPE_*) */ + int depth; /* Depth (ignored in this version) */ + int bands; /* Number of bands (1, 2, 3, or 4) */ + int xsize; /* Image dimension. */ + int ysize; + + /* Colour palette (for "P" images only) */ + ImagingPalette palette; + + /* Data pointers */ + UINT8 **image8; /* Set for 8-bit images (pixelsize=1). */ + INT32 **image32; /* Set for 32-bit images (pixelsize=4). */ + + /* Internals */ + char **image; /* Actual raster data. */ + char *block; /* Set if data is allocated in a single block. */ + + int pixelsize; /* Size of a pixel, in bytes (1, 2 or 4) */ + int linesize; /* Size of a line, in bytes (xsize * pixelsize) */ + + /* Virtual methods */ + void (*destroy)(Imaging im); + +}; + + +#define IMAGING_PIXEL_1(im,x,y) ((im)->image8[(y)][(x)]) +#define IMAGING_PIXEL_L(im,x,y) ((im)->image8[(y)][(x)]) +#define IMAGING_PIXEL_LA(im,x,y) ((im)->image[(y)][(x)*4]) +#define IMAGING_PIXEL_P(im,x,y) ((im)->image8[(y)][(x)]) +#define IMAGING_PIXEL_PA(im,x,y) ((im)->image[(y)][(x)*4]) +#define IMAGING_PIXEL_I(im,x,y) ((im)->image32[(y)][(x)]) +#define IMAGING_PIXEL_F(im,x,y) (((FLOAT32*)(im)->image32[y])[x]) +#define IMAGING_PIXEL_RGB(im,x,y) ((im)->image[(y)][(x)*4]) +#define IMAGING_PIXEL_RGBA(im,x,y) ((im)->image[(y)][(x)*4]) +#define IMAGING_PIXEL_CMYK(im,x,y) ((im)->image[(y)][(x)*4]) +#define IMAGING_PIXEL_YCbCr(im,x,y) ((im)->image[(y)][(x)*4]) + +#define IMAGING_PIXEL_UINT8(im,x,y) ((im)->image8[(y)][(x)]) +#define IMAGING_PIXEL_INT32(im,x,y) ((im)->image32[(y)][(x)]) +#define IMAGING_PIXEL_FLOAT32(im,x,y) (((FLOAT32*)(im)->image32[y])[x]) + +#define IMAGING_ACCESS_HEAD\ + int (*getline)(ImagingAccess access, char *buffer, int y);\ + void (*destroy)(ImagingAccess access) + +struct ImagingAccessInstance { + IMAGING_ACCESS_HEAD; + + /* Data members */ + Imaging im; + +}; + + +struct ImagingHistogramInstance { + + /* Format */ + char mode[4+1]; /* Band names (of corresponding source image) */ + int bands; /* Number of bands (1, 3, or 4) */ + + /* Data */ + long *histogram; /* Histogram (bands*256 longs) */ + +}; + + +struct ImagingPaletteInstance { + + /* Format */ + char mode[4+1]; /* Band names */ + + /* Data */ + UINT8 palette[1024];/* Palette data (same format as image data) */ + + INT16* cache; /* Palette cache (used for predefined palettes) */ + int keep_cache; /* This palette will be reused; keep cache */ + +}; + + +/* Objects */ +/* ------- */ + +extern Imaging ImagingNew(const char* mode, int xsize, int ysize); +extern Imaging ImagingNew2(const char* mode, Imaging imOut, Imaging imIn); +extern void ImagingDelete(Imaging im); + +extern Imaging ImagingNewBlock(const char* mode, int xsize, int ysize); +extern Imaging ImagingNewArray(const char* mode, int xsize, int ysize); +extern Imaging ImagingNewMap(const char* filename, int readonly, + const char* mode, int xsize, int ysize); + +extern Imaging ImagingNewPrologue(const char *mode, + unsigned xsize, unsigned ysize); +extern Imaging ImagingNewPrologueSubtype(const char *mode, + unsigned xsize, unsigned ysize, + int structure_size); +extern Imaging ImagingNewEpilogue(Imaging im); + +extern void ImagingCopyInfo(Imaging destination, Imaging source); + +extern void ImagingHistogramDelete(ImagingHistogram histogram); + +extern ImagingAccess ImagingAccessNew(Imaging im); +extern void ImagingAccessDelete(ImagingAccess access); + +extern ImagingPalette ImagingPaletteNew(const char *mode); +extern ImagingPalette ImagingPaletteNewBrowser(void); +extern ImagingPalette ImagingPaletteDuplicate(ImagingPalette palette); +extern void ImagingPaletteDelete(ImagingPalette palette); + +extern int ImagingPaletteCachePrepare(ImagingPalette palette); +extern void ImagingPaletteCacheUpdate(ImagingPalette palette, + int r, int g, int b); +extern void ImagingPaletteCacheDelete(ImagingPalette palette); + +#define ImagingPaletteCache(p, r, g, b)\ + p->cache[(r>>2) + (g>>2)*64 + (b>>2)*64*64] + +extern Imaging ImagingQuantize(Imaging im, int colours, int mode, int kmeans); + +/* Threading */ +/* --------- */ + +typedef void* ImagingSectionCookie; + +extern void ImagingSectionEnter(ImagingSectionCookie* cookie); +extern void ImagingSectionLeave(ImagingSectionCookie* cookie); + +/* Exceptions */ +/* ---------- */ + +extern void* ImagingError_IOError(void); +extern void* ImagingError_MemoryError(void); +extern void* ImagingError_ModeError(void); /* maps to ValueError by default */ +extern void* ImagingError_Mismatch(void); /* maps to ValueError by default */ +extern void* ImagingError_ValueError(const char* message); + +/* Transform callbacks */ +/* ------------------- */ + +/* standard transforms */ +#define IMAGING_TRANSFORM_AFFINE 0 +#define IMAGING_TRANSFORM_PERSPECTIVE 2 +#define IMAGING_TRANSFORM_QUAD 3 + + +/* standard filters */ +#define IMAGING_TRANSFORM_NEAREST 0 +#define IMAGING_TRANSFORM_ANTIALIAS 1 +#define IMAGING_TRANSFORM_BILINEAR 2 +#define IMAGING_TRANSFORM_BICUBIC 3 + +typedef int (*ImagingTransformMap)(double* X, double* Y, + int x, int y, void* data); +typedef int (*ImagingTransformFilter)(void* out, Imaging im, + double x, double y, + void* data); + +/* Image Manipulation Methods */ +/* -------------------------- */ + +extern Imaging ImagingBlend(Imaging imIn1, Imaging imIn2, float alpha); +extern Imaging ImagingCopy(Imaging im); +extern Imaging ImagingConvert( + Imaging im, const char* mode, ImagingPalette palette, int dither); +extern Imaging ImagingConvertMatrix(Imaging im, const char *mode, float m[]); +extern Imaging ImagingCrop(Imaging im, int x0, int y0, int x1, int y1); +extern Imaging ImagingExpand(Imaging im, int x, int y, int mode); +extern Imaging ImagingFill(Imaging im, const void* ink); +extern int ImagingFill2( + Imaging into, const void* ink, Imaging mask, + int x0, int y0, int x1, int y1); +extern Imaging ImagingFillBand(Imaging im, int band, int color); +extern Imaging ImagingFillLinearGradient(const char* mode); +extern Imaging ImagingFillRadialGradient(const char* mode); +extern Imaging ImagingFilter( + Imaging im, int xsize, int ysize, const FLOAT32* kernel, + FLOAT32 offset, FLOAT32 divisor); +extern Imaging ImagingFlipLeftRight(Imaging imOut, Imaging imIn); +extern Imaging ImagingFlipTopBottom(Imaging imOut, Imaging imIn); +extern Imaging ImagingGetBand(Imaging im, int band); +extern int ImagingGetBBox(Imaging im, int bbox[4]); +typedef struct { int x, y; INT32 count; INT32 pixel; } ImagingColorItem; +extern ImagingColorItem* ImagingGetColors(Imaging im, int maxcolors, + int *colors); +extern int ImagingGetExtrema(Imaging im, void *extrema); +extern int ImagingGetProjection(Imaging im, UINT8* xproj, UINT8* yproj); +extern ImagingHistogram ImagingGetHistogram( + Imaging im, Imaging mask, void *extrema); +extern Imaging ImagingModeFilter(Imaging im, int size); +extern Imaging ImagingNegative(Imaging im); +extern Imaging ImagingOffset(Imaging im, int xoffset, int yoffset); +extern int ImagingPaste( + Imaging into, Imaging im, Imaging mask, + int x0, int y0, int x1, int y1); +extern Imaging ImagingPoint( + Imaging im, const char* tablemode, const void* table); +extern Imaging ImagingPointTransform( + Imaging imIn, double scale, double offset); +extern Imaging ImagingPutBand(Imaging im, Imaging imIn, int band); +extern Imaging ImagingRankFilter(Imaging im, int size, int rank); +extern Imaging ImagingResize(Imaging imOut, Imaging imIn, int filter); +extern Imaging ImagingRotate( + Imaging imOut, Imaging imIn, double theta, int filter); +extern Imaging ImagingRotate90(Imaging imOut, Imaging imIn); +extern Imaging ImagingRotate180(Imaging imOut, Imaging imIn); +extern Imaging ImagingRotate270(Imaging imOut, Imaging imIn); +extern Imaging ImagingStretch(Imaging imOut, Imaging imIn, int filter); +extern Imaging ImagingTransformPerspective( + Imaging imOut, Imaging imIn, int x0, int y0, int x1, int y1, + double a[8], int filter, int fill); +extern Imaging ImagingTransformAffine( + Imaging imOut, Imaging imIn, int x0, int y0, int x1, int y1, + double a[6], int filter, int fill); +extern Imaging ImagingTransformQuad( + Imaging imOut, Imaging imIn, int x0, int y0, int x1, int y1, + double a[8], int filter, int fill); +extern Imaging ImagingTransform( + Imaging imOut, Imaging imIn, int x0, int y0, int x1, int y1, + ImagingTransformMap transform, void* transform_data, + ImagingTransformFilter filter, void* filter_data, + int fill); +extern Imaging ImagingCopy2(Imaging imOut, Imaging imIn); +extern Imaging ImagingConvert2(Imaging imOut, Imaging imIn); + +/* Channel operations */ +/* any mode, except "F" */ +extern Imaging ImagingChopLighter(Imaging imIn1, Imaging imIn2); +extern Imaging ImagingChopDarker(Imaging imIn1, Imaging imIn2); +extern Imaging ImagingChopDifference(Imaging imIn1, Imaging imIn2); +extern Imaging ImagingChopMultiply(Imaging imIn1, Imaging imIn2); +extern Imaging ImagingChopScreen(Imaging imIn1, Imaging imIn2); +extern Imaging ImagingChopAdd( + Imaging imIn1, Imaging imIn2, float scale, int offset); +extern Imaging ImagingChopSubtract( + Imaging imIn1, Imaging imIn2, float scale, int offset); +extern Imaging ImagingChopAddModulo(Imaging imIn1, Imaging imIn2); +extern Imaging ImagingChopSubtractModulo(Imaging imIn1, Imaging imIn2); + +/* "1" images only */ +extern Imaging ImagingChopAnd(Imaging imIn1, Imaging imIn2); +extern Imaging ImagingChopOr(Imaging imIn1, Imaging imIn2); +extern Imaging ImagingChopXor(Imaging imIn1, Imaging imIn2); + +/* Image measurement */ +extern void ImagingCrack(Imaging im, int x0, int y0); + +/* Graphics */ +struct ImagingAffineMatrixInstance { + float a[9]; +}; + +typedef struct ImagingAffineMatrixInstance *ImagingAffineMatrix; + +extern int ImagingDrawArc(Imaging im, int x0, int y0, int x1, int y1, + int start, int end, const void* ink, int op); +extern int ImagingDrawBitmap(Imaging im, int x0, int y0, Imaging bitmap, + const void* ink, int op); +extern int ImagingDrawChord(Imaging im, int x0, int y0, int x1, int y1, + int start, int end, const void* ink, int fill, + int op); +extern int ImagingDrawEllipse(Imaging im, int x0, int y0, int x1, int y1, + const void* ink, int fill, int op); +extern int ImagingDrawLine(Imaging im, int x0, int y0, int x1, int y1, + const void* ink, int op); +extern int ImagingDrawWideLine(Imaging im, int x0, int y0, int x1, int y1, + const void* ink, int width, int op); +extern int ImagingDrawPieslice(Imaging im, int x0, int y0, int x1, int y1, + int start, int end, const void* ink, int fill, + int op); +extern int ImagingDrawPoint(Imaging im, int x, int y, const void* ink, int op); +extern int ImagingDrawPolygon(Imaging im, int points, int *xy, + const void* ink, int fill, int op); +extern int ImagingDrawRectangle(Imaging im, int x0, int y0, int x1, int y1, + const void* ink, int fill, int op); + +/* Level 2 graphics (WORK IN PROGRESS) */ +extern ImagingOutline ImagingOutlineNew(void); +extern void ImagingOutlineDelete(ImagingOutline outline); + +extern int ImagingDrawOutline(Imaging im, ImagingOutline outline, + const void* ink, int fill, int op); + +extern int ImagingOutlineMove(ImagingOutline outline, float x, float y); +extern int ImagingOutlineLine(ImagingOutline outline, float x, float y); +extern int ImagingOutlineCurve(ImagingOutline outline, float x1, float y1, + float x2, float y2, float x3, float y3); +extern int ImagingOutlineTransform(ImagingOutline outline, double a[6]); + +extern int ImagingOutlineClose(ImagingOutline outline); + +/* Special effects */ +extern Imaging ImagingEffectSpread(Imaging imIn, int distance); +extern Imaging ImagingEffectNoise(int xsize, int ysize, float sigma); +extern Imaging ImagingEffectMandelbrot(int xsize, int ysize, + double extent[4], int quality); + +/* Obsolete */ +extern int ImagingToString(Imaging im, int orientation, char *buffer); +extern int ImagingFromString(Imaging im, int orientation, char *buffer); + + +/* File I/O */ +/* -------- */ + +/* Built-in drivers */ +extern Imaging ImagingOpenPPM(const char* filename); +extern int ImagingSavePPM(Imaging im, const char* filename); + +/* Utility functions */ +extern UINT32 ImagingCRC32(UINT32 crc, UINT8* buffer, int bytes); + +/* Codecs */ +typedef struct ImagingCodecStateInstance *ImagingCodecState; +typedef int (*ImagingCodec)(Imaging im, ImagingCodecState state, + UINT8* buffer, int bytes); + +extern int ImagingBitDecode(Imaging im, ImagingCodecState state, + UINT8* buffer, int bytes); +extern int ImagingEpsEncode(Imaging im, ImagingCodecState state, + UINT8* buffer, int bytes); +extern int ImagingFliDecode(Imaging im, ImagingCodecState state, + UINT8* buffer, int bytes); +extern int ImagingGifDecode(Imaging im, ImagingCodecState state, + UINT8* buffer, int bytes); +extern int ImagingGifEncode(Imaging im, ImagingCodecState state, + UINT8* buffer, int bytes); +extern int ImagingHexDecode(Imaging im, ImagingCodecState state, + UINT8* buffer, int bytes); +#ifdef HAVE_LIBJPEG +extern int ImagingJpegDecode(Imaging im, ImagingCodecState state, + UINT8* buffer, int bytes); +extern int ImagingJpegEncode(Imaging im, ImagingCodecState state, + UINT8* buffer, int bytes); +#endif +extern int ImagingLzwDecode(Imaging im, ImagingCodecState state, + UINT8* buffer, int bytes); +#ifdef HAVE_LIBMPEG +extern int ImagingMpegDecode(Imaging im, ImagingCodecState state, + UINT8* buffer, int bytes); +#endif +extern int ImagingMspDecode(Imaging im, ImagingCodecState state, + UINT8* buffer, int bytes); +extern int ImagingPackbitsDecode(Imaging im, ImagingCodecState state, + UINT8* buffer, int bytes); +extern int ImagingPcdDecode(Imaging im, ImagingCodecState state, + UINT8* buffer, int bytes); +extern int ImagingPcxDecode(Imaging im, ImagingCodecState state, + UINT8* buffer, int bytes); +extern int ImagingPcxEncode(Imaging im, ImagingCodecState state, + UINT8* buffer, int bytes); +extern int ImagingRawDecode(Imaging im, ImagingCodecState state, + UINT8* buffer, int bytes); +extern int ImagingRawEncode(Imaging im, ImagingCodecState state, + UINT8* buffer, int bytes); +extern int ImagingSunRleDecode(Imaging im, ImagingCodecState state, + UINT8* buffer, int bytes); +extern int ImagingTgaRleDecode(Imaging im, ImagingCodecState state, + UINT8* buffer, int bytes); +extern int ImagingXbmDecode(Imaging im, ImagingCodecState state, + UINT8* buffer, int bytes); +extern int ImagingXbmEncode(Imaging im, ImagingCodecState state, + UINT8* buffer, int bytes); +#ifdef HAVE_LIBZ +extern int ImagingZipDecode(Imaging im, ImagingCodecState state, + UINT8* buffer, int bytes); +extern int ImagingZipEncode(Imaging im, ImagingCodecState state, + UINT8* buffer, int bytes); +#endif + +typedef void (*ImagingShuffler)(UINT8* out, const UINT8* in, int pixels); + +/* Public shufflers */ +extern void ImagingPackRGB(UINT8* out, const UINT8* in, int pixels); +extern void ImagingPackBGR(UINT8* out, const UINT8* in, int pixels); +extern void ImagingUnpackRGB(UINT8* out, const UINT8* in, int pixels); +extern void ImagingUnpackBGR(UINT8* out, const UINT8* in, int pixels); +extern void ImagingUnpackYCC(UINT8* out, const UINT8* in, int pixels); +extern void ImagingUnpackYCCA(UINT8* out, const UINT8* in, int pixels); +extern void ImagingUnpackYCbCr(UINT8* out, const UINT8* in, int pixels); + +extern void ImagingConvertRGB2YCbCr(UINT8* out, const UINT8* in, int pixels); +extern void ImagingConvertYCbCr2RGB(UINT8* out, const UINT8* in, int pixels); + +extern ImagingShuffler ImagingFindUnpacker(const char* mode, + const char* rawmode, int* bits_out); +extern ImagingShuffler ImagingFindPacker(const char* mode, + const char* rawmode, int* bits_out); + +struct ImagingCodecStateInstance { + int count; + int state; + int errcode; + int x, y; + int ystep; + int xsize, ysize, xoff, yoff; + ImagingShuffler shuffle; + int bits, bytes; + UINT8 *buffer; + void *context; +}; + +/* Errcodes */ +#define IMAGING_CODEC_END 1 +#define IMAGING_CODEC_OVERRUN -1 +#define IMAGING_CODEC_BROKEN -2 +#define IMAGING_CODEC_UNKNOWN -3 +#define IMAGING_CODEC_CONFIG -8 +#define IMAGING_CODEC_MEMORY -9 + +#if defined(__cplusplus) +} +#endif Property changes on: src/extentions/pycms/Imaging.h ___________________________________________________________________ Name: svn:eol-style + native Index: src/extentions/pycms/pyCMSdll.c =================================================================== --- src/extentions/pycms/pyCMSdll.c (.../trunk/sK1) (revision 0) +++ src/extentions/pycms/pyCMSdll.c (.../branches/hackontest/sK1) (revision 560) @@ -0,0 +1,673 @@ +#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\ +http://www.cazabon.com\n\ +\n\ +pyCMS home page: http://www.cazabon.com/pyCMS\n\ +littleCMS home page: http://www.littlecms.com\n\ +(littleCMS is Copyright (C) 1998-2001 Marti Maria)\n\ +\n\ +This library is free software; you can redistribute it and/or\n\ +modify it under the terms of the GNU Lesser General Public\n\ +License as published by the Free Software Foundation; either\n\ +version 2.1 of the License, or (at your option) any later version.\n\ +\n\ +This library is distributed in the hope that it will be useful,\n\ +but WITHOUT ANY WARRANTY; without even the implied warranty of\n\ +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n\ +Lesser General Public License for more details.\n\ +\n\ +You should have received a copy of the GNU Lesser General Public\n\ +License along with this library; if not, write to the Free Software\n\ +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n\ +" + +///////////////////////////////////////////////////////////////////////////// +// includes +///////////////////////////////////////////////////////////////////////////// +#include "Python.h" +//#include "patchlevel.h" // so we can include the Python version automatically in pyCMSdll.versions() +#include "lcms.h" +#include "Imaging.h" + + +///////////////////////////////////////////////////////////////////////////// +// version information: update this before compiling for the versions you're using +///////////////////////////////////////////////////////////////////////////// +#define PYCMSVERSION "0.0.2 alpha" +#define LITTLECMSVERSION "1.09b" +#define PILVERSION "1.1.3" + +//#ifndef PY_MAJOR_VERSION + // before 1.5.2b2, these were not supported +// #define PY_MAJOR_VERSION 0 +// #define PY_MINOR_VERSION 0 +// #define PY_MICRO_VERSION 0 +//#endif +#define PYTHONVERSION "2.2.0" + +///////////////////////////////////////////////////////////////////////////// +// version history +///////////////////////////////////////////////////////////////////////////// +/* +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 +///////////////////////////////////////////////////////////////////////////// +/* +getDefaultIntent doesn't seem to work properly... whassup??? I'm getting very large int return values instead of 0-3 +getProfileName and getProfileInfo are a bit shaky... work on these to solidify them! + +Add comments to code to make it clearer for others to read/understand!!! +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 reading and writing embedded profiles in JPEG and TIFF files +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 + +*/ + + +///////////////////////////////////////////////////////////////////////////// +// options / configuration +///////////////////////////////////////////////////////////////////////////// +// Set the action to take upon error within the CMS module +// LCMS_ERROR_SHOW pop-up window showing error, do not close application +// LCMS_ERROR_ABORT pop-up window showing error, close the application +// LCMS_ERROR_IGNORE ignore the error and continue +#define cmsERROR_HANDLER LCMS_ERROR_SHOW + + +///////////////////////////////////////////////////////////////////////////// +// reference +///////////////////////////////////////////////////////////////////////////// +/* +INTENT_PERCEPTUAL 0 +INTENT_RELATIVE_COLORIMETRIC 1 +INTENT_SATURATION 2 +INTENT_ABSOLUTE_COLORIMETRIC 3 +*/ + + +///////////////////////////////////////////////////////////////////////////// +// structs +///////////////////////////////////////////////////////////////////////////// +typedef struct { + PyObject_HEAD + Imaging image; +} ImagingObject; + + +///////////////////////////////////////////////////////////////////////////// +// internal functions +///////////////////////////////////////////////////////////////////////////// +DWORD +findLCMStype (char* PILmode) { + char *errorMsg = NULL; + + 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 { + // take a wild guess... but you probably should fail instead. + return TYPE_GRAY_8; // so there's no buffer overrun... + } +} + +int +pyCMSdoTransform (Imaging im, Imaging imOut, cmsHTRANSFORM hTransform) { + int i; + + if (im->xsize > imOut->xsize) { + return -1; + } + if (im->ysize > imOut->ysize) { + return -1; + } + + Py_BEGIN_ALLOW_THREADS + + for (i=0; i < im->ysize; i++) + { + cmsDoTransform(hTransform, im->image[i], + imOut->image[i], + im->xsize); + } + + Py_END_ALLOW_THREADS + + return 0; +} + +cmsHTRANSFORM +_buildTransform (cmsHPROFILE hInputProfile, cmsHPROFILE hOutputProfile, char *sInMode, char *sOutMode, int iRenderingIntent) { + cmsHTRANSFORM hTransform; + + cmsErrorAction(cmsERROR_HANDLER); + + Py_BEGIN_ALLOW_THREADS + + // create the transform + hTransform = cmsCreateTransform(hInputProfile, + findLCMStype(sInMode), + hOutputProfile, + findLCMStype(sOutMode), + iRenderingIntent, 0); + + Py_END_ALLOW_THREADS + + return hTransform; +} + +cmsHTRANSFORM +_buildProofTransform(cmsHPROFILE hInputProfile, cmsHPROFILE hOutputProfile, cmsHPROFILE hDisplayProfile, char *sInMode, char *sOutMode, int iRenderingIntent, int iDisplayIntent) { + cmsHTRANSFORM hTransform; + + cmsErrorAction(cmsERROR_HANDLER); + + Py_BEGIN_ALLOW_THREADS + + // create the transform + hTransform = cmsCreateProofingTransform(hInputProfile, + findLCMStype(sInMode), + hOutputProfile, + findLCMStype(sOutMode), + hDisplayProfile, + iRenderingIntent, + iDisplayIntent, + 0); + + Py_END_ALLOW_THREADS + + return hTransform; +} + +///////////////////////////////////////////////////////////////////////////// +// Python callable functions +///////////////////////////////////////////////////////////////////////////// +static PyObject * +versions (PyObject *self, PyObject *args) { + return Py_BuildValue ("ssss", PYCMSVERSION, LITTLECMSVERSION, PYTHONVERSION, PILVERSION); +} + +static PyObject * +about (PyObject *self, PyObject *args) { + return Py_BuildValue("s", COPYRIGHTINFO); +} + +static PyObject * +copyright (PyObject *self, PyObject *args) { + return about(self, args); +} + +static PyObject * +getOpenProfile(PyObject *self, PyObject *args) { + char *sProfile = NULL; + + cmsHPROFILE hProfile; + + if (!PyArg_ParseTuple(args, "s", &sProfile)) { + return Py_BuildValue("s", "ERROR: Could not parse argument tuple passed to pyCMSdll.getOpenProfile()"); + } + + cmsErrorAction(cmsERROR_HANDLER); + + hProfile = cmsOpenProfileFromFile(sProfile, "r"); + + return Py_BuildValue("O", PyCObject_FromVoidPtr(hProfile, cmsCloseProfile)); +} + +static PyObject * +buildTransform(PyObject *self, PyObject *args) { + char *sInputProfile; + char *sOutputProfile; + char *sInMode; + char *sOutMode; + int iRenderingIntent = 0; + cmsHPROFILE hInputProfile, hOutputProfile; + cmsHTRANSFORM transform; + + if (!PyArg_ParseTuple(args, "ssss|i", &sInputProfile, &sOutputProfile, &sInMode, &sOutMode, &iRenderingIntent)) { + return Py_BuildValue("s", "ERROR: Could not parse argument tuple passed to pyCMSdll.buildTransform()"); + } + + cmsErrorAction(cmsERROR_HANDLER); + + hInputProfile = cmsOpenProfileFromFile(sInputProfile, "r"); + hOutputProfile = cmsOpenProfileFromFile(sOutputProfile, "r"); + + transform = _buildTransform(hInputProfile, hOutputProfile, sInMode, sOutMode, iRenderingIntent); + + cmsCloseProfile(hInputProfile); + cmsCloseProfile(hOutputProfile); + + return PyCObject_FromVoidPtr(transform, cmsDeleteTransform); // this may not be right way to call the destructor...? +} + +static PyObject * +buildTransformFromOpenProfiles (PyObject *self, PyObject *args) { + char *sInMode; + char *sOutMode; + int iRenderingIntent = 0; + void *pInputProfile; + void *pOutputProfile; + cmsHPROFILE hInputProfile, hOutputProfile; + void *hTransformPointer = NULL; + cmsHTRANSFORM transform; + + if (!PyArg_ParseTuple(args, "OOss|i", &pInputProfile, &pOutputProfile, &sInMode, &sOutMode, &iRenderingIntent)) { + return Py_BuildValue("s", "ERROR: Could not parse argument tuple passed to pyCMSdll.buildTransformFromOpenProfiles()"); + } + + cmsErrorAction(cmsERROR_HANDLER); + + hInputProfile = (cmsHPROFILE) PyCObject_AsVoidPtr(pInputProfile); + hOutputProfile = (cmsHPROFILE) PyCObject_AsVoidPtr(pOutputProfile); + + transform = _buildTransform(hInputProfile, hOutputProfile, sInMode, sOutMode, iRenderingIntent); + + // we don't have to close these profiles... but do we have to decref them? + + return PyCObject_FromVoidPtr(transform, cmsDeleteTransform); // this may not be right way to call the destructor...? +} + +static PyObject * +buildProofTransform(PyObject *self, PyObject *args) { + char *sInputProfile; + char *sOutputProfile; + char *sDisplayProfile; + char *sInMode; + char *sOutMode; + int iRenderingIntent = 0; + int iDisplayIntent = 0; + cmsHTRANSFORM transform; + + cmsHPROFILE hInputProfile, hOutputProfile, hDisplayProfile; + + if (!PyArg_ParseTuple(args, "sssss|ii", &sInputProfile, &sOutputProfile, &sDisplayProfile, &sInMode, &sOutMode, &iRenderingIntent, &iDisplayIntent)) { + return Py_BuildValue("s", "ERROR: Could not parse argument tuple passed to pyCMSdll.buildProofTransform()"); + } + + cmsErrorAction(cmsERROR_HANDLER); + + // open the input and output profiles + hInputProfile = cmsOpenProfileFromFile(sInputProfile, "r"); + hOutputProfile = cmsOpenProfileFromFile(sOutputProfile, "r"); + hDisplayProfile = cmsOpenProfileFromFile(sDisplayProfile, "r"); + + transform = _buildProofTransform(hInputProfile, hOutputProfile, hDisplayProfile, sInMode, sOutMode, iRenderingIntent, iDisplayIntent); + + cmsCloseProfile(hInputProfile); + cmsCloseProfile(hOutputProfile); + cmsCloseProfile(hDisplayProfile); + + return PyCObject_FromVoidPtr(transform, cmsDeleteTransform); // this may not be right way to call the destructor...? + +} + +static PyObject * +buildProofTransformFromOpenProfiles(PyObject *self, PyObject *args) { + char *sInMode; + char *sOutMode; + int iRenderingIntent = 0; + int iDisplayIntent = 0; + void *pInputProfile; + void *pOutputProfile; + void *pDisplayProfile; + cmsHTRANSFORM transform; + + cmsHPROFILE hInputProfile, hOutputProfile, hDisplayProfile; + + if (!PyArg_ParseTuple(args, "OOOss|ii", &pInputProfile, &pOutputProfile, &pDisplayProfile, &sInMode, &sOutMode, &iRenderingIntent, &iDisplayIntent)) { + return Py_BuildValue("s", "ERROR: Could not parse argument tuple passed to pyCMSdll.buildProofTransform()"); + } + + cmsErrorAction(cmsERROR_HANDLER); + + hInputProfile = (cmsHPROFILE) PyCObject_AsVoidPtr(pInputProfile); + hOutputProfile = (cmsHPROFILE) PyCObject_AsVoidPtr(pOutputProfile); + hDisplayProfile = (cmsHPROFILE) PyCObject_AsVoidPtr(pDisplayProfile); + + transform = _buildProofTransform(hInputProfile, hOutputProfile, hDisplayProfile, sInMode, sOutMode, iRenderingIntent, iDisplayIntent); + + // we don't have to close these profiles, but do we have to decref them? + + return PyCObject_FromVoidPtr(transform, cmsDeleteTransform); // this may not be right way to call the destructor...? +} + +static PyObject * +applyTransform(PyObject *self, PyObject *args) { + long idIn; + long idOut; + void *hTransformPointer; + cmsHTRANSFORM hTransform; + Imaging im; + Imaging imOut; + + int result; + + if (!PyArg_ParseTuple(args, "llO", &idIn, &idOut, &hTransformPointer)) { + return Py_BuildValue("s", "ERROR: Could not parse the data passed to pyCMSdll.applyTransform()"); + } + + im = (Imaging) idIn; + imOut = (Imaging) idOut; + + cmsErrorAction(cmsERROR_HANDLER); + + hTransform = (cmsHTRANSFORM) PyCObject_AsVoidPtr(hTransformPointer); + + result = pyCMSdoTransform(im, imOut, hTransform); + + return Py_BuildValue("i", result); +} + +static PyObject * +profileToProfile(PyObject *self, PyObject *args) +{ + Imaging im; + Imaging imOut; + long idIn; + long idOut = 0L; + char *sInputProfile = NULL; + char *sOutputProfile = NULL; + int iRenderingIntent = 0; + char *inMode; + char *outMode; + int result; + cmsHPROFILE hInputProfile, hOutputProfile; + cmsHTRANSFORM hTransform; + + // parse the PyObject arguments, assign to variables accordingly + if (!PyArg_ParseTuple(args, "llss|i", &idIn, &idOut, &sInputProfile, &sOutputProfile, &iRenderingIntent)) { + return Py_BuildValue("s", "ERROR: Could not parse the argument tuple passed to pyCMSdll.profileToProfile()"); + } + + im = (Imaging) idIn; + + if (idOut != 0L) { + imOut = (Imaging) idOut; + } + + cmsErrorAction(cmsERROR_HANDLER); + + // Check the modes of imIn and imOut to set the color type for the transform + // Note that the modes do NOT have to be the same, as long as they are each + // supported by the relevant profile specified + + inMode = im->mode; + if (idOut == 0L) { + outMode = inMode; + } + else { + outMode = imOut->mode; + } + + // open the input and output profiles + hInputProfile = cmsOpenProfileFromFile(sInputProfile, "r"); + hOutputProfile = cmsOpenProfileFromFile(sOutputProfile, "r"); + + // create the transform + hTransform = _buildTransform(hInputProfile, hOutputProfile, inMode, outMode, iRenderingIntent); + + // apply the transform to imOut (or directly to im in place if idOut is not supplied) + if (idOut != 0L) { + result = pyCMSdoTransform (im, imOut, hTransform); + } + else { + result = pyCMSdoTransform (im, im, hTransform); + } + + // free the transform and profiles + cmsDeleteTransform(hTransform); + cmsCloseProfile(hInputProfile); + cmsCloseProfile(hOutputProfile); + + // return 0 on success, -1 on failure + return Py_BuildValue("i", result); +} + +////////////////////////////////////////////////////////////////////////////// +// Python-Callable On-The-Fly profile creation functions +////////////////////////////////////////////////////////////////////////////// +static PyObject * +createProfile(PyObject *self, PyObject *args) +{ + char *sColorSpace; + cmsHPROFILE hProfile; + int iColorTemp = 0; + LPcmsCIExyY whitePoint = NULL; + int result; + + if (!PyArg_ParseTuple(args, "s|i", &sColorSpace, &iColorTemp)) { + return Py_BuildValue("s", "ERROR: Could not parse the argument tuple passed to pyCMSdll.createProfile()"); + } + + cmsErrorAction(cmsERROR_HANDLER); + + if (strcmp(sColorSpace, "LAB") == 0) { + if (iColorTemp > 0) { + result = cmsWhitePointFromTemp(iColorTemp, whitePoint); + if (result == FALSE) { + return Py_BuildValue("s", "ERROR: Could not calculate white point from color temperature provided, must be integer in degrees Kelvin"); + } + hProfile = cmsCreateLabProfile(whitePoint); + } + else { + hProfile = cmsCreateLabProfile(NULL); + } + } + else if (strcmp(sColorSpace, "XYZ") == 0) { + hProfile = cmsCreateXYZProfile(); + } + else if (strcmp(sColorSpace, "sRGB") == 0) { + hProfile = cmsCreate_sRGBProfile(); + } + else { + return Py_BuildValue("s", "ERROR: Color space requested is not valid for built-in profiles"); + } + + return Py_BuildValue("O", PyCObject_FromVoidPtr(hProfile, cmsCloseProfile)); +} + +////////////////////////////////////////////////////////////////////////////// +// Python callable profile information functions +////////////////////////////////////////////////////////////////////////////// +static PyObject * +getProfileName(PyObject *self, PyObject *args) +{ + // I've had some intermittant problems with this function and getProfileInfo... look at them closer + char *sProfile; + char name[1024]; + + int closeProfile = FALSE; + + cmsHPROFILE hProfile; + + if (!PyArg_ParseTuple(args, "s", &sProfile)) { + if (!PyArg_ParseTuple(args, "O", &hProfile)) { + return Py_BuildValue("s", "ERROR: Could not parse the argument tuple passed to pyCMSdll.getProfileName()"); + } + } + else { + hProfile = cmsOpenProfileFromFile(sProfile, "r"); + closeProfile = TRUE; + } + + // is there a better way to do this? I can't seem to work with the const char* return value otherwise + sprintf(name, "%s\n", cmsTakeProductName(hProfile)); + + if (closeProfile == TRUE) { + cmsCloseProfile(hProfile); + } + + return Py_BuildValue("s", name); +} + +static PyObject * +getProfileInfo(PyObject *self, PyObject *args) +{ + char *sProfile; + char info[4096]; + int closeProfile = FALSE; + + cmsHPROFILE hProfile; + + if (!PyArg_ParseTuple(args, "s", &sProfile)) { + if (!PyArg_ParseTuple(args, "O", &hProfile)) { + return Py_BuildValue("s", "ERROR: Could not parse the argument tuple passed to pyCMSdll.getProfileInfo()"); + } + } + else { + hProfile = cmsOpenProfileFromFile(sProfile, "r"); + closeProfile = TRUE; + } + + // is there a better way to do this? I can't seem to work with the const char* return value otherwise + sprintf(info, "%s\n", cmsTakeProductInfo(hProfile)); + + if (closeProfile == TRUE) { + cmsCloseProfile(hProfile); + } + + return Py_BuildValue("s", info); +} + +static PyObject * +getDefaultIntent(PyObject *self, PyObject *args) +{ + char *sProfile; + int intent = 0; + int closeProfile = FALSE; + + cmsHPROFILE hProfile; + + if (!PyArg_ParseTuple(args, "s", &sProfile)) { + if (!PyArg_ParseTuple(args, "O", &hProfile)) { + return Py_BuildValue("s", "ERROR: Could not parse the argument tuple passed to pyCMSdll.getDefaultIntent()"); + } + } + else { + hProfile = cmsOpenProfileFromFile(sProfile, "r"); + closeProfile = TRUE; + } + + intent = cmsTakeRenderingIntent(hProfile); + + if (closeProfile == TRUE) { + cmsCloseProfile(hProfile); + } + + return Py_BuildValue("i", intent); +} + +static PyObject * +isIntentSupported(PyObject *self, PyObject *args) +{ + char *sProfile; + int iIntent; + int iDirection; + int closeProfile = FALSE; + + int result; + + cmsHPROFILE hProfile; + + if (!PyArg_ParseTuple(args, "sii", &sProfile, &iIntent, &iDirection)) { + if (!PyArg_ParseTuple(args, "Oii", &hProfile, &iIntent, &iDirection)) { + return Py_BuildValue("s", "ERROR: Could not parse the argument tuple passed to pyCMSdll.isIntentSupported()"); + } + } + else { + hProfile = cmsOpenProfileFromFile(sProfile, "r"); + closeProfile = TRUE; + } + + result = cmsIsIntentSupported(hProfile, iIntent, iDirection); + + if (closeProfile == TRUE) { + cmsCloseProfile(hProfile); + } + + if (result == TRUE) { + return Py_BuildValue("i", 1); + } + else { + return Py_BuildValue("i", -1); + } +} + +///////////////////////////////////////////////////////////////////////////// +// Python interface setup +///////////////////////////////////////////////////////////////////////////// +static PyMethodDef pyCMSdll_methods[] = { + // pyCMS info + {"versions", versions, 1, "pyCMSdll.versions() returs tuple of pyCMSversion, littleCMSversion, pythonVersion that it was compiled with (don't trust this 100%, they must be set manually in the source code for now)"}, + {"about", about, 1, "pyCMSdll.about() returns info about pyCMSdll"}, + {"copyright", copyright, 1, "pyCMSdll.copyright() returns info about pyCMSdll"}, + + // profile and transform functions + {"profileToProfile", profileToProfile, 1, "pyCMSdll.profileToProfile (idIn, idOut, InputProfile, OutputProfile, [RenderingIntent]) returns 0 on success, -1 on failure. If idOut is the same as idIn, idIn is modified in place, otherwise the results are applied to idOut"}, + {"getOpenProfile", getOpenProfile, 1, "pyCMSdll.getOpenProfile (profileName) returns a handle to an open pyCMS profile that can be used to build a transform"}, + {"buildTransform", buildTransform, 1, "pyCMSdll.buildTransform (InputProfile, OutputProfile, InMode, OutMode, [RenderingIntent]) returns a handle to a pre-computed ICC transform that can be used for processing multiple images, saving calculation time"}, + {"buildProofTransform", buildProofTransform, 1, "pyCMSdll.buildProofTransform (InputProfile, OutputProfile, DisplayProfile, InMode, OutMode, [RenderingIntent], [DisplayRenderingIntent]) returns a handle to a pre-computed soft-proofing (simulating the output device capabilities on the display device) ICC transform that can be used for processing multiple images, saving calculation time"}, + {"buildProofTransformFromOpenProfiles", buildProofTransformFromOpenProfiles, 1, "pyCMSdll.buildProofTransformFromOpenProfiles(InputProfile, OutputProfile, DisplayProfile, InMode, OutMode, [RenderingIntent], [DisplayRenderingIntent]) returns a handle to a pre-computed soft-proofing transform. Profiles should be HANDLES, not pathnames."}, + {"applyTransform", applyTransform, 1, "pyCMSdll.applyTransform (idIn, idOut, hTransform) applys a pre-calcuated transform (from pyCMSdll.buildTransform) to an image. If idIn and idOut are the same, it modifies the image in place, otherwise the new image is built in idOut. Returns 0 on success, -1 on failure"}, + {"buildTransformFromOpenProfiles", buildTransformFromOpenProfiles, 1, "pyCMSdll.buildTransformFromOpenProfiles (InputProfile, OutputProfile, InMode, OutMode, RenderingIntent) returns a handle to a pre-computed ICC transform that can be used for processing multiple images, saving calculation time"}, + + // on-the-fly profile creation functions + {"createProfile", createProfile, 1, "pyCMSdll.createProfile (colorSpace, [colorTemp]) returns a handle to an open profile created on the fly. colorSpace can be 'LAB', 'XYZ', or 'xRGB'. If using LAB, you can specify a white point color temperature, or let it default to D50 (5000K)"}, + + // profile info functions + {"getProfileName", getProfileName, 1, "pyCMSdll.getProfileName (profile) returns the internal name of the profile"}, + {"getProfileInfo", getProfileInfo, 1, "pyCMSdll.getProfileInfo (profile) returns additional information about the profile"}, + {"getDefaultIntent", getDefaultIntent, 1, "pyCMSdll.getDefaultIntent (profile) returns the default rendering intent of the profile (as an integer)"}, + {"isIntentSupported", isIntentSupported, 1, "pyCMSdll.isIntentSupported (profile, intent, direction) returns 1 if profile supports that intent, -1 if it doesnt. Direction is what the profile is being used for: INPUT = 0, OUTPUT = 1, PROOF = 2"}, + + {NULL, NULL} +}; + +void initpyCMSdll(void) +{ + Py_InitModule("pyCMSdll", pyCMSdll_methods); +} Property changes on: src/extentions/pycms/pyCMSdll.c ___________________________________________________________________ Name: svn:eol-style + native Index: src/share/icons/CrystalSVG/context/context_image_gray_disabled.png =================================================================== Cannot display: file marked as a binary type. svn:mime-type = image/png Property changes on: src/share/icons/CrystalSVG/context/context_image_gray_disabled.png ___________________________________________________________________ Name: svn:mime-type + image/png Index: src/share/icons/CrystalSVG/context/context_image_gray.png =================================================================== Cannot display: file marked as a binary type. svn:mime-type = image/png Property changes on: src/share/icons/CrystalSVG/context/context_image_gray.png ___________________________________________________________________ Name: svn:mime-type + image/png Index: src/share/icons/CrystalSVG/context/context_image_cmyk.png =================================================================== Cannot display: file marked as a binary type. svn:mime-type = image/png Property changes on: src/share/icons/CrystalSVG/context/context_image_cmyk.png ___________________________________________________________________ Name: svn:mime-type + image/png Index: src/share/icons/CrystalSVG/context/context_image_cmyk_disabled.png =================================================================== Cannot display: file marked as a binary type. svn:mime-type = image/png Property changes on: src/share/icons/CrystalSVG/context/context_image_cmyk_disabled.png ___________________________________________________________________ Name: svn:mime-type + image/png Index: src/share/icons/CrystalSVG/context/context_image_bw_disabled.png =================================================================== Cannot display: file marked as a binary type. svn:mime-type = image/png Property changes on: src/share/icons/CrystalSVG/context/context_image_bw_disabled.png ___________________________________________________________________ Name: svn:mime-type + image/png Index: src/share/icons/CrystalSVG/context/context_image_rgb_disabled.png =================================================================== Cannot display: file marked as a binary type. svn:mime-type = image/png Property changes on: src/share/icons/CrystalSVG/context/context_image_rgb_disabled.png ___________________________________________________________________ Name: svn:mime-type + image/png Index: src/share/icons/CrystalSVG/context/context_image_bw.png =================================================================== Cannot display: file marked as a binary type. svn:mime-type = image/png Property changes on: src/share/icons/CrystalSVG/context/context_image_bw.png ___________________________________________________________________ Name: svn:mime-type + image/png Index: src/share/icons/CrystalSVG/context/context_image_rgb.png =================================================================== Cannot display: file marked as a binary type. svn:mime-type = image/png Property changes on: src/share/icons/CrystalSVG/context/context_image_rgb.png ___________________________________________________________________ Name: svn:mime-type + image/png Index: setup.cfg =================================================================== --- setup.cfg (.../trunk/sK1) (revision 560) +++ setup.cfg (.../branches/hackontest/sK1) (revision 560) @@ -2,5 +2,5 @@ release = 0 packager = Igor Novikov provides = sk1 -requires = python-imaging libtcl8.5 libtk8.5 python-lcms python-reportlab +requires = python-imaging libtcl8.5 libtk8.5 python-lcms python-reportlab liblcms .