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