/* Copyright (C) EPSON SOFTWARE DEVELOPMENT LABORATORY, INC. 1999,2000.
   Copyright (C) SEIKO EPSON CORPORATION 2000-2005.

   Ghostscript printer driver for EPSON ESC/Page and ESC/Page-Color.

   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.


 SPECIAL THANKS:

    本ドライバの作成にあたり、大森紀人さんの gdevlips, gdevl4v.c を参考に
    させて頂きました。


 NOTES:

  - About Ghostscript 5.10/5.50 BUGS
    Ghostscript 5.10/5.50 の Vector driver の setlinewidth 関数には
    バグがあります。本来スケールが変更されるにしたがって線の太さも変更され
    なければなりませんが、Ghostscript 5.10/5.50 ではスケールを考慮するのを
    忘れています。
    このドライバはそのバグを回避するためにスケールを自分で処理しています。

 */

#if ( 6 > GS_VERSION_MAJOR )

#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"
#include "gdevpstr.h"
#include "ghost.h"
#include "gzstate.h"
#include "imemory.h"
#include "igstate.h"
#include "gdevescv.h"
#include "gspath.h"
#include "gzpath.h"

#else /* 6 <= GS_VERSION_MAJOR */

#include <stdlib.h>		/* for abs() */
#include "math_.h"
#include "time_.h"
#include "memory_.h"
#include "gx.h"
#include "gserrors.h"
#include "gzpath.h"
#include "gxdevice.h"
#include "gdevvec.h"

#if ( 7 >= GS_VERSION_MAJOR )
#include "gscspace.h"
#endif

#include "gdevescv.h"

#endif /* GS_VERSION_MAJOR */

/* ---------------- Device definition ---------------- */

/* Device procedures */
private dev_proc_open_device(escv_open);
private dev_proc_output_page(escv_output_page);
private dev_proc_close_device(escv_close);
private dev_proc_copy_mono(escv_copy_mono);
private dev_proc_copy_color(escv_copy_color);
private dev_proc_put_params(escv_put_params);
private dev_proc_get_params(escv_get_params);
private dev_proc_fill_mask(escv_fill_mask);
private dev_proc_begin_image(escv_begin_image);


gs_public_st_suffix_add0_final(st_device_escv, gx_device_escv,
			       "gx_device_escv", device_escv_enum_ptrs, device_escv_reloc_ptrs,
			       gx_device_finalize, st_device_vector);


/* for ESC/Page-Color
** 原点の値を 0 とした場合,計算誤差？の問題から描画エリアが狂うため
** 原点を 0.001 としておく。
*/
#define escv_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(0.001, 0.001, lm, 0, 0, tm),\
        std_device_part3_()


/* for ESC/Page (Monochrome) */
#define esmv_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 / 72.0, -tm * ydpi / 72.0, 5.0 / (MMETER_PER_INCH / POINT),\
        0, 0, 5.0 / (MMETER_PER_INCH / POINT)), /* LPD.2.  041203 saito */\
        std_device_part3_()


/* for ESC/Page-Color */
#define escv_device_body(name)	\
  escv_device_full_body(gx_device_escv, 0, name, \
				&st_device_escv,\
/* width & height */		ESCPAGE_DEFAULT_WIDTH, ESCPAGE_DEFAULT_HEIGHT,\
/* default resolution */	X_DPI, Y_DPI,\
/* color info */		3, 24, 255, 255, 256, 256,\
				ESCPAGE_LEFT_MARGIN_DEFAULT,\
				ESCPAGE_BOTTOM_MARGIN_DEFAULT,\
				ESCPAGE_RIGHT_MARGIN_DEFAULT,\
				ESCPAGE_TOP_MARGIN_DEFAULT)


/* for ESC/Page (Monochrome) */
#define esmv_device_body(name)	\
  esmv_device_full_body(gx_device_escv, 0, name, \
				&st_device_escv,\
/* width & height */		ESCPAGE_DEFAULT_WIDTH, ESCPAGE_DEFAULT_HEIGHT,\
/* default resolution */	X_DPI, Y_DPI,\
/* color info */		1, 8, 255, 255, 256, 256,\
				ESCPAGE_LEFT_MARGIN_DEFAULT,\
				ESCPAGE_BOTTOM_MARGIN_DEFAULT,\
				ESCPAGE_RIGHT_MARGIN_DEFAULT,\
				ESCPAGE_TOP_MARGIN_DEFAULT)



#define escv_procs_part1 \
	escv_open,				/* open_device */\
	gx_default_get_initial_matrix,		/* get_initial_matrix */\
	NULL,					/* sync_output */\
	escv_output_page,			/* output_page */\
	escv_close				/* close_device */

#define escv_procs_part2 \
	gdev_vector_fill_rectangle,		/* fill_rectangle */\
	NULL,					/* tile_rectangle */\
	escv_copy_mono,				/* dev_t_proc_copy_mono */\
	escv_copy_color,			/* dev_t_proc_copy_color */\
	NULL,					/* draw_line */\
	NULL,					/* get_bits */\
	escv_get_params,			/* dev_t_proc_get_params */\
	escv_put_params,			/* dev_t_proc_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,		/* dev_t_proc_get_page_device */\
	NULL,					/* get_alpha_bits */\
	NULL,					/* copy_alpha */\
	NULL,					/* get_band */\
	NULL,					/* copy_rop */\
	gdev_vector_fill_path,			/* fill_path */\
	gdev_vector_stroke_path,		/* stroke_path */\
	escv_fill_mask,				/* fill_mask */\
	gdev_vector_fill_trapezoid,		/* fill_trapezoid */\
	gdev_vector_fill_parallelogram,		/* fill_parallelogram */\
	gdev_vector_fill_triangle,		/* fill_triangle */\
	NULL,	/****** WRONG ******/		/* draw_thin_line */\
	escv_begin_image,			/* begin_image */\
	NULL,					/* image_data */\
	NULL,					/* end_image */\
	NULL,					/* strip_tile_rectangle */\
	NULL					/******strip_copy_rop******/



/* for ESC/Page-Color */
#define escv_procs	\
{\
        escv_procs_part1,\
	gx_default_rgb_map_rgb_color, /* map_rgb_color */\
	gx_default_rgb_map_color_rgb, /* map_color_rgb */\
        escv_procs_part2\
}


/* for ESC/Page (Monochrome) */
#define esmv_procs	\
{\
        escv_procs_part1,\
	gx_default_gray_map_rgb_color, /* map_rgb_color */\
	gx_default_gray_map_color_rgb, /* map_color_rgb */\
        escv_procs_part2\
}


#define	escv_init_code_common \
	ESCPAGE_MANUALFEED_DEFAULT, /*   bool          manualFeed;     * Use manual feed *  */\
	ESCPAGE_CASSETFEED_DEFAULT, /*   int           cassetFeed;     * Input Casset *  */\
	ESCPAGE_RIT_DEFAULT,	/*   bool          RITOff;         * RIT Control * */\
	FALSE,			/*   bool          Collate; */\
	0,			/*   int           toner_density; */\
	FALSE,			/*   bool          toner_saving; */\
	0,			/*   int           prev_paper_size; */\
	0,			/*   int           prev_paper_width; */\
	0,			/*   int           prev_paper_height; */\
	0,			/*   int           prev_num_copies; */\
	-1,			/*   int           prev_feed_mode; */\
	0,			/*   int           orientation; */\
	ESCPAGE_FACEUP_DEFAULT,	/*   bool          faceup; */\
	ESCPAGE_MEDIATYPE_DEFAULT, /*   int           MediaType; */\
	0,			/*   bool          first_page; */\
	0,			/*   bool          Duplex; */\
	ESCPAGE_TUMBLE_DEFAULT,	/*   bool          Tumble; */\
	0,			/*   int           ncomp; */\
	0,			/*   int           MaskReverse; */\
	0,			/*   int           MaskState; */\
	TRUE,			/*   bool          c4map;          * 4bit ColorMap * */\
	TRUE,			/*   bool          c8map;          * 8bit ColorMap * */\
	0,			/*   int           prev_x; */\
	0,			/*   int           prev_y; */\
	0,			/*   gx_color_index        prev_color; */\
	0,			/*   gx_color_index        current_color; */\
	3,			/*   floatp        lwidth; */\
	0,			/*   long          cap; */\
	3,			/*   long          join; */\
	0,			/*   long          reverse_x; */\
	0,			/*   long          reverse_y; */\
       {0,},			/*   gs_matrix     xmat;		* matrix * */\
	0,			/*   int           bx; */\
	0,			/*   int           by; */\
	0,			/*   int           w;		* width * */\
	0,			/*   int           h;		* height * */\
	0,			/*   int           roll; */\
	0,			/*   float         sx;		* scale x * */\
	0,			/*   float         sy;		* scale y * */\
	0,			/*   long          dd; */\
       {0,}			/*   gx_bitmap_id  id_cache[VCACHE + 1];    * for Font Downloading * */


/* for ESC/Page-Color */
#define	escv_init_code \
        vector_initial_values,\
	1,                      /*   int           colormode;      1=ESC/Page-Color */\
        escv_init_code_common


/* for ESC/Page (Monochrome) */
#define	esmv_init_code \
        vector_initial_values,\
	0,                      /*   int           colormode;      0=ESC/Page(Monochrome) */\
        escv_init_code_common


/* for ESC/Page (Monochrome) */
gx_device_escv far_data gs_epl2050_device ={esmv_device_body("epl2050"), esmv_procs, esmv_init_code};
gx_device_escv far_data gs_epl2050p_device={esmv_device_body("epl2050p"),esmv_procs, esmv_init_code};
gx_device_escv far_data gs_epl2120_device ={esmv_device_body("epl2120"), esmv_procs, esmv_init_code};
gx_device_escv far_data gs_epl2500_device ={esmv_device_body("epl2500"), esmv_procs, esmv_init_code};
gx_device_escv far_data gs_epl2750_device ={esmv_device_body("epl2750"), esmv_procs, esmv_init_code};
gx_device_escv far_data gs_epl5800_device ={esmv_device_body("epl5800"), esmv_procs, esmv_init_code};
gx_device_escv far_data gs_epl5900_device ={esmv_device_body("epl5900"), esmv_procs, esmv_init_code};
gx_device_escv far_data gs_epl6100_device ={esmv_device_body("epl6100"), esmv_procs, esmv_init_code};
gx_device_escv far_data gs_epl6200_device ={esmv_device_body("epl6200"), esmv_procs, esmv_init_code};
gx_device_escv far_data gs_lp1800_device  ={esmv_device_body("lp1800"),  esmv_procs, esmv_init_code};
gx_device_escv far_data gs_lp1900_device  ={esmv_device_body("lp1900"),  esmv_procs, esmv_init_code};
gx_device_escv far_data gs_lp2200_device  ={esmv_device_body("lp2200"),  esmv_procs, esmv_init_code};
gx_device_escv far_data gs_lp2400_device  ={esmv_device_body("lp2400"),  esmv_procs, esmv_init_code};
gx_device_escv far_data gs_lp2500_device  ={esmv_device_body("lp2500"),  esmv_procs, esmv_init_code};
gx_device_escv far_data gs_lp7500_device  ={esmv_device_body("lp7500"),  esmv_procs, esmv_init_code};
gx_device_escv far_data gs_lp7700_device  ={esmv_device_body("lp7700"),  esmv_procs, esmv_init_code};
gx_device_escv far_data gs_lp7900_device  ={esmv_device_body("lp7900"),  esmv_procs, esmv_init_code};
gx_device_escv far_data gs_lp8100_device  ={esmv_device_body("lp8100"),  esmv_procs, esmv_init_code};
gx_device_escv far_data gs_lp8300f_device ={esmv_device_body("lp8300f"), esmv_procs, esmv_init_code};
gx_device_escv far_data gs_lp8400f_device ={esmv_device_body("lp8400f"), esmv_procs, esmv_init_code};
gx_device_escv far_data gs_lp8600_device  ={esmv_device_body("lp8600"),  esmv_procs, esmv_init_code};
gx_device_escv far_data gs_lp8600f_device ={esmv_device_body("lp8600f"), esmv_procs, esmv_init_code};
gx_device_escv far_data gs_lp8700_device  ={esmv_device_body("lp8700"),  esmv_procs, esmv_init_code};
gx_device_escv far_data gs_lp8900_device  ={esmv_device_body("lp8900"),  esmv_procs, esmv_init_code};
gx_device_escv far_data gs_lp9000b_device ={esmv_device_body("lp9000b"), esmv_procs, esmv_init_code};
gx_device_escv far_data gs_lp9100_device  ={esmv_device_body("lp9100"),  esmv_procs, esmv_init_code};
gx_device_escv far_data gs_lp9200b_device ={esmv_device_body("lp9200b"), esmv_procs, esmv_init_code};
gx_device_escv far_data gs_lp9300_device  ={esmv_device_body("lp9300"),  esmv_procs, esmv_init_code};
gx_device_escv far_data gs_lp9400_device  ={esmv_device_body("lp9400"),  esmv_procs, esmv_init_code};
gx_device_escv far_data gs_lp9600_device  ={esmv_device_body("lp9600"),  esmv_procs, esmv_init_code};
gx_device_escv far_data gs_lp9600s_device ={esmv_device_body("lp9600s"), esmv_procs, esmv_init_code};

/* for ESC/Page-Color */
gx_device_escv far_data gs_alc1900_device ={escv_device_body("alc1900"), escv_procs, escv_init_code};
gx_device_escv far_data gs_alc2000_device ={escv_device_body("alc2000"), escv_procs, escv_init_code};
gx_device_escv far_data gs_alc4000_device ={escv_device_body("alc4000"), escv_procs, escv_init_code};
gx_device_escv far_data gs_alc4100_device ={escv_device_body("alc4100"), escv_procs, escv_init_code};
gx_device_escv far_data gs_alc8500_device ={escv_device_body("alc8500"), escv_procs, escv_init_code};
gx_device_escv far_data gs_alc8600_device ={escv_device_body("alc8600"), escv_procs, escv_init_code};
gx_device_escv far_data gs_alc9100_device ={escv_device_body("alc9100"), escv_procs, escv_init_code};
gx_device_escv far_data gs_lp3000c_device ={escv_device_body("lp3000c"), escv_procs, escv_init_code};
gx_device_escv far_data gs_lp8000c_device ={escv_device_body("lp8000c"), escv_procs, escv_init_code};
gx_device_escv far_data gs_lp8200c_device ={escv_device_body("lp8200c"), escv_procs, escv_init_code};
gx_device_escv far_data gs_lp8300c_device ={escv_device_body("lp8300c"), escv_procs, escv_init_code};
gx_device_escv far_data gs_lp8500c_device ={escv_device_body("lp8500c"), escv_procs, escv_init_code};
gx_device_escv far_data gs_lp8800c_device ={escv_device_body("lp8800c"), escv_procs, escv_init_code};
gx_device_escv far_data gs_lp9000c_device ={escv_device_body("lp9000c"), escv_procs, escv_init_code};
gx_device_escv far_data gs_lp9200c_device ={escv_device_body("lp9200c"), escv_procs, escv_init_code};
gx_device_escv far_data gs_lp9500c_device ={escv_device_body("lp9500c"), escv_procs, escv_init_code};
gx_device_escv far_data gs_lp9800c_device ={escv_device_body("lp9800c"), escv_procs, escv_init_code};



/* Vector device implementation */
#if ( 6 > GS_VERSION_MAJOR )
private int escv_beginpage(P1(gx_device_vector * vdev));
private int escv_setfillcolor(P2(gx_device_vector * vdev, const gx_drawing_color * pdc));
private int escv_setstrokecolor(P2(gx_device_vector * vdev, const gx_drawing_color * pdc));
private int escv_setdash(P4(gx_device_vector * vdev, const float *pattern, 
			    uint count, floatp offset));
private int escv_setflat(P2(gx_device_vector * vdev, floatp flatness));
private int escv_setlogop(P3(gx_device_vector * vdev, gs_logical_operation_t lop, 
			     gs_logical_operation_t diff));
private int escv_vector_dorect(gx_device_vector * vdev, fixed x0, fixed y0, fixed x1,
			       fixed y1, gx_path_type_t type);
private int escv_vector_dopath(gx_device_vector * vdev, const gx_path * ppath,
			       gx_path_type_t type);
private int escv_beginpath(P2(gx_device_vector * vdev, gx_path_type_t type));
private int escv_moveto(P6(gx_device_vector * vdev, floatp x0, floatp y0,
			   floatp x, floatp y, gx_path_type_t type));
private int escv_lineto(P6(gx_device_vector * vdev, floatp x0, floatp y0,
			   floatp x, floatp y, gx_path_type_t type));
private int escv_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));
private int escv_closepath(P6(gx_device_vector * vdev, floatp x, floatp y,
			      floatp x_start, floatp y_start, gx_path_type_t type));

private int escv_endpath(P2(gx_device_vector * vdev, gx_path_type_t type));
private int escv_setlinewidth(gx_device_vector * vdev, floatp width);
private int escv_setlinecap(gx_device_vector * vdev, gs_line_cap cap);
private int escv_setlinejoin(gx_device_vector * vdev, gs_line_join join);
private int escv_setmiterlimit(gx_device_vector * vdev, floatp limit);

#else /* 6 <= GS_VERSION_MAJOR */

/* Page management */
private int escv_beginpage (gx_device_vector * vdev);
/* Imager state */
private int escv_setlinewidth (gx_device_vector * vdev, floatp width);
private int escv_setlinecap (gx_device_vector * vdev, gs_line_cap cap);
private int escv_setlinejoin (gx_device_vector * vdev, gs_line_join join);
private int escv_setmiterlimit (gx_device_vector * vdev, floatp limit);
private int escv_setdash (gx_device_vector * vdev, const float *pattern,
			  uint count, floatp offset);
private int escv_setflat (gx_device_vector * vdev, floatp flatness);
private int escv_setlogop (gx_device_vector * vdev, gs_logical_operation_t lop,
			   gs_logical_operation_t diff);
/* Other state */
#if ( 8 <= GS_VERSION_MAJOR )
private bool escv_can_handle_hl_color (gx_device_vector * vdev, const gs_imager_state * pis,
				       const gx_drawing_color * pdc);
private int escv_setfillcolor (gx_device_vector * vdev, const gs_imager_state * pis, 
			       const gx_drawing_color * pdc);
private int escv_setstrokecolor (gx_device_vector * vdev, const gs_imager_state * pis,
				 const gx_drawing_color * pdc);
#else
private int escv_setfillcolor (gx_device_vector * vdev, const gx_drawing_color * pdc);
private int escv_setstrokecolor (gx_device_vector * vdev, const gx_drawing_color * pdc);
#endif
/* Paths */
/* dopath and dorect are normally defaulted */
private int escv_vector_dopath (gx_device_vector * vdev, const gx_path * ppath,
				gx_path_type_t type, const gs_matrix *pmat);
private int escv_vector_dorect (gx_device_vector * vdev, fixed x0, fixed y0, fixed x1,
				fixed y1, gx_path_type_t type);
private int escv_beginpath (gx_device_vector * vdev, gx_path_type_t type);
private int escv_moveto (gx_device_vector * vdev, floatp x0, floatp y0,
			 floatp x, floatp y, gx_path_type_t type);
private int escv_lineto (gx_device_vector * vdev, floatp x0, floatp y0,
			 floatp x, floatp y, gx_path_type_t type);
private int escv_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);
private int escv_closepath (gx_device_vector * vdev, floatp x0, floatp y0,
			    floatp x_start, floatp y_start, gx_path_type_t type);
private int escv_endpath (gx_device_vector * vdev, gx_path_type_t type);

#endif /* GS_VERSION_MAJOR */

private const gx_device_vector_procs escv_vector_procs =
  {
    /* Page management */
    escv_beginpage,
    /* Imager state */
    escv_setlinewidth,
    escv_setlinecap,
    escv_setlinejoin,
    escv_setmiterlimit,
    escv_setdash,
    escv_setflat,
    escv_setlogop,
    /* Other state */
#if ( 8 <= GS_VERSION_MAJOR )
    escv_can_handle_hl_color,	/* add gs815 */
#endif
    escv_setfillcolor,	/* fill & stroke colors are the same */
    escv_setstrokecolor,
    /* Paths */
    escv_vector_dopath,
    escv_vector_dorect,
    escv_beginpath,
    escv_moveto,
    escv_lineto,
    escv_curveto,
    escv_closepath,
    escv_endpath
  };

private void escv_write_begin(gx_device *dev, int bits, int x, int y, int sw, int sh, int dw, int dh, int roll);
private void escv_write_data(gx_device *dev, int bits, char *buf, int bsize, int w, int ras);
private void escv_write_end(gx_device *dev, int bits);


/* ---------------- Utilities ---------------- */

/* Put a string on a stream.
   This function is copy of `pputs' in gdevpstr.c */
private int
lputs(stream * s, const char *str)
{
  uint	len = strlen(str);
  uint	used;
  int		status;

  status = sputs(s, (const byte *)str, len, &used);

  return (status >= 0 && used == len ? 0 : EOF);
}

/* Write a string on a stream. */
private void
put_bytes(stream * s, const byte * data, uint count)
{
  uint used;

  sputs(s, data, count, &used);
}


private int
escv_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 < ESCPAGE_WIDTH_MIN ||
	 width > ESCPAGE_WIDTH_MAX ||
	 height < ESCPAGE_HEIGHT_MIN ||
	 height > ESCPAGE_HEIGHT_MAX)) {
      return_error(gs_error_rangecheck);
    }
  } else {			/* landscape */
    if ((width < ESCPAGE_HEIGHT_MIN ||
	 width > ESCPAGE_HEIGHT_MAX ||
	 height < ESCPAGE_WIDTH_MIN ||
	 height > ESCPAGE_WIDTH_MAX )) {
      return_error(gs_error_rangecheck);
    }
  }

  /* Resolution Check */
  if (xdpi != ydpi) {
    return_error(gs_error_rangecheck);
  }

  if ((xdpi < ESCPAGE_DPI_MIN ||
       xdpi > ESCPAGE_DPI_MAX)) {
    return_error(gs_error_rangecheck);
  }

  return 0;			/* pass */
}


/* ---------------- Vector device implementation ---------------- */

private int
escv_vector_dopath(gx_device_vector * vdev, const gx_path * ppath,
		   gx_path_type_t type
#if ( 6 <= GS_VERSION_MAJOR )
		   , const gs_matrix *pmat
#endif
		   )
{
  bool do_close = (type & gx_path_type_stroke) != 0;
  gs_fixed_rect rect;
  gs_point scale;
  double x_start = 0, y_start = 0, x_prev = 0, y_prev = 0;
  bool first = true;
  gs_path_enum cenum;
  int code;

  stream	*s = gdev_vector_stream(vdev);
  char	obuf[128];

  if (gx_path_is_rectangle(ppath, &rect))
    return (*vdev_proc(vdev, dorect)) (vdev, rect.p.x, rect.p.y, rect.q.x, rect.q.y, type);
  scale = vdev->scale;
  code = (*vdev_proc(vdev, beginpath)) (vdev, type);
  gx_path_enum_init(&cenum, ppath);

  for (;;) {
    double	x, y;
    fixed	vs[6];
    int	pe_op, cnt;
    const segment *pseg;


    pe_op = gx_path_enum_next(&cenum, (gs_fixed_point *) vs);

  sw:switch (pe_op) {
  case 0:		/* done */
    return (*vdev_proc(vdev, endpath)) (vdev, type);

  case gs_pe_moveto:
    x = fixed2float(vs[0]) / scale.x;
    y = fixed2float(vs[1]) / scale.y;

    /* サブパス開始命令 p1 */
    (void)sprintf(obuf, ESC_GS "0;%d;%dmvpG", (int)x, (int)y);
    lputs(s, obuf);

    if (first)
      x_start = x, y_start = y, first = false;
    break;

  case gs_pe_lineto:
    cnt = 1;
    for (pseg = cenum.pseg; pseg != 0 && pseg->type == s_line; cnt++, pseg = pseg->next);

    (void)sprintf(obuf, ESC_GS "0;%d", cnt);
    lputs(s, obuf);

    do {
      (void)sprintf(obuf, ";%d;%d",
		    (int)(fixed2float(vs[0]) / scale.x),
		    (int)(fixed2float(vs[1]) / scale.y));
      lputs(s, obuf);

      pe_op = gx_path_enum_next(&cenum, (gs_fixed_point *) vs);
    } while (pe_op == gs_pe_lineto);

    /* パス・ポリライン命令 */
    lputs(s, "lnpG");

    goto sw;

  case gs_pe_curveto:
    cnt = 1;
    for (pseg = cenum.pseg; pseg != 0 && pseg->type == s_curve; cnt++, pseg = pseg->next);
    (void)sprintf(obuf, ESC_GS "0;%d", cnt * 3);
    lputs(s, obuf);

    do {
      (void)sprintf(obuf, ";%d;%d;%d;%d;%d;%d",
		    (int)(fixed2float(vs[0]) / scale.x), (int)(fixed2float(vs[1]) / scale.y),
		    (int)(fixed2float(vs[2]) / scale.x), (int)(fixed2float(vs[3]) / scale.y),
		    (int)(fixed2float(vs[4]) / scale.x), (int)(fixed2float(vs[5]) / scale.y));
      lputs(s, obuf);

      pe_op = gx_path_enum_next(&cenum, (gs_fixed_point *) vs);
    } while (pe_op == gs_pe_curveto);

    /* ベジェ曲線 */
    lputs(s, "bzpG");

    goto sw;

  case gs_pe_closepath:
    x = x_start, y = y_start;
    if (do_close) {
      lputs(s, ESC_GS "clpG");
      break;
    }

    pe_op = gx_path_enum_next(&cenum, (gs_fixed_point *) vs);
    if (pe_op != 0) {
      lputs(s, ESC_GS "clpG");

      if (code < 0)
	return code;
      goto sw;
    }
    return (*vdev_proc(vdev, endpath)) (vdev, type);
  default:		/* can't happen */
    return_error(gs_error_unknownerror);
  }
    if (code < 0)
      return code;
    x_prev = x, y_prev = y;
  }
}


private int
escv_vector_dorect(gx_device_vector * vdev, fixed x0, fixed y0, fixed x1,
		   fixed y1, gx_path_type_t type)
{
  int		code;
  char	obuf[128];
  gs_point	scale;
  stream	*s = gdev_vector_stream(vdev);

  code = (*vdev_proc(vdev, beginpath))(vdev, type);
  if (code < 0)
    return code;

  scale = vdev->scale;

  (void)sprintf(obuf, ESC_GS "0;%d;%d;%d;%d;0;0rrpG",
		(int)(fixed2float(x0) / scale.x),
		(int)(fixed2float(y0) / scale.y),
		(int)(fixed2float(x1) / scale.x),
		(int)(fixed2float(y1) / scale.y));
  lputs(s, obuf);

#if 0
  /* Ghostscript 側のバグで closepath を呼んでいないので処理を会わせる。 */

  /* 本来は (*vdev_proc(vdev, closepath))() を呼ぶべき */
  lputs(s, ESC_GS "clpG");
#endif

  return (*vdev_proc(vdev, endpath))(vdev, type);
}


/* ---------- */

private const EPaperTable ePaperTable[NUM_OF_PAPER_TABLES] =
  {
    {933, 1369, 72, "A3PLUS"},	/* A3 NOBI */
    {842, 1191, 13, "A3"},	/* A3 */
    {792, 1224, 36, "B"},	/* Ledger */
    {729, 1032, 24, "B4"},	/* B4 JIS */
    {709, 1001, 24, "B4"},	/* B4 */
    {612, 1008, 32, "LGL"},	/* Legal */
    {612,  936, 34, "GLG"},	/* Government Letter */ /* LPD.1. */
    {612,  792, 30, "LT"},	/* Letter */
    {595,  935, 37, "F4"},	/* F4 */
    {595,  842, 14, "A4"},	/* A4 */
    {576,  756, 35, "GLT"},	/* Government Legal */ /* LPD.1. */
    {522,  756, 33, "EXE"},	/* Executive */
    {516,  729, 25, "B5"},	/* B5 JIS */
    {499,  709, 99, "IB5"},	/* Envelope ISO B5 */
    {459,  649, 91, "C5"},	/* Envelope C5 */
    {420,  595, 15, "A5"},	/* A5 */
    {396,  612, 31, "HLT"},	/* Half Letter */
    {312,  624, 90, "DL"},	/* DL */
    {298,  666, 64, "YOU4"},	/* Japanese Envelope You4 */
    {297,  684, 81, "C10"},	/* Commercial 10 */
    {283,  420, 38, "POSTCARD"},/* PostCard */
    {279,  540, 80, "MON"},	/* Monarch */
    {  0,    0, -1, ""}		/* Undefined */
  };

private const EPaperTable *
escv_checkpapersize(gx_device_vector * vdev)
{
  gx_device_escv	*const pdev = (gx_device_escv *)vdev;
  int			devw, devh;
  paper_candidate	candidate[NUM_OF_PAPER_TABLES];
  int			num_candidate;

  
  if (pdev->MediaSize[0] < pdev->MediaSize[1]) {
    /* portrait */
    devw = pdev->MediaSize[0];
    devh = pdev->MediaSize[1];
  } else {
    /* landscape */
    devw = pdev->MediaSize[1];
    devh = pdev->MediaSize[0];
  }

  /* pick up papersize candidate */
  {
    const EPaperTable *pt;
    int delta;

    num_candidate = 0;

    for (delta = 0; delta <= MAX_PAPER_SIZE_DELTA; delta++) {
      for (pt = ePaperTable; 0 <= pt->escpage; pt++) {
	if ( (pt->width  + delta) >= devw &&
	     (pt->width  - delta) <= devw &&
	     (pt->height + delta) >= devh &&
	     (pt->height - delta) <= devh) {

	  candidate[num_candidate].paper = pt;
	  candidate[num_candidate].absw = abs(pt->width  - devw);
	  candidate[num_candidate].absh = abs(pt->height - devh);
	  candidate[num_candidate].score = 0;
	  candidate[num_candidate].isfillw = false;
	  candidate[num_candidate].isfillh = false;
	  candidate[num_candidate].isminw  = false;
	  candidate[num_candidate].isminh  = false;

	  if( 0 <= (pt->width - devw) ){
	    candidate[num_candidate].isfillw = true;
	  }
	  if( 0 <= (pt->height - devh) ){
	    candidate[num_candidate].isfillh = true;
	  }
	  num_candidate++;
	}
      }
      if ( 0 < num_candidate ) {
	break;
      }
    }
  }
  
  /* no papersize match, so use default paper size */
  if ( 0 == num_candidate  ) {
    return (const EPaperTable *)0;		/* not found */
  }

  if ( 1 == num_candidate ) {
    return candidate[0].paper; /* find */
  }

  /* search abstruct minw & minh */
  {
    int absminw;
    int absminh;
    int i;

    absminw = candidate[0].absw;
    absminh = candidate[0].absh;
    for (i = 1; i < num_candidate; i++) {
      if (absminw > candidate[i].absw) {
	absminw = candidate[i].absw;
      }
      if (absminh > candidate[i].absh) {
	absminh = candidate[i].absh;
      }
    }

    /* check isminw & isminh flag */
    for (i = 0; i < num_candidate; i++) {
      if (absminw == candidate[i].absw) {
	candidate[i].isminw = true;
      }
      if (absminh == candidate[i].absh) {
	candidate[i].isminh = true;
      }
    }

    /* add score */
    for (i = 0; i < num_candidate; i++) {
      if (candidate[i].isminw == true) {
	candidate[i].score += 100;
      }
      if (candidate[i].isminh == true) {
	candidate[i].score += 100;
      }
      if (candidate[i].isfillw == true) {
	candidate[i].score += 10;
      }
      if (candidate[i].isfillh == true) {
	candidate[i].score += 10;
      }
      if (absminw < absminh) {
	if (candidate[i].isminw == true) {
	  candidate[i].score += 1;
	}
      } else {
	if (candidate[i].isminh == true) {
	  candidate[i].score += 1;
	}
      }
    }
  }

  /* select highest score papersize */
  {
    int best_candidate;
    int i;

    best_candidate = 0;
    for (i = 1; i < num_candidate; i++) {
      if ( candidate[best_candidate].score <= candidate[i].score ) {
	best_candidate = i;
      }
    }
    return candidate[best_candidate].paper;
  }
}

private int
escv_beginpage(gx_device_vector * vdev)
{
  gx_device_escv	*const pdev = (gx_device_escv *)vdev;

  if (pdev -> first_page) {

    /* not use gdev_vector_stream */
    stream		*s = vdev->strm;
    char		ebuf[1024];
    int                 MaxRes;
    int                 Local;
    int                 Duplex;
    int                 FaceUp;

    const struct {
      const char *name;
      const int resolution;
      const int locale;
      const int duplex;
      const int faceup;
    } model_resource[] = {
      /* model, resolution, loca,deplex,faceup */
      { "alc1900", RES600,  ENG, TRUE,  FALSE },
      { "alc2000", RES600,  ENG, TRUE,  FALSE },
      { "alc4000", RES1200, ENG, TRUE,  FALSE },
      { "alc4100", RES600,  ENG, TRUE,  FALSE },
      { "alc8500", RES600,  ENG, TRUE,  TRUE },
      { "alc8600", RES600,  ENG, TRUE,  TRUE },
      { "alc9100", RES600,  ENG, TRUE,  TRUE },
      { "epl2050", RES1200, ENG, TRUE,  FALSE },
      { "epl2050p",RES1200, ENG, TRUE,  FALSE },
      { "epl2120", RES1200, ENG, TRUE,  FALSE },
      { "epl2500", RES600,  ENG, TRUE,  FALSE },
      { "epl2750", RES600,  ENG, TRUE,  FALSE },
      { "epl5800", RES1200, ENG, FALSE, FALSE },
      { "epl5900", RES1200, ENG, FALSE, FALSE },
      { "epl6100", RES1200, ENG, FALSE, FALSE },
      { "epl6200", RES1200, ENG, FALSE, FALSE },
      { "lp1800",  RES600,  JPN, FALSE, FALSE },
      { "lp1900",  RES1200, JPN, FALSE, FALSE },
      { "lp2200",  RES1200, JPN, FALSE, FALSE },
      { "lp2400",  RES1200, JPN, FALSE, FALSE },
      { "lp2500",  RES1200, JPN, FALSE, FALSE },
      { "lp3000c", RES600,  JPN, TRUE,  FALSE },
      { "lp7500",  RES600,  JPN, TRUE,  FALSE },
      { "lp7700",  RES600,  JPN, TRUE,  FALSE },
      { "lp7900",  RES600,  JPN, TRUE,  FALSE },
      { "lp8000c", RES600,  JPN, FALSE, TRUE },
      { "lp8100",  RES600,  JPN, TRUE,  FALSE },
      { "lp8200c", RES600,  JPN, FALSE, TRUE },
      { "lp8300c", RES600,  JPN, TRUE,  TRUE },
      { "lp8300f", RES600,  JPN, TRUE,  FALSE },
      { "lp8400f", RES600,  JPN, TRUE,  FALSE },
      { "lp8500c", RES600,  JPN, TRUE,  TRUE },
      { "lp8600",  RES600,  JPN, TRUE,  FALSE },
      { "lp8600f", RES600,  JPN, TRUE,  FALSE },
      { "lp8700",  RES1200, JPN, TRUE,  FALSE },
      { "lp8800c", RES600,  JPN, TRUE,  TRUE },
      { "lp8900",  RES600,  JPN, TRUE,  FALSE },
      { "lp9000b", RES600,  JPN, TRUE,  FALSE },
      { "lp9000c", RES600,  JPN, TRUE,  FALSE },
      { "lp9100",  RES600,  JPN, TRUE,  FALSE },
      { "lp9200b", RES600,  JPN, TRUE,  FALSE },
      { "lp9200c", RES600,  JPN, TRUE,  FALSE },
      { "lp9300",  RES600,  JPN, TRUE,  FALSE },
      { "lp9400",  RES600,  JPN, TRUE,  FALSE },
      { "lp9500c", RES600,  JPN, TRUE,  TRUE },
      { "lp9600",  RES600,  JPN, TRUE,  FALSE },
      { "lp9600s", RES600,  JPN, TRUE,  FALSE },
      { "lp9800c", RES600,  JPN, TRUE,  TRUE },
      { "",        -1,      -1,  FALSE, FALSE }
    };

    /* set default */
    MaxRes = RES600;
    Local  = JPN;
    Duplex = FALSE;
    FaceUp = FALSE;



    lputs(s, "\033\001@EJL \012");
    {
      char   str[32];
      time_t t;
      size_t i;
      struct tm *tm;

      time(&t);
      tm =  localtime( (const time_t *) &t );

      i = strftime(str, 6, "%M", (const struct tm *)tm);

      if ( 6 >= i ) {
	str[i] = '\0';
	lputs(s, "@EJL SJ ID=\"");
	lputs(s, str);
	lputs(s, "\"\012");

	lputs(s, "@EJL JI ID=\"");
	lputs(s, str);
	lputs(s, "\"\012");

	i = strftime(str, 30, "%Y/%m/%d %H:%M:%S", (const struct tm *)tm);
	if ( 30 >= i ) {
	  str[i] = '\0';
	  lputs(s, "@EJL JI DATE=\"");
	  lputs(s, str);
	  lputs(s, "\"\012");
	}

      } else {
	lputs(s, "@EJL SJ ID=\"Ghostscript\"\012");
      }
    }

    lputs(s, "@EJL JI OS=\"Linux\"\012");

    {
      int i;

      for ( i = 0; (-1) != model_resource[i].resolution; i++ ) {
	if ( 0 == strcmp( pdev->dname, model_resource[i].name ) )
	  break;
      }

      if ( (-1) != model_resource[i].resolution ) {
	MaxRes = model_resource[i].resolution;
	Local  = model_resource[i].locale;
	Duplex = model_resource[i].duplex;
	FaceUp = model_resource[i].faceup;

	lputs(s, "@EJL JI PRINTER=\"");
	lputs(s, model_resource[i].name);
	lputs(s, "\" DRIVER=\"");
	lputs(s, model_resource[i].name);
	lputs(s, "\"\012");

      }
    }

    lputs(s, "@EJL CO DRIVER=\"GS-LPD 3.2.0\"\012");

    lputs(s, "@EJL SE LA=ESC/PAGE\012");

    lputs(s, "@EJL SET");

    /* Resolusion */
    if (vdev->x_pixels_per_inch == 1200){
      if (MaxRes == 1200){
	lputs(s, " RS=1200");
      } else {
	lputs(s, " RS=FN");
      }
    } else if (vdev->x_pixels_per_inch == 600) {
      lputs(s, " RS=FN");
    } else {
      lputs(s, " RS=QK");
    }

    /* Output Unit */
    if ((pdev->faceup && FaceUp) || (pdev->MediaType && FaceUp)) {
      lputs(s, " OU=FU");
    } else {
      lputs(s, " OU=FD");
    }

    /* Paper unit */
    if (pdev->MediaType){
      if (Local == ENG){
	lputs(s, " PU=1");
      } else {
	lputs(s, " PU=15");
      }
    }else{
      if (pdev->manualFeed) {
	if (Local == ENG){
	  lputs(s, " PU=1");
	} else {
	  lputs(s, " PU=15");
	}
      } else if (pdev->cassetFeed) {
	(void)sprintf(ebuf, " PU=%d", pdev->cassetFeed);
	lputs(s, ebuf);
      } else {
	lputs(s, " PU=AU");
      }
    }

    if (Duplex && pdev->Duplex) {
      /* Duplex ON */
      lputs(s, " DX=ON");

      /* binding type */
      if (pdev->Tumble) {
	lputs(s, " BD=SE");
      } else {
	lputs(s, " BD=LE");
      }
    } else {
      /* Duplex off */
      lputs(s, " DX=OFF");
    }

    /* Number of copies */
    if (pdev->NumCopies) {
      if (pdev->NumCopies >= 1000) {
	pdev->NumCopies = 999;
      }

      /* lp8000c not have QT */
      if (strcmp(pdev->dname, "lp8000c") == 0) {
	(void)sprintf(ebuf, " QT=1 CO=%d", pdev->NumCopies);
      } else {
	if (pdev->Collate) {
	  /* CO is 1, when set QT */
	  (void)sprintf(ebuf, " QT=%d CO=1", pdev->NumCopies);
	} else {
	  /* QT is 1, when not specified QT */
	  (void)sprintf(ebuf, " QT=1 CO=%d", pdev->NumCopies);
	}
      }
      lputs(s, ebuf);
    } else {
      lputs(s, " QT=1 CO=1");
    }

    if (pdev->toner_density) {
      (void)sprintf(ebuf, " DL=%d", pdev->toner_density);
      lputs(s, ebuf);
    }

    if (pdev->orientation) {
      lputs(s, " OR=LA");
    }

    if (pdev->toner_saving) {
      lputs(s, " SN=ON");
    }

    if (pdev->RITOff) {
      lputs(s, " RI=OFF");
    } else {
      lputs(s, " RI=ON");
    }

    if (pdev->MediaType == 1) {
      lputs(s, " PK=TH");
    } else if (pdev->MediaType == 2) {
      lputs(s, " PK=TR");
    } else {
      lputs(s, " PK=NM");
    }

    lputs(s, " PS=");
    {
      const EPaperTable *pt;

      pt = escv_checkpapersize(vdev);
      if ( 0 == pt ) {
	lputs(s, "A4");
      } else {
	lputs(s, pt->name);
      }
    }


    if( 0 == pdev->colormode ) { /* ESC/Page (Monochrome) */

#define	START_CODE1	ESC_GS "1tsE" ESC_GS "1owE" ESC_GS "0alfP" ESC_GS "0affP" ESC_GS "0;0;0clfP" ESC_GS "0pmP" ESC_GS "1024ibI" ESC_GS "2cmE" ESC_GS "0bcI" ESC_GS "1;10mlG"

#define	STRAT_CODE	ESC_GS "1mmE" ESC_GS "1csE"

      lputs(s, " ZO=OFF EC=ON SZ=OFF SL=YES TO=0.0MM LO=0.0MM\012");
      lputs(s, "@EJL EN LA=ESC/PAGE\012");

      lputs(s, ESC_GS "rhE");

      lputs(s, STRAT_CODE);

      if (vdev->x_pixels_per_inch == 1200) {
	/* 1200 dpi */
	lputs(s, ESC_GS "0;0.06muE");
	lputs(s, ESC_GS "1;45;156htmE");
	lputs(s, ESC_GS "9;1200;1200drE" ESC_GS "2;1200;1200drE" ESC_GS "1;1200;1200drE" ESC_GS "0;1200;1200drE");
	lputs(s, ESC_GS "1;1;raE");
      } else if (vdev->x_pixels_per_inch == 600) {
	/* 600 dpi */
	lputs(s, ESC_GS "0;0.12muE");
	lputs(s, ESC_GS "1;45;106htmE");
	lputs(s, ESC_GS "9;600;600drE" ESC_GS "2;600;600drE" ESC_GS "1;600;600drE" ESC_GS "0;600;600drE");
      } else {
	/* 300 dpi */
	lputs(s, ESC_GS "0;0.24muE");
	lputs(s, ESC_GS "1;45;71htmE");
	lputs(s, ESC_GS "9;300;300drE" ESC_GS "2;300;300drE" ESC_GS "1;300;300drE" ESC_GS "0;300;300drE");
      }

      lputs(s, START_CODE1);

      lputs(s, ESC_GS "0sarG");		/* 絶対座標指定 */
      /*	lputs(s, ESC_GS "1owE");*/

    } else {			/* ESC/Page-Color */

#define	COLOR_START_CODE1	ESC_GS "1tsE" ESC_GS "0alfP" ESC_GS "0affP" ESC_GS "0;0;0clfP" ESC_GS "0pmP" ESC_GS "1024ibI" ESC_GS "2cmE" ESC_GS "0bcI" ESC_GS "1;10mlG"

#define	LP8000_CODE	ESC_GS "0pddO" ESC_GS "0;0mmE" ESC_GS "2csE" ESC_GS "0;1;3cmmE" ESC_GS "0;1raE" ESC_GS "0;2;4ccmE"

#define	LP8200_CODE	ESC_GS "0pddO" ESC_GS "0;0cmmE" ESC_GS "1;2;3ccmE" ESC_GS "2;2;3ccmE" ESC_GS "3;2;4ccmE" ESC_GS "1;1raE" ESC_GS "2;1raE" ESC_GS "3;1raE"


      lputs(s, " ZO=OFF EC=ON SZ=OFF SL=YES TO=0 LO=0\012");
      lputs(s, "@EJL EN LA=ESC/PAGE-COLOR\012");

      lputs(s, ESC_GS "rhE");

      if (strcmp(vdev -> dname, "lp8000c") == 0) {
	lputs(s, LP8000_CODE);
      } else {
	lputs(s, LP8200_CODE);
      }

      put_bytes(s, ESC_GS "7;0;2;0cam{E\012\000\000\000\000\000\000", 20);
      lputs(s, ESC_GS "0;0cmmE");

      if (vdev->x_pixels_per_inch == 1200) {
	/* 1200 dpi */
	lputs(s, ESC_GS "0;0.06muE");
	lputs(s, ESC_GS "3;1200;1200drE" ESC_GS "2;1200;1200drE" ESC_GS "1;1200;1200drE" ESC_GS "0;1200;1200drE");
      } else if (vdev->x_pixels_per_inch == 600) {
	/* 600 dpi */
	lputs(s, ESC_GS "0;0.12muE");
	lputs(s, ESC_GS "3;600;600drE" ESC_GS "2;600;600drE" ESC_GS "1;600;600drE" ESC_GS "0;600;600drE");
      } else {
	/* 300 dpi */
	lputs(s, ESC_GS "0;0.24muE");
	lputs(s, ESC_GS "3;300;300drE" ESC_GS "2;300;300drE" ESC_GS "1;300;300drE" ESC_GS "0;300;300drE");
      }
      lputs(s, ESC_GS "0;0loE");

/*    lputs(s, ESC_GS "0poE"); *//* for TEST */

      lputs(s, COLOR_START_CODE1);
      lputs(s, ESC_GS "8;1;2;2;2plr{E");
      put_bytes(s, "\377\377\377\377\000\000\000\000", 8);

      lputs(s, ESC_GS "0sarG");		/* 絶対座標指定 */
      lputs(s, ESC_GS "2;204wfE");		/* rop 指定 */

    }	/* ESC/Page-Color */

  }
    
  return 0;
}


private int
escv_setlinewidth(gx_device_vector * vdev, floatp width)
{
  stream			*s = gdev_vector_stream(vdev);
  gx_device_escv *const	pdev = (gx_device_escv *) vdev;
  char			obuf[64];

#if GS_VERSION_MAJOR == 5
  /* Scale を掛けているのは, Ghostscript 5.10/5.50 のバグのため */
  floatp 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 (width < 1) width = 1;

  /* ESC/Page では線幅／終端／接合部の設定は１つのコマンドになっているため保持しておく。 */
  pdev -> lwidth = width;

  (void)sprintf(obuf, ESC_GS "%d;%d;%dlwG",
		(int)(pdev -> lwidth),
		(int)(pdev -> cap),
		(int)(pdev -> join));
  lputs(s, obuf);

  return 0;
}


private int
escv_setlinecap(gx_device_vector * vdev, gs_line_cap cap)
{
  stream			*s = gdev_vector_stream(vdev);
  gx_device_escv *const	pdev = (gx_device_escv *) vdev;
  char			obuf[64];

  /* ESC/Page では線幅／終端／接合部の設定は１つのコマンドになっているため保持しておく。 */
  pdev -> cap = cap;

  if (pdev -> cap >= 3) return -1;

  (void)sprintf(obuf, ESC_GS "%d;%d;%dlwG",
		(int)(pdev -> lwidth),
		(int)(pdev -> cap),
		(int)(pdev -> join));
  lputs(s, obuf);

  return 0;
}


private int
escv_setlinejoin(gx_device_vector * vdev, gs_line_join join)
{
  stream			*s = gdev_vector_stream(vdev);
  gx_device_escv *const	pdev = (gx_device_escv *) vdev;
  char			obuf[64];

  /* ESC/Page では線幅／終端／接合部の設定は１つのコマンドになっているため保持しておく。 */
  switch (join) {
  case 0:
    pdev -> join = 3;		/* miter */
    break;
  case 1:
    pdev -> join = 1;		/* round */
    break;
  case 2:
    pdev -> join = 2;		/* bevel */
    break;
  default:
    return -1;
  }

  (void)sprintf(obuf, ESC_GS "%d;%d;%dlwG",
		(int)(pdev -> lwidth),
		(int)(pdev -> cap),
		(int)(pdev -> join));
  lputs(s, obuf);

  return 0;
}


private int
escv_setmiterlimit(gx_device_vector * vdev, floatp limit)
{
  stream			*s = gdev_vector_stream(vdev);
  gx_device_escv *const	pdev = (gx_device_escv *) vdev;
  char			obuf[128];

  /* マイターリミット値を設定するには lwG にて 接合部指定(n3) が 3 になっている
  ** 必要がある。
  */
  if (pdev -> join != 3) {
    /* 強制的に接合部指定を行う */
    pdev -> join = 3;
    (void)sprintf(obuf, ESC_GS "%d;%d;%dlwG",
		  (int)(pdev -> lwidth),
		  (int)(pdev -> cap),
		  (int)(pdev -> join));
    lputs(s, obuf);
  }

  (void)sprintf(obuf, ESC_GS "1;%dmlG", (int)limit);
  lputs(s, obuf);

  return 0;
}


#if ( 8 <= GS_VERSION_MAJOR )
private bool
escv_can_handle_hl_color(gx_device_vector * vdev, const gs_imager_state * pis, 
                         const gx_drawing_color * pdc)
{
  return false;
}
#endif


private int
escv_setfillcolor(gx_device_vector * vdev,
#if ( 8 <= GS_VERSION_MAJOR )
		  const gs_imager_state * pis,
#endif
		  const gx_drawing_color * pdc)
{
  stream			*s = gdev_vector_stream(vdev);
  gx_device_escv *const	pdev = (gx_device_escv *) vdev;
  gx_color_index		color = gx_dc_pure_color(pdc);
  char			obuf[64];

  if (!gx_dc_is_pure(pdc)) return_error(gs_error_rangecheck);
  pdev->current_color = color;

  if( 0 == pdev->colormode ) { /* ESC/Page (Monochrome) */

    (void)sprintf(obuf, /*ESC_GS "1owE"*/ ESC_GS "0;0;100spE" ESC_GS "1;0;%ldccE" ,color);
    lputs(s, obuf);

    if (vdev->x_pixels_per_inch == 1200) {
      lputs(s, ESC_GS "1;45;156htmE");
    } else if (vdev->x_pixels_per_inch == 600) {
      lputs(s, ESC_GS "1;45;106htmE");
    } else {
      lputs(s, ESC_GS "1;45;71htmE");
    }

  } else {			/* ESC/Page-Color */


    /* パターンＯＮ指定／ソリッドパターン指定 */
    (void)sprintf(obuf, ESC_GS "1;2;3;%d;%d;%dfpE",
		  (unsigned char)(color >> 16 & 0xff),
		  (unsigned char)(color >> 8 & 0xff),
		  (unsigned char)(color & 0xff));
    lputs(s, obuf);
    lputs(s, ESC_GS "3;2;1;0;0cpE" ESC_GS "1;2;1;0;0cpE" ESC_GS "5;2;1;0;0cpE");

  }	/* ESC/Page-Color */

  return 0;
}


private int
escv_setstrokecolor(gx_device_vector * vdev,
#if ( 8 <= GS_VERSION_MAJOR )
		    const gs_imager_state * pis,
#endif
		    const gx_drawing_color * pdc)
{
  stream			*s = gdev_vector_stream(vdev);
  gx_device_escv *const	pdev = (gx_device_escv *) vdev;
  gx_color_index		color = gx_dc_pure_color(pdc);
  char			obuf[64];

  if (!gx_dc_is_pure(pdc)) return_error(gs_error_rangecheck);

  if( 0 == pdev->colormode ) { /* ESC/Page (Monochrome) */

    pdev->current_color = color;

    (void)sprintf(obuf, /*ESC_GS "1owE"*/ ESC_GS "0;0;100spE" ESC_GS "1;1;%ldccE" , color);
    lputs(s, obuf);

    if (vdev->x_pixels_per_inch == 1200) {
      lputs(s, ESC_GS "1;45;156htmE");
    } else if (vdev->x_pixels_per_inch == 600) {
      lputs(s, ESC_GS "1;45;106htmE");
    } else {
      lputs(s, ESC_GS "1;45;71htmE");
    }

  } else {			/* ESC/Page-Color */

    if (vdev->color_info.depth == 24) {

      pdev->current_color = color;
      /* パターンＯＮ色指定／ソリッドパターン指定 */
      (void)sprintf(obuf, ESC_GS "1;2;3;%d;%d;%dfpE" ESC_GS "2;2;1;0;0cpE",
		    (unsigned char)(color >> 16 & 0xff),
		    (unsigned char)(color >> 8 & 0xff),
		    (unsigned char)(color & 0xff));
      lputs(s, obuf);

    }
  }	/* ESC/Page-Color */

  return 0;
}


/* 線種指定命令 */
private int
escv_setdash(gx_device_vector * vdev, const float *pattern, uint count, floatp offset)
{
  stream			*s = gdev_vector_stream(vdev);
  int				i;
  char			obuf[64];

#if GS_VERSION_MAJOR == 5
  float			scale, xscale, yscale;
  /* 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, ESC_GS "0;0lpG");
    return 0;
  }
    
  /* offset が０以外の場合は描画不可として返却 */
  if (offset != 0) return -1;

  if (count) {
    if (count == 1) {
#if GS_VERSION_MAJOR == 5
      (void)sprintf(obuf, ESC_GS "1;%d;%ddlG", 
		    (int)(pattern[0] * scale / vdev->x_pixels_per_inch + 0.5),
		    (int)(pattern[0] * scale / vdev->x_pixels_per_inch + 0.5));
#else
      (void)sprintf(obuf, ESC_GS "1;%d;%ddlG", pattern[0], pattern[0]);
#endif
      lputs(s, obuf);
    } else {
      /* pattern に０があった場合は描画不可として返却 */
      for (i = 0; i < count; ++i) {
	if (pattern[i] == 0) return -1;
      }

      lputs(s, ESC_GS "1");
      for (i = 0; i < count; ++i) {
#if GS_VERSION_MAJOR == 5
	(void)sprintf(obuf, ";%d", (int)(pattern[i] * scale / vdev->x_pixels_per_inch + 0.5));

#else
	(void)sprintf(obuf, ";%d", pattern[i]);
#endif
	lputs(s, obuf);
      }
      lputs(s, "dlG");
    }
    lputs(s, ESC_GS "1;1lpG");
  }
  return 0;
}


/* パス平滑度指定 */
private int
escv_setflat(gx_device_vector * vdev, floatp flatness)
{
  return 0;
}


private int
escv_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;
}


private int
escv_beginpath(gx_device_vector * vdev, gx_path_type_t type)
{
  stream		*s = gdev_vector_stream(vdev);

  /* パス構築開始命令 */
  if (type & gx_path_type_clip) {
    lputs(s, ESC_GS "1bgpG");		/* クリップ登録 */
  } else {
    lputs(s, ESC_GS "0bgpG");		/* 描画登録 */
  }
  return 0;
}


private int
escv_moveto(gx_device_vector * vdev,
	    floatp x0, floatp y0, floatp x1, floatp y1, gx_path_type_t type)
{
  stream	*s = gdev_vector_stream(vdev);
  char	obuf[64];

  /* サブパス開始命令 */
  (void)sprintf(obuf, ESC_GS "0;%d;%dmvpG", (int)x1, (int)y1);
  lputs(s, obuf);

  return 0;
}


private int
escv_lineto(gx_device_vector * vdev,
	    floatp x0, floatp y0, floatp x1, floatp y1, gx_path_type_t type)
{
  stream	*s = gdev_vector_stream(vdev);
  char	obuf[64];

  (void)sprintf(obuf, ESC_GS "0;1;%d;%dlnpG", (int)x1, (int)y1);
  lputs(s, obuf);

  return 0;
}


private int
escv_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);
  char	obuf[128];

  /* ベジェ曲線 */
  (void)sprintf(obuf, ESC_GS "0;3;%d;%d;%d;%d;%d;%dbzpG",
		(int)x1, (int)y1, (int)x2, (int)y2, (int)x3, (int)y3);
  lputs(s, obuf);

  return 0;
}


private int
escv_closepath(gx_device_vector * vdev, floatp x, floatp y,
	       floatp x_start, floatp y_start, gx_path_type_t type)
{
  stream	*s = gdev_vector_stream(vdev);

  lputs(s, ESC_GS "clpG");
  return 0;
}


private int
escv_endpath(gx_device_vector * vdev, gx_path_type_t type)
{
  stream	*s = gdev_vector_stream(vdev);

  if (type & gx_path_type_fill || type & gx_path_type_clip) {
    /* default で処理されるが出力しておく */
    lputs(s, ESC_GS "clpG");
  }

  /* パスクローズ */
  lputs(s, ESC_GS "enpG");

  /* パス描画 */
  if (type & gx_path_type_clip) {

    /* クリップ指定
    ** クリップにも gx_path_type_winding_number, gx_path_type_even_odd の判断が
    ** 必要だと思うが gs 側が付加してこない。 
    ** とりあえず gx_path_type_even_odd をデフォルトにする。
    */
    lputs(s, ESC_GS "1;2capG");
  } else if (type & gx_path_type_fill) {

    /* 塗りつぶし規則設定 */
    if (type & gx_path_type_even_odd) {
      lputs(s, ESC_GS "0;2drpG");		/* 塗りつぶし描画 */
    } else {
      lputs(s, ESC_GS "0;1drpG");		/* 塗りつぶし描画 */
    }
  } else {	
    lputs(s, ESC_GS "0;0drpG");		/* 輪郭線描画 */
  }

  return 0;
}

/* ---------------- Driver procedures ---------------- */

/* ------ Open/close/page ------ */

/* Open the device. */
private int
escv_open(gx_device * dev)
{
  gx_device_vector	*const vdev = (gx_device_vector *) dev;
  gx_device_escv	*const pdev = (gx_device_escv *) dev;
  int			code;
  /*    char		*error, *path;*/
  float               width, height;

  code = escv_range_check(dev);
  if (code < 0) return code;

  vdev->v_memory = dev->memory;
  /****** VERY WRONG ******/
  vdev->vec_procs = &escv_vector_procs;

  code = gdev_vector_open_file_bbox(vdev, 512, true);
  if (code < 0) return code;

  gdev_vector_init(vdev);
  pdev->first_page = true;

  if(pdev->orientation){

    if( 0 == pdev->colormode ) { /* ESC/Page (Monochrome) */

      pdev->Margins[1] = (pdev->width - pdev->height - \
			  ESCPAGE_LEFT_MARGIN_DEFAULT * vdev->x_pixels_per_inch / 72.0) * \
	X_DPI / vdev->x_pixels_per_inch;

    } else {			/* ESC/Page-Color */

      /*    pdev->Margins[1] = pdev->width - pdev->height + dev->HWMargins[0];
       */
      pdev->Margins[1] = (pdev->width - pdev->height) * \
	X_DPI / vdev->x_pixels_per_inch;

    }	/* ESC/Page-Color */

    width = dev->MediaSize[0];
    height  = dev->MediaSize[1];
    dev->MediaSize[0] = height;
    dev->MediaSize[1] = width;
  }

  return 0;
}


/* Wrap up ("output") a page. */
private int
escv_output_page(gx_device * dev, int num_copies, int flush)
{
  gx_device_vector *const vdev = (gx_device_vector *) dev;
  gx_device_escv *const pdev = (gx_device_escv *) dev;
  stream *s = gdev_vector_stream(vdev);

  /* 線幅,終端処理,接合部処理を初期化しておく */
  lputs(s, ESC_GS "3;0;0lwG" ESC_GS "1;10mlG" ESC_FF);

  sflush(s);
  vdev->in_page = false;
  pdev->first_page = false;

  gdev_vector_reset(vdev);

  return 0;
}


private int
escv_close(gx_device *dev)
{
  gx_device_vector	*const vdev = (gx_device_vector *) dev;
  FILE		*f = vdev->file;

  /* 終了処理コードは決め打ち */
  (void)fprintf(f, ESC_GS "rhE" "\033\001@EJL \012@EJL EJ \012\033\001@EJL \012");

  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. */
private int
escv_get_params(gx_device * dev, gs_param_list * plist)
{
  gx_device_escv	*const pdev = (gx_device_escv *) dev;
  int			code;
  int			ncode;

  code = gdev_vector_get_params(dev, plist);
  if (code < 0) return code;

  if ((ncode = param_write_bool(plist, ESCPAGE_OPTION_MANUALFEED, &pdev->manualFeed)) < 0)
    code = ncode;

  if ((ncode = param_write_int(plist, ESCPAGE_OPTION_CASSETFEED, &pdev->cassetFeed)) < 0)
    code = ncode;

  if ((ncode = param_write_bool(plist, ESCPAGE_OPTION_RIT, &pdev->RITOff)) < 0)
    code = ncode;

  if ((ncode = param_write_bool(plist, ESCPAGE_OPTION_COLLATE, &pdev->Collate)) < 0)
    code = ncode;

  if ((ncode = param_write_int(plist, ESCPAGE_OPTION_TONERDENSITY, &pdev->toner_density)) < 0)
    code = ncode;

  if ((ncode = param_write_bool(plist, ESCPAGE_OPTION_LANDSCAPE, &pdev->orientation)) < 0)
    code = ncode;

  if ( param_write_bool(plist, ESCPAGE_OPTION_TONERSAVING, &pdev->toner_saving)< 0)
    code = ncode;

  if ((ncode = param_write_bool(plist, ESCPAGE_OPTION_DUPLEX, &pdev->Duplex)) < 0)
    code = ncode;

  if ((ncode = param_write_bool(plist, ESCPAGE_OPTION_DUPLEX_TUMBLE, &pdev->Tumble)) < 0)
    code = ncode;

  if ((ncode = param_write_bool(plist, ESCPAGE_OPTION_FACEUP, &pdev->faceup)) < 0)
    code = ncode;

  if ((ncode = param_write_int(plist, ESCPAGE_OPTION_MEDIATYPE, &pdev->MediaType)) < 0)
    code = ncode;

  return code;
}


/* Put parameters. */
private int
escv_put_params(gx_device * dev, gs_param_list * plist)
{
  gx_device_escv	*const pdev = (gx_device_escv *) dev;
  int			ecode = 0;
  int			code;
  gs_param_name	param_name;
  gs_param_string	pmedia;
  bool		mf = pdev->manualFeed;
  int			cass = pdev->cassetFeed;
  bool		tum = pdev->Tumble;
  bool		collate = pdev->Collate;
  int			toner_density = pdev->toner_density;
  bool		toner_saving = pdev->toner_saving;
  bool		landscape = pdev->orientation;
  bool		faceup = pdev->faceup;
  bool		duplex = pdev->Duplex;
  bool		RITOff = pdev->RITOff;
  int			old_bpp = dev->color_info.depth;
  int			bpp = 0;

  if ((code = param_read_bool(plist, (param_name = ESCPAGE_OPTION_MANUALFEED), &mf)) < 0) {
    param_signal_error(plist, param_name, ecode = code);
  }
  switch (code = param_read_int(plist, (param_name = ESCPAGE_OPTION_CASSETFEED), &cass)) {
  case 0:
    if (cass < -1 || cass > 15)
      ecode = gs_error_limitcheck;
    else
      break;
    goto casse;
  default:
    ecode = code;
  casse:param_signal_error(plist, param_name, ecode);
  case 1:
    break;
  }

  if((code = param_read_bool(plist, (param_name = ESCPAGE_OPTION_COLLATE), &collate)) < 0) {
    param_signal_error(plist, param_name, ecode = code);
  }

  if ((code = param_read_bool(plist, (param_name = ESCPAGE_OPTION_RIT), &RITOff)) < 0) {
    param_signal_error(plist, param_name, ecode = code);
  }

  switch (code = param_read_string(plist, (param_name = ESCPAGE_OPTION_MEDIATYPE), &pmedia)) {
  case 0:
    if (pmedia.size > ESCPAGE_MEDIACHAR_MAX)
      ecode = gs_error_limitcheck;
    else {		/* Check the validity of ``MediaType'' characters */

      if (strcmp(pmedia.data, "TRANS") == 0) {
	pdev->MediaType = 2;
      } else if (strcmp(pmedia.data, "THICK") == 0) {
	pdev->MediaType = 1;
      } else {
	ecode = gs_error_rangecheck;
	goto pmediae;
      }
    }
    break;
    goto pmediae;
  default:
    ecode = code;
  pmediae:param_signal_error(plist, param_name, ecode);
  case 1:
    if(!pdev->MediaType){
      pdev->MediaType = 0;
      pmedia.data = 0;
    }
    break;
  }

  switch (code = param_read_int(plist,
				(param_name = ESCPAGE_OPTION_TONERDENSITY), &toner_density)) {
  case 0:
    if (toner_density < 0 || toner_density > 5)
      ecode = gs_error_rangecheck;
    else
      break;
    goto tden;
  default:
    ecode = code;
  tden:
    param_signal_error(plist, param_name, ecode);
  case 1:
    break;
  }

  switch (code = param_read_bool(plist, (param_name = ESCPAGE_OPTION_TONERSAVING), &toner_saving)) {
  case 0:
    break;
  default:
    if ((code = param_read_null(plist, param_name)) == 0) {
      break;
    }
    ecode = code;
    param_signal_error(plist, param_name, ecode);
  case 1:
    break;   
  }

  if ((code = param_read_bool(plist, (param_name = ESCPAGE_OPTION_DUPLEX), &duplex)) < 0)
    param_signal_error(plist, param_name, ecode = code);

  if ((code = param_read_bool(plist, (param_name = ESCPAGE_OPTION_DUPLEX_TUMBLE), &tum)) < 0)
    param_signal_error(plist, param_name, ecode = code);

  if ((code = param_read_bool(plist, (param_name = ESCPAGE_OPTION_LANDSCAPE), &landscape)) < 0)
    param_signal_error(plist, param_name, ecode = code);

  if ((code = param_read_bool(plist, (param_name = ESCPAGE_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->faceup = faceup;
  pdev->RITOff = RITOff;
  pdev->orientation = landscape;
  pdev->toner_density = toner_density;
  pdev->toner_saving = toner_saving;
  pdev->Collate = collate;
  pdev->Duplex = duplex;
  pdev->Tumble = tum;

  if (bpp != 0 && bpp != old_bpp && pdev->is_open)
    return gs_closedevice(dev);

  return 0;
}

/* ---------------- Images ---------------- */


private int
escv_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_escv *const	pdev = (gx_device_escv *) dev;
  gx_device_vector *const	vdev = (gx_device_vector *) dev;
  stream			*s = gdev_vector_stream(vdev);
  gx_drawing_color		color;
  int				code = 0;
  gx_color_index		c_color = 0;
  char			obuf[128];
  int				depth = 1;
#if ( 8 <= GS_VERSION_MAJOR )
  /* FIXME! add for gs815 */
  const gs_imager_state * pis = (const gs_imager_state *)0;
#endif

  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);
    escv_setfillcolor(vdev,
#if ( 8 <= GS_VERSION_MAJOR )
		      pis,
#endif
		      &dcolor); /* FIXME! gs815 */
  }

  if (zero == gx_no_color_index) {

    if (one == gx_no_color_index) return 0;
    if (pdev->MaskState != 1) {

      if( 0 == pdev->colormode ) { /* ESC/Page (Monochrome) */

	/*	    lputs(s, ESC_GS "1owE");*/
	(void)sprintf(obuf, ESC_GS "1;1;%ldccE", c_color);
	lputs(s, obuf);

	if (vdev->x_pixels_per_inch == 1200) {
	  lputs(s, ESC_GS "1;45;156htmE");
	} else if (vdev->x_pixels_per_inch == 600) {
	  lputs(s, ESC_GS "1;45;106htmE");
	} else {
	  lputs(s, ESC_GS "1;45;71htmE");
	}

      } else {			/* ESC/Page-Color */

	lputs(s, ESC_GS "2;184wfE" ESC_GS "3;184wfE" ESC_GS "5;184wfE");

      }	/* ESC/Page-Color */

      pdev->MaskState = 1;   
    }	
    c_color = one;

  } else if (one == gx_no_color_index)
    /* 1bit は透明 ビット反転・zero 色に染める */
    {
      if (pdev->MaskState != 1) {

	if( 0 == pdev->colormode ) { /* ESC/Page (Monochrome) */

	  /*	    lputs(s, ESC_GS "1owE");*/

	} else {			/* ESC/Page-Color */

	  lputs(s, ESC_GS "3;184wfE" ESC_GS "5;184wfE");

	}	/* ESC/Page-Color */

	pdev->MaskState = 1;
      }
      c_color = zero;
    } else if (one == vdev->white) {

      if (pdev->MaskState != 0) {

	if( 0 == pdev->colormode ) { /* ESC/Page (Monochrome) */

	  /*	    lputs(s, ESC_GS "1owE");*/

	} else {			/* ESC/Page-Color */

	  lputs(s, ESC_GS "3;204wfE" ESC_GS "5;204wfE");

	}	/* ESC/Page-Color */

	pdev->MaskState = 0;
      }
      c_color = zero;
    } else {

      if (pdev->MaskState != 1) {

	if( 0 == pdev->colormode ) { /* ESC/Page (Monochrome) */

	  /*	    lputs(s, ESC_GS "1owE");*/

	} else {			/* ESC/Page-Color */

	  lputs(s, ESC_GS "3;184wfE" ESC_GS "5;184wfE");

	}	/* ESC/Page-Color */

	pdev->MaskState = 1;
      }
      color_set_pure(&color, one);
      code = gdev_vector_update_fill_color((gx_device_vector *) pdev,
#if ( 8 <= GS_VERSION_MAJOR )
					   pis,
#endif
					   &color);

      /* ここを通過したら以下の色設定は無意味？ */
    }
  if (code < 0) return 0;

  if( 0 == pdev->colormode ) { /* ESC/Page (Monochrome) */
  } else {			/* ESC/Page-Color */

    /* パターンＯＮ指定／ソリッドパターン指定 */
    (void)sprintf(obuf, ESC_GS "1;2;3;%d;%d;%dfpE",
		  (unsigned char)(c_color >> 16 & 0xff),
		  (unsigned char)(c_color >> 8 & 0xff),
		  (unsigned char)(c_color & 0xff));
    lputs(s, obuf);

    lputs(s, ESC_GS "5;2;1;0;0cpE");

  }	/* ESC/Page-Color */

  escv_write_begin(dev, depth, (int)x, (int)y, w, h, w, h, 0);
  {
    int		i, j;
    uint		width_bytes = (w + 7) >> 3;
    uint		num_bytes = width_bytes * h; 

    byte *buf = gs_alloc_bytes(vdev->memory, num_bytes, "escv_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);
	}
      }
    }

    escv_write_data(dev, depth, buf, num_bytes, w, h);
    gs_free_object(vdev->memory, buf, "escv_copy_mono(buf)");
  }
  escv_write_end(dev, depth);
  return 0;
}


/* Copy a color bitmap. */
private int
escv_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_escv	*const pdev = (gx_device_escv *) dev;
  gx_device_vector	*const vdev = (gx_device_vector *) dev;

  int			depth = dev->color_info.depth;
  int			num_components = (depth < 24 ? 1 : 3);
  uint		width_bytes = w * num_components;

  if (pdev->MaskState != 0) {

    if( 0 == pdev->colormode ) { /* ESC/Page (Monochrome) */

      /*	lputs(s, ESC_GS "1owE");*/

    } else {			/* ESC/Page-Color */
      stream		*s = gdev_vector_stream(vdev);

      lputs(s, ESC_GS "3;204wfE" ESC_GS "5;204wfE");

    }	/* ESC/Page-Color */
    pdev->MaskState = 0;
  }

  escv_write_begin(dev, depth, (int)x, (int)y, w, h, w, h, 0);

  {
    int		i;
    uint		num_bytes = width_bytes * h;
    byte		*buf = gs_alloc_bytes(vdev->memory, num_bytes, "escv_copy_color(buf)");

    for (i = 0; i < h; ++i) {
      memcpy(buf + i * width_bytes, data + ((data_x * depth) >> 3) + i * raster, width_bytes);
    }

    escv_write_data(dev, depth, buf, num_bytes, w, h);
    gs_free_object(vdev->memory, buf, "escv_copy_color(buf)");
  }

  escv_write_end(dev, depth);
  return 0;
}


/* Fill a mask. */
private int
escv_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_escv   *const pdev = (gx_device_escv *)   dev;
  stream           *s    = gdev_vector_stream(vdev);

  gx_color_index		color = gx_dc_pure_color(pdcolor);
  char			obuf[64];

#if ( 8 <= GS_VERSION_MAJOR )
  /* FIXME! add for gs815 */
  const gs_imager_state * pis = (const gs_imager_state *)0;
#endif

  if (w <= 0 || h <= 0) return 0;
    
  if (depth > 1 ||
      gdev_vector_update_fill_color(vdev,
#if ( 8 <= GS_VERSION_MAJOR )
				    pis,
#endif
				    pdcolor) < 0 ||
      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( 0 == pdev->colormode ) { /* ESC/Page (Monochrome) */

    if (!gx_dc_is_pure(pdcolor)) return_error(gs_error_rangecheck);
    pdev->current_color = color;

    (void)sprintf(obuf, ESC_GS "0;0;100spE" ESC_GS "1;1;%ldccE" ,color);
    lputs(s, obuf);


    if (vdev->x_pixels_per_inch == 1200) {
      lputs(s, ESC_GS "1;45;156htmE");
    } else if (vdev->x_pixels_per_inch == 600) {
      lputs(s, ESC_GS "1;45;106htmE");
    } else {
      lputs(s, ESC_GS "1;45;71htmE");
    }

    if(pdev->MaskState != 1) {
      /*      lputs(s, ESC_GS "1owE");*/
      pdev->MaskState = 1;
    }

  } else {			/* ESC/Page-Color */

    if (pdev->MaskState != 1) {

      lputs(s, ESC_GS "3;184wfE" ESC_GS "5;184wfE");
      pdev->MaskState = 1;
    }

    if (id != gs_no_id && data_x == 0 && depth == 1) {
      char		obuf[128];
      int		i;
      uint		width_bytes = (w + 7) >> 3;
      uint		num_bytes = width_bytes * h;
      byte		*buf;

      if (pdev -> id_cache[id & VCACHE] != id) {

	buf = gs_alloc_bytes(vdev->memory, num_bytes, "escv_fill_mask(buf)");

	/* cache entry */
	for (i = 0; i < h; ++i) {
	  memcpy(buf + i * width_bytes, data + (data_x >> 3) + i * raster, width_bytes);
	}

	(void)sprintf(obuf, ESC_GS "%d;%d;%d;%d;0db{F", num_bytes, (int)(id & VCACHE), w, h);
	lputs(s, obuf);
	put_bytes(s, buf, num_bytes);

	gs_free_object(vdev->memory, buf, "escv_fill_mask(buf)");
	pdev -> id_cache[id & VCACHE] = id;
      }

      (void)sprintf(obuf, ESC_GS "%dX" ESC_GS "%dY", x, y);
      lputs(s, obuf);
      (void)sprintf(obuf, ESC_GS "%lddbF", id & VCACHE);
      lputs(s, obuf);

      return 0;
    }
  }	/* ESC/Page-Color */

  escv_write_begin(dev, depth, (int)x, (int)y, w, h, w, h, 0);
  {
    int		i;
    uint		width_bytes = (w + 7) >> 3;
    uint		num_bytes = width_bytes * h;
    byte		*buf = gs_alloc_bytes(vdev->memory, num_bytes, "escv_fill_mask(buf)");

    for (i = 0; i < h; ++i) {
      memcpy(buf + i * width_bytes, data + (data_x >> 3) + i * raster, width_bytes);
    }

    escv_write_data(dev, depth, buf, num_bytes, w, h);
    escv_write_end(dev, depth);
    gs_free_object(vdev->memory, buf, "escv_fill_mask(buf)");
  }

  return 0;
}

/* ---------------- High-level images ---------------- */

private image_enum_proc_plane_data(escv_image_plane_data);
private image_enum_proc_end_image(escv_image_end_image);
private const gx_image_enum_procs_t escv_image_enum_procs =
  {
    escv_image_plane_data, escv_image_end_image
  };


/* Start processing an image. */
private int
escv_begin_image(gx_device * dev,
		 const gs_imager_state * pis, const gs_image_t * pim,
		 gs_image_format_t format, const gs_int_rect * prect,
		 const gx_drawing_color * pdcolor, const gx_clip_path * pcpath,
		 gs_memory_t * mem, gx_image_enum_common_t **pinfo)
{
  gx_device_vector *const	vdev = (gx_device_vector *) dev;
  gx_device_escv *const	pdev = (gx_device_escv *) dev;
  stream			*s = gdev_vector_stream((gx_device_vector *) pdev);
  gdev_vector_image_enum_t	*pie = 
    gs_alloc_struct(mem, gdev_vector_image_enum_t, &st_vector_image_enum, "escv_begin_image");
  const gs_color_space	*pcs = pim->ColorSpace;
  gs_color_space_index	index;
  int				num_components = 1;
  bool can_do = prect == 0 &&
    (pim->format == gs_image_format_chunky ||
     pim->format == gs_image_format_component_planar);

  gs_matrix			imat;
  int				code;
  int				ty, bx, by, cx, cy, dx, dy, sx, sy;

  gx_color_index		color = gx_dc_pure_color(pdcolor);
  char		        obuf[128];

  if (pie == 0) return_error(gs_error_VMerror);
  pie->memory = mem;
  code = gdev_vector_begin_image(vdev, pis, pim, format, prect,
				 pdcolor, pcpath, mem, &escv_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:
	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:
	can_do = false;
      }
    }
  }
  if (!can_do) {
    return gx_default_begin_image(dev, pis, pim, format, prect,
				  pdcolor, pcpath, mem, &pie->default_info);
  }

  if (pim->ImageMask || (pim->BitsPerComponent == 1 && num_components == 1)) {
    if (pim->Decode[0] > pim->Decode[1]) {
      pdev->MaskReverse = 1;
    } else {
      if( 0 == pdev->colormode ) { /* ESC/Page (Monochrome) */
      } else {			/* ESC/Page-Color */
	lputs(s, ESC_GS "8;1;2;2;2plr{E");
	put_bytes(s, "\000\000\000\000\377\377\377\377", 8);
      }	/* ESC/Page-Color */
      pdev->MaskReverse = 0;
    }
  }

  /* Write the image/colorimage/imagemask preamble. */
  gs_matrix_invert(&pim->ImageMatrix, &imat);
  gs_matrix_multiply(&imat, &ctm_only(pis), &imat);

  ty = 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;

  sx = bx - (int)imat.tx;
  sy = by - (int)imat.ty;

  /* とりあえず絵の位置に収まるように強制的に座標を変更する。 */
  pdev -> roll = 0;
  pdev -> reverse_x = pdev -> reverse_y = 0;
  if (imat.tx > bx) {
    pdev -> reverse_x = 1;
    sx = -sx;
    imat.tx = bx;
  }

  if (imat.ty > by) {
    pdev -> reverse_y = 1;
    sy = -sy;
    imat.ty = by;
  }

  (void)memcpy(&pdev -> xmat, &imat, sizeof(gs_matrix));
  pdev -> sx = sx;
  pdev -> sy = sy;
  pdev -> h = pim->Height;
  pdev -> w = pim->Width;
  pdev -> dd = 0;
  pdev -> bx = 0;
  pdev -> by = 0;

  if (ty == cy) {
    /* 回転時の描画については現在未実装。GS 側の機能を使用する */
    return -1;
  }

  if (pim->ImageMask) {
    pdev->ncomp = 1;

    /* 描画論理設定命令 - 透過 */
    if (pdev->MaskState != 1) {

      if( 0 == pdev->colormode ) { /* ESC/Page (Monochrome) */

	/*	    lputs(s, ESC_GS "1owE");*/
	(void)sprintf(obuf, ESC_GS "1;1;%ldccE", color);
	lputs(s, obuf);

	if (vdev->x_pixels_per_inch == 1200) {
	  lputs(s, ESC_GS "1;45;156htmE");
	} else if (vdev->x_pixels_per_inch == 600) {
	  lputs(s, ESC_GS "1;45;106htmE");
	} else {
	  lputs(s, ESC_GS "1;45;71htmE");
	}

      } else {			/* ESC/Page-Color */

	lputs(s, ESC_GS "3;184wfE" ESC_GS "5;184wfE");
	pdev->MaskState = 1;

      }	/* ESC/Page-Color */

    }

  } else {

    /* 描画論理設定命令 - 白塗り */
    if (pdev->MaskState != 0) {

      if( 0 == pdev->colormode ) { /* ESC/Page (Monochrome) */
	/*	  lputs(s, ESC_GS "1owE");*/ /* 184->204 */
      } else {			/* ESC/Page-Color */
	lputs(s, ESC_GS "3;204wfE" ESC_GS "5;204wfE");
      }	/* ESC/Page-Color */

      pdev->MaskState = 0;
    }
    pdev->ncomp = num_components;
  }

  if (pdev -> reverse_y) return 0;

  escv_write_begin(dev, pie->bits_per_pixel, (int)imat.tx, (int)imat.ty, pie->width, pie->height, sx, sy, pdev -> roll);
    
  return 0;
}


/* Process the next piece of an image. */
private int
#if GS_VERSION_MAJOR >= 6
escv_image_plane_data(gx_image_enum_common_t *info, const gx_image_plane_t *planes, int height, int *rows_used)
#else
     escv_image_plane_data(gx_device *dev, gx_image_enum_common_t *info, const gx_image_plane_t *planes, int height)
#endif
{
#if GS_VERSION_MAJOR >= 6
  gx_device *dev = info->dev;
#endif
  gx_device_vector *const	vdev = (gx_device_vector *) dev;
  gx_device_escv *const	pdev = (gx_device_escv *) dev;
  gdev_vector_image_enum_t	*pie = (gdev_vector_image_enum_t *) info;

  int				y;
  int				plane;
  int				width_bytes, tbyte;
  byte			*buf;

  if (pie->default_info) return gx_image_plane_data(pie->default_info, planes, height);

  gx_image_plane_data(pie->bbox_info, planes, height);

  {

#if GS_VERSION_MAJOR >= 6
    if (height == 260)
      height = 1;
#endif
    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, "escv_image_data(buf)");

    if (pdev -> reverse_y) {

      if (pdev -> h == height) {
	if( 0 == pdev->colormode ) { /* ESC/Page (Monochrome) */

	  if(tbyte == 1){
	    if(strcmp(pdev->dname, "lp1800") != 0 &&
	       strcmp(pdev->dname, "lp9600") != 0) {
	      pdev->w += pdev->sx / 2048;
	      height  += pdev->sy / 2048;
	    }
	  }

	} else {			/* ESC/Page-Color */

	  if(tbyte == 1){
	    pdev->w += pdev->sx / 2048;
	    height  += pdev->sy / 2048;
	  }

	}	/* ESC/Page-Color */


	escv_write_begin(dev, pie->bits_per_pixel, (int)pdev -> xmat.tx, (int)pdev -> xmat.ty, pdev -> w, height, (int)pdev -> sx, (int)pdev -> sy, pdev -> roll);

      } else {
	float	yy, sy;

	yy = (pdev -> h * pdev->xmat.yy) - (pdev -> dd * pdev -> xmat.yy) - (height * pdev -> xmat.yy);
	if (yy == 0) {
	  yy = (pdev -> h * pdev->xmat.yx) - (pdev -> dd * pdev -> xmat.yx) - (height * pdev -> xmat.yx);
	}

	if (pdev -> by) {
	  sy = (int)pdev -> xmat.ty - (int)yy;
	  sy = pdev -> by - (int)sy;
	} else {
	  sy = height * pdev -> xmat.yy + 0.5;
	}
	if (sy < 0) {
	  sy = -sy;
	}

	escv_write_begin(dev, pie->bits_per_pixel, (int)pdev -> xmat.tx, (int)pdev -> xmat.ty - (int)yy, pdev -> w, height, (int)pdev -> sx, (int)sy, pdev -> roll);

	pdev -> by = (int)pdev -> xmat.ty - (int)yy;
      }
    }
    pdev -> dd += height;

    for (plane = 0; plane < pie->num_planes; ++plane) {

      for (y = 0; y < height; ++y) {

	int     bit, w;
	const byte *p;
	byte *d;
	byte c;

	p = planes[plane].data + ((planes[plane].data_x * pie->bits_per_pixel) >> 3) + y * planes[plane].raster;
	if (pdev -> reverse_y) {

	  d = buf + (height - y) * width_bytes;

	  if (!pdev -> reverse_x) {
	    (void)memcpy(buf + (height - y - 1) * width_bytes,
			 planes[plane].data + ((planes[plane].data_x * pie->bits_per_pixel) >> 3)
			 + y * planes[plane].raster, width_bytes);

	  }

	} else {

	  d = buf + (y + 1) * width_bytes;

	  if (!pdev -> reverse_x) {

	    (void)memcpy(buf + y * width_bytes,
			 planes[plane].data + ((planes[plane].data_x * pie->bits_per_pixel) >> 3)
			 + y * planes[plane].raster, width_bytes);

	  }
	}
	if (pdev -> reverse_x) {
	  if (pie->bits_per_pixel == 1) {
	    for (w = 0; w < width_bytes; w++) {
	      c = 0;
	      for (bit = 0; bit < 8; bit++) {
		if (*p & 1 << (7 - bit)) {
		  c |= 1 << bit;
		}
	      }
	      p++;
	      *--d = c;
	    }
	  } else if (pie->bits_per_pixel == 8){
	    for (w = 0; w < width_bytes; w++) {
	      *--d = *p++;
	    }
	  } else {
	    for (w = 0; w < width_bytes / 3; w++) {
	      *--d = *(p + 2);
	      *--d = *(p + 1);
	      *--d = *p;
	      p += 3;
	    }
	  }
	}
      }
    }

    if(tbyte == 1){
      int t;

      if( 0 == pdev->colormode ) { /* ESC/Page (Monochrome) */

	gs_free_object(vdev->memory, buf, "escv_image_data(buf)");
	if(strcmp(pdev->dname, "lp1800") == 0 ||
	   strcmp(pdev->dname, "lp9600") == 0) {
	  if(pdev->sx > pdev->sy){
	    height  = pdev->sy;
	    pdev->w = pdev->sx; 
	    tbyte = ((pdev->sx + 7) / 8) * pdev->sy;
	  } else {
	    if(pdev->sx < pdev->sy){
	      height  = pdev->sy;
	      pdev->w = pdev->sx; 
	      tbyte = ((pdev->sx + 7) / 8) * pdev->sy;
	    } else {
	      tbyte = 1;
	    }
	  }

	} else {
	  if(pdev->sx > pdev->sy){
	    tbyte = 1;
	  } else {
	    if(pdev->sx < pdev->sy){
	      tbyte = tbyte * height;
	    } else {
	      tbyte = 1;
	    }
	  }
	}
	buf = gs_alloc_bytes(vdev->memory, tbyte, "escv_image_data(buf)");
	for(t = 0; t < tbyte; t++){
	  buf[t] = 0xff;
	}

      } else {			/* ESC/Page-Color */

	gs_free_object(vdev->memory, buf, "escv_image_data(buf)");
	if(pdev->sx > pdev->sy){
	  tbyte = 1;
	} else {
	  if(pdev->sx < pdev->sy){
	    tbyte = tbyte * height;
	  } else {
	    tbyte = 1;
	  }
	}

	buf = gs_alloc_bytes(vdev->memory, tbyte, "escv_image_data(buf)");
	for(t = 0; t < tbyte; t++){
	  buf[t] = 0x00;
	}

      }	/* ESC/Page-Color */

    }

    escv_write_data(dev, pie->bits_per_pixel, buf, tbyte, pdev -> w, height);

    if (pdev -> reverse_y) {
      escv_write_end(dev, pie->bits_per_pixel);
    }

    gs_free_object(vdev->memory, buf, "escv_image_data(buf)");
  }
  return (pie->y += height) >= pie->height;
}


private int
#if GS_VERSION_MAJOR >= 6
escv_image_end_image(gx_image_enum_common_t * info, bool draw_last)
#else
     escv_image_end_image(gx_device *dev, gx_image_enum_common_t * info, bool draw_last)
#endif
{
#if GS_VERSION_MAJOR >= 6
  gx_device *dev = info->dev;
#endif
  gx_device_vector		*const vdev = (gx_device_vector *) dev;
  gx_device_escv		*const pdev = (gx_device_escv *) dev;
  gdev_vector_image_enum_t	*pie = (gdev_vector_image_enum_t *) info;
  int				code;

  if (!(pdev -> reverse_y)) {
    escv_write_end(dev, pie->bits_per_pixel);
  }

  pdev->reverse_x = pdev->reverse_y = 0;
  if (pdev->MaskReverse == 0) {
    if( 0 == pdev->colormode ) { /* ESC/Page (Monochrome) */
      ;
    } else {			/* ESC/Page-Color */

      stream			*s = gdev_vector_stream((gx_device_vector *)pdev);

      lputs(s, ESC_GS "8;1;2;2;2plr{E");
      put_bytes(s, "\377\377\377\377\000\000\000\000", 8);
    }	/* ESC/Page-Color */
  }
  pdev->MaskReverse = -1;

  code = gdev_vector_end_image(vdev, (gdev_vector_image_enum_t *) pie, draw_last, pdev->white);
  return code;
}


private void escv_write_begin(gx_device *dev, int bits, int x, int y, int sw, int sh, int dw, int dh, int roll)
{
  gx_device_vector *const     vdev = (gx_device_vector *) dev;
  gx_device_escv   *const     pdev = (gx_device_escv *)dev;
  stream			*s = gdev_vector_stream((gx_device_vector *)dev);
  char                        obuf[128], *tmp, *p;
  int				i, comp;

  if( 0 == pdev->colormode ) { /* ESC/Page (Monochrome) */

    (void)sprintf(obuf, ESC_GS "%dX" ESC_GS "%dY", x, y);
    lputs(s, obuf);

    comp = 10;

    if (bits == 1) {
      if (strcmp(pdev->dname, "lp1800") == 0 ||
          strcmp(pdev->dname, "lp9600") == 0) {
	(void)sprintf(obuf, ESC_GS "0bcI");
      }else{
	(void)sprintf(obuf, ESC_GS "5;%d;%d;%d;%d;%dsrI",  sw, sh, dw, dh, roll);
      }
    } else if (bits == 4) {
      if (pdev -> c4map) {
	pdev -> c4map = FALSE;
      }
      (void)sprintf(obuf, ESC_GS "1;1;1;0;%d;%d;%d;%d;%d;%dscrI", comp, sw, sh, dw, dh, roll);
    } else if (bits == 8) {
      if (pdev -> c8map) {
	pdev -> c8map = FALSE;
      }
      (void)sprintf(obuf, ESC_GS "1;1;1;0;%d;%d;%d;%d;%d;%dscrI", comp, sw, sh, dw, dh, roll);
    } else {
      /* 24 bit */
      (void)sprintf(obuf, ESC_GS "1;1;1;0;%d;%d;%d;%d;%d;%dscrI", comp, sw, sh, dw, dh, roll);
    }    

  } else {			/* ESC/Page-Color */

    (void)sprintf(obuf, ESC_GS "%dX" ESC_GS "%dY", x, y);
    lputs(s, obuf);

    comp = 0;

    if (bits == 1) {
      (void)sprintf(obuf, ESC_GS "2;201;1;%d;%d;%d;%d;%d;%dscrI", comp, sw, sh, dw, dh, roll);
    } else if (bits == 4) {
      if (pdev -> c4map) {
	/* カラーマップ登録 */
	lputs(s, ESC_GS "64;2;2;16;16plr{E");
	p = tmp = gs_alloc_bytes(vdev->memory, 64, "escv_write_begin(tmp4)");
	for (i = 0; i < 16; i++) {
	  *p++ = i << 4;
	  *p++ = i << 4;
	  *p++ = i << 4;
	  *p++ = i << 4;
	}
	put_bytes(s, tmp, 64);
	gs_free_object(vdev->memory, tmp, "escv_write_begin(tmp4)");
	pdev -> c4map = FALSE;
      }
      (void)sprintf(obuf, ESC_GS "2;203;2;%d;%d;%d;%d;%d;%dscrI", comp, sw, sh, dw, dh, roll);
    } else if (bits == 8) {
      if (pdev -> c8map) {
	/* カラーマップ登録 */
	lputs(s, ESC_GS "1024;4;2;256;256plr{E");
	p = tmp = gs_alloc_bytes(vdev->memory, 1024, "escv_write_begin(tmp)");
	for (i = 0; i < 256; i++) {
	  *p++ = i;
	  *p++ = i;
	  *p++ = i;
	  *p++ = i;
	}
	put_bytes(s, tmp, 1024);
	gs_free_object(vdev->memory, tmp, "escv_write_begin(tmp)");
	pdev -> c8map = FALSE;
      }
      (void)sprintf(obuf, ESC_GS "2;204;4;%d;%d;%d;%d;%d;%dscrI", comp, sw, sh, dw, dh, roll);
    } else {
      /* 24 bit */
      (void)sprintf(obuf, ESC_GS "2;102;0;%d;%d;%d;%d;%d;%dscrI", comp, sw, sh, dw, dh, roll);
    }    

  }	/* ESC/Page-Color */

  lputs(s, obuf);

  return;
}


private void escv_write_data(gx_device *dev, int bits, char *buf, int bsize, int w, int ras)
{
  gx_device_vector *const     vdev = (gx_device_vector *) dev;
  gx_device_escv *const       pdev = (gx_device_escv *) dev;
  stream			*s = gdev_vector_stream((gx_device_vector *)pdev);
  char                        obuf[128];
  int				size;
  char			*tmps, *p;

  if( 0 == pdev->colormode ) { /* ESC/Page (Monochrome) */

    tmps = 0;

    if (bits == 12) {
      p = tmps = gs_alloc_bytes(vdev->memory, bsize * 2, "escv_write_data(tmp)");
      for (size = 0; size < bsize; size++) {
	*p++ = buf[size] & 0xF0;
	*p++ = buf[size] << 4;
      }
      bsize = bsize * 2;
      buf = tmps;
    }

    if(bits == 4) {
      p = tmps = gs_alloc_bytes(vdev->memory, bsize * 2, "escv_write_data(tmp)");
      for (size = 0; size < bsize; size++) {
	*p++ = ((buf[size] & 0xF0) * 0xFF / 0xF0);
	*p++ = ((buf[size] << 4 & 0xF0) * 0xFF / 0xF0);
      }
      bsize = bsize * 2;
      buf = tmps;
    }


    if(bits == 1){
      if (strcmp(pdev->dname, "lp1800") == 0 || \
	  strcmp(pdev->dname, "lp9600") == 0) {
	(void)sprintf(obuf, ESC_GS "%d;1;%d;%d;0db{I", bsize, w, ras);
      }else{
	(void)sprintf(obuf, ESC_GS "%d;%du{I", bsize, ras);
      }
    }else{
      (void)sprintf(obuf, ESC_GS "%d;%dcu{I", bsize, ras);
    }
    lputs(s, obuf);

    put_bytes(s, buf, bsize);

    if (bits == 12 || bits == 4) {
      gs_free_object(vdev->memory, tmps, "escv_write_data(tmp)");
    }

  } else {			/* ESC/Page-Color */

    char                        tmp;

    tmps = 0;
    if (bits == 12) {
      p = tmps = gs_alloc_bytes(vdev->memory, bsize * 2, "escv_write_data(tmp)");
      for (size = 0; size < bsize; size++) {
	tmp = buf[size] & 0xF0;
	*p++ = (tmp + (tmp >> 4 & 0x0F));
	tmp = buf[size] << 4;
	*p++ = (tmp + (tmp >> 4 & 0x0F));
      }
      bsize = bsize * 2;
      buf = tmps;
    }

    (void)sprintf(obuf, ESC_GS "%d;%dcu{I", bsize, ras);
    lputs(s, obuf);
    put_bytes(s, buf, bsize);

    if (bits == 12) {
      gs_free_object(vdev->memory, tmps, "escv_write_data(tmp)");
    }
  }	/* ESC/Page-Color */

  return;
}


private void escv_write_end(gx_device *dev, int bits)
{
  gx_device_escv *const       pdev = (gx_device_escv *) dev;
  stream			*s = gdev_vector_stream((gx_device_vector *)pdev);

  if( 0 == pdev->colormode ) { /* ESC/Page (Monochrome) */

    if(bits == 1){
      if (strcmp(pdev->dname, "lp1800") == 0 || \
	  strcmp(pdev->dname, "lp9600") == 0) {
	lputs(s, ESC_GS "1dbI");
      } else {
	lputs(s, ESC_GS "erI");
      }
    }else{
      lputs(s, ESC_GS "ecrI");
    }

  } else {			/* ESC/Page-Color */

    lputs(s, ESC_GS "ecrI");

  }	/* ESC/Page-Color */

  return;
}

/* end of file */
