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_shading.c 14574 2005-10-29 16:27:43Z bonefish $ 14 * 15 * PDFlib routines for smooth shading 16 * 17 */ 18 19#include "p_intern.h" 20#include "p_font.h" 21 22typedef enum 23{ 24 shnone = 0, 25 axial = 2, 26 radial = 3 27} pdf_shadingtype_e; 28 29struct pdf_shading_s { 30 pdc_id obj_id; /* object id of this shading */ 31 pdc_bool used_on_current_page; /* this shading used on current page */ 32}; 33 34void 35pdf_init_shadings(PDF *p) 36{ 37 int i; 38 39 p->shadings_number = 0; 40 p->shadings_capacity = SHADINGS_CHUNKSIZE; 41 42 p->shadings = (pdf_shading *) pdc_malloc(p->pdc, 43 sizeof(pdf_shading) * p->shadings_capacity, "pdf_init_shadings"); 44 45 for (i = 0; i < p->shadings_capacity; i++) { 46 p->shadings[i].used_on_current_page = pdc_false; 47 p->shadings[i].obj_id = PDC_BAD_ID; 48 } 49} 50 51static void 52pdf_grow_shadings(PDF *p) 53{ 54 int i; 55 56 p->shadings = (pdf_shading *) pdc_realloc(p->pdc, p->shadings, 57 sizeof(pdf_shading) * 2 * p->shadings_capacity, "pdf_grow_shadings"); 58 59 for (i = p->shadings_capacity; i < 2 * p->shadings_capacity; i++) { 60 p->shadings[i].used_on_current_page = pdc_false; 61 p->shadings[i].obj_id = PDC_BAD_ID; 62 } 63 64 p->shadings_capacity *= 2; 65} 66 67void 68pdf_write_page_shadings(PDF *p) 69{ 70 int i, total = 0; 71 72 for (i = 0; i < p->shadings_number; i++) 73 if (p->shadings[i].used_on_current_page) 74 total++; 75 76 if (total > 0) { 77 pdc_puts(p->out, "/Shading"); 78 79 pdc_begin_dict(p->out); /* Shading */ 80 81 for (i = 0; i < p->shadings_number; i++) { 82 if (p->shadings[i].used_on_current_page) { 83 p->shadings[i].used_on_current_page = pdc_false; /* reset */ 84 pdc_printf(p->out, "/Sh%d %ld 0 R\n", i, p->shadings[i].obj_id); 85 } 86 } 87 88 pdc_end_dict(p->out); /* Shading */ 89 } 90} 91 92void 93pdf_cleanup_shadings(PDF *p) 94{ 95 if (p->shadings) { 96 pdc_free(p->pdc, p->shadings); 97 p->shadings = NULL; 98 } 99} 100 101static const pdc_defopt pdf_shading_pattern_options[] = 102{ 103 {"gstate", pdc_gstatehandle, 0, 1, 1, 0, 0, NULL}, 104 PDC_OPT_TERMINATE 105}; 106 107PDFLIB_API int PDFLIB_CALL 108PDF_shading_pattern(PDF *p, int shading, const char *optlist) 109{ 110 static const char fn[] = "PDF_shading_pattern"; 111 pdc_resopt *results; 112 pdc_clientdata data; 113 int gstate = -1; 114 int retval = -1; 115 116 if (!pdf_enter_api(p, fn, 117 (pdf_state) (pdf_state_document | pdf_state_page | pdf_state_font), 118 "(p[%p], %d, \"%s\")", (void *) p, shading, optlist)) { 119 PDF_RETURN_HANDLE(p, retval) 120 } 121 122 if (p->compatibility == PDC_1_3) 123 pdc_error(p->pdc, PDF_E_SHADING13, 0, 0, 0, 0); 124 125 PDF_INPUT_HANDLE(p, shading) 126 pdf_check_handle(p, shading, pdc_shadinghandle); 127 128 if (optlist && strlen(optlist)) { 129 data.maxgstate = p->extgstates_number - 1; 130 data.hastobepos = p->hastobepos; 131 132 results = pdc_parse_optionlist(p->pdc, 133 optlist, pdf_shading_pattern_options, &data, pdc_true); 134 135 (void) pdc_get_optvalues(p->pdc, "gstate", results, &gstate, NULL); 136 137 pdc_cleanup_optionlist(p->pdc, results); 138 } 139 140 if (p->pattern_number == p->pattern_capacity) 141 pdf_grow_pattern(p); 142 143 if (PDF_GET_STATE(p) == pdf_state_page) 144 pdf_end_contents_section(p); 145 146 /* Pattern object */ 147 p->pattern[p->pattern_number].obj_id = pdc_begin_obj(p->out, PDC_NEW_ID); 148 149 /* Shadings don't have a painttype, but this signals to the 150 * code which writes the pattern usage that no color values 151 * will be required when setting the pattern color space. 152 */ 153 p->pattern[p->pattern_number].painttype = 1; 154 155 pdc_begin_dict(p->out); /* Pattern dict*/ 156 157 pdc_puts(p->out, "/PatternType 2\n"); /* shading pattern */ 158 159 pdc_printf(p->out, "/Shading %ld 0 R\n", p->shadings[shading].obj_id); 160 161 p->shadings[shading].used_on_current_page = pdc_true; 162 163 if (gstate != -1) { 164 pdc_printf(p->out, "/ExtGState %ld 0 R\n", 165 pdf_get_gstate_id(p, gstate)); 166 } 167 168 pdc_end_dict(p->out); /* Pattern dict*/ 169 pdc_end_obj(p->out); /* Pattern object */ 170 171 if (PDF_GET_STATE(p) == pdf_state_page) 172 pdf_begin_contents_section(p); 173 174 retval = p->pattern_number; 175 p->pattern_number++; 176 PDF_RETURN_HANDLE(p, retval) 177} 178 179PDFLIB_API void PDFLIB_CALL 180PDF_shfill(PDF *p, int shading) 181{ 182 static const char fn[] = "PDF_shfill"; 183 int legal_states; 184 185 if (PDF_GET_STATE(p) == pdf_state_glyph && !pdf_get_t3colorized(p)) 186 legal_states = pdf_state_page | pdf_state_pattern | pdf_state_template; 187 188 else if (PDF_GET_STATE(p) == pdf_state_pattern && 189 p->pattern[p->pattern_number-1].painttype == 2) 190 legal_states = pdf_state_page | pdf_state_glyph | pdf_state_template; 191 192 else 193 legal_states = pdf_state_content; 194 195 if (!pdf_enter_api(p, fn, (pdf_state) legal_states, 196 "(p[%p], %d)\n", (void *) p, shading)) 197 return; 198 199 if (p->compatibility == PDC_1_3) 200 pdc_error(p->pdc, PDF_E_SHADING13, 0, 0, 0, 0); 201 202 PDF_INPUT_HANDLE(p, shading) 203 pdf_check_handle(p, shading, pdc_shadinghandle); 204 205 if (PDF_GET_STATE(p) == pdf_state_path) 206 pdf_end_path(p); 207 208 pdf_end_text(p); 209 210 pdc_printf(p->out, "/Sh%d sh\n", shading); 211 212 p->shadings[shading].used_on_current_page = pdc_true; 213} 214 215static const pdc_defopt pdf_shading_options[] = 216{ 217 {"N", pdc_floatlist, PDC_OPT_NOZERO, 1, 1, 0, PDC_FLOAT_MAX, NULL}, 218 {"r0", pdc_floatlist, PDC_OPT_NONE, 1, 1, 0, PDC_FLOAT_MAX, NULL}, 219 {"r1", pdc_floatlist, PDC_OPT_NONE, 1, 1, 0, PDC_FLOAT_MAX, NULL}, 220 {"extend0", pdc_booleanlist, PDC_OPT_NONE, 0, 1, 0, 1, NULL}, 221 {"extend1", pdc_booleanlist, PDC_OPT_NONE, 0, 1, 0, 0, NULL}, 222 {"antialias", pdc_booleanlist, PDC_OPT_NONE, 0, 1, 0, 0, NULL}, 223 PDC_OPT_TERMINATE 224}; 225 226PDFLIB_API int PDFLIB_CALL 227PDF_shading( 228 PDF *p, 229 const char *type, 230 float x_0, float y_0, 231 float x_1, float y_1, 232 float c_1, float c_2, float c_3, float c_4, 233 const char *optlist) 234{ 235 static const char fn[] = "PDF_shading"; 236 pdf_shadingtype_e shtype = shnone; 237 pdf_color *color0, color1; 238 pdf_colorspace *cs; 239 pdc_resopt *results; 240 float N = (float) 1.0; 241 float r_0, r_1; 242 pdc_bool extend0 = pdc_false, extend1 = pdc_false, antialias = pdc_false; 243 int retval = -1; 244 245 if (!pdf_enter_api(p, fn, 246 (pdf_state) (pdf_state_document | pdf_state_page | pdf_state_font), 247 "(p[%p], \"%s\", \"%s\")", 248 (void *) p, type, optlist)) 249 { 250 PDF_RETURN_HANDLE(p, retval) 251 } 252 253 if (p->compatibility == PDC_1_3) 254 pdc_error(p->pdc, PDF_E_SHADING13, 0, 0, 0, 0); 255 256 if (!strcmp(type, "axial")) { 257 shtype = axial; 258 259 } else if (!strcmp(type, "radial")) { 260 shtype = radial; 261 262 } else 263 pdc_error(p->pdc, PDC_E_ILLARG_STRING, "type", type, 0, 0); 264 265 color0 = &p->cstate[p->sl].fill; 266 267 color1.cs = color0->cs; 268 269 cs = &p->colorspaces[color0->cs]; 270 271 switch (cs->type) { 272 case DeviceGray: 273 color1.val.gray = c_1; 274 break; 275 276 case DeviceRGB: 277 color1.val.rgb.r = c_1; 278 color1.val.rgb.g = c_2; 279 color1.val.rgb.b = c_3; 280 break; 281 282 case DeviceCMYK: 283 color1.val.cmyk.c = c_1; 284 color1.val.cmyk.m = c_2; 285 color1.val.cmyk.y = c_3; 286 color1.val.cmyk.k = c_4; 287 break; 288 289 290 291 default: 292 pdc_error(p->pdc, PDF_E_INT_BADCS, 293 pdc_errprintf(p->pdc, "%d", color0->cs), 0, 0, 0); 294 } 295 296 if (optlist && strlen(optlist)) { 297 results = pdc_parse_optionlist(p->pdc, 298 optlist, pdf_shading_options, NULL, pdc_true); 299 300 (void) pdc_get_optvalues(p->pdc, "N", results, &N, NULL); 301 302 (void) pdc_get_optvalues(p->pdc, "antialias", results, &antialias,NULL); 303 304 if (shtype == radial) { 305 if (pdc_get_optvalues(p->pdc, "r0", results, &r_0, NULL) != 1) 306 pdc_error(p->pdc, PDC_E_OPT_NOTFOUND, "r0", 0, 0, 0); 307 308 if (pdc_get_optvalues(p->pdc, "r1", results, &r_1, NULL) != 1) 309 pdc_error(p->pdc, PDC_E_OPT_NOTFOUND, "r1", 0, 0, 0); 310 } 311 312 if (shtype == axial) { 313 if (pdc_get_optvalues(p->pdc, "r0", results, &r_0, NULL) == 1) 314 pdc_warning(p->pdc, PDC_E_OPT_IGNORED, "r0", 0, 0, 0); 315 316 if (pdc_get_optvalues(p->pdc, "r1", results, &r_1, NULL) == 1) 317 pdc_warning(p->pdc, PDC_E_OPT_IGNORED, "r1", 0, 0, 0); 318 } 319 320 if (shtype == radial || shtype == axial) { 321 pdc_get_optvalues(p->pdc, "extend0", results, &extend0, NULL); 322 pdc_get_optvalues(p->pdc, "extend1", results, &extend1, NULL); 323 } 324 325 pdc_cleanup_optionlist(p->pdc, results); 326 } 327 328 if (p->shadings_number == p->shadings_capacity) 329 pdf_grow_shadings(p); 330 331 if (PDF_GET_STATE(p) == pdf_state_page) 332 pdf_end_contents_section(p); 333 334 /* Shading object */ 335 p->shadings[p->shadings_number].obj_id = pdc_begin_obj(p->out, PDC_NEW_ID); 336 337 pdc_begin_dict(p->out); /* Shading dict*/ 338 339 pdc_printf(p->out, "/ShadingType %d\n", (int) shtype); 340 341 pdc_printf(p->out, "/ColorSpace"); 342 pdf_write_colorspace(p, color1.cs, pdc_false); 343 pdc_puts(p->out, "\n"); 344 345 if (antialias) 346 pdc_printf(p->out, "/AntiAlias true\n"); 347 348 switch (shtype) { 349 case axial: /* Type 2 */ 350 pdc_printf(p->out, "/Coords[%f %f %f %f]\n", x_0, y_0, x_1, y_1); 351 if (extend0 || extend1) 352 pdc_printf(p->out, "/Extend[%s %s]\n", 353 extend0 ? "true" : "false", extend1 ? "true" : "false"); 354 pdc_puts(p->out, "/Function"); 355 pdf_write_function_dict(p, color0, &color1, N); 356 break; 357 358 case radial: /* Type 3 */ 359 pdc_printf(p->out, "/Coords[%f %f %f %f %f %f]\n", 360 x_0, y_0, r_0, x_1, y_1, r_1); 361 if (extend0 || extend1) 362 pdc_printf(p->out, "/Extend[%s %s]\n", 363 extend0 ? "true" : "false", extend1 ? "true" : "false"); 364 pdc_puts(p->out, "/Function"); 365 pdf_write_function_dict(p, color0, &color1, N); 366 break; 367 368 default: 369 break; 370 } 371 372 pdc_end_dict(p->out); /* Shading dict */ 373 pdc_end_obj(p->out); /* Shading object */ 374 375 if (PDF_GET_STATE(p) == pdf_state_page) 376 pdf_begin_contents_section(p); 377 378 retval = p->shadings_number; 379 p->shadings_number++; 380 PDF_RETURN_HANDLE(p, retval) 381} 382