Various background processes must be launched detached from current console (if any).
[wine] / dlls / mscms / transform.c
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_LCMS
38
39 static DWORD from_profile( HPROFILE profile )
40 {
41     PROFILEHEADER header;
42
43     GetColorProfileHeader( profile, &header );
44     TRACE( "color space: 0x%08x %s\n", header.phDataColorSpace, MSCMS_dbgstr_tag( header.phDataColorSpace ) );
45
46     switch (header.phDataColorSpace)
47     {
48     case 0x434d594b: return TYPE_CMYK_16;  /* 'CMYK' */
49     case 0x47524159: return TYPE_GRAY_16;  /* 'GRAY' */
50     case 0x4c616220: return TYPE_Lab_16;   /* 'Lab ' */
51     case 0x52474220: return TYPE_RGB_16;   /* 'RGB ' */
52     case 0x58595a20: return TYPE_XYZ_16;   /* 'XYZ ' */
53     default:
54         WARN("unhandled format\n");
55         return TYPE_RGB_16;
56     }
57 }
58
59 static DWORD from_bmformat( BMFORMAT format )
60 {
61     static int quietfixme = 0;
62     TRACE( "bitmap format: 0x%08x\n", format );
63
64     switch (format)
65     {
66     case BM_RGBTRIPLETS: return TYPE_RGB_8;
67     case BM_BGRTRIPLETS: return TYPE_BGR_8;
68     case BM_GRAY:        return TYPE_GRAY_8;
69     case BM_xRGBQUADS:   return TYPE_ARGB_8;
70     case BM_xBGRQUADS:   return TYPE_ABGR_8;
71     default:
72         if (quietfixme == 0)
73         {
74             FIXME("unhandled bitmap format 0x%x\n", format);
75             quietfixme = 1;
76         }
77         return TYPE_RGB_8;
78     }
79 }
80
81 static DWORD from_type( COLORTYPE type )
82 {
83     TRACE( "color type: 0x%08x\n", type );
84
85     switch (type)
86     {
87     case COLOR_GRAY:    return TYPE_GRAY_16;
88     case COLOR_RGB:     return TYPE_RGB_16;
89     case COLOR_XYZ:     return TYPE_XYZ_16;
90     case COLOR_Yxy:     return TYPE_Yxy_16;
91     case COLOR_Lab:     return TYPE_Lab_16;
92     case COLOR_CMYK:    return TYPE_CMYK_16;
93     default:
94         FIXME("unhandled color type\n");
95         return TYPE_RGB_16;
96     }
97 }
98
99 #endif /* HAVE_LCMS */
100
101 /******************************************************************************
102  * CreateColorTransformA            [MSCMS.@]
103  *
104  * See CreateColorTransformW.
105  */
106 HTRANSFORM WINAPI CreateColorTransformA( LPLOGCOLORSPACEA space, HPROFILE dest,
107     HPROFILE target, DWORD flags )
108 {
109     LOGCOLORSPACEW spaceW;
110     DWORD len;
111
112     TRACE( "( %p, %p, %p, 0x%08x )\n", space, dest, target, flags );
113
114     if (!space || !dest) return FALSE;
115
116     memcpy( &spaceW, space, FIELD_OFFSET(LOGCOLORSPACEA, lcsFilename) );
117     spaceW.lcsSize = sizeof(LOGCOLORSPACEW);
118
119     len = MultiByteToWideChar( CP_ACP, 0, space->lcsFilename, -1, NULL, 0 );
120     MultiByteToWideChar( CP_ACP, 0, space->lcsFilename, -1, spaceW.lcsFilename, len );
121
122     return CreateColorTransformW( &spaceW, dest, target, flags );
123 }
124
125 /******************************************************************************
126  * CreateColorTransformW            [MSCMS.@]
127  *
128  * Create a color transform.
129  *
130  * PARAMS
131  *  space  [I] Input color space.
132  *  dest   [I] Color profile of destination device.
133  *  target [I] Color profile of target device.
134  *  flags  [I] Flags.
135  *
136  * RETURNS
137  *  Success: Handle to a transform.
138  *  Failure: NULL
139  */
140 HTRANSFORM WINAPI CreateColorTransformW( LPLOGCOLORSPACEW space, HPROFILE dest,
141     HPROFILE target, DWORD flags )
142 {
143     HTRANSFORM ret = NULL;
144 #ifdef HAVE_LCMS
145     struct transform transform;
146     struct profile *dst, *tgt = NULL;
147     cmsHPROFILE cmsinput, cmsoutput, cmstarget = NULL;
148     DWORD in_format, out_format, proofing = 0;
149     int intent;
150
151     TRACE( "( %p, %p, %p, 0x%08x )\n", space, dest, target, flags );
152
153     if (!space || !(dst = grab_profile( dest ))) return FALSE;
154
155     if (target && !(tgt = grab_profile( target )))
156     {
157         release_profile( dst );
158         return FALSE;
159     }
160     intent = space->lcsIntent > 3 ? INTENT_PERCEPTUAL : space->lcsIntent;
161
162     TRACE( "lcsIntent:   %x\n", space->lcsIntent );
163     TRACE( "lcsCSType:   %s\n", MSCMS_dbgstr_tag( space->lcsCSType ) );
164     TRACE( "lcsFilename: %s\n", debugstr_w( space->lcsFilename ) );
165
166     in_format  = TYPE_RGB_16;
167     out_format = from_profile( dest );
168
169     cmsinput = cmsCreate_sRGBProfile(); /* FIXME: create from supplied color space */
170     if (target)
171     {
172         proofing = cmsFLAGS_SOFTPROOFING;
173         cmstarget = tgt->cmsprofile;
174     }
175     cmsoutput = dst->cmsprofile;
176     transform.cmstransform = cmsCreateProofingTransform(cmsinput, in_format, cmsoutput, out_format, cmstarget,
177                                                         intent, INTENT_ABSOLUTE_COLORIMETRIC, proofing);
178
179     ret = create_transform( &transform );
180
181     if (tgt) release_profile( tgt );
182     release_profile( dst );
183
184 #endif /* HAVE_LCMS */
185     return ret;
186 }
187
188 /******************************************************************************
189  * CreateMultiProfileTransform      [MSCMS.@]
190  *
191  * Create a color transform from an array of color profiles.
192  *
193  * PARAMS
194  *  profiles  [I] Array of color profiles.
195  *  nprofiles [I] Number of color profiles.
196  *  intents   [I] Array of rendering intents.
197  *  flags     [I] Flags.
198  *  cmm       [I] Profile to take the CMM from.
199  *
200  * RETURNS
201  *  Success: Handle to a transform.
202  *  Failure: NULL
203  */ 
204 HTRANSFORM WINAPI CreateMultiProfileTransform( PHPROFILE profiles, DWORD nprofiles,
205     PDWORD intents, DWORD nintents, DWORD flags, DWORD cmm )
206 {
207     HTRANSFORM ret = NULL;
208 #ifdef HAVE_LCMS
209     cmsHPROFILE *cmsprofiles, cmsconvert = NULL;
210     struct transform transform;
211     struct profile *profile0, *profile1;
212     DWORD in_format, out_format;
213
214     TRACE( "( %p, 0x%08x, %p, 0x%08x, 0x%08x, 0x%08x )\n",
215            profiles, nprofiles, intents, nintents, flags, cmm );
216
217     if (!profiles || !nprofiles || !intents) return NULL;
218
219     if (nprofiles > 2)
220     {
221         FIXME("more than 2 profiles not supported\n");
222         return NULL;
223     }
224
225     profile0 = grab_profile( profiles[0] );
226     if (!profile0) return NULL;
227     profile1 = grab_profile( profiles[1] );
228     if (!profile1)
229     {
230         release_profile( profile0 );
231         return NULL;
232     }
233     in_format  = from_profile( profiles[0] );
234     out_format = from_profile( profiles[nprofiles - 1] );
235
236     if (in_format != out_format)
237     {
238         /* insert a conversion profile for pairings that lcms doesn't handle */
239         if (out_format == TYPE_RGB_16) cmsconvert = cmsCreate_sRGBProfile();
240         if (out_format == TYPE_Lab_16) cmsconvert = cmsCreateLabProfile( NULL );
241     }
242
243     cmsprofiles = HeapAlloc( GetProcessHeap(), 0, (nprofiles + 1) * sizeof(cmsHPROFILE) );
244     if (cmsprofiles)
245     {
246         cmsprofiles[0] = profile0->cmsprofile;
247         if (cmsconvert)
248         {
249             cmsprofiles[1] = cmsconvert;
250             cmsprofiles[2] = profile1->cmsprofile;
251             nprofiles++;
252         }
253         else
254         {
255             cmsprofiles[1] = profile1->cmsprofile;
256         }
257         transform.cmstransform = cmsCreateMultiprofileTransform( cmsprofiles, nprofiles, in_format, out_format, *intents, 0 );
258
259         HeapFree( GetProcessHeap(), 0, cmsprofiles );
260         ret = create_transform( &transform );
261     }
262
263     release_profile( profile0 );
264     release_profile( profile1 );
265
266 #endif /* HAVE_LCMS */
267     return ret;
268 }
269
270 /******************************************************************************
271  * DeleteColorTransform             [MSCMS.@]
272  *
273  * Delete a color transform.
274  *
275  * PARAMS
276  *  transform [I] Handle to a color transform.
277  *
278  * RETURNS
279  *  Success: TRUE
280  *  Failure: FALSE
281  */ 
282 BOOL WINAPI DeleteColorTransform( HTRANSFORM handle )
283 {
284     BOOL ret = FALSE;
285 #ifdef HAVE_LCMS
286
287     TRACE( "( %p )\n", handle );
288
289     ret = close_transform( handle );
290
291 #endif /* HAVE_LCMS */
292     return ret;
293 }
294
295 /******************************************************************************
296  * TranslateBitmapBits              [MSCMS.@]
297  *
298  * Perform color translation.
299  *
300  * PARAMS
301  *  transform    [I] Handle to a color transform.
302  *  srcbits      [I] Source bitmap.
303  *  input        [I] Format of the source bitmap.
304  *  width        [I] Width of the source bitmap.
305  *  height       [I] Height of the source bitmap.
306  *  inputstride  [I] Number of bytes in one scanline.
307  *  destbits     [I] Destination bitmap.
308  *  output       [I] Format of the destination bitmap.
309  *  outputstride [I] Number of bytes in one scanline. 
310  *  callback     [I] Callback function.
311  *  data         [I] Callback data. 
312  *
313  * RETURNS
314  *  Success: TRUE
315  *  Failure: FALSE
316  */
317 BOOL WINAPI TranslateBitmapBits( HTRANSFORM handle, PVOID srcbits, BMFORMAT input,
318     DWORD width, DWORD height, DWORD inputstride, PVOID destbits, BMFORMAT output,
319     DWORD outputstride, PBMCALLBACKFN callback, ULONG data )
320 {
321     BOOL ret = FALSE;
322 #ifdef HAVE_LCMS
323     struct transform *transform = grab_transform( handle );
324
325     TRACE( "( %p, %p, 0x%08x, 0x%08x, 0x%08x, 0x%08x, %p, 0x%08x, 0x%08x, %p, 0x%08x )\n",
326            handle, srcbits, input, width, height, inputstride, destbits, output,
327            outputstride, callback, data );
328
329     if (!transform) return FALSE;
330     cmsChangeBuffersFormat( transform->cmstransform, from_bmformat(input), from_bmformat(output) );
331
332     cmsDoTransform( transform->cmstransform, srcbits, destbits, width * height );
333     release_transform( transform );
334     ret = TRUE;
335
336 #endif /* HAVE_LCMS */
337     return ret;
338 }
339
340 /******************************************************************************
341  * TranslateColors              [MSCMS.@]
342  *
343  * Perform color translation.
344  *
345  * PARAMS
346  *  transform    [I] Handle to a color transform.
347  *  input        [I] Array of input colors.
348  *  number       [I] Number of colors to translate.
349  *  input_type   [I] Input color format.
350  *  output       [O] Array of output colors.
351  *  output_type  [I] Output color format.
352  *
353  * RETURNS
354  *  Success: TRUE
355  *  Failure: FALSE
356  */
357 BOOL WINAPI TranslateColors( HTRANSFORM handle, PCOLOR in, DWORD count,
358                              COLORTYPE input_type, PCOLOR out, COLORTYPE output_type )
359 {
360 #ifdef HAVE_LCMS
361     BOOL ret = TRUE;
362     struct transform *transform = grab_transform( handle );
363     cmsHTRANSFORM xfrm;
364     unsigned int i;
365
366     TRACE( "( %p, %p, %d, %d, %p, %d )\n", handle, in, count, input_type, out, output_type );
367
368     if (!transform) return FALSE;
369
370     xfrm = transform->cmstransform;
371     cmsChangeBuffersFormat( xfrm, from_type(input_type), from_type(output_type) );
372
373     switch (input_type)
374     {
375     case COLOR_RGB:
376     {
377         switch (output_type)
378         {
379         case COLOR_RGB:  for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].rgb, &out[i].rgb, 1 ); goto done;
380         case COLOR_Lab:  for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].rgb, &out[i].Lab, 1 ); goto done;
381         case COLOR_GRAY: for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].rgb, &out[i].gray, 1 ); goto done;
382         case COLOR_CMYK: for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].rgb, &out[i].cmyk, 1 ); goto done;
383         case COLOR_XYZ:  for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].rgb, &out[i].XYZ, 1 ); goto done;
384         default:
385             FIXME("unhandled input/output pair: %d/%d\n", input_type, output_type);
386             ret = FALSE;
387             break;
388         }
389         break;
390     }
391     case COLOR_Lab:
392     {
393         switch (output_type)
394         {
395         case COLOR_RGB:  for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].Lab, &out[i].rgb, 1 ); goto done;
396         case COLOR_Lab:  for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].Lab, &out[i].Lab, 1 ); goto done;
397         case COLOR_GRAY: for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].Lab, &out[i].gray, 1 ); goto done;
398         case COLOR_CMYK: for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].Lab, &out[i].cmyk, 1 ); goto done;
399         case COLOR_XYZ:  for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].Lab, &out[i].XYZ, 1 ); goto done;
400         default:
401             FIXME("unhandled input/output pair: %d/%d\n", input_type, output_type);
402             ret = FALSE;
403             break;
404         }
405         break;
406     }
407     case COLOR_GRAY:
408     {
409         switch (output_type)
410         {
411         case COLOR_RGB:  for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].gray, &out[i].rgb, 1 ); goto done;
412         case COLOR_Lab:  for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].gray, &out[i].Lab, 1 ); goto done;
413         case COLOR_GRAY: for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].gray, &out[i].gray, 1 ); goto done;
414         case COLOR_CMYK: for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].gray, &out[i].cmyk, 1 ); goto done;
415         case COLOR_XYZ:  for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].gray, &out[i].XYZ, 1 ); goto done;
416         default:
417             FIXME("unhandled input/output pair: %d/%d\n", input_type, output_type);
418             ret = FALSE;
419             break;
420         }
421         break;
422     }
423     case COLOR_CMYK:
424     {
425         switch (output_type)
426         {
427         case COLOR_RGB:  for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].cmyk, &out[i].rgb, 1 ); goto done;
428         case COLOR_Lab:  for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].cmyk, &out[i].Lab, 1 ); goto done;
429         case COLOR_GRAY: for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].cmyk, &out[i].gray, 1 ); goto done;
430         case COLOR_CMYK: for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].cmyk, &out[i].cmyk, 1 ); goto done;
431         case COLOR_XYZ:  for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].cmyk, &out[i].XYZ, 1 ); goto done;
432         default:
433             FIXME("unhandled input/output pair: %d/%d\n", input_type, output_type);
434             ret = FALSE;
435             break;
436         }
437         break;
438     }
439     case COLOR_XYZ:
440     {
441         switch (output_type)
442         {
443         case COLOR_RGB:  for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].XYZ, &out[i].rgb, 1 ); goto done;
444         case COLOR_Lab:  for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].XYZ, &out[i].Lab, 1 ); goto done;
445         case COLOR_GRAY: for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].XYZ, &out[i].gray, 1 ); goto done;
446         case COLOR_CMYK: for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].XYZ, &out[i].cmyk, 1 ); goto done;
447         case COLOR_XYZ:  for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].XYZ, &out[i].XYZ, 1 ); goto done;
448         default:
449             FIXME("unhandled input/output pair: %d/%d\n", input_type, output_type);
450             ret = FALSE;
451             break;
452         }
453         break;
454     }
455     default:
456         FIXME("unhandled input/output pair: %d/%d\n", input_type, output_type);
457         ret = FALSE;
458         break;
459     }
460
461 done:
462     release_transform( transform );
463     return ret;
464
465 #else  /* HAVE_LCMS */
466     return FALSE;
467 #endif /* HAVE_LCMS */
468 }