1 /* Copyright (C) 1997, 2000-2004 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: gdevps.c,v 1.40 2004/10/07 05:18:34 ray Exp $ */
18 /* PostScript-writing driver */
19 #include "math_.h"
20 #include "memory_.h"
21 #include "string_.h"
22 #include "time_.h"
23 #include "gx.h"
24 #include "gserrors.h"
25 #include "gscdefs.h"
26 #include "gsmatrix.h" /* for gsiparam.h */
27 #include "gsiparam.h"
28 #include "gsline.h"
29 #include "gsparam.h"
30 #include "gxdevice.h"
31 #include "gscspace.h"
32 #include "gxdcolor.h"
33 #include "gxpath.h"
34 #include "spprint.h"
35 #include "strimpl.h"
36 #include "sstring.h"
37 #include "sa85x.h"
38 #include "gdevpsdf.h"
39 #include "gdevpsu.h"
40
41 /* Current ProcSet version */
42 #define PSWRITE_PROCSET_VERSION 1
43
44 /* Guaranteed size of operand stack accoeding to PLRM */
45 #define MAXOPSTACK 500
46
47 private int psw_open_printer(gx_device * dev);
48 private int psw_close_printer(gx_device * dev);
49
50 /* ---------------- Device definition ---------------- */
51
52 /* Device procedures */
53 private dev_proc_open_device(psw_open);
54 private dev_proc_output_page(psw_output_page);
55 private dev_proc_close_device(psw_close);
56 private dev_proc_fill_rectangle(psw_fill_rectangle);
57 private dev_proc_copy_mono(psw_copy_mono);
58 private dev_proc_copy_color(psw_copy_color);
59 private dev_proc_put_params(psw_put_params);
60 private dev_proc_get_params(psw_get_params);
61 private dev_proc_fill_path(psw_fill_path);
62 private dev_proc_stroke_path(psw_stroke_path);
63 private dev_proc_fill_mask(psw_fill_mask);
64 private dev_proc_begin_image(psw_begin_image);
65
66 #define X_DPI 720
67 #define Y_DPI 720
68
69 typedef struct psw_path_state_s {
70 int num_points; /* # of points since last non-lineto */
71 int move; /* 1 iff last non-lineto was moveto, else 0 */
72 gs_point dprev[2]; /* line deltas before previous point, */
73 /* if num_points - move >= 2 */
74 } psw_path_state_t;
75
76 typedef struct psw_image_params_s {
77 gx_bitmap_id id;
78 ushort width, height;
79 } psw_image_params_t;
80
81 typedef struct gx_device_pswrite_s {
82 gx_device_psdf_common;
83 /* LanguageLevel in pswrite_common is settable. */
84 gx_device_pswrite_common_t pswrite_common;
85 #define LanguageLevel_default 2.0
86 #define psdf_version_default psdf_version_level2
87 /* End of parameters */
88 bool first_page;
89 psdf_binary_writer *image_writer;
90 #define image_stream image_writer->strm
91 #define image_cache_size 197
92 #define image_cache_reprobe_step 121
93 psw_image_params_t image_cache[image_cache_size];
94 bool cache_toggle;
95 struct pf_ {
96 gs_int_rect rect;
97 gx_color_index color;
98 } page_fill;
99 /* Temporary state while writing a path */
100 psw_path_state_t path_state;
101 } gx_device_pswrite;
102
103 /* GC descriptor and procedures */
104 gs_private_st_suffix_add1_final(st_device_pswrite, gx_device_pswrite,
105 "gx_device_pswrite", device_pswrite_enum_ptrs,
106 device_pswrite_reloc_ptrs, gx_device_finalize,
107 st_device_psdf, image_writer);
108
109 #define psw_procs\
110 { psw_open,\
111 gx_upright_get_initial_matrix,\
112 NULL, /* sync_output */\
113 psw_output_page,\
114 psw_close,\
115 gx_default_rgb_map_rgb_color,\
116 gx_default_rgb_map_color_rgb,\
117 psw_fill_rectangle,\
118 NULL, /* tile_rectangle */\
119 psw_copy_mono,\
120 psw_copy_color,\
121 NULL, /* draw_line */\
122 psdf_get_bits,\
123 psw_get_params,\
124 psw_put_params,\
125 NULL, /* map_cmyk_color */\
126 NULL, /* get_xfont_procs */\
127 NULL, /* get_xfont_device */\
128 NULL, /* map_rgb_alpha_color */\
129 gx_page_device_get_page_device,\
130 NULL, /* get_alpha_bits */\
131 NULL, /* copy_alpha */\
132 NULL, /* get_band */\
133 NULL, /* copy_rop */\
134 psw_fill_path,\
135 psw_stroke_path,\
136 psw_fill_mask,\
137 gdev_vector_fill_trapezoid,\
138 gdev_vector_fill_parallelogram,\
139 gdev_vector_fill_triangle,\
140 NULL /****** WRONG ******/, /* draw_thin_line */\
141 psw_begin_image,\
142 NULL, /* image_data */\
143 NULL, /* end_image */\
144 NULL, /* strip_tile_rectangle */\
145 NULL,/******psw_strip_copy_rop******/\
146 NULL, /* get_clipping_box */\
147 NULL, /* begin_typed_image */\
148 psdf_get_bits_rectangle,\
149 NULL, /* map_color_rgb_alpha */\
150 psdf_create_compositor\
151 }
152
153 const gx_device_pswrite gs_pswrite_device = {
154 std_device_dci_type_body(gx_device_pswrite, 0, "pswrite",
155 &st_device_pswrite,
156 DEFAULT_WIDTH_10THS * X_DPI / 10,
157 DEFAULT_HEIGHT_10THS * Y_DPI / 10,
158 X_DPI, Y_DPI, 3, 24, 255, 255, 256, 256),
159 psw_procs,
160 psdf_initial_values(psdf_version_default, 1 /*true */ ), /* (ASCII85EncodePages) */
161 PSWRITE_COMMON_VALUES(LanguageLevel_default, /* LanguageLevel */
162 0 /*false*/, /* ProduceEPS */
163 PSWRITE_PROCSET_VERSION /* ProcSet_version */)
164 };
165
166 const gx_device_pswrite gs_epswrite_device = {
167 std_device_dci_type_body(gx_device_pswrite, 0, "epswrite",
168 &st_device_pswrite,
169 DEFAULT_WIDTH_10THS * X_DPI / 10,
170 DEFAULT_HEIGHT_10THS * Y_DPI / 10,
171 X_DPI, Y_DPI, 3, 24, 255, 255, 256, 256),
172 psw_procs,
173 psdf_initial_values(psdf_version_default, 1 /*true */ ), /* (ASCII85EncodePages) */
174 PSWRITE_COMMON_VALUES(LanguageLevel_default, /* LanguageLevel */
175 1 /*true*/, /* ProduceEPS */
176 PSWRITE_PROCSET_VERSION /* ProcSet_version */)
177 };
178
179 /* Vector device implementation */
180 private int
181 psw_beginpage(gx_device_vector * vdev),
182 psw_can_handle_hl_color(gx_device_vector * vdev, const gs_imager_state * pis,
183 const gx_drawing_color * pdc),
184 psw_setcolors(gx_device_vector * vdev, const gs_imager_state * pis,
185 const gx_drawing_color * pdc),
186 psw_dorect(gx_device_vector * vdev, fixed x0, fixed y0, fixed x1,
187 fixed y1, gx_path_type_t type),
188 psw_beginpath(gx_device_vector * vdev, gx_path_type_t type),
189 psw_moveto(gx_device_vector * vdev, floatp x0, floatp y0,
190 floatp x, floatp y, gx_path_type_t type),
191 psw_lineto(gx_device_vector * vdev, floatp x0, floatp y0,
192 floatp x, floatp y, gx_path_type_t type),
193 psw_curveto(gx_device_vector * vdev, floatp x0, floatp y0,
194 floatp x1, floatp y1, floatp x2, floatp y2,
195 floatp x3, floatp y3, gx_path_type_t type),
196 psw_closepath(gx_device_vector * vdev, floatp x0, floatp y0,
197 floatp x_start, floatp y_start, gx_path_type_t type),
198 psw_endpath(gx_device_vector * vdev, gx_path_type_t type);
199 private const gx_device_vector_procs psw_vector_procs = {
200 /* Page management */
201 psw_beginpage,
202 /* Imager state */
203 psdf_setlinewidth,
204 psdf_setlinecap,
205 psdf_setlinejoin,
206 psdf_setmiterlimit,
207 psdf_setdash,
208 psdf_setflat,
209 psdf_setlogop,
210 /* Other state */
211 psw_can_handle_hl_color,
212 psw_setcolors, /* fill & stroke colors are the same */
213 psw_setcolors,
214 /* Paths */
215 psdf_dopath,
216 psw_dorect,
217 psw_beginpath,
218 psw_moveto,
219 psw_lineto,
220 psw_curveto,
221 psw_closepath,
222 psw_endpath
223 };
224
225 /* ---------------- File header ---------------- */
226
227 /*
228 * NOTE: Increment PSWRITE_PROCSET_VERSION (above) whenever the following
229 * definitions change.
230 */
231
232 private const char *const psw_procset[] = {
233 "/!{bind def}bind def/#{load def}!/N/counttomark #",
234 /* <rbyte> <gbyte> <bbyte> rG - */
235 /* <graybyte> G - */
236 "/rG{3{3 -1 roll 255 div}repeat setrgbcolor}!/G{255 div setgray}!/K{0 G}!",
237 /* <bbyte> <rgbyte> r6 - */
238 /* <gbyte> <rbbyte> r5 - */
239 /* <rbyte> <gbbyte> r3 - */
240 "/r6{dup 3 -1 roll rG}!/r5{dup 3 1 roll rG}!/r3{dup rG}!",
241 "/w/setlinewidth #/J/setlinecap #",
242 "/j/setlinejoin #/M/setmiterlimit #/d/setdash #/i/setflat #",
243 "/m/moveto #/l/lineto #/c/rcurveto #",
244 /* <dx1> <dy1> ... <dxn> <dyn> p - */
245 "/p{N 2 idiv{N -2 roll rlineto}repeat}!",
246 /* <x> <y> <dx1> <dy1> ... <dxn> <dyn> P - */
247 "/P{N 0 gt{N -2 roll moveto p}if}!",
248 "/h{p closepath}!/H{P closepath}!",
249 /* <dx> lx - */
250 /* <dy> ly - */
251 /* <dx2> <dy2> <dx3> <dy3> v - */
252 /* <dx1> <dy1> <dx2> <dy2> y - */
253 "/lx{0 rlineto}!/ly{0 exch rlineto}!/v{0 0 6 2 roll c}!/y{2 copy c}!",
254 /* <x> <y> <dx> <dy> re - */
255 "/re{4 -2 roll m exch dup lx exch ly neg lx h}!",
256 /* <x> <y> <a> <b> ^ <x> <y> <a> <b> <-x> <-y> */
257 "/^{3 index neg 3 index neg}!",
258 "/f{P fill}!/f*{P eofill}!/s{H stroke}!/S{P stroke}!",
259 "/q/gsave #/Q/grestore #/rf{re fill}!",
260 "/Y{P clip newpath}!/Y*{P eoclip newpath}!/rY{re Y}!",
261 /* <w> <h> <name> <data> <?> |= <w> <h> <data> */
262 "/|={pop exch 4 1 roll 1 array astore cvx 3 array astore cvx exch 1 index def exec}!",
263 /* <w> <h> <name> <length> <src> | <w> <h> <data> */
264 "/|{exch string readstring |=}!",
265 /* <w> <?> <name> (<length>|) + <w> <?> <name> <length> */
266 "/+{dup type/nametype eq{2 index 7 add -3 bitshift 2 index mul}if}!",
267 /* <w> <h> <name> (<length>|) $ <w> <h> <data> */
268 "/@/currentfile #/${+ @ |}!",
269 /* <file> <nbytes> <ncomp> B <proc_1> ... <proc_ncomp> true */
270 "/B{{2 copy string{readstring pop}aload pop 4 array astore cvx",
271 "3 1 roll}repeat pop pop true}!",
272 /* <x> <y> <w> <h> <bpc/inv> <src> Ix <w> <h> <bps/inv> <mtx> <src> */
273 "/Ix{[1 0 0 1 11 -2 roll exch neg exch neg]exch}!",
274 /* <x> <y> <h> <src> , - */
275 /* <x> <y> <h> <src> If - */
276 /* <x> <y> <h> <src> I - */
277 "/,{true exch Ix imagemask}!/If{false exch Ix imagemask}!/I{exch Ix image}!",
278 0
279 };
280
281 private const char *const psw_1_procset[] = {
282 0
283 };
284
285 private const char *const psw_1_x_procset[] = {
286 /* <w> <h> <name> <length> <src> |X <w> <h> <data> */
287 /* <w> <h> <name> (<length>|) $X <w> <h> <data> */
288 "/|X{exch string readhexstring |=}!/$X{+ @ |X}!",
289 /* - @X <hexsrc> */
290 "/@X{{currentfile ( ) readhexstring pop}}!",
291 0
292 };
293
294 private const char *const psw_1_5_procset[] = {
295 /* <x> <y> <w> <h> <src> <bpc> Ic - */
296 "/Ic{exch Ix false 3 colorimage}!",
297 0
298 };
299
300 private const char *const psw_2_procset[] = {
301 /* <src> <w> <h> -mark- ... F <g4src> */
302 /* <src> <w> <h> FX <g4src> */
303 "/F{/Columns counttomark 3 add -2 roll/Rows exch/K -1/BlackIs1 true>>",
304 "/CCITTFaxDecode filter}!/FX{<</EndOfBlock false F}!",
305 /* <src> X <a85src> */
306 /* - @X <a85src> */
307 /* <w> <h> <src> /&2 <w> <h> <src> <w> <h> */
308 "/X{/ASCII85Decode filter}!/@X{@ X}!/&2{2 index 2 index}!",
309 /* <w> <h> @F <w> <h> <g4src> */
310 /* <w> <h> @C <w> <h> <g4a85src> */
311 "/@F{@ &2<<F}!/@C{@X &2 FX}!",
312 /* <w> <h> <name> (<length>|) $X <w> <h> <data> */
313 /* <w> <h> <?> <?> <src> &4 <w> <h> <?> <?> <src> <w> <h> */
314 /* <w> <h> <name> (<length>|) $F <w> <h> <data> */
315 /* <w> <h> <name> (<length>|) $C <w> <h> <data> */
316 "/$X{+ @X |}!/&4{4 index 4 index}!/$F{+ @ &4<<F |}!/$C{+ @X &4 FX |}!",
317 /* <w> <h> <bpc> <matrix> <decode> <interpolate> <src>IC - */
318 "/IC{3 1 roll 10 dict begin 1{/ImageType/Interpolate/Decode/DataSource",
319 "/ImageMatrix/BitsPerComponent/Height/Width}{exch def}forall",
320 "currentdict end image}!",
321 /* A hack for compatibility with interpreters, which don't consume
322 ASCII85Decode EOD when reader stops immediately before it : */
323 "/~{@ read {pop} if}!",
324 0
325 };
326
327 /* ---------------- Utilities ---------------- */
328
329 /*
330 * Output the file header. This must write to a file, not a stream,
331 * because it may be called during finalization.
332 */
333 private int
psw_begin_file(gx_device_pswrite * pdev,const gs_rect * pbbox)334 psw_begin_file(gx_device_pswrite *pdev, const gs_rect *pbbox)
335 {
336 int code;
337 FILE *f = pdev->file;
338 char const * const *p1;
339 char const * const *p2;
340
341 if (pdev->pswrite_common.LanguageLevel < 1.5) {
342 p1 = psw_1_x_procset;
343 p2 = psw_1_procset;
344 } else if (pdev->pswrite_common.LanguageLevel > 1.5) {
345 p1 = psw_1_5_procset;
346 p2 = psw_2_procset;
347 } else {
348 p1 = psw_1_x_procset;
349 p2 = psw_1_5_procset;
350 }
351
352 if ((code = psw_begin_file_header(f, (gx_device *)pdev, pbbox,
353 &pdev->pswrite_common,
354 pdev->params.ASCII85EncodePages)) < 0 ||
355 (code = psw_print_lines(f, psw_procset)) < 0 ||
356 (code = psw_print_lines(f, p1)) < 0 ||
357 (code = psw_print_lines(f, p2)) < 0 ||
358 (code = psw_end_file_header(f)) < 0)
359 return code;
360 if(fflush(f) == EOF)
361 return_error(gs_error_ioerror);
362 return 0;
363 }
364
365 /* Reset the image cache. */
366 private void
image_cache_reset(gx_device_pswrite * pdev)367 image_cache_reset(gx_device_pswrite * pdev)
368 {
369 int i;
370
371 for (i = 0; i < image_cache_size; ++i)
372 pdev->image_cache[i].id = gx_no_bitmap_id;
373 pdev->cache_toggle = false;
374 }
375
376 /* Look up or enter image parameters in the cache. */
377 /* Return -1 if the key is not in the cache, or its index. */
378 /* If id is gx_no_bitmap_id or enter is false, do not enter it. */
379 private int
image_cache_lookup(gx_device_pswrite * pdev,gx_bitmap_id id,int width,int height,bool enter)380 image_cache_lookup(gx_device_pswrite * pdev, gx_bitmap_id id,
381 int width, int height, bool enter)
382 {
383 int i1, i2;
384 psw_image_params_t *pip1;
385 psw_image_params_t *pip2;
386
387 if (id == gx_no_bitmap_id)
388 return -1;
389 i1 = id % image_cache_size;
390 pip1 = &pdev->image_cache[i1];
391 if (pip1->id == id && pip1->width == width && pip1->height == height) {
392 return i1;
393 }
394 i2 = (i1 + image_cache_reprobe_step) % image_cache_size;
395 pip2 = &pdev->image_cache[i2];
396 if (pip2->id == id && pip2->width == width && pip2->height == height) {
397 return i2;
398 }
399 if (enter) {
400 int i = ((pdev->cache_toggle = !pdev->cache_toggle) ? i2 : i1);
401 psw_image_params_t *pip = &pdev->image_cache[i];
402
403 pip->id = id, pip->width = width, pip->height = height;
404 return i;
405 }
406 return -1;
407 }
408
409 /*
410 * Prepare the encoding stream for image data.
411 * Return 1 if using ASCII (Hex or 85) encoding, 0 if binary.
412 */
413 private int
psw_image_stream_setup(gx_device_pswrite * pdev,bool binary_ok)414 psw_image_stream_setup(gx_device_pswrite * pdev, bool binary_ok)
415 {
416 int code;
417 bool save = pdev->binary_ok;
418
419 if (pdev->pswrite_common.LanguageLevel >= 2 || binary_ok) {
420 pdev->binary_ok = binary_ok;
421 code = psdf_begin_binary((gx_device_psdf *)pdev, pdev->image_writer);
422 } else {
423 /* LanguageLevel 1, binary not OK. Use ASCIIHex encoding. */
424 pdev->binary_ok = true;
425 code = psdf_begin_binary((gx_device_psdf *)pdev, pdev->image_writer);
426 if (code >= 0) {
427 stream_state *st =
428 s_alloc_state(pdev->v_memory, s_AXE_template.stype,
429 "psw_image_stream_setup");
430
431 if (st == 0)
432 code = gs_note_error(gs_error_VMerror);
433 else {
434 code = psdf_encode_binary(pdev->image_writer,
435 &s_AXE_template, st);
436 if (code >= 0)
437 ((stream_AXE_state *)st)->EndOfData = false; /* no > */
438 }
439 }
440 }
441 pdev->binary_ok = save;
442 return (code < 0 ? code : !binary_ok);
443 }
444
445 /* Clean up after writing an image. */
446 private int
psw_image_cleanup(gx_device_pswrite * pdev)447 psw_image_cleanup(gx_device_pswrite * pdev)
448 {
449 int code = 0;
450
451 if (pdev->image_stream != 0) {
452 code = psdf_end_binary(pdev->image_writer);
453 memset(pdev->image_writer, 0, sizeof(*pdev->image_writer));
454 }
455 return code;
456 }
457
458 /* Write data for an image. Assumes width > 0, height > 0. */
459 private int
psw_put_bits(stream * s,const byte * data,int data_x_bit,uint raster,uint width_bits,int height)460 psw_put_bits(stream * s, const byte * data, int data_x_bit, uint raster,
461 uint width_bits, int height)
462 {
463 const byte *row = data + (data_x_bit >> 3);
464 int shift = data_x_bit & 7;
465 int y;
466
467 for (y = 0; y < height; ++y, row += raster) {
468 if (shift == 0)
469 stream_write(s, row, (width_bits + 7) >> 3);
470 else {
471 const byte *src = row;
472 int wleft = width_bits;
473 int cshift = 8 - shift;
474
475 for (; wleft + shift > 8; ++src, wleft -= 8)
476 stream_putc(s, (byte)((*src << shift) + (src[1] >> cshift)));
477 if (wleft > 0)
478 stream_putc(s, (byte)((*src << shift) & (byte)(0xff00 >> wleft)));
479 }
480 if (s->end_status == ERRC)
481 return_error(gs_error_ioerror);
482 }
483 return 0;
484 }
485 private int
psw_put_image_bits(gx_device_pswrite * pdev,const char * op,const byte * data,int data_x,uint raster,int width,int height,int depth)486 psw_put_image_bits(gx_device_pswrite *pdev, const char *op,
487 const byte * data, int data_x, uint raster,
488 int width, int height, int depth)
489 {
490 int code;
491
492 pprints1(pdev->strm, "%s\n", op);
493 code = psw_put_bits(pdev->image_stream, data, data_x * depth, raster,
494 width * depth, height);
495 if (code < 0)
496 return code;
497 psw_image_cleanup(pdev);
498 return 0;
499 }
500 private int
psw_put_image(gx_device_pswrite * pdev,const char * op,int encode,const byte * data,int data_x,uint raster,int width,int height,int depth)501 psw_put_image(gx_device_pswrite *pdev, const char *op, int encode,
502 const byte * data, int data_x, uint raster,
503 int width, int height, int depth)
504 {
505 int code = psw_image_stream_setup(pdev, !(encode & 1));
506
507 if (code < 0)
508 return code;
509 if (encode & 2) {
510 code = psdf_CFE_binary(pdev->image_writer, width, height, false);
511 if (code < 0)
512 return code;
513 }
514 return psw_put_image_bits(pdev, op, data, data_x, raster,
515 width, height, depth);
516 }
517 private int
psw_image_write(gx_device_pswrite * pdev,const char * imagestr,const byte * data,int data_x,uint raster,gx_bitmap_id id,int x,int y,int width,int height,int depth)518 psw_image_write(gx_device_pswrite * pdev, const char *imagestr,
519 const byte * data, int data_x, uint raster, gx_bitmap_id id,
520 int x, int y, int width, int height, int depth)
521 {
522 stream *s = gdev_vector_stream((gx_device_vector *) pdev);
523 uint width_bits = width * depth;
524 int index = image_cache_lookup(pdev, id, width_bits, height, false);
525 char str[40];
526 char endstr[20];
527 int code, encode;
528 const char *op;
529
530 if (index >= 0) {
531 sprintf(str, "%d%c", index / 26, index % 26 + 'A');
532 pprintd2(s, "%d %d ", x, y);
533 pprints2(s, "%s %s\n", str, imagestr);
534 if (s->end_status == ERRC)
535 return_error(gs_error_ioerror);
536 return 0;
537 }
538 pprintd4(s, "%d %d %d %d ", x, y, width, height);
539 encode = !pdev->binary_ok;
540 if (depth == 1 && width > 16 && pdev->pswrite_common.LanguageLevel >= 2) {
541 /*
542 * We should really look at the statistics of the image before
543 * committing to using G4 encoding....
544 */
545 encode += 2;
546 }
547 if (id == gx_no_bitmap_id || width_bits * (ulong) height > 8000) {
548 static const char *const uncached[4] = {
549 "@", "@X", "@F", "@C"
550 };
551
552 stream_puts(s, uncached[encode]);
553 op = imagestr;
554 strcpy(endstr, "\n");
555 } else {
556 static const char *const cached[4] = {
557 "$", "$X", "$F", "$C"
558 };
559
560 index = image_cache_lookup(pdev, id, width_bits, height, true);
561 sprintf(str, "/%d%c", index / 26, index % 26 + 'A');
562 stream_puts(s, str);
563 if (depth != 1)
564 pprintld1(s, " %ld", ((width_bits + 7) >> 3) * (ulong) height);
565 op = cached[encode];
566 sprintf(endstr, "\n%s\n", imagestr);
567 }
568 if (s->end_status == ERRC)
569 return_error(gs_error_ioerror);
570 /*
571 * In principle, we should put %%BeginData: / %%EndData around all data
572 * sections. However, as long as the data are ASCII (not binary), they
573 * can't cause problems for a DSC parser as long as all lines are
574 * limited to 255 characters and there is no possibility that %% might
575 * occur at the beginning of a line. ASCIIHexEncoded data can't contain
576 * % at all, and our implementation of ASCII85Encode also guarantees
577 * the desired property. Therefore, we only bracket binary data.
578 */
579 if (encode & 1) {
580 /* We're using ASCII encoding. */
581 stream_putc(s, '\n');
582 code = psw_put_image(pdev, op, encode, data, data_x, raster,
583 width, height, depth);
584 if (code < 0)
585 return code;
586 } else {
587 /*
588 * Do a pre-pass to compute the amount of binary data for the
589 * %%BeginData DSC comment.
590 */
591 stream poss;
592
593 s_init(s, pdev->memory);
594 swrite_position_only(&poss);
595 pdev->strm = &poss;
596 code = psw_put_image(pdev, op, encode, data, data_x, raster,
597 width, height, depth);
598 pdev->strm = s;
599 if (code < 0)
600 return code;
601 pprintld1(s, "\n%%%%BeginData: %ld\n", stell(&poss));
602 code = psw_put_image(pdev, op, encode, data, data_x, raster,
603 width, height, depth);
604 if (code < 0)
605 return code;
606 stream_puts(s, "\n%%EndData");
607 }
608 stream_puts(s, endstr);
609 if (s->end_status == ERRC)
610 return_error(gs_error_ioerror);
611 return 0;
612 }
613
614 /* Print a matrix. */
615 private void
psw_put_matrix(stream * s,const gs_matrix * pmat)616 psw_put_matrix(stream * s, const gs_matrix * pmat)
617 {
618 pprintg6(s, "[%g %g %g %g %g %g]",
619 pmat->xx, pmat->xy, pmat->yx, pmat->yy, pmat->tx, pmat->ty);
620 }
621
622 /* Check for a deferred erasepage. */
623 private int
psw_check_erasepage(gx_device_pswrite * pdev)624 psw_check_erasepage(gx_device_pswrite *pdev)
625 {
626 int code = 0;
627
628 if (pdev->page_fill.color != gx_no_color_index) {
629 if (pdev->page_fill.rect.p.x != pdev->page_fill.rect.q.x
630 && pdev->page_fill.rect.p.y != pdev->page_fill.rect.q.y)
631 {
632 code = gdev_vector_fill_rectangle((gx_device *)pdev,
633 pdev->page_fill.rect.p.x,
634 pdev->page_fill.rect.p.y,
635 pdev->page_fill.rect.q.x -
636 pdev->page_fill.rect.p.x,
637 pdev->page_fill.rect.q.y -
638 pdev->page_fill.rect.p.y,
639 pdev->page_fill.color);
640 }
641 pdev->page_fill.color = gx_no_color_index;
642 }
643 return code;
644 }
645 #define CHECK_BEGIN_PAGE(pdev)\
646 BEGIN\
647 int code_ = psw_check_erasepage(pdev);\
648 \
649 if (code_ < 0)\
650 return code_;\
651 END
652
653 /* Check if we write each page into separate file. */
654 private bool
psw_is_separate_pages(gx_device_vector * const vdev)655 psw_is_separate_pages(gx_device_vector *const vdev)
656 {
657 const char *fmt;
658 gs_parsed_file_name_t parsed;
659 int code = gx_parse_output_file_name(&parsed, &fmt, vdev->fname, strlen(vdev->fname));
660
661 return (code >= 0 && fmt != 0);
662 }
663
664 /* ---------------- Vector device implementation ---------------- */
665
666 private int
psw_beginpage(gx_device_vector * vdev)667 psw_beginpage(gx_device_vector * vdev)
668 {
669 gx_device_pswrite *const pdev = (gx_device_pswrite *)vdev;
670 int code = psw_open_printer((gx_device *)vdev);
671
672 stream *s = vdev->strm;
673
674 if (code < 0)
675 return code;
676
677 if (pdev->first_page) {
678 code = psw_begin_file(pdev, NULL);
679 if (code < 0)
680 return code;
681 }
682
683 code = psw_write_page_header(s, (gx_device *)vdev, &pdev->pswrite_common, true,
684 (psw_is_separate_pages(vdev) ? 1 : vdev->PageCount + 1),
685 image_cache_size);
686 if (code < 0)
687 return code;
688
689 pdev->page_fill.color = gx_no_color_index;
690 return 0;
691 }
692
693
694 private int
psw_can_handle_hl_color(gx_device_vector * vdev,const gs_imager_state * pis1,const gx_drawing_color * pdc)695 psw_can_handle_hl_color(gx_device_vector * vdev, const gs_imager_state * pis1,
696 const gx_drawing_color * pdc)
697 {
698 return false; /* High level color is not implemented yet. */
699 }
700
701 private int
psw_setcolors(gx_device_vector * vdev,const gs_imager_state * pis1,const gx_drawing_color * pdc)702 psw_setcolors(gx_device_vector * vdev, const gs_imager_state * pis1,
703 const gx_drawing_color * pdc)
704 {
705 const gs_imager_state * pis = NULL; /* High level color is not implemented yet. */
706 if (!gx_dc_is_pure(pdc))
707 return_error(gs_error_rangecheck);
708 /* PostScript only keeps track of a single color. */
709 gx_hld_save_color(pis, pdc, &vdev->saved_fill_color);
710 gx_hld_save_color(pis, pdc, &vdev->saved_stroke_color);
711 {
712 stream *s = gdev_vector_stream(vdev);
713 gx_color_index color = gx_dc_pure_color(pdc);
714 int r = color >> 16;
715 int g = (color >> 8) & 0xff;
716 int b = color & 0xff;
717
718 if (r == g && g == b) {
719 if (r == 0)
720 stream_puts(s, "K\n");
721 else
722 pprintd1(s, "%d G\n", r);
723 } else if (r == g)
724 pprintd2(s, "%d %d r6\n", b, r);
725 else if (g == b)
726 pprintd2(s, "%d %d r3\n", r, g);
727 else if (r == b)
728 pprintd2(s, "%d %d r5\n", g, b);
729 else
730 pprintd3(s, "%d %d %d rG\n", r, g, b);
731 if (s->end_status == ERRC)
732 return_error(gs_error_ioerror);
733 }
734 return 0;
735 }
736
737 /* Redefine dorect to recognize rectangle fills. */
738 private int
psw_dorect(gx_device_vector * vdev,fixed x0,fixed y0,fixed x1,fixed y1,gx_path_type_t type)739 psw_dorect(gx_device_vector * vdev, fixed x0, fixed y0, fixed x1, fixed y1,
740 gx_path_type_t type)
741 {
742 if ((type & ~gx_path_type_rule) != gx_path_type_fill)
743 return psdf_dorect(vdev, x0, y0, x1, y1, type);
744 pprintg4(gdev_vector_stream(vdev), "%g %g %g %g rf\n",
745 fixed2float(x0), fixed2float(y0),
746 fixed2float(x1 - x0), fixed2float(y1 - y0));
747 if ((gdev_vector_stream(vdev))->end_status == ERRC)
748 return_error(gs_error_ioerror);
749 return 0;
750 }
751
752 /*
753 * We redefine path tracing to use a compact form for polygons; also,
754 * we only need to write coordinates with 2 decimals of precision,
755 * since this is 10 times more precise than any existing output device.
756 */
757 inline private double
round_coord2(floatp v)758 round_coord2(floatp v)
759 {
760 return floor(v * 100 + 0.5) / 100.0;
761 }
762 private void
print_coord2(stream * s,floatp x,floatp y,const char * str)763 print_coord2(stream * s, floatp x, floatp y, const char *str)
764 {
765 pprintg2(s, "%g %g ", round_coord2(x), round_coord2(y));
766 if (str != 0)
767 stream_puts(s, str);
768 }
769
770 private int
psw_beginpath(gx_device_vector * vdev,gx_path_type_t type)771 psw_beginpath(gx_device_vector * vdev, gx_path_type_t type)
772 {
773 gx_device_pswrite *const pdev = (gx_device_pswrite *)vdev;
774
775 if (type & (gx_path_type_fill | gx_path_type_stroke)) {
776 /*
777 * fill_path and stroke_path call CHECK_BEGIN_PAGE themselves:
778 * we do it here to handle polygons (trapezoid, parallelogram,
779 * triangle), which don't go through fill_path.
780 */
781 CHECK_BEGIN_PAGE(pdev);
782 }
783 pdev->path_state.num_points = 0;
784 pdev->path_state.move = 0;
785 if (type & gx_path_type_clip) {
786 /*
787 * This approach doesn't work for clip + fill or stroke, but that
788 * combination can't occur.
789 */
790 stream *s = gdev_vector_stream(vdev);
791
792 stream_puts(s, "Q q\n");
793 gdev_vector_reset(vdev);
794 if (s->end_status == ERRC)
795 return_error(gs_error_ioerror);
796 }
797 return 0;
798 }
799
800 private int
psw_moveto(gx_device_vector * vdev,floatp x0,floatp y0,floatp x,floatp y,gx_path_type_t type)801 psw_moveto(gx_device_vector * vdev, floatp x0, floatp y0, floatp x, floatp y,
802 gx_path_type_t type)
803 {
804 stream *s = gdev_vector_stream(vdev);
805 gx_device_pswrite *const pdev = (gx_device_pswrite *)vdev;
806
807 if (pdev->path_state.num_points > pdev->path_state.move)
808 stream_puts(s, (pdev->path_state.move ? "P\n" : "p\n"));
809 else if (pdev->path_state.move) {
810 /*
811 * Two consecutive movetos -- possible only if a zero-length line
812 * was discarded.
813 */
814 stream_puts(s, "pop pop\n");
815 }
816 print_coord2(s, x, y, NULL);
817 pdev->path_state.num_points = 1;
818 pdev->path_state.move = 1;
819 if (s->end_status == ERRC)
820 return_error(gs_error_ioerror);
821 return 0;
822 }
823
824 private int
psw_lineto(gx_device_vector * vdev,floatp x0,floatp y0,floatp x,floatp y,gx_path_type_t type)825 psw_lineto(gx_device_vector * vdev, floatp x0, floatp y0, floatp x, floatp y,
826 gx_path_type_t type)
827 {
828 double dx = x - x0, dy = y - y0;
829
830 /*
831 * Omit null lines except when stroking (so that linecap works).
832 ****** MAYBE WRONG IF PATH CONSISTS ONLY OF NULL LINES. ******
833 */
834 if ((type & gx_path_type_stroke) || dx != 0 || dy != 0) {
835 stream *s = gdev_vector_stream(vdev);
836 gx_device_pswrite *const pdev = (gx_device_pswrite *)vdev;
837
838 if (pdev->path_state.num_points > MAXOPSTACK / 2 - 10) {
839 stream_puts(s, (pdev->path_state.move ? "P\n" : "p\n"));
840 pdev->path_state.num_points = 0;
841 pdev->path_state.move = 0;
842 }
843 else if (pdev->path_state.num_points > 0 &&
844 !(pdev->path_state.num_points & 7)
845 )
846 stream_putc(s, '\n'); /* limit line length for DSC compliance */
847 if (pdev->path_state.num_points - pdev->path_state.move >= 2 &&
848 dx == -pdev->path_state.dprev[1].x &&
849 dy == -pdev->path_state.dprev[1].y
850 )
851 stream_puts(s, "^ ");
852 else
853 print_coord2(s, dx, dy, NULL);
854 pdev->path_state.num_points++;
855 pdev->path_state.dprev[1] = pdev->path_state.dprev[0];
856 pdev->path_state.dprev[0].x = dx;
857 pdev->path_state.dprev[0].y = dy;
858 if (s->end_status == ERRC)
859 return_error(gs_error_ioerror);
860 }
861 return 0;
862 }
863
864 private int
psw_curveto(gx_device_vector * vdev,floatp x0,floatp y0,floatp x1,floatp y1,floatp x2,floatp y2,floatp x3,floatp y3,gx_path_type_t type)865 psw_curveto(gx_device_vector * vdev, floatp x0, floatp y0,
866 floatp x1, floatp y1, floatp x2, floatp y2, floatp x3, floatp y3,
867 gx_path_type_t type)
868 {
869 stream *s = gdev_vector_stream(vdev);
870 double dx1 = x1 - x0, dy1 = y1 - y0;
871 double dx2 = x2 - x0, dy2 = y2 - y0;
872 double dx3 = x3 - x0, dy3 = y3 - y0;
873 gx_device_pswrite *const pdev = (gx_device_pswrite *)vdev;
874
875 if (pdev->path_state.num_points > 0)
876 stream_puts(s, (pdev->path_state.move ?
877 (pdev->path_state.num_points == 1 ? "m\n" : "P\n") :
878 "p\n"));
879 if (dx1 == 0 && dy1 == 0) {
880 print_coord2(s, dx2, dy2, NULL);
881 print_coord2(s, dx3, dy3, "v\n");
882 } else if (x3 == x2 && y3 == y2) {
883 print_coord2(s, dx1, dy1, NULL);
884 print_coord2(s, dx2, dy2, "y\n");
885 } else {
886 print_coord2(s, dx1, dy1, NULL);
887 print_coord2(s, dx2, dy2, NULL);
888 print_coord2(s, dx3, dy3, "c\n");
889 }
890 pdev->path_state.num_points = 0;
891 pdev->path_state.move = 0;
892 if (s->end_status == ERRC)
893 return_error(gs_error_ioerror);
894 return 0;
895 }
896
897 private int
psw_closepath(gx_device_vector * vdev,floatp x0,floatp y0,floatp x_start,floatp y_start,gx_path_type_t type)898 psw_closepath(gx_device_vector * vdev, floatp x0, floatp y0,
899 floatp x_start, floatp y_start, gx_path_type_t type)
900 {
901 gx_device_pswrite *const pdev = (gx_device_pswrite *)vdev;
902
903 stream_puts(gdev_vector_stream(vdev),
904 (pdev->path_state.num_points > 0 && pdev->path_state.move ?
905 "H\n" : "h\n"));
906 pdev->path_state.num_points = 0;
907 pdev->path_state.move = 0;
908 if ((gdev_vector_stream(vdev))->end_status == ERRC)
909 return_error(gs_error_ioerror);
910 return 0;
911 }
912
913 private int
psw_endpath(gx_device_vector * vdev,gx_path_type_t type)914 psw_endpath(gx_device_vector * vdev, gx_path_type_t type)
915 {
916 stream *s = vdev->strm;
917 const char *star = (type & gx_path_type_even_odd ? "*" : "");
918 gx_device_pswrite *const pdev = (gx_device_pswrite *)vdev;
919
920 if (pdev->path_state.num_points > 0 && !pdev->path_state.move)
921 stream_puts(s, "p ");
922 if (type & gx_path_type_fill) {
923 if (type & (gx_path_type_stroke | gx_path_type_clip))
924 pprints1(s, "q f%s Q ", star);
925 else
926 pprints1(s, "f%s\n", star);
927 }
928 if (type & gx_path_type_stroke) {
929 if (type & gx_path_type_clip)
930 stream_puts(s, "q S Q ");
931 else
932 stream_puts(s, "S\n");
933 }
934 if (type & gx_path_type_clip)
935 pprints1(s, "Y%s\n", star);
936 if (s->end_status == ERRC)
937 return_error(gs_error_ioerror);
938 return 0;
939 }
940
941 /* ---------------- Driver procedures ---------------- */
942
943 /* ------ Open/close/page ------ */
944
945 /* Open the device. */
946 private int
psw_open(gx_device * dev)947 psw_open(gx_device * dev)
948 {
949 gs_memory_t *mem = gs_memory_stable(dev->memory);
950 gx_device_vector *const vdev = (gx_device_vector *)dev;
951 gx_device_pswrite *const pdev = (gx_device_pswrite *)vdev;
952
953 vdev->v_memory = mem;
954 vdev->vec_procs = &psw_vector_procs;
955
956 gdev_vector_init(vdev);
957 vdev->fill_options = vdev->stroke_options = gx_path_type_optimize;
958 pdev->binary_ok = !pdev->params.ASCII85EncodePages;
959 pdev->image_writer = gs_alloc_struct(mem, psdf_binary_writer,
960 &st_psdf_binary_writer,
961 "psw_open(image_writer)");
962 memset(pdev->image_writer, 0, sizeof(*pdev->image_writer)); /* for GC */
963 image_cache_reset(pdev);
964
965 pdev->strm = NULL;
966
967 /* if (ppdev->OpenOutputFile) */
968 {
969 int code = psw_open_printer(dev);
970
971 if (code < 0)
972 return code;
973 }
974
975 return 0;
976 }
977
978 /* Wrap up ("output") a page. */
979 private int
psw_output_page(gx_device * dev,int num_copies,int flush)980 psw_output_page(gx_device * dev, int num_copies, int flush)
981 {
982 int code;
983 gx_device_vector *const vdev = (gx_device_vector *)dev;
984 gx_device_pswrite *const pdev = (gx_device_pswrite *)vdev;
985 stream *s = gdev_vector_stream(vdev);
986
987 /* Check for a legitimate empty page. */
988 CHECK_BEGIN_PAGE(pdev);
989 sflush(s); /* sync stream and file */
990 code = psw_write_page_trailer(vdev->file, num_copies, flush);
991 if(code < 0)
992 return code;
993 vdev->in_page = false;
994 pdev->first_page = false;
995 gdev_vector_reset(vdev);
996 image_cache_reset(pdev);
997 if (ferror(vdev->file))
998 return_error(gs_error_ioerror);
999
1000 dev->PageCount ++;
1001 if (psw_is_separate_pages(vdev)) {
1002 code = psw_close_printer(dev);
1003
1004 if (code < 0)
1005 return code;
1006 }
1007 return 0;
1008 }
1009
1010 /* Close the device. */
1011 /* Note that if this is being called as a result of finalization, */
1012 /* the stream may have been finalized; but the file will still be open. */
1013 private int
psw_close(gx_device * dev)1014 psw_close(gx_device * dev)
1015 {
1016 gx_device_vector *const vdev = (gx_device_vector *)dev;
1017 gx_device_pswrite *const pdev = (gx_device_pswrite *)vdev;
1018
1019 gs_free_object(pdev->v_memory, pdev->image_writer,
1020 "psw_close(image_writer)");
1021 pdev->image_writer = 0;
1022
1023 if (vdev->strm != NULL) {
1024 int code = psw_close_printer(dev);
1025
1026 if (code < 0)
1027 return code;
1028 }
1029
1030 return 0;
1031 }
1032
1033 /* ---------------- Get/put parameters ---------------- */
1034
1035 /* Get parameters. */
1036 private int
psw_get_params(gx_device * dev,gs_param_list * plist)1037 psw_get_params(gx_device * dev, gs_param_list * plist)
1038 {
1039 gx_device_pswrite *const pdev = (gx_device_pswrite *)dev;
1040 int code = gdev_psdf_get_params(dev, plist);
1041 int ecode;
1042
1043 if (code < 0)
1044 return code;
1045 if ((ecode = param_write_float(plist, "LanguageLevel", &pdev->pswrite_common.LanguageLevel)) < 0)
1046 return ecode;
1047 return code;
1048 }
1049
1050 /* Put parameters. */
1051 private int
psw_put_params(gx_device * dev,gs_param_list * plist)1052 psw_put_params(gx_device * dev, gs_param_list * plist)
1053 {
1054 int ecode = 0;
1055 int code;
1056 gs_param_name param_name;
1057 gx_device_pswrite *const pdev = (gx_device_pswrite *)dev;
1058 float ll = pdev->pswrite_common.LanguageLevel;
1059 psdf_version save_version = pdev->version;
1060
1061 switch (code = param_read_float(plist, (param_name = "LanguageLevel"), &ll)) {
1062 case 0:
1063 if (ll == 1.0 || ll == 1.5 || ll == 2.0 || ll == 3.0)
1064 break;
1065 code = gs_error_rangecheck;
1066 default:
1067 ecode = code;
1068 param_signal_error(plist, param_name, ecode);
1069 case 1:
1070 ;
1071 }
1072
1073 if (ecode < 0)
1074 return ecode;
1075 /*
1076 * We have to set version to the new value, because the set of
1077 * legal parameter values for psdf_put_params varies according to
1078 * the version.
1079 */
1080 {
1081 static const psdf_version vv[3] =
1082 {
1083 psdf_version_level1, psdf_version_level1_color,
1084 psdf_version_level2
1085 };
1086
1087 pdev->version = vv[(int)(ll * 2) - 2];
1088 }
1089 code = gdev_psdf_put_params(dev, plist);
1090 if (code < 0) {
1091 pdev->version = save_version;
1092 return code;
1093 }
1094 pdev->pswrite_common.LanguageLevel = ll;
1095 return code;
1096 }
1097
1098 /* ---------------- Rectangles ---------------- */
1099
1100 private int
psw_fill_rectangle(gx_device * dev,int x,int y,int w,int h,gx_color_index color)1101 psw_fill_rectangle(gx_device * dev, int x, int y, int w, int h,
1102 gx_color_index color)
1103 {
1104 gx_device_pswrite *const pdev = (gx_device_pswrite *)dev;
1105
1106 /*
1107 * If the transfer function doesn't map 1 setgray to device white,
1108 * the first rectangle fill on a page (from erasepage) will be with
1109 * some color other than white, which gdev_vector_fill_rectangle
1110 * won't handle correctly. Note that this doesn't happen on the
1111 * very first page of a document.
1112 */
1113 if (!pdev->in_page && !pdev->first_page) {
1114 if (pdev->page_fill.color == gx_no_color_index) {
1115 /* Save, but don't output, the erasepage. */
1116 pdev->page_fill.rect.p.x = x;
1117 pdev->page_fill.rect.p.y = y;
1118 pdev->page_fill.rect.q.x = x + w;
1119 pdev->page_fill.rect.q.y = y + h;
1120 pdev->page_fill.color = color;
1121 return 0;
1122 }
1123 }
1124 return gdev_vector_fill_rectangle(dev, x, y, w, h, color);
1125 }
1126
1127 /*
1128 * Open the printer's output file if necessary.
1129 */
1130
1131 private int
psw_open_printer(gx_device * dev)1132 psw_open_printer(gx_device * dev)
1133 {
1134 gx_device_vector *const vdev = (gx_device_vector *)dev;
1135 gx_device_pswrite *const pdev = (gx_device_pswrite *)vdev;
1136
1137 if (vdev->strm != 0) {
1138 return 0;
1139 }
1140 {
1141 int code = gdev_vector_open_file_options(vdev, 512,
1142 VECTOR_OPEN_FILE_SEQUENTIAL_OK |
1143 VECTOR_OPEN_FILE_BBOX);
1144
1145 if (code < 0)
1146 return code;
1147 }
1148
1149 pdev->first_page = true;
1150
1151 return 0;
1152 }
1153
1154 /*
1155 * Close the printer's output file.
1156 */
1157
1158 private int
psw_close_printer(gx_device * dev)1159 psw_close_printer(gx_device * dev)
1160 {
1161 int code;
1162 gx_device_vector *const vdev = (gx_device_vector *)dev;
1163 gx_device_pswrite *const pdev = (gx_device_pswrite *)vdev;
1164 FILE *f = vdev->file;
1165 gs_rect bbox;
1166
1167 gx_device_bbox_bbox(vdev->bbox_device, &bbox);
1168 if (pdev->first_page & !vdev->in_page) {
1169 /* Nothing has been written. Write the file header now. */
1170 code = psw_begin_file(pdev, &bbox);
1171 if (code < 0)
1172 return code;
1173 } else {
1174 /* If there is an incomplete page, complete it now. */
1175 if (vdev->in_page) {
1176 /*
1177 * Flush the stream after writing page trailer.
1178 */
1179
1180 stream *s = vdev->strm;
1181 code = psw_write_page_trailer(vdev->file, 1, 1);
1182 if(code < 0)
1183 return code;
1184 sflush(s);
1185
1186 dev->PageCount++;
1187 }
1188 }
1189 code = psw_end_file(f, dev, &pdev->pswrite_common, &bbox,
1190 (psw_is_separate_pages(vdev) ? 1 : vdev->PageCount));
1191 if(code < 0)
1192 return code;
1193
1194 return gdev_vector_close_file(vdev);
1195 }
1196
1197 /* ---------------- Images ---------------- */
1198
1199 /* Copy a monochrome bitmap. */
1200 private int
psw_copy_mono(gx_device * dev,const byte * data,int data_x,int raster,gx_bitmap_id id,int x,int y,int w,int h,gx_color_index zero,gx_color_index one)1201 psw_copy_mono(gx_device * dev, const byte * data,
1202 int data_x, int raster, gx_bitmap_id id, int x, int y, int w, int h,
1203 gx_color_index zero, gx_color_index one)
1204 {
1205 gx_device_vector *const vdev = (gx_device_vector *)dev;
1206 gx_device_pswrite *const pdev = (gx_device_pswrite *)vdev;
1207 gx_drawing_color color;
1208 const char *op;
1209 int code = 0;
1210
1211 CHECK_BEGIN_PAGE(pdev);
1212 if (w <= 0 || h <= 0)
1213 return 0;
1214 (*dev_proc(vdev->bbox_device, copy_mono))
1215 ((gx_device *) vdev->bbox_device, data, data_x, raster, id,
1216 x, y, w, h, zero, one);
1217 if (one == gx_no_color_index) {
1218 set_nonclient_dev_color(&color, zero);
1219 code = gdev_vector_update_fill_color((gx_device_vector *) pdev,
1220 NULL, &color);
1221 op = "If";
1222 } else if (zero == vdev->black && one == vdev->white)
1223 op = "1 I";
1224 else {
1225 if (zero != gx_no_color_index) {
1226 code = (*dev_proc(dev, fill_rectangle)) (dev, x, y, w, h, zero);
1227 if (code < 0)
1228 return code;
1229 }
1230 set_nonclient_dev_color(&color, one);
1231 code = gdev_vector_update_fill_color((gx_device_vector *) pdev,
1232 NULL, &color);
1233 op = ",";
1234 }
1235 if (code < 0)
1236 return 0;
1237 code = gdev_vector_update_clip_path(vdev, NULL);
1238 if (code < 0)
1239 return code;
1240 return psw_image_write(pdev, op, data, data_x, raster, id,
1241 x, y, w, h, 1);
1242 }
1243
1244 /* Copy a color bitmap. */
1245 private int
psw_copy_color(gx_device * dev,const byte * data,int data_x,int raster,gx_bitmap_id id,int x,int y,int w,int h)1246 psw_copy_color(gx_device * dev,
1247 const byte * data, int data_x, int raster, gx_bitmap_id id,
1248 int x, int y, int w, int h)
1249 {
1250 int depth = dev->color_info.depth;
1251 const byte *bits = data + data_x * 3;
1252 char op[6];
1253 int code;
1254 gx_device_vector *const vdev = (gx_device_vector *)dev;
1255 gx_device_pswrite *const pdev = (gx_device_pswrite *)vdev;
1256
1257 CHECK_BEGIN_PAGE(pdev);
1258 if (w <= 0 || h <= 0)
1259 return 0;
1260 (*dev_proc(vdev->bbox_device, copy_color))
1261 ((gx_device *) vdev->bbox_device, data, data_x, raster, id,
1262 x, y, w, h);
1263 /*
1264 * If this is a 1-pixel-high image, check for it being all the
1265 * same color, and if so, fill it as a rectangle.
1266 */
1267 if (h == 1 && !memcmp(bits, bits + 3, (w - 1) * 3)) {
1268 return (*dev_proc(dev, fill_rectangle))
1269 (dev, x, y, w, h, (bits[0] << 16) + (bits[1] << 8) + bits[2]);
1270 }
1271 sprintf(op, "%d Ic", depth / 3); /* RGB */
1272 code = gdev_vector_update_clip_path(vdev, NULL);
1273 if (code < 0)
1274 return code;
1275 return psw_image_write(pdev, op, data, data_x, raster, id,
1276 x, y, w, h, depth);
1277 }
1278
1279 /* Fill or stroke a path. */
1280 /* We redefine these to skip empty paths, and to allow optimization. */
1281 private int
psw_fill_path(gx_device * dev,const gs_imager_state * pis,gx_path * ppath,const gx_fill_params * params,const gx_device_color * pdevc,const gx_clip_path * pcpath)1282 psw_fill_path(gx_device * dev, const gs_imager_state * pis,
1283 gx_path * ppath, const gx_fill_params * params,
1284 const gx_device_color * pdevc, const gx_clip_path * pcpath)
1285 {
1286 CHECK_BEGIN_PAGE((gx_device_pswrite *)dev);
1287 if (gx_path_is_void(ppath))
1288 return 0;
1289 /* Update the clipping path now. */
1290 gdev_vector_update_clip_path((gx_device_vector *)dev, pcpath);
1291 return gdev_vector_fill_path(dev, pis, ppath, params, pdevc, pcpath);
1292 }
1293 private int
psw_stroke_path(gx_device * dev,const gs_imager_state * pis,gx_path * ppath,const gx_stroke_params * params,const gx_device_color * pdcolor,const gx_clip_path * pcpath)1294 psw_stroke_path(gx_device * dev, const gs_imager_state * pis,
1295 gx_path * ppath, const gx_stroke_params * params,
1296 const gx_device_color * pdcolor, const gx_clip_path * pcpath)
1297 {
1298 gx_device_vector *const vdev = (gx_device_vector *)dev;
1299
1300 CHECK_BEGIN_PAGE((gx_device_pswrite *)dev);
1301 if (gx_path_is_void(ppath) &&
1302 (gx_path_is_null(ppath) ||
1303 gs_currentlinecap((const gs_state *)pis) != gs_cap_round)
1304 )
1305 return 0;
1306 /* Update the clipping path now. */
1307 gdev_vector_update_clip_path(vdev, pcpath);
1308 /* Do the right thing for oddly transformed coordinate systems.... */
1309 {
1310 gx_device_pswrite *const pdev = (gx_device_pswrite *)vdev;
1311 stream *s;
1312 int code;
1313 double scale;
1314 bool set_ctm;
1315 gs_matrix mat;
1316
1317 if (!gx_dc_is_pure(pdcolor))
1318 return gx_default_stroke_path(dev, pis, ppath, params, pdcolor,
1319 pcpath);
1320 set_ctm = (bool)gdev_vector_stroke_scaling(vdev, pis, &scale, &mat);
1321 gdev_vector_update_clip_path(vdev, pcpath);
1322 gdev_vector_prepare_stroke((gx_device_vector *)pdev, pis, params,
1323 pdcolor, scale);
1324 s = pdev->strm;
1325 if (set_ctm) {
1326 stream_puts(s, "q");
1327 if (is_fzero2(mat.xy, mat.yx) && is_fzero2(mat.tx, mat.ty))
1328 pprintg2(s, " %g %g scale\n", mat.xx, mat.yy);
1329 else {
1330 psw_put_matrix(s, &mat);
1331 stream_puts(s, "concat\n");
1332 }
1333 if (s->end_status == ERRC)
1334 return_error(gs_error_ioerror);
1335 }
1336 code = gdev_vector_dopath(vdev, ppath, gx_path_type_stroke,
1337 (set_ctm ? &mat : (const gs_matrix *)0));
1338 if (code < 0)
1339 return code;
1340 if (set_ctm)
1341 stream_puts(s, "Q\n");
1342 }
1343 /* We must merge in the bounding box explicitly. */
1344 return (vdev->bbox_device == 0 ? 0 :
1345 dev_proc(vdev->bbox_device, stroke_path)
1346 ((gx_device *)vdev->bbox_device, pis, ppath, params,
1347 pdcolor, pcpath));
1348 }
1349
1350 /* Fill a mask. */
1351 private int
psw_fill_mask(gx_device * dev,const byte * data,int data_x,int raster,gx_bitmap_id id,int x,int y,int w,int h,const gx_drawing_color * pdcolor,int depth,gs_logical_operation_t lop,const gx_clip_path * pcpath)1352 psw_fill_mask(gx_device * dev,
1353 const byte * data, int data_x, int raster, gx_bitmap_id id,
1354 int x, int y, int w, int h,
1355 const gx_drawing_color * pdcolor, int depth,
1356 gs_logical_operation_t lop, const gx_clip_path * pcpath)
1357 {
1358 gx_device_vector *const vdev = (gx_device_vector *)dev;
1359 gx_device_pswrite *const pdev = (gx_device_pswrite *)vdev;
1360
1361 CHECK_BEGIN_PAGE(pdev);
1362 if (w <= 0 || h <= 0)
1363 return 0;
1364
1365 /* gdev_vector_update_clip_path may output a grestore and gsave,
1366 * causing the setting of the color to be lost. Therefore, we
1367 * must update the clip path first.
1368 */
1369 if (depth > 1 ||
1370 gdev_vector_update_clip_path(vdev, pcpath) < 0 ||
1371 gdev_vector_update_fill_color(vdev, NULL, pdcolor) < 0 ||
1372 gdev_vector_update_log_op(vdev, lop) < 0
1373 )
1374 return gx_default_fill_mask(dev, data, data_x, raster, id,
1375 x, y, w, h, pdcolor, depth, lop, pcpath);
1376 (*dev_proc(vdev->bbox_device, fill_mask))
1377 ((gx_device *) vdev->bbox_device, data, data_x, raster, id,
1378 x, y, w, h, pdcolor, depth, lop, pcpath);
1379 /* Update the clipping path now. */
1380 gdev_vector_update_clip_path(vdev, pcpath);
1381 return psw_image_write(pdev, ",", data, data_x, raster, id,
1382 x, y, w, h, 1);
1383 }
1384
1385 /* ---------------- High-level images ---------------- */
1386
1387 private image_enum_proc_plane_data(psw_image_plane_data);
1388 private image_enum_proc_end_image(psw_image_end_image);
1389 private const gx_image_enum_procs_t psw_image_enum_procs = {
1390 psw_image_plane_data, psw_image_end_image
1391 };
1392
1393 /* Start processing an image. */
1394 private int
psw_begin_image(gx_device * dev,const gs_imager_state * pis,const gs_image_t * pim,gs_image_format_t format,const gs_int_rect * prect,const gx_drawing_color * pdcolor,const gx_clip_path * pcpath,gs_memory_t * mem,gx_image_enum_common_t ** pinfo)1395 psw_begin_image(gx_device * dev,
1396 const gs_imager_state * pis, const gs_image_t * pim,
1397 gs_image_format_t format, const gs_int_rect * prect,
1398 const gx_drawing_color * pdcolor, const gx_clip_path * pcpath,
1399 gs_memory_t * mem, gx_image_enum_common_t ** pinfo)
1400 {
1401 gx_device_vector *const vdev = (gx_device_vector *)dev;
1402 gx_device_pswrite *const pdev = (gx_device_pswrite *)vdev;
1403 gdev_vector_image_enum_t *pie;
1404 const gs_color_space *pcs = pim->ColorSpace;
1405 const gs_color_space *pbcs = pcs;
1406 const char *base_name = NULL;
1407 gs_color_space_index index;
1408 int num_components;
1409 bool binary = pdev->binary_ok;
1410 byte *buffer = 0; /* image buffer if needed */
1411 stream *bs = 0; /* buffer stream if needed */
1412 #define MAX_IMAGE_OP 10 /* imagemask\n */
1413 int code;
1414
1415 CHECK_BEGIN_PAGE(pdev);
1416 pie = gs_alloc_struct(mem, gdev_vector_image_enum_t,
1417 &st_vector_image_enum, "psw_begin_image");
1418 if (pie == 0)
1419 return_error(gs_error_VMerror);
1420 if (prect && !(prect->p.x == 0 && prect->p.y == 0 &&
1421 prect->q.x == pim->Width && prect->q.y == pim->Height)
1422 )
1423 goto fail;
1424 switch (pim->format) {
1425 case gs_image_format_chunky:
1426 case gs_image_format_component_planar:
1427 break;
1428 default:
1429 goto fail;
1430 }
1431 pie->memory = mem;
1432 pie->default_info = 0; /* not used */
1433 if (pim->ImageMask) {
1434 index = -1; /* bogus, not used */
1435 num_components = 1;
1436 } else {
1437 index = gs_color_space_get_index(pcs);
1438 num_components = gs_color_space_num_components(pcs);
1439 if (pim->CombineWithColor)
1440 goto fail;
1441 /*
1442 * We can only handle Device color spaces right now, or Indexed
1443 * color spaces over them, and only the default Decode [0 1 ...]
1444 * or [0 2^BPC-1] respectively.
1445 */
1446 switch (index) {
1447 case gs_color_space_index_Indexed: {
1448 if (pdev->pswrite_common.LanguageLevel < 2 || pcs->params.indexed.use_proc ||
1449 pim->Decode[0] != 0 ||
1450 pim->Decode[1] != (1 << pim->BitsPerComponent) - 1
1451 ) {
1452 goto fail;
1453 }
1454 pbcs = (const gs_color_space *)&pcs->params.indexed.base_space;
1455 switch (gs_color_space_get_index(pbcs)) {
1456 case gs_color_space_index_DeviceGray:
1457 base_name = "DeviceGray"; break;
1458 case gs_color_space_index_DeviceRGB:
1459 base_name = "DeviceRGB"; break;
1460 case gs_color_space_index_DeviceCMYK:
1461 base_name = "DeviceCMYK"; break;
1462 default:
1463 goto fail;
1464 }
1465 break;
1466 }
1467 case gs_color_space_index_DeviceGray:
1468 case gs_color_space_index_DeviceRGB:
1469 case gs_color_space_index_DeviceCMYK: {
1470 int i;
1471
1472 for (i = 0; i < num_components * 2; ++i)
1473 if (pim->Decode[i] != (i & 1))
1474 goto fail;
1475 break;
1476 }
1477 default:
1478 goto fail;
1479 }
1480 }
1481 if (pdev->pswrite_common.LanguageLevel < 2 && !pim->ImageMask) {
1482 /*
1483 * Restrict ourselves to Level 1 images: bits per component <= 8,
1484 * not indexed.
1485 */
1486 if (pim->BitsPerComponent > 8 || pbcs != pcs)
1487 goto fail;
1488 }
1489 if (gdev_vector_begin_image(vdev, pis, pim, format, prect, pdcolor,
1490 pcpath, mem, &psw_image_enum_procs, pie) < 0)
1491 goto fail;
1492 if (binary) {
1493 /*
1494 * We need to buffer the entire image in memory. Currently, the
1495 * only reason for this is the infamous "short image" problem: the
1496 * image may actually have fewer rows than its height specifies. If
1497 * it weren't for that, we could know the size of the binary data in
1498 * advance. However, this will change if we compress images.
1499 */
1500 uint bsize = MAX_IMAGE_OP +
1501 ((pie->bits_per_row + 7) >> 3) * pie->height;
1502
1503 buffer = gs_alloc_bytes(mem, bsize, "psw_begin_image(buffer)");
1504 bs = s_alloc(mem, "psw_begin_image(buffer stream)");
1505 if (buffer && bs) {
1506 swrite_string(bs, buffer, bsize);
1507 } else {
1508 /* An allocation failed. */
1509 gs_free_object(mem, bs, "psw_begin_image(buffer stream)");
1510 gs_free_object(mem, buffer, "psw_begin_image(buffer)");
1511 /*
1512 * Rather than returning VMerror, we fall back to an ASCII
1513 * encoding, which doesn't require a buffer stream.
1514 */
1515 buffer = 0;
1516 bs = 0;
1517 binary = false;
1518 }
1519 }
1520 if (binary) {
1521 /* Set up the image stream to write into the buffer. */
1522 stream *save = pdev->strm;
1523
1524 pdev->strm = bs;
1525 code = psw_image_stream_setup(pdev, true);
1526 pdev->strm = save;
1527 } else {
1528 code = psw_image_stream_setup(pdev, false);
1529 }
1530 if (code < 0)
1531 goto fail;
1532 /* Update the clipping path now. */
1533 gdev_vector_update_clip_path(vdev, pcpath);
1534 /* Write the image/colorimage/imagemask preamble. */
1535 {
1536 stream *s = gdev_vector_stream((gx_device_vector *) pdev);
1537 const char *source = (code ? "@X" : "@");
1538 gs_matrix imat;
1539 const char *op;
1540
1541 stream_puts(s, "q");
1542 (*dev_proc(dev, get_initial_matrix)) (dev, &imat);
1543 gs_matrix_scale(&imat, 72.0 / dev->HWResolution[0],
1544 72.0 / dev->HWResolution[1], &imat);
1545 gs_matrix_invert(&imat, &imat);
1546 gs_matrix_multiply(&ctm_only(pis), &imat, &imat);
1547 psw_put_matrix(s, &imat);
1548 pprintd2(s, "concat\n%d %d ", pie->width, pie->height);
1549 if (pim->ImageMask) {
1550 stream_puts(s, (pim->Decode[0] == 0 ? "false" : "true"));
1551 psw_put_matrix(s, &pim->ImageMatrix);
1552 stream_puts(s, source);
1553 op = "imagemask";
1554 } else {
1555 pprintd1(s, "%d", pim->BitsPerComponent);
1556 psw_put_matrix(s, &pim->ImageMatrix);
1557 if (pbcs != pcs) {
1558 /* This is an Indexed color space. */
1559 pprints1(s, "[/Indexed /%s ", base_name);
1560 pprintd1(s, "%d\n", pcs->params.indexed.hival);
1561 /*
1562 * Don't write the table in binary: it might interfere
1563 * with DSC parsing.
1564 */
1565 s_write_ps_string(s, pcs->params.indexed.lookup.table.data,
1566 pcs->params.indexed.lookup.table.size,
1567 PRINT_ASCII85_OK);
1568 pprintd1(s, "\n]setcolorspace[0 %d]", (int)pim->Decode[1]);
1569 pprints2(s, "%s %s",
1570 (pim->Interpolate ? "true" : "false"), source);
1571 op = "IC";
1572 } else if (index == gs_color_space_index_DeviceGray) {
1573 stream_puts(s, source);
1574 op = "image";
1575 } else {
1576 if (format == gs_image_format_chunky)
1577 pprints1(s, "%s false", source);
1578 else {
1579 /* We have to use procedures. */
1580 stream_puts(s, source);
1581 pprintd2(s, " %d %d B",
1582 (pim->Width * pim->BitsPerComponent + 7) >> 3,
1583 num_components);
1584 }
1585 pprintd1(s, " %d", num_components);
1586 op = "colorimage";
1587 }
1588 }
1589 stream_putc(s, '\n');
1590 pprints1((bs ? bs : s), "%s\n", op);
1591 if (s->end_status == ERRC) {
1592 gs_free_object(mem, bs, "psw_begin_image(buffer stream)");
1593 gs_free_object(mem, buffer, "psw_begin_image(buffer)");
1594 gs_free_object(mem, pie, "psw_begin_image");
1595 return_error(gs_error_ioerror);
1596 }
1597 }
1598 *pinfo = (gx_image_enum_common_t *) pie;
1599 return 0;
1600 fail:
1601 gs_free_object(mem, bs, "psw_begin_image(buffer stream)");
1602 gs_free_object(mem, buffer, "psw_begin_image(buffer)");
1603 gs_free_object(mem, pie, "psw_begin_image");
1604 return gx_default_begin_image(dev, pis, pim, format, prect,
1605 pdcolor, pcpath, mem, pinfo);
1606 }
1607
1608 /* Process the next piece of an image. */
1609 private int
psw_image_plane_data(gx_image_enum_common_t * info,const gx_image_plane_t * planes,int height,int * rows_used)1610 psw_image_plane_data(gx_image_enum_common_t * info,
1611 const gx_image_plane_t * planes, int height,
1612 int *rows_used)
1613 {
1614 gx_device *dev = info->dev;
1615 gx_device_pswrite *const pdev = (gx_device_pswrite *)dev;
1616 gdev_vector_image_enum_t *pie = (gdev_vector_image_enum_t *) info;
1617 int code =
1618 gx_image_plane_data_rows(pie->bbox_info, planes, height, rows_used);
1619 int pi;
1620
1621 for (pi = 0; pi < pie->num_planes; ++pi) {
1622 if (pie->bits_per_row != pie->width * info->plane_depths[pi])
1623 return_error(gs_error_rangecheck);
1624 psw_put_bits(pdev->image_stream, planes[pi].data,
1625 planes[pi].data_x * info->plane_depths[pi],
1626 planes[pi].raster, pie->bits_per_row,
1627 *rows_used);
1628 if (pdev->image_stream->end_status == ERRC)
1629 return_error(gs_error_ioerror);
1630 }
1631 pie->y += *rows_used;
1632 return code;
1633 }
1634
1635 /* Clean up by releasing the buffers. */
1636 private int
psw_image_end_image(gx_image_enum_common_t * info,bool draw_last)1637 psw_image_end_image(gx_image_enum_common_t * info, bool draw_last)
1638 {
1639 gx_device *dev = info->dev;
1640 gx_device_vector *const vdev = (gx_device_vector *)dev;
1641 gx_device_pswrite *const pdev = (gx_device_pswrite *)vdev;
1642 gdev_vector_image_enum_t *pie = (gdev_vector_image_enum_t *) info;
1643 int code;
1644
1645 code = gdev_vector_end_image(vdev, pie, draw_last, pdev->white);
1646 if (code > 0) {
1647 stream *s = pdev->strm;
1648 stream *bs = pdev->image_stream;
1649
1650 /* If we were buffering a binary image, write it now. */
1651 while (bs != s && bs->strm != 0)
1652 bs = bs->strm;
1653 psw_image_cleanup(pdev);
1654 if (bs != s) {
1655 /*
1656 * We were buffering a binary image. Write it now, with the
1657 * DSC comments.
1658 */
1659 gs_memory_t *mem = bs->memory;
1660 byte *buffer = bs->cbuf;
1661 long len = stell(bs);
1662 uint ignore;
1663
1664 pprintld1(s, "%%%%BeginData: %ld\n", len);
1665 sputs(s, buffer, (uint)len, &ignore);
1666 stream_puts(s, "\n%%EndData");
1667 /* Free the buffer and its stream. */
1668 gs_free_object(mem, bs, "psw_image_end_image(buffer stream)");
1669 gs_free_object(mem, buffer, "psw_image_end_image(buffer)");
1670 }
1671 stream_puts(s, "\nQ\n");
1672 if (s->end_status == ERRC)
1673 return_error(gs_error_ioerror);
1674 }
1675 return code;
1676 }
1677