olivierberten / SwatchBooker

Swatch book viewer/convertor/editor
http://www.selapa.net/swatchbooker/
43 stars 6 forks source link

Python bindings for lcms2 #3

Closed luzpaz closed 7 years ago

luzpaz commented 9 years ago

Background: I pinged @olivierberten (https://answers.launchpad.net/swatchbooker/+question/271814)

I'm part of the Scribus community (https://github.com/scribusproject/). Recently it has come to my attention that Swatchbooker has immense potential but it seems that development on it has been dormant. What can be done to help move things in the right direction?

Olivier responded:

Currently, apart for time, the main stopper for me is the lack of Python bindings for LittleCMS2, which makes it hard to make work in any recent environment... I tried to do something simple with ctypes but it crashes in threads, which I use in SwatchBooker. And I don't have the expertise nor the time to dig deeper into it...

By the way, I intend to go on with the development on GitHub instead of Launchpad... https://github.com/olivierberten/SwatchBooker

So I sent an email to the lcms ML: http://sourceforge.net/p/lcms/mailman/message/34497820/

What is the status of Python bindings for lcms2? Is anyone working on this?

And a response comes back:

It's not exactly the same, and is probably only an option on Linux, but libcolord has an API that wraps the important parts of lcms2 and provides a nice GObjectIntrospection interface that can be easily consumed in Python. https://github.com/hughsie/colord/blob/master/examples/cd-get-devices.py is an example talking to the daemon, but if this is interesting to you I can do an example that does a colorspace conversion.

Richard.

luzpaz commented 9 years ago

Continuation... So I reply to Richard directly (accidentally off-list) with

Yes please :)

So Richard replies

I can do an example that does a colorspace conversion.

Yes please :)

So I had a try at this just now, but my python knowledge is lacking. I'm not sure how you get access to the raw bytes in an image from python and what coding conventions you'd use in a library. Ideas welcome here. I've included the incomplete code below. I'm happy to add more functionality into libcolord if this is required (e.g. if we want to pass an array of "ddd" to the process function).

Richard


import gi
gi.require_version('Colord', '1.0')

from gi.repository import Colord
from gi.repository import Gio

# load sRGB (without using the daemon)
icc_src = Colord.Icc.new()
h = Gio.file_new_for_path('/usr/share/color/icc/colord/sRGB.icc')
icc_src.load_file(h, Colord.IccLoadFlags.NONE)

# load AdobeRGB (without using the daemon)
icc_dst = Colord.Icc.new()
h = Gio.file_new_for_path('/usr/share/color/icc/colord/AdobeRGB1998.icc')
icc_dst.load_file(h, Colord.IccLoadFlags.NONE)

# set up the transform
transform = Colord.Transform.new()
transform.set_input_pixel_format(Colord.PIXEL_FORMAT_RGB24)
transform.set_input_icc(icc_src)
transform.set_output_icc(icc_dst)
transform.set_output_pixel_format(Colord.PIXEL_FORMAT_RGB24)
transform.set_rendering_intent(Colord.RenderingIntent.PERCEPTUAL)
transform.set_bpc(True)

# hmm, not sure how to make process() accept raw image data
data_in = [0.5,0.6,0.7]
transform.process(data_in, data_in, 1, 1, 1, None)
luzpaz commented 9 years ago

Above Richard writes:

So I had a try at this just now, but my python knowledge is lacking. I'm not sure how you get access to the raw bytes in an image from python and what coding conventions you'd use in a library. Ideas welcome here. I've included the incomplete code below. I'm happy to add more functionality into libcolord if this is required (e.g. if we want to pass an array of "ddd" to the process function).

So I'm CCing some possible help from friends: @berteh @sk1project @aoloe @qulogic

QuLogic commented 9 years ago

According to this, functions with bare gpointer should not be exposed over introspection. They should instead be annotated with the expected array dimensions. However, this seems a bit difficult since the function accepts an array in multiple dimensions with varied data types.

You can create the memory pointer using NumPy arrays. I'm not sure why the example uses [0.5, 0.6, 0.7]; the settings are PIXEL_FORMAT_RGB24 which should be 3 bytes of 0-255, not floats.

This works but since you are passing around pointers and stuff, you should check the caveats and ensure your array is allocated suitably:

data_in = np.array([0.5*255, 0.6*255, 0.7*255],
                   dtype=np.uint8)  # NOTE: Use correct type here, not floats!
print(data_in)
transform.process(data_in.ctypes.data, data_in.ctypes.data, 1, 1, 1, None)
print(data_in)

and outputs:

[127 153 178]
[134 152 176]
olivierberten commented 7 years ago

There's now some bindings for Python3: https://bitbucket.org/johnpfjefferies/little-cms-python-bindings/

No idea what it would take to convert it to python 2...

sk1project commented 7 years ago

lcms2 binding for python 2 is available in sk1 repo since 2012 year:

https://github.com/sk1project/sk1-wx/blob/master/src/uc2/cms/_cms2.c

2017-01-24 23:53 GMT+02:00 Olivier Berten notifications@github.com:

There's now some bindings for Python3: https://bitbucket.org/ johnpfjefferies/little-cms-python-bindings/

No idea what it would take to convert it to python 2...

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/olivierberten/SwatchBooker/issues/3#issuecomment-274950918, or mute the thread https://github.com/notifications/unsubscribe-auth/AMz4a7f7c8dSJKirVnl3YmRZldt1p9Yzks5rVnLMgaJpZM4GFo_I .

olivierberten commented 7 years ago

True but since I have no clue about C programming or Python packaging, I have no idea how to use it with SwatchBooker.

PIL/Pillow also has lcms2 bindings but only with a limited set of features that don't match the few ones I need...

sk1project commented 7 years ago

Which features do you need? May be we could refactor the module for SwatchBooker.

2017-01-25 10:50 GMT+02:00 Olivier Berten notifications@github.com:

True but since I have no clue about C programming or Python packaging, I have no idea how to use it with SwatchBooker.

PIL/Pillow also has lcms2 bindings but only with a limited set of features that don't match the few ones I need...

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/olivierberten/SwatchBooker/issues/3#issuecomment-275051579, or mute the thread https://github.com/notifications/unsubscribe-auth/AMz4a13_4s4AK4G0owsS6JFWaevbNAzgks5rVwzVgaJpZM4GFo_I .

olivierberten commented 7 years ago

the functions I'm using in SwatchBooker are:

cmsOpenProfileFromFile
cmsCreate_sRGBProfile
cmsCreateLab4Profile
cmsCreateXYZProfile
cmsCreateTransform
cmsCloseProfile
cmsDoTransform
cmsDeleteTransform
sk1project commented 7 years ago

So it's just functions for color values transform, not for PIL bitmaps. This list simplifies refactoring task. Btw, cmsCloseProfile and cmsDeleteTransform are not required because Python can manage resources automatically. I'm not sure about cmsCreate_sRGBProfile, cmsCreateLab4Profile, cmsCreateXYZProfile functions because we don't use built-in profiles due to not perfect calculation result. But they should be in lcms2 API definitely.

We will start this job soon and let you know the result.

2017-01-28 22:46 GMT+02:00 Olivier Berten notifications@github.com:

the functions I'm using in SwatchBooker are:

cmsOpenProfileFromFile cmsCreate_sRGBProfile cmsCreateLab4Profile cmsCreateXYZProfile cmsCreateTransform cmsCloseProfile cmsDoTransform cmsDeleteTransform

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/olivierberten/SwatchBooker/issues/3#issuecomment-275873569, or mute the thread https://github.com/notifications/unsubscribe-auth/AMz4a1ZXkmJfgSuapfHFTLdFYFHMVhc1ks5rW6lDgaJpZM4GFo_I .

olivierberten commented 7 years ago

PIL bitmaps are converted directly inside PIL but their binding don't expose the "simple" color transform functions...

In the meantime I did manage to have it working with an updated version of ctypesgen and the THR version of the functions so there's no emergency anymore.

Thank you anyway!

olivierberten commented 7 years ago

Just released 0.7.5 with the lcms2 bindings.

sk1project commented 7 years ago

Nevertheless we almost completed lcms2 native extension so we will send it you soon.

2017-02-10 17:16 GMT+02:00 Olivier Berten notifications@github.com:

Just released 0.7.5 with the lcms2 bindings.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/olivierberten/SwatchBooker/issues/3#issuecomment-278971384, or mute the thread https://github.com/notifications/unsubscribe-auth/AMz4ay3n6OIM8G6tMQRnBTlLCJpokJkRks5rbH9UgaJpZM4GFo_I .

sk1project commented 7 years ago

Hi Olivier!

It seems lcms2 extension for SwatchBooker is ready.

https://github.com/sk1project/python-lcms2

We have refactored our lcms2 binding to be backward compatible with python-lcms. So using it you just need to replace 'lcms' imports by 'lcms2'. We marked the sources as "Specially created for SwatchBooker" so you could include them into project source code (for example, as a subpackage of swatchbooker package).

python-lcms2 is designed as a standalone project to demonstrate how to build native extension under posix platform. If you will need MS Windows build we could provide required binary resources and setup.py routines.

2017-02-10 17:35 GMT+02:00 sk1.project.org sk1.project.org@gmail.com:

Nevertheless we almost completed lcms2 native extension so we will send it you soon.

2017-02-10 17:16 GMT+02:00 Olivier Berten notifications@github.com:

Just released 0.7.5 with the lcms2 bindings.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/olivierberten/SwatchBooker/issues/3#issuecomment-278971384, or mute the thread https://github.com/notifications/unsubscribe-auth/AMz4ay3n6OIM8G6tMQRnBTlLCJpokJkRks5rbH9UgaJpZM4GFo_I .