1 /* Copyright (C) 1989, 1995, 1996, 1997, 1998, 1999, 2000 Aladdin Enterprises. 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: zimage.c,v 1.15 2005/06/15 18:40:08 igor Exp $ */ 18 /* Image operators */ 19 #include "math_.h" 20 #include "memory_.h" 21 #include "ghost.h" 22 #include "oper.h" 23 #include "gscolor.h" 24 #include "gscspace.h" 25 #include "gscolor2.h" 26 #include "gsmatrix.h" 27 #include "gsimage.h" 28 #include "gxfixed.h" 29 #include "gsstruct.h" 30 #include "gxiparam.h" 31 #include "idict.h" 32 #include "idparam.h" 33 #include "estack.h" /* for image[mask] */ 34 #include "ialloc.h" 35 #include "igstate.h" 36 #include "ilevel.h" 37 #include "store.h" 38 #include "stream.h" 39 #include "ifilter.h" /* for stream exception handling */ 40 #include "iimage.h" 41 42 /* Forward references */ 43 private int zimage_data_setup(i_ctx_t *i_ctx_p, const gs_pixel_image_t * pim, 44 gx_image_enum_common_t * pie, 45 const ref * sources, int npop); 46 private int image_proc_process(i_ctx_t *); 47 private int image_file_continue(i_ctx_t *); 48 private int image_string_continue(i_ctx_t *); 49 private int image_cleanup(i_ctx_t *); 50 51 52 53 /* Extract and check the parameters for a gs_data_image_t. */ 54 int 55 data_image_params(const gs_memory_t *mem, 56 const ref *op, gs_data_image_t *pim, 57 image_params *pip, bool require_DataSource, 58 int num_components, int max_bits_per_component, 59 bool has_alpha) 60 { 61 int code; 62 int decode_size; 63 ref *pds; 64 65 check_type(*op, t_dictionary); 66 check_dict_read(*op); 67 if ((code = dict_int_param(op, "Width", 0, max_int_in_fixed / 2, 68 -1, &pim->Width)) < 0 || 69 (code = dict_int_param(op, "Height", 0, max_int_in_fixed / 2, 70 -1, &pim->Height)) < 0 || 71 (code = dict_matrix_param(mem, op, "ImageMatrix", 72 &pim->ImageMatrix)) < 0 || 73 (code = dict_bool_param(op, "MultipleDataSources", false, 74 &pip->MultipleDataSources)) < 0 || 75 (code = dict_int_param(op, "BitsPerComponent", 1, 76 max_bits_per_component, -1, 77 &pim->BitsPerComponent)) < 0 || 78 (code = decode_size = dict_floats_param(mem, op, "Decode", 79 num_components * 2, 80 &pim->Decode[0], NULL)) < 0 || 81 (code = dict_bool_param(op, "Interpolate", false, 82 &pim->Interpolate)) < 0 83 ) 84 return code; 85 pip->pDecode = &pim->Decode[0]; 86 /* Extract and check the data sources. */ 87 if ((code = dict_find_string(op, "DataSource", &pds)) <= 0) { 88 if (require_DataSource) 89 return (code < 0 ? code : gs_note_error(e_rangecheck)); 90 return 1; /* no data source */ 91 } 92 if (pip->MultipleDataSources) { 93 long i, n = num_components + (has_alpha ? 1 : 0); 94 if (!r_is_array(pds)) 95 return_error(e_typecheck); 96 if (r_size(pds) != n) 97 return_error(e_rangecheck); 98 for (i = 0; i < n; ++i) 99 array_get(mem, pds, i, &pip->DataSource[i]); 100 } else 101 pip->DataSource[0] = *pds; 102 return 0; 103 } 104 105 /* Extract and check the parameters for a gs_pixel_image_t. */ 106 int 107 pixel_image_params(i_ctx_t *i_ctx_p, const ref *op, gs_pixel_image_t *pim, 108 image_params *pip, int max_bits_per_component, 109 bool has_alpha) 110 { 111 int num_components = 112 gs_color_space_num_components(gs_currentcolorspace(igs)); 113 int code; 114 115 if (num_components < 1) 116 return_error(e_rangecheck); /* Pattern space not allowed */ 117 pim->ColorSpace = gs_currentcolorspace(igs); 118 code = data_image_params(imemory, op, (gs_data_image_t *) pim, pip, true, 119 num_components, max_bits_per_component, 120 has_alpha); 121 if (code < 0) 122 return code; 123 pim->format = 124 (pip->MultipleDataSources ? gs_image_format_component_planar : 125 gs_image_format_chunky); 126 return dict_bool_param(op, "CombineWithColor", false, 127 &pim->CombineWithColor); 128 } 129 130 /* Common setup for all Level 1 and 2 images, and ImageType 4 images. */ 131 int 132 zimage_setup(i_ctx_t *i_ctx_p, const gs_pixel_image_t * pim, 133 const ref * sources, bool uses_color, int npop) 134 { 135 gx_image_enum_common_t *pie; 136 int code = 137 gs_image_begin_typed((const gs_image_common_t *)pim, igs, 138 uses_color, &pie); 139 140 if (code < 0) 141 return code; 142 return zimage_data_setup(i_ctx_p, (const gs_pixel_image_t *)pim, pie, 143 sources, npop); 144 } 145 146 /* Common code for .image1 and .alphaimage operators */ 147 int 148 image1_setup(i_ctx_t * i_ctx_p, bool has_alpha) 149 { 150 os_ptr op = osp; 151 gs_image_t image; 152 image_params ip; 153 int code; 154 155 gs_image_t_init(&image, gs_currentcolorspace(igs)); 156 code = pixel_image_params( i_ctx_p, 157 op, 158 (gs_pixel_image_t *)&image, 159 &ip, 160 (level2_enabled ? 16 : 8), 161 has_alpha ); 162 if (code < 0) 163 return code; 164 165 image.Alpha = (has_alpha ? gs_image_alpha_last : gs_image_alpha_none); 166 return zimage_setup( i_ctx_p, 167 (gs_pixel_image_t *)&image, 168 &ip.DataSource[0], 169 image.CombineWithColor, 170 1 ); 171 } 172 173 /* <dict> .image1 - */ 174 private int 175 zimage1(i_ctx_t *i_ctx_p) 176 { 177 return image1_setup(i_ctx_p, false); 178 } 179 180 /* <dict> .imagemask1 - */ 181 private int 182 zimagemask1(i_ctx_t *i_ctx_p) 183 { 184 os_ptr op = osp; 185 gs_image_t image; 186 image_params ip; 187 int code; 188 189 gs_image_t_init_mask_adjust(&image, false, 190 gs_incachedevice(igs) != CACHE_DEVICE_NONE); 191 code = data_image_params(imemory, op, (gs_data_image_t *) & image, 192 &ip, true, 1, 1, false); 193 if (code < 0) 194 return code; 195 if (ip.MultipleDataSources) 196 return_error(e_rangecheck); 197 return zimage_setup(i_ctx_p, (gs_pixel_image_t *)&image, &ip.DataSource[0], 198 true, 1); 199 } 200 201 202 /* Common setup for all Level 1 and 2 images, and ImageType 3 and 4 images. */ 203 /* 204 * We push the following on the estack. 205 * control mark, 206 * num_sources, 207 * for I = num_sources-1 ... 0: 208 * data source I, 209 * aliasing information: 210 * if source is not file, 1, except that the topmost value 211 * is used for bookkeeping in the procedure case (see below); 212 * if file is referenced by a total of M different sources and 213 * this is the occurrence with the lowest I, M; 214 * otherwise, -J, where J is the lowest I of the same file as 215 * this one; 216 * current plane index, 217 * num_sources, 218 * enumeration structure. 219 */ 220 #define NUM_PUSH(nsource) ((nsource) * 2 + 5) 221 /* 222 * We can access these values either from the bottom (esp at control mark - 1, 223 * EBOT macros) or the top (esp = enumeration structure, ETOP macros). 224 * Note that all macros return pointers. 225 */ 226 #define EBOT_NUM_SOURCES(ep) ((ep) + 2) 227 #define EBOT_SOURCE(ep, i)\ 228 ((ep) + 3 + (EBOT_NUM_SOURCES(ep)->value.intval - 1 - (i)) * 2) 229 #define ETOP_SOURCE(ep, i)\ 230 ((ep) - 4 - (i) * 2) 231 #define ETOP_PLANE_INDEX(ep) ((ep) - 2) 232 #define ETOP_NUM_SOURCES(ep) ((ep) - 1) 233 private int 234 zimage_data_setup(i_ctx_t *i_ctx_p, const gs_pixel_image_t * pim, 235 gx_image_enum_common_t * pie, const ref * sources, int npop) 236 { 237 int num_sources = pie->num_planes; 238 int inumpush = NUM_PUSH(num_sources); 239 int code; 240 gs_image_enum *penum; 241 int px; 242 const ref *pp; 243 244 check_estack(inumpush + 2); /* stuff above, + continuation + proc */ 245 make_int(EBOT_NUM_SOURCES(esp), num_sources); 246 /* 247 * Note that the data sources may be procedures, strings, or (Level 248 * 2 only) files. (The Level 1 reference manual says that Level 1 249 * requires procedures, but Adobe Level 1 interpreters also accept 250 * strings.) The sources must all be of the same type. 251 * 252 * The Adobe documentation explicitly says that if two or more of the 253 * data sources are the same or inter-dependent files, the result is not 254 * defined. We don't have a problem with the bookkeeping for 255 * inter-dependent files, since each one has its own buffer, but we do 256 * have to be careful if two or more sources are actually the same file. 257 * That is the reason for the aliasing information described above. 258 */ 259 for (px = 0, pp = sources; px < num_sources; px++, pp++) { 260 es_ptr ep = EBOT_SOURCE(esp, px); 261 262 make_int(ep + 1, 1); /* default is no aliasing */ 263 switch (r_type(pp)) { 264 case t_file: 265 if (!level2_enabled) 266 return_error(e_typecheck); 267 /* Check for aliasing. */ 268 { 269 int pi; 270 271 for (pi = 0; pi < px; ++pi) 272 if (sources[pi].value.pfile == pp->value.pfile) { 273 /* Record aliasing */ 274 make_int(ep + 1, -pi); 275 EBOT_SOURCE(esp, pi)[1].value.intval++; 276 break; 277 } 278 } 279 /* falls through */ 280 case t_string: 281 if (r_type(pp) != r_type(sources)) { 282 if (pie != NULL) 283 gx_image_end(pie, false); /* Clean up pie */ 284 return_error(e_typecheck); 285 } 286 check_read(*pp); 287 break; 288 default: 289 if (!r_is_proc(sources)) { 290 if (pie != NULL) 291 gx_image_end(pie, false); /* Clean up pie */ 292 return_error(e_typecheck); 293 } 294 check_proc(*pp); 295 } 296 *ep = *pp; 297 } 298 /* Always place the image enumerator into local memory, 299 because pie may have local objects inherited from igs, 300 which may be local when the current allocation mode is global. 301 Bug 688140. */ 302 if ((penum = gs_image_enum_alloc(imemory_local, "image_setup")) == 0) 303 return_error(e_VMerror); 304 code = gs_image_enum_init(penum, pie, (const gs_data_image_t *)pim, igs); 305 if (code != 0) { /* error, or empty image */ 306 int code1 = gs_image_cleanup_and_free_enum(penum); 307 308 if (code >= 0) /* empty image */ 309 pop(npop); 310 if (code >= 0 && code1 < 0) 311 code = code1; 312 return code; 313 } 314 push_mark_estack(es_other, image_cleanup); 315 esp += inumpush - 1; 316 make_int(ETOP_PLANE_INDEX(esp), 0); 317 make_int(ETOP_NUM_SOURCES(esp), num_sources); 318 make_struct(esp, avm_local, penum); 319 switch (r_type(sources)) { 320 case t_file: 321 push_op_estack(image_file_continue); 322 break; 323 case t_string: 324 push_op_estack(image_string_continue); 325 break; 326 default: /* procedure */ 327 push_op_estack(image_proc_process); 328 break; 329 } 330 pop(npop); 331 return o_push_estack; 332 } 333 /* Pop all the control information off the e-stack. */ 334 private es_ptr 335 zimage_pop_estack(es_ptr tep) 336 { 337 return tep - NUM_PUSH(ETOP_NUM_SOURCES(tep)->value.intval); 338 } 339 340 /* 341 * Continuation for procedure data source. We use the topmost aliasing slot 342 * to remember whether we've just called the procedure (1) or whether we're 343 * returning from a RemapColor callout (0). 344 */ 345 private int 346 image_proc_continue(i_ctx_t *i_ctx_p) 347 { 348 os_ptr op = osp; 349 gs_image_enum *penum = r_ptr(esp, gs_image_enum); 350 int px = ETOP_PLANE_INDEX(esp)->value.intval; 351 int num_sources = ETOP_NUM_SOURCES(esp)->value.intval; 352 uint size, used[gs_image_max_planes]; 353 gs_const_string plane_data[gs_image_max_planes]; 354 const byte *wanted; 355 int i, code; 356 357 if (!r_has_type_attrs(op, t_string, a_read)) { 358 check_op(1); 359 /* Procedure didn't return a (readable) string. Quit. */ 360 esp = zimage_pop_estack(esp); 361 image_cleanup(i_ctx_p); 362 return_error(!r_has_type(op, t_string) ? e_typecheck : e_invalidaccess); 363 } 364 size = r_size(op); 365 if (size == 0 && ETOP_SOURCE(esp, 0)[1].value.intval == 0) 366 code = 1; 367 else { 368 for (i = 0; i < num_sources; i++) 369 plane_data[i].size = 0; 370 plane_data[px].data = op->value.bytes; 371 plane_data[px].size = size; 372 code = gs_image_next_planes(penum, plane_data, used); 373 if (code == e_RemapColor) { 374 op->value.bytes += used[px]; /* skip used data */ 375 r_dec_size(op, used[px]); 376 ETOP_SOURCE(esp, 0)[1].value.intval = 0; /* RemapColor callout */ 377 return code; 378 } 379 } 380 if (code) { /* Stop now. */ 381 esp = zimage_pop_estack(esp); 382 pop(1); 383 image_cleanup(i_ctx_p); 384 return (code < 0 ? code : o_pop_estack); 385 } 386 pop(1); 387 wanted = gs_image_planes_wanted(penum); 388 do { 389 if (++px == num_sources) 390 px = 0; 391 } while (!wanted[px]); 392 ETOP_PLANE_INDEX(esp)->value.intval = px; 393 return image_proc_process(i_ctx_p); 394 } 395 private int 396 image_proc_process(i_ctx_t *i_ctx_p) 397 { 398 int px = ETOP_PLANE_INDEX(esp)->value.intval; 399 gs_image_enum *penum = r_ptr(esp, gs_image_enum); 400 const byte *wanted = gs_image_planes_wanted(penum); 401 int num_sources = ETOP_NUM_SOURCES(esp)->value.intval; 402 const ref *pp; 403 404 ETOP_SOURCE(esp, 0)[1].value.intval = 0; /* procedure callout */ 405 while (!wanted[px]) { 406 if (++px == num_sources) 407 px = 0; 408 ETOP_PLANE_INDEX(esp)->value.intval = px; 409 } 410 pp = ETOP_SOURCE(esp, px); 411 push_op_estack(image_proc_continue); 412 *++esp = *pp; 413 return o_push_estack; 414 } 415 416 /* Continue processing data from an image with file data sources. */ 417 private int 418 image_file_continue(i_ctx_t *i_ctx_p) 419 { 420 gs_image_enum *penum = r_ptr(esp, gs_image_enum); 421 int num_sources = ETOP_NUM_SOURCES(esp)->value.intval; 422 423 for (;;) { 424 uint min_avail = max_int; 425 gs_const_string plane_data[gs_image_max_planes]; 426 int code; 427 int px; 428 const ref *pp; 429 bool at_eof = false; 430 431 /* 432 * Do a first pass through the files to ensure that at least 433 * one has data available in its buffer. 434 */ 435 436 for (px = 0, pp = ETOP_SOURCE(esp, 0); px < num_sources; 437 ++px, pp -= 2 438 ) { 439 int num_aliases = pp[1].value.intval; 440 stream *s = pp->value.pfile; 441 int min_left; 442 uint avail; 443 444 if (num_aliases <= 0) 445 num_aliases = ETOP_SOURCE(esp, -num_aliases)[1].value.intval; 446 while ((avail = sbufavailable(s)) <= 447 (min_left = sbuf_min_left(s)) + num_aliases - 1) { 448 int next = s->end_status; 449 450 switch (next) { 451 case 0: 452 s_process_read_buf(s); 453 continue; 454 case EOFC: 455 at_eof = true; 456 break; /* with no data available */ 457 case INTC: 458 case CALLC: 459 return 460 s_handle_read_exception(i_ctx_p, next, pp, 461 NULL, 0, image_file_continue); 462 default: 463 /* case ERRC: */ 464 return_error(e_ioerror); 465 } 466 break; /* for EOFC */ 467 } 468 /* 469 * Note that in the EOF case, we can get here with no data 470 * available. 471 */ 472 if (avail >= min_left) 473 avail = (avail - min_left) / num_aliases; /* may be 0 */ 474 if (avail < min_avail) 475 min_avail = avail; 476 plane_data[px].data = sbufptr(s); 477 plane_data[px].size = avail; 478 } 479 480 /* 481 * Now pass the available buffered data to the image processor. 482 * Even if there is no available data, we must call 483 * gs_image_next_planes one more time to finish processing any 484 * retained data. 485 */ 486 487 { 488 int pi; 489 uint used[gs_image_max_planes]; 490 491 code = gs_image_next_planes(penum, plane_data, used); 492 /* Now that used has been set, update the streams. */ 493 for (pi = 0, pp = ETOP_SOURCE(esp, 0); pi < num_sources; 494 ++pi, pp -= 2 495 ) 496 sbufskip(pp->value.pfile, used[pi]); 497 if (code == e_RemapColor) 498 return code; 499 } 500 if (at_eof) 501 code = 1; 502 if (code) { 503 int code1; 504 505 esp = zimage_pop_estack(esp); 506 code1 = image_cleanup(i_ctx_p); 507 return (code < 0 ? code : code1 < 0 ? code1 : o_pop_estack); 508 } 509 } 510 } 511 512 /* Process data from an image with string data sources. */ 513 /* This may still encounter a RemapColor callback. */ 514 private int 515 image_string_continue(i_ctx_t *i_ctx_p) 516 { 517 gs_image_enum *penum = r_ptr(esp, gs_image_enum); 518 int num_sources = ETOP_NUM_SOURCES(esp)->value.intval; 519 gs_const_string sources[gs_image_max_planes]; 520 uint used[gs_image_max_planes]; 521 522 /* Pass no data initially, to find out how much is retained. */ 523 memset(sources, 0, sizeof(sources[0]) * num_sources); 524 for (;;) { 525 int px; 526 int code = gs_image_next_planes(penum, sources, used); 527 528 if (code == e_RemapColor) 529 return code; 530 stop_now: 531 if (code) { /* Stop now. */ 532 esp -= NUM_PUSH(num_sources); 533 image_cleanup(i_ctx_p); 534 return (code < 0 ? code : o_pop_estack); 535 } 536 for (px = 0; px < num_sources; ++px) 537 if (sources[px].size == 0) { 538 const ref *psrc = ETOP_SOURCE(esp, px); 539 uint size = r_size(psrc); 540 541 if (size == 0) { /* empty source */ 542 code = 1; 543 goto stop_now; 544 } 545 sources[px].data = psrc->value.bytes; 546 sources[px].size = size; 547 } 548 } 549 } 550 551 /* Clean up after enumerating an image */ 552 private int 553 image_cleanup(i_ctx_t *i_ctx_p) 554 { 555 es_ptr ep_top = esp + NUM_PUSH(EBOT_NUM_SOURCES(esp)->value.intval); 556 gs_image_enum *penum = r_ptr(ep_top, gs_image_enum); 557 558 return gs_image_cleanup_and_free_enum(penum); 559 } 560 561 /* ------ Initialization procedure ------ */ 562 563 const op_def zimage_op_defs[] = 564 { 565 {"1.image1", zimage1}, 566 {"1.imagemask1", zimagemask1}, 567 /* Internal operators */ 568 {"1%image_proc_continue", image_proc_continue}, 569 {"0%image_file_continue", image_file_continue}, 570 {"0%image_string_continue", image_string_continue}, 571 op_def_end(0) 572 }; 573