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