diff options
Diffstat (limited to 'contrib/lips4/gdevl4v.c')
-rw-r--r-- | contrib/lips4/gdevl4v.c | 2481 |
1 files changed, 2481 insertions, 0 deletions
diff --git a/contrib/lips4/gdevl4v.c b/contrib/lips4/gdevl4v.c new file mode 100644 index 00000000..eb4f31a1 --- /dev/null +++ b/contrib/lips4/gdevl4v.c @@ -0,0 +1,2481 @@ +/* Copyright (C) 1998, 1999 Norihito Ohmori. + + Ghostscript printer driver + for Canon LBP (LIPS IV) + + This software is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY. No author or distributor accepts responsibility + to anyone for the consequences of using it or for whether it serves any + particular purpose or works at all, unless he says so in writing. Refer + to the GNU General Public License for full details. + + Everyone is granted permission to copy, modify and redistribute + this software, but only under the conditions described in the GNU + General Public License. A copy of this license is supposed to have been + given to you along with this software so you can know your rights and + responsibilities. It should be in a file named COPYING. Among other + things, the copyright notice and this notice must be preserved on all + copies. + */ + +/*$Id: gdevl4v.c $ */ +/* Vector Version of LIPS driver */ + +/* + + Vector driver は Ghostscript 5.0 から新たに加わったドライバです。 + よって仕様が安定していません。Ghostscript 5.10 と Ghostscript 5.50 では + Hi-level bitmap imaging の仕様が変わっています。 + Ghostscript 6.0 では更に text_begin という API が追加されるようです。 + + ○Ghostscript 5.10/5.50 のバグについて + + Ghostscript 5.10/5.50 の Vector driver の setlinewidth 関数には + バグがあります。本来スケールが変更されるにしたがって線の太さも変更され + なければなりませんが、Ghostscript 5.10/5.50 ではスケールを考慮するのを + 忘れています。(バグ報告を2回ほど送ったのだけれど...) + このドライバはそのバグを回避するためにスケールを自分で処理しています。 + + Ghostscript 5.10 の生成するパスは Ghostscript 5.50 が生成するパスよりも + 非常に効率の悪いものになることがあります。LIPS IV の処理できる限界を超える + こともありました。効率の悪いパスは速度の低下にもつながるので Ghostscript + 5.50 を使った方がこのドライバでは出力速度が速くなります。 + + また Ghostscript 5.10 では + fill_trapezoid、fill_parallelogram、fill_triangle + の関数の挙動が変になることがあったのでこれらは使っていません。 + + ○ LIPS IV のバグについて + + このドライバは開発中に発見した次の LIPS IV のバグを回避しています。 + 1. 1 dot のイメージを変形したときに座標の計算が狂う + 2. 小さなイメージを描画すると正常に描かれない + 3. クリッピング命令とパス・クリッピング命令がそれぞれ独立に働いてしまう。 + + 1. は 1 dot のイメージを矩形にして回避しました。 + 2. はイメージ領域確保命令で分割を指定することにより回避しました。 + 3. はクリッピング命令を使わないことにして回避しました。 + + ○ LIPS IV の仕様について + + 1. 単色イメージ・カラー指定命令はグレースケールイメージに対しても + 働いてしまいます。 + 2. LIPS IV ではグレースケールの色表現が PostScript と逆です。 + 3. LIPS IV にはイメージのビットを反転させるコマンドはありません。 + 4. LIPS IV には CMYK のカラースペースはありません。 + + */ + +#include "string.h" +#include "math_.h" +#include "gx.h" +#include "gserrors.h" +#include "gsmatrix.h" +#include "gsparam.h" +#include "gxdevice.h" +#include "gscspace.h" +#include "gsutil.h" +#include "gdevvec.h" +#if 0 +#include "gdevpstr.h" +#else +#include "spprint.h" +#endif + +#include "gzstate.h" + +#include "gdevlips.h" + +/* ---------------- Device definition ---------------- */ + +/* Device procedures */ +static dev_proc_open_device(lips4v_open); +static dev_proc_output_page(lips4v_output_page); +static dev_proc_close_device(lips4v_close); +static dev_proc_copy_mono(lips4v_copy_mono); +static dev_proc_copy_color(lips4v_copy_color); +static dev_proc_put_params(lips4v_put_params); +static dev_proc_get_params(lips4v_get_params); +static dev_proc_fill_mask(lips4v_fill_mask); +static dev_proc_begin_image(lips4v_begin_image); + +#define X_DPI 600 +#define Y_DPI 600 + +typedef struct gx_device_lips4v_s +{ + gx_device_vector_common; + lips_params_common; + lips4_params_common; + bool first_page; + bool ManualFeed; + bool Duplex; + int Duplex_set; + bool Tumble; + bool OneBitMask; /* for LIPS Bug */ + int ncomp; + int MaskReverse; + int MaskState; + bool TextMode; + int prev_x; + int prev_y; + gx_color_index prev_color; + gx_color_index current_color; + int linecap; + /* for Font Downloading */ +#define max_cached_chars 256 /* 128 * n */ + bool FontDL; + int current_font; + int count; + gx_bitmap_id id_table[max_cached_chars + 1]; + gx_bitmap_id id_cache[max_cached_chars + 1]; +} +gx_device_lips4v; + +gs_public_st_suffix_add0_final(st_device_lips4v, gx_device_lips4v, + "gx_device_lips4v", device_lips4v_enum_ptrs, + device_lips4v_reloc_ptrs, gx_device_finalize, + st_device_vector); + +#define lips_device_full_body(dtype, pprocs, dname, stype, w, h, xdpi, ydpi, ncomp, depth, mg, mc, dg, dc, lm, bm, rm, tm)\ + std_device_part1_(dtype, pprocs, dname, stype, open_init_closed),\ + dci_values(ncomp, depth, mg, mc, dg, dc),\ + std_device_part2_(w, h, xdpi, ydpi),\ + offset_margin_values(-lm * xdpi, -tm * ydpi, lm * 72.0, bm * 72.0, rm * 72.0, tm * 72.0),\ + std_device_part3_() + +#define lips4v_device_body\ + lips_device_full_body(gx_device_lips4v, 0, "lips4v",\ + &st_device_lips4v,\ + DEFAULT_WIDTH_10THS * X_DPI / 10,\ + DEFAULT_HEIGHT_10THS * Y_DPI / 10,\ + X_DPI, Y_DPI,\ + 1, 8, 1000, 1000, 5, 2,\ + LIPS4_LEFT_MARGIN_DEFAULT,\ + LIPS4_BOTTOM_MARGIN_DEFAULT,\ + LIPS4_RIGHT_MARGIN_DEFAULT,\ + LIPS4_TOP_MARGIN_DEFAULT) + +#define lips4v_procs\ + { lips4v_open,\ + gx_upright_get_initial_matrix,\ + NULL, /* sync_output */\ + lips4v_output_page,\ + lips4v_close,\ + gx_default_gray_map_rgb_color,\ + gx_default_gray_map_color_rgb,\ + gdev_vector_fill_rectangle,\ + NULL, /* tile_rectangle */\ + lips4v_copy_mono,\ + lips4v_copy_color,\ + NULL, /* draw_line */\ + NULL, /* get_bits */\ + lips4v_get_params,\ + lips4v_put_params,\ + NULL, /* map_cmyk_color */\ + NULL, /* get_xfont_procs */\ + NULL, /* get_xfont_device */\ + NULL, /* map_rgb_alpha_color */\ + gx_page_device_get_page_device,\ + NULL, /* get_alpha_bits */\ + NULL, /* copy_alpha */\ + NULL, /* get_band */\ + NULL, /* copy_rop */\ + gdev_vector_fill_path,\ + gdev_vector_stroke_path,\ + lips4v_fill_mask,\ + gdev_vector_fill_trapezoid,\ + gdev_vector_fill_parallelogram,\ + gdev_vector_fill_triangle,\ + NULL /****** WRONG ******/, /* draw_thin_line */\ + lips4v_begin_image,\ + NULL,\ + NULL,\ + NULL, /* strip_tile_rectangle */\ + NULL/******strip_copy_rop******/\ + } + +gx_device_lips4v far_data gs_lips4v_device = { + lips4v_device_body, + lips4v_procs, + vector_initial_values, + LIPS_CASSETFEED_DEFAULT, + LIPS_USERNAME_DEFAULT, + FALSE /* PJL */ , + 0 /* toner_density */ , + FALSE /* toner_saving */ , + 0 /* toner_saving_set */ , + 0, 0, 0, 0, -1, + 0 /* prev_duplex_mode */ , + LIPS_NUP_DEFAULT, + LIPS_FACEUP_DEFAULT, + LIPS_MEDIATYPE_DEFAULT, + 0 /* first_page */ , + LIPS_MANUALFEED_DEFAULT, + 0 /* Duplex */ , 0 /* Duplex_set */ , LIPS_TUMBLE_DEFAULT, + 0 /* OneBitMask */ , + 0 /* ncomp */ , -1 /* MaskReverse */ , 0 /* MaskState */ , + 0 /* TextMode */ , 0 /* prev_x */ , 0 /* prev_y */ , + 0 /* prev_color */ , 0 /* current_color */ , + 0 /* linecap */ , + 0 /* FontDL */ , + -1 /* current_font */ , + 0 /* count */ , + {0}, + {0} +}; + +/* Vector device implementation */ +#if GS_VERSION_MAJOR >= 8 +static int lips4v_beginpage(gx_device_vector * vdev); +static int lips4v_setfillcolor(gx_device_vector * vdev, const gs_gstate * pgs, + const gx_drawing_color * pdc); +static int lips4v_setstrokecolor(gx_device_vector * vdev, const gs_gstate * pgs, + const gx_drawing_color * pdc); +static int lips4v_setdash(gx_device_vector * vdev, const float *pattern, + uint count, double offset); +static int lips4v_setflat(gx_device_vector * vdev, double flatness); +static int +lips4v_setlogop(gx_device_vector * vdev, gs_logical_operation_t lop, + gs_logical_operation_t diff); +static int lips4v_can_handle_hl_color(gx_device_vector * vdev, const gs_gstate * pgs, + const gx_drawing_color * pdc); +static int + +lips4v_beginpath(gx_device_vector * vdev, gx_path_type_t type); +static int +lips4v_moveto(gx_device_vector * vdev, double x0, double y0, double x, + double y, gx_path_type_t type); +static int +lips4v_lineto(gx_device_vector * vdev, double x0, double y0, double x, + double y, gx_path_type_t type); +static int +lips4v_curveto(gx_device_vector * vdev, double x0, double y0, double x1, + double y1, double x2, double y2, double x3, double y3, + gx_path_type_t type); +static int +lips4v_closepath(gx_device_vector * vdev, double x, double y, double x_start, + double y_start, gx_path_type_t type); + +static int lips4v_endpath(gx_device_vector * vdev, gx_path_type_t type); +#else +static int lips4v_beginpage(P1(gx_device_vector * vdev)); +static int lips4v_setfillcolor(P2(gx_device_vector * vdev, + const gx_drawing_color * pdc)); +static int lips4v_setstrokecolor(P2(gx_device_vector * vdev, + const gx_drawing_color * pdc)); +static int lips4v_setdash(P4(gx_device_vector * vdev, const float *pattern, + uint count, double offset)); +static int lips4v_setflat(P2(gx_device_vector * vdev, double flatness)); +static int +lips4v_setlogop(P3 + + (gx_device_vector * vdev, gs_logical_operation_t lop, + gs_logical_operation_t diff)); +static int + +lips4v_beginpath(P2(gx_device_vector * vdev, gx_path_type_t type)); +static int +lips4v_moveto(P6 + (gx_device_vector * vdev, double x0, double y0, double x, + double y, gx_path_type_t type)); +static int +lips4v_lineto(P6 + (gx_device_vector * vdev, double x0, double y0, double x, + double y, gx_path_type_t type)); +static int +lips4v_curveto(P10 + (gx_device_vector * vdev, double x0, double y0, double x1, + double y1, double x2, double y2, double x3, double y3, + gx_path_type_t type)); +static int +lips4v_closepath(P6 + (gx_device_vector * vdev, double x, double y, double x_start, + double y_start, gx_path_type_t type)); + +static int lips4v_endpath(P2(gx_device_vector * vdev, gx_path_type_t type)); +#endif +static int lips4v_setlinewidth(gx_device_vector * vdev, double width); +static int lips4v_setlinecap(gx_device_vector * vdev, gs_line_cap cap); +static int lips4v_setlinejoin(gx_device_vector * vdev, gs_line_join join); +static int lips4v_setmiterlimit(gx_device_vector * vdev, double limit); +static const gx_device_vector_procs lips4v_vector_procs = { + /* Page management */ + lips4v_beginpage, + /* Imager state */ + lips4v_setlinewidth, + lips4v_setlinecap, + lips4v_setlinejoin, + lips4v_setmiterlimit, + lips4v_setdash, + lips4v_setflat, + lips4v_setlogop, + /* Other state */ +#if GS_VERSION_MAJOR >= 8 + lips4v_can_handle_hl_color, /* can_handle_hl_color (dummy) */ +#endif + lips4v_setfillcolor, /* fill & stroke colors are the same */ + lips4v_setstrokecolor, + /* Paths */ + gdev_vector_dopath, + gdev_vector_dorect, + lips4v_beginpath, + lips4v_moveto, + lips4v_lineto, + lips4v_curveto, + lips4v_closepath, + lips4v_endpath +}; + +/* ---------------- File header ---------------- */ + +static const char *l4v_file_header1 = + + "\033%-12345X@PJL CJLMODE\n@PJL JOB\n\033%-12345X@PJL CJLMODE\n"; +static const char *l4v_file_header2 = "@PJL SET LPARM : LIPS SW2 = ON\n"; +static const char *l4v_file_header3 = "@PJL ENTER LANGUAGE = LIPS\n"; +static const char *l4v_file_header4 = "\033%@\033P41;"; + +static const char *l4vmono_file_header = + + ";1J" L4VMONO_STRING LIPS_VERSION "\033\\\033[0\"p\033<"; + +static const char *l4vcolor_file_header = + + ";1J" L4VCOLOR_STRING LIPS_VERSION "\033\\\033[1\"p\033<"; + +/* ---------------- Utilities ---------------- */ + +static void +lips_param(int param, char *c) +{ + int i, j; + bool bSign; + + bSign = TRUE; + if (param < 0) { + bSign = FALSE; + param = -param; + } + if (param < 16) + i = 1; + else if (param < 1024) + i = 2; + else if (param < 65536) + i = 3; + else + i = 4; + + c[i] = '\0'; + c[i - 1] = (param & 0x0f) | 0x20 | (bSign ? 0x10 : 0x00); + param >>= 4; + for (j = i - 2; j >= 0; j--) { + c[j] = (param & 0x3f) | 0x40; + param >>= 6; + } +} + +static void +sput_lips_int(stream * s, int param) +{ + int i; + char c[5]; + + lips_param(param, c); + for (i = 0; i < strlen(c); i++) + sputc(s, c[i]); +} + +/* Put a string on a stream. + This function is copy of `pputs' in gdevpstr.c */ +static int +lputs(stream * s, const char *str) +{ + uint len = strlen(str); + uint used; + int status = sputs(s, (const byte *)str, len, &used); + + return (status >= 0 && used == len ? 0 : EOF); +} + +/* Write a string on a stream. */ +static void +put_bytes(stream * s, const byte * data, uint count) +{ + uint used; + + sputs(s, data, count, &used); +} + +/* for Font Downloading */ +static void +put_int(stream * s, uint number) +{ + sputc(s, number >> 8); + sputc(s, number & 0xff); +} + +static int +lips4v_range_check(gx_device * dev) +{ + int width = dev->MediaSize[0]; + int height = dev->MediaSize[1]; + int xdpi = dev->x_pixels_per_inch; + int ydpi = dev->y_pixels_per_inch; + + /* Paper Size Check */ + if (width <= height) { /* portrait */ + if ((width < LIPS_WIDTH_MIN || width > LIPS_WIDTH_MAX || + height < LIPS_HEIGHT_MIN || height > LIPS_HEIGHT_MAX) && + !(width == LIPS_LEDGER_WIDTH && height == LIPS_LEDGER_HEIGHT)) + return_error(gs_error_rangecheck); + } else { /* landscape */ + if ((width < LIPS_HEIGHT_MIN || width > LIPS_HEIGHT_MAX || + height < LIPS_WIDTH_MIN || height > LIPS_WIDTH_MAX) && + !(width == LIPS_LEDGER_HEIGHT && height == LIPS_LEDGER_WIDTH)) + return_error(gs_error_rangecheck); + } + + /* Resolution Check */ + if (xdpi != ydpi) + return_error(gs_error_rangecheck); + else { + if ((xdpi < LIPS_DPI_MIN || xdpi > LIPS4_DPI_MAX) + && xdpi != LIPS4_DPI_SUPERFINE) return_error(gs_error_rangecheck); + } + + return 0; +} + +static void +lips4v_set_cap(gx_device * dev, int x, int y) +{ + + char cap[15]; + stream *s = gdev_vector_stream((gx_device_vector *) dev); + gx_device_lips4v *const pdev = (gx_device_lips4v *) dev; + int dx = x - pdev->prev_x; + int dy = y - pdev->prev_y; + + if (dx > 0) { + gs_sprintf(cap, "%c%da", LIPS_CSI, dx); + lputs(s, cap); + } else if (dx < 0) { + gs_sprintf(cap, "%c%dj", LIPS_CSI, -dx); + lputs(s, cap); + } + if (dy > 0) { + gs_sprintf(cap, "%c%dk", LIPS_CSI, dy); + lputs(s, cap); + } else if (dy < 0) { + gs_sprintf(cap, "%c%de", LIPS_CSI, -dy); + lputs(s, cap); + } + pdev->prev_x = x; + pdev->prev_y = y; +} + +#define POINT 18 + +/* Font Downloading Routine */ +static int +lips4v_copy_text_char(gx_device * dev, const byte * data, + int raster, gx_bitmap_id id, int x, int y, int w, int h) +{ + gx_device_lips4v *const pdev = (gx_device_lips4v *) dev; + stream *s = gdev_vector_stream((gx_device_vector *) dev); + uint width_bytes = (w + 7) >> 3; + uint size = width_bytes * h; + int i, j; + uint ccode = 0; + char cset_sub[9], cset[64], cset_number[8], text_color[15]; + int cell_length = (POINT * (int)dev->x_pixels_per_inch) / 72; + bool download = TRUE; + + if (w > cell_length || h > cell_length || !pdev->FontDL) + return -1; + + for (j = pdev->count - 1; j >= 0; j--) { + if (pdev->id_table[j] == id) + /* font is found */ + { + download = FALSE; + ccode = j; + for (i = j; i < pdev->count - 1; i++) { + pdev->id_cache[i] = pdev->id_cache[i + 1]; + } + pdev->id_cache[pdev->count - 1] = id; + break; + } + } + + if (download) { + if (pdev->count > max_cached_chars - 1) { + gx_bitmap_id tmpid = pdev->id_cache[0]; + + for (j = pdev->count - 1; j >= 0; j--) { + if (pdev->id_table[j] == tmpid) { + ccode = j; + break; + } + } + for (i = j; i < pdev->count - 1; i++) { + pdev->id_cache[i] = pdev->id_cache[i + 1]; + } + pdev->id_cache[pdev->count - 1] = tmpid; + } else { + ccode = pdev->count; + pdev->id_cache[pdev->count] = id; + } + } + if (pdev->TextMode == FALSE) { + /* Text mode */ + lputs(s, "}p"); + sput_lips_int(s, x); + sput_lips_int(s, y); + sputc(s, LIPS_IS2); + pdev->TextMode = TRUE; + pdev->prev_x = x; + pdev->prev_y = y; + } else + lips4v_set_cap(dev, x, y); + + if (download) { + if (ccode % 128 == 0 && ccode == pdev->count) { + /* 文字セット登録補助命令 */ + gs_sprintf(cset_sub, "%c%dx%c", LIPS_DCS, ccode / 128, LIPS_ST); + lputs(s, cset_sub); + /* 文字セット登録命令 */ + gs_sprintf(cset, + "%c%d;1;0;0;3840;8;400;100;0;0;200;%d;%d;0;0;;;;;%d.p", + LIPS_CSI, + size + 9, cell_length, /* Cell Width */ + cell_length, /* Cell Height */ + (int)dev->x_pixels_per_inch); + lputs(s, cset); + } else { + /* 1文字登録命令 */ + gs_sprintf(cset, + "%c%d;%d;8;%d.q", LIPS_CSI, + size + 9, ccode / 128, (int)dev->x_pixels_per_inch); + lputs(s, cset); + } + + /* ユーザ文字登録データ のヘッダ */ + sputc(s, ccode % 128); /* charcter code */ + put_int(s, w); + put_int(s, 0); + put_int(s, h); + put_int(s, 0); + for (i = h - 1; i >= 0; --i) { + put_bytes(s, data + i * raster, width_bytes); + } + } + /* 文字セット・アサイン番号選択命令2 */ + if (download) { + if (pdev->current_font != ccode / 128) { + gs_sprintf(cset_number, "%c%d%%v", LIPS_CSI, ccode / 128); + lputs(s, cset_number); + pdev->current_font = ccode / 128; + } + } else { + if (pdev->current_font != ccode / 128) { + gs_sprintf(cset_number, "%c%d%%v", LIPS_CSI, ccode / 128); + lputs(s, cset_number); + pdev->current_font = ccode / 128; + } + } + + /* カラー */ + if (pdev->current_color != pdev->prev_color) { + if (pdev->color_info.depth == 8) { + sputc(s, LIPS_CSI); + lputs(s, "?10;2;"); + gs_sprintf(text_color, "%d", + (int)(pdev->color_info.max_gray - pdev->current_color)); + } else { + int r = (pdev->current_color >> 16) * 1000.0 / 255.0; + int g = ((pdev->current_color >> 8) & 0xff) * 1000.0 / 255.0; + int b = (pdev->current_color & 0xff) * 1000.0 / 255.0; + + sputc(s, LIPS_CSI); + lputs(s, "?10;;"); + gs_sprintf(text_color, "%d;%d;%d", r, g, b); + } + lputs(s, text_color); + lputs(s, "%p"); + pdev->prev_color = pdev->current_color; + } + /* 制御文字印字命令 */ + if (ccode % 128 == 0x00 || + (ccode % 128 >= 0x07 && ccode % 128 <= 0x0F) || + ccode % 128 == 0x1B) { + sputc(s, LIPS_CSI); + lputs(s, "1.v"); + } + sputc(s, ccode % 128); + + if (download) { + pdev->id_table[ccode] = id; + if (pdev->count < max_cached_chars - 1) + pdev->count++; + } + return 0; +} + +static void +reverse_buffer(byte * buf, int Len) +{ + int i; + + for (i = 0; i < Len; i++) + *(buf + i) = ~*(buf + i); +} + +static void +lips4v_write_image_data(gx_device_vector * vdev, byte * buf, int tbyte, + int reverse) +{ + stream *s = gdev_vector_stream(vdev); + byte *cbuf = gs_alloc_bytes(vdev->memory, tbyte * 3 / 2, + "lips4v_write_image_data(cbuf)"); + byte *cbuf_rle = gs_alloc_bytes(vdev->memory, tbyte * 3, + "lips4v_write_image_data(cbuf_rle)"); + int Len, Len_rle; + + if (reverse) + reverse_buffer(buf, tbyte); + + Len = lips_packbits_encode(buf, cbuf, tbyte); + Len_rle = lips_rle_encode(buf, cbuf_rle, tbyte); + + if (Len > tbyte && Len_rle > tbyte) { + /* Not compress */ + lputs(s, "0"); + sput_lips_int(s, tbyte); + sputc(s, LIPS_IS2); + + put_bytes(s, buf, tbyte); + } else if (Len > Len_rle) { + /* Use RunLength encode */ + lputs(s, ":"); + sput_lips_int(s, Len_rle); + sputc(s, LIPS_IS2); + + put_bytes(s, cbuf_rle, Len_rle); + } else { + /* Use PackBits encode */ + lputs(s, ";"); + sput_lips_int(s, Len); + sputc(s, LIPS_IS2); + + put_bytes(s, cbuf, Len); + } + + gs_free_object(vdev->memory, cbuf, "lips4v_write_image_data(cbuf)"); + gs_free_object(vdev->memory, cbuf_rle, + "lips4v_write_image_data(cbuf_rle)"); +} + +/* ---------------- Vector device implementation ---------------- */ + +static int +lips4v_beginpage(gx_device_vector * vdev) +{ /* + * We can't use gdev_vector_stream here, because this may be called + * from there before in_page is set. + */ + gx_device_lips4v *const pdev = (gx_device_lips4v *) vdev; + stream *s = vdev->strm; + int dpi = vdev->x_pixels_per_inch; + int width = pdev->MediaSize[0]; + int height = pdev->MediaSize[1]; + int paper_size, x0, y0; + char dpi_char[6], unit[14]; + char page_header[8], l4vmono_page_header[7], l4vcolor_page_header[7]; + char duplex_char[6], tumble_char[6], toner_d[26], toner_s[5], + + nup_char[10]; + char username[6 + LIPS_USERNAME_MAX], feedmode[5], paper[16], + + faceup_char[256]; + bool dup = pdev->Duplex; + int dupset = pdev->Duplex_set; + bool tum = pdev->Tumble; + + /* ベクタ・モード移行命令 CSI &} は頁ごとに発行する */ + + if (pdev->first_page) { + if (pdev->pjl) { + lputs(s, l4v_file_header1); + if ((int)pdev->x_pixels_per_inch == 1200) + lputs(s, "@PJL SET RESOLUTION = SUPERFINE\n"); + else if ((int)pdev->x_pixels_per_inch == 600) + lputs(s, "@PJL SET RESOLUTION = FINE\n"); + else if ((int)pdev->x_pixels_per_inch == 300) + lputs(s, "@PJL SET RESOLUTION = QUICK\n"); + lputs(s, l4v_file_header2); + if (pdev->toner_density) { + gs_sprintf(toner_d, "@PJL SET TONER-DENSITY=%d\n", + pdev->toner_density); + lputs(s, toner_d); + } + if (pdev->toner_saving_set) { + lputs(s, "@PJL SET TONER-SAVING="); + if (pdev->toner_saving) + gs_sprintf(toner_s, "ON\n"); + else + gs_sprintf(toner_s, "OFF\n"); + lputs(s, toner_s); + } + lputs(s, l4v_file_header3); + } + lputs(s, l4v_file_header4); + + if (dpi > 9999) + return_error(gs_error_rangecheck); + + /* set reaolution (dpi) */ + gs_sprintf(dpi_char, "%d", dpi); + lputs(s, dpi_char); + + if (pdev->color_info.depth == 8) + lputs(s, l4vmono_file_header); + else + lputs(s, l4vcolor_file_header); + + /* username */ + gs_sprintf(username, "%c2y%s%c", LIPS_DCS, pdev->Username, LIPS_ST); + lputs(s, username); + } + if (strcmp(pdev->mediaType, "PlainPaper") == 0) { + sputc(s, LIPS_CSI); + lputs(s, "20\'t"); + } + else if (strcmp(pdev->mediaType, "OHP") == 0 || + strcmp(pdev->mediaType, "TransparencyFilm") == 0) { + sputc(s, LIPS_CSI); + lputs(s, "40\'t"); /* OHP mode (for LBP-2160) */ + } + else if (strcmp(pdev->mediaType, "CardBoard") == 0) { + sputc(s, LIPS_CSI); + lputs(s, "30\'t"); /* CardBoard mode (for LBP-2160) */ + } + else if (strcmp(pdev->mediaType, "GlossyFilm") == 0) { + sputc(s, LIPS_CSI); + lputs(s, "41\'t"); /* GlossyFilm mode (for LBP-2160) */ + } + + /* 給紙モード */ + if (pdev->ManualFeed || + (strcmp(pdev->mediaType, "PlainPaper") != 0 + && strcmp(pdev->mediaType, LIPS_MEDIATYPE_DEFAULT) != 0)) { + /* Use ManualFeed */ + if (pdev->prev_feed_mode != 10) { + gs_sprintf(feedmode, "%c10q", LIPS_CSI); + lputs(s, feedmode); + pdev->prev_feed_mode = 10; + } + } else { + if (pdev->prev_feed_mode != pdev->cassetFeed) { + gs_sprintf(feedmode, "%c%dq", LIPS_CSI, pdev->cassetFeed); + lputs(s, feedmode); + pdev->prev_feed_mode = pdev->cassetFeed; + } + } + + paper_size = lips_media_selection(width, height); + + /* 用紙サイズ */ + if (pdev->prev_paper_size != paper_size) { + if (paper_size == USER_SIZE) { + /* modified by shige 06/27 2003 + gs_sprintf(paper, "%c80;%d;%dp", LIPS_CSI, width * 10, height * 10); */ + /* modified by shige 11/09 2003 + gs_sprintf(paper, "%c80;%d;%dp", LIPS_CSI, height * 10, width * 10); */ + gs_sprintf(paper, "%c80;%d;%dp", LIPS_CSI, + (height * 10 > LIPS_HEIGHT_MAX_720)? + LIPS_HEIGHT_MAX_720 : (height * 10), + (width * 10 > LIPS_WIDTH_MAX_720)? + LIPS_WIDTH_MAX_720 : (width * 10)); + lputs(s, paper); + } else if (paper_size == USER_SIZE + LANDSCAPE) { + /* modified by shige 06/27 2003 + gs_sprintf(paper, "%c81;%d;%dp", LIPS_CSI, height * 10, width * 10); */ + /* modified by shige 11/09 2003 + gs_sprintf(paper, "%c81;%d;%dp", LIPS_CSI, width * 10, height * 10); */ + gs_sprintf(paper, "%c80;%d;%dp", LIPS_CSI, + (width * 10 > LIPS_HEIGHT_MAX_720)? + LIPS_HEIGHT_MAX_720 : (width * 10), + (height * 10 > LIPS_WIDTH_MAX_720)? + LIPS_WIDTH_MAX_720 : (height * 10)); + lputs(s, paper); + } else { + gs_sprintf(paper, "%c%dp", LIPS_CSI, paper_size); + lputs(s, paper); + } + } else if (paper_size == USER_SIZE) { + if (pdev->prev_paper_width != width || + pdev->prev_paper_height != height) + /* modified by shige 06/27 2003 + gs_sprintf(paper, "%c80;%d;%dp", LIPS_CSI, width * 10, height * 10); */ + /* modified by shige 11/09 2003 + gs_sprintf(paper, "%c80;%d;%dp", LIPS_CSI, height * 10, width * 10); */ + gs_sprintf(paper, "%c80;%d;%dp", LIPS_CSI, + (height * 10 > LIPS_HEIGHT_MAX_720)? + LIPS_HEIGHT_MAX_720 : (height * 10), + (width * 10 > LIPS_WIDTH_MAX_720)? + LIPS_WIDTH_MAX_720 : (width * 10)); + lputs(s, paper); + } else if (paper_size == USER_SIZE + LANDSCAPE) { + if (pdev->prev_paper_width != width || + pdev->prev_paper_height != height) + /* modified by shige 06/27 2003 + gs_sprintf(paper, "%c81;%d;%dp", LIPS_CSI, height * 10, width * 10); */ + /* modified by shige 11/09 2003 + gs_sprintf(paper, "%c81;%d;%dp", LIPS_CSI, width * 10, height * 10); */ + gs_sprintf(paper, "%c80;%d;%dp", LIPS_CSI, + (width * 10 > LIPS_HEIGHT_MAX_720)? + LIPS_HEIGHT_MAX_720 : (width * 10), + (height * 10 > LIPS_WIDTH_MAX_720)? + LIPS_WIDTH_MAX_720 : (height * 10)); + lputs(s, paper); + } + pdev->prev_paper_size = paper_size; + pdev->prev_paper_width = width; + pdev->prev_paper_height = height; + + if (pdev->faceup) { + gs_sprintf(faceup_char, "%c11;12;12~", LIPS_CSI); + lputs(s, faceup_char); + } + /* N-up Printing Setting */ + if (pdev->first_page) { + if (pdev->nup != 1) { + gs_sprintf(nup_char, "%c%d1;;%do", LIPS_CSI, pdev->nup, paper_size); + lputs(s, nup_char); + } + } + /* Duplex Setting */ + if (dupset && dup) { + if (pdev->prev_duplex_mode == 0 || pdev->prev_duplex_mode == 1) { + gs_sprintf(duplex_char, "%c2;#x", LIPS_CSI); /* duplex */ + lputs(s, duplex_char); + if (!tum) { + /* long edge binding */ + if (pdev->prev_duplex_mode != 2) { + gs_sprintf(tumble_char, "%c0;#w", LIPS_CSI); + lputs(s, tumble_char); + } + pdev->prev_duplex_mode = 2; + } else { + /* short edge binding */ + if (pdev->prev_duplex_mode != 3) { + gs_sprintf(tumble_char, "%c2;#w", LIPS_CSI); + lputs(s, tumble_char); + } + pdev->prev_duplex_mode = 3; + } + } + } else if (dupset && !dup) { + if (pdev->prev_duplex_mode != 1) { + gs_sprintf(duplex_char, "%c0;#x", LIPS_CSI); /* simplex */ + lputs(s, duplex_char); + } + pdev->prev_duplex_mode = 1; + } + sputc(s, LIPS_CSI); + lputs(s, "?1;4;5;6;14l"); + sputc(s, LIPS_CSI); + lputs(s, "?2;3;h"); + + /* size unit (dpi) */ + sputc(s, LIPS_CSI); + lputs(s, "11h"); + gs_sprintf(unit, "%c?7;%d I", LIPS_CSI, (int)pdev->x_pixels_per_inch); + lputs(s, unit); + gs_sprintf(page_header, "%c[0&}#%c", LIPS_ESC, LIPS_IS2); + lputs(s, page_header); /* vector mode */ + + lputs(s, "!0"); /* size unit (dpi) */ + sput_lips_int(s, dpi); + lputs(s, "1"); + sputc(s, LIPS_IS2); + + if (pdev->color_info.depth == 8) { + gs_sprintf(l4vmono_page_header, "!13%c$%c", LIPS_IS2, LIPS_IS2); + lputs(s, l4vmono_page_header); + } else { + gs_sprintf(l4vcolor_page_header, "!11%c$%c", LIPS_IS2, LIPS_IS2); + lputs(s, l4vcolor_page_header); + } + + lputs(s, "(00"); + sput_lips_int(s, + ((width - dev_l_margin(vdev) - dev_r_margin(vdev)) * dpi) / + 72); + sput_lips_int(s, + ((height - dev_b_margin(vdev) - dev_t_margin(vdev)) * dpi) / + 72); + sputc(s, LIPS_IS2); + + /* 原点移動命令 */ + x0 = (dev_l_margin(vdev) - 5. / MMETER_PER_INCH) * dpi; + y0 = (dev_b_margin(vdev) - 5. / MMETER_PER_INCH) * dpi; + + if (x0 != 0 && y0 != 0) { + lputs(s, "}\""); + sput_lips_int(s, x0); + sput_lips_int(s, y0); + sputc(s, LIPS_IS2); + } + lputs(s, "I00"); + sputc(s, LIPS_IS2); + lputs(s, "}F2"); + sputc(s, LIPS_IS2); + lputs(s, "}H1"); + sputc(s, LIPS_IS2); + lputs(s, "*0"); + sputc(s, LIPS_IS2); + + pdev->MaskState = 1; /* 初期化: 透過 */ + pdev->linecap = 0; + lputs(s, "}M"); + sput_lips_int(s, 3277); /* 11 degree : 16383 * 2 / 10 */ + sputc(s, LIPS_IS2); + lputs(s, "}I1"); /* non-zero winding rule is default */ + sputc(s, LIPS_IS2); + + return 0; +} + +static int +lips4v_setlinewidth(gx_device_vector * vdev, double width) +{ + stream *s = gdev_vector_stream(vdev); + gx_device_lips4v *const pdev = (gx_device_lips4v *) vdev; + +#if 0 + /* Scale を掛けているのは, Ghostscript 5.10/5.50 のバグのため */ + double xscale, yscale; + + xscale = fabs(igs->ctm.xx); + yscale = fabs(igs->ctm.xy); + + if (xscale == 0 || yscale > xscale) /* if portrait */ + width = ceil(width * yscale); + else + width = ceil(width * xscale); +#endif + + if (pdev->TextMode) { + sputc(s, LIPS_CSI); + lputs(s, "&}"); + pdev->TextMode = FALSE; + } + if (width < 1) + width = 1; + + lputs(s, "F1"); + sput_lips_int(s, width); + sputc(s, LIPS_IS2); + + return 0; +} + +static int +lips4v_setlinecap(gx_device_vector * vdev, gs_line_cap cap) +{ + stream *s = gdev_vector_stream(vdev); + gx_device_lips4v *const pdev = (gx_device_lips4v *) vdev; + char c[6]; + int line_cap = 0; + + if (pdev->TextMode) { + sputc(s, LIPS_CSI); + lputs(s, "&}"); + pdev->TextMode = FALSE; + } + switch (cap) { + default: + case 0: + case 3: + line_cap = 0; /* butt */ + break; + case 1: + line_cap = 1; /* round */ + break; + case 2: + line_cap = 2; /* square */ + break; + } + /* 線端形状指定命令 */ + gs_sprintf(c, "}E%d%c", line_cap, LIPS_IS2); + lputs(s, c); + + pdev->linecap = cap; + + return 0; +} + +static int +lips4v_setlinejoin(gx_device_vector * vdev, gs_line_join join) +{ + stream *s = gdev_vector_stream(vdev); + gx_device_lips4v *const pdev = (gx_device_lips4v *) vdev; + +/* 線接続指定命令 */ + char c[5]; + int lips_join = 0; + + if (pdev->TextMode) { + sputc(s, LIPS_CSI); + lputs(s, "&}"); + pdev->TextMode = FALSE; + } + + switch (join) { + default: + case 0: + lips_join = 2; /* miter */ + break; + case 1: + lips_join = 1; /* round */ + break; + case 2: + lips_join = 3; /* bevel */ + break; + case 3: + case 4: + lips_join = 0; /* none */ + break; + } + + gs_sprintf(c, "}F%d%c", lips_join, LIPS_IS2); + lputs(s, c); + + return 0; +} + +static int +lips4v_setmiterlimit(gx_device_vector * vdev, double limit) +{ + stream *s = gdev_vector_stream(vdev); + gx_device_lips4v *const pdev = (gx_device_lips4v *) vdev; + double lips_miterlimit; + + if (pdev->TextMode) { + sputc(s, LIPS_CSI); + lputs(s, "&}"); + pdev->TextMode = FALSE; + } + lips_miterlimit = (16383.0 * 2.0) / limit; + + lputs(s, "}M"); + sput_lips_int(s, lips_miterlimit); + sputc(s, LIPS_IS2); + + return 0; +} + +#if GS_VERSION_MAJOR >= 8 +static int +lips4v_setfillcolor(gx_device_vector * vdev, const gs_gstate * pgs, const gx_drawing_color * pdc) +#else +static int +lips4v_setfillcolor(gx_device_vector * vdev, const gx_drawing_color * pdc) +#endif +{ + + if (!gx_dc_is_pure(pdc)) + return_error(gs_error_rangecheck); + { + stream *s = gdev_vector_stream(vdev); + gx_device_lips4v *const pdev = (gx_device_lips4v *) vdev; + gx_color_index color = gx_dc_pure_color(pdc); + int drawing_color = 0; + float r = 0.0F, g = 0.0F, b = 0.0F; + + if (vdev->color_info.depth == 8) { + drawing_color = vdev->color_info.max_gray - color; + } else { + r = (color >> 16) * 1000.0 / 255.0; + g = ((color >> 8) & 0xff) * 1000.0 / 255.0; + b = (color & 0xff) * 1000.0 / 255.0; + } + + if (pdev->TextMode) { + sputc(s, LIPS_CSI); + lputs(s, "&}"); + pdev->TextMode = FALSE; + } + pdev->current_color = color; + + if (color == gx_no_color_index) { + lputs(s, "I0"); + sputc(s, LIPS_IS2); + } else { + lputs(s, "I1"); + sputc(s, LIPS_IS2); + } + + /* 塗りつぶしカラー指定命令 */ + /* J {color} IS2 */ + lputs(s, "J"); + if (vdev->color_info.depth == 8) { + sput_lips_int(s, drawing_color); + } else { + sput_lips_int(s, r); + sput_lips_int(s, g); + sput_lips_int(s, b); + } + sputc(s, LIPS_IS2); + + /* 単色イメージ・カラー指定命令 */ + /* }T {color} IS2 */ + lputs(s, "}T"); + if (vdev->color_info.depth == 8) { + sput_lips_int(s, drawing_color); + } else { + sput_lips_int(s, r); + sput_lips_int(s, g); + sput_lips_int(s, b); + } + sputc(s, LIPS_IS2); + } + return 0; +} + +#if GS_VERSION_MAJOR >= 8 +static int +lips4v_setstrokecolor(gx_device_vector * vdev, const gs_gstate * pgs, const gx_drawing_color * pdc) +#else +static int +lips4v_setstrokecolor(gx_device_vector * vdev, const gx_drawing_color * pdc) +#endif +{ + if (!gx_dc_is_pure(pdc)) + return_error(gs_error_rangecheck); + { + stream *s = gdev_vector_stream(vdev); + gx_device_lips4v *const pdev = (gx_device_lips4v *) vdev; + gx_color_index color = gx_dc_pure_color(pdc); + float r = 0.0F, g = 0.0F, b = 0.0F; + + if (vdev->color_info.depth == 24) { + r = (color >> 16) * 1000 / 255.0; + g = ((color >> 8) & 0xff) * 1000 / 255.0; + b = (color & 0xff) * 1000 / 255.0; + } + + if (pdev->TextMode) { + sputc(s, LIPS_CSI); + lputs(s, "&}"); + pdev->TextMode = FALSE; + } + /* ラインカラー指定命令 */ + /* G {color} IS2 */ + lputs(s, "G"); + if (vdev->color_info.depth == 8) { + sput_lips_int(s, vdev->color_info.max_gray - color); + } else { + sput_lips_int(s, r); + sput_lips_int(s, g); + sput_lips_int(s, b); + } + sputc(s, LIPS_IS2); + } + return 0; +} + +/* 線種指定命令 */ +static int +lips4v_setdash(gx_device_vector * vdev, const float *pattern, uint count, + double offset) +{ + stream *s = gdev_vector_stream(vdev); + gx_device_lips4v *const pdev = (gx_device_lips4v *) vdev; + int i; +#if 0 + float scale, xscale, yscale; +#endif + + if (pdev->TextMode) { + sputc(s, LIPS_CSI); + lputs(s, "&}"); + pdev->TextMode = FALSE; + } +#if 0 + /* Scale を掛けているのは, Ghostscript 5.10/5.50 のバグのため */ + xscale = fabs(igs->ctm.xx); + yscale = fabs(igs->ctm.xy); + + if (xscale == 0) /* if portrait */ + scale = yscale; + else + scale = xscale; +#endif + + if (count == 0) { + lputs(s, "E10"); + sputc(s, LIPS_IS2); + } else { + lputs(s, "}d"); + sputc(s, 0x2c); + lputs(s, "1"); +#if 0 + sput_lips_int(s, offset * scale / vdev->x_pixels_per_inch + 0.5); +#else + sput_lips_int(s, offset); +#endif + for (i = 0; i < count; ++i) { + if (pdev->linecap == 1 && count == 2 && pattern[0] == 0) { + if (i == 0) { + sput_lips_int(s, 1); + } else { +#if 0 + sput_lips_int(s, + pattern[i] * scale / + vdev->x_pixels_per_inch - 0.5); +#else + sput_lips_int(s, pattern[i] - 1); +#endif + } + } else { +#if 0 + sput_lips_int(s, + pattern[i] * scale / vdev->x_pixels_per_inch + + 0.5); +#else + sput_lips_int(s, pattern[i]); +#endif + } + } + sputc(s, LIPS_IS2); + lputs(s, "E1"); + sputc(s, 0x2c); + lputs(s, "0"); + sputc(s, LIPS_IS2); + } + + return 0; +} + +/* パス平滑度指定 */ +static int +lips4v_setflat(gx_device_vector * vdev, double flatness) +{ + stream *s = gdev_vector_stream(vdev); + gx_device_lips4v *const pdev = (gx_device_lips4v *) vdev; + + if (pdev->TextMode) { + sputc(s, LIPS_CSI); + lputs(s, "&}"); + pdev->TextMode = FALSE; + } + lputs(s, "Pf"); + sput_lips_int(s, flatness); + sputc(s, LIPS_IS2); + + return 0; +} + +static int +lips4v_setlogop(gx_device_vector * vdev, gs_logical_operation_t lop, + gs_logical_operation_t diff) +{ +/****** SHOULD AT LEAST DETECT SET-0 & SET-1 ******/ + return 0; +} + +#if GS_VERSION_MAJOR >= 8 +/*--- added for Ghostscritp 8.15 ---*/ +static int +lips4v_can_handle_hl_color(gx_device_vector * vdev, const gs_gstate * pgs1, + const gx_drawing_color * pdc) +{ + return false; /* High level color is not implemented yet. */ +} +#endif + +static int +lips4v_beginpath(gx_device_vector * vdev, gx_path_type_t type) +{ + stream *s = gdev_vector_stream(vdev); + gx_device_lips4v *const pdev = (gx_device_lips4v *) vdev; + + if (pdev->TextMode) { + sputc(s, LIPS_CSI); + lputs(s, "&}"); + pdev->TextMode = FALSE; + } + /* パス構築開始命令 */ + if (type & gx_path_type_clip) { + lputs(s, "P(10"); + sputc(s, LIPS_IS2); + } else + lputs(s, "P(00"); + sputc(s, LIPS_IS2); + + return 0; +} + +static int +lips4v_moveto(gx_device_vector * vdev, double x0, double y0, double x, + double y, gx_path_type_t type) +{ + stream *s = gdev_vector_stream(vdev); + + /* サブパス開始命令 p1 */ + lputs(s, "p10"); + sput_lips_int(s, x); + sput_lips_int(s, y); + sputc(s, LIPS_IS2); + + return 0; +} + +static int +lips4v_lineto(gx_device_vector * vdev, double x0, double y0, double x, + double y, gx_path_type_t type) +{ + stream *s = gdev_vector_stream(vdev); + gx_device_lips4v *const pdev = (gx_device_lips4v *) vdev; + + /* if round cap */ + if (pdev->linecap == 1) { + if ((x0 == x) && (y0 == y)) + x += 1; + } + + /* パス・ポリライン命令 */ + lputs(s, "p402"); + sput_lips_int(s, x); + sput_lips_int(s, y); + sputc(s, LIPS_IS2); + + return 0; +} + +static int +lips4v_curveto(gx_device_vector * vdev, double x0, double y0, + double x1, double y1, double x2, double y2, double x3, + double y3, gx_path_type_t type) +{ + stream *s = gdev_vector_stream(vdev); + + /* パス・ポリライン命令 */ + lputs(s, "p404"); + sput_lips_int(s, x1); + sput_lips_int(s, y1); + sput_lips_int(s, x2); + sput_lips_int(s, y2); + sput_lips_int(s, x3); + sput_lips_int(s, y3); + sputc(s, LIPS_IS2); + + return 0; +} + +static int +lips4v_closepath(gx_device_vector * vdev, double x, double y, + double x_start, double y_start, gx_path_type_t type) +{ + stream *s = gdev_vector_stream(vdev); + + lputs(s, "p0"); + sputc(s, LIPS_IS2); + return 0; +} + +static int +lips4v_endpath(gx_device_vector * vdev, gx_path_type_t type) +{ + stream *s = gdev_vector_stream(vdev); + + lputs(s, "P)"); + sputc(s, LIPS_IS2); + if (type & gx_path_type_rule) { + if (type & gx_path_type_winding_number) { + lputs(s, "}I1"); + sputc(s, LIPS_IS2); + } else { + lputs(s, "}I0"); + sputc(s, LIPS_IS2); + } + } + if (type & gx_path_type_fill) { + if (type & gx_path_type_stroke) { + lputs(s, "P&00"); + sputc(s, LIPS_IS2); + } else { + lputs(s, "PF00"); + sputc(s, LIPS_IS2); + } + } + if (type & gx_path_type_stroke) { + lputs(s, "PS00"); + sputc(s, LIPS_IS2); + } + if (type & gx_path_type_clip) { + lputs(s, "PC10"); + sputc(s, LIPS_IS2); + } + return 0; +} + +/* ---------------- Driver procedures ---------------- */ + +/* ------ Open/close/page ------ */ + +/* Open the device. */ +static int +lips4v_open(gx_device * dev) +{ + gx_device_vector *const vdev = (gx_device_vector *) dev; + gx_device_lips4v *const pdev = (gx_device_lips4v *) dev; + + int code; + + code = lips4v_range_check(dev); + if (code < 0) + return code; + + vdev->v_memory = dev->memory; +/****** WRONG ******/ + vdev->vec_procs = &lips4v_vector_procs; + +#if GS_VERSION_MAJOR >= 8 + code = gdev_vector_open_file_options(vdev, 512, + (VECTOR_OPEN_FILE_SEQUENTIAL|VECTOR_OPEN_FILE_BBOX)); +#else + code = gdev_vector_open_file_bbox(vdev, 512, true); +#endif + if (code < 0) + return code; + +#if GS_VERSION_MAJOR >= 8 + if (pdev->bbox_device != NULL) { + if (pdev->bbox_device->memory == NULL) + pdev->bbox_device->memory = gs_memory_stable(dev->memory); + } +#endif + + gdev_vector_init(vdev); + pdev->first_page = true; + + return 0; +} + +/* Wrap up ("output") a page. */ +static int +lips4v_output_page(gx_device * dev, int num_copies, int flush) +{ + gx_device_vector *const vdev = (gx_device_vector *) dev; + gx_device_lips4v *const pdev = (gx_device_lips4v *) dev; + stream *s = gdev_vector_stream(vdev); + char str[6]; + + if (pdev->TextMode) { + sputc(s, LIPS_CSI); + lputs(s, "&}"); + pdev->TextMode = FALSE; + } + lputs(s, "%"); + sputc(s, LIPS_IS2); + lputs(s, "}p"); + sputc(s, LIPS_IS2); + + if (num_copies > 255) + num_copies = 255; + if (pdev->prev_num_copies != num_copies) { + gs_sprintf(str, "%c%dv", LIPS_CSI, num_copies); + lputs(s, str); + pdev->prev_num_copies = num_copies; + } + sputc(s, LIPS_FF); + sflush(s); + vdev->in_page = false; + pdev->first_page = false; + gdev_vector_reset(vdev); + return 0; +} + +static int +lips4v_close(gx_device * dev) +{ + gx_device_vector *const vdev = (gx_device_vector *) dev; + gx_device_lips4v *const pdev = (gx_device_lips4v *) dev; + gp_file *f = vdev->file; + + gp_fprintf(f, "%c0J%c", LIPS_DCS, LIPS_ST); + if (pdev->pjl) { + gp_fprintf(f, "%c%%-12345X@PJL SET LPARM : LIPS SW2 = OFF\n", LIPS_ESC); + gp_fprintf(f, + "%c%%-12345X%c%%-12345X@PJL EOJ\n" + "%c%%-12345X", LIPS_ESC, LIPS_ESC, LIPS_ESC); + } + gdev_vector_close_file(vdev); + + return 0; +} + +/* Close the device. */ +/* Note that if this is being called as a result of finalization, */ +/* the stream may no longer exist; but the file will still be open. */ + +/* ---------------- Get/put parameters ---------------- */ + +/* Get parameters. */ +static int +lips4v_get_params(gx_device * dev, gs_param_list * plist) +{ + gx_device_lips4v *const pdev = (gx_device_lips4v *) dev; + int code = gdev_vector_get_params(dev, plist); + int ncode; + gs_param_string usern; + gs_param_string pmedia; + + if (code < 0) + return code; + + if ((ncode = param_write_bool(plist, LIPS_OPTION_MANUALFEED, + &pdev->ManualFeed)) < 0) + code = ncode; + + if ((ncode = param_write_int(plist, LIPS_OPTION_CASSETFEED, + &pdev->cassetFeed)) < 0) + code = ncode; + + if ((ncode = param_write_bool(plist, LIPS_OPTION_DUPLEX_TUMBLE, + &pdev->Tumble)) < 0) + code = ncode; + + if ((ncode = param_write_int(plist, LIPS_OPTION_NUP, &pdev->nup)) < 0) + code = ncode; + + if ((ncode = param_write_bool(plist, LIPS_OPTION_PJL, &pdev->pjl)) < 0) + code = ncode; + + if ((ncode = param_write_int(plist, LIPS_OPTION_TONERDENSITY, + &pdev->toner_density)) < 0) + code = ncode; + + if (pdev->toner_saving_set >= 0 && + (code = (pdev->toner_saving_set ? + param_write_bool(plist, LIPS_OPTION_TONERSAVING, + &pdev-> + toner_saving) : param_write_null(plist, + LIPS_OPTION_TONERSAVING))) + < 0) + code = ncode; + + if (pdev->Duplex_set >= 0 && + (ncode = (pdev->Duplex_set ? + param_write_bool(plist, "Duplex", &pdev->Duplex) : + param_write_null(plist, "Duplex"))) < 0) + code = ncode; + + if ((ncode = param_write_bool(plist, LIPS_OPTION_FONTDOWNLOAD, + &pdev->FontDL)) < 0) + code = ncode; + + if ((ncode = param_write_bool(plist, LIPS_OPTION_FACEUP, + &pdev->faceup)) < 0) code = ncode; + + pmedia.data = (const byte *)pdev->mediaType, + pmedia.size = strlen(pdev->mediaType), pmedia.persistent = false; + + if ((ncode = param_write_string(plist, LIPS_OPTION_MEDIATYPE, + &pmedia)) < 0) code = ncode; + + if (code < 0) + return code; + + usern.data = (const byte *)pdev->Username, + usern.size = strlen(pdev->Username), usern.persistent = false; + + return param_write_string(plist, LIPS_OPTION_USER_NAME, &usern); +} + +/* Put parameters. */ +static int +lips4v_put_params(gx_device * dev, gs_param_list * plist) +{ + gx_device_lips4v *const pdev = (gx_device_lips4v *) dev; + int ecode = 0; + int code; + gs_param_name param_name; + gs_param_string pmedia; + bool mf = pdev->ManualFeed; + int cass = pdev->cassetFeed; + gs_param_string usern; + bool tum = pdev->Tumble; + int nup = pdev->nup; + bool pjl = pdev->pjl; + int toner_density = pdev->toner_density; + bool toner_saving = pdev->toner_saving; + bool toner_saving_set = pdev->toner_saving_set; + bool fontdl = pdev->FontDL; + bool faceup = pdev->faceup; + bool duplex; + int duplex_set = -1; + int old_bpp = dev->color_info.depth; + int bpp = 0; + + if ((code = param_read_bool(plist, + (param_name = LIPS_OPTION_MANUALFEED), + &mf)) < 0) { + param_signal_error(plist, param_name, ecode = code); + } + switch (code = param_read_int(plist, + (param_name = LIPS_OPTION_CASSETFEED), + &cass)) { + case 0: + if (cass < -1 || cass > 17 || (cass > 3 && cass < 10)) + ecode = gs_error_limitcheck; + else + break; + goto casse; + default: + ecode = code; + casse:param_signal_error(plist, param_name, ecode); + case 1: + break; + } + + switch (code = param_read_string(plist, + (param_name = LIPS_OPTION_MEDIATYPE), + &pmedia)) { + case 0: + if (pmedia.size > LIPS_MEDIACHAR_MAX) { + ecode = gs_error_limitcheck; + goto pmediae; + } else { /* Check the validity of ``MediaType'' characters */ + if (strcmp((const char *)pmedia.data, "PlainPaper") != 0 && + strcmp((const char *)pmedia.data, "OHP") != 0 && + strcmp((const char *)pmedia.data, "TransparencyFilm") != 0 && /* same as OHP */ + strcmp((const char *)pmedia.data, "GlossyFilm") != 0 && + strcmp((const char *)pmedia.data, "CardBoard") != 0) { + ecode = gs_error_rangecheck; + goto pmediae; + } + } + break; + default: + ecode = code; + pmediae:param_signal_error(plist, param_name, ecode); + case 1: + pmedia.data = 0; + break; + } + + switch (code = param_read_string(plist, + (param_name = LIPS_OPTION_USER_NAME), + &usern)) { + case 0: + if (usern.size > LIPS_USERNAME_MAX) { + ecode = gs_error_limitcheck; + goto userne; + } else { /* Check the validity of ``User Name'' characters */ + int i; + + for (i = 0; i < usern.size; i++) + if (usern.data[i] < 0x20 || usern.data[i] > 0x7e + /* + && usern.data[i] < 0xa0) || + usern.data[i] > 0xfe + */ + ) { + ecode = gs_error_rangecheck; + goto userne; + } + } + break; + default: + ecode = code; + userne:param_signal_error(plist, param_name, ecode); + case 1: + usern.data = 0; + break; + } + + if ((code = param_read_bool(plist, + (param_name = LIPS_OPTION_DUPLEX_TUMBLE), + &tum)) < 0) + param_signal_error(plist, param_name, ecode = code); + + switch (code = param_read_int(plist, + (param_name = LIPS_OPTION_NUP), &nup)) { + case 0: + if (nup != 1 && nup != 2 && nup != 4) + ecode = gs_error_rangecheck; + else + break; + goto nupe; + default: + ecode = code; + nupe:param_signal_error(plist, param_name, ecode); + case 1: + break; + } + + if ((code = param_read_bool(plist, + (param_name = LIPS_OPTION_PJL), &pjl)) < 0) + param_signal_error(plist, param_name, ecode = code); + + switch (code = param_read_int(plist, + (param_name = LIPS_OPTION_TONERDENSITY), + &toner_density)) { + case 0: + if (toner_density < 0 || toner_density > 8) + ecode = gs_error_rangecheck; + else + break; + goto tden; + default: + ecode = code; + tden:param_signal_error(plist, param_name, ecode); + case 1: + break; + } + + if (pdev->toner_saving_set >= 0) + switch (code = + param_read_bool(plist, (param_name = LIPS_OPTION_TONERSAVING), + &toner_saving)) { + case 0: + toner_saving_set = 1; + break; + default: + if ((code = param_read_null(plist, param_name)) == 0) { + toner_saving_set = 0; + break; + } + ecode = code; + param_signal_error(plist, param_name, ecode); + case 1: + break; + } + + if (pdev->Duplex_set >= 0) /* i.e., Duplex is supported */ + switch (code = param_read_bool(plist, (param_name = "Duplex"), + &duplex)) { + case 0: + duplex_set = 1; + break; + default: + if ((code = param_read_null(plist, param_name)) == 0) { + duplex_set = 0; + break; + } + ecode = code; + param_signal_error(plist, param_name, ecode); + case 1: + break; + } + if ((code = param_read_bool(plist, + (param_name = LIPS_OPTION_FONTDOWNLOAD), + &fontdl)) < 0) + param_signal_error(plist, param_name, ecode = code); + + if ((code = param_read_bool(plist, + (param_name = LIPS_OPTION_FACEUP), + &faceup)) < 0) { + param_signal_error(plist, param_name, ecode = code); + } + + switch (code = param_read_int(plist, (param_name = "BitsPerPixel"), &bpp)) { + case 0: + if (bpp != 8 && bpp != 24) + ecode = gs_error_rangecheck; + else + break; + goto bppe; + default: + ecode = code; + bppe:param_signal_error(plist, param_name, ecode); + case 1: + break; + } + + if (bpp != 0) { + dev->color_info.depth = bpp; + dev->color_info.num_components = ((bpp == 8) ? 1 : 3); + dev->color_info.max_gray = (bpp > 8 ? 255 : 1000); + dev->color_info.max_color = (bpp > 8 ? 255 : 1000); + dev->color_info.dither_grays = (bpp > 8 ? 256 : 5); + dev->color_info.dither_colors = (bpp > 8 ? 256 : 2); + dev_proc(pdev, map_rgb_color) = + ((bpp == 8) ? gx_default_gray_map_rgb_color : + gx_default_rgb_map_rgb_color); + dev_proc(pdev, map_color_rgb) = + ((bpp == 8) ? gx_default_gray_map_color_rgb : + gx_default_rgb_map_color_rgb); + } + + if (ecode < 0) + return ecode; + code = gdev_vector_put_params(dev, plist); + if (code < 0) + return code; + + pdev->ManualFeed = mf; + pdev->cassetFeed = cass; + pdev->Tumble = tum; + pdev->nup = nup; + pdev->pjl = pjl; + pdev->toner_density = toner_density; + pdev->toner_saving = toner_saving; + pdev->toner_saving_set = toner_saving_set; + pdev->FontDL = fontdl; + pdev->faceup = faceup; + + if (duplex_set >= 0) { + pdev->Duplex = duplex; + pdev->Duplex_set = duplex_set; + } + if (pmedia.data != 0 && + bytes_compare(pmedia.data, pmedia.size, + (const byte *)pdev->mediaType, strlen(pdev->mediaType)) + ) { + memcpy(pdev->mediaType, pmedia.data, pmedia.size); + pdev->mediaType[pmedia.size] = 0; + } + if (usern.data != 0 && + bytes_compare(usern.data, usern.size, + (const byte *)pdev->Username, strlen(pdev->Username)) + ) { + memcpy(pdev->Username, usern.data, usern.size); + pdev->Username[usern.size] = 0; + } + if (bpp != 0 && bpp != old_bpp && pdev->is_open) + return gs_closedevice(dev); + return 0; +} + +/* ---------------- Images ---------------- */ + +static int +lips4v_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) +{ + gx_device_lips4v *const pdev = (gx_device_lips4v *) dev; + gx_device_vector *const vdev = (gx_device_vector *) dev; + stream *s = gdev_vector_stream(vdev); + int dpi = dev->x_pixels_per_inch; + gx_drawing_color color; + int code = 0; + double r, g, b; + + if (id != gs_no_id && zero == gx_no_color_index && + one != gx_no_color_index && data_x == 0) { + gx_drawing_color dcolor; + + color_set_pure(&dcolor, one); +#if GS_VERSION_MAJOR >= 8 + lips4v_setfillcolor(vdev, NULL, &dcolor); +#else + lips4v_setfillcolor(vdev, &dcolor); +#endif + + if (lips4v_copy_text_char(dev, data, raster, id, x, y, w, h) >= 0) + return 0; + } + if (pdev->TextMode) { + sputc(s, LIPS_CSI); + lputs(s, "&}"); + pdev->TextMode = FALSE; + } + /* + (*dev_proc(vdev->bbox_device, copy_mono)) + ((gx_device *)vdev->bbox_device, data, data_x, raster, id, + x, y, w, h, zero, one); + */ + if (zero == gx_no_color_index) { + if (one == gx_no_color_index) + return 0; + /* one 色に染め、透過にする */ + if (pdev->MaskState != 1) { + lputs(s, "}H1"); + sputc(s, LIPS_IS2); + pdev->MaskState = 1; + } + if (pdev->color_info.depth == 8) { + gx_color_index one_color = vdev->color_info.max_gray - one; + + lputs(s, "}T"); + sput_lips_int(s, one_color); + sputc(s, LIPS_IS2); + } else { + r = (one >> 16) * 1000.0 / 255.0; + g = ((one >> 8) & 0xff) * 1000.0 / 255.0; + b = (one & 0xff) * 1000.0 / 255.0; + lputs(s, "}T"); + sput_lips_int(s, r); + sput_lips_int(s, g); + sput_lips_int(s, b); + sputc(s, LIPS_IS2); + } + } else if (one == gx_no_color_index) + /* 1bit は透明 ビット反転・zero 色に染める */ + { + gx_color_index zero_color = vdev->color_info.max_gray - zero; + + if (pdev->MaskState != 1) { + lputs(s, "}H1"); + sputc(s, LIPS_IS2); + pdev->MaskState = 1; + } + if (pdev->color_info.depth == 8) { + lputs(s, "}T"); + sput_lips_int(s, zero_color); + sputc(s, LIPS_IS2); + } else { + r = (zero >> 16) * 1000.0 / 255.0; + g = ((zero >> 8) & 0xff) * 1000.0 / 255.0; + b = (zero & 0xff) * 1000.0 / 255.0; + lputs(s, "}T"); + sput_lips_int(s, r); + sput_lips_int(s, g); + sput_lips_int(s, b); + sputc(s, LIPS_IS2); + } + } else if (one == vdev->white) { + /* ビット反転 白塗り zero 色に染める */ + gx_color_index zero_color = vdev->color_info.max_gray - zero; + + if (pdev->MaskState != 0) { + lputs(s, "}H0"); + sputc(s, LIPS_IS2); + pdev->MaskState = 0; + } + if (pdev->color_info.depth == 8) { + lputs(s, "}T"); + sput_lips_int(s, zero_color); + sputc(s, LIPS_IS2); + } else { + r = (zero >> 16) * 1000.0 / 255.0; + g = ((zero >> 8) & 0xff) * 1000.0 / 255.0; + b = (zero & 0xff) * 1000.0 / 255.0; + lputs(s, "}T"); + sput_lips_int(s, r); + sput_lips_int(s, g); + sput_lips_int(s, b); + sputc(s, LIPS_IS2); + } + } else { + if (zero != gx_no_color_index) { + code = (*dev_proc(dev, fill_rectangle)) (dev, x, y, w, h, zero); + if (code < 0) + return code; + } + if (pdev->MaskState != 1) { + lputs(s, "}H1"); + sputc(s, LIPS_IS2); + pdev->MaskState = 1; + } + color_set_pure(&color, one); + +#if GS_VERSION_MAJOR >= 8 + code = gdev_vector_update_fill_color((gx_device_vector *) pdev, + NULL, &color); +#else + code = gdev_vector_update_fill_color((gx_device_vector *) pdev, + &color); +#endif + } + if (code < 0) + return 0; + lputs(s, "}P"); + sput_lips_int(s, x); /* Position X */ + sput_lips_int(s, y); /* Position Y */ + sput_lips_int(s, dpi * 100); + sput_lips_int(s, dpi * 100); + sput_lips_int(s, h); /* Height */ + sput_lips_int(s, w); /* Width */ + lputs(s, "100110"); + sputc(s, LIPS_IS2); + + lputs(s, "}Q11"); + + { + int i, j; + uint width_bytes = (w + 7) >> 3; + uint num_bytes = round_up(width_bytes, 4) * h; + byte *buf = gs_alloc_bytes(vdev->memory, num_bytes, + "lips4v_copy_mono(buf)"); + + if (data_x % 8 == 0) { + for (i = 0; i < h; ++i) { + memcpy(buf + i * width_bytes, + data + (data_x >> 3) + i * raster, width_bytes); + } + } else { + for (i = 0; i < h; ++i) { + for (j = 0; j < width_bytes; j++) { + *(buf + i * width_bytes + j) = + *(data + (data_x >> 3) + i * raster + + j) << (data_x % 8) | *(data + (data_x >> 3) + + i * raster + j + 1) >> (8 - + data_x + % 8); + } + } + } + + if (one == gx_no_color_index + || (one == vdev->white + && zero != gx_no_color_index)) lips4v_write_image_data(vdev, + buf, + num_bytes, + TRUE); + else + lips4v_write_image_data(vdev, buf, num_bytes, FALSE); + + gs_free_object(vdev->memory, buf, "lips4v_copy_mono(buf)"); + } + + return 0; +} + +/* Copy a color bitmap. */ +static int +lips4v_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) +{ + gx_device_lips4v *const pdev = (gx_device_lips4v *) dev; + gx_device_vector *const vdev = (gx_device_vector *) dev; + + stream *s = gdev_vector_stream(vdev); + int depth = dev->color_info.depth; + int dpi = dev->x_pixels_per_inch; + int num_components = (depth < 24 ? 1 : 3); + uint width_bytes = w * num_components; + + if (dev->color_info.depth == 8) { + gx_drawing_color dcolor; + + /* LIPS IV ではグレースケールも単色イメージ・カラー指定命令に + 影響されるので黒色を指定しなければならない。 */ + color_set_pure(&dcolor, vdev->black); +#if GS_VERSION_MAJOR >= 8 + lips4v_setfillcolor(vdev, NULL, &dcolor); +#else + lips4v_setfillcolor(vdev, &dcolor); +#endif + } else { + if (pdev->TextMode) { + sputc(s, LIPS_CSI); + lputs(s, "&}"); + pdev->TextMode = FALSE; + } + } + + if (pdev->MaskState != 0) { + lputs(s, "}H0"); /* 論理描画設定命令 */ + sputc(s, LIPS_IS2); + pdev->MaskState = 0; + } + lputs(s, "}P"); + sput_lips_int(s, x); + sput_lips_int(s, y); + sput_lips_int(s, dpi * 100); + sput_lips_int(s, dpi * 100); + sput_lips_int(s, h); + sput_lips_int(s, w); + sput_lips_int(s, depth / num_components); + sputc(s, depth < 24 ? '0' : ':'); /* 24 bit のとき点順次 */ + lputs(s, "0110"); + sputc(s, LIPS_IS2); + + { + int i; + uint num_bytes = width_bytes * h; + byte *buf = gs_alloc_bytes(vdev->memory, num_bytes, + "lips4v_copy_color(buf)"); + + lputs(s, "}Q11"); + + for (i = 0; i < h; ++i) { + memcpy(buf + i * width_bytes, + data + ((data_x * depth) >> 3) + i * raster, width_bytes); + } + + if (dev->color_info.depth == 8) + lips4v_write_image_data(vdev, buf, num_bytes, TRUE); + else + lips4v_write_image_data(vdev, buf, num_bytes, FALSE); + + gs_free_object(vdev->memory, buf, "lips4v_copy_color(buf)"); + } + + return 0; +} + +/* Fill a mask. */ +static int +lips4v_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) +{ + gx_device_vector *const vdev = (gx_device_vector *) dev; + gx_device_lips4v *const pdev = (gx_device_lips4v *) dev; + stream *s = gdev_vector_stream(vdev); + int dpi = dev->x_pixels_per_inch; + + if (w <= 0 || h <= 0) + return 0; + if (depth > 1 || +#if GS_VERSION_MAJOR >= 8 + gdev_vector_update_fill_color(vdev, NULL, pdcolor) < 0 || +#else + gdev_vector_update_fill_color(vdev, pdcolor) < 0 || +#endif + gdev_vector_update_clip_path(vdev, pcpath) < 0 || + gdev_vector_update_log_op(vdev, lop) < 0) + return gx_default_fill_mask(dev, data, data_x, raster, id, + x, y, w, h, pdcolor, depth, lop, pcpath); +#if 1 + (*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); +#endif + if (id != gs_no_id && data_x == 0) { + if (lips4v_copy_text_char(dev, data, raster, id, x, y, w, h) >= 0) + return 0; + } + if (pdev->TextMode) { + sputc(s, LIPS_CSI); + lputs(s, "&}"); + pdev->TextMode = FALSE; + } + /* 書きだし */ + if (pdev->MaskState != 1) { + lputs(s, "}H1"); /* 論理描画設定命令 */ + sputc(s, LIPS_IS2); + pdev->MaskState = 1; + } + lputs(s, "}P"); + sput_lips_int(s, x); + sput_lips_int(s, y); + sput_lips_int(s, dpi * 100); + sput_lips_int(s, dpi * 100); + sput_lips_int(s, h); + sput_lips_int(s, w); + lputs(s, "100110"); + sputc(s, LIPS_IS2); + + lputs(s, "}Q11"); + + { + int i; + uint width_bytes = (w + 7) >> 3; + uint num_bytes = round_up(width_bytes, 4) * h; + byte *buf = gs_alloc_bytes(vdev->memory, num_bytes, + "lips4v_fill_mask(buf)"); + + for (i = 0; i < h; ++i) { + memcpy(buf + i * width_bytes, data + (data_x >> 3) + i * raster, + width_bytes); + } + + lips4v_write_image_data(vdev, buf, num_bytes, FALSE); + + gs_free_object(vdev->memory, buf, "lips4v_fill_mask(buf)"); + } + + return 0; +} + +/* ---------------- High-level images ---------------- */ + +static image_enum_proc_plane_data(lips4v_image_plane_data); +static image_enum_proc_end_image(lips4v_image_end_image); +static const gx_image_enum_procs_t lips4v_image_enum_procs = { + lips4v_image_plane_data, lips4v_image_end_image +}; + +/* Start processing an image. */ +static int +lips4v_begin_image(gx_device * dev, + const gs_gstate * pgs, 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) +{ + gx_device_vector *const vdev = (gx_device_vector *) dev; + gx_device_lips4v *const pdev = (gx_device_lips4v *) dev; + gdev_vector_image_enum_t *pie = + gs_alloc_struct(mem, gdev_vector_image_enum_t, + &st_vector_image_enum, "lips4v_begin_image"); + const gs_color_space *pcs = pim->ColorSpace; + gs_color_space_index index = 0; + int num_components = 1; + bool can_do = prect == 0 && + (pim->format == gs_image_format_chunky || + + pim->format == gs_image_format_component_planar); + + int code; + + if (pie == 0) + return_error(gs_error_VMerror); + pie->memory = mem; + code = gdev_vector_begin_image(vdev, pgs, pim, format, prect, + pdcolor, pcpath, mem, + &lips4v_image_enum_procs, pie); + if (code < 0) + return code; + *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); + + if (pim->CombineWithColor) + can_do = false; + else { + switch (index) { + case gs_color_space_index_DeviceGray: + if ((pim->Decode[0] != 0 || pim->Decode[1] != 1) + && (pim->Decode[0] != 1 || pim->Decode[1] != 0)) + can_do = false; + break; + case gs_color_space_index_DeviceRGB: + /* LIPS では RGB を反転することはできない */ + if (pim->Decode[0] != 0 || pim->Decode[1] != 1 || + pim->Decode[2] != 0 || pim->Decode[3] != 1 || + pim->Decode[4] != 0) + can_do = false; + break; + default: + /* + LIPS では L*a*b* 形式のカラースペースが使えます。 + CIEBasedABC を使って表現できないこともないのですが、 + 動作確認できないので低レベルの関数にまかせることに + しちゃいます。 + それよりも CMYK のカラースペースが欲しい... + */ + can_do = false; + } + } + } + if (!can_do) + return gx_default_begin_image(dev, pgs, pim, format, prect, + pdcolor, pcpath, mem, + &pie->default_info); + else if (index == gs_color_space_index_DeviceGray) { + gx_drawing_color dcolor; + + /* LIPS IV ではグレースケールも単色イメージ・カラー指定命令に + 影響されるので黒色を明示的に指定しなければならない。 */ + color_set_pure(&dcolor, vdev->black); +#if GS_VERSION_MAJOR >= 8 + lips4v_setfillcolor(vdev, NULL, &dcolor); +#else + lips4v_setfillcolor(vdev, &dcolor); +#endif + } + if (pim->ImageMask || (pim->BitsPerComponent == 1 && num_components == 1)) { + if (pim->Decode[0] > pim->Decode[1]) + pdev->MaskReverse = 1; + else + pdev->MaskReverse = 0; + } + /* Write the image/colorimage/imagemask preamble. */ + { + stream *s = gdev_vector_stream((gx_device_vector *) pdev); + int ax, ay, bx, by, cx, cy, dx, dy; + int tbyte; + gs_matrix imat; + int interpolate = 0; + + if (pdev->TextMode) { + sputc(s, LIPS_CSI); + lputs(s, "&}"); + pdev->TextMode = FALSE; + } + code = gs_matrix_invert(&pim->ImageMatrix, &imat); + if (code < 0) + return code; + + gs_matrix_multiply(&imat, &ctm_only(pgs), &imat); + /* + [xx xy yx yy tx ty] + LIPS の座標系に変換を行なう。 + + }U{Ax}{Ay}{Bx}{By}{Cx}{Cy}{pie->height}{pie->width} + {pim->BitsPerComponent}{0}{0}{1} LIPS_IS2 + */ + + /* }Q110{byte} LIPS_IS2 */ + ax = imat.tx; + ay = imat.ty; + bx = imat.xx * pim->Width + imat.yx * pim->Height + imat.tx; + by = imat.xy * pim->Width + imat.yy * pim->Height + imat.ty; + cx = imat.yx * pim->Height + imat.tx; + cy = imat.yy * pim->Height + imat.ty; + dx = imat.xx * pim->Width + imat.tx; + dy = imat.xy * pim->Width + imat.ty; + + if (pim->ImageMask) { + tbyte = + (pie->width * pim->BitsPerComponent + + 7) / 8 * num_components * pie->height; + pdev->ncomp = 1; + if (tbyte == 1) { + /* LIPS IV では 1 dot のイメージを変形すると座標が狂うバグが + ある。よって 1 dot のイメージは矩形として処理する。 */ + pdev->OneBitMask = true; + /* Draw Rectangle */ + lputs(s, "2"); + sput_lips_int(s, ax); + sput_lips_int(s, ay); + sput_lips_int(s, cx - ax); + sput_lips_int(s, cy - ay); + sput_lips_int(s, bx - cx); + sput_lips_int(s, by - cy); + sput_lips_int(s, dx - bx); + sput_lips_int(s, dy - by); + sputc(s, LIPS_IS2); + return 0; + } else { + /* 描画論理設定命令 - 透過 */ + if (pdev->MaskState != 1) { + lputs(s, "}H1"); + sputc(s, LIPS_IS2); + pdev->MaskState = 1; + } + } + } else { + /* 描画論理設定命令 - 白塗り */ + if (pdev->MaskState != 0) { + lputs(s, "}H0"); + sputc(s, LIPS_IS2); + pdev->MaskState = 0; + } + pdev->ncomp = num_components; + } + + lputs(s, "}U"); + sput_lips_int(s, ax); + sput_lips_int(s, ay); + sput_lips_int(s, bx); + sput_lips_int(s, by); + sput_lips_int(s, cx); + sput_lips_int(s, cy); + sput_lips_int(s, pie->height); + sput_lips_int(s, pie->width); + sput_lips_int(s, pim->BitsPerComponent); + + if (pim->Interpolate) { + if (pim->BitsPerComponent * pie->num_planes == 1) + interpolate = 1; + else + interpolate = 3; + } + if (pim->ImageMask) { /* 1bit のとき */ + lputs(s, "0"); + } else { + if (index == gs_color_space_index_DeviceGray) + lputs(s, "0"); + else { + if (format == gs_image_format_chunky) /* RGBRGBRGB... */ + sputc(s, 0x3a); + else /* RRR...GGG...BBB... */ + sputc(s, 0x3b); + } + } + if (interpolate > 0) + sput_lips_int(s, interpolate); + sputc(s, LIPS_IS2); + } + return 0; +} + +/* Process the next piece of an image. */ +static int +lips4v_image_plane_data(gx_image_enum_common_t * info, + const gx_image_plane_t * planes, int height, + int *rows_used) +{ + gx_device *dev = info->dev; + gx_device_vector *const vdev = (gx_device_vector *) dev; + gx_device_lips4v *const pdev = (gx_device_lips4v *) dev; + gdev_vector_image_enum_t *pie = (gdev_vector_image_enum_t *) info; + + stream *s = gdev_vector_stream((gx_device_vector *) pdev); + int y; + + if (pdev->OneBitMask) { + /* + lputs(s, "\200"); + */ + pie->y += height; + return 1; + } + if (pie->default_info) + return gx_image_plane_data(pie->default_info, planes, height); + gx_image_plane_data(pie->bbox_info, planes, height); + { + int plane; + int width_bytes, tbyte; + byte *buf; + + width_bytes = + (pie->width * pie->bits_per_pixel / pdev->ncomp + + 7) / 8 * pdev->ncomp; + tbyte = width_bytes * height; + buf = gs_alloc_bytes(vdev->memory, tbyte, "lips4v_image_data(buf)"); + + for (plane = 0; plane < pie->num_planes; ++plane) + for (y = 0; y < height; ++y) { + memcpy(buf + y * width_bytes, + planes[plane].data + + ((planes[plane].data_x * pie->bits_per_pixel) >> 3) + + y * planes[plane].raster, width_bytes); + } + + lputs(s, "}Q10"); + + if ((pie->bits_per_pixel > 1 && pdev->ncomp == 1) || + pdev->MaskReverse == 0) { + lips4v_write_image_data(vdev, buf, tbyte, TRUE); + } else + lips4v_write_image_data(vdev, buf, tbyte, FALSE); + + gs_free_object(vdev->memory, buf, "lips4v_image_data(buf)"); + + } + + return (pie->y += height) >= pie->height; +} + +static int +lips4v_image_end_image(gx_image_enum_common_t * info, bool draw_last) +{ + gx_device *dev = info->dev; + gx_device_vector *const vdev = (gx_device_vector *) dev; + gx_device_lips4v *const pdev = (gx_device_lips4v *) dev; + gdev_vector_image_enum_t *pie = (gdev_vector_image_enum_t *) info; + stream *s = gdev_vector_stream((gx_device_vector *) pdev); + int code; + + if (pdev->OneBitMask) + pdev->OneBitMask = false; + else + lputs(s, "}Q1100"); + sputc(s, LIPS_IS2); /* End of Image */ + + pdev->MaskReverse = -1; + + code = gdev_vector_end_image(vdev, (gdev_vector_image_enum_t *) pie, + draw_last, pdev->white); + return code; +} |