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