Thread: [Lcms-user] Difficulty with cmsTransform in C#
An ICC-based CMM for color management
Brought to you by:
mm2
|
From: Roger B. <gr...@vi...> - 2016-06-16 19:40:32
|
Tengo una pequena problema...
I need to convert 400 RGB values to Lab using a monitor profile.
I use the following C# code :
string Source = "Monitor.icm";
IntPtr hSource = cmsOpenProfileFromFile(Source, "r");
xform = cmsCreateTransform(hSource, TYPE_RGB_DBL, hLab2, TYPE_Lab_DBL,
INTENT_ABSOLUTE_COLORIMETRIC, 0);
for (int i = 0; i < 400; i++)
{
input[0] = R[i];
input[1] = G[i];
input[2] = B[i];
cmsDoTransform(xform, input, output, 1);
L = output[0];
a = output[1];
b = output[2];
}
First time through the loop I get valid Lab results.
But subsequent passage through the loop always return the same Lab values?
The input[] values do change as expected.
When I use this code outside of a loop, it works perfect.
/ Roger Breton
|
|
From: Edgar L. <lo...@co...> - 2016-06-17 07:12:03
|
Did you declare input[] and output[] as volatile? (s. https://msdn.microsoft.com/de-de/library/x13ttww7.aspx) Edgar Am 16.06.2016 um 21:25 schrieb Roger Breton: > Tengo una pequena problema... > > I need to convert 400 RGB values to Lab using a monitor profile. > > I use the following C# code : > > string Source = "Monitor.icm"; > IntPtr hSource = cmsOpenProfileFromFile(Source, "r"); > > xform = cmsCreateTransform(hSource, TYPE_RGB_DBL, hLab2, TYPE_Lab_DBL, > INTENT_ABSOLUTE_COLORIMETRIC, 0); > > for (int i = 0; i < 400; i++) > { > input[0] = R[i]; > input[1] = G[i]; > input[2] = B[i]; > > cmsDoTransform(xform, input, output, 1); > > L = output[0]; > a = output[1]; > b = output[2]; > } > > First time through the loop I get valid Lab results. > But subsequent passage through the loop always return the same Lab values? > The input[] values do change as expected. > > When I use this code outside of a loop, it works perfect. > > / Roger Breton > > > ------------------------------------------------------------------------------ > What NetFlow Analyzer can do for you? Monitors network bandwidth and traffic > patterns at an interface-level. Reveals which users, apps, and protocols are > consuming the most bandwidth. Provides multi-vendor support for NetFlow, > J-Flow, sFlow and other flows. Make informed decisions using capacity planning > reports. http://sdm.link/zohomanageengine > _______________________________________________ > Lcms-user mailing list > Lcm...@li... > https://lists.sourceforge.net/lists/listinfo/lcms-user > -- lakeBits Inh. Edgar Loser Haydnstr. 25 78464 Konstanz Tel 0049 7531 5844154 0 Fax 0049 7531 5844154 9 http://www.colymp.com/ mailto:lo...@co... |
|
From: Marti M. <mar...@li...> - 2016-06-17 07:12:46
|
Hi Roger, I'm not a c# expert, but your code seems fine. I guess the problem is elsewhere... Regards Marti Maria The LittleCMS project http://www.littlecms.com -----Original Message----- From: Roger Breton [mailto:gr...@vi...] Sent: jueves, 16 de junio de 2016 21:25 To: lcm...@li... Subject: [Lcms-user] Difficulty with cmsTransform in C# Tengo una pequena problema... I need to convert 400 RGB values to Lab using a monitor profile. I use the following C# code : string Source = "Monitor.icm"; IntPtr hSource = cmsOpenProfileFromFile(Source, "r"); xform = cmsCreateTransform(hSource, TYPE_RGB_DBL, hLab2, TYPE_Lab_DBL, INTENT_ABSOLUTE_COLORIMETRIC, 0); for (int i = 0; i < 400; i++) { input[0] = R[i]; input[1] = G[i]; input[2] = B[i]; cmsDoTransform(xform, input, output, 1); L = output[0]; a = output[1]; b = output[2]; } First time through the loop I get valid Lab results. But subsequent passage through the loop always return the same Lab values? The input[] values do change as expected. When I use this code outside of a loop, it works perfect. / Roger Breton ---------------------------------------------------------------------------- -- What NetFlow Analyzer can do for you? Monitors network bandwidth and traffic patterns at an interface-level. Reveals which users, apps, and protocols are consuming the most bandwidth. Provides multi-vendor support for NetFlow, J-Flow, sFlow and other flows. Make informed decisions using capacity planning reports. http://sdm.link/zohomanageengine _______________________________________________ Lcms-user mailing list Lcm...@li... https://lists.sourceforge.net/lists/listinfo/lcms-user |
|
From: Roger B. <gr...@vi...> - 2016-06-30 00:27:07
|
If I could develop my application strictly in C, my problems accessing
LittleCMS would be non-existent,
but I need to develop in C# :(
I am seeking help with re-coding the cmsDoTransform declaration.
Right now, I use this :
[DllImport(@lcmsPath, CallingConvention = CallingConvention.Winapi)]
static extern void cmsDoTransform(
IntPtr xform,
[MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2), In] double[]
inputColors,
[MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3), Out] double[]
outputColors, uint Size);
In code, I use this :
double[] input = { 0.5, 0.5, 0.5, 0 };
double[] output = { 0, 0, 0, 0 };
cmsDoTransform(xform, input, output, 1);
As you can see, I pass individual RGB values [in], recovering CMYK values
[out].
The cmsCreateTransform looks like this :
IntPtr xform = cmsCreateTransform(hSRGB, TYPE_RGB_DBL, hDestination,
TYPE_CMYK_DBL, INTENT_RELATIVE_COLORIMETRIC, 0);
Works perfect.
But now, I need to pass 'pixels' (to convert bitmap images) values instead
of individual device values.
Obviously, I need to modify the pinvoke declaration to accommodate the
difference in data type.
I am no C# specialist (maybe someday?) but I read that I may not need very
meticulous marshalling of data between my C# and lcms.dll.
So I am looking for a way to rewrite the declaration to accommodate more
than just 'double'.
In C, the original cmsDoTransform function require a Handle to the Transform
(another pointer), pointers to an input and output buffers, and the size of
the buffer themselves :
cmsDoTransform(cmsHTRANSFORM Transform, const void * InputBuffer,
void * OutputBuffer,
cmsUInt32Number Size);
(Not sure what the 'const' keyword in front of the first void * statement
does?)
So my first awkward/intuitive shot at rewriting the function in C# call
looks like this :
[DllImport(lcms2Path, CallingConvention = CallingConvention.Winapi)]
static extern void cmsDoTransform(IntPtr xform, IntPtr inputColors [in],
IntPtr outputColors [out], uint Size);
I have not tried running this code yet but I have been reading quite a bit
about pointers and how they have a fixed size, no matter the type of data
they point to.
So my question becomes how do I pass pointers to the these buffers in my new
declaration?
I read somewhere about the need to use the keyword 'unsafe' but I am not
sure.
Also read about the need to use the attributes [in] and [out] in marshalling
the data.
(The Marshalling of data is a HUGE topic in itself as I found out through my
hours of reading online)
Ultimately, my goal is is to convert JPEG or TIFF images from one color
space to another through LittleCMS.
Thank you so much in advance for your kind help.
/ Roger Breton
|
|
From: Edgar L. <lo...@co...> - 2016-06-30 08:16:37
|
> If I could develop my application strictly in C, my problems accessing > LittleCMS would be non-existent, > but I need to develop in C# :( Working with C# is not too bad! >[...] > cmsDoTransform(cmsHTRANSFORM Transform, const void * InputBuffer, > void * OutputBuffer, > cmsUInt32Number Size); > > (Not sure what the 'const' keyword in front of the first void * statement > does?) By writing 'const' Marti is telling us, that cmsDoTransform will not touch the data in InputBuffer. I.e. we can either pass a const void* or we can pass a void*. If he would had omit to write 'const' and we would have just a const void* inputBuffer we could not pass this pointer to cmsDoTransform (compiler error)... (s. http://stackoverflow.com/questions/4064286/c-const-keyword-explanation) > [DllImport(lcms2Path, CallingConvention = CallingConvention.Winapi)] > static extern void cmsDoTransform(IntPtr xform, IntPtr inputColors [in], > IntPtr outputColors [out], uint Size); > > So my question becomes how do I pass pointers to the these buffers in my new > declaration? > I read somewhere about the need to use the keyword 'unsafe' but I am not > sure. > Also read about the need to use the attributes [in] and [out] in marshalling > the data. > (The Marshalling of data is a HUGE topic in itself as I found out through my > hours of reading online) > > Ultimately, my goal is is to convert JPEG or TIFF images from one color > space to another through LittleCMS. It's not that difficult... Here is what I'm using (somehow stripped, without error handling, without cleanup...) public static class NativeMethods { [DllImport("lcms2.dll")] public static extern void cmsDoTransform( [In] IntPtr Transform, [In] byte[] InputBuffer, [Out] byte[] OutputBuffer, [In] UInt32 Size); } // We use WPF classes to read binary data of the images: // Namespace: System.Windows.Media.Imaging // Assembly: PresentationCore (in PresentationCore.dll) BitmapDecoder biDec = BitmapDecoder.Create(.....) BitmapFrame biFrm = biDec.Frames[0]; PixelFormat inputFormat = biFrm.Format; uint lcmsInputFormat = 0; FormatConvertedBitmap fcb = null; // if we have an input format that we cannot use direktly in lcms // we have to create a temporary bitmap with lcms compatible format and use this instead of biFrm if (inputFormat == PixelFormats.Bgra32) { lcmsInputFormat = 0x44499; // Lcms.Format.TYPE_BGRA_8; } else if (inputFormat == PixelFormats.Bgr24) { lcmsInputFormat = 0x40419; // Lcms.Format.TYPE_BGR_8; } else { inputFormat = PixelFormats.Bgra32; // we enforce Bgra32 format lcmsInputFormat = 0x44499; // Lcms.Format.TYPE_BGRA_8; fcb = new FormatConvertedBitmap(biFrm, inputFormat, null, 0); if (fcb == null) { throw new Exception("Unable to create FormatConvertedBitmap"); } } // create lcms inputprofile IntPtr inputProfileH = IntPtr.Zero; if (biFrm.ColorContexts != null) { byte[] inputProfile = StreamToArray(biFrm.ColorContexts[0].OpenProfileStream()); inputProfileH = Basic.Lcms.NativeMethods.cmsOpenProfileFromMem(inputProfile, (uint)inputProfile.Length); } else { inputProfileH = Basic.Lcms.NativeMethods.cmsCreate_sRGBProfile(); } IntPtr outputProfileH = .....; // create your lcms output profile IntPtr lcmsTrafo = NativeMethods.cmsCreateTransform( inputProfileH , lcmsInputFormat , outputProfileH , lcmsInputFormat // output format = input format , YourRenderingIntent , 0); // copy image data to byte[] int stride = biFrm.PixelWidth * inputFormat.BitsPerPixel / 8; Byte[] inputBitmapData = new Byte[stride * biFrm.PixelHeight]; if (fcb == null) { // we copy pixel data from original image biFrm.CopyPixels(inputBitmapData, stride, 0); } else { // we copy pixel data from format converted bitmap fcb.CopyPixels(inputBitmapData, stride, 0); } // I have to copy the whole data, to get a copy of alpha channel (lcms 2.7) Byte[] outputBitmapData = inputBitmapData.Clone() as Byte[]; NativeMethods.cmsDoTransform(lcmsTrafo, inputBitmapData, outputBitmapData, (uint)(biFrm.PixelWidth * biFrm.PixelHeight)); // create a new image, based on outputBitmapData: BitmapSource ccb = BitmapSource.Create( biFrm.PixelWidth, biFrm.PixelHeight , biFrm.DpiX, biFrm.DpiY , inputFormat , null , outputBitmapData , stride); // create e.g. .png file: BitmapEncoder biEnc = new PngBitmapEncoder(); biEnc.Frames.Add(BitmapFrame.Create(ccb)); biEnc.Save(YourOutputStream); -- lakeBits Inh. Edgar Loser Haydnstr. 25 78464 Konstanz Tel 0049 7531 5844154 0 Fax 0049 7531 5844154 9 http://www.colymp.com/ mailto:lo...@co... |