xref: /plan9/sys/src/cmd/gs/src/gdevpsdu.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
1 /* Copyright (C) 1997, 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: gdevpsdu.c,v 1.23 2005/03/14 18:08:36 dan Exp $ */
18 /* Common utilities for PostScript and PDF writers */
19 #include "stdio_.h"		/* for FILE for jpeglib.h */
20 #include "jpeglib_.h"		/* for sdct.h */
21 #include "memory_.h"
22 #include "gx.h"
23 #include "gserrors.h"
24 #include "gdevpsdf.h"
25 #include "strimpl.h"
26 #include "sa85x.h"
27 #include "scfx.h"
28 #include "sdct.h"
29 #include "sjpeg.h"
30 #include "spprint.h"
31 #include "sstring.h"
32 #include "gsovrc.h"
33 
34 /* Structure descriptors */
35 public_st_device_psdf();
36 public_st_psdf_binary_writer();
37 
38 /* Standard color command names. */
39 const psdf_set_color_commands_t psdf_set_fill_color_commands = {
40     "g", "rg", "k", "cs", "sc", "scn"
41 };
42 const psdf_set_color_commands_t psdf_set_stroke_color_commands = {
43     "G", "RG", "K", "CS", "SC", "SCN"
44 };
45 
46 
47 /* Define parameter-setting procedures. */
48 extern stream_state_proc_put_params(s_DCTE_put_params, stream_DCT_state);
49 
50 /* ---------------- Vector implementation procedures ---------------- */
51 
52 int
psdf_setlinewidth(gx_device_vector * vdev,floatp width)53 psdf_setlinewidth(gx_device_vector * vdev, floatp width)
54 {
55     pprintg1(gdev_vector_stream(vdev), "%g w\n", width);
56     return 0;
57 }
58 
59 int
psdf_setlinecap(gx_device_vector * vdev,gs_line_cap cap)60 psdf_setlinecap(gx_device_vector * vdev, gs_line_cap cap)
61 {
62     pprintd1(gdev_vector_stream(vdev), "%d J\n", cap);
63     return 0;
64 }
65 
66 int
psdf_setlinejoin(gx_device_vector * vdev,gs_line_join join)67 psdf_setlinejoin(gx_device_vector * vdev, gs_line_join join)
68 {
69     pprintd1(gdev_vector_stream(vdev), "%d j\n", join);
70     return 0;
71 }
72 
73 int
psdf_setmiterlimit(gx_device_vector * vdev,floatp limit)74 psdf_setmiterlimit(gx_device_vector * vdev, floatp limit)
75 {
76     pprintg1(gdev_vector_stream(vdev), "%g M\n", limit);
77     return 0;
78 }
79 
80 int
psdf_setdash(gx_device_vector * vdev,const float * pattern,uint count,floatp offset)81 psdf_setdash(gx_device_vector * vdev, const float *pattern, uint count,
82 	     floatp offset)
83 {
84     stream *s = gdev_vector_stream(vdev);
85     int i;
86 
87     stream_puts(s, "[ ");
88     for (i = 0; i < count; ++i)
89 	pprintg1(s, "%g ", pattern[i]);
90     pprintg1(s, "] %g d\n", offset);
91     return 0;
92 }
93 
94 int
psdf_setflat(gx_device_vector * vdev,floatp flatness)95 psdf_setflat(gx_device_vector * vdev, floatp flatness)
96 {
97     pprintg1(gdev_vector_stream(vdev), "%g i\n", flatness);
98     return 0;
99 }
100 
101 int
psdf_setlogop(gx_device_vector * vdev,gs_logical_operation_t lop,gs_logical_operation_t diff)102 psdf_setlogop(gx_device_vector * vdev, gs_logical_operation_t lop,
103 	      gs_logical_operation_t diff)
104 {
105 /****** SHOULD AT LEAST DETECT SET-0 & SET-1 ******/
106     return 0;
107 }
108 
109 int
psdf_dorect(gx_device_vector * vdev,fixed x0,fixed y0,fixed x1,fixed y1,gx_path_type_t type)110 psdf_dorect(gx_device_vector * vdev, fixed x0, fixed y0, fixed x1, fixed y1,
111 	    gx_path_type_t type)
112 {
113     int code = (*vdev_proc(vdev, beginpath)) (vdev, type);
114 
115     if (code < 0)
116 	return code;
117     pprintg4(gdev_vector_stream(vdev), "%g %g %g %g re\n",
118 	     fixed2float(x0), fixed2float(y0),
119 	     fixed2float(x1 - x0), fixed2float(y1 - y0));
120     return (*vdev_proc(vdev, endpath)) (vdev, type);
121 }
122 
123 int
psdf_beginpath(gx_device_vector * vdev,gx_path_type_t type)124 psdf_beginpath(gx_device_vector * vdev, gx_path_type_t type)
125 {
126     return 0;
127 }
128 
129 int
psdf_moveto(gx_device_vector * vdev,floatp x0,floatp y0,floatp x,floatp y,gx_path_type_t type)130 psdf_moveto(gx_device_vector * vdev, floatp x0, floatp y0, floatp x, floatp y,
131 	    gx_path_type_t type)
132 {
133     pprintg2(gdev_vector_stream(vdev), "%g %g m\n", x, y);
134     return 0;
135 }
136 
137 int
psdf_lineto(gx_device_vector * vdev,floatp x0,floatp y0,floatp x,floatp y,gx_path_type_t type)138 psdf_lineto(gx_device_vector * vdev, floatp x0, floatp y0, floatp x, floatp y,
139 	    gx_path_type_t type)
140 {
141     pprintg2(gdev_vector_stream(vdev), "%g %g l\n", x, y);
142     return 0;
143 }
144 
145 int
psdf_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)146 psdf_curveto(gx_device_vector * vdev, floatp x0, floatp y0,
147 	   floatp x1, floatp y1, floatp x2, floatp y2, floatp x3, floatp y3,
148 	     gx_path_type_t type)
149 {
150     if (x1 == x0 && y1 == y0 && x2 == x3 && y2 == y3)
151 	pprintg2(gdev_vector_stream(vdev), "%g %g l\n", x3, y3);
152     else if (x1 == x0 && y1 == y0)
153 	pprintg4(gdev_vector_stream(vdev), "%g %g %g %g v\n",
154 		 x2, y2, x3, y3);
155     else if (x3 == x2 && y3 == y2)
156 	pprintg4(gdev_vector_stream(vdev), "%g %g %g %g y\n",
157 		 x1, y1, x2, y2);
158     else
159 	pprintg6(gdev_vector_stream(vdev), "%g %g %g %g %g %g c\n",
160 		 x1, y1, x2, y2, x3, y3);
161     return 0;
162 }
163 
164 int
psdf_closepath(gx_device_vector * vdev,floatp x0,floatp y0,floatp x_start,floatp y_start,gx_path_type_t type)165 psdf_closepath(gx_device_vector * vdev, floatp x0, floatp y0,
166 	       floatp x_start, floatp y_start, gx_path_type_t type)
167 {
168     stream_puts(gdev_vector_stream(vdev), "h\n");
169     return 0;
170 }
171 
172 /* endpath is deliberately omitted. */
173 
174 /* ---------------- Utilities ---------------- */
175 
176 gx_color_index
psdf_adjust_color_index(gx_device_vector * vdev,gx_color_index color)177 psdf_adjust_color_index(gx_device_vector *vdev, gx_color_index color)
178 {
179     /*
180      * Since gx_no_color_index is all 1's, we can't represent
181      * a CMYK color consisting of full ink in all 4 components.
182      * However, this color must be available for registration marks.
183      * gxcmap.c fudges this by changing the K component to 254;
184      * undo this fudge here.
185      */
186     return (color == (gx_no_color_index ^ 1) ? gx_no_color_index : color);
187 }
188 
189 /* Round a double value to a specified precision. */
190 double
psdf_round(double v,int precision,int radix)191 psdf_round(double v, int precision, int radix)
192 {
193     double mul = 1;
194     double w = v;
195 
196     if (w <= 0)
197 	return w;
198     while (w < precision) {
199 	w *= radix;
200 	mul *= radix;
201     }
202     return (int)(w + 0.5) / mul;
203 }
204 
205 /*
206  * Since we only have 8 bits of color to start with, round the
207  * values to 3 digits for more compact output.
208  */
209 private inline double
round_byte_color(gx_color_index cv)210 round_byte_color(gx_color_index cv)
211 {
212     return (int)((uint)cv * (1000.0 / 255.0) + 0.5) / 1000.0;
213 }
214 int
psdf_set_color(gx_device_vector * vdev,const gx_drawing_color * pdc,const psdf_set_color_commands_t * ppscc)215 psdf_set_color(gx_device_vector * vdev, const gx_drawing_color * pdc,
216 	       const psdf_set_color_commands_t *ppscc)
217 {
218     const char *setcolor;
219 
220     if (!gx_dc_is_pure(pdc))
221 	return_error(gs_error_rangecheck);
222     {
223 	stream *s = gdev_vector_stream(vdev);
224 	gx_color_index color =
225 	    psdf_adjust_color_index(vdev, gx_dc_pure_color(pdc));
226 	/*
227 	 * Normally we would precompute all of v0 .. v3, but gcc 2.7.2.3
228 	 * generates incorrect code for Intel CPUs if we do this.  The code
229 	 * below is longer, but does less computation in some cases.
230 	 */
231 	double v3 = round_byte_color(color & 0xff);
232 
233 	switch (vdev->color_info.num_components) {
234 	case 4:
235 	    /* if (v0 == 0 && v1 == 0 && v2 == 0 && ...) */
236 	    if ((color & 0xffffff00) == 0 && ppscc->setgray != 0) {
237 		v3 = 1.0 - v3;
238 		goto g;
239 	    }
240 	    pprintg4(s, "%g %g %g %g", round_byte_color(color >> 24),
241 		     round_byte_color((color >> 16) & 0xff),
242 		     round_byte_color((color >> 8) & 0xff), v3);
243 	    setcolor = ppscc->setcmykcolor;
244 	    break;
245 	case 3:
246 	    /* if (v1 == v2 && v2 == v3 && ...) */
247 	    if (!((color ^ (color >> 8)) & 0xffff) && ppscc->setgray != 0)
248 		goto g;
249 	    pprintg3(s, "%g %g %g", round_byte_color((color >> 16) & 0xff),
250 		     round_byte_color((color >> 8) & 0xff), v3);
251 	    setcolor = ppscc->setrgbcolor;
252 	    break;
253 	case 1:
254 	g:
255 	    pprintg1(s, "%g", v3);
256 	    setcolor = ppscc->setgray;
257 	    break;
258 	default:		/* can't happen */
259 	    return_error(gs_error_rangecheck);
260 	}
261 	if (setcolor)
262 	    pprints1(s, " %s\n", setcolor);
263     }
264     return 0;
265 }
266 
267 /* ---------------- Binary data writing ---------------- */
268 
269 /* Begin writing binary data. */
270 int
psdf_begin_binary(gx_device_psdf * pdev,psdf_binary_writer * pbw)271 psdf_begin_binary(gx_device_psdf * pdev, psdf_binary_writer * pbw)
272 {
273     gs_memory_t *mem = pbw->memory = pdev->v_memory;
274 
275     pbw->target = pdev->strm;
276     pbw->dev = pdev;
277     pbw->strm = 0;		/* for GC in case of failure */
278     /* If not binary, set up the encoding stream. */
279     if (!pdev->binary_ok) {
280 #define BUF_SIZE 100		/* arbitrary */
281 	byte *buf = gs_alloc_bytes(mem, BUF_SIZE, "psdf_begin_binary(buf)");
282 	stream_A85E_state *ss = (stream_A85E_state *)
283 	    s_alloc_state(mem, s_A85E_template.stype,
284 			  "psdf_begin_binary(stream_state)");
285 	stream *s = s_alloc(mem, "psdf_begin_binary(stream)");
286 
287 	if (buf == 0 || ss == 0 || s == 0) {
288 	    gs_free_object(mem, s, "psdf_begin_binary(stream)");
289 	    gs_free_object(mem, ss, "psdf_begin_binary(stream_state)");
290 	    gs_free_object(mem, buf, "psdf_begin_binary(buf)");
291 	    return_error(gs_error_VMerror);
292 	}
293 	ss->template = &s_A85E_template;
294 	s_init_filter(s, (stream_state *)ss, buf, BUF_SIZE, pdev->strm);
295 #undef BUF_SIZE
296 	pbw->strm = s;
297     } else {
298 	pbw->strm = pdev->strm;
299     }
300     return 0;
301 }
302 
303 /* Add an encoding filter.  The client must have allocated the stream state, */
304 /* if any, using pdev->v_memory. */
305 int
psdf_encode_binary(psdf_binary_writer * pbw,const stream_template * template,stream_state * ss)306 psdf_encode_binary(psdf_binary_writer * pbw, const stream_template * template,
307 		   stream_state * ss)
308 {
309     return (s_add_filter(&pbw->strm, template, ss, pbw->memory) == 0 ?
310 	    gs_note_error(gs_error_VMerror) : 0);
311 }
312 
313 /*
314  * Acquire parameters, and optionally set up the filter for, a DCTEncode
315  * filter.  This is a separate procedure so it can be used to validate
316  * filter parameters when they are set, rather than waiting until they are
317  * used.  pbw = NULL means just set up the stream state.
318  */
319 int
psdf_DCT_filter(gs_param_list * plist,stream_state * st,int Columns,int Rows,int Colors,psdf_binary_writer * pbw)320 psdf_DCT_filter(gs_param_list *plist /* may be NULL */,
321 		stream_state /*stream_DCTE_state*/ *st,
322 		int Columns, int Rows, int Colors,
323 		psdf_binary_writer *pbw /* may be NULL */)
324 {
325 	stream_DCT_state *const ss = (stream_DCT_state *) st;
326 	gs_memory_t *mem = st->memory;
327 	jpeg_compress_data *jcdp;
328 	gs_c_param_list rcc_list;
329 	int code;
330 
331 	/*
332 	 * "Wrap" the actual Dict or ACSDict parameter list in one that
333 	 * sets Rows, Columns, and Colors.
334 	 */
335 	gs_c_param_list_write(&rcc_list, mem);
336 	if ((code = param_write_int((gs_param_list *)&rcc_list, "Rows",
337 				    &Rows)) < 0 ||
338 	    (code = param_write_int((gs_param_list *)&rcc_list, "Columns",
339 				    &Columns)) < 0 ||
340 	    (code = param_write_int((gs_param_list *)&rcc_list, "Colors",
341 				    &Colors)) < 0
342 	    ) {
343 	    goto rcc_fail;
344 	}
345 	gs_c_param_list_read(&rcc_list);
346 	if (plist)
347 	    gs_c_param_list_set_target(&rcc_list, plist);
348 	/* Allocate space for IJG parameters. */
349 	jcdp = gs_alloc_struct_immovable(mem, jpeg_compress_data,
350            &st_jpeg_compress_data, "zDCTE");
351         if (jcdp == 0)
352 	    return_error(gs_error_VMerror);
353 	ss->data.compress = jcdp;
354 	jcdp->memory = ss->jpeg_memory = mem;	/* set now for allocation */
355 	if ((code = gs_jpeg_create_compress(ss)) < 0)
356 	    goto dcte_fail;	/* correct to do jpeg_destroy here */
357 	/* Read parameters from dictionary */
358 	s_DCTE_put_params((gs_param_list *)&rcc_list, ss); /* ignore errors */
359 	/* Create the filter. */
360 	jcdp->template = s_DCTE_template;
361 	/* Make sure we get at least a full scan line of input. */
362 	ss->scan_line_size = jcdp->cinfo.input_components *
363 	    jcdp->cinfo.image_width;
364 	jcdp->template.min_in_size =
365 	    max(s_DCTE_template.min_in_size, ss->scan_line_size);
366 	/* Make sure we can write the user markers in a single go. */
367 	jcdp->template.min_out_size =
368 	    max(s_DCTE_template.min_out_size, ss->Markers.size);
369 	if (pbw)
370 	    code = psdf_encode_binary(pbw, &jcdp->template, st);
371 	if (code >= 0) {
372 	    gs_c_param_list_release(&rcc_list);
373 	    return 0;
374 	}
375     dcte_fail:
376 	gs_jpeg_destroy(ss);
377 	gs_free_object(mem, jcdp, "setup_image_compression");
378     rcc_fail:
379 	gs_c_param_list_release(&rcc_list);
380 	return code;
381 }
382 
383 /* Add a 2-D CCITTFax encoding filter. */
384 /* Set EndOfBlock iff the stream is not ASCII85 encoded. */
385 int
psdf_CFE_binary(psdf_binary_writer * pbw,int w,int h,bool invert)386 psdf_CFE_binary(psdf_binary_writer * pbw, int w, int h, bool invert)
387 {
388     gs_memory_t *mem = pbw->memory;
389     const stream_template *template = &s_CFE_template;
390     stream_CFE_state *st =
391 	gs_alloc_struct(mem, stream_CFE_state, template->stype,
392 			"psdf_CFE_binary");
393     int code;
394 
395     if (st == 0)
396 	return_error(gs_error_VMerror);
397     (*template->set_defaults) ((stream_state *) st);
398     st->K = -1;
399     st->Columns = w;
400     st->Rows = 0;
401     st->BlackIs1 = !invert;
402     st->EndOfBlock = pbw->strm->state->template != &s_A85E_template;
403     code = psdf_encode_binary(pbw, template, (stream_state *) st);
404     if (code < 0)
405 	gs_free_object(mem, st, "psdf_CFE_binary");
406     return code;
407 }
408 
409 /* Finish writing binary data. */
410 int
psdf_end_binary(psdf_binary_writer * pbw)411 psdf_end_binary(psdf_binary_writer * pbw)
412 {
413     int status = s_close_filters(&pbw->strm, pbw->target);
414 
415     return (status >= 0 ? 0 : gs_note_error(gs_error_ioerror));
416 }
417 
418 /* ---------------- Overprint, Get Bits ---------------- */
419 
420 /*
421  * High level devices cannot perform get_bits or get_bits_rectangle
422  * operations, for obvious reasons.
423  */
424 int
psdf_get_bits(gx_device * dev,int y,byte * data,byte ** actual_data)425 psdf_get_bits(gx_device * dev, int y, byte * data, byte ** actual_data)
426 {
427     return_error(gs_error_unregistered);
428 }
429 
430 int
psdf_get_bits_rectangle(gx_device * dev,const gs_int_rect * prect,gs_get_bits_params_t * params,gs_int_rect ** unread)431 psdf_get_bits_rectangle(
432     gx_device *             dev,
433     const gs_int_rect *     prect,
434     gs_get_bits_params_t *  params,
435     gs_int_rect **          unread )
436 {
437     return_error(gs_error_unregistered);
438 }
439 
440 /*
441  * Create compositor procedure for PostScript/PDF writer. Since these
442  * devices directly support overprint (and have access to the imager
443  * state), no compositor is required for overprint support. Hence, this
444  * routine just recognizes and discards invocations of the overprint
445  * compositor.
446  */
447 int
psdf_create_compositor(gx_device * dev,gx_device ** pcdev,const gs_composite_t * pct,gs_imager_state * pis,gs_memory_t * mem)448 psdf_create_compositor(
449     gx_device *             dev,
450     gx_device **            pcdev,
451     const gs_composite_t *  pct,
452     gs_imager_state * pis,
453     gs_memory_t *           mem )
454 {
455     if (gs_is_overprint_compositor(pct)) {
456         *pcdev = dev;
457         return 0;
458     } else
459         return gx_default_create_compositor(dev, pcdev, pct, pis, mem);
460 }
461