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 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 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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