xref: /reactos/dll/win32/mscms/transform.c (revision eb856c35)
1 /*
2  * MSCMS - Color Management System for Wine
3  *
4  * Copyright 2005, 2006, 2008 Hans Leidekker
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20 
21 #include "config.h"
22 #include "wine/debug.h"
23 
24 #include <stdarg.h>
25 
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winnls.h"
29 #include "wingdi.h"
30 #include "winuser.h"
31 #include "icm.h"
32 
33 #include "mscms_priv.h"
34 
35 WINE_DEFAULT_DEBUG_CHANNEL(mscms);
36 
37 #ifdef HAVE_LCMS2
38 
from_bmformat(BMFORMAT format)39 static DWORD from_bmformat( BMFORMAT format )
40 {
41     static BOOL quietfixme = FALSE;
42     DWORD ret;
43 
44     switch (format)
45     {
46     case BM_RGBTRIPLETS: ret = TYPE_RGB_8; break;
47     case BM_BGRTRIPLETS: ret = TYPE_BGR_8; break;
48     case BM_GRAY:        ret = TYPE_GRAY_8; break;
49     case BM_xRGBQUADS:   ret = TYPE_ARGB_8; break;
50     case BM_xBGRQUADS:   ret = TYPE_ABGR_8; break;
51     case BM_KYMCQUADS:   ret = TYPE_KYMC_8; break;
52     default:
53         if (!quietfixme)
54         {
55             FIXME( "unhandled bitmap format %08x\n", format );
56             quietfixme = TRUE;
57         }
58         ret = TYPE_RGB_8;
59         break;
60     }
61     TRACE( "color space: %08x -> %08x\n", format, ret );
62     return ret;
63 }
64 
from_type(COLORTYPE type)65 static DWORD from_type( COLORTYPE type )
66 {
67     DWORD ret;
68 
69     switch (type)
70     {
71     case COLOR_GRAY: ret = TYPE_GRAY_16; break;
72     case COLOR_RGB:  ret = TYPE_RGB_16; break;
73     case COLOR_XYZ:  ret = TYPE_XYZ_16; break;
74     case COLOR_Yxy:  ret = TYPE_Yxy_16; break;
75     case COLOR_Lab:  ret = TYPE_Lab_16; break;
76     case COLOR_CMYK: ret = TYPE_CMYK_16; break;
77     default:
78         FIXME( "unhandled color type %08x\n", type );
79         ret = TYPE_RGB_16;
80         break;
81     }
82 
83     TRACE( "color type: %08x -> %08x\n", type, ret );
84     return ret;
85 }
86 
87 #endif /* HAVE_LCMS2 */
88 
89 /******************************************************************************
90  * CreateColorTransformA            [MSCMS.@]
91  *
92  * See CreateColorTransformW.
93  */
CreateColorTransformA(LPLOGCOLORSPACEA space,HPROFILE dest,HPROFILE target,DWORD flags)94 HTRANSFORM WINAPI CreateColorTransformA( LPLOGCOLORSPACEA space, HPROFILE dest,
95     HPROFILE target, DWORD flags )
96 {
97     LOGCOLORSPACEW spaceW;
98     DWORD len;
99 
100     TRACE( "( %p, %p, %p, 0x%08x )\n", space, dest, target, flags );
101 
102     if (!space || !dest) return FALSE;
103 
104     memcpy( &spaceW, space, FIELD_OFFSET(LOGCOLORSPACEA, lcsFilename) );
105     spaceW.lcsSize = sizeof(LOGCOLORSPACEW);
106 
107     len = MultiByteToWideChar( CP_ACP, 0, space->lcsFilename, -1, NULL, 0 );
108     MultiByteToWideChar( CP_ACP, 0, space->lcsFilename, -1, spaceW.lcsFilename, len );
109 
110     return CreateColorTransformW( &spaceW, dest, target, flags );
111 }
112 
113 /******************************************************************************
114  * CreateColorTransformW            [MSCMS.@]
115  *
116  * Create a color transform.
117  *
118  * PARAMS
119  *  space  [I] Input color space.
120  *  dest   [I] Color profile of destination device.
121  *  target [I] Color profile of target device.
122  *  flags  [I] Flags.
123  *
124  * RETURNS
125  *  Success: Handle to a transform.
126  *  Failure: NULL
127  */
CreateColorTransformW(LPLOGCOLORSPACEW space,HPROFILE dest,HPROFILE target,DWORD flags)128 HTRANSFORM WINAPI CreateColorTransformW( LPLOGCOLORSPACEW space, HPROFILE dest,
129     HPROFILE target, DWORD flags )
130 {
131     HTRANSFORM ret = NULL;
132 #ifdef HAVE_LCMS2
133     struct transform transform;
134     struct profile *dst, *tgt = NULL;
135     cmsHPROFILE cmsinput, cmsoutput, cmstarget = NULL;
136     DWORD proofing = 0;
137     int intent;
138 
139     TRACE( "( %p, %p, %p, 0x%08x )\n", space, dest, target, flags );
140 
141     if (!space || !(dst = grab_profile( dest ))) return FALSE;
142 
143     if (target && !(tgt = grab_profile( target )))
144     {
145         release_profile( dst );
146         return FALSE;
147     }
148     intent = space->lcsIntent > 3 ? INTENT_PERCEPTUAL : space->lcsIntent;
149 
150     TRACE( "lcsIntent:   %x\n", space->lcsIntent );
151     TRACE( "lcsCSType:   %s\n", dbgstr_tag( space->lcsCSType ) );
152     TRACE( "lcsFilename: %s\n", debugstr_w( space->lcsFilename ) );
153 
154     cmsinput = cmsCreate_sRGBProfile(); /* FIXME: create from supplied color space */
155     if (target)
156     {
157         proofing = cmsFLAGS_SOFTPROOFING;
158         cmstarget = tgt->cmsprofile;
159     }
160     cmsoutput = dst->cmsprofile;
161     transform.cmstransform = cmsCreateProofingTransform(cmsinput, 0, cmsoutput, 0, cmstarget,
162                                                         intent, INTENT_ABSOLUTE_COLORIMETRIC,
163                                                         proofing);
164     if (!transform.cmstransform)
165     {
166         if (tgt) release_profile( tgt );
167         release_profile( dst );
168         return FALSE;
169     }
170 
171     ret = create_transform( &transform );
172 
173     if (tgt) release_profile( tgt );
174     release_profile( dst );
175 
176 #endif /* HAVE_LCMS2 */
177     return ret;
178 }
179 
180 /******************************************************************************
181  * CreateMultiProfileTransform      [MSCMS.@]
182  *
183  * Create a color transform from an array of color profiles.
184  *
185  * PARAMS
186  *  profiles  [I] Array of color profiles.
187  *  nprofiles [I] Number of color profiles.
188  *  intents   [I] Array of rendering intents.
189  *  flags     [I] Flags.
190  *  cmm       [I] Profile to take the CMM from.
191  *
192  * RETURNS
193  *  Success: Handle to a transform.
194  *  Failure: NULL
195  */
CreateMultiProfileTransform(PHPROFILE profiles,DWORD nprofiles,PDWORD intents,DWORD nintents,DWORD flags,DWORD cmm)196 HTRANSFORM WINAPI CreateMultiProfileTransform( PHPROFILE profiles, DWORD nprofiles,
197     PDWORD intents, DWORD nintents, DWORD flags, DWORD cmm )
198 {
199     HTRANSFORM ret = NULL;
200 #ifdef HAVE_LCMS2
201     cmsHPROFILE *cmsprofiles;
202     struct transform transform;
203     struct profile *profile0, *profile1;
204 
205     TRACE( "( %p, 0x%08x, %p, 0x%08x, 0x%08x, 0x%08x )\n",
206            profiles, nprofiles, intents, nintents, flags, cmm );
207 
208     if (!profiles || !nprofiles || !intents) return NULL;
209 
210     if (nprofiles > 2)
211     {
212         FIXME("more than 2 profiles not supported\n");
213         return NULL;
214     }
215 
216     profile0 = grab_profile( profiles[0] );
217     if (!profile0) return NULL;
218     profile1 = grab_profile( profiles[1] );
219     if (!profile1)
220     {
221         release_profile( profile0 );
222         return NULL;
223     }
224 
225     if ((cmsprofiles = HeapAlloc( GetProcessHeap(), 0, (nprofiles + 1) * sizeof(cmsHPROFILE) )))
226     {
227         cmsprofiles[0] = profile0->cmsprofile;
228         cmsprofiles[1] = profile1->cmsprofile;
229 
230         transform.cmstransform = cmsCreateMultiprofileTransform( cmsprofiles, nprofiles, 0,
231                                                                  0, *intents, 0 );
232         HeapFree( GetProcessHeap(), 0, cmsprofiles );
233         if (!transform.cmstransform)
234         {
235             release_profile( profile0 );
236             release_profile( profile1 );
237             return FALSE;
238         }
239         ret = create_transform( &transform );
240     }
241 
242     release_profile( profile0 );
243     release_profile( profile1 );
244 
245 #endif /* HAVE_LCMS2 */
246     return ret;
247 }
248 
249 /******************************************************************************
250  * DeleteColorTransform             [MSCMS.@]
251  *
252  * Delete a color transform.
253  *
254  * PARAMS
255  *  transform [I] Handle to a color transform.
256  *
257  * RETURNS
258  *  Success: TRUE
259  *  Failure: FALSE
260  */
DeleteColorTransform(HTRANSFORM handle)261 BOOL WINAPI DeleteColorTransform( HTRANSFORM handle )
262 {
263     BOOL ret = FALSE;
264 #ifdef HAVE_LCMS2
265 
266     TRACE( "( %p )\n", handle );
267 
268     ret = close_transform( handle );
269 
270 #endif /* HAVE_LCMS2 */
271     return ret;
272 }
273 
274 /******************************************************************************
275  * TranslateBitmapBits              [MSCMS.@]
276  *
277  * Perform color translation.
278  *
279  * PARAMS
280  *  transform    [I] Handle to a color transform.
281  *  srcbits      [I] Source bitmap.
282  *  input        [I] Format of the source bitmap.
283  *  width        [I] Width of the source bitmap.
284  *  height       [I] Height of the source bitmap.
285  *  inputstride  [I] Number of bytes in one scanline.
286  *  destbits     [I] Destination bitmap.
287  *  output       [I] Format of the destination bitmap.
288  *  outputstride [I] Number of bytes in one scanline.
289  *  callback     [I] Callback function.
290  *  data         [I] Callback data.
291  *
292  * RETURNS
293  *  Success: TRUE
294  *  Failure: FALSE
295  */
TranslateBitmapBits(HTRANSFORM handle,PVOID srcbits,BMFORMAT input,DWORD width,DWORD height,DWORD inputstride,PVOID destbits,BMFORMAT output,DWORD outputstride,PBMCALLBACKFN callback,ULONG data)296 BOOL WINAPI TranslateBitmapBits( HTRANSFORM handle, PVOID srcbits, BMFORMAT input,
297     DWORD width, DWORD height, DWORD inputstride, PVOID destbits, BMFORMAT output,
298     DWORD outputstride, PBMCALLBACKFN callback, ULONG data )
299 {
300     BOOL ret = FALSE;
301 #ifdef HAVE_LCMS2
302     struct transform *transform = grab_transform( handle );
303 
304     TRACE( "( %p, %p, 0x%08x, 0x%08x, 0x%08x, 0x%08x, %p, 0x%08x, 0x%08x, %p, 0x%08x )\n",
305            handle, srcbits, input, width, height, inputstride, destbits, output,
306            outputstride, callback, data );
307 
308     if (!transform) return FALSE;
309     if (!cmsChangeBuffersFormat( transform->cmstransform, from_bmformat(input), from_bmformat(output) ))
310         return FALSE;
311 
312     cmsDoTransform( transform->cmstransform, srcbits, destbits, width * height );
313     release_transform( transform );
314     ret = TRUE;
315 
316 #endif /* HAVE_LCMS2 */
317     return ret;
318 }
319 
320 /******************************************************************************
321  * TranslateColors              [MSCMS.@]
322  *
323  * Perform color translation.
324  *
325  * PARAMS
326  *  transform    [I] Handle to a color transform.
327  *  input        [I] Array of input colors.
328  *  number       [I] Number of colors to translate.
329  *  input_type   [I] Input color format.
330  *  output       [O] Array of output colors.
331  *  output_type  [I] Output color format.
332  *
333  * RETURNS
334  *  Success: TRUE
335  *  Failure: FALSE
336  */
TranslateColors(HTRANSFORM handle,PCOLOR in,DWORD count,COLORTYPE input_type,PCOLOR out,COLORTYPE output_type)337 BOOL WINAPI TranslateColors( HTRANSFORM handle, PCOLOR in, DWORD count,
338                              COLORTYPE input_type, PCOLOR out, COLORTYPE output_type )
339 {
340 #ifdef HAVE_LCMS2
341     BOOL ret = TRUE;
342     struct transform *transform = grab_transform( handle );
343     cmsHTRANSFORM xfrm;
344     unsigned int i;
345 
346     TRACE( "( %p, %p, %d, %d, %p, %d )\n", handle, in, count, input_type, out, output_type );
347 
348     if (!transform) return FALSE;
349 
350     xfrm = transform->cmstransform;
351     if (!cmsChangeBuffersFormat( xfrm, from_type(input_type), from_type(output_type) ))
352         return FALSE;
353 
354     switch (input_type)
355     {
356     case COLOR_RGB:
357     {
358         switch (output_type)
359         {
360         case COLOR_RGB:  for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].rgb, &out[i].rgb, 1 ); goto done;
361         case COLOR_Lab:  for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].rgb, &out[i].Lab, 1 ); goto done;
362         case COLOR_GRAY: for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].rgb, &out[i].gray, 1 ); goto done;
363         case COLOR_CMYK: for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].rgb, &out[i].cmyk, 1 ); goto done;
364         case COLOR_XYZ:  for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].rgb, &out[i].XYZ, 1 ); goto done;
365         default:
366             FIXME("unhandled input/output pair: %d/%d\n", input_type, output_type);
367             ret = FALSE;
368             break;
369         }
370         break;
371     }
372     case COLOR_Lab:
373     {
374         switch (output_type)
375         {
376         case COLOR_RGB:  for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].Lab, &out[i].rgb, 1 ); goto done;
377         case COLOR_Lab:  for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].Lab, &out[i].Lab, 1 ); goto done;
378         case COLOR_GRAY: for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].Lab, &out[i].gray, 1 ); goto done;
379         case COLOR_CMYK: for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].Lab, &out[i].cmyk, 1 ); goto done;
380         case COLOR_XYZ:  for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].Lab, &out[i].XYZ, 1 ); goto done;
381         default:
382             FIXME("unhandled input/output pair: %d/%d\n", input_type, output_type);
383             ret = FALSE;
384             break;
385         }
386         break;
387     }
388     case COLOR_GRAY:
389     {
390         switch (output_type)
391         {
392         case COLOR_RGB:  for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].gray, &out[i].rgb, 1 ); goto done;
393         case COLOR_Lab:  for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].gray, &out[i].Lab, 1 ); goto done;
394         case COLOR_GRAY: for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].gray, &out[i].gray, 1 ); goto done;
395         case COLOR_CMYK: for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].gray, &out[i].cmyk, 1 ); goto done;
396         case COLOR_XYZ:  for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].gray, &out[i].XYZ, 1 ); goto done;
397         default:
398             FIXME("unhandled input/output pair: %d/%d\n", input_type, output_type);
399             ret = FALSE;
400             break;
401         }
402         break;
403     }
404     case COLOR_CMYK:
405     {
406         switch (output_type)
407         {
408         case COLOR_RGB:  for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].cmyk, &out[i].rgb, 1 ); goto done;
409         case COLOR_Lab:  for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].cmyk, &out[i].Lab, 1 ); goto done;
410         case COLOR_GRAY: for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].cmyk, &out[i].gray, 1 ); goto done;
411         case COLOR_CMYK: for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].cmyk, &out[i].cmyk, 1 ); goto done;
412         case COLOR_XYZ:  for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].cmyk, &out[i].XYZ, 1 ); goto done;
413         default:
414             FIXME("unhandled input/output pair: %d/%d\n", input_type, output_type);
415             ret = FALSE;
416             break;
417         }
418         break;
419     }
420     case COLOR_XYZ:
421     {
422         switch (output_type)
423         {
424         case COLOR_RGB:  for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].XYZ, &out[i].rgb, 1 ); goto done;
425         case COLOR_Lab:  for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].XYZ, &out[i].Lab, 1 ); goto done;
426         case COLOR_GRAY: for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].XYZ, &out[i].gray, 1 ); goto done;
427         case COLOR_CMYK: for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].XYZ, &out[i].cmyk, 1 ); goto done;
428         case COLOR_XYZ:  for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].XYZ, &out[i].XYZ, 1 ); goto done;
429         default:
430             FIXME("unhandled input/output pair: %d/%d\n", input_type, output_type);
431             ret = FALSE;
432             break;
433         }
434         break;
435     }
436     default:
437         FIXME("unhandled input/output pair: %d/%d\n", input_type, output_type);
438         ret = FALSE;
439         break;
440     }
441 
442 done:
443     release_transform( transform );
444     return ret;
445 
446 #else  /* HAVE_LCMS2 */
447     return FALSE;
448 #endif /* HAVE_LCMS2 */
449 }
450