lcms-user Mailing List for Little cms color engine (Page 2)
An ICC-based CMM for color management
Brought to you by:
mm2
You can subscribe to this list here.
2001 |
Jan
|
Feb
|
Mar
|
Apr
(2) |
May
(15) |
Jun
(24) |
Jul
(9) |
Aug
(14) |
Sep
|
Oct
(12) |
Nov
(17) |
Dec
(31) |
---|---|---|---|---|---|---|---|---|---|---|---|---|
2002 |
Jan
(34) |
Feb
(7) |
Mar
(7) |
Apr
(16) |
May
(4) |
Jun
(14) |
Jul
(34) |
Aug
(54) |
Sep
(11) |
Oct
(25) |
Nov
(1) |
Dec
(6) |
2003 |
Jan
(27) |
Feb
(54) |
Mar
(23) |
Apr
(68) |
May
(82) |
Jun
(36) |
Jul
(45) |
Aug
(45) |
Sep
(49) |
Oct
(30) |
Nov
(65) |
Dec
(23) |
2004 |
Jan
(52) |
Feb
(52) |
Mar
(35) |
Apr
(38) |
May
(93) |
Jun
(22) |
Jul
(51) |
Aug
(50) |
Sep
(73) |
Oct
(28) |
Nov
(30) |
Dec
(51) |
2005 |
Jan
(22) |
Feb
(79) |
Mar
(38) |
Apr
(51) |
May
(95) |
Jun
(60) |
Jul
(56) |
Aug
(49) |
Sep
(22) |
Oct
(43) |
Nov
(15) |
Dec
(40) |
2006 |
Jan
(51) |
Feb
(31) |
Mar
(37) |
Apr
(25) |
May
(9) |
Jun
(13) |
Jul
(17) |
Aug
(66) |
Sep
(7) |
Oct
(12) |
Nov
(14) |
Dec
(31) |
2007 |
Jan
(18) |
Feb
(9) |
Mar
(22) |
Apr
(18) |
May
(5) |
Jun
(25) |
Jul
(2) |
Aug
(15) |
Sep
(12) |
Oct
(40) |
Nov
(10) |
Dec
(23) |
2008 |
Jan
(21) |
Feb
(56) |
Mar
(12) |
Apr
(23) |
May
(47) |
Jun
(75) |
Jul
(24) |
Aug
(2) |
Sep
(7) |
Oct
(26) |
Nov
(20) |
Dec
(16) |
2009 |
Jan
(14) |
Feb
(1) |
Mar
(29) |
Apr
(54) |
May
(18) |
Jun
(16) |
Jul
(5) |
Aug
(3) |
Sep
(38) |
Oct
(6) |
Nov
(25) |
Dec
(28) |
2010 |
Jan
(11) |
Feb
(26) |
Mar
(2) |
Apr
(10) |
May
(45) |
Jun
(94) |
Jul
(11) |
Aug
(32) |
Sep
(18) |
Oct
(37) |
Nov
(19) |
Dec
(34) |
2011 |
Jan
(21) |
Feb
(16) |
Mar
(16) |
Apr
(29) |
May
(17) |
Jun
(18) |
Jul
(7) |
Aug
(21) |
Sep
(10) |
Oct
(7) |
Nov
(15) |
Dec
(6) |
2012 |
Jan
(13) |
Feb
(16) |
Mar
(15) |
Apr
(12) |
May
(15) |
Jun
(31) |
Jul
(22) |
Aug
(15) |
Sep
(46) |
Oct
(21) |
Nov
(15) |
Dec
(33) |
2013 |
Jan
(19) |
Feb
(17) |
Mar
(31) |
Apr
(17) |
May
(27) |
Jun
(24) |
Jul
(26) |
Aug
(11) |
Sep
(9) |
Oct
(22) |
Nov
(14) |
Dec
(16) |
2014 |
Jan
(20) |
Feb
(66) |
Mar
(29) |
Apr
(13) |
May
(9) |
Jun
|
Jul
(11) |
Aug
(21) |
Sep
(15) |
Oct
(5) |
Nov
(5) |
Dec
(10) |
2015 |
Jan
(6) |
Feb
(26) |
Mar
(26) |
Apr
|
May
(9) |
Jun
(5) |
Jul
(5) |
Aug
(11) |
Sep
(8) |
Oct
|
Nov
|
Dec
|
2016 |
Jan
(3) |
Feb
|
Mar
(9) |
Apr
(3) |
May
(16) |
Jun
(26) |
Jul
(32) |
Aug
(27) |
Sep
(9) |
Oct
|
Nov
(4) |
Dec
(10) |
2017 |
Jan
(11) |
Feb
(44) |
Mar
(6) |
Apr
(8) |
May
(1) |
Jun
(2) |
Jul
(34) |
Aug
(28) |
Sep
(3) |
Oct
(9) |
Nov
(3) |
Dec
|
2018 |
Jan
(1) |
Feb
(5) |
Mar
(6) |
Apr
(1) |
May
(1) |
Jun
(2) |
Jul
|
Aug
(1) |
Sep
(6) |
Oct
|
Nov
(6) |
Dec
|
2019 |
Jan
(18) |
Feb
(16) |
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
(7) |
Sep
(3) |
Oct
(10) |
Nov
(1) |
Dec
(3) |
2020 |
Jan
|
Feb
|
Mar
|
Apr
|
May
(17) |
Jun
(23) |
Jul
|
Aug
(4) |
Sep
|
Oct
|
Nov
|
Dec
|
2021 |
Jan
(10) |
Feb
(3) |
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
(5) |
Oct
|
Nov
(1) |
Dec
|
2022 |
Jan
(8) |
Feb
|
Mar
(9) |
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
(13) |
Nov
(12) |
Dec
|
2023 |
Jan
|
Feb
(1) |
Mar
(9) |
Apr
|
May
(3) |
Jun
(5) |
Jul
(3) |
Aug
(8) |
Sep
|
Oct
|
Nov
(1) |
Dec
(9) |
2024 |
Jan
(8) |
Feb
|
Mar
(14) |
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
From: flap <fb...@oh...> - 2023-12-29 11:06:08
|
Hi list, what I want: an 8 bit grey-scale output for my printer, where the input dot values (0 … 255) are scaled and limited to values of 40 … 240 (…just an example). So I created a simple test input data (256 elements of unsigned char) with a linear ramp from 0 (at index 0) … 255 (at index 255). And I created an array with 4096 short entries beginning with 40 (* 256 for unsigned short) and ramp up linear to 240 (* 256 for unsigned short) and feed it into cmsBuildTabulatedToneCurve16() and cmsCreateGrayProfile() with cmsD50_xyY() as its whitepoint (for the output profile). For the input profile I used cmsBuildGamma() with a value of 1.0 and cmsCreateGrayProfile() with cmsD50_xyY(). After creating the transformation with cmsCreateTransform() with input/output types both TYPE_GRAY_8 and an intent of INTENT_PERCEPTUAL and applying this transformation with cmsDoTransformLineStride () to my simple input data, the output result is still almost linear from 0 to 255 and not limited to 40 … 240. So, I think I'm using the tone curves in a wrong way. But where is my mistake? Cheers, Jürgen |
From: flap <fb...@oh...> - 2023-12-22 10:36:19
|
Hi Marti, Myself wrote: > […] > > I will try with valgrind. Result: classic "use-after-free" error... m( Thank you for pointing me to a memory corruption tip. Cheers, Jürgen |
From: <mar...@li...> - 2023-12-22 02:41:43
|
Hi Jürgen, > It only happens (e.g. the error message) in my final application. The same > piece of code works in my test program (which does at most the same, same > PNG file, same output definition). This is memory corruption. Maybe you have closed the input or output profiles before calling cmsCreateTransform? The snipped you send is correct, used in many different places with no problems. Could you run your program under a memory checker, valgrind or visual studio sanitizer, for example? Upgrading to 2.16 would be also a good idea, but I doubt using an old version is the root cause of this issue. Regards Marti Maria The LittleCMS Project https://www.littlecms.com > -----Original Message----- > From: flap <fb...@oh...> > Sent: Thursday, December 21, 2023 6:51 PM > To: lcm...@li... > Subject: [Lcms-user] cmsCreateTransform(): Unclear error message > > Hello list, > > I have the following lines in my code: > > […] > assert(cmsGetColorSpace(info->incms) == cmsSigRgbData); > assert(cmsGetColorSpace(info->outcms) == cmsSigGrayData); > > cmsHTRANSFORM trans = cmsCreateTransform(info->incms, > TYPE_RGB_8, /* from 24 bit RGB raster */ > info->outcms, > TYPE_GRAY_8, /* into an 8 bit grey-scale raster */ > INTENT_PERCEPTUAL, > 0); /* no further flags for now */ > if (trans == NULL) > return -EINVAL; > […] > > The catched error message when calling cmsCreateTransform() is code 13 ('not > suitable') and 'Couldn't link the profiles'. What does it mean? > > It only happens (e.g. the error message) in my final application. The same > piece of code works in my test program (which does at most the same, same > PNG file, same output definition). > > I'm now confused what the difference can be to make the call fail. > > Background: The "info->incms" comes from an embedded ICC profile in the > PNG file and the "info->outcms" is a virtual profile generated with > cmsCreateGrayProfileTHR(). On my system liblcms2.so.2 -> liblcms2.so.2.0.12 > is in use. > > Cheers, > Jürgen > > > > > > _______________________________________________ > Lcms-user mailing list > Lcm...@li... > https://lists.sourceforge.net/lists/listinfo/lcms-user |
From: flap <fb...@oh...> - 2023-12-21 22:35:37
|
Hi Marti, mar...@li... wrote: > > It only happens (e.g. the error message) in my final application. The same > > piece of code works in my test program (which does at most the same, same > > PNG file, same output definition). > > This is memory corruption. Maybe you have closed the input or output > profiles before calling cmsCreateTransform? No, both profiles are still open. > The snipped you send is correct, used in many different places with no > problems. Could you run your program under a memory checker, valgrind or > visual studio sanitizer, for example? My programs run with ASAN enabled. Most of the time it triggers in a reliable manner if the memory gets corrupted. Here not - yet. I will try with valgrind. Thanks, Jürgen |
From: flap <fb...@oh...> - 2023-12-21 17:51:36
|
Hello list, I have the following lines in my code: […] assert(cmsGetColorSpace(info->incms) == cmsSigRgbData); assert(cmsGetColorSpace(info->outcms) == cmsSigGrayData); cmsHTRANSFORM trans = cmsCreateTransform(info->incms, TYPE_RGB_8, /* from 24 bit RGB raster */ info->outcms, TYPE_GRAY_8, /* into an 8 bit grey-scale raster */ INTENT_PERCEPTUAL, 0); /* no further flags for now */ if (trans == NULL) return -EINVAL; […] The catched error message when calling cmsCreateTransform() is code 13 ('not suitable') and 'Couldn't link the profiles'. What does it mean? It only happens (e.g. the error message) in my final application. The same piece of code works in my test program (which does at most the same, same PNG file, same output definition). I'm now confused what the difference can be to make the call fail. Background: The "info->incms" comes from an embedded ICC profile in the PNG file and the "info->outcms" is a virtual profile generated with cmsCreateGrayProfileTHR(). On my system liblcms2.so.2 -> liblcms2.so.2.0.12 is in use. Cheers, Jürgen |
From: <mar...@li...> - 2023-12-04 03:04:08
|
Little CMS 2.16 released I am glad to the announce the release 2.16 of the LittleCMS open-source color engine. lcms2-2.16 is a featured release. Changes: * New: import .CUBE files as RGB device links * New: Read/Write MHC2 tags for Windows GPU access * New: Support for UTF8 on multi-localized Unicode functions * New: Support for OkLab color space, built-in and formatter. * Improved: floating point transforms float -> integers are now honored as float * Improved: MSYS2, mingw is now supported * Improved: preferred CMM, platform and creator now survive profile edition. * Fixed: tificc now can deal with Lab TIFF * Fixed: code can now be compiled by a C++17 compiler, "register" keywork use is detected at compile time. * Fixed: Reverted PostScript creation that corrupted some interpreters. * Bug fixing & security enhancements Little CMS intends to be an open source small-footprint color management engine, with special focus on accuracy and performance. It uses the International Color Consortium standard (ICC), which is the modern standard when regarding to color management. The ICC specification is widely used and is referred to in many International and other de-facto standards. It was approved as an International Standard, ISO 15076-1, in 2005. Main site: http://www.littlecms.com Downloads: http://www.littlecms.com/download.html https://sourceforge.net/projects/lcms/files/latest/download https://github.com/mm2/Little-CMS/releases/tag/lcms2.16 Best regards, Marti Maria The Little CMS project http://www.littlecms.com |
From: <mar...@li...> - 2023-11-19 15:03:45
|
Hi, It's time to make a new release. I try to alternate stabilization and new features, and this time it's new features. The first release candidate is available here: https://github.com/mm2/Little-CMS/releases/tag/lcms2.16rc1 Changes * New: import .CUBE files as RGB devicelinks * New: Read/Write MHC2 tags for Windows GPU access * New: Support for UTF8 on multilocalized unicode functions * New: Support for OkLab color space, built-in and formatter. * Improved: floating point transforms float -> integers are now honored as float * Improved: MSYS2, mingw is now supported * Improved: preferred CMM, platform and creator now survive profile edition. * Fixed: tificc now can deal with Lab TIFF * Fixed: code can now be compiled by a C++17 compiler, "register" keywork use detected at compile time. * Fixed: Reverted PostScript creation that corrupted some interpreters. * Bug fixing & security enhancements Feel free to test it on all your products, tentative release date for final lcms2-2.16 is end of Nov-2023 Please contact me on any issue either on info { at } littecms.com or using this list. Best regards Marti Maria The LittleCMS Project https://www.littlecms.com |
From: <mar...@li...> - 2023-08-15 11:57:59
|
Hello Sergey, > The actual data of the image(byte, short, int, float, double)->float->short->start > lcms > internal->float->apply color transform in floats->end lcms > internal->float->internals->short->float->the data of the > image(byte, short, int, float, double). So at the end we have a "good" precision > of the result especially if the image stores the color component in 17+ bits. I don't know the internal architecture of OpenJDK, so maybe this is not feasible, but it seems to me the way you are doing the conversions is a serious throughput killer. Lcms goes in a lot of trouble to optimize color transforms to make them as fast as possible whilst keeping the maximum precision. So, if you are going to convert a bitmap of 8 bits to another bitmap of 8 bits, your best option is to tell lcms to use 8 bits on input and output. The math precision and throughput performance you will obtain is actually better than going to float and then back to 8 bits, because lcms use tricks on rounding and fixed-point interpolation to go fast and accurate. Ditto for 16 bits, float, double, half... Floating point transforms should be only used when your data is already in floating point, or in the case you want to convert to floating point. But that should be transparent to you, you should only tell the engine how your data is organized and let it to pick the better way to do the conversion. If you always convert to float assuming this is going to increase precision you are obtaining the inverse effect: sometimes less precision and definitively slower throughput. But again, I don't know OpenJDK architecture, so maybe the float step is unavoidable because other components. Best regards Marti Maria The LittleCMS Project https://www.littlecms.com > -----Original Message----- > From: Sergey Bylokhov <byl...@am...> > Sent: Monday, August 14, 2023 10:18 PM > To: Philip Race <phi...@or...>; mar...@li...; lcms- > us...@li... > Subject: Re: [Lcms-user] Configuration of the bounded/unbounded mode > > On 8/13/23 15:07, Philip Race wrote: > > Sergey, > > > > Why do you want to do this ? I'm not sure I see the value in it. > > > > Although JDK does support float for images, none of the standard image > > formats use floats. > > Unfortunately not, even though most standard images use bytes and ints to > convert color profiles and access pixels in images, we use floats. So the > common pattern we have is: > The actual data of the image(byte, short, int, float, double)->float->short->start > lcms > internal->float->apply color transform in floats->end lcms > internal->float->internals->short->float->the data of the > image(byte, short, int, float, double). So at the end we have a "good" precision > of the result especially if the image stores the color component in 17+ bits. > > An examples of such conversion: > 1. > https://github.com/openjdk/jdk/blob/595fdd36c5f735b53ed2950c539be46382f > 9bcdd/src/java.desktop/share/classes/sun/java2d/cmm/lcms/LCMSTransform.j > ava#L230 > 2. > https://github.com/openjdk/jdk/blob/595fdd36c5f735b53ed2950c539be46382f > 9bcdd/src/java.desktop/share/classes/java/awt/image/ColorConvertOp.java#L8 > 09 > 3. Well we have a public API for such float based conversion - > to/From/RGB/CIEXYZ: > https://github.com/openjdk/jdk/blob/595fdd36c5f735b53ed2950c539be46382f > 9bcdd/src/java.desktop/share/classes/java/awt/color/ICC_ColorSpace.java#L20 > 2 > > > But there are a few things I would like to check before starting to work on the > OpenJDK side. > 1. The slow performance of the float based calculations, described here: > https://github.com/mm2/Little-CMS/issues/356 But I think elimination of an > additional conversion should compensate that. > 2. Compatibility related to the out-gamut values discussed in this thread. I > would like to understand how to implement clip properly. Note that our > current implementation do not clip out-of-gamtut values but blindly cast to > short and get some "random" value at the end. > > -- > Best regards, Sergey. |
From: Sergey B. <byl...@am...> - 2023-08-14 20:18:06
|
On 8/13/23 15:07, Philip Race wrote: > Sergey, > > Why do you want to do this ? I'm not sure I see the value in it. > > Although JDK does support float for images, none of the standard image > formats use floats. Unfortunately not, even though most standard images use bytes and ints to convert color profiles and access pixels in images, we use floats. So the common pattern we have is: The actual data of the image(byte, short, int, float, double)->float->short->start lcms internal->float->apply color transform in floats->end lcms internals->short->float->the data of the image(byte, short, int, float, double). So at the end we have a "good" precision of the result especially if the image stores the color component in 17+ bits. An examples of such conversion: 1. https://github.com/openjdk/jdk/blob/595fdd36c5f735b53ed2950c539be46382f9bcdd/src/java.desktop/share/classes/sun/java2d/cmm/lcms/LCMSTransform.java#L230 2. https://github.com/openjdk/jdk/blob/595fdd36c5f735b53ed2950c539be46382f9bcdd/src/java.desktop/share/classes/java/awt/image/ColorConvertOp.java#L809 3. Well we have a public API for such float based conversion - to/From/RGB/CIEXYZ: https://github.com/openjdk/jdk/blob/595fdd36c5f735b53ed2950c539be46382f9bcdd/src/java.desktop/share/classes/java/awt/color/ICC_ColorSpace.java#L202 But there are a few things I would like to check before starting to work on the OpenJDK side. 1. The slow performance of the float based calculations, described here: https://github.com/mm2/Little-CMS/issues/356 But I think elimination of an additional conversion should compensate that. 2. Compatibility related to the out-gamut values discussed in this thread. I would like to understand how to implement clip properly. Note that our current implementation do not clip out-of-gamtut values but blindly cast to short and get some "random" value at the end. -- Best regards, Sergey. |
From: Philip R. <phi...@or...> - 2023-08-13 22:19:26
|
Sergey, Why do you want to do this ? I'm not sure I see the value in it. Although JDK does support float for images, none of the standard image formats use floats. So I'm not sure how well this change would be tested nor where we'd see any benefit from it so who is asking for this ? -phil. On 8/13/23 2:36 AM, mar...@li... wrote: > Hi, > > Keep in mind the CMM internally operates always in unbounded mode and clips > values at final stage if you use anything but floating point. Also, not all > profiles allow unbounded mode. Doing the change you purpose would have a > severe impact on applications not expecting values negative or over 1.0. > By using shorts, you are limiting precision to 16 bits, if you use floats, > you get more accuracy. Also note the encoding range changes, 0.1 for RGB, > 0.100 for CMYK and for Lab it comes already decoded. > Unbounded mode works in both directions, if you feed the transform with a > value bigger then 1.0 and the profile supports it, the obtained XYZ would be > an out-of-gamut extrapolation. > > The flag cmsFLAGS_NONEGATIVES was introduced to prevent only negative values > because security issues, does not work for values bigger than 1. In any > case, no matter what you do, the result would be wrong because this is an > out of gamut value. Clipping is an option, just the simplest gamut mapping > you could do. > >> 3. What about the use case when the user splits the "big" transform into a >> few small intermediate transformations, is it possible to enable > "unbounded" >> mode for all transformations except for the output of the latest > transform? > > Sure. Just ad a couple of "if >= 0 && <= 1.0" at the very end of the > pipeline. > > Regards > > Marti Maria > The LittleCMS Project > https://www.littlecms.com > > > >> -----Original Message----- >> From: Sergey Bylokhov via Lcms-user <lcm...@li...> >> Sent: Sunday, August 13, 2023 1:48 AM >> To: lcm...@li... >> Subject: [Lcms-user] Configuration of the bounded/unbounded mode >> >> Hello, Colors Experts! >> >> I am working on the OpenJDK project and have a couple of questions about >> the LittleCMS library. >> >> The OpenJDK uses the LittleCMS for color conversion for a long time. And > one >> of the use cases is getting the pixel data from the user in float format. >> Unfortunately before passing this float data to the LittleCMS the OpenJDK >> converts them to shorts(16 bit) and after color transformation converts > the >> shorts to floats back and returns that floats to the user. >> >> The current implementation was done for LittleCMS 1 and was not updated > for >> version 2. I have read this[1] document about the "Floating Point Encoding >> Range" added to the spec in 2006 and how it is implemented in the > LittleCMS >> library and would like to use this functionality in OpenJDK. >> >> The change in OpenJDK should be straightforward, delete the intermediate >> conversion from floats to shorts and back and pass the floats directly to > the >> LittleCMS library. But this is a moment I would like to clarify some > possible >> impacts on the compatibility with the old behavior. >> >> 1. It is a good thing to do all intermediate computation in the unbounded >> mode during color transformation, but how the out-of-gamut values are >> handled for input and output data? That was not a problem for short but >> could be a problem for floats, for example, what will happen if 2.0f is > passed >> as a color value for the sRGB format - will it be clipped? or error will > occur? or >> transformation will be applied as-is? >> >> 2. What about the output? There is a cmsFLAGS_NONEGATIVES flag to prevent >> negative values but when and how that values will be clipped by the upper >> bounds? There are no options to configure that and it seems some clipping >> occurs here and there in the code based on some constants which are not >> exposed as CMS API. >> >> 3. What about the use case when the user splits the "big" transform into a >> few small intermediate transformations, is it possible to enable > "unbounded" >> mode for all transformations except for the output of the latest > transform? >> Thank you for any suggestions! >> >> [1] https://www.littlecms.com/CIC18_UnboundedCMM.pdf >> >> -- >> Best regards, Sergey. >> >> >> _______________________________________________ >> Lcms-user mailing list >> Lcm...@li... >> https://lists.sourceforge.net/lists/listinfo/lcms-user > > > _______________________________________________ > Lcms-user mailing list > Lcm...@li... > https://lists.sourceforge.net/lists/listinfo/lcms-user |
From: <mar...@li...> - 2023-08-13 10:53:20
|
Hi, Keep in mind the CMM internally operates always in unbounded mode and clips values at final stage if you use anything but floating point. Also, not all profiles allow unbounded mode. Doing the change you purpose would have a severe impact on applications not expecting values negative or over 1.0. By using shorts, you are limiting precision to 16 bits, if you use floats, you get more accuracy. Also note the encoding range changes, 0.1 for RGB, 0.100 for CMYK and for Lab it comes already decoded. Unbounded mode works in both directions, if you feed the transform with a value bigger then 1.0 and the profile supports it, the obtained XYZ would be an out-of-gamut extrapolation. The flag cmsFLAGS_NONEGATIVES was introduced to prevent only negative values because security issues, does not work for values bigger than 1. In any case, no matter what you do, the result would be wrong because this is an out of gamut value. Clipping is an option, just the simplest gamut mapping you could do. > 3. What about the use case when the user splits the "big" transform into a > few small intermediate transformations, is it possible to enable "unbounded" > mode for all transformations except for the output of the latest transform? Sure. Just ad a couple of "if >= 0 && <= 1.0" at the very end of the pipeline. Regards Marti Maria The LittleCMS Project https://www.littlecms.com > -----Original Message----- > From: Sergey Bylokhov via Lcms-user <lcm...@li...> > Sent: Sunday, August 13, 2023 1:48 AM > To: lcm...@li... > Subject: [Lcms-user] Configuration of the bounded/unbounded mode > > Hello, Colors Experts! > > I am working on the OpenJDK project and have a couple of questions about > the LittleCMS library. > > The OpenJDK uses the LittleCMS for color conversion for a long time. And one > of the use cases is getting the pixel data from the user in float format. > Unfortunately before passing this float data to the LittleCMS the OpenJDK > converts them to shorts(16 bit) and after color transformation converts the > shorts to floats back and returns that floats to the user. > > The current implementation was done for LittleCMS 1 and was not updated for > version 2. I have read this[1] document about the "Floating Point Encoding > Range" added to the spec in 2006 and how it is implemented in the LittleCMS > library and would like to use this functionality in OpenJDK. > > The change in OpenJDK should be straightforward, delete the intermediate > conversion from floats to shorts and back and pass the floats directly to the > LittleCMS library. But this is a moment I would like to clarify some possible > impacts on the compatibility with the old behavior. > > 1. It is a good thing to do all intermediate computation in the unbounded > mode during color transformation, but how the out-of-gamut values are > handled for input and output data? That was not a problem for short but > could be a problem for floats, for example, what will happen if 2.0f is passed > as a color value for the sRGB format - will it be clipped? or error will occur? or > transformation will be applied as-is? > > 2. What about the output? There is a cmsFLAGS_NONEGATIVES flag to prevent > negative values but when and how that values will be clipped by the upper > bounds? There are no options to configure that and it seems some clipping > occurs here and there in the code based on some constants which are not > exposed as CMS API. > > 3. What about the use case when the user splits the "big" transform into a > few small intermediate transformations, is it possible to enable "unbounded" > mode for all transformations except for the output of the latest transform? > > Thank you for any suggestions! > > [1] https://www.littlecms.com/CIC18_UnboundedCMM.pdf > > -- > Best regards, Sergey. > > > _______________________________________________ > Lcms-user mailing list > Lcm...@li... > https://lists.sourceforge.net/lists/listinfo/lcms-user |
From: Sergey B. <byl...@am...> - 2023-08-13 00:04:08
|
Hello, Colors Experts! I am working on the OpenJDK project and have a couple of questions about the LittleCMS library. The OpenJDK uses the LittleCMS for color conversion for a long time. And one of the use cases is getting the pixel data from the user in float format. Unfortunately before passing this float data to the LittleCMS the OpenJDK converts them to shorts(16 bit) and after color transformation converts the shorts to floats back and returns that floats to the user. The current implementation was done for LittleCMS 1 and was not updated for version 2. I have read this[1] document about the "Floating Point Encoding Range" added to the spec in 2006 and how it is implemented in the LittleCMS library and would like to use this functionality in OpenJDK. The change in OpenJDK should be straightforward, delete the intermediate conversion from floats to shorts and back and pass the floats directly to the LittleCMS library. But this is a moment I would like to clarify some possible impacts on the compatibility with the old behavior. 1. It is a good thing to do all intermediate computation in the unbounded mode during color transformation, but how the out-of-gamut values are handled for input and output data? That was not a problem for short but could be a problem for floats, for example, what will happen if 2.0f is passed as a color value for the sRGB format - will it be clipped? or error will occur? or transformation will be applied as-is? 2. What about the output? There is a cmsFLAGS_NONEGATIVES flag to prevent negative values but when and how that values will be clipped by the upper bounds? There are no options to configure that and it seems some clipping occurs here and there in the code based on some constants which are not exposed as CMS API. 3. What about the use case when the user splits the "big" transform into a few small intermediate transformations, is it possible to enable "unbounded" mode for all transformations except for the output of the latest transform? Thank you for any suggestions! [1] https://www.littlecms.com/CIC18_UnboundedCMM.pdf -- Best regards, Sergey. |
From: <mar...@li...> - 2023-08-11 18:37:54
|
Hi, > One further question about your suggestion, if the images are higher bit > depth than 8-bit should I use more than 256 points to create my tone curve, > or will lcms2 smooth the shape of the curve well enough that 256 points is still > adequate? The CMM uses nodes by interpolation, so there is no need to use 256 points. You could any number. Since this takes few memory you could use up to 4096. Including more than 4096 points gives no further accuracy gain. Please note the profiles always use precision higher than 8 bits, unless you use a very old flavor of v2 profiles. Regards Marti Maria The LittleCMS Project https://www.littlecms.com > -----Original Message----- > From: Adrian Knagg-Baugh <aje...@gm...> > Sent: Thursday, August 10, 2023 7:23 PM > To: mar...@li... > Subject: Re: [Lcms-user] Handling channel extraction > > Yes. The images in question are most often either 16-bit unsigned int or 32-bit > float format (they're astronomical data). I'm content with the loss of channel > interaction, and in many cases the RGB images start out being composited > from mono images taken through filters anyway. There are a couple of reasons > we do this in the program: one is to read partial areas of images which is used > in parallelising stacking images together to improve SNR. In this case I don't > think we care about the color profile, because it will invariably be linear > anyway at that stage of acquisition, and the parts are immediately going to be > averaged (sort of) and reassembled into an image with the same color profile. > But also there is a function to split a 3-color image into separate single > channel R, G and B images, perhaps the user only wants one channel or > perhaps they want to process each one separately and then recombine them. > So in that case I think I do need to assign a reasonable color profile to each > split-out channel. > > One further question about your suggestion, if the images are higher bit > depth than 8-bit should I use more than 256 points to create my tone curve, > or will lcms2 smooth the shape of the curve well enough that 256 points is still > adequate? > > Thanks, > > Adrian. > > On Thu, Aug 10, 2023 at 5:42 PM <mar...@li...> wrote: > > > > Hi, > > > > If I understand correctly, you want to split an image, say for example > > a RGB TIFF file, in 3 TIFF gray files, one per channel. And then you > > want to embed in each one of those TIFFs a gray profile derivate from > > the RGB profile you found embedded in the original file. Is that? > > > > First, I should warn you that doing that you will lose information, as > > all the inter-actions between channels are lost, so you will get how > > the channel contributes to the image if converted to gray, but nothing > > else. Having said so, you should not use the TRC tags, that is only an > > implementation detail and you may find profiles that are not using > > matrix-shaper. All profiles using AtoB tags are not going to work in this way. > > > > I would rather use this approach which seems more general to me: > > > > - Get the embedded profile from original image. > > - Create a transform from this profile to the XYZ built-in. Use > > perceptual or relative colorimetric intent + BPC. > > - Feed this transform from channel values from 0 to 255 set other > > channels to 0. Get the Y from resulting XYZ. You will end with an > > array of 256 Y values that corresponds to the obtained Y when using > > that value on that channel. > > - With those 256 Y values, crate a tone curve and with the tone curve, > > create a gray profile. Use D50 as white point. That would be the r > > channel profile. > > - Repeat for g and b. All those profiles would explain the > > contribution of the channel to Y, which is the maximum you can do on gray > images. > > > > Hope that helps > > Regards > > > > Marti Maria > > The LittleCMS Project > > https://www.littlecms.com > > > > > > > > > > > -----Original Message----- > > > From: Adrian Knagg-Baugh <aje...@gm...> > > > Sent: Thursday, August 10, 2023 5:52 PM > > > To: lcm...@li... > > > Subject: [Lcms-user] Handling channel extraction > > > > > > Hi, > > > I'm trying to understand how to handle assignment of a color profile > > > to a single channel extracted from a colour image that may have an > > > arbitrary > > RGB > > > color profile (e.g. extracting the R channel). > > > > > > Would something like this work, assuming rgb_profile is the > > > cmsHPROFILE associated with the full RGB image? > > > > > > cmsHPROFILE extracted_profile == NULL; if (cmsIsTag(rgb_profile, > > > cmsSigRedTRCTag) && cmsIsTag(rgb_profile, > > > cmsSigMediaWhitePoint)) { > > > cmsToneCurve tonecurve = cmsReadTag(rgb_profile, cmsSigRedTRCTag); > > > cmsCIExyY whitepoint = cmsReadTag(rgb_profle, > cmsSigMediaWhitePoint); > > > extracted_profile = cmsCreateGrayProfile(whitepoint, tonecurve); } > > > > > > Thanks, > > > > > > Adrian. > > > > > > > > > _______________________________________________ > > > Lcms-user mailing list > > > Lcm...@li... > > > https://lists.sourceforge.net/lists/listinfo/lcms-user > > |
From: <mar...@li...> - 2023-08-10 21:27:58
|
Hi, If I understand correctly, you want to split an image, say for example a RGB TIFF file, in 3 TIFF gray files, one per channel. And then you want to embed in each one of those TIFFs a gray profile derivate from the RGB profile you found embedded in the original file. Is that? First, I should warn you that doing that you will lose information, as all the inter-actions between channels are lost, so you will get how the channel contributes to the image if converted to gray, but nothing else. Having said so, you should not use the TRC tags, that is only an implementation detail and you may find profiles that are not using matrix-shaper. All profiles using AtoB tags are not going to work in this way. I would rather use this approach which seems more general to me: - Get the embedded profile from original image. - Create a transform from this profile to the XYZ built-in. Use perceptual or relative colorimetric intent + BPC. - Feed this transform from channel values from 0 to 255 set other channels to 0. Get the Y from resulting XYZ. You will end with an array of 256 Y values that corresponds to the obtained Y when using that value on that channel. - With those 256 Y values, crate a tone curve and with the tone curve, create a gray profile. Use D50 as white point. That would be the r channel profile. - Repeat for g and b. All those profiles would explain the contribution of the channel to Y, which is the maximum you can do on gray images. Hope that helps Regards Marti Maria The LittleCMS Project https://www.littlecms.com > -----Original Message----- > From: Adrian Knagg-Baugh <aje...@gm...> > Sent: Thursday, August 10, 2023 5:52 PM > To: lcm...@li... > Subject: [Lcms-user] Handling channel extraction > > Hi, > I'm trying to understand how to handle assignment of a color profile to a > single channel extracted from a colour image that may have an arbitrary RGB > color profile (e.g. extracting the R channel). > > Would something like this work, assuming rgb_profile is the cmsHPROFILE > associated with the full RGB image? > > cmsHPROFILE extracted_profile == NULL; > if (cmsIsTag(rgb_profile, cmsSigRedTRCTag) && cmsIsTag(rgb_profile, > cmsSigMediaWhitePoint)) { > cmsToneCurve tonecurve = cmsReadTag(rgb_profile, cmsSigRedTRCTag); > cmsCIExyY whitepoint = cmsReadTag(rgb_profle, cmsSigMediaWhitePoint); > extracted_profile = cmsCreateGrayProfile(whitepoint, tonecurve); } > > Thanks, > > Adrian. > > > _______________________________________________ > Lcms-user mailing list > Lcm...@li... > https://lists.sourceforge.net/lists/listinfo/lcms-user |
From: Adrian Knagg-B. <aje...@gm...> - 2023-08-10 15:52:35
|
Hi, I'm trying to understand how to handle assignment of a color profile to a single channel extracted from a colour image that may have an arbitrary RGB color profile (e.g. extracting the R channel). Would something like this work, assuming rgb_profile is the cmsHPROFILE associated with the full RGB image? cmsHPROFILE extracted_profile == NULL; if (cmsIsTag(rgb_profile, cmsSigRedTRCTag) && cmsIsTag(rgb_profile, cmsSigMediaWhitePoint)) { cmsToneCurve tonecurve = cmsReadTag(rgb_profile, cmsSigRedTRCTag); cmsCIExyY whitepoint = cmsReadTag(rgb_profle, cmsSigMediaWhitePoint); extracted_profile = cmsCreateGrayProfile(whitepoint, tonecurve); } Thanks, Adrian. |
From: Tamas L. <lit...@gm...> - 2023-07-14 08:55:16
|
Hi, I encountered a strange working behavior of my X-Rite i1 and don't know how to solve that problem.. We have a new small size photo printer in our shop which uses a special dye ink. I usually do my own calibrations instead of using those ones that come from the manufacturers and 99% of my profiles work as I expected. Except for this printer. Manufacturer's profile has some serious shadows (disadvantage) that I don't like, but the blacks are 99.9% black (advantage). My profiles have a much more linear response without that shadow (advantage), but the blacks always have some color tints in it - like a little bit greenish - compared to "real" blacks. The manufacturer's profile can "guess" this black, but i1Profiler cannot and I don't know the reason why. Because i1Profiler performs well on other types of paper and printer, I think it's caused by a bad combination of photo paper and dye ink type. (My first guess was the high OBA content, but the OBA Calibration mode in i1Profiler had similar results.) What can I do with it? I also don't know how we can define the grays & blacks, what is an exact gray without (or a min.) color components included.... Is there a way to move my "wrong" calibration to the right direction? How can I measure the exact distance for it...? Not only in theory, but programmatically, too (I am familiar with lcms). Is it the right path to solve the problem? Any ideas or help welcome! Thanks! Tamas |
From: <mar...@li...> - 2023-07-14 08:42:24
|
Hi Adrian, What you need are contexts. Contexts gives you exactly the functionality you asked for: cmsContext ctx_single = cmsCreateContext(NULL, NULL); // A context for 1 thread cmsContext ctx_multi = cmsCreateContext(cmsThreadedExtensions(CMS_THREADED_GUESS_MAX_THREADS), NULL); // A context for multi-threaded Then use cmsCreateTransformTHR to create different transforms on each context. The obtained transforms will use one thread or be multithreaded. You can just apply the transforms by using cmsDoTransform or cmsTransformLineStride. The CMM knows if it should split or not the work because that information is already in the transform handle. Hope that helps Regards Marti Maria The LittleCMS Project https://www.littlecms.com > -----Original Message----- > From: Adrian Knagg-Baugh <aje...@gm...> > Sent: Friday, July 14, 2023 1:10 AM > To: lcm...@li... > Subject: [Lcms-user] How to change number of threads between transforms > > Hi, > > Please excuse the skeletal pseudocode. Sometimes in my code I would like to > use multiple threads when doing a transform, but at other times it is > important that I only use a single thread. So I need to work out how best to > switch between the two configurations. > > Is it permitted to do something like this: > { > cmsPlugin(cmsFastFloatExtensions()); // Register fast float plugin > cmsPlugin(cmsThreadedExtensions(CMS_THREADED_GUESS_MAX_THREADS, > 0)); // Register the threading plugin with maximum threads > > // I want this transform to use maximum threads > cmsDoTransformLineStride(...); > > // I want this next transform to use only 1 thread > cmsPlugin(cmsThreadedExtensions(1, 0)); // Reconfigure the threading plugin > with 1 thread cmsDoTransformLineStride(...); // Do the single-threaded > transform > > // Now back to maximum threads... > cmsPlugin(cmsThreadedExtensions(CMS_THREADED_GUESS_MAX_THREADS, > 0)); // Reconfigure the threading plugin with maximum threads } > > Or instead would I have to do this: > { > cmsPlugin(cmsFastFloatExtensions()); // Register fast float plugin > cmsPlugin(cmsThreadedExtensions(CMS_THREADED_GUESS_MAX_THREADS, > 0)); // Register the threading plugin with maximum threads > > // I want this transform to use maximum threads > cmsDoTransformLineStride(...); > > // I want this next transform to use only 1 thread cmsUnregisterPlugins(); // > Revert to pristine lcms2 cmsPlugin(cmsFastFloatExtensions()); // Re-register > fast float plugin only cmsDoTransformLineStride(...); // Do the single-threaded > transform > > // Now back to maximum threads... > cmsPlugin(cmsThreadedExtensions(CMS_THREADED_GUESS_MAX_THREADS, > 0)); // Re-register threading plugin with maximum threads } > > Thanks, > > Adrian. > > > _______________________________________________ > Lcms-user mailing list > Lcm...@li... > https://lists.sourceforge.net/lists/listinfo/lcms-user |
From: Adrian Knagg-B. <aje...@gm...> - 2023-07-13 23:10:12
|
Hi, Please excuse the skeletal pseudocode. Sometimes in my code I would like to use multiple threads when doing a transform, but at other times it is important that I only use a single thread. So I need to work out how best to switch between the two configurations. Is it permitted to do something like this: { cmsPlugin(cmsFastFloatExtensions()); // Register fast float plugin cmsPlugin(cmsThreadedExtensions(CMS_THREADED_GUESS_MAX_THREADS, 0)); // Register the threading plugin with maximum threads // I want this transform to use maximum threads cmsDoTransformLineStride(...); // I want this next transform to use only 1 thread cmsPlugin(cmsThreadedExtensions(1, 0)); // Reconfigure the threading plugin with 1 thread cmsDoTransformLineStride(...); // Do the single-threaded transform // Now back to maximum threads... cmsPlugin(cmsThreadedExtensions(CMS_THREADED_GUESS_MAX_THREADS, 0)); // Reconfigure the threading plugin with maximum threads } Or instead would I have to do this: { cmsPlugin(cmsFastFloatExtensions()); // Register fast float plugin cmsPlugin(cmsThreadedExtensions(CMS_THREADED_GUESS_MAX_THREADS, 0)); // Register the threading plugin with maximum threads // I want this transform to use maximum threads cmsDoTransformLineStride(...); // I want this next transform to use only 1 thread cmsUnregisterPlugins(); // Revert to pristine lcms2 cmsPlugin(cmsFastFloatExtensions()); // Re-register fast float plugin only cmsDoTransformLineStride(...); // Do the single-threaded transform // Now back to maximum threads... cmsPlugin(cmsThreadedExtensions(CMS_THREADED_GUESS_MAX_THREADS, 0)); // Re-register threading plugin with maximum threads } Thanks, Adrian. |
From: Tamas L. <lit...@gm...> - 2023-06-19 20:30:57
|
Thank you for your fast reply! It took me a few days to find the bug in the "reverse interpolation" part, and you are right, I was lost in details. Probably I can fine-tune the interpolation somehow, but the printed results - especially the "BullsEye" gradients are very beautiful now. Thanks again! Tamas On Thu, 15 Jun 2023 at 08:41, <mar...@li...> wrote: > Hello, > > > > When doing this kind of things, it is important to keep in mind the real > goals of the process because sometimes is very easy to get lost in details. > > > > “Linearization” is a term that I’ve seen used to a multitude of scenarios. > > > > > A valid approach when profiling a printer is to do it on two steps. The > first step would be to bring the particular printer to a generic well-known > state. For example, by using C, M Y and K tone curves, one per output > channel. Then profile this generic printer. The first step is known as > “linearization”. The obvious advantage of this approach is you have not to > reprofile your printer often but just recompute the curves, which is by far > cheaper and faster. > > > > Another situation when the term linearization is used is when you want a > profile to “match” the characteristics of a given metric. Examples of this > are to create an RGB device space that behaves linearly on Luma. Some of > the linearization goal metrics are intuitive, others are not. For example, > when linearizing CMYK, you can use L* on all channels but on Yellow. > Reason is yellow contributes poorly to L*, and is better to use b* in this > case. Other metrics can be optical density or its derivatives. > > > > So, assuming you want a tone curve to make a gray device space to behave > linearly with L*, you could print a scale of 10-20 patches and then measure > it. With the obtained values perform reverse interpolation. For each L* you > will obtain which device gray value to print. With those values build a > tone curve and you got the linearization. As a test, your tone curve should > match the printed values. > > > > When doing multidimensional, things go more complex though. > > > > Hope that helps > > Regards > > > > Marti Maria > > The LittleCMS Project > > https://www.littlecms.com > > > > > > > > > > > > > > *From:* Tamas Littmann <lit...@gm...> > *Sent:* Wednesday, June 14, 2023 1:39 PM > *To:* lcm...@li... > *Subject:* [Lcms-user] Linearization > > > > Hello, > > > > I have used LCMS for image color space transforms for lots of years, but I > am relatively new in creating my own profiles. > > Using C# and .NET, I can do most of the creating process successfully. > > However, it seems that I cannot move on from some of the easiest steps (I > think I understand the process, but the results are not satisfactory). > > > > Here, I try to minimize the problem, and use 1D transforms (linearization > curve) and Grayscale space (only 1 color). > > > > In this case, how can I linearize a black&white grayscale image/printer? > > > > Here is what I tried to do: > > 1. Print an equal step grayscale ramp (in grayscale mode, using 8-bit 0 - > 255 values. E.g: for six steps it's 0/51/102/153/204/255). 52 steps seems > to be a good starting point (steps are 0 - 5 - 10 - 15 - 20 - etc..) > > > > 2. I have an X-Rite i1 / Datacolor Spyder, so I can read the values in LAB > format (saved CGATS files). > > > > 3. White Point LAB L* is usually around 94, black point LAB L* is usually > from 3 - 15, depends the type of media, so i need to slice this range to > equal steps to find the linear values (if i want something else, not like a > linear line, but a special curve, i need to slice this range according to > that curves). > > > > 4. Normalize both LAB L* data arrays to a 0.0 - 100.0 range. > > > > 5. Find the difference between the measured ones and the linear ones. > > > > 6. Used those differences to calculate LAB L* -> Grayscale values. (This > is the point where I think I misunderstand something). Normally I added > these difference values to the original source Gray -> LAB L* values. > > > > I can use the corrected LAB L* values to create normal output profiles, or > can use the Grayscale values to create a simple DeviceLink profile. The > easiest method is to use the cmsBuildTabulatedToneCurve16 with the > resulting values converted to the 0 - 65535 range. (But also got advice to > use an 1D LUT table, but the ToneCurves are needs to be enough) > > > > Everything seems right and works flawlessly, except the results are not > (very) linear and the classic 'bullseye' images are wrong.... > > > > > > From anyone who tried to do similar linearizations in the past or any hint > or help would be very helpful for me. > > > > Many thanks, > > Tamas > > > > > |
From: <mar...@li...> - 2023-06-15 20:06:43
|
Hello, I have written a small program to check this and found it works fine to me. At first glance I see a couple of things on your code, but didn't analyze in detail. float_xyz[] do not compile, you need to set the size, which at least should be 3. Another thing is the formatters TYPE_RGB_FLT_PLANAR and TYPE_XYZ_FLT_PLANAR that are not in lcms2.h, therefore you have defined them elsewhere. Check if correct. Anyway, this is the program I did that gives the right values. #include "lcms2.h" #define TYPE_RGB_FLT_PLANAR (FLOAT_SH(1)|COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(4)|PLANAR_SH(1)) #define TYPE_XYZ_FLT_PLANAR (FLOAT_SH(1)|COLORSPACE_SH(PT_XYZ)|CHANNELS_SH(3)|BYTES_SH(4)|PLANAR_SH(1)) int main() { float rgb[] = { 0.75f, 0.5f, 0.3f }; float xyz[3]; cmsHPROFILE srgb_icc = cmsCreate_sRGBProfile(); cmsHPROFILE xyz_icc = cmsCreateXYZProfile(); cmsHTRANSFORM workingtoxyz = cmsCreateTransform(srgb_icc, TYPE_RGB_FLT_PLANAR, xyz_icc, TYPE_XYZ_FLT_PLANAR, INTENT_PERCEPTUAL, 0); cmsCloseProfile(xyz_icc); cmsCloseProfile(srgb_icc); cmsDoTransform(workingtoxyz, rgb, xyz, 1); printf("LCMS rgb2xyz: %f %f %f\n", xyz[0], xyz[1], xyz[2]); cmsDeleteTransform(workingtoxyz); return 0; } Output: LCMS rgb2xyz: 0.320747 0.274139 0.080336 You can verify the values using this calculator http://www.brucelindbloom.com/index.html?ColorCalculator.html Hope that helps Marti Maria The LittleCMS Project https://www.littlecms.com > -----Original Message----- > From: Adrian Knagg-Baugh <aje...@gm...> > Sent: Thursday, June 15, 2023 8:54 PM > To: lcm...@li... > Subject: [Lcms-user] RGB to XYZ conversion > > Hello, > > I'm trying to convert data from a source RGB colorspace to HSLuv (that color > space is a bit niche but I specifically want to use it for a saturation stretching > function). I did an initial test using the C implementation from hsluv.org and > sRGB source data and it works well, but I want to be able to cope with any RGB > source profile so my plan was to use LittleCMS to convert the source data to > XYZ and then use the hsluv.org functions to convert XYZ to HSLuv. > > However I'm getting unexpected results from the initial conversion to XYZ and > I wonder if I'm doing something wrong. Here's what I'm trying, first I make a > transform: > ``` > cmsHPROFILE xyz = cmsCreateXYZProfile(); > cmsUInt32Number formatrgb = TYPE_RGB_FLT_PLANAR; > cmsUInt32Number formatxyz = TYPE_XYZ_FLT_PLANAR; > cmsHTRANSFORM workingtoxyz = cmsCreateTransform(gfit.icc_profile, > formatrgb, xyz, formatxyz, com.pref.icc.processing_intent, 0); > cmsCloseProfile(xyz); > ``` > gfit.icc_profile is a cmsHPROFILE and contains a sRGB profile, and > com.pref.processing_intent is set to INTENT_PERCEPTUAL: those work fine > throughout the rest of the code. > But when I apply it with cmsDoTransform() the effect on an image looks > completely wrong compared with my initial test using hsluv's rgb2xyz() > function. I tested the RGB to XYZ conversion using the following: > ``` > float test_rgb[] = {0.75f, 0.5f, 0.3f}; > float test_xyz[]; > printf("RGB test: %f %f %f\n", test_rgb[0], test_rgb[1], test_rgb[2]); > hsluv_rgbtoxyz(test_rgb[0], test_rgb[1], test_rgb[2], &test_xyz[0], > &test_xyz[1], &test_xyz[2]); > printf("HSLuv rgb2xyz: %f %f %f\n", test_xyz[0], test_xyz[1], test_xyz[2]); > cmsDoTransform(workingtoxyz, (void*) &test_rgb, (void*) &test_xyz, 1); > printf("LCMS rgb2xyz: %f %f %f\n", test_xyz[0], test_xyz[1], test_xyz[2]); ``` > And the results are completely different: > > HSLuv rgb2xyz: 0.305239 0.269471 0.105229 LCMS rgb2xyz: 0.160394 > 0.137083 0.040251 > > I assume I'm doing something wrong but I can't see what - grateful for any > help you can offer. > > Thanks, > > Adrian. > > > _______________________________________________ > Lcms-user mailing list > Lcm...@li... > https://lists.sourceforge.net/lists/listinfo/lcms-user |
From: Adrian Knagg-B. <aje...@gm...> - 2023-06-15 18:53:53
|
Hello, I'm trying to convert data from a source RGB colorspace to HSLuv (that color space is a bit niche but I specifically want to use it for a saturation stretching function). I did an initial test using the C implementation from hsluv.org and sRGB source data and it works well, but I want to be able to cope with any RGB source profile so my plan was to use LittleCMS to convert the source data to XYZ and then use the hsluv.org functions to convert XYZ to HSLuv. However I'm getting unexpected results from the initial conversion to XYZ and I wonder if I'm doing something wrong. Here's what I'm trying, first I make a transform: ``` cmsHPROFILE xyz = cmsCreateXYZProfile(); cmsUInt32Number formatrgb = TYPE_RGB_FLT_PLANAR; cmsUInt32Number formatxyz = TYPE_XYZ_FLT_PLANAR; cmsHTRANSFORM workingtoxyz = cmsCreateTransform(gfit.icc_profile, formatrgb, xyz, formatxyz, com.pref.icc.processing_intent, 0); cmsCloseProfile(xyz); ``` gfit.icc_profile is a cmsHPROFILE and contains a sRGB profile, and com.pref.processing_intent is set to INTENT_PERCEPTUAL: those work fine throughout the rest of the code. But when I apply it with cmsDoTransform() the effect on an image looks completely wrong compared with my initial test using hsluv's rgb2xyz() function. I tested the RGB to XYZ conversion using the following: ``` float test_rgb[] = {0.75f, 0.5f, 0.3f}; float test_xyz[]; printf("RGB test: %f %f %f\n", test_rgb[0], test_rgb[1], test_rgb[2]); hsluv_rgbtoxyz(test_rgb[0], test_rgb[1], test_rgb[2], &test_xyz[0], &test_xyz[1], &test_xyz[2]); printf("HSLuv rgb2xyz: %f %f %f\n", test_xyz[0], test_xyz[1], test_xyz[2]); cmsDoTransform(workingtoxyz, (void*) &test_rgb, (void*) &test_xyz, 1); printf("LCMS rgb2xyz: %f %f %f\n", test_xyz[0], test_xyz[1], test_xyz[2]); ``` And the results are completely different: HSLuv rgb2xyz: 0.305239 0.269471 0.105229 LCMS rgb2xyz: 0.160394 0.137083 0.040251 I assume I'm doing something wrong but I can't see what - grateful for any help you can offer. Thanks, Adrian. |
From: <mar...@li...> - 2023-06-15 07:56:39
|
Hello, When doing this kind of things, it is important to keep in mind the real goals of the process because sometimes is very easy to get lost in details. “Linearization” is a term that I’ve seen used to a multitude of scenarios. A valid approach when profiling a printer is to do it on two steps. The first step would be to bring the particular printer to a generic well-known state. For example, by using C, M Y and K tone curves, one per output channel. Then profile this generic printer. The first step is known as “linearization”. The obvious advantage of this approach is you have not to reprofile your printer often but just recompute the curves, which is by far cheaper and faster. Another situation when the term linearization is used is when you want a profile to “match” the characteristics of a given metric. Examples of this are to create an RGB device space that behaves linearly on Luma. Some of the linearization goal metrics are intuitive, others are not. For example, when linearizing CMYK, you can use L* on all channels but on Yellow. Reason is yellow contributes poorly to L*, and is better to use b* in this case. Other metrics can be optical density or its derivatives. So, assuming you want a tone curve to make a gray device space to behave linearly with L*, you could print a scale of 10-20 patches and then measure it. With the obtained values perform reverse interpolation. For each L* you will obtain which device gray value to print. With those values build a tone curve and you got the linearization. As a test, your tone curve should match the printed values. When doing multidimensional, things go more complex though. Hope that helps Regards Marti Maria The LittleCMS Project https://www.littlecms.com From: Tamas Littmann <lit...@gm...> Sent: Wednesday, June 14, 2023 1:39 PM To: lcm...@li... Subject: [Lcms-user] Linearization Hello, I have used LCMS for image color space transforms for lots of years, but I am relatively new in creating my own profiles. Using C# and .NET, I can do most of the creating process successfully. However, it seems that I cannot move on from some of the easiest steps (I think I understand the process, but the results are not satisfactory). Here, I try to minimize the problem, and use 1D transforms (linearization curve) and Grayscale space (only 1 color). In this case, how can I linearize a black&white grayscale image/printer? Here is what I tried to do: 1. Print an equal step grayscale ramp (in grayscale mode, using 8-bit 0 - 255 values. E.g: for six steps it's 0/51/102/153/204/255). 52 steps seems to be a good starting point (steps are 0 - 5 - 10 - 15 - 20 - etc..) 2. I have an X-Rite i1 / Datacolor Spyder, so I can read the values in LAB format (saved CGATS files). 3. White Point LAB L* is usually around 94, black point LAB L* is usually from 3 - 15, depends the type of media, so i need to slice this range to equal steps to find the linear values (if i want something else, not like a linear line, but a special curve, i need to slice this range according to that curves). 4. Normalize both LAB L* data arrays to a 0.0 - 100.0 range. 5. Find the difference between the measured ones and the linear ones. 6. Used those differences to calculate LAB L* -> Grayscale values. (This is the point where I think I misunderstand something). Normally I added these difference values to the original source Gray -> LAB L* values. I can use the corrected LAB L* values to create normal output profiles, or can use the Grayscale values to create a simple DeviceLink profile. The easiest method is to use the cmsBuildTabulatedToneCurve16 with the resulting values converted to the 0 - 65535 range. (But also got advice to use an 1D LUT table, but the ToneCurves are needs to be enough) Everything seems right and works flawlessly, except the results are not (very) linear and the classic 'bullseye' images are wrong.... >From anyone who tried to do similar linearizations in the past or any hint or help would be very helpful for me. Many thanks, Tamas |
From: Tamas L. <lit...@gm...> - 2023-06-14 11:39:14
|
Hello, I have used LCMS for image color space transforms for lots of years, but I am relatively new in creating my own profiles. Using C# and .NET, I can do most of the creating process successfully. However, it seems that I cannot move on from some of the easiest steps (I think I understand the process, but the results are not satisfactory). Here, I try to minimize the problem, and use 1D transforms (linearization curve) and Grayscale space (only 1 color). In this case, how can I linearize a black&white grayscale image/printer? Here is what I tried to do: 1. Print an equal step grayscale ramp (in grayscale mode, using 8-bit 0 - 255 values. E.g: for six steps it's 0/51/102/153/204/255). 52 steps seems to be a good starting point (steps are 0 - 5 - 10 - 15 - 20 - etc..) 2. I have an X-Rite i1 / Datacolor Spyder, so I can read the values in LAB format (saved CGATS files). 3. White Point LAB L* is usually around 94, black point LAB L* is usually from 3 - 15, depends the type of media, so i need to slice this range to equal steps to find the linear values (if i want something else, not like a linear line, but a special curve, i need to slice this range according to that curves). 4. Normalize both LAB L* data arrays to a 0.0 - 100.0 range. 5. Find the difference between the measured ones and the linear ones. 6. Used those differences to calculate LAB L* -> Grayscale values. (This is the point where I think I misunderstand something). Normally I added these difference values to the original source Gray -> LAB L* values. I can use the corrected LAB L* values to create normal output profiles, or can use the Grayscale values to create a simple DeviceLink profile. The easiest method is to use the cmsBuildTabulatedToneCurve16 with the resulting values converted to the 0 - 65535 range. (But also got advice to use an 1D LUT table, but the ToneCurves are needs to be enough) Everything seems right and works flawlessly, except the results are not (very) linear and the classic 'bullseye' images are wrong.... >From anyone who tried to do similar linearizations in the past or any hint or help would be very helpful for me. Many thanks, Tamas |
From: John J. <j.j...@nt...> - 2023-05-04 17:08:17
|
Many thanks Marti, John On 04/05/2023 15:46, mar...@li... wrote: > Hi, > > Problem is if I change this 100 scaling, I break photoshop notation, and many people is using that. > > A neat solution would be writing a formatter plug-in to replace double encoding to the scale you need. You could copy & paste the formatters code you want to change from cmspack.c and modify it. > > You probably not need all the variants, so you could simplify the code and get some throughput boost. > See some examples on plug-ins manual, "Formatters plug-in" > > Regards > Marti Maria > The LittleCMS Project > https://www.littlecms.com > > > >> -----Original Message----- >> From: John Jefferies via Lcms-user <lcm...@li...> >> Sent: Thursday, May 4, 2023 2:13 PM >> To: lcm...@li... >> Subject: [Lcms-user] Device space float ranges >> >> Hello Marti, >> I have a system where all colour spaces are device spaces (PT_GRAY, PT_RGB, >> PT_CMYK, PT_MCH*), and all colour values are floats in the range of 0-1. I >> therefore need a formatter to handle this, so I use this >> formatter: >> cmsFormatterForColorspaceOfProfile(hProfile, sizeof(float), TRUE) >> >> It appears that lcms assumes that the client's float colour values are in the >> range 0-100 if colour space is an IsInkSpace(). The problem then becomes >> how to marshal my float values into and out of lcms. It appears that in client >> code, I have to ensure the values are *100 or /100 as appropriate if the colour >> space I have is an ink space. >> >> For my purposes, that's a bit daft. Firstly, IsInkSpace() isn't an exported >> function so the client code has to duplicate the function itself. Secondly, it's >> rather inefficient. Thirdly, the client code is uglier than it needs to be. Finally, >> the assumed range of 0-100 isn't documented anywhere that I could find; >> apologies if it is somewhere blindingly obvious. >> >> Is there any other way to use float values in the range 0-1? >> >> Regards + many thanks >> John >> >> >> >> _______________________________________________ >> Lcms-user mailing list >> Lcm...@li... >> https://lists.sourceforge.net/lists/listinfo/lcms-user |
From: <mar...@li...> - 2023-05-04 15:36:18
|
Hi, Problem is if I change this 100 scaling, I break photoshop notation, and many people is using that. A neat solution would be writing a formatter plug-in to replace double encoding to the scale you need. You could copy & paste the formatters code you want to change from cmspack.c and modify it. You probably not need all the variants, so you could simplify the code and get some throughput boost. See some examples on plug-ins manual, "Formatters plug-in" Regards Marti Maria The LittleCMS Project https://www.littlecms.com > -----Original Message----- > From: John Jefferies via Lcms-user <lcm...@li...> > Sent: Thursday, May 4, 2023 2:13 PM > To: lcm...@li... > Subject: [Lcms-user] Device space float ranges > > Hello Marti, > I have a system where all colour spaces are device spaces (PT_GRAY, PT_RGB, > PT_CMYK, PT_MCH*), and all colour values are floats in the range of 0-1. I > therefore need a formatter to handle this, so I use this > formatter: > cmsFormatterForColorspaceOfProfile(hProfile, sizeof(float), TRUE) > > It appears that lcms assumes that the client's float colour values are in the > range 0-100 if colour space is an IsInkSpace(). The problem then becomes > how to marshal my float values into and out of lcms. It appears that in client > code, I have to ensure the values are *100 or /100 as appropriate if the colour > space I have is an ink space. > > For my purposes, that's a bit daft. Firstly, IsInkSpace() isn't an exported > function so the client code has to duplicate the function itself. Secondly, it's > rather inefficient. Thirdly, the client code is uglier than it needs to be. Finally, > the assumed range of 0-100 isn't documented anywhere that I could find; > apologies if it is somewhere blindingly obvious. > > Is there any other way to use float values in the range 0-1? > > Regards + many thanks > John > > > > _______________________________________________ > Lcms-user mailing list > Lcm...@li... > https://lists.sourceforge.net/lists/listinfo/lcms-user |