diff options
Diffstat (limited to 'gs/src/gdevps.c')
-rw-r--r-- | gs/src/gdevps.c | 602 |
1 files changed, 427 insertions, 175 deletions
diff --git a/gs/src/gdevps.c b/gs/src/gdevps.c index 454460bc0..ecffd584c 100644 --- a/gs/src/gdevps.c +++ b/gs/src/gdevps.c @@ -1,4 +1,4 @@ -/* Copyright (C) 1997 Aladdin Enterprises. All rights reserved. +/* Copyright (C) 1997, 1998 Aladdin Enterprises. All rights reserved. This file is part of Aladdin Ghostscript. @@ -16,19 +16,22 @@ all copies. */ -/* gdevps.c */ +/*Id: gdevps.c */ /* PostScript-writing driver */ #include "math_.h" +#include "memory_.h" #include "time_.h" #include "gx.h" #include "gserrors.h" #include "gscdefs.h" #include "gsmatrix.h" /* for gsiparam.h */ #include "gsiparam.h" +#include "gsline.h" #include "gsparam.h" #include "gxdevice.h" #include "gscspace.h" #include "gxdcolor.h" +#include "gzpath.h" #include "gdevpsdf.h" #include "gdevpstr.h" #include "strimpl.h" @@ -43,10 +46,6 @@ /* ---------------- Device definition ---------------- */ -/* Define the size of the internal stream buffer. */ -/* (This is not a limitation: it only affects performance.) */ -#define sbuf_size 512 - /* Device procedures */ private dev_proc_open_device(psw_open); private dev_proc_output_page(psw_output_page); @@ -55,32 +54,49 @@ private dev_proc_copy_mono(psw_copy_mono); private dev_proc_copy_color(psw_copy_color); private dev_proc_put_params(psw_put_params); private dev_proc_get_params(psw_get_params); +private dev_proc_fill_path(psw_fill_path); +private dev_proc_stroke_path(psw_stroke_path); private dev_proc_fill_mask(psw_fill_mask); private dev_proc_begin_image(psw_begin_image); -private dev_proc_image_data(psw_image_data); -private dev_proc_end_image(psw_end_image); #define X_DPI 720 #define Y_DPI 720 +typedef struct psw_path_state_s { + int num_points; /* # of points since last non-lineto */ + bool move; /* true iff last non-lineto was moveto */ + gs_point dprev[2]; /* line deltas before previous point, */ + /* if num_points - move >= 2 */ +} psw_path_state_t; + +typedef struct psw_image_params_s { + gx_bitmap_id id; + ushort width, height; +} psw_image_params_t; + typedef struct gx_device_pswrite_s { gx_device_psdf_common; /* Settable parameters */ #define LanguageLevel_default 2.0 +#define psdf_version_default psdf_version_level2 float LanguageLevel; /* End of parameters */ bool ProduceEPS; bool first_page; long bbox_position; - stream *image_stream; - byte *image_buf; -#define num_cached_images 137 - gx_bitmap_id image_cache[num_cached_images]; + psdf_binary_writer image_writer; +#define image_stream image_writer.strm +#define image_cache_size 197 +#define image_cache_reprobe_step 121 + psw_image_params_t image_cache[image_cache_size]; + bool cache_toggle; + /* Temporary state while writing a path */ + psw_path_state_t path_state; } gx_device_pswrite; -gs_private_st_suffix_add2_final(st_device_pswrite, gx_device_pswrite, +gs_private_st_suffix_add1_final(st_device_pswrite, gx_device_pswrite, "gx_device_pswrite", device_pswrite_enum_ptrs, device_pswrite_reloc_ptrs, - gx_device_finalize, st_device_psdf, image_stream, image_buf); + gx_device_finalize, st_device_psdf, image_stream); #define psw_procs\ { psw_open,\ @@ -107,53 +123,62 @@ gs_private_st_suffix_add2_final(st_device_pswrite, gx_device_pswrite, NULL, /* copy_alpha */\ NULL, /* get_band */\ NULL, /* copy_rop */\ - gdev_vector_fill_path,\ - gdev_vector_stroke_path,\ + psw_fill_path,\ + psw_stroke_path,\ psw_fill_mask,\ gdev_vector_fill_trapezoid,\ gdev_vector_fill_parallelogram,\ gdev_vector_fill_triangle,\ NULL /****** WRONG ******/, /* draw_thin_line */\ psw_begin_image,\ - psw_image_data,\ - psw_end_image,\ + NULL, /* image_data */\ + NULL, /* end_image */\ NULL, /* strip_tile_rectangle */\ NULL/******psw_strip_copy_rop******/\ } -gx_device_pswrite far_data gs_pswrite_device = +const gx_device_pswrite gs_pswrite_device = {std_device_dci_type_body(gx_device_pswrite, 0, "pswrite", &st_device_pswrite, DEFAULT_WIDTH_10THS * X_DPI / 10, DEFAULT_HEIGHT_10THS * Y_DPI / 10, X_DPI, Y_DPI, 3, 24, 255, 255, 256, 256), psw_procs, - psdf_initial_values(1 /*true */ ), /* (ASCII85EncodePages) */ + psdf_initial_values(psdf_version_default, 1 /*true */ ), /* (ASCII85EncodePages) */ LanguageLevel_default, /* LanguageLevel */ 0 /*false *//* ProduceEPS */ }; -gx_device_pswrite far_data gs_epswrite_device = +const gx_device_pswrite gs_epswrite_device = {std_device_dci_type_body(gx_device_pswrite, 0, "epswrite", &st_device_pswrite, DEFAULT_WIDTH_10THS * X_DPI / 10, DEFAULT_HEIGHT_10THS * Y_DPI / 10, X_DPI, Y_DPI, 3, 24, 255, 255, 256, 256), psw_procs, - psdf_initial_values(1 /*true */ ), /* (ASCII85EncodePages) */ + psdf_initial_values(psdf_version_default, 1 /*true */ ), /* (ASCII85EncodePages) */ LanguageLevel_default, /* LanguageLevel */ 1 /*true *//* ProduceEPS */ }; /* Vector device implementation */ -private int psw_beginpage(P1(gx_device_vector * vdev)); -private int psw_setcolors(P2(gx_device_vector * vdev, - const gx_drawing_color * pdc)); -private int psw_endpath(P2(gx_device_vector * vdev, gx_path_type_t type)); +private int + psw_beginpage(P1(gx_device_vector * vdev)), psw_setlinewidth(P2(gx_device_vector * vdev, floatp width)), + psw_setcolors(P2(gx_device_vector * vdev, const gx_drawing_color * pdc)), + psw_dorect(P6(gx_device_vector * vdev, fixed x0, fixed y0, fixed x1, fixed y1, + gx_path_type_t type)), psw_beginpath(P2(gx_device_vector * vdev, gx_path_type_t type)), + psw_moveto(P6(gx_device_vector * vdev, floatp x0, floatp y0, + floatp x, floatp y, gx_path_type_t type)), psw_lineto(P6(gx_device_vector * vdev, floatp x0, floatp y0, + floatp x, floatp y, gx_path_type_t type)), + psw_curveto(P10(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)), psw_closepath(P6(gx_device_vector * vdev, floatp x0, floatp y0, + floatp x_start, floatp y_start, gx_path_type_t type)), + psw_endpath(P2(gx_device_vector * vdev, gx_path_type_t type)); private const gx_device_vector_procs psw_vector_procs = { /* Page management */ psw_beginpage, /* Imager state */ - psdf_setlinewidth, + psw_setlinewidth, psdf_setlinecap, psdf_setlinejoin, psdf_setmiterlimit, @@ -165,31 +190,31 @@ private const gx_device_vector_procs psw_vector_procs = psw_setcolors, /* Paths */ psdf_dopath, - psdf_dorect, - psdf_beginpath, - psdf_moveto, - psdf_lineto, - psdf_curveto, - psdf_closepath, + psw_dorect, + psw_beginpath, + psw_moveto, + psw_lineto, + psw_curveto, + psw_closepath, psw_endpath }; /* ---------------- File header ---------------- */ -private const char *psw_ps_header[] = +private const char *const psw_ps_header[] = { "%!PS-Adobe-3.0", "%%Pages: (atend)", 0 }; -private const char *psw_eps_header[] = +private const char *const psw_eps_header[] = { "%!PS-Adobe-3.0 EPSF-3.0", 0 }; -private const char *psw_header[] = +private const char *const psw_header[] = { "%%EndComments", "%%BeginProlog", @@ -197,43 +222,53 @@ private const char *psw_header[] = 0 }; -private const char *psw_prolog[] = +private const char *const psw_prolog[] = { "%%BeginResource: procset GS_pswrite_ProcSet", "/GS_pswrite_ProcSet 40 dict dup begin", - "/!{bind def}bind def/X{load def}!", - "/rg/setrgbcolor X/g/setgray X/w/setlinewidth X/J/setlinecap X", - "/j/setlinejoin X/M/setmiterlimit X/d/setdash X/i/setflat X", - "/m/moveto X/l/lineto X/c/curveto X/h/closepath X", - "/lx{0 rlineto}!/ly{0 exch rlineto}!/v{currentpoint 6 2 roll c}!/y{2 copy c}!", + "/!{bind def}bind def/#{load def}!", + "/rG{3{3 -1 roll 255 div}repeat setrgbcolor}!/G{255 div setgray}!/K{0 G}!", + "/r6{dup 3 -1 roll rG}!/r5{dup 3 1 roll rG}!/r3{dup rG}!", + "/w/setlinewidth #/J/setlinecap #", + "/j/setlinejoin #/M/setmiterlimit #/d/setdash #/i/setflat #", + "/m/moveto #/l/lineto #/c/rcurveto #/h{p closepath}!/H{P closepath}!", + "/lx{0 rlineto}!/ly{0 exch rlineto}!/v{0 0 6 2 roll c}!/y{2 copy c}!", "/re{4 -2 roll m exch dup lx exch ly neg lx h}!", - "/q/gsave X/Q/grestore X/f/fill X/f*/eofill X/S/stroke X/rf{re f}!", - "/Y{initclip clip newpath}!/Y*{initclip eoclip newpath}!/rY{re Y}!", - "/@/currentfile X/|{string readstring pop}!", - /* <w> <h> <x> <y> <bps/inv> <src> Ix <w> <h> <bps/inv> <mtx> <src> */ - "/Ix{[1 0 0 1 9 -1 roll neg 9 -1 roll neg]exch}!", - "/It{true exch Ix imagemask}!/If{false exch Ix imagemask}!/I{exch Ix image}!", + "/^{3 index neg 3 index neg}!", + "/P{count 0 gt{count -2 roll moveto p}if}!", + "/p{count 2 idiv{count -2 roll rlineto}repeat}!", +"/f{P fill}!/f*{P eofill}!/S{P stroke}!/q/gsave #/Q/grestore #/rf{re fill}!", + "/Y{initclip P clip newpath}!/Y*{initclip P eoclip newpath}!/rY{re Y}!", + /* <w> <h> <name> <src> <length> | <w> <h> <data> */ + "/|{exch string readstring pop exch 4 1 roll 3 packedarray cvx exch 1 index def exec}!", + "/+{dup type/nametype eq{2 index 7 add -3 bitshift 2 index mul}if}!", + "/@/currentfile #/${+ @ |}!", + /* <x> <y> <w> <h> <bpc/inv> <src> Ix <w> <h> <bps/inv> <mtx> <src> */ + "/Ix{[1 0 0 1 11 -2 roll exch neg exch neg]exch}!", +"/,{true exch Ix imagemask}!/If{false exch Ix imagemask}!/I{exch Ix image}!", 0 }; -private const char *psw_1_prolog[] = +private const char *const psw_1_prolog[] = { 0 }; -private const char *psw_1_5_prolog[] = +private const char *const psw_1_5_prolog[] = { - "/Ic{Ix false 1 colorimage}!", + "/Ic{exch Ix false 3 colorimage}!", 0 }; -private const char *psw_2_prolog[] = +private const char *const psw_2_prolog[] = { - "/@85{@/ASCII85Decode filter}!", + "/F{<</Columns 4 2 roll/Rows exch/K -1/BlackIs1 true >>/CCITTFaxDecode filter}!", + "/X{/ASCII85Decode filter}!/@X{@ X}!/+F{2 index 2 index F}!/@F{@ +F}!/@C{@X +F}!", + "/$X{+ @X |}!/-F{4 index 4 index F}!/$F{+ @ -F |}!/$C{+ @X -F |}!", 0 }; -private const char *psw_end_prolog[] = +private const char *const psw_end_prolog[] = { "end def", "%%EndResource", @@ -242,7 +277,7 @@ private const char *psw_end_prolog[] = }; private void -psw_put_lines(stream * s, const char **lines) +psw_put_lines(stream * s, const char *const lines[]) { int i; @@ -258,89 +293,68 @@ image_cache_reset(gx_device_pswrite * pdev) { int i; - for (i = 0; i < num_cached_images; ++i) - pdev->image_cache[i] = gx_no_bitmap_id; + for (i = 0; i < image_cache_size; ++i) + pdev->image_cache[i].id = gx_no_bitmap_id; + pdev->cache_toggle = false; } -/* Look up or enter an image ID in the cache. */ +/* Look up or enter image parameters in the cache. */ +/* Return -1 if the key is not in the cache, or its index. */ /* If id is gx_no_bitmap_id or enter is false, do not enter it. */ -private bool -image_cache_lookup(gx_device_pswrite * pdev, gx_bitmap_id id, bool enter) +private int +image_cache_lookup(gx_device_pswrite * pdev, gx_bitmap_id id, + int width, int height, bool enter) { - int i; + int i1, i2; + psw_image_params_t *pip1; + psw_image_params_t *pip2; if (id == gx_no_bitmap_id) - return false; - i = id % num_cached_images; - if (pdev->image_cache[i] == id) - return true; - if (enter) - pdev->image_cache[i] = id; - return false; -} - -/* Set up to write a device-pixel image. */ -/* Return false if the image is empty. */ -private bool -psw_image_setup(gx_device_pswrite * pdev, int x, int y, int w, int h) -{ - stream *s = pdev->strm; + return -1; + i1 = id % image_cache_size; + pip1 = &pdev->image_cache[i1]; + if (pip1->id == id && pip1->width == width && pip1->height == height) { + return i1; + } + i2 = (i1 + image_cache_reprobe_step) % image_cache_size; + pip2 = &pdev->image_cache[i2]; + if (pip2->id == id && pip2->width == width && pip2->height == height) { + return i2; + } + if (enter) { + int i = ((pdev->cache_toggle = !pdev->cache_toggle) ? i2 : i1); + psw_image_params_t *pip = &pdev->image_cache[i]; - if (w <= 0 || h <= 0) - return false; - pprintd4(s, "%d %d %d %d ", w, h, x, y); - return true; + pip->id = id, pip->width = width, pip->height = height; + return i; + } + return -1; } /* Prepare the encoding stream for image data. */ /* Return 1 if we are using ASCII85 encoding. */ -private const stream_procs filter_write_procs = -{s_std_noavailable, s_std_noseek, s_std_write_reset, - s_std_write_flush, s_filter_close -}; private int psw_image_stream_setup(gx_device_pswrite * pdev) { - pdev->image_stream = gdev_vector_stream((gx_device_vector *) pdev); - if (pdev->LanguageLevel >= 2 && pdev->params.ASCII85EncodePages) { - gs_memory_t *mem = pdev->v_memory; - stream *prev_stream = pdev->image_stream; - uint buf_size = 200; /* arbitrary */ - byte *buf = pdev->image_buf = - gs_alloc_bytes(mem, buf_size, "psw_set_image_stream(buf)"); - stream *es = pdev->image_stream = - s_alloc(mem, "psw_set_image_stream(stream)"); - - if (es == 0 || buf == 0) { - return_error(gs_error_VMerror); - } - s_std_init(es, buf, buf_size, &filter_write_procs, s_mode_write); - es->template = &s_A85E_template; - es->procs.process = es->template->process; - es->strm = prev_stream; - return 1; - } - return 0; + int code = + psdf_begin_binary((gx_device_psdf *) pdev, &pdev->image_writer); + + return + (code < 0 ? code : + pdev->image_stream->state->template == &s_A85E_template ? 1 : 0); } /* Clean up after writing an image. */ private void psw_image_cleanup(gx_device_pswrite * pdev) { - gs_memory_t *mem = pdev->v_memory; - - if (pdev->image_stream != 0 && pdev->image_stream != pdev->strm) { - sclose(pdev->image_stream); - gs_free_object(mem, pdev->image_stream, "psw_image_cleanup(stream)"); + if (pdev->image_stream != 0) { + psdf_end_binary(&pdev->image_writer); pdev->image_stream = 0; } - if (pdev->image_buf) { - gs_free_object(mem, pdev->image_buf, "psw_image_cleanup(buf)"); - pdev->image_buf = 0; - } } -/* Write data for an image. */ +/* Write data for an image. Assumes width > 0, height > 0. */ /****** IGNORES data_x ******/ private void psw_put_bits(stream * s, const byte * data, int data_x_bit, uint raster, @@ -354,42 +368,63 @@ psw_put_bits(stream * s, const byte * data, int data_x_bit, uint raster, } private int psw_image_write(gx_device_pswrite * pdev, const char *imagestr, - const byte * data, int data_x_bit, uint raster, gx_bitmap_id id, - uint width_bits, int height) + const byte * data, int data_x, uint raster, gx_bitmap_id id, + int x, int y, int width, int height, int depth) { - stream *s = pdev->strm; - int code; - const char *source; - - if (image_cache_lookup(pdev, id, false)) { - pprintld1(s, "I%ld ", id); - pprints1(s, "%s\n", imagestr); + stream *s = gdev_vector_stream((gx_device_vector *) pdev); + uint width_bits = width * depth; + int data_x_bit = data_x * depth; + int index = image_cache_lookup(pdev, id, width_bits, height, false); + char str[40]; + int code, encode; + + if (index >= 0) { + sprintf(str, "%d%c", index / 26, index % 26 + 'A'); + pprintd2(s, "%d %d ", x, y); + pprints2(s, "%s %s\n", str, imagestr); return 0; } - code = psw_image_stream_setup(pdev); + pprintd4(s, "%d %d %d %d ", x, y, width, height); + encode = code = psw_image_stream_setup(pdev); if (code < 0) return code; - source = (code ? "@85" : "@"); - if (id == gx_no_bitmap_id || width_bits * (ulong) height > 8000 || - width_bits == 0 || height == 0 - ) { - pprints2(s, "%s %s\n", source, imagestr); + if (depth == 1 && width > 16) { + /* + * We should really look at the statistics of the image before + * committing to using G4 encoding.... + */ + code = psdf_CFE_binary(&pdev->image_writer, width, height, false); + if (code < 0) + return code; + encode += 2; + } + if (id == gx_no_bitmap_id || width_bits * (ulong) height > 8000) { + const char *const uncached[4] = + { + "@", "@X", "@F", "@C" + }; + + pprints2(s, "%s %s\n", uncached[encode], imagestr); psw_put_bits(pdev->image_stream, data, data_x_bit, raster, width_bits, height); psw_image_cleanup(pdev); spputc(s, '\n'); } else { - char str[40]; + const char *const cached[4] = + { + "$", "$X", "$F", "$C" + }; - image_cache_lookup(pdev, id, true); - sprintf(str, "/I%ld %s %ld |\n", - id, source, ((width_bits + 7) >> 3) * (ulong) height); + index = image_cache_lookup(pdev, id, width_bits, height, true); + sprintf(str, "/%d%c ", index / 26, index % 26 + 'A'); pputs(s, str); + if (depth != 1) + pprintld1(s, "%ld ", ((width_bits + 7) >> 3) * (ulong) height); + pprints1(s, "%s\n", cached[encode]); psw_put_bits(pdev->image_stream, data, data_x_bit, raster, width_bits, height); psw_image_cleanup(pdev); - pprintld1(s, "\ndef I%ld ", id); - pprints1(s, "%s\n", imagestr); + pprints1(s, "\n%s\n", imagestr); } return 0; } @@ -420,7 +455,7 @@ psw_beginpage(gx_device_vector * vdev) pputs(s, "%%BoundingBox: (atend)\n"); } else { /* File is seekable, leave room to rewrite bbox. */ pdev->bbox_position = stell(s); - pputs(s, "................................................................\n"); + pputs(s, "%...............................................................\n"); } pprints1(s, "%%%%Creator: %s ", gs_product); pprintld1(s, "%ld ", (long)gs_revision); @@ -456,17 +491,171 @@ psw_beginpage(gx_device_vector * vdev) psw_put_lines(s, psw_end_prolog); } pprintld2(s, "%%%%Page: %ld %ld\n%%%%BeginPageSetup\n", page, page); - pprintg2(s, "save GS_pswrite_ProcSet begin %g %g scale\n%%%%EndPageSetup\n", + pprintg2(s, "/pagesave save def GS_pswrite_ProcSet begin %g %g scale\n%%%%EndPageSetup\n", 72.0 / vdev->HWResolution[0], 72.0 / vdev->HWResolution[1]); return 0; } private int +psw_setlinewidth(gx_device_vector * vdev, floatp width) +{ /* + * The vector scale is 1, but we have to rescale the line width + * (which is given in device pixels) to account for the actual + * page scaling in effect. + */ + return psdf_setlinewidth(vdev, width * 72.0 / vdev->HWResolution[1]); +} + +private int psw_setcolors(gx_device_vector * vdev, const gx_drawing_color * pdc) -{ /* PostScript only keeps track of a single color. */ +{ + if (!gx_dc_is_pure(pdc)) + return_error(gs_error_rangecheck); + /* PostScript only keeps track of a single color. */ vdev->fill_color = *pdc; vdev->stroke_color = *pdc; - return psdf_setfillcolor(vdev, pdc); + { + stream *s = gdev_vector_stream(vdev); + gx_color_index color = gx_dc_pure_color(pdc); + int r = color >> 16; + int g = (color >> 8) & 0xff; + int b = color & 0xff; + + if (r == g && g == b) { + if (r == 0) + pputs(s, "K\n"); + else + pprintd1(s, "%d G\n", r); + } else if (r == g) + pprintd2(s, "%d %d r6\n", b, r); + else if (g == b) + pprintd2(s, "%d %d r3\n", r, g); + else if (r == b) + pprintd2(s, "%d %d r5\n", g, b); + else + pprintd3(s, "%d %d %d rG\n", r, g, b); + } + return 0; +} + +/* Redefine dorect to recognize rectangle fills. */ +private int +psw_dorect(gx_device_vector * vdev, fixed x0, fixed y0, fixed x1, fixed y1, + gx_path_type_t type) +{ + if ((type & ~gx_path_type_rule) != gx_path_type_fill) + return psdf_dorect(vdev, x0, y0, x1, y1, type); + pprintg4(gdev_vector_stream(vdev), "%g %g %g %g rf\n", + fixed2float(x0), fixed2float(y0), + fixed2float(x1 - x0), fixed2float(y1 - y0)); + return 0; +} + +/* + * We redefine path tracing to use a compact form for polygons; also, + * we only need to write coordinates with 2 decimals of precision, + * since this is 10 times more precise than any existing output device. + */ +#define round_coord(v) (floor((v) * 100 + 0.5) / 100.0) +private void +print_coord2(stream * s, floatp x, floatp y, const char *str) +{ + pprintg2(s, "%g %g ", round_coord(x), round_coord(y)); + if (str != 0) + pputs(s, str); +} +#undef round_coord + +private int +psw_beginpath(gx_device_vector * vdev, gx_path_type_t type) +{ + pdev->path_state.num_points = 0; + pdev->path_state.move = false; + return 0; +} + +private int +psw_moveto(gx_device_vector * vdev, floatp x0, floatp y0, floatp x, floatp y, + gx_path_type_t type) +{ + stream *s = gdev_vector_stream(vdev); + + if (pdev->path_state.num_points > 1) + pputs(s, (pdev->path_state.move ? "P\n" : "p\n")); + print_coord2(s, x, y, NULL); + pdev->path_state.num_points = 1; + pdev->path_state.move = true; + return 0; +} + +private int +psw_lineto(gx_device_vector * vdev, floatp x0, floatp y0, floatp x, floatp y, + gx_path_type_t type) +{ + double dx = x - x0, dy = y - y0; + + /* + * Omit null lines when filling. + ****** MAYBE WRONG IF PATH CONSISTS ONLY OF NULL LINES. ****** + */ + if (dx != 0 || dy != 0) { + stream *s = gdev_vector_stream(vdev); + + if (pdev->path_state.num_points - pdev->path_state.move >= 2 && + dx == -pdev->path_state.dprev[1].x && + dy == -pdev->path_state.dprev[1].y + ) + pputs(s, "^ "); + else + print_coord2(s, dx, dy, NULL); + pdev->path_state.num_points++; + pdev->path_state.dprev[1] = pdev->path_state.dprev[0]; + pdev->path_state.dprev[0].x = dx; + pdev->path_state.dprev[0].y = dy; + } + return 0; +} + +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) +{ + stream *s = gdev_vector_stream(vdev); + double dx1 = x1 - x0, dy1 = y1 - y0; + double dx2 = x2 - x0, dy2 = y2 - y0; + double dx3 = x3 - x0, dy3 = y3 - y0; + + if (pdev->path_state.num_points > 0) + pputs(s, (pdev->path_state.move ? + (pdev->path_state.num_points == 1 ? "m\n" : "P\n") : + "p\n")); + if (dx1 == 0 && dy1 == 0) { + print_coord2(s, dx2, dy2, NULL); + print_coord2(s, dx3, dy3, "v\n"); + } else if (x3 == x2 && y3 == y2) { + print_coord2(s, dx1, dy1, NULL); + print_coord2(s, dx2, dy2, "y\n"); + } else { + print_coord2(s, dx1, dy1, NULL); + print_coord2(s, dx2, dy2, NULL); + print_coord2(s, dx3, dy3, "c\n"); + } + pdev->path_state.num_points = 0; + pdev->path_state.move = false; + return 0; +} + +private int +psw_closepath(gx_device_vector * vdev, floatp x0, floatp y0, + floatp x_start, floatp y_start, gx_path_type_t type) +{ + pputs(gdev_vector_stream(vdev), + (pdev->path_state.num_points > 0 && pdev->path_state.move ? + "H\n" : "h\n")); + pdev->path_state.num_points = 0; + pdev->path_state.move = false; + return 0; } private int @@ -475,6 +664,8 @@ psw_endpath(gx_device_vector * vdev, gx_path_type_t type) stream *s = vdev->strm; const char *star = (type & gx_path_type_even_odd ? "*" : ""); + if (pdev->path_state.num_points > 1 && !pdev->path_state.move) + pputs(s, "p "); if (type & gx_path_type_fill) { if (type & (gx_path_type_stroke | gx_path_type_clip)) pprints1(s, "q f%s Q ", star); @@ -516,6 +707,7 @@ psw_open(gx_device * dev) } gdev_vector_init(vdev); pdev->first_page = true; + pdev->binary_ok = !pdev->params.ASCII85EncodePages; image_cache_reset(pdev); return 0; } @@ -528,7 +720,7 @@ psw_output_page(gx_device * dev, int num_copies, int flush) if (num_copies != 1) pprintd1(s, "userdict /#copies %d put\n", num_copies); - pprints1(s, "end %s restore\n%%%%PageTrailer\n", + pprints1(s, "end %s pagesave restore\n%%%%PageTrailer\n", (flush ? "showpage" : "copypage")); sflush(s); vdev->in_page = false; @@ -594,6 +786,7 @@ psw_put_params(gx_device * dev, gs_param_list * plist) int code; gs_param_name param_name; float ll = pdev->LanguageLevel; + psdf_version save_version = pdev->version; switch (code = param_read_float(plist, (param_name = "LanguageLevel"), &ll)) { case 0: @@ -609,10 +802,25 @@ psw_put_params(gx_device * dev, gs_param_list * plist) if (ecode < 0) return ecode; + /* + * We have to set version to the new value, because the set of + * legal parameter values for psdf_put_params varies according to + * the version. + */ + { + static const psdf_version vv[3] = + { + psdf_version_level1, psdf_version_level1_color, + psdf_version_level2 + }; + + pdev->version = vv[(int)(ll * 2) - 2]; + } code = gdev_psdf_put_params(dev, plist); - if (code < 0) + if (code < 0) { + pdev->version = save_version; return code; - + } pdev->LanguageLevel = ll; return code; } @@ -629,6 +837,8 @@ psw_copy_mono(gx_device * dev, const byte * data, const char *op; int code = 0; + if (w <= 0 || h <= 0) + return 0; (*dev_proc(vdev->bbox_device, copy_mono)) ((gx_device *) vdev->bbox_device, data, data_x, raster, id, x, y, w, h, zero, one); @@ -648,13 +858,12 @@ psw_copy_mono(gx_device * dev, const byte * data, color_set_pure(&color, one); code = gdev_vector_update_fill_color((gx_device_vector *) pdev, &color); - op = "It"; + op = ","; } if (code < 0) return 0; - return (psw_image_setup(pdev, x, y, w, h) ? - psw_image_write(pdev, op, data, data_x, raster, id, - w, h) : 0); + return psw_image_write(pdev, op, data, data_x, raster, id, + x, y, w, h, 1); } /* Copy a color bitmap. */ @@ -664,15 +873,49 @@ psw_copy_color(gx_device * dev, int x, int y, int w, int h) { int depth = dev->color_info.depth; + const byte *bits = data + data_x * 3; + char op[6]; + if (w <= 0 || h <= 0) + return 0; (*dev_proc(vdev->bbox_device, copy_color)) ((gx_device *) vdev->bbox_device, data, data_x, raster, id, x, y, w, h); - if (!psw_image_setup(pdev, x, y, w, h)) + /* + * If this is a 1-pixel-high image, check for it being all the + * same color, and if so, fill it as a rectangle. + */ + if (h == 1 && !memcmp(bits, bits + 3, (w - 1) * 3)) { + return (*dev_proc(dev, fill_rectangle)) + (dev, x, y, w, h, (bits[0] << 16) + (bits[1] << 8) + bits[2]); + } + sprintf(op, "%d Ic", depth / 3); /* RGB */ + return psw_image_write(pdev, op, data, data_x, raster, id, + x, y, w, h, depth); +} + +/* Fill or stroke a path. */ +/* We redefine these to skip empty paths. */ +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) +{ + if (gx_path_is_void(ppath)) + return 0; + return gdev_vector_fill_path(dev, pis, ppath, params, pdevc, pcpath); +} +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 * pdevc, const gx_clip_path * pcpath) +{ + if (gx_path_is_void(ppath) && + (gx_path_is_null(ppath) || + gs_currentlinecap((const gs_state *)pis) != gs_cap_round) + ) return 0; - pprintd1(pdev->strm, " %d", depth); - return psw_image_write(pdev, "Ic", data, data_x * depth, - raster, id, w * depth, h); + return gdev_vector_stroke_path(dev, pis, ppath, params, pdevc, pcpath); } /* Fill a mask. */ @@ -683,6 +926,8 @@ psw_fill_mask(gx_device * dev, const gx_drawing_color * pdcolor, int depth, gs_logical_operation_t lop, const gx_clip_path * pcpath) { + if (w <= 0 || h <= 0) + return 0; if (depth > 1 || gdev_vector_update_fill_color(vdev, pdcolor) < 0 || gdev_vector_update_clip_path(vdev, pcpath) < 0 || @@ -693,20 +938,26 @@ psw_fill_mask(gx_device * dev, (*dev_proc(vdev->bbox_device, fill_mask)) ((gx_device *) vdev->bbox_device, data, data_x, raster, id, x, y, w, h, pdcolor, depth, lop, pcpath); - return (psw_image_setup(pdev, x, y, w, h) ? - psw_image_write(pdev, "It", - data, data_x, raster, id, w, h) : 0); + return psw_image_write(pdev, ",", data, data_x, raster, id, + x, y, w, h, 1); } /* ---------------- High-level images ---------------- */ +private image_enum_proc_plane_data(psw_image_plane_data); +private image_enum_proc_end_image(psw_image_end_image); +private const gx_image_enum_procs_t psw_image_enum_procs = +{ + psw_image_plane_data, psw_image_end_image +}; + /* Start processing an image. */ 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, void **pinfo) + gs_memory_t * mem, gx_image_enum_common_t ** pinfo) { gdev_vector_image_enum_t *pie = gs_alloc_struct(mem, gdev_vector_image_enum_t, @@ -720,7 +971,7 @@ psw_begin_image(gx_device * dev, if (pie == 0) return_error(gs_error_VMerror); pie->memory = mem; - *pinfo = pie; + *pinfo = (gx_image_enum_common_t *) pie; if (!pim->ImageMask) { index = gs_color_space_get_index(pcs); num_components = gs_color_space_num_components(pcs); @@ -749,7 +1000,7 @@ psw_begin_image(gx_device * dev, } if (!can_do || gdev_vector_begin_image(vdev, pis, pim, format, prect, pdcolor, - pcpath, mem, pie) < 0 || + pcpath, mem, &psw_image_enum_procs, pie) < 0 || (code = psw_image_stream_setup(pdev)) < 0 ) return gx_default_begin_image(dev, pis, pim, format, prect, @@ -758,7 +1009,7 @@ psw_begin_image(gx_device * dev, /* Write the image/colorimage/imagemask preamble. */ { stream *s = gdev_vector_stream((gx_device_vector *) pdev); - const char *source = (code ? "@85" : "@"); + const char *source = (code ? "@X" : "@"); gs_matrix imat; pputs(s, "q"); @@ -793,37 +1044,38 @@ psw_begin_image(gx_device * dev, /* Process the next piece of an image. */ private int -psw_image_data(gx_device * dev, - void *info, const byte ** planes, int data_x, uint raster, int height) +psw_image_plane_data(gx_device * dev, + gx_image_enum_common_t * info, const gx_image_plane_t * planes, int height) { - gdev_vector_image_enum_t *pie = info; + gdev_vector_image_enum_t *pie = (gdev_vector_image_enum_t *) info; if (pie->default_info) - return gx_default_image_data(dev, pie->default_info, planes, - data_x, raster, height); - (*dev_proc(vdev->bbox_device, image_data)) - ((gx_device *) vdev->bbox_device, pie->bbox_info, - planes, data_x, raster, height); + return gx_device_image_plane_data(dev, pie->default_info, planes, + height); + gx_device_image_plane_data((gx_device *) vdev->bbox_device, + pie->bbox_info, planes, height); { - int plane; - - for (plane = 0; plane < pie->num_planes; ++plane) - psw_put_bits(pdev->image_stream, planes[plane], - data_x * pie->bits_per_pixel, raster, - pie->bits_per_row, height); + int pi; + + for (pi = 0; pi < pie->num_planes; ++pi) + psw_put_bits(pdev->image_stream, planes[pi].data, + planes[pi].data_x * info->plane_depths[pi], + planes[pi].raster, + pie->width * info->plane_depths[pi], + height); } return (pie->y += height) >= pie->height; } /* Clean up by releasing the buffers. */ private int -psw_end_image(gx_device * dev, void *info, bool draw_last) +psw_image_end_image(gx_device * dev, gx_image_enum_common_t * info, + bool draw_last) { - gdev_vector_image_enum_t *pie = info; + gdev_vector_image_enum_t *pie = (gdev_vector_image_enum_t *) info; int code; - code = gdev_vector_end_image(vdev, (gdev_vector_image_enum_t *) pie, - draw_last, pdev->white); + code = gdev_vector_end_image(vdev, pie, draw_last, pdev->white); if (code > 0) { psw_image_cleanup(pdev); pputs(pdev->strm, "\nQ\n"); |