1 /* Copyright (C) 2002 artofcode LLC. All rights reserved. 2 3 This software is provided AS-IS with no warranty, either express or 4 implied. 5 6 This software is distributed under license and may not be copied, 7 modified or distributed except as expressly authorized under the terms 8 of the license contained in the file LICENSE in this distribution. 9 10 For more information about licensing, please refer to 11 http://www.ghostscript.com/licensing/. For information on 12 commercial licensing, go to http://www.artifex.com/licensing/ or 13 contact Artifex Software, Inc., 101 Lucas Valley Road #110, 14 San Rafael, CA 94903, U.S.A., +1(415)492-9861. 15 */ 16 17 /*$Id: gdevpsd.c,v 1.23 2005/08/30 06:38:44 igor Exp $ */ 18 /* PhotoShop (PSD) export device, supporting DeviceN color models. */ 19 20 #include "math_.h" 21 #include "gdevprn.h" 22 #include "gsparam.h" 23 #include "gscrd.h" 24 #include "gscrdp.h" 25 #include "gxlum.h" 26 #include "gdevdcrd.h" 27 #include "gstypes.h" 28 #include "icc.h" 29 #include "gxdcconv.h" 30 #include "gdevdevn.h" 31 #include "gsequivc.h" 32 33 /* Enable logic for a local ICC output profile. */ 34 #define ENABLE_ICC_PROFILE 0 35 36 /* Define the device parameters. */ 37 #ifndef X_DPI 38 # define X_DPI 72 39 #endif 40 #ifndef Y_DPI 41 # define Y_DPI 72 42 #endif 43 44 /* The device descriptor */ 45 private dev_proc_open_device(psd_prn_open); 46 private dev_proc_get_params(psd_get_params); 47 private dev_proc_put_params(psd_put_params); 48 private dev_proc_print_page(psd_print_page); 49 private dev_proc_map_color_rgb(psd_map_color_rgb); 50 private dev_proc_get_color_mapping_procs(get_psdrgb_color_mapping_procs); 51 private dev_proc_get_color_mapping_procs(get_psd_color_mapping_procs); 52 private dev_proc_get_color_comp_index(psd_get_color_comp_index); 53 private dev_proc_encode_color(psd_encode_color); 54 private dev_proc_decode_color(psd_decode_color); 55 private dev_proc_update_spot_equivalent_colors(psd_update_spot_equivalent_colors); 56 57 /* This is redundant with color_info.cm_name. We may eliminate this 58 typedef and use the latter string for everything. */ 59 typedef enum { 60 psd_DEVICE_GRAY, 61 psd_DEVICE_RGB, 62 psd_DEVICE_CMYK, 63 psd_DEVICE_N 64 } psd_color_model; 65 66 /* 67 * A structure definition for a DeviceN type device 68 */ 69 typedef struct psd_device_s { 70 gx_device_common; 71 gx_prn_device_common; 72 73 /* ... device-specific parameters ... */ 74 75 gs_devn_params devn_params; /* DeviceN generated parameters */ 76 77 equivalent_cmyk_color_params equiv_cmyk_colors; 78 79 psd_color_model color_model; 80 81 /* ICC color profile objects, for color conversion. */ 82 char profile_rgb_fn[256]; 83 icmLuBase *lu_rgb; 84 int lu_rgb_outn; 85 86 char profile_cmyk_fn[256]; 87 icmLuBase *lu_cmyk; 88 int lu_cmyk_outn; 89 90 char profile_out_fn[256]; 91 icmLuBase *lu_out; 92 } psd_device; 93 94 /* GC procedures */ 95 private 96 ENUM_PTRS_WITH(psd_device_enum_ptrs, psd_device *pdev) 97 { 98 if (index < pdev->devn_params.separations.num_separations) 99 ENUM_RETURN(pdev->devn_params.separations.names[index].data); 100 ENUM_PREFIX(st_device_printer, 101 pdev->devn_params.separations.num_separations); 102 } 103 104 ENUM_PTRS_END 105 private RELOC_PTRS_WITH(psd_device_reloc_ptrs, psd_device *pdev) 106 { 107 RELOC_PREFIX(st_device_printer); 108 { 109 int i; 110 111 for (i = 0; i < pdev->devn_params.separations.num_separations; ++i) { 112 RELOC_PTR(psd_device, devn_params.separations.names[i].data); 113 } 114 } 115 } 116 RELOC_PTRS_END 117 118 /* Even though psd_device_finalize is the same as gx_device_finalize, */ 119 /* we need to implement it separately because st_composite_final */ 120 /* declares all 3 procedures as private. */ 121 private void 122 psd_device_finalize(void *vpdev) 123 { 124 gx_device_finalize(vpdev); 125 } 126 127 gs_private_st_composite_final(st_psd_device, psd_device, 128 "psd_device", psd_device_enum_ptrs, psd_device_reloc_ptrs, 129 psd_device_finalize); 130 131 /* 132 * Macro definition for psd device procedures 133 */ 134 #define device_procs(get_color_mapping_procs)\ 135 { psd_prn_open,\ 136 gx_default_get_initial_matrix,\ 137 NULL, /* sync_output */\ 138 gdev_prn_output_page, /* output_page */\ 139 gdev_prn_close, /* close */\ 140 NULL, /* map_rgb_color - not used */\ 141 psd_map_color_rgb, /* map_color_rgb */\ 142 NULL, /* fill_rectangle */\ 143 NULL, /* tile_rectangle */\ 144 NULL, /* copy_mono */\ 145 NULL, /* copy_color */\ 146 NULL, /* draw_line */\ 147 NULL, /* get_bits */\ 148 psd_get_params, /* get_params */\ 149 psd_put_params, /* put_params */\ 150 NULL, /* map_cmyk_color - not used */\ 151 NULL, /* get_xfont_procs */\ 152 NULL, /* get_xfont_device */\ 153 NULL, /* map_rgb_alpha_color */\ 154 gx_page_device_get_page_device, /* get_page_device */\ 155 NULL, /* get_alpha_bits */\ 156 NULL, /* copy_alpha */\ 157 NULL, /* get_band */\ 158 NULL, /* copy_rop */\ 159 NULL, /* fill_path */\ 160 NULL, /* stroke_path */\ 161 NULL, /* fill_mask */\ 162 NULL, /* fill_trapezoid */\ 163 NULL, /* fill_parallelogram */\ 164 NULL, /* fill_triangle */\ 165 NULL, /* draw_thin_line */\ 166 NULL, /* begin_image */\ 167 NULL, /* image_data */\ 168 NULL, /* end_image */\ 169 NULL, /* strip_tile_rectangle */\ 170 NULL, /* strip_copy_rop */\ 171 NULL, /* get_clipping_box */\ 172 NULL, /* begin_typed_image */\ 173 NULL, /* get_bits_rectangle */\ 174 NULL, /* map_color_rgb_alpha */\ 175 NULL, /* create_compositor */\ 176 NULL, /* get_hardware_params */\ 177 NULL, /* text_begin */\ 178 NULL, /* finish_copydevice */\ 179 NULL, /* begin_transparency_group */\ 180 NULL, /* end_transparency_group */\ 181 NULL, /* begin_transparency_mask */\ 182 NULL, /* end_transparency_mask */\ 183 NULL, /* discard_transparency_layer */\ 184 get_color_mapping_procs, /* get_color_mapping_procs */\ 185 psd_get_color_comp_index, /* get_color_comp_index */\ 186 psd_encode_color, /* encode_color */\ 187 psd_decode_color, /* decode_color */\ 188 NULL, /* pattern_manage */\ 189 NULL, /* fill_rectangle_hl_color */\ 190 NULL, /* include_color_space */\ 191 NULL, /* fill_linear_color_scanline */\ 192 NULL, /* fill_linear_color_trapezoid */\ 193 NULL, /* fill_linear_color_triangle */\ 194 psd_update_spot_equivalent_colors /* update_spot_equivalent_colors */\ 195 } 196 197 198 private fixed_colorant_name DeviceGrayComponents[] = { 199 "Gray", 200 0 /* List terminator */ 201 }; 202 203 private fixed_colorant_name DeviceRGBComponents[] = { 204 "Red", 205 "Green", 206 "Blue", 207 0 /* List terminator */ 208 }; 209 210 #define psd_device_body(procs, dname, ncomp, pol, depth, mg, mc, cn)\ 211 std_device_full_body_type_extended(psd_device, &procs, dname,\ 212 &st_psd_device,\ 213 (int)((long)(DEFAULT_WIDTH_10THS) * (X_DPI) / 10),\ 214 (int)((long)(DEFAULT_HEIGHT_10THS) * (Y_DPI) / 10),\ 215 X_DPI, Y_DPI,\ 216 GX_DEVICE_COLOR_MAX_COMPONENTS, /* MaxComponents */\ 217 ncomp, /* NumComp */\ 218 pol, /* Polarity */\ 219 depth, 0, /* Depth, GrayIndex */\ 220 mg, mc, /* MaxGray, MaxColor */\ 221 mg + 1, mc + 1, /* DitherGray, DitherColor */\ 222 GX_CINFO_SEP_LIN, /* Linear & Separable */\ 223 cn, /* Process color model name */\ 224 0, 0, /* offsets */\ 225 0, 0, 0, 0 /* margins */\ 226 ),\ 227 prn_device_body_rest_(psd_print_page) 228 229 /* 230 * PSD device with RGB process color model. 231 */ 232 private const gx_device_procs spot_rgb_procs = device_procs(get_psdrgb_color_mapping_procs); 233 234 const psd_device gs_psdrgb_device = 235 { 236 psd_device_body(spot_rgb_procs, "psdrgb", 3, GX_CINFO_POLARITY_ADDITIVE, 24, 255, 255, "DeviceRGB"), 237 /* devn_params specific parameters */ 238 { 8, /* Bits per color - must match ncomp, depth, etc. above */ 239 DeviceRGBComponents, /* Names of color model colorants */ 240 3, /* Number colorants for RGB */ 241 0, /* MaxSeparations has not been specified */ 242 {0}, /* SeparationNames */ 243 0, /* SeparationOrder names */ 244 {0, 1, 2, 3, 4, 5, 6, 7 } /* Initial component SeparationOrder */ 245 }, 246 { true }, /* equivalent CMYK colors for spot colors */ 247 /* PSD device specific parameters */ 248 psd_DEVICE_RGB, /* Color model */ 249 }; 250 251 /* 252 * Select the default number of components based upon the number of bits 253 * that we have in a gx_color_index 254 */ 255 #define NC ((arch_sizeof_color_index <= 8) ? arch_sizeof_color_index : 8) 256 257 /* 258 * PSD device with CMYK process color model and spot color support. 259 */ 260 private const gx_device_procs spot_cmyk_procs 261 = device_procs(get_psd_color_mapping_procs); 262 263 const psd_device gs_psdcmyk_device = 264 { 265 psd_device_body(spot_cmyk_procs, "psdcmyk", NC, GX_CINFO_POLARITY_SUBTRACTIVE, NC * 8, 255, 255, "DeviceCMYK"), 266 /* devn_params specific parameters */ 267 { 8, /* Bits per color - must match ncomp, depth, etc. above */ 268 DeviceCMYKComponents, /* Names of color model colorants */ 269 4, /* Number colorants for CMYK */ 270 NC, /* MaxSeparations has not been specified */ 271 {0}, /* SeparationNames */ 272 0, /* SeparationOrder names */ 273 {0, 1, 2, 3, 4, 5, 6, 7 } /* Initial component SeparationOrder */ 274 }, 275 { true }, /* equivalent CMYK colors for spot colors */ 276 /* PSD device specific parameters */ 277 psd_DEVICE_CMYK, /* Color model */ 278 }; 279 280 #undef NC 281 282 /* Open the psd devices */ 283 int 284 psd_prn_open(gx_device * pdev) 285 { 286 int code = gdev_prn_open(pdev); 287 288 set_linear_color_bits_mask_shift(pdev); 289 pdev->color_info.separable_and_linear = GX_CINFO_SEP_LIN; 290 return code; 291 } 292 293 /* 294 * The following procedures are used to map the standard color spaces into 295 * the color components for the psdrgb device. 296 */ 297 private void 298 gray_cs_to_psdrgb_cm(gx_device * dev, frac gray, frac out[]) 299 { 300 int i = ((psd_device *)dev)->devn_params.separations.num_separations; 301 302 out[0] = out[1] = out[2] = gray; 303 for(; i>0; i--) /* Clear spot colors */ 304 out[2 + i] = 0; 305 } 306 307 private void 308 rgb_cs_to_psdrgb_cm(gx_device * dev, const gs_imager_state *pis, 309 frac r, frac g, frac b, frac out[]) 310 { 311 int i = ((psd_device *)dev)->devn_params.separations.num_separations; 312 313 out[0] = r; 314 out[1] = g; 315 out[2] = b; 316 for(; i>0; i--) /* Clear spot colors */ 317 out[2 + i] = 0; 318 } 319 320 private void 321 cmyk_cs_to_psdrgb_cm(gx_device * dev, 322 frac c, frac m, frac y, frac k, frac out[]) 323 { 324 int i = ((psd_device *)dev)->devn_params.separations.num_separations; 325 326 color_cmyk_to_rgb(c, m, y, k, NULL, out); 327 for(; i>0; i--) /* Clear spot colors */ 328 out[2 + i] = 0; 329 } 330 331 /* Color mapping routines for the psdcmyk device */ 332 333 private void 334 gray_cs_to_psdcmyk_cm(gx_device * dev, frac gray, frac out[]) 335 { 336 int * map = ((psd_device *) dev)->devn_params.separation_order_map; 337 338 gray_cs_to_devn_cm(dev, map, gray, out); 339 } 340 341 private void 342 rgb_cs_to_psdcmyk_cm(gx_device * dev, const gs_imager_state *pis, 343 frac r, frac g, frac b, frac out[]) 344 { 345 int * map = ((psd_device *) dev)->devn_params.separation_order_map; 346 347 rgb_cs_to_devn_cm(dev, map, pis, r, g, b, out); 348 } 349 350 private void 351 cmyk_cs_to_psdcmyk_cm(gx_device * dev, 352 frac c, frac m, frac y, frac k, frac out[]) 353 { 354 int * map = ((psd_device *) dev)->devn_params.separation_order_map; 355 356 cmyk_cs_to_devn_cm(dev, map, c, m, y, k, out); 357 } 358 359 private void 360 cmyk_cs_to_spotn_cm(gx_device * dev, frac c, frac m, frac y, frac k, frac out[]) 361 { 362 psd_device *xdev = (psd_device *)dev; 363 int n = xdev->devn_params.separations.num_separations; 364 icmLuBase *luo = xdev->lu_cmyk; 365 int i; 366 367 if (luo != NULL) { 368 double in[4]; 369 double tmp[MAX_CHAN]; 370 int outn = xdev->lu_cmyk_outn; 371 372 in[0] = frac2float(c); 373 in[1] = frac2float(m); 374 in[2] = frac2float(y); 375 in[3] = frac2float(k); 376 luo->lookup(luo, tmp, in); 377 for (i = 0; i < outn; i++) 378 out[i] = float2frac(tmp[i]); 379 for (; i < n + 4; i++) 380 out[i] = 0; 381 } else { 382 /* If no profile given, assume CMYK */ 383 out[0] = c; 384 out[1] = m; 385 out[2] = y; 386 out[3] = k; 387 for(i = 0; i < n; i++) /* Clear spot colors */ 388 out[4 + i] = 0; 389 } 390 } 391 392 private void 393 gray_cs_to_spotn_cm(gx_device * dev, frac gray, frac out[]) 394 { 395 cmyk_cs_to_spotn_cm(dev, 0, 0, 0, (frac)(frac_1 - gray), out); 396 } 397 398 private void 399 rgb_cs_to_spotn_cm(gx_device * dev, const gs_imager_state *pis, 400 frac r, frac g, frac b, frac out[]) 401 { 402 psd_device *xdev = (psd_device *)dev; 403 int n = xdev->devn_params.separations.num_separations; 404 icmLuBase *luo = xdev->lu_rgb; 405 int i; 406 407 if (luo != NULL) { 408 double in[3]; 409 double tmp[MAX_CHAN]; 410 int outn = xdev->lu_rgb_outn; 411 412 in[0] = frac2float(r); 413 in[1] = frac2float(g); 414 in[2] = frac2float(b); 415 luo->lookup(luo, tmp, in); 416 for (i = 0; i < outn; i++) 417 out[i] = float2frac(tmp[i]); 418 for (; i < n + 4; i++) 419 out[i] = 0; 420 } else { 421 frac cmyk[4]; 422 423 color_rgb_to_cmyk(r, g, b, pis, cmyk); 424 cmyk_cs_to_spotn_cm(dev, cmyk[0], cmyk[1], cmyk[2], cmyk[3], 425 out); 426 } 427 } 428 429 private const gx_cm_color_map_procs psdRGB_procs = { 430 gray_cs_to_psdrgb_cm, rgb_cs_to_psdrgb_cm, cmyk_cs_to_psdrgb_cm 431 }; 432 433 private const gx_cm_color_map_procs psdCMYK_procs = { 434 gray_cs_to_psdcmyk_cm, rgb_cs_to_psdcmyk_cm, cmyk_cs_to_psdcmyk_cm 435 }; 436 437 private const gx_cm_color_map_procs psdN_procs = { 438 gray_cs_to_spotn_cm, rgb_cs_to_spotn_cm, cmyk_cs_to_spotn_cm 439 }; 440 441 /* 442 * These are the handlers for returning the list of color space 443 * to color model conversion routines. 444 */ 445 private const gx_cm_color_map_procs * 446 get_psdrgb_color_mapping_procs(const gx_device * dev) 447 { 448 return &psdRGB_procs; 449 } 450 451 private const gx_cm_color_map_procs * 452 get_psd_color_mapping_procs(const gx_device * dev) 453 { 454 const psd_device *xdev = (const psd_device *)dev; 455 456 if (xdev->color_model == psd_DEVICE_RGB) 457 return &psdRGB_procs; 458 else if (xdev->color_model == psd_DEVICE_CMYK) 459 return &psdCMYK_procs; 460 else if (xdev->color_model == psd_DEVICE_N) 461 return &psdN_procs; 462 else 463 return NULL; 464 } 465 466 /* 467 * Encode a list of colorant values into a gx_color_index_value. 468 */ 469 private gx_color_index 470 psd_encode_color(gx_device *dev, const gx_color_value colors[]) 471 { 472 int bpc = ((psd_device *)dev)->devn_params.bitspercomponent; 473 int drop = sizeof(gx_color_value) * 8 - bpc; 474 gx_color_index color = 0; 475 int i = 0; 476 int ncomp = dev->color_info.num_components; 477 478 for (; i<ncomp; i++) { 479 color <<= bpc; 480 color |= (colors[i] >> drop); 481 } 482 return (color == gx_no_color_index ? color ^ 1 : color); 483 } 484 485 /* 486 * Decode a gx_color_index value back to a list of colorant values. 487 */ 488 private int 489 psd_decode_color(gx_device * dev, gx_color_index color, gx_color_value * out) 490 { 491 int bpc = ((psd_device *)dev)->devn_params.bitspercomponent; 492 int drop = sizeof(gx_color_value) * 8 - bpc; 493 int mask = (1 << bpc) - 1; 494 int i = 0; 495 int ncomp = dev->color_info.num_components; 496 497 for (; i<ncomp; i++) { 498 out[ncomp - i - 1] = (gx_color_value) ((color & mask) << drop); 499 color >>= bpc; 500 } 501 return 0; 502 } 503 504 /* 505 * Convert a gx_color_index to RGB. 506 */ 507 private int 508 psd_map_color_rgb(gx_device *dev, gx_color_index color, gx_color_value rgb[3]) 509 { 510 psd_device *xdev = (psd_device *)dev; 511 512 if (xdev->color_model == psd_DEVICE_RGB) 513 return psd_decode_color(dev, color, rgb); 514 /* TODO: return reasonable values. */ 515 rgb[0] = 0; 516 rgb[1] = 0; 517 rgb[2] = 0; 518 return 0; 519 } 520 521 /* 522 * Device proc for updating the equivalent CMYK color for spot colors. 523 */ 524 private int 525 psd_update_spot_equivalent_colors(gx_device *pdev, const gs_state * pgs) 526 { 527 psd_device * psdev = (psd_device *)pdev; 528 529 update_spot_equivalent_cmyk_colors(pdev, pgs, 530 &psdev->devn_params, &psdev->equiv_cmyk_colors); 531 return 0; 532 } 533 534 #if ENABLE_ICC_PROFILE 535 private int 536 psd_open_profile(psd_device *xdev, char *profile_fn, icmLuBase **pluo, 537 int *poutn) 538 { 539 icmFile *fp; 540 icc *icco; 541 icmLuBase *luo; 542 543 dlprintf1("psd_open_profile %s\n", profile_fn); 544 fp = new_icmFileStd_name(profile_fn, (char *)"rb"); 545 if (fp == NULL) 546 return_error(gs_error_undefinedfilename); 547 icco = new_icc(); 548 if (icco == NULL) 549 return_error(gs_error_VMerror); 550 if (icco->read(icco, fp, 0)) 551 return_error(gs_error_rangecheck); 552 luo = icco->get_luobj(icco, icmFwd, icmDefaultIntent, icmSigDefaultData, icmLuOrdNorm); 553 if (luo == NULL) 554 return_error(gs_error_rangecheck); 555 *pluo = luo; 556 luo->spaces(luo, NULL, NULL, NULL, poutn, NULL, NULL, NULL, NULL); 557 return 0; 558 } 559 560 private int 561 psd_open_profiles(psd_device *xdev) 562 { 563 int code = 0; 564 if (xdev->lu_out == NULL && xdev->profile_out_fn[0]) { 565 code = psd_open_profile(xdev, xdev->profile_out_fn, 566 &xdev->lu_out, NULL); 567 } 568 if (code >= 0 && xdev->lu_rgb == NULL && xdev->profile_rgb_fn[0]) { 569 code = psd_open_profile(xdev, xdev->profile_rgb_fn, 570 &xdev->lu_rgb, &xdev->lu_rgb_outn); 571 } 572 if (code >= 0 && xdev->lu_cmyk == NULL && xdev->profile_cmyk_fn[0]) { 573 code = psd_open_profile(xdev, xdev->profile_cmyk_fn, 574 &xdev->lu_cmyk, &xdev->lu_cmyk_outn); 575 } 576 return code; 577 } 578 #endif 579 580 /* Get parameters. We provide a default CRD. */ 581 private int 582 psd_get_params(gx_device * pdev, gs_param_list * plist) 583 { 584 psd_device *xdev = (psd_device *)pdev; 585 int code; 586 #if ENABLE_ICC_PROFILE 587 gs_param_string pos; 588 gs_param_string prgbs; 589 gs_param_string pcmyks; 590 #endif 591 592 code = gdev_prn_get_params(pdev, plist); 593 if (code < 0) 594 return code; 595 code = devn_get_params(pdev, plist, 596 &(xdev->devn_params), &(xdev->equiv_cmyk_colors)); 597 if (code < 0) 598 return code; 599 600 #if ENABLE_ICC_PROFILE 601 pos.data = (const byte *)xdev->profile_out_fn, 602 pos.size = strlen(xdev->profile_out_fn), 603 pos.persistent = false; 604 code = param_write_string(plist, "ProfileOut", &pos); 605 if (code < 0) 606 return code; 607 608 prgbs.data = (const byte *)xdev->profile_rgb_fn, 609 prgbs.size = strlen(xdev->profile_rgb_fn), 610 prgbs.persistent = false; 611 code = param_write_string(plist, "ProfileRgb", &prgbs); 612 if (code < 0) 613 return code; 614 615 pcmyks.data = (const byte *)xdev->profile_cmyk_fn, 616 pcmyks.size = strlen(xdev->profile_cmyk_fn), 617 pcmyks.persistent = false; 618 code = param_write_string(plist, "ProfileCmyk", &prgbs); 619 #endif 620 621 return code; 622 } 623 624 #if ENABLE_ICC_PROFILE 625 private int 626 psd_param_read_fn(gs_param_list *plist, const char *name, 627 gs_param_string *pstr, uint max_len) 628 { 629 int code = param_read_string(plist, name, pstr); 630 631 if (code == 0) { 632 if (pstr->size >= max_len) 633 param_signal_error(plist, name, code = gs_error_rangecheck); 634 } else { 635 pstr->data = 0; 636 } 637 return code; 638 } 639 #endif 640 641 /* Compare a C string and a gs_param_string. */ 642 static bool 643 param_string_eq(const gs_param_string *pcs, const char *str) 644 { 645 return (strlen(str) == pcs->size && 646 !strncmp(str, (const char *)pcs->data, pcs->size)); 647 } 648 649 private int 650 psd_set_color_model(psd_device *xdev, psd_color_model color_model) 651 { 652 xdev->color_model = color_model; 653 if (color_model == psd_DEVICE_GRAY) { 654 xdev->devn_params.std_colorant_names = DeviceGrayComponents; 655 xdev->devn_params.num_std_colorant_names = 1; 656 xdev->color_info.cm_name = "DeviceGray"; 657 xdev->color_info.polarity = GX_CINFO_POLARITY_ADDITIVE; 658 } else if (color_model == psd_DEVICE_RGB) { 659 xdev->devn_params.std_colorant_names = DeviceRGBComponents; 660 xdev->devn_params.num_std_colorant_names = 3; 661 xdev->color_info.cm_name = "DeviceRGB"; 662 xdev->color_info.polarity = GX_CINFO_POLARITY_ADDITIVE; 663 } else if (color_model == psd_DEVICE_CMYK) { 664 xdev->devn_params.std_colorant_names = DeviceCMYKComponents; 665 xdev->devn_params.num_std_colorant_names = 4; 666 xdev->color_info.cm_name = "DeviceCMYK"; 667 xdev->color_info.polarity = GX_CINFO_POLARITY_SUBTRACTIVE; 668 } else if (color_model == psd_DEVICE_N) { 669 xdev->devn_params.std_colorant_names = DeviceCMYKComponents; 670 xdev->devn_params.num_std_colorant_names = 4; 671 xdev->color_info.cm_name = "DeviceN"; 672 xdev->color_info.polarity = GX_CINFO_POLARITY_SUBTRACTIVE; 673 } else { 674 return -1; 675 } 676 677 return 0; 678 } 679 680 /* Set parameters. We allow setting the number of bits per component. */ 681 private int 682 psd_put_params(gx_device * pdev, gs_param_list * plist) 683 { 684 psd_device * const pdevn = (psd_device *) pdev; 685 int code = 0; 686 #if ENABLE_ICC_PROFILE 687 gs_param_string po; 688 gs_param_string prgb; 689 gs_param_string pcmyk; 690 #endif 691 gs_param_string pcm; 692 psd_color_model color_model = pdevn->color_model; 693 gx_device_color_info save_info = pdevn->color_info; 694 695 #if ENABLE_ICC_PROFILE 696 code = psd_param_read_fn(plist, "ProfileOut", &po, 697 sizeof(pdevn->profile_out_fn)); 698 if (code >= 0) 699 code = psd_param_read_fn(plist, "ProfileRgb", &prgb, 700 sizeof(pdevn->profile_rgb_fn)); 701 if (code >= 0) 702 code = psd_param_read_fn(plist, "ProfileCmyk", &pcmyk, 703 sizeof(pdevn->profile_cmyk_fn)); 704 #endif 705 706 if (code >= 0) 707 code = param_read_name(plist, "ProcessColorModel", &pcm); 708 if (code == 0) { 709 if (param_string_eq (&pcm, "DeviceGray")) 710 color_model = psd_DEVICE_GRAY; 711 else if (param_string_eq (&pcm, "DeviceRGB")) 712 color_model = psd_DEVICE_RGB; 713 else if (param_string_eq (&pcm, "DeviceCMYK")) 714 color_model = psd_DEVICE_CMYK; 715 else if (param_string_eq (&pcm, "DeviceN")) 716 color_model = psd_DEVICE_N; 717 else { 718 param_signal_error(plist, "ProcessColorModel", 719 code = gs_error_rangecheck); 720 } 721 } 722 723 if (code >= 0) 724 code = psd_set_color_model(pdevn, color_model); 725 726 /* handle the standard DeviceN related parameters */ 727 if (code == 0) 728 code = devn_printer_put_params(pdev, plist, 729 &(pdevn->devn_params), &(pdevn->equiv_cmyk_colors)); 730 731 if (code < 0) { 732 pdev->color_info = save_info; 733 return code; 734 } 735 736 #if ENABLE_ICC_PROFILE 737 /* Open any ICC profiles that have been specified. */ 738 if (po.data != 0) { 739 memcpy(pdevn->profile_out_fn, po.data, po.size); 740 pdevn->profile_out_fn[po.size] = 0; 741 } 742 if (prgb.data != 0) { 743 memcpy(pdevn->profile_rgb_fn, prgb.data, prgb.size); 744 pdevn->profile_rgb_fn[prgb.size] = 0; 745 } 746 if (pcmyk.data != 0) { 747 memcpy(pdevn->profile_cmyk_fn, pcmyk.data, pcmyk.size); 748 pdevn->profile_cmyk_fn[pcmyk.size] = 0; 749 } 750 if (memcmp(&pdevn->color_info, &save_info, 751 size_of(gx_device_color_info)) != 0) 752 code = psd_open_profiles(pdevn); 753 #endif 754 755 return code; 756 } 757 758 759 /* 760 * This routine will check to see if the color component name match those 761 * that are available amoung the current device's color components. 762 * 763 * Parameters: 764 * dev - pointer to device data structure. 765 * pname - pointer to name (zero termination not required) 766 * nlength - length of the name 767 * 768 * This routine returns a positive value (0 to n) which is the device colorant 769 * number if the name is found. It returns a negative value if not found. 770 */ 771 private int 772 psd_get_color_comp_index(gx_device * dev, const char * pname, 773 int name_size, int component_type) 774 { 775 return devn_get_color_comp_index(dev, 776 &(((psd_device *)dev)->devn_params), 777 &(((psd_device *)dev)->equiv_cmyk_colors), 778 pname, name_size, component_type, ENABLE_AUTO_SPOT_COLORS); 779 } 780 781 782 /* ------ Private definitions ------ */ 783 784 /* All two-byte quantities are stored MSB-first! */ 785 #if arch_is_big_endian 786 # define assign_u16(a,v) a = (v) 787 # define assign_u32(a,v) a = (v) 788 #else 789 # define assign_u16(a,v) a = ((v) >> 8) + ((v) << 8) 790 # define assign_u32(a,v) a = (((v) >> 24) & 0xff) + (((v) >> 8) & 0xff00) + (((v) & 0xff00) << 8) + (((v) & 0xff) << 24) 791 #endif 792 793 typedef struct { 794 FILE *f; 795 796 int width; 797 int height; 798 int base_bytes_pp; /* almost always 3 (rgb) or 4 (CMYK) */ 799 int n_extra_channels; 800 int num_channels; /* base_bytes_pp + any spot colors that are imaged */ 801 /* Map output channel number to original separation number. */ 802 int chnl_to_orig_sep[GX_DEVICE_COLOR_MAX_COMPONENTS]; 803 /* Map output channel number to gx_color_index position. */ 804 int chnl_to_position[GX_DEVICE_COLOR_MAX_COMPONENTS]; 805 806 /* byte offset of image data */ 807 int image_data_off; 808 } psd_write_ctx; 809 810 private int 811 psd_setup(psd_write_ctx *xc, psd_device *dev) 812 { 813 int i; 814 815 #define NUM_CMYK_COMPONENTS 4 816 xc->base_bytes_pp = dev->devn_params.num_std_colorant_names; 817 xc->num_channels = xc->base_bytes_pp; 818 xc->n_extra_channels = dev->devn_params.separations.num_separations; 819 xc->width = dev->width; 820 xc->height = dev->height; 821 822 /* 823 * Determine the order of the output components. This is based upon 824 * the SeparationOrder parameter. This parameter can be used to select 825 * which planes are actually imaged. For the process color model channels 826 * we image the channels which are requested. Non requested process color 827 * model channels are simply filled with white. For spot colors we only 828 * image the requested channels. Note: There are no spot colors with 829 * the RGB color model. 830 */ 831 for (i = 0; i < xc->base_bytes_pp + xc->n_extra_channels; i++) 832 xc->chnl_to_position[i] = -1; 833 for (i = 0; i < xc->base_bytes_pp + xc->n_extra_channels; i++) { 834 int sep_order_num = dev->devn_params.separation_order_map[i]; 835 836 if (sep_order_num != GX_DEVICE_COLOR_MAX_COMPONENTS) { 837 if (i < NUM_CMYK_COMPONENTS) /* Do not rearrange CMYK */ 838 xc->chnl_to_position[i] = sep_order_num; 839 else { /* Re arrange separations */ 840 xc->chnl_to_position[xc->num_channels] = sep_order_num; 841 xc->chnl_to_orig_sep[xc->num_channels++] = i; 842 } 843 } 844 } 845 846 return 0; 847 } 848 849 private int 850 psd_write(psd_write_ctx *xc, const byte *buf, int size) { 851 int code; 852 853 code = fwrite(buf, 1, size, xc->f); 854 if (code < 0) 855 return code; 856 return 0; 857 } 858 859 private int 860 psd_write_8(psd_write_ctx *xc, byte v) 861 { 862 return psd_write(xc, (byte *)&v, 1); 863 } 864 865 private int 866 psd_write_16(psd_write_ctx *xc, bits16 v) 867 { 868 bits16 buf; 869 870 assign_u16(buf, v); 871 return psd_write(xc, (byte *)&buf, 2); 872 } 873 874 private int 875 psd_write_32(psd_write_ctx *xc, bits32 v) 876 { 877 bits32 buf; 878 879 assign_u32(buf, v); 880 return psd_write(xc, (byte *)&buf, 4); 881 } 882 883 private int 884 psd_write_header(psd_write_ctx *xc, psd_device *pdev) 885 { 886 int code = 0; 887 int bytes_pp = xc->num_channels; 888 int chan_idx; 889 int chan_names_len = 0; 890 int sep_num; 891 const devn_separation_name *separation_name; 892 893 psd_write(xc, (const byte *)"8BPS", 4); /* Signature */ 894 psd_write_16(xc, 1); /* Version - Always equal to 1*/ 895 /* Reserved 6 Bytes - Must be zero */ 896 psd_write_32(xc, 0); 897 psd_write_16(xc, 0); 898 psd_write_16(xc, (bits16) bytes_pp); /* Channels (2 Bytes) - Supported range is 1 to 24 */ 899 psd_write_32(xc, xc->height); /* Rows */ 900 psd_write_32(xc, xc->width); /* Columns */ 901 psd_write_16(xc, 8); /* Depth - 1, 8 and 16 */ 902 psd_write_16(xc, (bits16) xc->base_bytes_pp); /* Mode - RGB=3, CMYK=4 */ 903 904 /* Color Mode Data */ 905 psd_write_32(xc, 0); /* No color mode data */ 906 907 /* Image Resources */ 908 909 /* Channel Names */ 910 for (chan_idx = NUM_CMYK_COMPONENTS; chan_idx < xc->num_channels; chan_idx++) { 911 sep_num = xc->chnl_to_orig_sep[chan_idx] - NUM_CMYK_COMPONENTS; 912 separation_name = &(pdev->devn_params.separations.names[sep_num]); 913 chan_names_len += (separation_name->size + 1); 914 } 915 psd_write_32(xc, 12 + (chan_names_len + (chan_names_len % 2)) 916 + (12 + (14 * (xc->num_channels - xc->base_bytes_pp))) 917 + 28); 918 psd_write(xc, (const byte *)"8BIM", 4); 919 psd_write_16(xc, 1006); /* 0x03EE */ 920 psd_write_16(xc, 0); /* PString */ 921 psd_write_32(xc, chan_names_len + (chan_names_len % 2)); 922 for (chan_idx = NUM_CMYK_COMPONENTS; chan_idx < xc->num_channels; chan_idx++) { 923 sep_num = xc->chnl_to_orig_sep[chan_idx] - NUM_CMYK_COMPONENTS; 924 separation_name = &(pdev->devn_params.separations.names[sep_num]); 925 psd_write_8(xc, (byte) separation_name->size); 926 psd_write(xc, separation_name->data, separation_name->size); 927 } 928 if (chan_names_len % 2) 929 psd_write_8(xc, 0); /* pad */ 930 931 /* DisplayInfo - Colors for each spot channels */ 932 psd_write(xc, (const byte *)"8BIM", 4); 933 psd_write_16(xc, 1007); /* 0x03EF */ 934 psd_write_16(xc, 0); /* PString */ 935 psd_write_32(xc, 14 * (xc->num_channels - xc->base_bytes_pp)); /* Length */ 936 for (chan_idx = NUM_CMYK_COMPONENTS; chan_idx < xc->num_channels; chan_idx++) { 937 sep_num = xc->chnl_to_orig_sep[chan_idx] - NUM_CMYK_COMPONENTS; 938 psd_write_16(xc, 02); /* CMYK */ 939 /* PhotoShop stores all component values as if they were additive. */ 940 if (pdev->equiv_cmyk_colors.color[sep_num].color_info_valid) { 941 #define convert_color(component) ((bits16)((65535 * ((double)\ 942 (frac_1 - pdev->equiv_cmyk_colors.color[sep_num].component)) / frac_1))) 943 psd_write_16(xc, convert_color(c)); /* Cyan */ 944 psd_write_16(xc, convert_color(m)); /* Magenta */ 945 psd_write_16(xc, convert_color(y)); /* Yellow */ 946 psd_write_16(xc, convert_color(k)); /* Black */ 947 #undef convert_color 948 } 949 else { /* Else set C = M = Y = 0, K = 1 */ 950 psd_write_16(xc, 65535); /* Cyan */ 951 psd_write_16(xc, 65535); /* Magenta */ 952 psd_write_16(xc, 65535); /* Yellow */ 953 psd_write_16(xc, 0); /* Black */ 954 } 955 psd_write_16(xc, 0); /* Opacity 0 to 100 */ 956 psd_write_8(xc, 2); /* Don't know */ 957 psd_write_8(xc, 0); /* Padding - Always Zero */ 958 } 959 960 /* Image resolution */ 961 psd_write(xc, (const byte *)"8BIM", 4); 962 psd_write_16(xc, 1005); /* 0x03ED */ 963 psd_write_16(xc, 0); /* PString */ 964 psd_write_32(xc, 16); /* Length */ 965 /* Resolution is specified as a fixed 16.16 bits */ 966 psd_write_32(xc, (int) (pdev->HWResolution[0] * 0x10000 + 0.5)); 967 psd_write_16(xc, 1); /* width: 1 --> resolution is pixels per inch */ 968 psd_write_16(xc, 1); /* width: 1 --> resolution is pixels per inch */ 969 psd_write_32(xc, (int) (pdev->HWResolution[1] * 0x10000 + 0.5)); 970 psd_write_16(xc, 1); /* height: 1 --> resolution is pixels per inch */ 971 psd_write_16(xc, 1); /* height: 1 --> resolution is pixels per inch */ 972 973 /* Layer and Mask information */ 974 psd_write_32(xc, 0); /* No layer or mask information */ 975 976 return code; 977 } 978 979 private void 980 psd_calib_row(psd_write_ctx *xc, byte **tile_data, const byte *row, 981 int channel, icmLuBase *luo) 982 { 983 int base_bytes_pp = xc->base_bytes_pp; 984 int n_extra_channels = xc->n_extra_channels; 985 int channels = base_bytes_pp + n_extra_channels; 986 int inn, outn; 987 int x; 988 double in[MAX_CHAN], out[MAX_CHAN]; 989 990 luo->spaces(luo, NULL, &inn, NULL, &outn, NULL, NULL, NULL, NULL); 991 992 for (x = 0; x < xc->width; x++) { 993 if (channel < outn) { 994 int plane_idx; 995 996 for (plane_idx = 0; plane_idx < inn; plane_idx++) 997 in[plane_idx] = row[x*channels+plane_idx] * (1.0 / 255); 998 999 (*tile_data)[x] = (int)(0.5 + 255 * out[channel]); 1000 luo->lookup(luo, out, in); 1001 } else { 1002 (*tile_data)[x] = 255 ^ row[x*channels+base_bytes_pp+channel]; 1003 } 1004 } 1005 } 1006 1007 /* 1008 * Output the image data for the PSD device. The data for the PSD is 1009 * written in separate planes. If the device is psdrgb then we simply 1010 * write three planes of RGB data. The DeviceN parameters (SeparationOrder, 1011 * SeparationCOlorNames, and MaxSeparations) are not applied to the psdrgb 1012 * device. 1013 * 1014 * The DeviceN parameters are applied to the psdcmyk device. If the 1015 * SeparationOrder parameter is not specified then first we write out the data 1016 * for the CMYK planes and then any separation planes. If the SeparationOrder 1017 * parameter is specified, then things are more complicated. Logically we 1018 * would simply write the planes specified by the SeparationOrder data. 1019 * However Photoshop expects there to be CMYK data. First we will write out 1020 * four planes of data for CMYK. If any of these colors are present in the 1021 * SeparationOrder data then the plane data will contain the color information. 1022 * If a color is not present then the plane data will be zero. After the CMYK 1023 * data, we will write out any separation data which is specified in the 1024 * SeparationOrder data. 1025 */ 1026 private int 1027 psd_write_image_data(psd_write_ctx *xc, gx_device_printer *pdev) 1028 { 1029 int code = 0; 1030 int raster = gdev_prn_raster(pdev); 1031 int i, j; 1032 byte *line, *sep_line; 1033 int base_bytes_pp = xc->base_bytes_pp; 1034 int bytes_pp =pdev->color_info.num_components; 1035 int chan_idx; 1036 psd_device *xdev = (psd_device *)pdev; 1037 icmLuBase *luo = xdev->lu_out; 1038 byte *row; 1039 1040 psd_write_16(xc, 0); /* Compression */ 1041 1042 line = gs_alloc_bytes(pdev->memory, raster, "psd_write_image_data"); 1043 sep_line = gs_alloc_bytes(pdev->memory, xc->width, "psd_write_sep_line"); 1044 1045 /* Print the output planes */ 1046 for (chan_idx = 0; chan_idx < xc->num_channels; chan_idx++) { 1047 for (j = 0; j < xc->height; ++j) { 1048 int data_pos = xc->chnl_to_position[chan_idx]; 1049 1050 /* Check if the separation is present in the SeparationOrder */ 1051 if (data_pos >= 0) { 1052 code = gdev_prn_get_bits(pdev, j, line, &row); 1053 if (luo == NULL) { 1054 for (i = 0; i < xc->width; ++i) { 1055 if (base_bytes_pp == 3) { 1056 /* RGB */ 1057 sep_line[i] = row[i*bytes_pp + data_pos]; 1058 } else { 1059 /* CMYK */ 1060 sep_line[i] = 255 - row[i*bytes_pp + data_pos]; 1061 } 1062 } 1063 } else { 1064 psd_calib_row(xc, &sep_line, row, data_pos, luo); 1065 } 1066 psd_write(xc, sep_line, xc->width); 1067 } else { 1068 if (chan_idx < NUM_CMYK_COMPONENTS) { 1069 /* Write empty process color */ 1070 for (i = 0; i < xc->width; ++i) 1071 sep_line[i] = 255; 1072 psd_write(xc, sep_line, xc->width); 1073 } 1074 } 1075 } 1076 } 1077 1078 gs_free_object(pdev->memory, sep_line, "psd_write_sep_line"); 1079 gs_free_object(pdev->memory, line, "psd_write_image_data"); 1080 return code; 1081 } 1082 1083 static int 1084 psd_print_page(gx_device_printer *pdev, FILE *file) 1085 { 1086 psd_write_ctx xc; 1087 1088 xc.f = file; 1089 1090 psd_setup(&xc, (psd_device *)pdev); 1091 psd_write_header(&xc, (psd_device *)pdev); 1092 psd_write_image_data(&xc, pdev); 1093 1094 return 0; 1095 } 1096