transform.c 14.8 KB
Newer Older
1 2 3
/*
 * MSCMS - Color Management System for Wine
 *
4
 * Copyright 2005, 2006, 2008 Hans Leidekker
5 6 7 8 9 10 11 12 13 14 15 16 17
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * 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 22 23 24 25 26 27 28 29 30 31 32
 */

#include "config.h"
#include "wine/debug.h"

#include <stdarg.h>

#include "windef.h"
#include "winbase.h"
#include "winnls.h"
#include "wingdi.h"
#include "winuser.h"
#include "icm.h"

33
#include "mscms_priv.h"
34 35 36

WINE_DEFAULT_DEBUG_CHANNEL(mscms);

37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
#ifdef HAVE_LCMS

static DWORD from_profile( HPROFILE profile )
{
    PROFILEHEADER header;

    GetColorProfileHeader( profile, &header );
    TRACE( "color space: 0x%08x %s\n", header.phDataColorSpace, MSCMS_dbgstr_tag( header.phDataColorSpace ) );

    switch (header.phDataColorSpace)
    {
    case 0x434d594b: return TYPE_CMYK_16;  /* 'CMYK' */
    case 0x47524159: return TYPE_GRAY_16;  /* 'GRAY' */
    case 0x4c616220: return TYPE_Lab_16;   /* 'Lab ' */
    case 0x52474220: return TYPE_RGB_16;   /* 'RGB ' */
    case 0x58595a20: return TYPE_XYZ_16;   /* 'XYZ ' */
    default:
        WARN("unhandled format\n");
        return TYPE_RGB_16;
    }
}

static DWORD from_bmformat( BMFORMAT format )
{
    TRACE( "bitmap format: 0x%08x\n", format );

    switch (format)
    {
    case BM_RGBTRIPLETS: return TYPE_RGB_8;
    case BM_BGRTRIPLETS: return TYPE_BGR_8;
    case BM_GRAY:        return TYPE_GRAY_8;
    default:
        FIXME("unhandled bitmap format\n");
        return TYPE_RGB_8;
    }
}

static DWORD from_type( COLORTYPE type )
{
    TRACE( "color type: 0x%08x\n", type );

    switch (type)
    {
    case COLOR_GRAY:    return TYPE_GRAY_16;
    case COLOR_RGB:     return TYPE_RGB_16;
    case COLOR_XYZ:     return TYPE_XYZ_16;
    case COLOR_Yxy:     return TYPE_Yxy_16;
    case COLOR_Lab:     return TYPE_Lab_16;
    case COLOR_CMYK:    return TYPE_CMYK_16;
    default:
        FIXME("unhandled color type\n");
        return TYPE_RGB_16;
    }
}

#endif /* HAVE_LCMS */

94 95 96 97 98
/******************************************************************************
 * CreateColorTransformA            [MSCMS.@]
 *
 * See CreateColorTransformW.
 */
99 100 101 102 103 104
HTRANSFORM WINAPI CreateColorTransformA( LPLOGCOLORSPACEA space, HPROFILE dest,
    HPROFILE target, DWORD flags )
{
    LOGCOLORSPACEW spaceW;
    DWORD len;

105
    TRACE( "( %p, %p, %p, 0x%08x )\n", space, dest, target, flags );
106 107 108 109 110 111 112 113 114 115 116 117

    if (!space || !dest) return FALSE;

    memcpy( &spaceW, space, FIELD_OFFSET(LOGCOLORSPACEA, lcsFilename) );
    spaceW.lcsSize = sizeof(LOGCOLORSPACEW);

    len = MultiByteToWideChar( CP_ACP, 0, space->lcsFilename, -1, NULL, 0 );
    MultiByteToWideChar( CP_ACP, 0, space->lcsFilename, -1, spaceW.lcsFilename, len );

    return CreateColorTransformW( &spaceW, dest, target, flags );
}

118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
/******************************************************************************
 * CreateColorTransformW            [MSCMS.@]
 *
 * Create a color transform.
 *
 * PARAMS
 *  space  [I] Input color space.
 *  dest   [I] Color profile of destination device.
 *  target [I] Color profile of target device.
 *  flags  [I] Flags.
 *
 * RETURNS
 *  Success: Handle to a transform.
 *  Failure: NULL
 */
133 134 135 136
HTRANSFORM WINAPI CreateColorTransformW( LPLOGCOLORSPACEW space, HPROFILE dest,
    HPROFILE target, DWORD flags )
{
    HTRANSFORM ret = NULL;
137
#ifdef HAVE_LCMS
138 139
    struct transform transform;
    struct profile *dst, *tgt = NULL;
140 141
    cmsHPROFILE cmsinput, cmsoutput, cmstarget = NULL;
    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 149 150 151 152
    if (target && !(tgt = grab_profile( target )))
    {
        release_profile( dst );
        return FALSE;
    }
153 154
    intent = space->lcsIntent > 3 ? INTENT_PERCEPTUAL : space->lcsIntent;

155 156 157
    TRACE( "lcsIntent:   %x\n", space->lcsIntent );
    TRACE( "lcsCSType:   %s\n", MSCMS_dbgstr_tag( space->lcsCSType ) );
    TRACE( "lcsFilename: %s\n", debugstr_w( space->lcsFilename ) );
158

159 160 161 162
    in_format  = TYPE_RGB_16;
    out_format = from_profile( dest );

    cmsinput = cmsCreate_sRGBProfile(); /* FIXME: create from supplied color space */
163 164
    if (target)
    {
165
        proofing = cmsFLAGS_SOFTPROOFING;
166
        cmstarget = tgt->cmsprofile;
167
    }
168 169 170
    cmsoutput = dst->cmsprofile;
    transform.cmstransform = cmsCreateProofingTransform(cmsinput, in_format, cmsoutput, out_format, cmstarget,
                                                        intent, INTENT_ABSOLUTE_COLORIMETRIC, proofing);
171

172 173 174 175
    ret = create_transform( &transform );

    if (tgt) release_profile( tgt );
    release_profile( dst );
176

177
#endif /* HAVE_LCMS */
178 179 180
    return ret;
}

181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196
/******************************************************************************
 * CreateMultiProfileTransform      [MSCMS.@]
 *
 * Create a color transform from an array of color profiles.
 *
 * PARAMS
 *  profiles  [I] Array of color profiles.
 *  nprofiles [I] Number of color profiles.
 *  intents   [I] Array of rendering intents.
 *  flags     [I] Flags.
 *  cmm       [I] Profile to take the CMM from.
 *
 * RETURNS
 *  Success: Handle to a transform.
 *  Failure: NULL
 */ 
197 198 199 200
HTRANSFORM WINAPI CreateMultiProfileTransform( PHPROFILE profiles, DWORD nprofiles,
    PDWORD intents, DWORD nintents, DWORD flags, DWORD cmm )
{
    HTRANSFORM ret = NULL;
201
#ifdef HAVE_LCMS
202
    cmsHPROFILE *cmsprofiles, cmsconvert = NULL;
203 204
    struct transform transform;
    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 209
           profiles, nprofiles, intents, nintents, flags, cmm );

210
    if (!profiles || !nprofiles || !intents) return NULL;
211

212 213 214 215 216
    if (nprofiles > 2)
    {
        FIXME("more than 2 profiles not supported\n");
        return NULL;
    }
217

218 219 220 221 222 223 224 225
    profile0 = grab_profile( profiles[0] );
    if (!profile0) return NULL;
    profile1 = grab_profile( profiles[1] );
    if (!profile1)
    {
        release_profile( profile0 );
        return NULL;
    }
226 227 228 229
    in_format  = from_profile( profiles[0] );
    out_format = from_profile( profiles[nprofiles - 1] );

    if (in_format != out_format)
230
    {
231 232 233
        /* insert a conversion profile for pairings that lcms doesn't handle */
        if (out_format == TYPE_RGB_16) cmsconvert = cmsCreate_sRGBProfile();
        if (out_format == TYPE_Lab_16) cmsconvert = cmsCreateLabProfile( NULL );
234 235
    }

236 237 238
    cmsprofiles = HeapAlloc( GetProcessHeap(), 0, (nprofiles + 1) * sizeof(cmsHPROFILE *) );
    if (cmsprofiles)
    {
239
        cmsprofiles[0] = profile0->cmsprofile;
240 241 242
        if (cmsconvert)
        {
            cmsprofiles[1] = cmsconvert;
243
            cmsprofiles[2] = profile1->cmsprofile;
244 245 246 247
            nprofiles++;
        }
        else
        {
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 257 258
    release_profile( profile0 );
    release_profile( profile1 );

259
#endif /* HAVE_LCMS */
260 261 262
    return ret;
}

263 264 265 266 267 268 269 270 271 272 273 274
/******************************************************************************
 * DeleteColorTransform             [MSCMS.@]
 *
 * Delete a color transform.
 *
 * PARAMS
 *  transform [I] Handle to a color transform.
 *
 * RETURNS
 *  Success: TRUE
 *  Failure: FALSE
 */ 
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 286
    return ret;
}
287

288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309
/******************************************************************************
 * TranslateBitmapBits              [MSCMS.@]
 *
 * Perform color translation.
 *
 * PARAMS
 *  transform    [I] Handle to a color transform.
 *  srcbits      [I] Source bitmap.
 *  input        [I] Format of the source bitmap.
 *  width        [I] Width of the source bitmap.
 *  height       [I] Height of the source bitmap.
 *  inputstride  [I] Number of bytes in one scanline.
 *  destbits     [I] Destination bitmap.
 *  output       [I] Format of the destination bitmap.
 *  outputstride [I] Number of bytes in one scanline. 
 *  callback     [I] Callback function.
 *  data         [I] Callback data. 
 *
 * RETURNS
 *  Success: TRUE
 *  Failure: FALSE
 */
310
BOOL WINAPI TranslateBitmapBits( HTRANSFORM handle, PVOID srcbits, BMFORMAT input,
311 312 313 314
    DWORD width, DWORD height, DWORD inputstride, PVOID destbits, BMFORMAT output,
    DWORD outputstride, PBMCALLBACKFN callback, ULONG data )
{
    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 321
           outputstride, callback, data );

322 323
    if (!transform) return FALSE;
    cmsChangeBuffersFormat( transform->cmstransform, from_bmformat(input), from_bmformat(output) );
324

325 326
    cmsDoTransform( transform->cmstransform, srcbits, destbits, width * height );
    release_transform( transform );
327 328
    ret = TRUE;

329
#endif /* HAVE_LCMS */
330 331
    return ret;
}
332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349

/******************************************************************************
 * TranslateColors              [MSCMS.@]
 *
 * Perform color translation.
 *
 * PARAMS
 *  transform    [I] Handle to a color transform.
 *  input        [I] Array of input colors.
 *  number       [I] Number of colors to translate.
 *  input_type   [I] Input color format.
 *  output       [O] Array of output colors.
 *  output_type  [I] Output color format.
 *
 * RETURNS
 *  Success: TRUE
 *  Failure: FALSE
 */
350
BOOL WINAPI TranslateColors( HTRANSFORM handle, PCOLOR in, DWORD count,
351 352 353 354
                             COLORTYPE input_type, PCOLOR out, COLORTYPE output_type )
{
    BOOL ret = FALSE;
#ifdef HAVE_LCMS
355 356
    struct transform *transform = grab_transform( handle );
    cmsHTRANSFORM xfrm;
357 358
    unsigned int i;

359 360 361
    TRACE( "( %p, %p, %d, %d, %p, %d )\n", handle, in, count, input_type, out, output_type );

    if (!transform) return FALSE;
362

363
    xfrm = transform->cmstransform;
364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441
    cmsChangeBuffersFormat( xfrm, from_type(input_type), from_type(output_type) );

    switch (input_type)
    {
    case COLOR_RGB:
    {
        switch (output_type)
        {
        case COLOR_RGB:  for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].rgb, &out[i].rgb, 1 ); return TRUE;
        case COLOR_Lab:  for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].rgb, &out[i].Lab, 1 ); return TRUE;
        case COLOR_GRAY: for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].rgb, &out[i].gray, 1 ); return TRUE;
        case COLOR_CMYK: for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].rgb, &out[i].cmyk, 1 ); return TRUE;
        case COLOR_XYZ:  for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].rgb, &out[i].XYZ, 1 ); return TRUE;
        default:
            FIXME("unhandled input/output pair: %d/%d\n", input_type, output_type);
            return FALSE;
        }
    }
    case COLOR_Lab:
    {
        switch (output_type)
        {
        case COLOR_RGB:  for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].Lab, &out[i].rgb, 1 ); return TRUE;
        case COLOR_Lab:  for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].Lab, &out[i].Lab, 1 ); return TRUE;
        case COLOR_GRAY: for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].Lab, &out[i].gray, 1 ); return TRUE;
        case COLOR_CMYK: for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].Lab, &out[i].cmyk, 1 ); return TRUE;
        case COLOR_XYZ:  for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].Lab, &out[i].XYZ, 1 ); return TRUE;
        default:
            FIXME("unhandled input/output pair: %d/%d\n", input_type, output_type);
            return FALSE;
        }
    }
    case COLOR_GRAY:
    {
        switch (output_type)
        {
        case COLOR_RGB:  for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].gray, &out[i].rgb, 1 ); return TRUE;
        case COLOR_Lab:  for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].gray, &out[i].Lab, 1 ); return TRUE;
        case COLOR_GRAY: for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].gray, &out[i].gray, 1 ); return TRUE;
        case COLOR_CMYK: for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].gray, &out[i].cmyk, 1 ); return TRUE;
        case COLOR_XYZ:  for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].gray, &out[i].XYZ, 1 ); return TRUE;
        default:
            FIXME("unhandled input/output pair: %d/%d\n", input_type, output_type);
            return FALSE;
        }
    }
    case COLOR_CMYK:
    {
        switch (output_type)
        {
        case COLOR_RGB:  for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].cmyk, &out[i].rgb, 1 ); return TRUE;
        case COLOR_Lab:  for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].cmyk, &out[i].Lab, 1 ); return TRUE;
        case COLOR_GRAY: for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].cmyk, &out[i].gray, 1 ); return TRUE;
        case COLOR_CMYK: for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].cmyk, &out[i].cmyk, 1 ); return TRUE;
        case COLOR_XYZ:  for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].cmyk, &out[i].XYZ, 1 ); return TRUE;
        default:
            FIXME("unhandled input/output pair: %d/%d\n", input_type, output_type);
            return FALSE;
        }
    }
    case COLOR_XYZ:
    {
        switch (output_type)
        {
        case COLOR_RGB:  for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].XYZ, &out[i].rgb, 1 ); return TRUE;
        case COLOR_Lab:  for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].XYZ, &out[i].Lab, 1 ); return TRUE;
        case COLOR_GRAY: for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].XYZ, &out[i].gray, 1 ); return TRUE;
        case COLOR_CMYK: for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].XYZ, &out[i].cmyk, 1 ); return TRUE;
        case COLOR_XYZ:  for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].XYZ, &out[i].XYZ, 1 ); return TRUE;
        default:
            FIXME("unhandled input/output pair: %d/%d\n", input_type, output_type);
            return FALSE;
        }
    }
    default:
        FIXME("unhandled input/output pair: %d/%d\n", input_type, output_type);
        break;
    }
442
    release_transform( transform );
443 444 445 446

#endif /* HAVE_LCMS */
    return ret;
}