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