1/*---------------------------------------------------------------------------* 2 | PDFlib - A library for generating PDF on the fly | 3 +---------------------------------------------------------------------------+ 4 | Copyright (c) 1997-2004 Thomas Merz and PDFlib GmbH. All rights reserved. | 5 +---------------------------------------------------------------------------+ 6 | | 7 | This software is subject to the PDFlib license. It is NOT in the | 8 | public domain. Extended versions and commercial licenses are | 9 | available, please check http://www.pdflib.com. | 10 | | 11 *---------------------------------------------------------------------------*/ 12 13/* $Id: p_color.c 14574 2005-10-29 16:27:43Z bonefish $ 14 * 15 * PDFlib color routines 16 * 17 */ 18 19#define P_COLOR_C 20 21#include "p_intern.h" 22#include "p_font.h" 23 24 25 26 27/* Avoid wrong error messages due to rounding artifacts. 28 * This doesn't do any harm since we truncate to 5 decimal places anyway 29 * when producing PDF output. 30 */ 31#define EPSILON ((float) (1.0 + PDF_SMALLREAL)) 32 33static void pdf_check_color_values(PDF *p, pdf_colorspacetype type, 34 float c1, float c2, float c3, float c4); 35 36int 37pdf_color_components(PDF *p, int slot) 38{ 39 pdf_colorspace *cs; 40 int components = 0; 41 42 cs = &p->colorspaces[slot]; 43 44 switch (cs->type) { 45 case DeviceGray: 46 case Indexed: 47 components = 1; 48 break; 49 50 case DeviceRGB: 51 components = 3; 52 break; 53 54 case DeviceCMYK: 55 components = 4; 56 break; 57 58 case PatternCS: 59 if (cs->val.pattern.base == pdc_undef) 60 components = 0; /* PaintType 1: colored pattern */ 61 else 62 components = pdf_color_components(p, cs->val.pattern.base); 63 64 default: 65 pdc_error(p->pdc, PDF_E_INT_BADCS, 66 pdc_errprintf(p->pdc, "%d", cs->type), 0, 0, 0); 67 } 68 69 return components; 70} /* pdf_color_components */ 71 72void 73pdf_write_color_values(PDF *p, pdf_color *color, pdf_drawmode drawmode) 74{ 75 pdf_colorspace *cs = &p->colorspaces[color->cs]; 76 77 switch (cs->type) { 78 case DeviceGray: 79 pdc_printf(p->out, "%f", color->val.gray); 80 81 if (drawmode == pdf_fill) 82 pdc_puts(p->out, " g\n"); 83 else if (drawmode == pdf_stroke) 84 pdc_puts(p->out, " G\n"); 85 break; 86 87 case DeviceRGB: 88 pdc_printf(p->out, "%f %f %f", 89 color->val.rgb.r, color->val.rgb.g, color->val.rgb.b); 90 91 if (drawmode == pdf_fill) 92 pdc_puts(p->out, " rg\n"); 93 else if (drawmode == pdf_stroke) 94 pdc_puts(p->out, " RG\n"); 95 break; 96 97 case DeviceCMYK: 98 pdc_printf(p->out, "%f %f %f %f", 99 color->val.cmyk.c, color->val.cmyk.m, 100 color->val.cmyk.y, color->val.cmyk.k); 101 102 if (drawmode == pdf_fill) 103 pdc_puts(p->out, " k\n"); 104 else if (drawmode == pdf_stroke) 105 pdc_puts(p->out, " K\n"); 106 break; 107 108 109 case PatternCS: 110 if (drawmode == pdf_fill) { 111 if (p->pattern[color->val.pattern].painttype == 1) { 112 pdc_puts(p->out, "/Pattern cs"); 113 } else if (p->pattern[color->val.pattern].painttype == 2) { 114 pdc_printf(p->out, "/CS%d cs ", color->cs); 115 pdf_write_color_values(p, 116 &p->cstate[p->sl].fill, pdf_none); 117 } 118 pdc_printf(p->out, "/P%d scn\n", color->val.pattern); 119 120 } else if (drawmode == pdf_stroke) { 121 if (p->pattern[color->val.pattern].painttype == 1) { 122 pdc_puts(p->out, "/Pattern CS"); 123 } else if (p->pattern[color->val.pattern].painttype == 2) { 124 pdc_printf(p->out, "/CS%d CS ", color->cs); 125 pdf_write_color_values(p, 126 &p->cstate[p->sl].stroke, pdf_none); 127 } 128 pdc_printf(p->out, "/P%d SCN\n", color->val.pattern); 129 } 130 131 p->pattern[color->val.pattern].used_on_current_page = pdc_true; 132 break; 133 134 135 case Indexed: /* LATER */ 136 default: 137 pdc_error(p->pdc, PDF_E_INT_BADCS, 138 pdc_errprintf(p->pdc, "%d", 139 p->colorspaces[color->cs].type), 0, 0, 0); 140 } 141} /* pdf_write_color_values */ 142 143static pdc_bool 144pdf_color_equal(PDF *p, pdf_color *c1, pdf_color *c2) 145{ 146 pdf_colorspace *cs1; 147 148 cs1 = &p->colorspaces[c1->cs]; 149 150 if (c1->cs != c2->cs) 151 return pdc_false; 152 153 switch (cs1->type) { 154 case DeviceGray: 155 return (c1->val.gray == c2->val.gray); 156 break; 157 158 case DeviceRGB: 159 return (c1->val.rgb.r == c2->val.rgb.r && 160 c1->val.rgb.g == c2->val.rgb.g && 161 c1->val.rgb.b == c2->val.rgb.b); 162 break; 163 164 case DeviceCMYK: 165 return (c1->val.cmyk.c == c2->val.cmyk.c && 166 c1->val.cmyk.m == c2->val.cmyk.m && 167 c1->val.cmyk.y == c2->val.cmyk.y && 168 c1->val.cmyk.k == c2->val.cmyk.k); 169 break; 170 171 case Indexed: 172 return (c1->val.idx == c2->val.idx); 173 break; 174 175 case PatternCS: 176 return (c1->val.pattern == c2->val.pattern); 177 break; 178 179 180 default: 181 break; 182 } 183 184 return pdc_true; 185} /* pdf_color_equal */ 186 187static pdc_bool 188pdf_colorspace_equal(PDF *p, pdf_colorspace *cs1, pdf_colorspace *cs2) 189{ 190 if (cs1->type != cs2->type) 191 return pdc_false; 192 193 switch (cs1->type) { 194 case DeviceGray: 195 case DeviceRGB: 196 case DeviceCMYK: 197 return pdc_true; 198 break; 199 200 201 case Indexed: 202 return ((cs1->val.indexed.base == cs2->val.indexed.base) && 203 (cs1->val.indexed.palette_size==cs2->val.indexed.palette_size)&& 204 (cs1->val.indexed.colormap_id != PDC_BAD_ID && 205 cs1->val.indexed.colormap_id == cs2->val.indexed.colormap_id)); 206 break; 207 208 case PatternCS: 209 return (cs1->val.pattern.base == cs2->val.pattern.base); 210 break; 211 212 213 default: 214 pdc_error(p->pdc, PDF_E_INT_BADCS, 215 pdc_errprintf(p->pdc, "%d", cs1->type), 0, 0, 0); 216 } 217 218 return pdc_false; 219} /* pdf_colorspace_equal */ 220 221static void 222pdf_grow_colorspaces(PDF *p) 223{ 224 int i; 225 226 p->colorspaces = (pdf_colorspace *) pdc_realloc(p->pdc, p->colorspaces, 227 sizeof(pdf_colorspace) * 2 * p->colorspaces_capacity, 228 "pdf_grow_colorspaces"); 229 230 for (i = p->colorspaces_capacity; i < 2 * p->colorspaces_capacity; i++) { 231 p->colorspaces[i].used_on_current_page = pdc_false; 232 } 233 234 p->colorspaces_capacity *= 2; 235} 236 237int 238pdf_add_colorspace(PDF *p, pdf_colorspace *cs, pdc_bool inuse) 239{ 240 pdf_colorspace *cs_new; 241 static const char fn[] = "pdf_add_colorspace"; 242 int slot; 243 244 for (slot = 0; slot < p->colorspaces_number; slot++) 245 { 246 if (pdf_colorspace_equal(p, &p->colorspaces[slot], cs)) 247 { 248 if (inuse) 249 p->colorspaces[slot].used_on_current_page = pdc_true; 250 return slot; 251 } 252 } 253 254 slot = p->colorspaces_number; 255 256 if (p->colorspaces_number >= p->colorspaces_capacity) 257 pdf_grow_colorspaces(p); 258 259 cs_new = &p->colorspaces[slot]; 260 261 cs_new->type = cs->type; 262 263 /* don't allocate id for simple color spaces, since we don't write these */ 264 if (PDF_SIMPLE_COLORSPACE(cs)) { 265 cs_new->obj_id = PDC_BAD_ID; 266 cs_new->used_on_current_page = pdc_false; 267 268 } else { 269 cs_new->obj_id = pdc_alloc_id(p->out); 270 cs_new->used_on_current_page = inuse; 271 } 272 273 switch (cs_new->type) { 274 case DeviceGray: 275 case DeviceRGB: 276 case DeviceCMYK: 277 break; 278 279 280 case Indexed: 281 cs_new->val.indexed.base = cs->val.indexed.base; 282 cs_new->val.indexed.palette_size = cs->val.indexed.palette_size; 283 cs_new->val.indexed.colormap_id = pdc_alloc_id(p->out); 284 cs_new->val.indexed.colormap = 285 (pdf_colormap *) pdc_malloc(p->pdc, sizeof(pdf_colormap), fn); 286 memcpy(cs_new->val.indexed.colormap, cs->val.indexed.colormap, 287 sizeof(pdf_colormap)); 288 cs_new->val.indexed.colormap_done = pdc_false; 289 break; 290 291 case PatternCS: 292 cs_new->val.pattern.base = cs->val.pattern.base; 293 break; 294 295 296 default: 297 pdc_error(p->pdc, PDF_E_INT_BADCS, 298 pdc_errprintf(p->pdc, "%d", cs_new->type), 0, 0, 0); 299 } 300 301 p->colorspaces_number++; 302 303 return slot; 304} /* pdf_add_colorspace */ 305 306void 307pdf_init_cstate(PDF *p) 308{ 309 pdf_cstate *cstate; 310 311 cstate = &p->cstate[p->sl]; 312 313 cstate->fill.cs = DeviceGray; 314 cstate->fill.val.gray = (float) 0.0; 315 316 cstate->stroke.cs = DeviceGray; 317 cstate->stroke.val.gray = (float) 0.0; 318} 319 320void 321pdf_set_color_values(PDF *p, pdf_color *c, pdf_drawmode drawmode) 322{ 323 pdf_color *current; 324 pdf_colorspace *cs; 325 326 cs = &p->colorspaces[c->cs]; 327 328 if (drawmode == pdf_stroke || drawmode == pdf_fillstroke) { 329 current = &p->cstate[p->sl].stroke; 330 331 if (!pdf_color_equal(p, current, c) || PDF_FORCE_OUTPUT()) 332 { 333 if (PDF_GET_STATE(p) != pdf_state_document) 334 pdf_write_color_values(p, c, pdf_stroke); 335 336 *current = *c; 337 } 338 } 339 if (drawmode == pdf_fill || drawmode == pdf_fillstroke) { 340 current = &p->cstate[p->sl].fill; 341 342 if (!pdf_color_equal(p, current, c) || PDF_FORCE_OUTPUT()) 343 { 344 if (PDF_GET_STATE(p) != pdf_state_document) 345 pdf_write_color_values(p, c, pdf_fill); 346 347 *current = *c; 348 } 349 } 350 351 /* simple colorspaces don't get written */ 352 if (!PDF_SIMPLE_COLORSPACE(cs)) 353 cs->used_on_current_page = pdc_true; 354 355} /* pdf_set_color_values */ 356 357PDFLIB_API void PDFLIB_CALL 358PDF_setgray_fill(PDF *p, float g) 359{ 360 static const char fn[] = "PDF_setgray_fill"; 361 pdf_color c; 362 363 if (!pdf_enter_api(p, fn, pdf_state_content, "(p[%p], %g)\n", 364 (void *) p, g)) 365 return; 366 367 pdf_check_color_values(p, DeviceGray, g, (float) 0, (float) 0, (float) 0); 368 c.cs = DeviceGray; 369 c.val.gray = g; 370 pdf_set_color_values(p, &c, pdf_fill); 371} 372 373PDFLIB_API void PDFLIB_CALL 374PDF_setgray_stroke(PDF *p, float g) 375{ 376 static const char fn[] = "PDF_setgray_stroke"; 377 pdf_color c; 378 379 if (!pdf_enter_api(p, fn, pdf_state_content, "(p[%p], %g)\n", 380 (void *) p, g)) 381 return; 382 383 pdf_check_color_values(p, DeviceGray, g, (float) 0, (float) 0, (float) 0); 384 c.cs = DeviceGray; 385 c.val.gray = g; 386 pdf_set_color_values(p, &c, pdf_stroke); 387} 388 389PDFLIB_API void PDFLIB_CALL 390PDF_setgray(PDF *p, float g) 391{ 392 static const char fn[] = "PDF_setgray"; 393 pdf_color c; 394 395 if (!pdf_enter_api(p, fn, pdf_state_content, "(p[%p], %g)\n", 396 (void *) p, g)) 397 return; 398 399 pdf_check_color_values(p, DeviceGray, g, (float) 0, (float) 0, (float) 0); 400 c.cs = DeviceGray; 401 c.val.gray = g; 402 pdf_set_color_values(p, &c, pdf_fillstroke); 403} 404 405/* RGB functions */ 406 407PDFLIB_API void PDFLIB_CALL 408PDF_setrgbcolor_fill(PDF *p, float r, float g, float b) 409{ 410 static const char fn[] = "PDF_setrgbcolor_fill"; 411 pdf_color c; 412 413 if (!pdf_enter_api(p, fn, pdf_state_content, "(p[%p], %g, %g, %g)\n", 414 (void *) p, r, g, b)) 415 return; 416 417 pdf_check_color_values(p, DeviceRGB, r, g, b, 0); 418 c.cs = DeviceRGB; 419 c.val.rgb.r = r; 420 c.val.rgb.g = g; 421 c.val.rgb.b = b; 422 pdf_set_color_values(p, &c, pdf_fill); 423} 424 425PDFLIB_API void PDFLIB_CALL 426PDF_setrgbcolor_stroke(PDF *p, float r, float g, float b) 427{ 428 static const char fn[] = "PDF_setrgbcolor_stroke"; 429 pdf_color c; 430 431 if (!pdf_enter_api(p, fn, pdf_state_content, "(p[%p], %g, %g, %g)\n", 432 (void *) p, r, g, b)) 433 return; 434 435 pdf_check_color_values(p, DeviceRGB, r, g, b, 0); 436 c.cs = DeviceRGB; 437 c.val.rgb.r = r; 438 c.val.rgb.g = g; 439 c.val.rgb.b = b; 440 pdf_set_color_values(p, &c, pdf_stroke); 441} 442 443PDFLIB_API void PDFLIB_CALL 444PDF_setrgbcolor(PDF *p, float r, float g, float b) 445{ 446 static const char fn[] = "PDF_setrgbcolor"; 447 pdf_color c; 448 449 if (!pdf_enter_api(p, fn, pdf_state_content, "(p[%p], %g, %g, %g)\n", 450 (void *) p, r, g, b)) 451 return; 452 453 pdf_check_color_values(p, DeviceRGB, r, g, b, 0); 454 c.cs = DeviceRGB; 455 c.val.rgb.r = r; 456 c.val.rgb.g = g; 457 c.val.rgb.b = b; 458 pdf_set_color_values(p, &c, pdf_fillstroke); 459} 460 461void 462pdf_init_colorspaces(PDF *p) 463{ 464 int i, slot; 465 pdf_colorspace cs; 466 467 468 p->colorspaces_number = 0; 469 p->colorspaces_capacity = COLORSPACES_CHUNKSIZE; 470 471 p->colorspaces = (pdf_colorspace *) 472 pdc_malloc(p->pdc, sizeof(pdf_colorspace) * p->colorspaces_capacity, 473 "pdf_init_colorspaces"); 474 475 for (i = 0; i < p->colorspaces_capacity; i++) { 476 p->colorspaces[i].used_on_current_page = pdc_false; 477 } 478 479 /* 480 * Initialize a few slots with simple color spaces for easier use. 481 * These can be used without further ado: the slot number is identical 482 * to the enum value due to the ordering below. 483 */ 484 485 cs.type = DeviceGray; 486 slot = pdf_add_colorspace(p, &cs, pdc_false); 487 cs.type = DeviceRGB; 488 slot = pdf_add_colorspace(p, &cs, pdc_false); 489 cs.type = DeviceCMYK; 490 slot = pdf_add_colorspace(p, &cs, pdc_false); 491 492} /* pdf_init_colorspaces */ 493 494void 495pdf_write_page_colorspaces(PDF *p) 496{ 497 int i, total = 0; 498 499 for (i = 0; i < p->colorspaces_number; i++) 500 if (p->colorspaces[i].used_on_current_page) 501 total++; 502 503 if (total > 0 504 ) { 505 pdc_puts(p->out, "/ColorSpace"); 506 507 pdc_begin_dict(p->out); /* color space names */ 508 509 for (i = 0; i < p->colorspaces_number; i++) { 510 pdf_colorspace *cs = &p->colorspaces[i]; 511 512 if (cs->used_on_current_page) { 513 cs->used_on_current_page = pdc_false; /* reset */ 514 515 /* don't write simple color spaces as resource */ 516 if (!PDF_SIMPLE_COLORSPACE(cs)) 517 pdc_printf(p->out, "/CS%d %ld 0 R\n", i, cs->obj_id); 518 } 519 } 520 521 522 pdc_end_dict(p->out); /* color space names */ 523 } 524} /* pdf_write_page_colorspaces */ 525 526void 527pdf_write_function_dict(PDF *p, pdf_color *c0, pdf_color *c1, float N) 528{ 529 pdf_colorspace *cs; 530 531 cs = &p->colorspaces[c1->cs]; 532 533 pdc_begin_dict(p->out); /* function dict */ 534 535 pdc_puts(p->out, "/FunctionType 2\n"); 536 pdc_puts(p->out, "/Domain[0 1]\n"); 537 pdc_printf(p->out, "/N %f\n", N); 538 539 switch (cs->type) { 540 541 case DeviceGray: 542 pdc_puts(p->out, "/Range[0 1]\n"); 543 if (c0->val.gray != 0) pdc_printf(p->out, "/C0[%f]\n", c0->val.gray); 544 if (c1->val.gray != 1) pdc_printf(p->out, "/C1[%f]", c1->val.gray); 545 break; 546 547 case DeviceRGB: 548 pdc_puts(p->out, "/Range[0 1 0 1 0 1]\n"); 549 pdc_printf(p->out, "/C0[%f %f %f]\n", 550 c0->val.rgb.r, c0->val.rgb.g, c0->val.rgb.b); 551 pdc_printf(p->out, "/C1[%f %f %f]", 552 c1->val.rgb.r, c1->val.rgb.g, c1->val.rgb.b); 553 break; 554 555 case DeviceCMYK: 556 pdc_puts(p->out, "/Range[0 1 0 1 0 1 0 1]\n"); 557 pdc_printf(p->out, "/C0[%f %f %f %f]\n", 558 c0->val.cmyk.c, c0->val.cmyk.m, c0->val.cmyk.y, c0->val.cmyk.k); 559 pdc_printf(p->out, "/C1[%f %f %f %f]", 560 c1->val.cmyk.c, c1->val.cmyk.m, c1->val.cmyk.y, c1->val.cmyk.k); 561 break; 562 563 564 default: 565 pdc_error(p->pdc, PDF_E_INT_BADCS, 566 pdc_errprintf(p->pdc, "%d", cs->type), 0, 0, 0); 567 } 568 569 pdc_end_dict(p->out); /* function dict */ 570} /* pdf_write_function_dict */ 571 572void 573pdf_write_colormap(PDF *p, int slot) 574{ 575 PDF_data_source src; 576 pdf_colorspace *cs, *base; 577 pdc_id length_id; 578 579 cs = &p->colorspaces[slot]; 580 581 if (cs->type != Indexed || cs->val.indexed.colormap_done == pdc_true) 582 return; 583 584 base = &p->colorspaces[cs->val.indexed.base]; 585 586 pdc_begin_obj(p->out, cs->val.indexed.colormap_id); /* colormap object */ 587 pdc_begin_dict(p->out); 588 589 if (p->debug['a']) 590 pdc_puts(p->out, "/Filter/ASCIIHexDecode\n"); 591 else if (pdc_get_compresslevel(p->out)) 592 pdc_puts(p->out, "/Filter/FlateDecode\n"); 593 594 /* Length of colormap object */ 595 length_id = pdc_alloc_id(p->out); 596 pdc_printf(p->out,"/Length %ld 0 R\n", length_id); 597 pdc_end_dict(p->out); 598 599 src.init = NULL; 600 src.fill = pdf_data_source_buf_fill; 601 src.terminate = NULL; 602 603 src.buffer_start = (unsigned char *) cs->val.indexed.colormap; 604 605 src.buffer_length = (size_t) (cs->val.indexed.palette_size * 606 pdf_color_components(p, cs->val.indexed.base)); 607 608 src.bytes_available = 0; 609 src.next_byte = NULL; 610 611 /* Write colormap data */ 612 if (p->debug['a']) 613 pdf_ASCIIHexEncode(p, &src); 614 else { 615 pdf_copy_stream(p, &src, pdc_true); /* colormap data */ 616 } 617 618 pdc_end_obj(p->out); /* colormap object */ 619 620 pdc_put_pdfstreamlength(p->out, length_id); 621 622 /* free the colormap now that it's written */ 623 pdc_free(p->pdc, cs->val.indexed.colormap); 624 cs->val.indexed.colormap = NULL; 625 cs->val.indexed.colormap_done = pdc_true; 626} /* pdf_write_colormap */ 627 628void 629pdf_write_colorspace(PDF *p, int slot, pdc_bool direct) 630{ 631 pdf_colorspace *cs; 632 int base; 633 634 if (slot < 0 || slot >= p->colorspaces_number) 635 pdc_error(p->pdc, PDF_E_INT_BADCS, 636 pdc_errprintf(p->pdc, "%d", slot), 0, 0, 0); 637 638 cs = &p->colorspaces[slot]; 639 640 /* we always write simple colorspaces directly */ 641 if (PDF_SIMPLE_COLORSPACE(cs)) 642 direct = pdc_true; 643 644 if (!direct) { 645 pdc_printf(p->out, " %ld 0 R", cs->obj_id); 646 return; 647 } 648 649 switch (cs->type) { 650 case DeviceGray: 651 pdc_printf(p->out, "/DeviceGray"); 652 break; 653 654 case DeviceRGB: 655 pdc_printf(p->out, "/DeviceRGB"); 656 break; 657 658 case DeviceCMYK: 659 pdc_printf(p->out, "/DeviceCMYK"); 660 break; 661 662 663 664 case Indexed: 665 base = cs->val.indexed.base; 666 667 pdc_puts(p->out, "[/Indexed"); 668 669 pdf_write_colorspace(p, base, pdc_false); 670 pdc_puts(p->out, " "); 671 672 pdc_printf(p->out, "%d %ld 0 R", cs->val.indexed.palette_size - 1, 673 cs->val.indexed.colormap_id); 674 pdc_puts(p->out, "]"); 675 break; 676 677 case PatternCS: 678 pdc_printf(p->out, "[/Pattern"); 679 pdf_write_colorspace(p, cs->val.pattern.base, pdc_false); 680 pdc_puts(p->out, "]"); 681 break; 682 683 default: 684 pdc_error(p->pdc, PDF_E_INT_BADCS, 685 pdc_errprintf(p->pdc, "%d", cs->type), 0, 0, 0); 686 } 687} /* pdf_write_colorspace */ 688 689void 690pdf_write_doc_colorspaces(PDF *p) 691{ 692 int i; 693 694 for (i = 0; i < p->colorspaces_number; i++) { 695 pdf_colorspace *cs = &p->colorspaces[i]; 696 697 /* don't write simple color spaces as resource */ 698 if (PDF_SIMPLE_COLORSPACE(cs)) 699 continue; 700 701 pdc_begin_obj(p->out, cs->obj_id); 702 pdf_write_colorspace(p, i, pdc_true); 703 pdc_puts(p->out, "\n"); 704 pdc_end_obj(p->out); /* color space resource */ 705 706 pdf_write_colormap(p, i); /* write pending colormaps */ 707 } 708} 709 710void 711pdf_cleanup_colorspaces(PDF *p) 712{ 713 int i; 714 715 if (!p->colorspaces) 716 return; 717 718 for (i = 0; i < p->colorspaces_number; i++) { 719 pdf_colorspace *cs = &p->colorspaces[i];; 720 721 switch (cs->type) { 722 case DeviceGray: 723 case DeviceRGB: 724 case DeviceCMYK: 725 case PatternCS: 726 break; 727 728 case Indexed: 729 if (cs->val.indexed.colormap) 730 pdc_free(p->pdc, cs->val.indexed.colormap); 731 break; 732 733 734 default: 735 pdc_error(p->pdc, PDF_E_INT_BADCS, 736 pdc_errprintf(p->pdc, "%d", cs->type), 0, 0, 0); 737 } 738 } 739 740 pdc_free(p->pdc, p->colorspaces); 741 p->colorspaces = NULL; 742} 743 744 745 746 747 748PDFLIB_API int PDFLIB_CALL 749PDF_makespotcolor(PDF *p, const char *spotname, int reserved) 750{ 751 static const char fn[] = "PDF_makespotcolor"; 752 int slot = -1; 753 754 if (!pdf_enter_api(p, fn, 755 (pdf_state) (pdf_state_content | pdf_state_document), 756 "(p[%p], \"%s\", %d)", (void *) p, spotname, reserved)) 757 { 758 PDF_RETURN_HANDLE(p, slot) 759 } 760 761 pdc_error(p->pdc, PDF_E_UNSUPP_SPOTCOLOR, 0, 0, 0, 0); 762 763 PDF_RETURN_HANDLE(p, slot) 764} 765 766 767 768static void 769pdf_check_color_values( 770 PDF *p, 771 pdf_colorspacetype type, 772 float c1, float c2, float c3, float c4) 773{ 774 switch (type) { 775 case DeviceGray: 776 if (c1 < 0.0 || c1 > EPSILON ) 777 pdc_error(p->pdc, PDC_E_ILLARG_FLOAT, 778 "c1", pdc_errprintf(p->pdc, "%f", c1), 0, 0); 779 break; 780 781 case DeviceRGB: 782 if (c1 < 0.0 || c1 > EPSILON ) 783 pdc_error(p->pdc, PDC_E_ILLARG_FLOAT, 784 "c1", pdc_errprintf(p->pdc, "%f", c1), 0, 0); 785 if (c2 < 0.0 || c2 > EPSILON ) 786 pdc_error(p->pdc, PDC_E_ILLARG_FLOAT, 787 "c2", pdc_errprintf(p->pdc, "%f", c2), 0, 0); 788 if (c3 < 0.0 || c3 > EPSILON ) 789 pdc_error(p->pdc, PDC_E_ILLARG_FLOAT, 790 "c3", pdc_errprintf(p->pdc, "%f", c3), 0, 0); 791 792 break; 793 794 case DeviceCMYK: 795 if (c1 < 0.0 || c1 > EPSILON ) 796 pdc_error(p->pdc, PDC_E_ILLARG_FLOAT, 797 "c1", pdc_errprintf(p->pdc, "%f", c1), 0, 0); 798 if (c2 < 0.0 || c2 > EPSILON ) 799 pdc_error(p->pdc, PDC_E_ILLARG_FLOAT, 800 "c2", pdc_errprintf(p->pdc, "%f", c2), 0, 0); 801 if (c3 < 0.0 || c3 > EPSILON ) 802 pdc_error(p->pdc, PDC_E_ILLARG_FLOAT, 803 "c3", pdc_errprintf(p->pdc, "%f", c3), 0, 0); 804 805 if (c4 < 0.0 || c4 > EPSILON ) 806 pdc_error(p->pdc, PDC_E_ILLARG_FLOAT, 807 "c4", pdc_errprintf(p->pdc, "%f", c4), 0, 0); 808 break; 809 810 811 812 case PatternCS: 813 pdf_check_handle(p, (int) c1, pdc_patternhandle); 814 break; 815 816 case Separation: 817 pdf_check_handle(p, (int) c1, pdc_colorhandle); 818 if (c2 < 0.0 || c2 > EPSILON ) 819 pdc_error(p->pdc, PDC_E_ILLARG_FLOAT, 820 "c2", pdc_errprintf(p->pdc, "%f", c2), 0, 0); 821 break; 822 823 case Indexed: 824 default: 825 break; 826 } 827} /* pdf_check_color_values */ 828 829static const pdc_keyconn pdf_fstype_keylist[] = 830{ 831 {"stroke", pdf_stroke}, 832 {"fill", pdf_fill}, 833 {"fillstroke", pdf_stroke | pdf_fill}, 834 {"both", pdf_stroke | pdf_fill}, 835 {NULL, 0} 836}; 837 838void 839pdf__setcolor( 840 PDF *p, 841 const char *fstype, 842 const char *colorspace, 843 float c1, float c2, float c3, float c4) 844{ 845 pdf_color c; 846 pdf_drawmode drawmode = pdf_none; 847 pdf_colorspace cs; 848 int k; 849 850 k = pdc_get_keycode_ci(fstype, pdf_fstype_keylist); 851 if (k == PDC_KEY_NOTFOUND) 852 pdc_error(p->pdc, PDC_E_ILLARG_STRING, "fstype", fstype, 0, 0); 853 drawmode = (pdf_drawmode) k; 854 855 k = pdc_get_keycode_ci(colorspace, pdf_colorspace_keylist); 856 if (k == PDC_KEY_NOTFOUND) 857 pdc_error(p->pdc, PDC_E_ILLARG_STRING, "colorspace", colorspace, 0, 0); 858 cs.type = (pdf_colorspacetype) k; 859 860 switch (cs.type) { 861 862 case DeviceGray: 863 c.cs = cs.type; 864 c.val.gray = c1; 865 pdf_check_color_values(p, cs.type, c1, c2, c3, c4); 866 break; 867 868 case DeviceRGB: 869 c.cs = cs.type; 870 c.val.rgb.r = c1; 871 c.val.rgb.g = c2; 872 c.val.rgb.b = c3; 873 pdf_check_color_values(p, cs.type, c1, c2, c3, c4); 874 break; 875 876 case DeviceCMYK: 877 c.cs = cs.type; 878 c.val.cmyk.c = c1; 879 c.val.cmyk.m = c2; 880 c.val.cmyk.y = c3; 881 c.val.cmyk.k = c4; 882 pdf_check_color_values(p, cs.type, c1, c2, c3, c4); 883 break; 884 885 886 case PatternCS: 887 888 c.val.pattern = (int) c1; 889 PDF_INPUT_HANDLE(p, c.val.pattern) 890 pdf_check_color_values(p, cs.type, c1, c2, c3, c4); 891 892 if (p->pattern[c.val.pattern].painttype == 1) { 893 cs.val.pattern.base = pdc_undef; 894 c.cs = pdf_add_colorspace(p, &cs, pdc_false); 895 } else { 896 cs.val.pattern.base = p->cstate[p->sl].fill.cs; 897 c.cs = pdf_add_colorspace(p, &cs, pdc_true); 898 } 899 break; 900 901 902 default: 903 pdc_error(p->pdc, PDC_E_OPT_UNSUPP, colorspace, 0, 0, 0); 904 } 905 906 pdf_set_color_values(p, &c, drawmode); 907} 908 909PDFLIB_API void PDFLIB_CALL 910PDF_setcolor( 911 PDF *p, 912 const char *fstype, 913 const char *colorspace, 914 float c1, float c2, float c3, float c4) 915{ 916 static const char fn[] = "PDF_setcolor"; 917 int legal_states; 918 919 if (PDF_GET_STATE(p) == pdf_state_glyph && !pdf_get_t3colorized(p)) 920 legal_states = pdf_state_page | pdf_state_pattern | pdf_state_template; 921 else 922 legal_states = pdf_state_content | pdf_state_document; 923 924 if (!pdf_enter_api(p, fn, (pdf_state) legal_states, 925 "(p[%p], \"%s\", \"%s\", %g, %g, %g, %g)\n", 926 (void *) p, fstype, colorspace, c1, c2, c3, c4)) 927 return; 928 929 if (!fstype || !*fstype) 930 pdc_error(p->pdc, PDC_E_ILLARG_EMPTY, "fstype", 0, 0, 0); 931 932 if (!colorspace || !*colorspace) 933 pdc_error(p->pdc, PDC_E_ILLARG_EMPTY, "colorspace", 0, 0, 0); 934 935 pdf__setcolor(p, fstype, colorspace, c1, c2, c3, c4); 936} 937