1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 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 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309
|
/* Copyright (C) 1989, 1990, 1991, 1993, 1994 Aladdin Enterprises. All rights reserved.
This file is part of GNU Ghostscript.
GNU Ghostscript is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY. No author or distributor accepts responsibility to
anyone for the consequences of using it or for whether it serves any
particular purpose or works at all, unless he says so in writing. Refer
to the GNU Ghostscript General Public License for full details.
*/
/* zpaint.c */
/* Painting operators */
#include "ghost.h"
#include "errors.h"
#include "oper.h"
#include "estack.h" /* for image[mask] */
#include "gsstruct.h"
#include "ialloc.h"
#include "igstate.h"
#include "ilevel.h"
#include "store.h"
#include "gscspace.h"
#include "gsmatrix.h"
#include "gsimage.h"
#include "gspaint.h"
#include "stream.h"
#include "ifilter.h" /* for stream exception handling */
/* Forward references */
/* zimage_setup is used by zimage2.c */
int zimage_setup(P11(int width, int height, gs_matrix *pmat,
ref *sources, int bits_per_component,
bool multi, const gs_color_space *pcs, int masked,
const float *decode, bool interpolate, int npop));
/* zimage_opaque_setup is used by zcolor1.c */
int zimage_opaque_setup(P4(os_ptr, bool, const gs_color_space_type _ds *, int));
private int image_setup(P7(os_ptr, int, bool, const gs_color_space_type _ds *, int, const float *, int));
private int image_process(P2(os_ptr, ref *));
private int image_continue(P1(os_ptr));
private int image_process_continue(P1(os_ptr));
private int image_cleanup(P1(os_ptr));
/* - fill - */
private int
zfill(register os_ptr op)
{ return gs_fill(igs);
}
/* - .fillpage - */
private int
zfillpage(register os_ptr op)
{ return gs_fillpage(igs);
}
/* - eofill - */
private int
zeofill(register os_ptr op)
{ return gs_eofill(igs);
}
/* - stroke - */
private int
zstroke(register os_ptr op)
{ return gs_stroke(igs);
}
/* Standard decoding maps for images. */
static const float decode_01[8] = { 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0 };
static const float decode_10[8] = { 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0 };
/* <width> <height> <bits/sample> <matrix> <datasrc> image - */
int
zimage(register os_ptr op)
{ return zimage_opaque_setup(op, false, &gs_color_space_type_DeviceGray, 5);
}
/* <width> <height> <paint_1s> <matrix> <datasrc> imagemask - */
int
zimagemask(register os_ptr op)
{ check_type(op[-2], t_boolean);
return image_setup(op, 1, false, &gs_color_space_type_DeviceGray, 1,
(op[-2].value.boolval ? decode_10 : decode_01), 5);
}
/* Common setup for image and colorimage. */
int
zimage_opaque_setup(register os_ptr op, bool multi,
const gs_color_space_type _ds *pcst, int npop)
{ check_int_leu(op[-2], (level2_enabled ? 12 : 8)); /* bits/sample */
return image_setup(op, (int)op[-2].value.intval, multi, pcst, 0, decode_01, npop);
}
/* Common setup for [color]image and imagemask. */
private int
image_setup(register os_ptr op, int bps, bool multi,
const gs_color_space_type _ds *pcst, int masked, const float *decode,
int npop)
{ gs_matrix mat;
int code;
gs_color_space cs;
check_type(op[-4], t_integer); /* width */
check_type(op[-3], t_integer); /* height */
if ( op[-4].value.intval < 0 || op[-3].value.intval < 0 )
return_error(e_rangecheck);
if ( (code = read_matrix(op - 1, &mat)) < 0 )
return code;
cs.type = pcst;
return zimage_setup((int)op[-4].value.intval,
(int)op[-3].value.intval,
&mat, op, bps, multi, &cs, masked, decode,
false, npop);
}
/* Common setup for Level 1 image/imagemask/colorimage and */
/* the Level 2 dictionary form of image/imagemask. */
int
zimage_setup(int width, int height, gs_matrix *pmat,
ref *sources, int bits_per_component,
bool multi, const gs_color_space *pcs,
int masked, const float *decode, bool interpolate, int npop)
{ int code;
gs_image_enum *penum;
int px;
ref *pp;
int num_sources = (multi ? pcs->type->num_components : 1);
/* We push on the estack: */
/* Control mark, 4 procs, last plane index, */
/* enumeration structure. */
#define inumpush 7
check_estack(inumpush + 2); /* stuff above, + continuation + proc */
/* Note that the "procedures" might not be procedures, */
/* but might be strings or files (Level 2 only). */
for ( px = 0, pp = sources; px < num_sources; px++, pp++ )
{ switch ( r_type(pp) )
{
case t_file:
if ( !level2_enabled )
return_error(e_typecheck);
/* falls through */
case t_string:
check_read(*pp);
break;
default:
check_proc(*pp);
}
}
if ( masked != 0 && decode != 0 )
{ /* Make sure decode is 0..1 or 1..0 */
if ( decode[0] == 0.0 && decode[1] == 1.0 )
masked = -1;
else if ( decode[0] == 1.0 && decode[1] == 0.0 )
masked = 1;
else
return_error(e_rangecheck);
}
if ( width == 0 || height == 0 ) /* empty image */
{ pop(npop);
return 0;
}
if ( (penum = gs_image_enum_alloc(imemory, "image_setup")) == 0 )
return_error(e_VMerror);
code = (masked != 0 ?
gs_imagemask_init(penum, igs, width, height,
masked < 0, interpolate, pmat, 1) :
gs_image_init(penum, igs, width, height, bits_per_component,
multi, pcs, decode, interpolate, pmat) );
if ( code < 0 )
{ ifree_object(penum, "image_setup");
return code;
}
push_mark_estack(es_other, image_cleanup);
++esp;
for ( px = 0, pp = sources; px < 4; esp++, px++, pp++ )
if ( px < num_sources )
*esp = *pp;
else
make_null(esp);
make_int(esp, 0); /* current plane */
++esp;
make_istruct(esp, 0, penum);
pop(npop);
push_op_estack(image_process_continue);
return o_push_estack;
}
/* Continuation procedure. Hand the string to the enumerator. */
private int
image_continue(register os_ptr op)
{ ref sref;
if ( !r_has_type_attrs(op, t_string, a_read) )
{ check_op(1);
/* Procedure didn't return a (readable) string. Quit. */
esp -= inumpush;
image_cleanup(op);
return_error(!r_has_type(op, t_string) ? e_typecheck : e_invalidaccess);
}
sref = *op;
pop(1);
return image_process(osp, &sref); /* osp because we did a pop */
}
/* Continue after an interrupt or a callout. */
private int
image_process_continue(os_ptr op)
{ return image_process(op, NULL);
}
/* Process data from an image data source. */
private int
image_process(os_ptr op, ref *psrc)
{ gs_image_enum *penum = r_ptr(esp, gs_image_enum);
ref *psref = psrc;
uint size, used;
int code;
int px;
es_ptr pproc;
if ( psref != NULL )
goto sw;
rd: px = (int)(esp[-1].value.intval);
pproc = esp - 5;
if ( px == 4 || r_has_type(pproc + px, t_null) )
esp[-1].value.intval = px = 0;
psref = pproc + px;
sw: switch ( r_type(psref) )
{
case t_string:
size = r_size(psref);
code = gs_image_next(penum, psref->value.bytes, size, &used);
break;
case t_file:
{ stream *s = psref->value.pfile;
while ( (size = sbufavailable(s)) == 0 )
{ int next = sgetc(s);
if ( next >= 0 )
{ sputback(s);
continue;
}
switch ( next )
{
case EOFC:
break; /* with size = 0 */
case INTC:
case CALLC:
return s_handle_read_exception(next, psref,
NULL, image_process_continue);
default:
/* case ERRC: */
return_error(e_ioerror);
}
break; /* for EOFC */
}
used = 0; /* in case of failure */
code = gs_image_next(penum, sbufptr(s), size, &used);
sskip(s, used);
} break;
default: /* procedure */
push_op_estack(image_continue);
*++esp = *psref;
return o_push_estack;
}
if ( size == 0 || code != 0 ) /* stop now */
{ esp -= inumpush;
image_cleanup(op);
if ( code < 0 ) return code;
return o_pop_estack;
}
++(esp[-1].value.intval);
goto rd;
}
/* Clean up after enumerating an image */
private int
image_cleanup(os_ptr op)
{ gs_image_enum *penum = r_ptr(esp + inumpush, gs_image_enum);
gs_image_cleanup(penum);
ifree_object(penum, "image_cleanup");
return 0;
}
/* ------ Non-standard operators ------ */
/* <width> <height> <data> .imagepath - */
private int
zimagepath(register os_ptr op)
{ int code;
check_type(op[-2], t_integer);
check_type(op[-1], t_integer);
check_read_type(*op, t_string);
if ( r_size(op) < ((op[-2].value.intval + 7) >> 3) * op[-1].value.intval )
return_error(e_rangecheck);
code = gs_imagepath(igs,
(int)op[-2].value.intval, (int)op[-1].value.intval,
op->value.const_bytes);
if ( code == 0 ) pop(3);
return code;
}
/* ------ Initialization procedure ------ */
BEGIN_OP_DEFS(zpaint_op_defs) {
{"0eofill", zeofill},
{"0fill", zfill},
{"0.fillpage", zfillpage},
{"5image", zimage},
{"5imagemask", zimagemask},
{"3.imagepath", zimagepath},
{"0stroke", zstroke},
/* Internal operators */
{"1%image_continue", image_continue},
{"0%image_process_continue", image_process_continue},
END_OP_DEFS(0) }
|