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