gimp/plug-ins/print/print-escp2.c
Michael Natterer 4458ab1484 new file
2000-10-21  Michael Natterer  <mitch@gimp.org>

	* plug-ins/print/RELNOTES: new file

	* plug-ins/print/Makefile.am
	* plug-ins/print/README
	* plug-ins/print/print-escp2.c
	* plug-ins/print/print-pcl.c
	* plug-ins/print/print-printers.c
	* plug-ins/print/print-weave.c: Updated to the latest CVS version
	of gimp-print's new stable "print-4_0_branch" branch.
2000-10-21 13:27:30 +00:00

4365 lines
119 KiB
C

/*
* "$Id$"
*
* Print plug-in EPSON ESC/P2 driver for the GIMP.
*
* Copyright 1997-2000 Michael Sweet (mike@easysw.com) and
* Robert Krawitz (rlk@alum.mit.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*
* This file must include only standard C header files. The core code must
* compile on generic platforms that don't support glib, gimp, gtk, etc.
*/
#ifndef WEAVETEST
#include "print.h"
#endif
#ifndef __GNUC__
# define inline
#endif /* !__GNUC__ */
/*#include <endian.h>*/
typedef enum {
COLOR_MONOCHROME,
COLOR_CMYK,
COLOR_CCMMYK
} colormode_t;
/*
* Mapping between color and linear index. The colors are
* black, magenta, cyan, yellow, light magenta, light cyan
*/
static const int color_indices[16] = { 0, 1, 2, -1,
3, -1, -1, -1,
-1, 4, 5, -1,
-1, -1, -1, -1 };
static const int colors[6] = { 0, 1, 2, 4, 1, 2 };
static const int densities[6] = { 0, 0, 0, 0, 1, 1 };
#ifndef WEAVETEST
static void
escp2_write_microweave(FILE *, const unsigned char *,
const unsigned char *, const unsigned char *,
const unsigned char *, const unsigned char *,
const unsigned char *, int, int, int, int, int,
int, int);
static void *initialize_weave(int jets, int separation, int oversample,
int horizontal, int vertical,
colormode_t colormode, int width, int linewidth,
int lineheight, int vertical_row_separation,
int first_line, int phys_lines, int strategy);
static void escp2_flush_all(void *, int model, int width, int hoffset,
int ydpi, int xdpi, int physical_xdpi, FILE *prn);
static void
escp2_write_weave(void *, FILE *, int, int, int, int, int, int, int,
const unsigned char *c, const unsigned char *m,
const unsigned char *y, const unsigned char *k,
const unsigned char *C, const unsigned char *M);
static void escp2_init_microweave(int);
static void escp2_free_microweave(void);
static void destroy_weave(void *);
/*
* We really need to get away from this silly static nonsense...
*/
#define PHYSICAL_BPI 720
#define MAX_OVERSAMPLED 4
#define MAX_BPP 2
#define BITS_PER_BYTE 8
#define COMPBUFWIDTH (PHYSICAL_BPI * MAX_OVERSAMPLED * MAX_BPP * \
MAX_CARRIAGE_WIDTH / BITS_PER_BYTE)
/*
* Printer capabilities.
*
* Various classes of printer capabilities are represented by bitmasks.
*/
typedef unsigned long long model_cap_t;
typedef unsigned long long model_featureset_t;
/*
* For each printer, we can select from a variety of dot sizes.
* For single dot size printers, the available sizes are usually 0,
* which is the "default", and some subset of 1-4. For simple variable
* dot size printers (with only one kind of variable dot size), the
* variable dot size is specified as 0x10. For newer printers, there
* is a choice of variable dot sizes available, 0x10, 0x11, and 0x12 in
* order of increasing size.
*
* Normally, we want to specify the smallest dot size that lets us achieve
* a density of less than .8 or thereabouts (above that we start to get
* some dither artifacts). This needs to be tested for each printer and
* resolution.
*
* An entry of -1 in a slot means that this resolution is not available.
*/
typedef struct escp2_dot_sizes
{
int dot_180;
int dot_360_microweave;
int dot_360;
int dot_720_microweave;
int dot_720;
int dot_1440_microweave;
int dot_1440;
} escp2_dot_size_t;
/*
* Specify the base density for each available resolution.
* This obviously depends upon the dot size. Experience suggests that
* variable dot size mode (0x10) on the 870 requires the density
* derived from the printer base and the resolution to be multiplied
* by 3.3. Using dot size 0x11 requires the density to be multiplied
* by 2.2.
*/
typedef struct escp2_densities
{
double d_180_180;
double d_360_360_micro;
double d_360_360;
double d_720_720_micro;
double d_720_720;
double d_1440_720_micro;
double d_1440_720;
double d_1440_1440;
double d_1440_2880;
} escp2_densities_t;
/*
* Definition of the multi-level inks available to a given printer.
* Each printer may use a different kind of ink droplet for variable
* and single drop size for each supported horizontal resolution and
* type of ink (4 or 6 color).
*
* Recall that 6 color ink is treated as simply another kind of
* multi-level ink, but the driver offers the user a choice of 4 and
* 6 color ink, so we need to define appropriate inksets for both
* kinds of ink.
*
* Stuff like the MIS 4 and 6 "color" monochrome inks doesn't fit into
* this model very nicely, so we'll either have to special case it
* or find some way of handling it in here.
*/
typedef struct escp2_variable_ink
{
simple_dither_range_t *range;
int count;
double density;
} escp2_variable_ink_t;
typedef struct escp2_variable_inkset
{
escp2_variable_ink_t *c;
escp2_variable_ink_t *m;
escp2_variable_ink_t *y;
escp2_variable_ink_t *k;
} escp2_variable_inkset_t;
typedef struct escp2_variable_inklist
{
escp2_variable_inkset_t *s_180_4;
escp2_variable_inkset_t *s_360_4;
escp2_variable_inkset_t *s_720_4;
escp2_variable_inkset_t *s_1440_4;
escp2_variable_inkset_t *s_180_6;
escp2_variable_inkset_t *s_360_6;
escp2_variable_inkset_t *s_720_6;
escp2_variable_inkset_t *s_1440_6;
escp2_variable_inkset_t *v_180_4;
escp2_variable_inkset_t *v_360_4;
escp2_variable_inkset_t *v_720_4;
escp2_variable_inkset_t *v_1440_4;
escp2_variable_inkset_t *v_180_6;
escp2_variable_inkset_t *v_360_6;
escp2_variable_inkset_t *v_720_6;
escp2_variable_inkset_t *v_1440_6;
} escp2_variable_inklist_t;
static simple_dither_range_t photo_dither_ranges[] =
{
{ 0.33, 0x1, 0, 1 },
{ 1.0, 0x1, 1, 1 }
};
static escp2_variable_ink_t photo_ink =
{
photo_dither_ranges,
sizeof(photo_dither_ranges) / sizeof(simple_dither_range_t),
.75
};
static simple_dither_range_t photo_6pl_dither_ranges[] =
{
{ 0.15, 0x1, 0, 1 },
{ 0.227, 0x2, 0, 2 },
/* { 0.333, 0x3, 0, 3 }, */
{ 0.45, 0x1, 1, 1 },
{ 0.68, 0x2, 1, 2 },
{ 1.0, 0x3, 1, 3 }
};
static escp2_variable_ink_t photo_6pl_ink =
{
photo_6pl_dither_ranges,
sizeof(photo_6pl_dither_ranges) / sizeof(simple_dither_range_t),
1.0
};
static simple_dither_range_t photo_pigment_dither_ranges[] =
{ /* MRS: Not calibrated! */
{ 0.15, 0x1, 0, 1 },
{ 0.227, 0x2, 0, 2 },
{ 0.5, 0x1, 1, 1 },
{ 1.0, 0x2, 1, 2 }
};
static escp2_variable_ink_t photo_pigment_ink =
{
photo_pigment_dither_ranges,
sizeof(photo_pigment_dither_ranges) / sizeof(simple_dither_range_t),
1.0
};
static simple_dither_range_t photo_4pl_dither_ranges[] =
{
{ 0.15, 0x1, 0, 1 },
{ 0.227, 0x2, 0, 2 },
/* { 0.333, 0x3, 0, 3 }, */
{ 0.45, 0x1, 1, 1 },
{ 0.68, 0x2, 1, 2 },
{ 1.0, 0x3, 1, 3 }
};
static escp2_variable_ink_t photo_4pl_ink =
{
photo_4pl_dither_ranges,
sizeof(photo_4pl_dither_ranges) / sizeof(simple_dither_range_t),
1.0
};
static simple_dither_range_t standard_6pl_dither_ranges[] =
{
{ 0.45, 0x1, 1, 1 },
{ 0.68, 0x2, 1, 2 },
{ 1.0, 0x3, 1, 3 }
};
static escp2_variable_ink_t standard_6pl_ink =
{
standard_6pl_dither_ranges,
sizeof(standard_6pl_dither_ranges) / sizeof(simple_dither_range_t),
1.0
};
static simple_dither_range_t standard_pigment_dither_ranges[] =
{ /* MRS: Not calibrated! */
{ 0.55, 0x1, 1, 1 },
{ 1.0, 0x2, 1, 2 }
};
static escp2_variable_ink_t standard_pigment_ink =
{
standard_pigment_dither_ranges,
sizeof(standard_pigment_dither_ranges) / sizeof(simple_dither_range_t),
1.0
};
static simple_dither_range_t standard_4pl_dither_ranges[] =
{
{ 0.45, 0x1, 1, 1 },
{ 0.68, 0x2, 1, 2 },
{ 1.0, 0x3, 1, 3 }
};
static escp2_variable_ink_t standard_4pl_ink =
{
standard_4pl_dither_ranges,
sizeof(standard_4pl_dither_ranges) / sizeof(simple_dither_range_t),
1.0
};
static simple_dither_range_t standard_3pl_dither_ranges[] =
{
{ 0.225, 0x1, 1, 1 },
{ 0.68, 0x2, 1, 2 },
{ 1.0, 0x3, 1, 3 }
};
static escp2_variable_ink_t standard_3pl_ink =
{
standard_3pl_dither_ranges,
sizeof(standard_3pl_dither_ranges) / sizeof(simple_dither_range_t),
1.0
};
static simple_dither_range_t photo_multishot_dither_ranges[] =
{
{ 0.1097, 0x1, 0, 1 },
{ 0.227, 0x2, 0, 2 },
/* { 0.333, 0x3, 0, 3 }, */
{ 0.28, 0x1, 1, 1 },
{ 0.58, 0x2, 1, 2 },
{ 0.85, 0x3, 1, 3 },
{ 1.0, 0x3, 1, 3 }
};
static escp2_variable_ink_t photo_multishot_ink =
{
photo_multishot_dither_ranges,
sizeof(photo_multishot_dither_ranges) / sizeof(simple_dither_range_t),
1.0
};
static simple_dither_range_t standard_multishot_dither_ranges[] =
{
{ 0.28, 0x1, 1, 1 },
{ 0.58, 0x2, 1, 2 },
{ 0.85, 0x3, 1, 3 },
{ 1.0, 0x3, 1, 3 }
};
static escp2_variable_ink_t standard_multishot_ink =
{
standard_multishot_dither_ranges,
sizeof(standard_multishot_dither_ranges) / sizeof(simple_dither_range_t),
1.0
};
static escp2_variable_inkset_t standard_inks =
{
NULL,
NULL,
NULL,
NULL
};
static escp2_variable_inkset_t photo_inks =
{
&photo_ink,
&photo_ink,
NULL,
NULL
};
static escp2_variable_inkset_t escp2_6pl_standard_inks =
{
&standard_6pl_ink,
&standard_6pl_ink,
&standard_6pl_ink,
&standard_6pl_ink
};
static escp2_variable_inkset_t escp2_6pl_photo_inks =
{
&photo_6pl_ink,
&photo_6pl_ink,
&standard_6pl_ink,
&standard_6pl_ink
};
static escp2_variable_inkset_t escp2_pigment_standard_inks =
{
&standard_pigment_ink,
&standard_pigment_ink,
&standard_pigment_ink,
&standard_pigment_ink
};
static escp2_variable_inkset_t escp2_pigment_photo_inks =
{
&photo_pigment_ink,
&photo_pigment_ink,
&standard_pigment_ink,
&standard_pigment_ink
};
static escp2_variable_inkset_t escp2_4pl_standard_inks =
{
&standard_4pl_ink,
&standard_4pl_ink,
&standard_4pl_ink,
&standard_4pl_ink
};
static escp2_variable_inkset_t escp2_4pl_photo_inks =
{
&photo_4pl_ink,
&photo_4pl_ink,
&standard_4pl_ink,
&standard_4pl_ink
};
static escp2_variable_inkset_t escp2_3pl_standard_inks =
{
&standard_3pl_ink,
&standard_3pl_ink,
&standard_3pl_ink,
&standard_3pl_ink
};
static escp2_variable_inkset_t escp2_multishot_standard_inks =
{
&standard_multishot_ink,
&standard_multishot_ink,
&standard_multishot_ink,
&standard_multishot_ink
};
static escp2_variable_inkset_t escp2_multishot_photo_inks =
{
&photo_multishot_ink,
&photo_multishot_ink,
&standard_multishot_ink,
&standard_multishot_ink
};
static escp2_variable_inklist_t simple_4color_inks =
{
&standard_inks,
&standard_inks,
&standard_inks,
&standard_inks,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL
};
static escp2_variable_inklist_t simple_6color_inks =
{
&standard_inks,
&standard_inks,
&standard_inks,
&standard_inks,
&photo_inks,
&photo_inks,
&photo_inks,
&photo_inks,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL
};
static escp2_variable_inklist_t variable_6pl_4color_inks =
{
&standard_inks,
&standard_inks,
&standard_inks,
&standard_inks,
NULL,
NULL,
NULL,
NULL,
&escp2_6pl_standard_inks,
&escp2_6pl_standard_inks,
&escp2_6pl_standard_inks,
&escp2_6pl_standard_inks,
NULL,
NULL,
NULL,
NULL
};
static escp2_variable_inklist_t variable_6pl_6color_inks =
{
&standard_inks,
&standard_inks,
&standard_inks,
&standard_inks,
&photo_inks,
&photo_inks,
&photo_inks,
&photo_inks,
&escp2_6pl_standard_inks,
&escp2_6pl_standard_inks,
&escp2_6pl_standard_inks,
&escp2_6pl_standard_inks,
&escp2_6pl_photo_inks,
&escp2_6pl_photo_inks,
&escp2_6pl_photo_inks,
&escp2_6pl_photo_inks
};
static escp2_variable_inklist_t variable_pigment_inks =
{
&standard_inks,
&standard_inks,
&standard_inks,
&standard_inks,
&photo_inks,
&photo_inks,
&photo_inks,
&photo_inks,
&escp2_pigment_standard_inks,
&escp2_pigment_standard_inks,
&escp2_pigment_standard_inks,
&escp2_pigment_standard_inks,
&escp2_pigment_photo_inks,
&escp2_pigment_photo_inks,
&escp2_pigment_photo_inks,
&escp2_pigment_photo_inks
};
static escp2_variable_inklist_t variable_3pl_inks =
{
&standard_inks,
&standard_inks,
&standard_inks,
&standard_inks,
NULL,
NULL,
NULL,
NULL,
&escp2_multishot_standard_inks,
&escp2_multishot_standard_inks,
&escp2_6pl_standard_inks,
&escp2_3pl_standard_inks,
NULL,
NULL,
NULL,
NULL
};
static escp2_variable_inklist_t variable_4pl_4color_inks =
{
&standard_inks,
&standard_inks,
&standard_inks,
&standard_inks,
NULL,
NULL,
NULL,
NULL,
&escp2_multishot_standard_inks,
&escp2_multishot_standard_inks,
&escp2_6pl_standard_inks,
&escp2_4pl_standard_inks,
NULL,
NULL,
NULL,
NULL
};
static escp2_variable_inklist_t variable_4pl_6color_inks =
{
&standard_inks,
&standard_inks,
&standard_inks,
&standard_inks,
&photo_inks,
&photo_inks,
&photo_inks,
&photo_inks,
&escp2_multishot_standard_inks,
&escp2_multishot_standard_inks,
&escp2_6pl_standard_inks,
&escp2_4pl_standard_inks,
&escp2_multishot_photo_inks,
&escp2_multishot_photo_inks,
&escp2_6pl_photo_inks,
&escp2_4pl_photo_inks
};
typedef struct escp2_printer
{
model_cap_t flags; /* Bitmask of flags, see below */
int nozzles; /* Number of nozzles per color */
int nozzle_separation; /* Separation between rows, in 1/720" */
int black_nozzles; /* Number of black nozzles (may be extra) */
int black_nozzle_separation; /* Separation between rows */
int xres; /* Normal distance between dots in */
/* softweave mode (inverse inches) */
int enhanced_xres; /* Distance between dots in highest */
/* quality modes */
int max_paper_width; /* Maximum paper width, in points*/
int max_paper_height; /* Maximum paper height, in points */
int left_margin; /* Left margin, points */
int right_margin; /* Right margin, points */
int top_margin; /* Absolute top margin, points */
int bottom_margin; /* Absolute bottom margin, points */
int separation_rows; /* Some printers require funky spacing */
/* arguments in microweave mode. */
int pseudo_separation_rows;/* Some printers require funky */
/* spacing arguments in softweave mode */
escp2_dot_size_t dot_sizes; /* Vector of dot sizes for resolutions */
escp2_densities_t densities; /* List of densities for each printer */
escp2_variable_inklist_t *inks; /* Choices of inks for this printer */
} escp2_printer_t;
#define MODEL_INIT_MASK 0xfull /* Is a special init sequence */
#define MODEL_INIT_STANDARD 0x0ull /* required for this printer, and if */
#define MODEL_INIT_900 0x1ull /* so, what */
#define MODEL_HASBLACK_MASK 0x10ull /* Can this printer print black ink */
#define MODEL_HASBLACK_YES 0x00ull /* when it is also printing color? */
#define MODEL_HASBLACK_NO 0x10ull /* Only the 1500 can't. */
#define MODEL_6COLOR_MASK 0x20ull /* Is this a 6-color printer? */
#define MODEL_6COLOR_NO 0x00ull
#define MODEL_6COLOR_YES 0x20ull
#define MODEL_1440DPI_MASK 0x40ull /* Can this printer do 1440x720 dpi? */
#define MODEL_1440DPI_NO 0x00ull
#define MODEL_1440DPI_YES 0x40ull
#define MODEL_GRAYMODE_MASK 0x80ull /* Does this printer support special */
#define MODEL_GRAYMODE_NO 0x00ull /* fast black printing? */
#define MODEL_GRAYMODE_YES 0x80ull
#define MODEL_720DPI_MODE_MASK 0x300ull /* Does this printer require old */
#define MODEL_720DPI_DEFAULT 0x000ull /* or new setting for printing */
#define MODEL_720DPI_600 0x100ull /* 720 dpi? Only matters for */
/* single dot size printers */
#define MODEL_VARIABLE_DOT_MASK 0xc00ull /* Does this printer support var */
#define MODEL_VARIABLE_NORMAL 0x000ull /* dot size printing? The newest */
#define MODEL_VARIABLE_4 0x400ull /* printers support multiple modes */
#define MODEL_VARIABLE_MULTI 0x800ull /* of variable dot sizes. */
#define MODEL_COMMAND_MASK 0xf000ull /* What general command set does */
#define MODEL_COMMAND_GENERIC 0x0000ull /* this printer use? */
#define MODEL_COMMAND_1998 0x1000ull
#define MODEL_COMMAND_1999 0x2000ull /* The 1999 series printers */
#define MODEL_INK_MASK 0x10000ull /* Does this printer support */
#define MODEL_INK_NORMAL 0x00000ull /* different types of inks? */
#define MODEL_INK_SELECTABLE 0x10000ull /* Only the Stylus Pro's do */
#define MODEL_ROLLFEED_MASK 0x20000ull /* Does this printer support */
#define MODEL_ROLLFEED_NO 0x00000ull /* a roll feed? */
#define MODEL_ROLLFEED_YES 0x20000ull
#define MODEL_ZEROMARGIN_MASK 0x40000ull /* Does this printer support */
#define MODEL_ZEROMARGIN_NO 0x00000ull /* zero margin mode? */
#define MODEL_ZEROMARGIN_YES 0x40000ull /* (print to the edge of the paper) */
#define INCH(x) (72 * x)
static escp2_printer_t model_capabilities[] =
{
/* FIRST GENERATION PRINTERS */
/* 0: Stylus Color */
{
(MODEL_INIT_STANDARD | MODEL_HASBLACK_YES | MODEL_INK_NORMAL
| MODEL_6COLOR_NO | MODEL_720DPI_DEFAULT | MODEL_VARIABLE_NORMAL
| MODEL_COMMAND_GENERIC | MODEL_GRAYMODE_YES | MODEL_1440DPI_NO
| MODEL_ROLLFEED_NO | MODEL_ZEROMARGIN_NO),
1, 1, 1, 1, 720, 720, INCH(17 / 2), INCH(14), 14, 14, 9, 49, 1, 0,
{ -2, -2, -1, -2, -1, -1, -1 },
{ 2.0, 1.3, 1.3, .568, 0, 0, 0, 0, 0 },
&simple_4color_inks
},
/* 1: Stylus Color Pro/Pro XL/400/500 */
{
(MODEL_INIT_STANDARD | MODEL_HASBLACK_YES | MODEL_INK_NORMAL
| MODEL_6COLOR_NO | MODEL_720DPI_DEFAULT | MODEL_VARIABLE_NORMAL
| MODEL_COMMAND_GENERIC | MODEL_GRAYMODE_NO | MODEL_1440DPI_NO
| MODEL_ROLLFEED_NO | MODEL_ZEROMARGIN_NO),
48, 6, 48, 6, 720, 720, INCH(17 / 2), INCH(14), 14, 14, 0, 30, 1, 0,
{ -2, -2, -1, -2, -1, -1, -1 },
{ 2.0, 1.3, 1.3, .631, 0, 0, 0, 0, 0 },
&simple_4color_inks
},
/* 2: Stylus Color 1500 */
{
(MODEL_INIT_STANDARD | MODEL_HASBLACK_NO | MODEL_INK_NORMAL
| MODEL_6COLOR_NO | MODEL_720DPI_DEFAULT | MODEL_VARIABLE_NORMAL
| MODEL_COMMAND_GENERIC | MODEL_GRAYMODE_NO | MODEL_1440DPI_NO
| MODEL_ROLLFEED_YES | MODEL_ZEROMARGIN_NO),
1, 1, 1, 1, 720, 720, INCH(11), INCH(17), 14, 14, 9, 49, 1, 0,
{ -2, -2, -1, -2, -1, -1, -1 },
{ 2.0, 1.3, 1.3, .631, 0, 0, 0, 0, 0 },
&simple_4color_inks
},
/* 3: Stylus Color 600 */
{
(MODEL_INIT_STANDARD | MODEL_HASBLACK_YES | MODEL_INK_NORMAL
| MODEL_6COLOR_NO | MODEL_720DPI_600 | MODEL_VARIABLE_NORMAL
| MODEL_COMMAND_GENERIC | MODEL_GRAYMODE_YES | MODEL_1440DPI_YES
| MODEL_ROLLFEED_NO | MODEL_ZEROMARGIN_NO),
32, 8, 32, 8, 720, 360, INCH(17 / 2), INCH(14), 8, 9, 0, 30, 1, 0,
{ 4, 4, -1, 2, 2, -1, 1 },
{ 2.0, 1.3, 1.3, .775, .775, .55, .55, .275, .138 },
&simple_4color_inks
},
/* 4: Stylus Color 800 */
{
(MODEL_INIT_STANDARD | MODEL_HASBLACK_YES | MODEL_INK_NORMAL
| MODEL_6COLOR_NO | MODEL_720DPI_DEFAULT | MODEL_VARIABLE_NORMAL
| MODEL_COMMAND_GENERIC | MODEL_GRAYMODE_YES | MODEL_1440DPI_YES
| MODEL_ROLLFEED_NO | MODEL_ZEROMARGIN_NO),
64, 4, 64, 4, 720, 360, INCH(17 / 2), INCH(14), 8, 9, 9, 40, 1, 4,
{ 3, 3, -1, 1, 1, -1, 4 },
{ 2.0, 1.3, 1.3, .775, .775, .55, .55, .275, .138 },
&simple_4color_inks
},
/* 5: Stylus Color 850 */
{
(MODEL_INIT_STANDARD | MODEL_HASBLACK_YES | MODEL_INK_NORMAL
| MODEL_6COLOR_NO | MODEL_720DPI_DEFAULT | MODEL_VARIABLE_NORMAL
| MODEL_COMMAND_GENERIC | MODEL_GRAYMODE_YES | MODEL_1440DPI_YES
| MODEL_ROLLFEED_NO | MODEL_ZEROMARGIN_NO),
64, 4, 128, 2, 720, 360, INCH(17 / 2), INCH(14), 9, 9, 9, 40, 1, 4,
{ 3, 3, -1, 1, 1, -1, 4 },
{ 2.0, 1.3, 1.3, .775, .775, .55, .55, .275, .138 },
&simple_4color_inks
},
/* 6: Stylus Color 1520 */
{
(MODEL_INIT_STANDARD | MODEL_HASBLACK_YES | MODEL_INK_NORMAL
| MODEL_6COLOR_NO | MODEL_720DPI_DEFAULT | MODEL_VARIABLE_NORMAL
| MODEL_COMMAND_GENERIC | MODEL_GRAYMODE_YES | MODEL_1440DPI_YES
| MODEL_ROLLFEED_YES | MODEL_ZEROMARGIN_NO),
64, 4, 64, 4, 720, 360, INCH(17), INCH(55), 8, 9, 9, 40, 1, 4,
{ 3, 3, -1, 1, 1, -1, 4 },
{ 2.0, 1.3, 1.3, .775, .775, .55, .55, .275, .138 },
&simple_4color_inks
},
/* SECOND GENERATION PRINTERS */
/* 7: Stylus Photo 700 */
{
(MODEL_INIT_STANDARD | MODEL_HASBLACK_YES | MODEL_INK_NORMAL
| MODEL_6COLOR_YES | MODEL_720DPI_600 | MODEL_VARIABLE_NORMAL
| MODEL_COMMAND_1998 | MODEL_GRAYMODE_NO | MODEL_1440DPI_YES
| MODEL_ROLLFEED_NO | MODEL_ZEROMARGIN_NO),
32, 8, 32, 8, 720, 360, INCH(17 / 2), INCH(14), 9, 9, 0, 30, 1, 0,
{ 3, 3, -1, -1, 1, -1, 4 },
{ 2.0, 1.3, 1.3, .775, .775, .55, .55, .275, .138 },
&simple_6color_inks
},
/* 8: Stylus Photo EX */
{
(MODEL_INIT_STANDARD | MODEL_HASBLACK_YES | MODEL_INK_NORMAL
| MODEL_6COLOR_YES | MODEL_720DPI_600 | MODEL_VARIABLE_NORMAL
| MODEL_COMMAND_1998 | MODEL_GRAYMODE_NO | MODEL_1440DPI_YES
| MODEL_ROLLFEED_NO | MODEL_ZEROMARGIN_NO),
32, 8, 32, 8, 720, 360, INCH(11), INCH(17), 9, 9, 0, 30, 1, 0,
{ 3, 3, -1, -1, 1, -1, 4 },
{ 2.0, 1.3, 1.3, .775, .775, .55, .55, .275, .138 },
&simple_6color_inks
},
/* 9: Stylus Photo */
{
(MODEL_INIT_STANDARD | MODEL_HASBLACK_YES | MODEL_INK_NORMAL
| MODEL_6COLOR_YES | MODEL_720DPI_600 | MODEL_VARIABLE_NORMAL
| MODEL_COMMAND_1998 | MODEL_GRAYMODE_NO | MODEL_1440DPI_NO
| MODEL_ROLLFEED_NO | MODEL_ZEROMARGIN_NO),
32, 8, 32, 8, 720, 360, INCH(17 / 2), INCH(14), 9, 9, 0, 30, 1, 0,
{ 3, 3, -1, -1, 1, -1, -1 },
{ 2.0, 1.3, 1.3, .775, .775, 0, 0, 0, 0 },
&simple_6color_inks
},
/* THIRD GENERATION PRINTERS */
/* 10: Stylus Color 440/460 */
/* Thorsten Schnier has confirmed that the separation is 8. Why on */
/* earth anyone would use 21 nozzles when designing a print head is */
/* completely beyond me, but there you are... */
{
(MODEL_INIT_STANDARD | MODEL_HASBLACK_YES | MODEL_INK_NORMAL
| MODEL_6COLOR_NO | MODEL_720DPI_600 | MODEL_VARIABLE_NORMAL
| MODEL_COMMAND_1999 | MODEL_GRAYMODE_YES | MODEL_1440DPI_NO
| MODEL_ROLLFEED_NO | MODEL_ZEROMARGIN_NO),
21, 8, 21, 8, 720, 720, INCH(17 / 2), INCH(14), 9, 9, 0, 9, 1, 0,
{ -1, 3, -1, 1, 1, -1, -1 },
{ 3.0, 2.0, 2.0, .900, .900, 0, 0, 0, 0 },
&simple_4color_inks
},
/* 11: Stylus Color 640 */
{
(MODEL_INIT_STANDARD | MODEL_HASBLACK_YES | MODEL_INK_NORMAL
| MODEL_6COLOR_NO | MODEL_720DPI_600 | MODEL_VARIABLE_NORMAL
| MODEL_COMMAND_1999 | MODEL_GRAYMODE_YES | MODEL_1440DPI_YES
| MODEL_ROLLFEED_NO | MODEL_ZEROMARGIN_NO),
32, 8, 64, 4, 720, 720, INCH(17 / 2), INCH(14), 9, 9, 0, 9, 1, 0,
{ -1, 3, -1, 1, 1, -1, 1 },
{ 3.0, 2.0, 2.0, .900, .900, .45, .45, .225, .113 },
&simple_4color_inks
},
/* 12: Stylus Color 740 */
{
(MODEL_INIT_STANDARD | MODEL_HASBLACK_YES | MODEL_INK_NORMAL
| MODEL_6COLOR_NO | MODEL_720DPI_DEFAULT | MODEL_VARIABLE_4
| MODEL_COMMAND_1999 | MODEL_GRAYMODE_YES | MODEL_1440DPI_YES
| MODEL_ROLLFEED_NO | MODEL_ZEROMARGIN_NO),
48, 6, 144, 2, 360, 360, INCH(17 / 2), INCH(14), 9, 9, 0, 9, 1, 0,
{ -1, 4, 0x10, 3, 0x10, -1, 0x10 },
{ 2.0, 1.3, 2.0, .646, .710, .323, .365, .1825, .0913 },
&variable_6pl_4color_inks
},
/* 13: Stylus Color 900 */
/* Still need to figure out density for 3 pl drops! */
{
(MODEL_INIT_900 | MODEL_HASBLACK_YES | MODEL_INK_NORMAL
| MODEL_6COLOR_NO | MODEL_720DPI_DEFAULT | MODEL_VARIABLE_4
| MODEL_COMMAND_1999 | MODEL_GRAYMODE_YES | MODEL_1440DPI_YES
| MODEL_ROLLFEED_NO | MODEL_ZEROMARGIN_NO),
96, 4, 192, 2, 360, 180, INCH(17 / 2), INCH(44), 9, 9, 0, 9, 1, 0,
{ -1, 1, 0x11, 1, 0x10, -1, 0x10 },
{ 2.0, 1.3, 1.3, .646, .710, .323, .365, .1825, .0913 },
&variable_3pl_inks
},
/* 14: Stylus Photo 750 */
{
(MODEL_INIT_900 | MODEL_HASBLACK_YES | MODEL_INK_NORMAL
| MODEL_6COLOR_YES | MODEL_720DPI_DEFAULT | MODEL_VARIABLE_4
| MODEL_COMMAND_1999 | MODEL_GRAYMODE_NO | MODEL_1440DPI_YES
| MODEL_ROLLFEED_NO | MODEL_ZEROMARGIN_NO),
48, 6, 48, 6, 360, 360, INCH(17 / 2), INCH(44), 9, 9, 0, 9, 1, 0,
{ -1, 2, 0x10, 4, 0x10, -1, 0x10 },
{ 2.0, 1.3, 1.3, .646, .710, .323, .365, .1825, .0913 },
&variable_6pl_6color_inks
},
/* 15: Stylus Photo 1200 */
{
(MODEL_INIT_900 | MODEL_HASBLACK_YES | MODEL_INK_NORMAL
| MODEL_6COLOR_YES | MODEL_720DPI_DEFAULT | MODEL_VARIABLE_4
| MODEL_COMMAND_1999 | MODEL_GRAYMODE_NO | MODEL_1440DPI_YES
| MODEL_ROLLFEED_YES | MODEL_ZEROMARGIN_NO),
48, 6, 48, 6, 360, 360, INCH(13), INCH(44), 9, 9, 0, 9, 1, 0,
{ -1, 2, 0x10, 4, 0x10, -1, 0x10 },
{ 2.0, 1.3, 1.3, .646, .710, .323, .365, .1825, .0913 },
&variable_6pl_6color_inks
},
/* 16: Stylus Color 860 */
{
(MODEL_INIT_900 | MODEL_HASBLACK_YES | MODEL_INK_NORMAL
| MODEL_6COLOR_NO | MODEL_720DPI_DEFAULT | MODEL_VARIABLE_MULTI
| MODEL_COMMAND_1999 | MODEL_GRAYMODE_YES | MODEL_1440DPI_YES
| MODEL_ROLLFEED_NO | MODEL_ZEROMARGIN_NO),
48, 6, 144, 2, 360, 360, INCH(17 / 2), INCH(14), 9, 9, 0, 9, 1, 0,
{ -1, 0, 0x12, 0, 0x11, -1, 0x10 },
{ 2.0, 1.3, 1.3, .431, .710, .216, .533, .2665, .1333 },
&variable_4pl_4color_inks
},
/* 17: Stylus Color 1160 */
{
(MODEL_INIT_900 | MODEL_HASBLACK_YES | MODEL_INK_NORMAL
| MODEL_6COLOR_NO | MODEL_720DPI_DEFAULT | MODEL_VARIABLE_MULTI
| MODEL_COMMAND_1999 | MODEL_GRAYMODE_YES | MODEL_1440DPI_YES
| MODEL_ROLLFEED_NO | MODEL_ZEROMARGIN_NO),
48, 6, 144, 2, 360, 360, INCH(13), INCH(44), 9, 9, 0, 9, 1, 0,
{ -1, 0, 0x12, 0, 0x11, -1, 0x10 },
{ 2.0, 1.3, 1.3, .431, .710, .216, .533, .2665, .1333 },
&variable_4pl_4color_inks
},
/* 18: Stylus Color 660 */
{
(MODEL_INIT_900 | MODEL_HASBLACK_YES | MODEL_INK_NORMAL
| MODEL_6COLOR_NO | MODEL_720DPI_600 | MODEL_VARIABLE_NORMAL
| MODEL_COMMAND_1998 | MODEL_GRAYMODE_YES | MODEL_1440DPI_YES
| MODEL_ROLLFEED_NO | MODEL_ZEROMARGIN_NO),
32, 8, 64, 4, 720, 720, INCH(17 / 2), INCH(44), 9, 9, 0, 9, 1, 8,
{ -1, 3, -1, 3, 0, -1, 0 },
{ 3.0, 2.0, 2.0, .646, .646, .323, .323, .1615, .0808 },
&simple_4color_inks
},
/* 19: Stylus Color 760 */
{
(MODEL_INIT_900 | MODEL_HASBLACK_YES | MODEL_INK_NORMAL
| MODEL_6COLOR_NO | MODEL_720DPI_DEFAULT | MODEL_VARIABLE_MULTI
| MODEL_COMMAND_1999 | MODEL_GRAYMODE_YES | MODEL_1440DPI_YES
| MODEL_ROLLFEED_NO | MODEL_ZEROMARGIN_NO),
48, 6, 144, 2, 360, 360, INCH(17 / 2), INCH(14), 9, 9, 0, 9, 1, 0,
{ -1, 0, 0x12, 0, 0x11, -1, 0x10 },
{ 2.0, 1.3, 1.3, .431, .710, .216, .533, .2665, .1333 },
&variable_4pl_4color_inks
},
/* 20: Stylus Photo 720 (Australia) */
{
(MODEL_INIT_900 | MODEL_HASBLACK_YES | MODEL_INK_NORMAL
| MODEL_6COLOR_YES | MODEL_720DPI_DEFAULT | MODEL_VARIABLE_4
| MODEL_COMMAND_1999 | MODEL_GRAYMODE_NO | MODEL_1440DPI_YES
| MODEL_ROLLFEED_NO | MODEL_ZEROMARGIN_NO),
32, 8, 32, 8, 360, 360, INCH(17 / 2), INCH(14), 9, 9, 0, 9, 1, 0,
{ -1, 2, 0x12, 4, 0x11, -1, 0x11 },
{ 2.0, 1.3, 1.3, .646, .710, .323, .365, .1825, .0913 },
&variable_6pl_6color_inks
},
/* 21: Stylus Color 480 */
{
(MODEL_INIT_900 | MODEL_HASBLACK_YES | MODEL_INK_NORMAL
| MODEL_6COLOR_NO | MODEL_720DPI_DEFAULT | MODEL_VARIABLE_4
| MODEL_COMMAND_1999 | MODEL_GRAYMODE_NO | MODEL_1440DPI_NO
| MODEL_ROLLFEED_NO | MODEL_ZEROMARGIN_NO),
15, 6, 15, 6, 360, 360, INCH(17 / 2), INCH(14), 9, 9, 0, 9, 1, 0,
{ -1, -2, 0x13, -2, 0x10, -1, -1 },
{ 2.0, 1.3, 1.3, .646, .710, .323, .365, .1825, .0913 },
&variable_6pl_4color_inks
},
/* 22: Stylus Photo 870 */
{
(MODEL_INIT_900 | MODEL_HASBLACK_YES | MODEL_INK_NORMAL
| MODEL_6COLOR_YES | MODEL_720DPI_DEFAULT | MODEL_VARIABLE_MULTI
| MODEL_COMMAND_1999 | MODEL_GRAYMODE_NO | MODEL_1440DPI_YES
| MODEL_ROLLFEED_YES | MODEL_ZEROMARGIN_YES),
48, 6, 48, 6, 360, 360, INCH(17 / 2), INCH(44), 0, 0, 0, 9, 1, 0,
{ -1, 4, 0x12, 2, 0x11, -1, 0x10 },
{ 2.0, 1.3, 1.3, .431, .710, .216, .533, .2665, .1333 },
&variable_4pl_6color_inks
},
/* 23: Stylus Photo 1270 */
{
(MODEL_INIT_900 | MODEL_HASBLACK_YES | MODEL_INK_NORMAL
| MODEL_6COLOR_YES | MODEL_720DPI_DEFAULT | MODEL_VARIABLE_MULTI
| MODEL_COMMAND_1999 | MODEL_GRAYMODE_NO | MODEL_1440DPI_YES
| MODEL_ROLLFEED_YES | MODEL_ZEROMARGIN_YES),
48, 6, 48, 6, 360, 360, INCH(13), INCH(44), 0, 0, 0, 9, 1, 0,
{ -1, 4, 0x12, 2, 0x11, -1, 0x10 },
{ 2.0, 1.3, 1.3, .431, .710, .216, .533, .2665, .1333 },
&variable_4pl_6color_inks
},
/* 24: Stylus Color 3000 */
{
(MODEL_INIT_STANDARD | MODEL_HASBLACK_YES | MODEL_INK_NORMAL
| MODEL_6COLOR_NO | MODEL_720DPI_DEFAULT | MODEL_VARIABLE_NORMAL
| MODEL_COMMAND_GENERIC | MODEL_GRAYMODE_YES | MODEL_1440DPI_YES
| MODEL_ROLLFEED_YES | MODEL_ZEROMARGIN_NO),
64, 4, 64, 4, 720, 360, INCH(17), INCH(55), 8, 9, 9, 40, 1, 4,
{ 3, 3, -1, 1, 1, -1, 4 },
{ 2.0, 1.3, 1.3, .775, .775, .55, .55, .275, .138 },
&simple_4color_inks
},
/* 25: Stylus Color 670 */
{
(MODEL_INIT_900 | MODEL_HASBLACK_YES | MODEL_INK_NORMAL
| MODEL_6COLOR_NO | MODEL_720DPI_DEFAULT | MODEL_VARIABLE_MULTI
| MODEL_COMMAND_1999 | MODEL_GRAYMODE_YES | MODEL_1440DPI_YES
| MODEL_ROLLFEED_NO | MODEL_ZEROMARGIN_NO),
32, 8, 64, 4, 360, 360, INCH(17 / 2), INCH(44), 9, 9, 0, 9, 1, 0,
{ -1, 3, 0x12, 3, 0x11, -1, 0x11 },
{ 2.0, 1.3, 1.3, .646, .710, .323, .365, .1825, .0913 },
&variable_6pl_4color_inks
},
/* 26: Stylus Photo 2000P */
{
(MODEL_INIT_900 | MODEL_HASBLACK_YES | MODEL_INK_NORMAL
| MODEL_6COLOR_YES | MODEL_720DPI_DEFAULT | MODEL_VARIABLE_4
| MODEL_COMMAND_1999 | MODEL_GRAYMODE_NO | MODEL_1440DPI_YES
| MODEL_ROLLFEED_NO | MODEL_ZEROMARGIN_NO),
48, 6, 144, 2, 360, 360, INCH(17 / 2), INCH(44), 9, 9, 0, 9, 1, 0,
{ -1, 2, 0x11, 4, 0x10, -1, 0x10 },
{ 2.0, 1.3, 1.3, .775, .852, .388, .438, .219, .110 },
&variable_pigment_inks
},
/* 27: Stylus Pro 5000 */
{
(MODEL_INIT_900 | MODEL_HASBLACK_YES | MODEL_INK_NORMAL
| MODEL_6COLOR_YES | MODEL_720DPI_DEFAULT | MODEL_VARIABLE_NORMAL
| MODEL_COMMAND_1999 | MODEL_GRAYMODE_NO | MODEL_1440DPI_YES
| MODEL_ROLLFEED_NO | MODEL_ZEROMARGIN_NO),
64, 4, 64, 4, 360, 360, INCH(13), INCH(1200), 9, 9, 0, 9, 1, 0,
{ -1, 2, -1, 4, 0, 4, 0 },
{ 2.0, 1.3, 1.3, .646, .646, .323, .323, .1615, .0808 },
&simple_6color_inks
},
/* 28: Stylus Pro 7000 */
{
(MODEL_INIT_900 | MODEL_HASBLACK_YES | MODEL_INK_NORMAL
| MODEL_6COLOR_YES | MODEL_720DPI_DEFAULT | MODEL_VARIABLE_NORMAL
| MODEL_COMMAND_1999 | MODEL_GRAYMODE_NO | MODEL_1440DPI_YES
| MODEL_ROLLFEED_YES | MODEL_ZEROMARGIN_NO),
64, 4, 64, 4, 360, 360, INCH(24), INCH(1200), 9, 9, 0, 9, 1, 0,
{ -1, 2, -1, 4, 0, 4, 0 },
{ 2.0, 1.3, 1.3, .646, .646, .323, .323, .1615, .0808 },
&simple_6color_inks
},
/* 29: Stylus Pro 7500 */
{
(MODEL_INIT_900 | MODEL_HASBLACK_YES | MODEL_INK_SELECTABLE
| MODEL_6COLOR_YES | MODEL_720DPI_DEFAULT | MODEL_VARIABLE_NORMAL
| MODEL_COMMAND_1999 | MODEL_GRAYMODE_NO | MODEL_1440DPI_YES
| MODEL_ROLLFEED_YES | MODEL_ZEROMARGIN_NO),
64, 4, 64, 4, 360, 360, INCH(24), INCH(1200), 9, 9, 0, 9, 1, 0,
{ -1, 2, -1, 4, 0, 4, 0 },
{ 2.0, 1.3, 1.3, .646, .646, .323, .323, .1615, .0808 },
&simple_6color_inks
},
/* 30: Stylus Pro 9000 */
{
(MODEL_INIT_900 | MODEL_HASBLACK_YES | MODEL_INK_NORMAL
| MODEL_6COLOR_YES | MODEL_720DPI_DEFAULT | MODEL_VARIABLE_NORMAL
| MODEL_COMMAND_1999 | MODEL_GRAYMODE_NO | MODEL_1440DPI_YES
| MODEL_ROLLFEED_YES | MODEL_ZEROMARGIN_NO),
64, 4, 64, 4, 360, 360, INCH(44), INCH(1200), 9, 9, 0, 9, 1, 0,
{ -1, 2, -1, 4, 0, 4, 0 },
{ 2.0, 1.3, 1.3, .646, .646, .323, .323, .1615, .0808 },
&simple_6color_inks
},
/* 31: Stylus Pro 9500 */
{
(MODEL_INIT_900 | MODEL_HASBLACK_YES | MODEL_INK_SELECTABLE
| MODEL_6COLOR_YES | MODEL_720DPI_DEFAULT | MODEL_VARIABLE_NORMAL
| MODEL_COMMAND_1999 | MODEL_GRAYMODE_NO | MODEL_1440DPI_YES
| MODEL_ROLLFEED_YES | MODEL_ZEROMARGIN_NO),
64, 4, 64, 4, 360, 360, INCH(44), INCH(1200), 9, 9, 0, 9, 1, 0,
{ -1, 2, -1, 4, 0, 4, 0 },
{ 2.0, 1.3, 1.3, .646, .646, .323, .323, .1615, .0808 },
&simple_6color_inks
},
};
typedef struct escp_init
{
int model;
int output_type;
int ydpi;
int xdpi;
int use_softweave;
int page_length;
int page_width;
int page_top;
int page_bottom;
int nozzles;
int nozzle_separation;
int horizontal_passes;
int vertical_passes;
int vertical_oversample;
int bits;
const char *paper_type;
} escp_init_t;
typedef struct {
const char name[65];
int hres;
int vres;
int softweave;
int vertical_passes;
int vertical_oversample;
} res_t;
static const res_t escp2_reslist[] = {
{ "180 DPI", 180, 180, 0, 1, 1 },
{ "360 DPI", 360, 360, 0, 1, 1 },
{ "360 DPI Softweave", 360, 360, 1, 1, 1 },
{ "360 DPI High Quality", 360, 360, 1, 2, 1 },
{ "720 DPI Microweave", 720, 720, 0, 1, 1 },
{ "720 DPI Softweave", 720, 720, 1, 1, 1 },
{ "720 DPI High Quality", 720, 720, 1, 2, 1 },
{ "720 DPI Highest Quality", 720, 720, 1, 4, 1 },
{ "1440 x 720 DPI Microweave", 1440, 720, 0, 1, 1 },
{ "1440 x 720 DPI Softweave", 1440, 720, 1, 1, 1 },
{ "1440 x 720 DPI Highest Quality", 1440, 720, 1, 2, 1 },
{ "1440 x 1440 DPI Emulated", 1440, 1440, 1, 1, 2 },
{ "1440 x 2880 DPI Emulated", 1440, 2880, 1, 1, 4 },
{ "", 0, 0, 0, 0, 0 }
};
typedef struct {
const char name[65];
int is_color;
int variable_dot_size;
int dot_size_bits;
simple_dither_range_t *standard_dither;
simple_dither_range_t *photo_dither;
} ink_t;
typedef struct {
const char name[65];
int paper_feed_sequence;
int platen_gap;
double base_density;
double k_lower_scale;
double k_upper;
} paper_t;
static const paper_t escp2_paper_list[] = {
{ "Plain Paper", 1, 0, .5, .25, .5 },
{ "Plain Paper Fast Load", 5, 0, .5, .25, .5 },
{ "Postcard", 2, 0, .6, .25, .6 },
{ "Glossy Film", 3, 0, 1.0, 1.0, .999 },
{ "Transparencies", 3, 0, 1.0, 1.0, .999 },
{ "Envelopes", 4, 0, .5, .25, .5 },
{ "Back Light Film", 6, 0, 1.0, 1.0, .999 },
{ "Matte Paper", 7, 0, 1.0, 1.0, .999 },
{ "Inkjet Paper", 7, 0, .78, .25, .6 },
{ "Photo Quality Inkjet Paper", 7, 0, 1, 1.0, .999 },
{ "Photo Paper", 8, 0, 1, 1.0, .999 },
{ "Premium Glossy Photo Paper", 8, 0, .9, 1.0, .999 },
{ "Photo Quality Glossy Paper", 6, 0, 1.0, 1.0, .999 },
{ "Other", 0, 0, .5, .25, .5 },
};
static const int paper_type_count = sizeof(escp2_paper_list) / sizeof(paper_t);
static const paper_t *
get_media_type(const char *name)
{
int i;
for (i = 0; i < paper_type_count; i++)
{
if (!strcmp(name, escp2_paper_list[i].name))
return &(escp2_paper_list[i]);
}
return NULL;
}
static int
escp2_has_cap(int model, model_featureset_t featureset,
model_featureset_t class)
{
return ((model_capabilities[model].flags & featureset) == class);
}
static unsigned
escp2_nozzles(int model)
{
return (model_capabilities[model].nozzles);
}
static unsigned
escp2_black_nozzles(int model)
{
return (model_capabilities[model].black_nozzles);
}
static unsigned
escp2_nozzle_separation(int model)
{
return (model_capabilities[model].nozzle_separation);
}
static unsigned
escp2_black_nozzle_separation(int model)
{
return (model_capabilities[model].black_nozzle_separation);
}
static unsigned
escp2_separation_rows(int model)
{
return (model_capabilities[model].separation_rows);
}
static unsigned
escp2_xres(int model)
{
return (model_capabilities[model].xres);
}
static unsigned
escp2_enhanced_xres(int model)
{
return (model_capabilities[model].enhanced_xres);
}
static int
escp2_ink_type(int model, int resolution, int microweave)
{
if (microweave)
{
switch (resolution)
{
case 180:
return model_capabilities[model].dot_sizes.dot_180;
case 360:
return model_capabilities[model].dot_sizes.dot_360_microweave;
case 720:
return model_capabilities[model].dot_sizes.dot_720_microweave;
case 1440:
return model_capabilities[model].dot_sizes.dot_1440_microweave;
default:
return -1;
}
}
else
{
switch (resolution)
{
case 180:
return model_capabilities[model].dot_sizes.dot_180;
case 360:
return model_capabilities[model].dot_sizes.dot_360;
case 720:
return model_capabilities[model].dot_sizes.dot_720;
case 1440:
return model_capabilities[model].dot_sizes.dot_1440;
default:
return -1;
}
}
}
static double
escp2_density(int model, int xdpi, int ydpi, int microweave)
{
if (microweave)
{
switch (xdpi)
{
case 180:
return model_capabilities[model].densities.d_180_180;
case 360:
return model_capabilities[model].densities.d_360_360_micro;
case 720:
return model_capabilities[model].densities.d_720_720_micro;
case 1440:
return model_capabilities[model].densities.d_1440_720_micro;
}
}
switch (xdpi)
{
case 180:
return model_capabilities[model].densities.d_180_180;
case 360:
return model_capabilities[model].densities.d_360_360;
case 720:
return model_capabilities[model].densities.d_720_720;
case 1440:
switch (ydpi)
{
case 720:
return model_capabilities[model].densities.d_1440_720;
case 1440:
return model_capabilities[model].densities.d_1440_1440;
case 2880:
return model_capabilities[model].densities.d_1440_2880;
}
}
return 0;
}
static escp2_variable_inkset_t *
escp2_inks(int model, int xdpi, int colors, int bits)
{
escp2_variable_inklist_t *inks = model_capabilities[model].inks;
switch (bits)
{
case 1:
switch (colors)
{
case 1:
case 4:
switch (xdpi)
{
case 180:
return inks->s_180_4;
case 360:
return inks->s_360_4;
case 720:
return inks->s_720_4;
case 1440:
return inks->s_1440_4;
}
case 6:
switch (xdpi)
{
case 180:
return inks->s_180_6;
case 360:
return inks->s_360_6;
case 720:
return inks->s_720_6;
case 1440:
return inks->s_1440_6;
}
}
case 2:
switch (colors)
{
case 1:
case 4:
switch (xdpi)
{
case 180:
return inks->v_180_4;
case 360:
return inks->v_360_4;
case 720:
return inks->v_720_4;
case 1440:
return inks->v_1440_4;
}
case 6:
switch (xdpi)
{
case 180:
return inks->v_180_6;
case 360:
return inks->v_360_6;
case 720:
return inks->v_720_6;
case 1440:
return inks->v_1440_6;
}
}
}
return NULL;
}
static unsigned
escp2_max_paper_width(int model)
{
return (model_capabilities[model].max_paper_width);
}
static unsigned
escp2_max_paper_height(int model)
{
return (model_capabilities[model].max_paper_height);
}
static unsigned
escp2_left_margin(int model)
{
return (model_capabilities[model].left_margin);
}
static unsigned
escp2_right_margin(int model)
{
return (model_capabilities[model].right_margin);
}
static unsigned
escp2_top_margin(int model)
{
return (model_capabilities[model].top_margin);
}
static unsigned
escp2_bottom_margin(int model)
{
return (model_capabilities[model].bottom_margin);
}
static int
escp2_pseudo_separation_rows(int model)
{
return (model_capabilities[model].pseudo_separation_rows);
}
/*
* 'escp2_parameters()' - Return the parameter values for the given parameter.
*/
char ** /* O - Parameter values */
escp2_parameters(const printer_t *printer, /* I - Printer model */
char *ppd_file, /* I - PPD file (not used) */
char *name, /* I - Name of parameter */
int *count) /* O - Number of values */
{
int i;
int model = printer->model;
char **valptrs;
static const char *ink_types[] =
{
"Six Color Photo",
"Four Color Standard"
};
if (count == NULL)
return (NULL);
*count = 0;
if (name == NULL)
return (NULL);
if (strcmp(name, "PageSize") == 0)
{
unsigned int length_limit, width_limit;
const papersize_t *papersizes = get_papersizes();
valptrs = malloc(sizeof(char *) * known_papersizes());
*count = 0;
width_limit = escp2_max_paper_width(model);
length_limit = escp2_max_paper_height(model);
for (i = 0; i < known_papersizes(); i++)
{
if (strlen(papersizes[i].name) > 0 &&
papersizes[i].width <= width_limit &&
papersizes[i].length <= length_limit)
{
valptrs[*count] = malloc(strlen(papersizes[i].name) + 1);
strcpy(valptrs[*count], papersizes[i].name);
(*count)++;
}
}
return (valptrs);
}
else if (strcmp(name, "Resolution") == 0)
{
const res_t *res = &(escp2_reslist[0]);
valptrs = malloc(sizeof(char *) * sizeof(escp2_reslist) / sizeof(res_t));
*count = 0;
while(res->hres)
{
if (escp2_ink_type(model, res->hres, !res->softweave) != -1)
{
int nozzles = escp2_nozzles(model);
int xdpi = res->hres;
int physical_xdpi = xdpi > 720 ? escp2_enhanced_xres(model) :
escp2_xres(model);
int horizontal_passes = xdpi / physical_xdpi;
int oversample = horizontal_passes * res->vertical_passes
* res->vertical_oversample;
if (horizontal_passes < 1)
horizontal_passes = 1;
if (oversample < 1)
oversample = 1;
if (((horizontal_passes * res->vertical_passes) <= 8) &&
(! res->softweave || (nozzles > 1 && nozzles > oversample)))
{
valptrs[*count] = malloc(strlen(res->name) + 1);
strcpy(valptrs[*count], res->name);
(*count)++;
}
}
res++;
}
return (valptrs);
}
else if (strcmp(name, "InkType") == 0)
{
if (escp2_has_cap(model, MODEL_6COLOR_MASK, MODEL_6COLOR_NO))
return NULL;
else
{
int ninktypes = sizeof(ink_types) / sizeof(char *);
valptrs = malloc(sizeof(char *) * ninktypes);
for (i = 0; i < ninktypes; i++)
{
valptrs[i] = malloc(strlen(ink_types[i]) + 1);
strcpy(valptrs[i], ink_types[i]);
}
*count = ninktypes;
return valptrs;
}
}
else if (strcmp(name, "MediaType") == 0)
{
int nmediatypes = paper_type_count;
valptrs = malloc(sizeof(char *) * nmediatypes);
for (i = 0; i < nmediatypes; i++)
{
valptrs[i] = malloc(strlen(escp2_paper_list[i].name) + 1);
strcpy(valptrs[i], escp2_paper_list[i].name);
}
*count = nmediatypes;
return valptrs;
}
else
return (NULL);
}
/*
* 'escp2_imageable_area()' - Return the imageable area of the page.
*/
void
escp2_imageable_area(const printer_t *printer, /* I - Printer model */
const vars_t *v, /* I */
int *left, /* O - Left position in points */
int *right, /* O - Right position in points */
int *bottom, /* O - Bottom position in points */
int *top) /* O - Top position in points */
{
int width, length; /* Size of page */
default_media_size(printer, v, &width, &length);
*left = escp2_left_margin(printer->model);
*right = width - escp2_right_margin(printer->model);
*top = length - escp2_top_margin(printer->model);
*bottom = escp2_bottom_margin(printer->model);
}
void
escp2_limit(const printer_t *printer, /* I - Printer model */
const vars_t *v, /* I */
int *width, /* O - Left position in points */
int *length) /* O - Top position in points */
{
*width = escp2_max_paper_width(printer->model);
*length = escp2_max_paper_height(printer->model);
}
const char *
escp2_default_resolution(const printer_t *printer)
{
const res_t *res = &(escp2_reslist[0]);
while (res->hres)
{
if (escp2_ink_type(printer->model, res->hres, !res->softweave) != -1)
{
int nozzles = escp2_nozzles(printer->model);
int xdpi = res->hres;
int physical_xdpi = xdpi > 720 ?
escp2_enhanced_xres(printer->model) : escp2_xres(printer->model);
int horizontal_passes = xdpi / physical_xdpi;
int oversample = horizontal_passes * res->vertical_passes
* res->vertical_oversample;
if (horizontal_passes < 1)
horizontal_passes = 1;
if (oversample < 1)
oversample = 1;
if (((horizontal_passes * res->vertical_passes) <= 8) &&
(! res->softweave || (nozzles > 1 && nozzles > oversample)))
return res->name;
}
res++;
}
return NULL;
}
static void
escp2_reset_printer(FILE *prn, escp_init_t *init)
{
/*
* Hack that seems to be necessary for these silly things to recognize
* the input. It only needs to be done once per printer evidently, but
* it needs to be done.
*/
if (escp2_has_cap(init->model, MODEL_INIT_MASK, MODEL_INIT_900))
fprintf(prn, "%c%c%c\033\001@EJL 1284.4\n@EJL \n\033@", 0, 0, 0);
fputs("\033@", prn); /* ESC/P2 reset */
}
static void
escp2_set_remote_sequence(FILE *prn, escp_init_t *init)
{
/* Magic remote mode commands, whatever they do */
if (escp2_has_cap(init->model, MODEL_COMMAND_MASK, MODEL_COMMAND_1999))
{
int feed_sequence = 0;
const paper_t *p = get_media_type(init->paper_type);
if (p)
feed_sequence = p->paper_feed_sequence;
fprintf(prn, /* Enter remote mode */
"\033(R\010%c%cREMOTE1"
/* Function unknown */
"PM\002%c%c%c"
/* Set mechanism sequence */
"SN\003%c%c%c%c",
0, 0,
0, 0, 0,
0, 0, 0, feed_sequence);
if (escp2_has_cap(init->model, MODEL_ZEROMARGIN_MASK,
MODEL_ZEROMARGIN_YES))
fprintf(prn, /* Set zero-margin print mode */
"FP\003%c%c\260\377", 0, 0);
fprintf(prn, /* Exit remote mode */
"\033%c%c%c", 0, 0, 0);
}
}
static void
escp2_set_graphics_mode(FILE *prn, escp_init_t *init)
{
fwrite("\033(G\001\000\001", 6, 1, prn); /* Enter graphics mode */
}
static void
escp2_set_resolution(FILE *prn, escp_init_t *init)
{
if (!(escp2_has_cap(init->model, MODEL_VARIABLE_DOT_MASK,
MODEL_VARIABLE_NORMAL)) &&
init->use_softweave)
fprintf(prn, "\033(U\005%c%c%c%c%c%c", 0, 1440 / init->ydpi,
1440 / init->ydpi,
1440 / (init->ydpi * (init->horizontal_passes > 2 ? 2 : 1)),
1440 % 256, 1440 / 256);
else
fprintf(prn, "\033(U\001%c%c", 0, 3600 / init->ydpi);
}
static void
escp2_set_color(FILE *prn, escp_init_t *init)
{
if (escp2_has_cap(init->model, MODEL_GRAYMODE_MASK, MODEL_GRAYMODE_YES))
fprintf(prn, "\033(K\002%c%c%c", 0, 0,
(init->output_type == OUTPUT_GRAY ? 1 : 2));
}
static void
escp2_set_microweave(FILE *prn, escp_init_t *init)
{
fprintf(prn, "\033(i\001%c%c", 0,
(init->use_softweave || init->ydpi < 720) ? 0 : 1);
}
static void
escp2_set_printhead_speed(FILE *prn, escp_init_t *init)
{
if (init->horizontal_passes * init->vertical_passes *
init->vertical_oversample * escp2_xres(init->model) / 720 > 2)
{
fprintf(prn, "\033U%c", 1);
if (init->xdpi > 720) /* Slow mode if available */
fprintf(prn, "\033(s%c%c%c", 1, 0, 2);
}
else
fprintf(prn, "\033U%c", 0);
}
static void
escp2_set_dot_size(FILE *prn, escp_init_t *init)
{
/* Dot size */
int drop_size = escp2_ink_type(init->model, init->xdpi,
!init->use_softweave);
if (drop_size >= 0)
fprintf(prn, "\033(e\002%c%c%c", 0, 0, drop_size);
}
static void
escp2_set_page_length(FILE *prn, escp_init_t *init)
{
int l = init->ydpi * init->page_length / 72;
if (!(escp2_has_cap(init->model, MODEL_VARIABLE_DOT_MASK,
MODEL_VARIABLE_NORMAL)) &&
init->use_softweave)
fprintf(prn, "\033(C\004%c%c%c%c%c", 0,
l & 0xff, (l >> 8) & 0xff, (l >> 16) & 0xff, (l >> 24) & 0xff);
else
fprintf(prn, "\033(C\002%c%c%c", 0, l & 255, l >> 8);
}
static void
escp2_set_margins(FILE *prn, escp_init_t *init)
{
int l = init->ydpi * (init->page_length - init->page_bottom) / 72;
int t = init->ydpi * (init->page_length - init->page_top) / 72;
if (!(escp2_has_cap(init->model, MODEL_VARIABLE_DOT_MASK,
MODEL_VARIABLE_NORMAL)) &&
init->use_softweave)
{
if (escp2_has_cap(init->model, MODEL_6COLOR_MASK, MODEL_6COLOR_YES))
fprintf(prn, "\033(c\010%c%c%c%c%c%c%c%c%c", 0,
t & 0xff, t >> 8, (t >> 16) & 0xff, (t >> 24) & 0xff,
l & 0xff, l >> 8, (l >> 16) & 0xff, (l >> 24) & 0xff);
else
fprintf(prn, "\033(c\004%c%c%c%c%c", 0,
t & 0xff, t >> 8, l & 0xff, l >> 8);
}
else
fprintf(prn, "\033(c\004%c%c%c%c%c", 0,
t & 0xff, t >> 8, l & 0xff, l >> 8);
}
static void
escp2_set_form_factor(FILE *prn, escp_init_t *init)
{
int page_width = init->page_width * init->ydpi / 72;
int page_length = init->page_length * init->ydpi / 72;
if (escp2_has_cap(init->model, MODEL_ZEROMARGIN_MASK, MODEL_ZEROMARGIN_YES))
/* Make the page 2/10" wider (probably ignored by the printer anyway) */
page_width += 144 * 720 / init->xdpi;
if (escp2_has_cap(init->model, MODEL_COMMAND_MASK, MODEL_COMMAND_1999))
fprintf(prn, "\033(S\010%c%c%c%c%c%c%c%c%c", 0,
((page_width >> 0) & 0xff), ((page_width >> 8) & 0xff),
((page_width >> 16) & 0xff), ((page_width >> 24) & 0xff),
((page_length >> 0) & 0xff), ((page_length >> 8) & 0xff),
((page_length >> 16) & 0xff), ((page_length >> 24) & 0xff));
}
static void
escp2_set_printhead_resolution(FILE *prn, escp_init_t *init)
{
if (!(escp2_has_cap(init->model, MODEL_VARIABLE_DOT_MASK,
MODEL_VARIABLE_NORMAL)) &&
init->use_softweave)
{
/* Magic resolution cookie */
if (init->xdpi > 720)
{
if (init->output_type == OUTPUT_GRAY)
fprintf(prn, "\033(D%c%c%c%c%c%c", 4, 0, 14400 % 256, 14400 / 256,
escp2_black_nozzle_separation(init->model) * 14400 / 720,
14400 / escp2_enhanced_xres(init->model));
else
fprintf(prn, "\033(D%c%c%c%c%c%c", 4, 0, 14400 % 256, 14400 / 256,
escp2_nozzle_separation(init->model) * 14400 / 720,
14400 / escp2_enhanced_xres(init->model));
}
else
{
if (init->output_type == OUTPUT_GRAY)
fprintf(prn, "\033(D%c%c%c%c%c%c", 4, 0, 14400 % 256, 14400 / 256,
escp2_black_nozzle_separation(init->model) * 14400 / 720,
14400 / escp2_xres(init->model));
else
fprintf(prn, "\033(D%c%c%c%c%c%c", 4, 0, 14400 % 256, 14400 / 256,
escp2_nozzle_separation(init->model) * 14400 / 720,
14400 / escp2_xres(init->model));
}
}
}
static void
escp2_init_printer(FILE *prn, escp_init_t *init)
{
if (init->ydpi > 720)
init->ydpi = 720;
escp2_reset_printer(prn, init);
escp2_set_remote_sequence(prn, init);
escp2_set_graphics_mode(prn, init);
escp2_set_resolution(prn, init);
escp2_set_color(prn, init);
escp2_set_microweave(prn, init);
escp2_set_printhead_speed(prn, init);
escp2_set_dot_size(prn, init);
escp2_set_page_length(prn, init);
escp2_set_margins(prn, init);
escp2_set_form_factor(prn, init);
escp2_set_printhead_resolution(prn, init);
}
static void
escp2_deinit_printer(FILE *prn, escp_init_t *init)
{
fputs(/* Eject page */
"\014"
/* ESC/P2 reset */
"\033@", prn);
if (escp2_has_cap(init->model, MODEL_COMMAND_MASK, MODEL_COMMAND_1999)) {
fprintf(prn, /* Enter remote mode */
"\033(R\010%c%cREMOTE1"
/* Load settings from NVRAM */
"LD%c%c"
/* Exit remote mode */
"\033%c%c%c", 0, 0, 0, 0, 0, 0, 0);
}
}
/*
* 'escp2_print()' - Print an image to an EPSON printer.
*/
void
escp2_print(const printer_t *printer, /* I - Model */
int copies, /* I - Number of copies */
FILE *prn, /* I - File to print to */
Image image, /* I - Image to print */
const vars_t *v)
{
unsigned char *cmap = v->cmap;
int model = printer->model;
const char *resolution = v->resolution;
const char *media_type = v->media_type;
int output_type = v->output_type;
int orientation = v->orientation;
const char *ink_type = v->ink_type;
double scaling = v->scaling;
int top = v->top;
int left = v->left;
int y; /* Looping vars */
int xdpi, ydpi; /* Resolution */
int physical_ydpi;
int physical_xdpi;
int n; /* Output number */
unsigned short *out; /* Output pixels (16-bit) */
unsigned char *in, /* Input pixels */
*black, /* Black bitmap data */
*cyan, /* Cyan bitmap data */
*magenta, /* Magenta bitmap data */
*lcyan, /* Light cyan bitmap data */
*lmagenta, /* Light magenta bitmap data */
*yellow; /* Yellow bitmap data */
int page_left, /* Left margin of page */
page_right, /* Right margin of page */
page_top, /* Top of page */
page_bottom, /* Bottom of page */
page_width, /* Width of page */
page_height, /* Height of page */
page_length, /* True length of page */
out_width, /* Width of image on page */
out_height, /* Height of image on page */
out_bpp, /* Output bytes per pixel */
length, /* Length of raster data */
errdiv, /* Error dividend */
errmod, /* Error modulus */
errval, /* Current error value */
errline, /* Current raster line */
errlast; /* Last raster line loaded */
convert_t colorfunc = 0; /* Color conversion function... */
int image_height,
image_width,
image_bpp;
int use_softweave = 0;
int nozzles = 1;
int nozzle_separation = 1;
int horizontal_passes = 1;
int vertical_passes = 1;
int vertical_oversample = 1;
int use_6color = 0;
const res_t *res;
int bits;
void * weave = NULL;
void * dither;
colormode_t colormode = COLOR_CCMMYK;
int separation_rows = escp2_separation_rows(model);
int ink_spread;
vars_t nv;
escp_init_t init;
escp2_variable_inkset_t *inks;
const paper_t *pt;
double k_upper, k_lower;
memcpy(&nv, v, sizeof(vars_t));
if (escp2_has_cap(model, MODEL_6COLOR_MASK, MODEL_6COLOR_YES) &&
strcmp(ink_type, "Four Color Standard") != 0 &&
nv.image_type != IMAGE_MONOCHROME)
use_6color = 1;
if (nv.image_type == IMAGE_MONOCHROME)
{
colormode = COLOR_MONOCHROME;
output_type = OUTPUT_GRAY;
bits = 1;
}
else if (output_type == OUTPUT_GRAY)
colormode = COLOR_MONOCHROME;
else if (use_6color)
colormode = COLOR_CCMMYK;
else
colormode = COLOR_CMYK;
/*
* Setup a read-only pixel region for the entire image...
*/
Image_init(image);
image_height = Image_height(image);
image_width = Image_width(image);
image_bpp = Image_bpp(image);
/*
* Choose the correct color conversion function...
*/
colorfunc = choose_colorfunc(output_type, image_bpp, cmap, &out_bpp, &nv);
/*
* Compute the output size...
*/
escp2_imageable_area(printer, &nv, &page_left, &page_right,
&page_bottom, &page_top);
compute_page_parameters(page_right, page_left, page_top, page_bottom,
scaling, image_width, image_height, image,
&orientation, &page_width, &page_height,
&out_width, &out_height, &left, &top);
/*
* Recompute the image height and width. If the image has been
* rotated, these will change from previously.
*/
image_height = Image_height(image);
image_width = Image_width(image);
/*
* Figure out the output resolution...
*/
for (res = &escp2_reslist[0];;res++)
{
if (!strcmp(resolution, res->name))
{
use_softweave = res->softweave;
xdpi = res->hres;
ydpi = res->vres;
vertical_passes = res->vertical_passes;
vertical_oversample = res->vertical_oversample;
if (xdpi > 720)
physical_xdpi = escp2_enhanced_xres(model);
else
physical_xdpi = escp2_xres(model);
if (use_softweave)
horizontal_passes = xdpi / physical_xdpi;
else
horizontal_passes = xdpi / 720;
if (horizontal_passes == 0)
horizontal_passes = 1;
if (output_type == OUTPUT_GRAY)
{
nozzles = escp2_black_nozzles(model);
if (nozzles == 0)
{
nozzle_separation = escp2_nozzle_separation(model);
nozzles = escp2_nozzles(model);
}
else
nozzle_separation = escp2_black_nozzle_separation(model);
}
else
{
nozzle_separation = escp2_nozzle_separation(model);
nozzles = escp2_nozzles(model);
}
if (ydpi < 720)
nozzle_separation = nozzle_separation * ydpi / 720;
break;
}
else if (!strcmp(resolution, ""))
{
return;
}
}
if (!(escp2_has_cap(model, MODEL_VARIABLE_DOT_MASK, MODEL_VARIABLE_NORMAL))
&& use_softweave)
bits = 2;
else
bits = 1;
/*
* Let the user know what we're doing...
*/
Image_progress_init(image);
/*
* Send ESC/P2 initialization commands...
*/
default_media_size(printer, &nv, &n, &page_length);
#if 0
/*
* I believe that this code is no longer needed. I think I put it in
* a while back because our softweave pattern couldn't handle the top
* and bottom of the page. Lying to the printer about the length of
* the page would allow us to print the entire image. With our current
* weave code able to use the entire width of the permitted region,
* this hack shouldn't be needed any more.
*/
page_length += (39 + (escp2_nozzles(model) * 2) *
escp2_nozzle_separation(model)) / 10; /* Top and bottom */
page_top += (39 + (escp2_nozzles(model) * 2) *
escp2_nozzle_separation(model)) / 10;
#endif
init.model = model;
init.output_type = output_type;
init.ydpi = ydpi;
init.xdpi = xdpi;
init.use_softweave = use_softweave;
init.page_length = page_length;
init.page_width = page_width;
init.page_top = page_top;
init.page_bottom = page_bottom;
init.horizontal_passes = horizontal_passes;
init.vertical_passes = vertical_passes;
init.vertical_oversample = vertical_oversample;
init.bits = bits;
init.paper_type = media_type;
escp2_init_printer(prn, &init);
/*
* Convert image size to printer resolution...
*/
out_width = xdpi * out_width / 72;
out_height = ydpi * out_height / 72;
physical_ydpi = ydpi;
if (ydpi > 720)
physical_ydpi = 720;
left = physical_ydpi * left / 72;
/*
* Adjust for zero-margin printing...
*/
if (escp2_has_cap(model, MODEL_ZEROMARGIN_MASK, MODEL_ZEROMARGIN_YES))
{
/*
* In zero-margin mode, the origin is about 3/20" to the left of the
* paper's left edge.
*/
left += 92 * physical_ydpi / 720;
}
/*
* Allocate memory for the raster data...
*/
length = (out_width + 7) / 8;
if (output_type == OUTPUT_GRAY)
{
black = malloc(length * bits);
cyan = NULL;
magenta = NULL;
lcyan = NULL;
lmagenta = NULL;
yellow = NULL;
}
else
{
cyan = malloc(length * bits);
magenta = malloc(length * bits);
yellow = malloc(length * bits);
if (escp2_has_cap(model, MODEL_HASBLACK_MASK, MODEL_HASBLACK_YES))
black = malloc(length * bits);
else
black = NULL;
if (use_6color) {
lcyan = malloc(length * bits);
lmagenta = malloc(length * bits);
} else {
lcyan = NULL;
lmagenta = NULL;
}
}
if (use_softweave)
/* Epson printers are all 720 physical dpi */
weave = initialize_weave(nozzles, nozzle_separation, horizontal_passes,
vertical_passes, vertical_oversample, colormode,
bits,
out_width * escp2_xres(model) / physical_ydpi,
out_height, separation_rows,
top * physical_ydpi / 72,
page_height * physical_ydpi / 72, use_softweave);
else
escp2_init_microweave(top * ydpi / 72);
/*
* Compute the LUT. For now, it's 8 bit, but that may eventually
* sometimes change.
*/
pt = get_media_type(nv.media_type);
if (pt)
nv.density *= pt->base_density;
else
nv.density *= .5; /* Can't find paper type? Assume plain */
nv.density *= escp2_density(model, xdpi, ydpi, !use_softweave);
if (nv.density > 1.0)
nv.density = 1.0;
compute_lut(256, &nv);
/*
* Output the page...
*/
if (xdpi > ydpi)
dither = init_dither(image_width, out_width, 1, xdpi / ydpi, &nv);
else
dither = init_dither(image_width, out_width, ydpi / xdpi, 1, &nv);
dither_set_black_levels(dither, 1.0, 1.0, 1.0);
if (use_6color)
k_lower = .4 / bits + .1;
else
k_lower = .25 / bits;
if (pt)
{
k_lower *= pt->k_lower_scale;
k_upper = pt->k_upper;
}
else
{
k_lower *= .5;
k_upper = .5;
}
dither_set_black_lower(dither, k_lower);
dither_set_black_upper(dither, k_upper);
if (bits == 2)
{
if (use_6color)
dither_set_adaptive_divisor(dither, 8);
else
dither_set_adaptive_divisor(dither, 16);
}
else
dither_set_adaptive_divisor(dither, 4);
inks = escp2_inks(model, xdpi, use_6color ? 6 : 4, bits);
if (inks->c)
dither_set_c_ranges(dither, inks->c->count, inks->c->range,
inks->c->density * nv.density);
if (inks->m)
dither_set_m_ranges(dither, inks->m->count, inks->m->range,
inks->m->density * nv.density);
if (inks->y)
dither_set_y_ranges(dither, inks->y->count, inks->y->range,
inks->y->density * nv.density);
if (inks->k)
dither_set_k_ranges(dither, inks->k->count, inks->k->range,
inks->k->density * nv.density);
if (bits == 2)
{
if (use_6color)
dither_set_transition(dither, .7);
else
dither_set_transition(dither, .5);
}
if (!strcmp(nv.dither_algorithm, "Ordered"))
dither_set_transition(dither, 1);
switch (nv.image_type)
{
case IMAGE_LINE_ART:
dither_set_ink_spread(dither, 19);
break;
case IMAGE_SOLID_TONE:
dither_set_ink_spread(dither, 15);
break;
case IMAGE_CONTINUOUS:
ink_spread = 13;
if (ydpi > 720)
ink_spread++;
if (bits > 1)
ink_spread++;
dither_set_ink_spread(dither, ink_spread);
break;
}
dither_set_density(dither, nv.density);
in = malloc(image_width * image_bpp);
out = malloc(image_width * out_bpp * 2);
errdiv = image_height / out_height;
errmod = image_height % out_height;
errval = 0;
errlast = -1;
errline = 0;
QUANT(0);
for (y = 0; y < out_height; y ++)
{
int duplicate_line = 1;
if ((y & 63) == 0)
Image_note_progress(image, y, out_height);
if (errline != errlast)
{
errlast = errline;
duplicate_line = 0;
Image_get_row(image, in, errline);
(*colorfunc)(in, out, image_width, image_bpp, cmap, &nv);
}
QUANT(1);
if (nv.image_type == IMAGE_MONOCHROME)
dither_monochrome(out, y, dither, black, duplicate_line);
else if (output_type == OUTPUT_GRAY)
dither_black(out, y, dither, black, duplicate_line);
else
dither_cmyk(out, y, dither, cyan, lcyan, magenta, lmagenta,
yellow, 0, black, duplicate_line);
QUANT(2);
if (use_softweave)
escp2_write_weave(weave, prn, length, ydpi, model, out_width, left,
xdpi, physical_xdpi,
cyan, magenta, yellow, black, lcyan, lmagenta);
else
escp2_write_microweave(prn, black, cyan, magenta, yellow, lcyan,
lmagenta, length, xdpi, ydpi, model,
out_width, left, bits);
QUANT(3);
errval += errmod;
errline += errdiv;
if (errval >= out_height)
{
errval -= out_height;
errline ++;
}
QUANT(4);
}
Image_progress_conclude(image);
if (use_softweave)
escp2_flush_all(weave, model, out_width, left, ydpi, xdpi, physical_xdpi,
prn);
else
escp2_free_microweave();
QUANT(5);
free_dither(dither);
/*
* Cleanup...
*/
free_lut(&nv);
free(in);
free(out);
if (use_softweave)
destroy_weave(weave);
if (black != NULL)
free(black);
if (cyan != NULL)
{
free(cyan);
free(magenta);
free(yellow);
}
if (lcyan != NULL)
{
free(lcyan);
free(lmagenta);
}
escp2_deinit_printer(prn, &init);
#ifdef QUANTIFY
print_timers();
#endif
}
static void
escp2_fold(const unsigned char *line,
int single_length,
unsigned char *outbuf)
{
int i;
memset(outbuf, 0, single_length * 2);
for (i = 0; i < single_length; i++)
{
unsigned char l0 = line[0];
unsigned char l1 = line[single_length];
if (l0 || l1)
{
outbuf[0] =
((l0 & (1 << 7)) >> 1) +
((l0 & (1 << 6)) >> 2) +
((l0 & (1 << 5)) >> 3) +
((l0 & (1 << 4)) >> 4) +
((l1 & (1 << 7)) >> 0) +
((l1 & (1 << 6)) >> 1) +
((l1 & (1 << 5)) >> 2) +
((l1 & (1 << 4)) >> 3);
outbuf[1] =
((l0 & (1 << 3)) << 3) +
((l0 & (1 << 2)) << 2) +
((l0 & (1 << 1)) << 1) +
((l0 & (1 << 0)) << 0) +
((l1 & (1 << 3)) << 4) +
((l1 & (1 << 2)) << 3) +
((l1 & (1 << 1)) << 2) +
((l1 & (1 << 0)) << 1);
}
line++;
outbuf += 2;
}
}
static void
escp2_split_2_1(int length,
const unsigned char *in,
unsigned char *outhi,
unsigned char *outlo)
{
unsigned char *outs[2];
int i;
int row = 0;
int limit = length * 2;
outs[0] = outhi;
outs[1] = outlo;
memset(outs[1], 0, limit);
for (i = 0; i < limit; i++)
{
unsigned char inbyte = in[i];
outs[0][i] = 0;
if (inbyte == 0)
continue;
/* For some reason gcc isn't unrolling this, even with -funroll-loops */
if (inbyte & 1)
{
outs[row][i] |= 1 & inbyte;
row = row ^ 1;
}
if (inbyte & (1 << 1))
{
outs[row][i] |= (1 << 1) & inbyte;
row = row ^ 1;
}
if (inbyte & (1 << 2))
{
outs[row][i] |= (1 << 2) & inbyte;
row = row ^ 1;
}
if (inbyte & (1 << 3))
{
outs[row][i] |= (1 << 3) & inbyte;
row = row ^ 1;
}
if (inbyte & (1 << 4))
{
outs[row][i] |= (1 << 4) & inbyte;
row = row ^ 1;
}
if (inbyte & (1 << 5))
{
outs[row][i] |= (1 << 5) & inbyte;
row = row ^ 1;
}
if (inbyte & (1 << 6))
{
outs[row][i] |= (1 << 6) & inbyte;
row = row ^ 1;
}
if (inbyte & (1 << 7))
{
outs[row][i] |= (1 << 7) & inbyte;
row = row ^ 1;
}
}
}
static void
escp2_split_2_2(int length,
const unsigned char *in,
unsigned char *outhi,
unsigned char *outlo)
{
unsigned char *outs[2];
int i;
unsigned row = 0;
int limit = length * 2;
outs[0] = outhi;
outs[1] = outlo;
memset(outs[1], 0, limit);
for (i = 0; i < limit; i++)
{
unsigned char inbyte = in[i];
outs[0][i] = 0;
if (inbyte == 0)
continue;
/* For some reason gcc isn't unrolling this, even with -funroll-loops */
if (inbyte & 3)
{
outs[row][i] |= (3 & inbyte);
row = row ^ 1;
}
if (inbyte & (3 << 2))
{
outs[row][i] |= ((3 << 2) & inbyte);
row = row ^ 1;
}
if (inbyte & (3 << 4))
{
outs[row][i] |= ((3 << 4) & inbyte);
row = row ^ 1;
}
if (inbyte & (3 << 6))
{
outs[row][i] |= ((3 << 6) & inbyte);
row = row ^ 1;
}
}
}
static void
escp2_split_2(int length,
int bits,
const unsigned char *in,
unsigned char *outhi,
unsigned char *outlo)
{
if (bits == 2)
escp2_split_2_2(length, in, outhi, outlo);
else
escp2_split_2_1(length, in, outhi, outlo);
}
static void
escp2_split_4_1(int length,
const unsigned char *in,
unsigned char *out0,
unsigned char *out1,
unsigned char *out2,
unsigned char *out3)
{
unsigned char *outs[4];
int i;
int row = 0;
int limit = length * 2;
outs[0] = out0;
outs[1] = out1;
outs[2] = out2;
outs[3] = out3;
memset(outs[1], 0, limit);
memset(outs[2], 0, limit);
memset(outs[3], 0, limit);
for (i = 0; i < limit; i++)
{
unsigned char inbyte = in[i];
outs[0][i] = 0;
if (inbyte == 0)
continue;
/* For some reason gcc isn't unrolling this, even with -funroll-loops */
if (inbyte & 1)
{
outs[row][i] |= 1 & inbyte;
row = (row + 1) & 3;
}
if (inbyte & (1 << 1))
{
outs[row][i] |= (1 << 1) & inbyte;
row = (row + 1) & 3;
}
if (inbyte & (1 << 2))
{
outs[row][i] |= (1 << 2) & inbyte;
row = (row + 1) & 3;
}
if (inbyte & (1 << 3))
{
outs[row][i] |= (1 << 3) & inbyte;
row = (row + 1) & 3;
}
if (inbyte & (1 << 4))
{
outs[row][i] |= (1 << 4) & inbyte;
row = (row + 1) & 3;
}
if (inbyte & (1 << 5))
{
outs[row][i] |= (1 << 5) & inbyte;
row = (row + 1) & 3;
}
if (inbyte & (1 << 6))
{
outs[row][i] |= (1 << 6) & inbyte;
row = (row + 1) & 3;
}
if (inbyte & (1 << 7))
{
outs[row][i] |= (1 << 7) & inbyte;
row = (row + 1) & 3;
}
}
}
static void
escp2_split_4_2(int length,
const unsigned char *in,
unsigned char *out0,
unsigned char *out1,
unsigned char *out2,
unsigned char *out3)
{
unsigned char *outs[4];
int i;
int row = 0;
int limit = length * 2;
outs[0] = out0;
outs[1] = out1;
outs[2] = out2;
outs[3] = out3;
memset(outs[1], 0, limit);
memset(outs[2], 0, limit);
memset(outs[3], 0, limit);
for (i = 0; i < limit; i++)
{
unsigned char inbyte = in[i];
outs[0][i] = 0;
if (inbyte == 0)
continue;
/* For some reason gcc isn't unrolling this, even with -funroll-loops */
if (inbyte & 3)
{
outs[row][i] |= 3 & inbyte;
row = (row + 1) & 3;
}
if (inbyte & (3 << 2))
{
outs[row][i] |= (3 << 2) & inbyte;
row = (row + 1) & 3;
}
if (inbyte & (3 << 4))
{
outs[row][i] |= (3 << 4) & inbyte;
row = (row + 1) & 3;
}
if (inbyte & (3 << 6))
{
outs[row][i] |= (3 << 6) & inbyte;
row = (row + 1) & 3;
}
}
}
static void
escp2_split_4(int length,
int bits,
const unsigned char *in,
unsigned char *out0,
unsigned char *out1,
unsigned char *out2,
unsigned char *out3)
{
if (bits == 2)
escp2_split_4_2(length, in, out0, out1, out2, out3);
else
escp2_split_4_1(length, in, out0, out1, out2, out3);
}
#if __BYTE_ORDER == __LITTLE_ENDIAN
#define SH20 0
#define SH21 8
#else
#define SH20 8
#define SH21 0
#endif
static void
escp2_unpack_2_1(int length,
const unsigned char *in,
unsigned char *out0,
unsigned char *out1)
{
unsigned char tempin,
bit,
temp0,
temp1;
for (bit = 128, temp0 = 0, temp1 = 0;
length > 0;
length --)
{
tempin = *in++;
if (tempin & 128)
temp0 |= bit;
if (tempin & 64)
temp1 |= bit;
bit >>= 1;
if (tempin & 32)
temp0 |= bit;
if (tempin & 16)
temp1 |= bit;
bit >>= 1;
if (tempin & 8)
temp0 |= bit;
if (tempin & 4)
temp1 |= bit;
bit >>= 1;
if (tempin & 2)
temp0 |= bit;
if (tempin & 1)
temp1 |= bit;
if (bit > 1)
bit >>= 1;
else
{
bit = 128;
*out0++ = temp0;
*out1++ = temp1;
temp0 = 0;
temp1 = 0;
}
}
if (bit < 128)
{
*out0++ = temp0;
*out1++ = temp1;
}
}
static void
escp2_unpack_2_2(int length,
const unsigned char *in,
unsigned char *out0,
unsigned char *out1)
{
unsigned char tempin,
shift,
temp0,
temp1;
length *= 2;
for (shift = 0, temp0 = 0, temp1 = 0;
length > 0;
length --)
{
/*
* Note - we can't use (tempin & N) >> (shift - M) since negative
* right-shifts are not always implemented.
*/
tempin = *in++;
if (tempin & 192)
temp0 |= (tempin & 192) >> shift;
if (tempin & 48)
temp1 |= ((tempin & 48) << 2) >> shift;
shift += 2;
if (tempin & 12)
temp0 |= ((tempin & 12) << 4) >> shift;
if (tempin & 3)
temp1 |= ((tempin & 3) << 6) >> shift;
if (shift < 6)
shift += 2;
else
{
shift = 0;
*out0++ = temp0;
*out1++ = temp1;
temp0 = 0;
temp1 = 0;
}
}
if (shift)
{
*out0++ = temp0;
*out1++ = temp1;
}
}
static void
escp2_unpack_2(int length,
int bits,
const unsigned char *in,
unsigned char *outlo,
unsigned char *outhi)
{
if (bits == 1)
escp2_unpack_2_1(length, in, outlo, outhi);
else
escp2_unpack_2_2(length, in, outlo, outhi);
}
#if __BYTE_ORDER == __LITTLE_ENDIAN
#define SH40 0
#define SH41 8
#define SH42 16
#define SH43 24
#else
#define SH40 24
#define SH41 16
#define SH42 8
#define SH43 0
#endif
static void
escp2_unpack_4_1(int length,
const unsigned char *in,
unsigned char *out0,
unsigned char *out1,
unsigned char *out2,
unsigned char *out3)
{
unsigned char tempin,
bit,
temp0,
temp1,
temp2,
temp3;
for (bit = 128, temp0 = 0, temp1 = 0, temp2 = 0, temp3 = 0;
length > 0;
length --)
{
tempin = *in++;
if (tempin & 128)
temp0 |= bit;
if (tempin & 64)
temp1 |= bit;
if (tempin & 32)
temp2 |= bit;
if (tempin & 16)
temp3 |= bit;
bit >>= 1;
if (tempin & 8)
temp0 |= bit;
if (tempin & 4)
temp1 |= bit;
if (tempin & 2)
temp2 |= bit;
if (tempin & 1)
temp3 |= bit;
if (bit > 1)
bit >>= 1;
else
{
bit = 128;
*out0++ = temp0;
*out1++ = temp1;
*out2++ = temp2;
*out3++ = temp3;
temp0 = 0;
temp1 = 0;
temp2 = 0;
temp3 = 0;
}
}
if (bit < 128)
{
*out0++ = temp0;
*out1++ = temp1;
*out2++ = temp2;
*out3++ = temp3;
}
}
static void
escp2_unpack_4_2(int length,
const unsigned char *in,
unsigned char *out0,
unsigned char *out1,
unsigned char *out2,
unsigned char *out3)
{
unsigned char tempin,
shift,
temp0,
temp1,
temp2,
temp3;
length *= 2;
for (shift = 0, temp0 = 0, temp1 = 0, temp2 = 0, temp3 = 0;
length > 0;
length --)
{
/*
* Note - we can't use (tempin & N) >> (shift - M) since negative
* right-shifts are not always implemented.
*/
tempin = *in++;
if (tempin & 192)
temp0 |= (tempin & 192) >> shift;
if (tempin & 48)
temp1 |= ((tempin & 48) << 2) >> shift;
if (tempin & 12)
temp2 |= ((tempin & 12) << 4) >> shift;
if (tempin & 3)
temp3 |= ((tempin & 3) << 6) >> shift;
if (shift < 6)
shift += 2;
else
{
shift = 0;
*out0++ = temp0;
*out1++ = temp1;
*out2++ = temp2;
*out3++ = temp3;
temp0 = 0;
temp1 = 0;
temp2 = 0;
temp3 = 0;
}
}
if (shift)
{
*out0++ = temp0;
*out1++ = temp1;
*out2++ = temp2;
*out3++ = temp3;
}
}
static void
escp2_unpack_4(int length,
int bits,
const unsigned char *in,
unsigned char *out0,
unsigned char *out1,
unsigned char *out2,
unsigned char *out3)
{
if (bits == 1)
escp2_unpack_4_1(length, in, out0, out1, out2, out3);
else
escp2_unpack_4_2(length, in, out0, out1, out2, out3);
}
static void
escp2_unpack_8_1(int length,
const unsigned char *in,
unsigned char *out0,
unsigned char *out1,
unsigned char *out2,
unsigned char *out3,
unsigned char *out4,
unsigned char *out5,
unsigned char *out6,
unsigned char *out7)
{
unsigned char tempin,
bit,
temp0,
temp1,
temp2,
temp3,
temp4,
temp5,
temp6,
temp7;
for (bit = 128, temp0 = 0, temp1 = 0, temp2 = 0,
temp3 = 0, temp4 = 0, temp5 = 0, temp6 = 0, temp7 = 0;
length > 0;
length --)
{
tempin = *in++;
if (tempin & 128)
temp0 |= bit;
if (tempin & 64)
temp1 |= bit;
if (tempin & 32)
temp2 |= bit;
if (tempin & 16)
temp3 |= bit;
if (tempin & 8)
temp4 |= bit;
if (tempin & 4)
temp5 |= bit;
if (tempin & 2)
temp6 |= bit;
if (tempin & 1)
temp7 |= bit;
if (bit > 1)
bit >>= 1;
else
{
bit = 128;
*out0++ = temp0;
*out1++ = temp1;
*out2++ = temp2;
*out3++ = temp3;
*out4++ = temp4;
*out5++ = temp5;
*out6++ = temp6;
*out7++ = temp7;
temp0 = 0;
temp1 = 0;
temp2 = 0;
temp3 = 0;
temp4 = 0;
temp5 = 0;
temp6 = 0;
temp7 = 0;
}
}
if (bit < 128)
{
*out0++ = temp0;
*out1++ = temp1;
*out2++ = temp2;
*out3++ = temp3;
*out4++ = temp4;
*out5++ = temp5;
*out6++ = temp6;
*out7++ = temp7;
}
}
static void
escp2_unpack_8_2(int length,
const unsigned char *in,
unsigned char *out0,
unsigned char *out1,
unsigned char *out2,
unsigned char *out3,
unsigned char *out4,
unsigned char *out5,
unsigned char *out6,
unsigned char *out7)
{
unsigned char tempin,
shift,
temp0,
temp1,
temp2,
temp3,
temp4,
temp5,
temp6,
temp7;
for (shift = 0, temp0 = 0, temp1 = 0,
temp2 = 0, temp3 = 0, temp4 = 0, temp5 = 0, temp6 = 0, temp7 = 0;
length > 0;
length --)
{
/*
* Note - we can't use (tempin & N) >> (shift - M) since negative
* right-shifts are not always implemented.
*/
tempin = *in++;
if (tempin & 192)
temp0 |= (tempin & 192) >> shift;
if (tempin & 48)
temp1 |= ((tempin & 48) << 2) >> shift;
if (tempin & 12)
temp2 |= ((tempin & 12) << 4) >> shift;
if (tempin & 3)
temp3 |= ((tempin & 3) << 6) >> shift;
tempin = *in++;
if (tempin & 192)
temp4 |= (tempin & 192) >> shift;
if (tempin & 48)
temp5 |= ((tempin & 48) << 2) >> shift;
if (tempin & 12)
temp6 |= ((tempin & 12) << 4) >> shift;
if (tempin & 3)
temp7 |= ((tempin & 3) << 6) >> shift;
if (shift < 6)
shift += 2;
else
{
shift = 0;
*out0++ = temp0;
*out1++ = temp1;
*out2++ = temp2;
*out3++ = temp3;
*out4++ = temp4;
*out5++ = temp5;
*out6++ = temp6;
*out7++ = temp7;
temp0 = 0;
temp1 = 0;
temp2 = 0;
temp3 = 0;
temp4 = 0;
temp5 = 0;
temp6 = 0;
temp7 = 0;
}
}
if (shift)
{
*out0++ = temp0;
*out1++ = temp1;
*out2++ = temp2;
*out3++ = temp3;
*out4++ = temp4;
*out5++ = temp5;
*out6++ = temp6;
*out7++ = temp7;
}
}
static void
escp2_unpack_8(int length,
int bits,
const unsigned char *in,
unsigned char *out0,
unsigned char *out1,
unsigned char *out2,
unsigned char *out3,
unsigned char *out4,
unsigned char *out5,
unsigned char *out6,
unsigned char *out7)
{
if (bits == 1)
escp2_unpack_8_1(length, in, out0, out1, out2, out3,
out4, out5, out6, out7);
else
escp2_unpack_8_2(length, in, out0, out1, out2, out3,
out4, out5, out6, out7);
}
static int
escp2_pack(const unsigned char *line,
int length,
unsigned char *comp_buf,
unsigned char **comp_ptr)
{
const unsigned char *start; /* Start of compressed data */
unsigned char repeat; /* Repeating char */
int count; /* Count of compressed bytes */
int tcount; /* Temporary count < 128 */
int active = 0; /* Have we found data? */
/*
* Compress using TIFF "packbits" run-length encoding...
*/
(*comp_ptr) = comp_buf;
while (length > 0)
{
/*
* Get a run of non-repeated chars...
*/
start = line;
line += 2;
length -= 2;
while (length > 0 && (line[-2] != line[-1] || line[-1] != line[0]))
{
if (! active && (line[-2] || line[-1] || line[0]))
active = 1;
line ++;
length --;
}
line -= 2;
length += 2;
/*
* Output the non-repeated sequences (max 128 at a time).
*/
count = line - start;
while (count > 0)
{
tcount = count > 128 ? 128 : count;
(*comp_ptr)[0] = tcount - 1;
memcpy((*comp_ptr) + 1, start, tcount);
(*comp_ptr) += tcount + 1;
start += tcount;
count -= tcount;
}
if (length <= 0)
break;
/*
* Find the repeated sequences...
*/
start = line;
repeat = line[0];
if (repeat)
active = 1;
line ++;
length --;
while (length > 0 && *line == repeat)
{
line ++;
length --;
}
/*
* Output the repeated sequences (max 128 at a time).
*/
count = line - start;
while (count > 0)
{
tcount = count > 128 ? 128 : count;
(*comp_ptr)[0] = 1 - tcount;
(*comp_ptr)[1] = repeat;
(*comp_ptr) += 2;
count -= tcount;
}
}
return active;
}
static unsigned char *microweave_s = 0;
static unsigned char *microweave_comp_ptr[6][4];
static int microweave_setactive[6][4];
static int accumulated_spacing = 0;
static int last_color = -1;
#define MICRO_S(c, l) (microweave_s + COMPBUFWIDTH * (l) + COMPBUFWIDTH * (c) * 4)
static void
escp2_init_microweave(int top)
{
if (!microweave_s)
microweave_s = malloc(6 * 4 * COMPBUFWIDTH);
accumulated_spacing = top;
}
static void
escp2_free_microweave()
{
if (microweave_s)
{
free(microweave_s);
microweave_s = NULL;
}
}
static int
escp2_do_microweave_pack(const unsigned char *line,
int length,
int oversample,
int bits,
int color)
{
static unsigned char *pack_buf = NULL;
static unsigned char *s[4] = { NULL, NULL, NULL, NULL };
const unsigned char *in;
int i;
int retval = 0;
if (!pack_buf)
pack_buf = malloc(COMPBUFWIDTH);
for (i = 0; i < oversample; i++)
{
if (!s[i])
s[i] = malloc(COMPBUFWIDTH);
}
if (!line ||
(line[0] == 0 && memcmp(line, line + 1, (bits * length) - 1) == 0))
{
for (i = 0; i < 4; i++)
microweave_setactive[color][i] = 0;
return 0;
}
if (bits == 1)
in = line;
else
{
escp2_fold(line, length, pack_buf);
in = pack_buf;
}
switch (oversample)
{
case 1:
memcpy(s[0], in, bits * length);
break;
case 2:
escp2_unpack_2(length, bits, in, s[0], s[1]);
break;
case 4:
escp2_unpack_4(length, bits, in, s[0], s[1], s[2], s[3]);
break;
}
for (i = 0; i < oversample; i++)
{
microweave_setactive[color][i] =
escp2_pack(s[i], length * bits, MICRO_S(color, i),
&(microweave_comp_ptr[color][i]));
retval |= microweave_setactive[color][i];
}
return retval;
}
static void
escp2_write_microweave(FILE *prn, /* I - Print file or command */
const unsigned char *k, /* I - Output bitmap data */
const unsigned char *c, /* I - Output bitmap data */
const unsigned char *m, /* I - Output bitmap data */
const unsigned char *y, /* I - Output bitmap data */
const unsigned char *lc, /* I - Output bitmap data */
const unsigned char *lm, /* I - Output bitmap data */
int length, /* I - Length of bitmap data */
int xdpi, /* I - Horizontal resolution */
int ydpi, /* I - Vertical resolution */
int model, /* I - Printer model */
int width, /* I - Printed width */
int offset, /* I - Offset from left side */
int bits)
{
int i, j;
int oversample = 1;
int gsetactive = 0;
if (xdpi > 720)
oversample = xdpi / 720;
gsetactive |= escp2_do_microweave_pack(k, length, oversample, bits, 0);
gsetactive |= escp2_do_microweave_pack(m, length, oversample, bits, 1);
gsetactive |= escp2_do_microweave_pack(c, length, oversample, bits, 2);
gsetactive |= escp2_do_microweave_pack(y, length, oversample, bits, 3);
gsetactive |= escp2_do_microweave_pack(lm, length, oversample, bits, 4);
gsetactive |= escp2_do_microweave_pack(lc, length, oversample, bits, 5);
if (!gsetactive)
{
accumulated_spacing++;
return;
}
for (i = 0; i < oversample; i++)
{
for (j = 0; j < 6; j++)
{
if (!microweave_setactive[j][i])
continue;
if (accumulated_spacing > 0)
fprintf(prn, "\033(v\002%c%c%c", 0, accumulated_spacing % 256,
(accumulated_spacing >> 8) % 256);
accumulated_spacing = 0;
/*
* Set the print head position.
*/
if (escp2_has_cap(model, MODEL_1440DPI_MASK, MODEL_1440DPI_YES) &&
xdpi > 720)
{
if (!escp2_has_cap(model, MODEL_VARIABLE_DOT_MASK,
MODEL_VARIABLE_NORMAL))
{
if (((offset * xdpi / 1440) + i) > 0)
fprintf(prn, "\033($%c%c%c%c%c%c", 4, 0,
((offset * xdpi / 1440) + i) & 255,
(((offset * xdpi / 1440) + i) >> 8) & 255,
(((offset * xdpi / 1440) + i) >> 16) & 255,
(((offset * xdpi / 1440) + i) >> 24) & 255);
}
else
{
if (((offset * 1440 / ydpi) + i) > 0)
fprintf(prn, "\033(\\%c%c%c%c%c%c", 4, 0, 160, 5,
((offset * 1440 / ydpi) + i) & 255,
((offset * 1440 / ydpi) + i) >> 8);
}
}
else
{
if (offset > 0)
fprintf(prn, "\033\\%c%c", offset & 255, offset >> 8);
}
if (j != last_color)
{
if (escp2_has_cap(model, MODEL_6COLOR_MASK, MODEL_6COLOR_YES))
fprintf(prn, "\033(r\002%c%c%c", 0, densities[j], colors[j]);
else
fprintf(prn, "\033r%c", colors[j]);
last_color = j;
}
/*
* Send a line of raster graphics...
*/
switch (ydpi) /* Raster graphics header */
{
case 180 :
fwrite("\033.\001\024\024\001", 6, 1, prn);
break;
case 360 :
fwrite("\033.\001\012\012\001", 6, 1, prn);
break;
case 720 :
if (escp2_has_cap(model, MODEL_720DPI_MODE_MASK,
MODEL_720DPI_600))
fwrite("\033.\001\050\005\001", 6, 1, prn);
else
fwrite("\033.\001\005\005\001", 6, 1, prn);
break;
}
putc(width & 255, prn); /* Width of raster line in pixels */
putc(width >> 8, prn);
fwrite(MICRO_S(j, i), microweave_comp_ptr[j][i] - MICRO_S(j, i),
1, prn);
putc('\r', prn);
}
}
accumulated_spacing++;
}
/*
* "Soft" weave
*
* The Epson Stylus Color/Photo printers don't have memory to print
* using all of the nozzles in the print head. For example, the Stylus Photo
* 700/EX has 32 nozzles. At 720 dpi, with an 8" wide image, a single line
* requires (8 * 720 * 6 / 8) bytes, or 4320 bytes (because the Stylus Photo
* printers have 6 ink colors). To use 32 nozzles would require 138240 bytes.
* It's actually worse than that, though, because the nozzles are spaced 8
* rows apart. Therefore, in order to store enough data to permit sending the
* page as a simple raster, the printer would require enough memory to store
* 256 rows, or 1105920 bytes. Considering that the Photo EX can print
* 11" wide, we're looking at more like 1.5 MB. In fact, these printers are
* capable of 1440 dpi horizontal resolution. This would require 3 MB. The
* printers actually have 64K-256K.
*
* With the newer (740/750 and later) printers it's even worse, since these
* printers support multiple dot sizes. But that's neither here nor there.
*
* Older Epson printers had a mode called MicroWeave (tm). In this mode, the
* host fed the printer individual rows of dots, and the printer bundled them
* up and sent them to the print head in the correct order to achieve high
* quality. This MicroWeave mode still works in new printers, but the
* implementation is very minimal: the printer uses exactly one nozzle of
* each color (the first one). This makes printing extremely slow (more than
* 30 minutes for one 8.5x11" page), although the quality is extremely high
* with no visible banding whatsoever. It's not good for the print head,
* though, since no ink is flowing through the other nozzles. This leads to
* drying of ink and possible permanent damage to the print head.
*
* By the way, although the Epson manual says that microweave mode should be
* used at 720 dpi, 360 dpi continues to work in much the same way. At 360
* dpi, data is fed to the printer one row at a time on all Epson printers.
* The pattern that the printer uses to print is very prone to banding.
* However, 360 dpi is inherently a low quality mode; if you're using it,
* presumably you don't much care about quality.
*
* Printers from roughly the Stylus Color 600 and later do not have the
* capability to do MicroWeave correctly. Instead, the host must arrange
* the output in the order that it will be sent to the print head. This
* is a very complex process; the jets in the print head are spaced more
* than one row (1/720") apart, so we can't simply send consecutive rows
* of dots to the printer. Instead, we have to pass e. g. the first, ninth,
* 17th, 25th... rows in order for them to print in the correct position on
* the paper. This interleaving process is called "soft" weaving.
*
* This decision was probably made to save money on memory in the printer.
* It certainly makes the driver code far more complicated than it would
* be if the printer could arrange the output. Is that a bad thing?
* Usually this takes far less CPU time than the dithering process, and it
* does allow us more control over the printing process, e. g. to reduce
* banding. Conceivably, we could even use this ability to map out bad
* jets.
*
* Interestingly, apparently the Windows (and presumably Macintosh) drivers
* for most or all Epson printers still list a "microweave" mode.
* Experiments have demonstrated that this does not in fact use the
* "microweave" mode of the printer. Possibly it does nothing, or it uses
* a different weave pattern from what the non-"microweave" mode does.
* This is unnecessarily confusing.
*
* What makes this interesting is that there are many different ways of
* of accomplishing this goal. The naive way would be to divide the image
* up into groups of 256 rows, and print all the mod8=0 rows in the first pass,
* mod8=1 rows in the second, and so forth. The problem with this approach
* is that the individual ink jets are not perfectly uniform; some emit
* slightly bigger or smaller drops than others. Since each group of 8
* adjacent rows is printed with the same nozzle, that means that there will
* be distinct streaks of lighter and darker bands within the image (8 rows
* is 1/90", which is visible; 1/720" is not). Possibly worse is that these
* patterns will repeat every 256 rows. This creates banding patterns that
* are about 1/3" wide.
*
* So we have to do something to break up this patterning.
*
* Epson does not publish the weaving algorithms that they use in their
* bundled drivers. Indeed, their developer web site
* (http://www.ercipd.com/isv/edr_docs.htm) does not even describe how to
* do this weaving at all; it says that the only way to achieve 720 dpi
* is to use MicroWeave. It does note (correctly) that 1440 dpi horizontal
* can only be achieved by the driver (i. e. in software). The manual
* actually makes it fairly clear how to do this (it requires two passes
* with horizontal head movement between passes), and it is presumably
* possible to do this with MicroWeave.
*
* The information about how to do this is apparently available under NDA.
* It's actually easy enough to reverse engineer what's inside a print file
* with a simple Perl script. There are presumably other printer commands
* that are not documented and may not be as easy to reverse engineer.
*
* I considered a few algorithms to perform the weave. The first one I
* devised let me use only (jets - distance_between_jets + 1) nozzles, or
* 25. This is OK in principle, but it's slower than using all nozzles.
* By playing around with it some more, I came up with an algorithm that
* lets me use all of the nozzles, except near the top and bottom of the
* page.
*
* This still produces some banding, though. Even better quality can be
* achieved by using multiple nozzles on the same line. How do we do this?
* In 1440x720 mode, we're printing two output lines at the same vertical
* position. However, if we want four passes, we have to effectively print
* each line twice. Actually doing this would increase the density, so
* what we do is print half the dots on each pass. This produces near-perfect
* output, and it's far faster than using (pseudo) "MicroWeave".
*
* The current algorithm is not completely general. The number of passes
* is limited to (nozzles / gap). On the Photo EX class printers, that limits
* it to 4 -- 32 nozzles, an inter-nozzle gap of 8 lines. Furthermore, there
* are a number of routines that are only coded up to 8 passes. Fortunately,
* this is enough passes to get rid of most banding. What's left is a very
* fine pattern that is sometimes described as "corduroy", since the pattern
* looks like that kind of fabric.
*
* Newer printers (those that support variable dot sizes, such as the 740,
* 1200, etc.) have an additional complication: when used in softweave mode,
* they operate at 360 dpi horizontal resolution. This requires FOUR passes
* to achieve 1440x720 dpi. Thus, to enable us to break up each row
* into separate sub-rows, we have to actually print each row eight times.
* Fortunately, all such printers have 48 nozzles and a gap of 6 rows,
* except for the high-speed 900, which uses 96 nozzles and a gap of 2 rows.
*
* I cannot let this entirely pass without commenting on the Stylus Color 440.
* This is a very low-end printer with 21 (!) nozzles and a separation of 8.
* The weave routine works correctly with single-pass printing, which is enough
* to minimally achieve 720 dpi output (it's physically a 720 dpi printer).
* However, the routine does not work correctly at more than one pass per row.
* Therefore, this printer bands badly.
*
* Yet another complication is how to get near the top and bottom of the page.
* This algorithm lets us print to within one head width of the top of the
* page, and a bit more than one head width from the bottom. That leaves a
* lot of blank space. Doing the weave properly outside of this region is
* increasingly difficult as we get closer to the edge of the paper; in the
* interior region, any nozzle can print any line, but near the top and
* bottom edges, only some nozzles can print. We've handled this for now by
* using the naive way mentioned above near the borders, and switching over
* to the high quality method in the interior. Unfortunately, this means
* that the quality is quite visibly degraded near the top and bottom of the
* page. Algorithms that degrade more gracefully are more complicated.
* Epson does not advertise that the printers can print at the very top of the
* page, although in practice most or all of them can. I suspect that the
* quality that can be achieved very close to the top is poor enough that
* Epson does not want to allow printing there. That is a valid decision,
* although we have taken another approach.
*
* To compute the weave information, we need to start with the following
* information:
*
* 1) The number of jets the print head has for each color;
*
* 2) The separation in rows between the jets;
*
* 3) The horizontal resolution of the printer;
*
* 4) The desired horizontal resolution of the output;
*
* 5) The desired extra passes to reduce banding.
*
* As discussed above, each row is actually printed in one or more passes
* of the print head; we refer to these as subpasses. For example, if we're
* printing at 1440(h)x720(v) on a printer with true horizontal resolution of
* 360 dpi, and we wish to print each line twice with different nozzles
* to reduce banding, we need to use 8 subpasses. The dither routine
* will feed us a complete row of bits for each color; we have to split that
* up, first by round robining the bits to ensure that they get printed at
* the right micro-position, and then to split up the bits that are actually
* turned on into two equal chunks to reduce banding.
*
* Given the above information, and the desired row index and subpass (which
* together form a line number), we can compute:
*
* 1) Which pass this line belongs to. Passes are numbered consecutively,
* and each pass must logically (see #3 below) start at no smaller a row
* number than the previous pass, as the printer cannot advance by a
* negative amount.
*
* 2) Which jet will print this line.
*
* 3) The "logical" first line of this pass. That is, what line would be
* printed by jet 0 in this pass. This number may be less than zero.
* If it is, there are ghost lines that don't actually contain any data.
* The difference between the logical first line of this pass and the
* logical first line of the preceding pass tells us how many lines must
* be advanced.
*
* 4) The "physical" first line of this pass. That is, the first line index
* that is actually printed in this pass. This information lets us know
* when we must prepare this pass.
*
* 5) The last line of this pass. This lets us know when we must actually
* send this pass to the printer.
*
* 6) The number of ghost rows this pass contains. We must still send the
* ghost data to the printer, so this lets us know how much data we must
* fill in prior to the start of the pass.
*
* The bookkeeping to keep track of all this stuff is quite hairy, and needs
* to be documented separately.
*
* The routine initialize_weave calculates the basic parameters, given
* the number of jets and separation between jets, in rows.
*
* -- Robert Krawitz <rlk@alum.mit.edu) November 3, 1999
*/
#endif /* !WEAVETEST */
typedef struct /* Weave parameters for a specific row */
{
int row; /* Absolute row # */
int pass; /* Computed pass # */
int jet; /* Which physical nozzle we're using */
int missingstartrows; /* Phantom rows (nonexistent rows that */
/* would be printed by nozzles lower than */
/* the first nozzle we're using this pass; */
/* with the current algorithm, always zero */
int logicalpassstart; /* Offset in rows (from start of image) */
/* that the printer must be for this row */
/* to print correctly with the specified jet */
int physpassstart; /* Offset in rows to the first row printed */
/* in this pass. Currently always equal to */
/* logicalpassstart */
int physpassend; /* Offset in rows (from start of image) to */
/* the last row that will be printed this */
/* pass (assuming that we're printing a full */
/* pass). */
} weave_t;
typedef struct /* Weave parameters for a specific pass */
{
int pass; /* Absolute pass number */
int missingstartrows; /* All other values the same as weave_t */
int logicalpassstart;
int physpassstart;
int physpassend;
int subpass;
} pass_t;
typedef union { /* Offsets from the start of each line */
unsigned long v[6]; /* (really pass) */
struct {
unsigned long k;
unsigned long m;
unsigned long c;
unsigned long y;
unsigned long M;
unsigned long C;
} p;
} lineoff_t;
typedef union { /* Is this line active? */
char v[6]; /* (really pass) */
struct {
char k;
char m;
char c;
char y;
char M;
char C;
} p;
} lineactive_t;
typedef union { /* Base pointers for each pass */
unsigned char *v[6];
struct {
unsigned char *k;
unsigned char *m;
unsigned char *c;
unsigned char *y;
unsigned char *M;
unsigned char *C;
} p;
} linebufs_t;
typedef struct {
linebufs_t *linebases; /* Base address of each row buffer */
lineoff_t *lineoffsets; /* Offsets within each row buffer */
lineactive_t *lineactive; /* Does this line have anything printed? */
int *linecounts; /* How many rows we've printed this pass */
pass_t *passes; /* Circular list of pass numbers */
int last_pass_offset; /* Starting row (offset from the start of */
/* the page) of the most recently printed */
/* pass (so we can determine how far to */
/* advance the paper) */
int last_pass; /* Number of the most recently printed pass */
int jets; /* Number of jets per color */
int separation; /* Offset from one jet to the next in rows */
void *weaveparm; /* Weave calculation parameter block */
int horizontal_weave; /* Number of horizontal passes required */
/* This is > 1 for some of the ultra-high */
/* resolution modes */
int vertical_subpasses; /* Number of passes per line (for better */
/* quality) */
int vmod; /* Number of banks of passes */
int oversample; /* Excess precision per row */
int ncolors; /* How many colors (1, 4, or 6) */
int horizontal_width; /* Line width in output pixels */
int vertical_height; /* Image height in output pixels */
int firstline; /* Actual first line (referenced to paper) */
int bitwidth; /* Bits per pixel */
int lineno;
int vertical_oversample; /* Vertical oversampling */
int current_vertical_subpass;
int separation_rows; /* Vertical spacing between rows. */
/* This is used for the 1520/3000, which */
/* use a funny value for the "print density */
/* in the vertical direction". */
int last_color;
} escp2_softweave_t;
#ifndef WEAVETEST
static inline int
get_color_by_params(int plane, int density)
{
if (plane > 4 || plane < 0 || density > 1 || density < 0)
return -1;
return color_indices[density * 8 + plane];
}
#endif
/*
* Initialize the weave parameters
*
* Rules:
*
* 1) Currently, osample * v_subpasses * v_subsample <= 8, and no one
* of these variables may exceed 4.
*
* 2) first_line >= 0
*
* 3) line_height < physlines
*
* 4) phys_lines >= 2 * jets * sep
*/
static void *
initialize_weave(int jets, /* Width of print head */
int sep, /* Separation in rows between jets */
int osample, /* Horizontal oversample */
int v_subpasses, /* Vertical passes */
int v_subsample, /* Vertical oversampling */
colormode_t colormode, /* mono, 4 color, 6 color */
int width, /* bits/pixel */
int linewidth, /* Width of a line, in pixels */
int lineheight, /* Number of lines that will be printed */
int separation_rows, /* Vertical spacing adjustment */
/* for weird printers (1520/3000, */
/* although they don't seem to do softweave */
/* anyway) */
int first_line, /* First line that will be printed on page */
int phys_lines, /* Total height of the page in rows */
int weave_strategy) /* Which weaving pattern to use */
{
int i;
escp2_softweave_t *sw = malloc(sizeof (escp2_softweave_t));
if (sw == 0)
return sw;
if (jets < 1)
jets = 1;
if (jets == 1 || sep < 1)
sep = 1;
if (v_subpasses < 1)
v_subpasses = 1;
sw->separation = sep;
sw->jets = jets;
sw->horizontal_weave = osample;
sw->vertical_oversample = v_subsample;
sw->vertical_subpasses = v_subpasses;
sw->oversample = osample * v_subpasses * v_subsample;
sw->firstline = first_line;
sw->lineno = first_line;
if (sw->oversample > jets) {
fprintf(stderr, "Weave error: oversample (%d) > jets (%d)\n",
sw->oversample, jets);
free(sw);
return 0;
}
sw->weaveparm = initialize_weave_params(sw->separation, sw->jets,
sw->oversample, first_line,
first_line + lineheight - 1,
phys_lines, weave_strategy);
/*
* The value of vmod limits how many passes may be unfinished at a time.
* If pass x is not yet printed, pass x+vmod cannot be started.
*/
sw->vmod = 2 * sw->separation * sw->oversample;
sw->separation_rows = separation_rows;
sw->bitwidth = width;
sw->last_pass_offset = 0;
sw->last_pass = -1;
sw->current_vertical_subpass = 0;
sw->last_color = -1;
switch (colormode)
{
case COLOR_MONOCHROME:
sw->ncolors = 1;
break;
case COLOR_CMYK:
sw->ncolors = 4;
break;
case COLOR_CCMMYK:
default:
sw->ncolors = 6;
break;
}
/*
* It's possible for the "compression" to actually expand the line by
* one part in 128.
*/
sw->horizontal_width = (linewidth + 128 + 7) * 129 / 128;
sw->vertical_height = lineheight;
sw->lineoffsets = malloc(sw->vmod * sizeof(lineoff_t));
memset(sw->lineoffsets, 0, sw->vmod * sizeof(lineoff_t));
sw->lineactive = malloc(sw->vmod * sizeof(lineactive_t));
sw->linebases = malloc(sw->vmod * sizeof(linebufs_t));
sw->passes = malloc(sw->vmod * sizeof(pass_t));
sw->linecounts = malloc(sw->vmod * sizeof(int));
memset(sw->linecounts, 0, sw->vmod * sizeof(int));
for (i = 0; i < sw->vmod; i++)
{
int j;
sw->passes[i].pass = -1;
for (j = 0; j < sw->ncolors; j++)
{
sw->linebases[i].v[j] =
malloc(jets * sw->bitwidth * sw->horizontal_width / 8);
}
}
return (void *) sw;
}
static void
destroy_weave(void *vsw)
{
int i, j;
escp2_softweave_t *sw = (escp2_softweave_t *) vsw;
free(sw->linecounts);
free(sw->passes);
free(sw->lineactive);
free(sw->lineoffsets);
for (i = 0; i < sw->vmod; i++)
{
for (j = 0; j < sw->ncolors; j++)
{
free(sw->linebases[i].v[j]);
}
}
free(sw->linebases);
destroy_weave_params(sw->weaveparm);
free(vsw);
}
static void
weave_parameters_by_row(const escp2_softweave_t *sw, int row,
int vertical_subpass, weave_t *w)
{
static const escp2_softweave_t *scache = 0;
static weave_t wcache;
static int rcache = -2;
static int vcache = -2;
int jetsused;
if (scache == sw && rcache == row && vcache == vertical_subpass)
{
memcpy(w, &wcache, sizeof(weave_t));
return;
}
scache = sw;
rcache = row;
vcache = vertical_subpass;
w->row = row;
calculate_row_parameters(sw->weaveparm, row, vertical_subpass,
&w->pass, &w->jet, &w->logicalpassstart,
&w->missingstartrows, &jetsused);
w->physpassstart = w->logicalpassstart + sw->separation * w->missingstartrows;
w->physpassend = w->physpassstart + sw->separation * (jetsused - 1);
memcpy(&wcache, w, sizeof(weave_t));
#if 0
printf("row %d, jet %d of pass %d "
"(pos %d, start %d, end %d, missing rows %d\n",
w->row, w->jet, w->pass, w->logicalpassstart, w->physpassstart,
w->physpassend, w->missingstartrows);
#endif
}
#ifndef WEAVETEST
static lineoff_t *
get_lineoffsets(const escp2_softweave_t *sw, int row, int subpass)
{
weave_t w;
weave_parameters_by_row(sw, row, subpass, &w);
return &(sw->lineoffsets[w.pass % sw->vmod]);
}
static lineactive_t *
get_lineactive(const escp2_softweave_t *sw, int row, int subpass)
{
weave_t w;
weave_parameters_by_row(sw, row, subpass, &w);
return &(sw->lineactive[w.pass % sw->vmod]);
}
static int *
get_linecount(const escp2_softweave_t *sw, int row, int subpass)
{
weave_t w;
weave_parameters_by_row(sw, row, subpass, &w);
return &(sw->linecounts[w.pass % sw->vmod]);
}
static const linebufs_t *
get_linebases(const escp2_softweave_t *sw, int row, int subpass)
{
weave_t w;
weave_parameters_by_row(sw, row, subpass, &w);
return &(sw->linebases[w.pass % sw->vmod]);
}
static pass_t *
get_pass_by_row(const escp2_softweave_t *sw, int row, int subpass)
{
weave_t w;
weave_parameters_by_row(sw, row, subpass, &w);
return &(sw->passes[w.pass % sw->vmod]);
}
static lineoff_t *
get_lineoffsets_by_pass(const escp2_softweave_t *sw, int pass)
{
return &(sw->lineoffsets[pass % sw->vmod]);
}
static lineactive_t *
get_lineactive_by_pass(const escp2_softweave_t *sw, int pass)
{
return &(sw->lineactive[pass % sw->vmod]);
}
static int *
get_linecount_by_pass(const escp2_softweave_t *sw, int pass)
{
return &(sw->linecounts[pass % sw->vmod]);
}
static const linebufs_t *
get_linebases_by_pass(const escp2_softweave_t *sw, int pass)
{
return &(sw->linebases[pass % sw->vmod]);
}
static pass_t *
get_pass_by_pass(const escp2_softweave_t *sw, int pass)
{
return &(sw->passes[pass % sw->vmod]);
}
/*
* If there are phantom rows at the beginning of a pass, fill them in so
* that the printer knows exactly what it doesn't have to print. We're
* using RLE compression here. Each line must be specified independently,
* so we have to compute how many full blocks (groups of 128 bytes, or 1024
* "off" pixels) and how much leftover is needed. Note that we can only
* RLE-encode groups of 2 or more bytes; single bytes must be specified
* with a count of 1.
*/
static void
fillin_start_rows(const escp2_softweave_t *sw, int row, int subpass,
int width, int missingstartrows)
{
lineoff_t *offsets = get_lineoffsets(sw, row, subpass);
const linebufs_t *bufs = get_linebases(sw, row, subpass);
int i = 0;
int k = 0;
int j;
width = sw->bitwidth * width * 8;
for (k = 0; k < missingstartrows; k++)
{
int bytes_to_fill = width;
int full_blocks = bytes_to_fill / (128 * 8);
int leftover = (7 + (bytes_to_fill % (128 * 8))) / 8;
int l = 0;
while (l < full_blocks)
{
for (j = 0; j < sw->ncolors; j++)
{
(bufs[0].v[j][2 * i]) = 129;
(bufs[0].v[j][2 * i + 1]) = 0;
}
i++;
l++;
}
if (leftover == 1)
{
for (j = 0; j < sw->ncolors; j++)
{
(bufs[0].v[j][2 * i]) = 1;
(bufs[0].v[j][2 * i + 1]) = 0;
}
i++;
}
else if (leftover > 0)
{
for (j = 0; j < sw->ncolors; j++)
{
(bufs[0].v[j][2 * i]) = 257 - leftover;
(bufs[0].v[j][2 * i + 1]) = 0;
}
i++;
}
}
for (j = 0; j < sw->ncolors; j++)
offsets[0].v[j] = 2 * i;
}
static void
initialize_row(const escp2_softweave_t *sw, int row, int width)
{
weave_t w;
int i;
for (i = 0; i < sw->oversample; i++)
{
weave_parameters_by_row(sw, row, i, &w);
if (w.physpassstart == row)
{
lineoff_t *lineoffs = get_lineoffsets(sw, row, i);
lineactive_t *lineactive = get_lineactive(sw, row, i);
int *linecount = get_linecount(sw, row, i);
int j;
pass_t *pass = get_pass_by_row(sw, row, i);
pass->pass = w.pass;
pass->missingstartrows = w.missingstartrows;
pass->logicalpassstart = w.logicalpassstart;
pass->physpassstart = w.physpassstart;
pass->physpassend = w.physpassend;
pass->subpass = i;
for (j = 0; j < sw->ncolors; j++)
{
if (lineoffs[0].v[j] != 0)
fprintf(stderr,
"WARNING: pass %d subpass %d row %d: lineoffs %ld\n",
w.pass, i, row, lineoffs[0].v[j]);
lineoffs[0].v[j] = 0;
lineactive[0].v[j] = 0;
}
if (*linecount != 0)
fprintf(stderr,
"WARNING: pass %d subpass %d row %d: linecount %d\n",
w.pass, i, row, *linecount);
*linecount = 0;
if (w.missingstartrows > 0)
fillin_start_rows(sw, row, i, width, w.missingstartrows);
}
}
}
/*
* A fair bit of this code is duplicated from escp2_write. That's rather
* a pity. It's also not correct for any but the 6-color printers. One of
* these days I'll unify it.
*/
static void
flush_pass(escp2_softweave_t *sw, int passno, int model, int width,
int hoffset, int ydpi, int xdpi, int physical_xdpi,
FILE *prn, int vertical_subpass)
{
int j;
lineoff_t *lineoffs = get_lineoffsets_by_pass(sw, passno);
lineactive_t *lineactive = get_lineactive_by_pass(sw, passno);
const linebufs_t *bufs = get_linebases_by_pass(sw, passno);
pass_t *pass = get_pass_by_pass(sw, passno);
int *linecount = get_linecount_by_pass(sw, passno);
int lwidth = (width + (sw->horizontal_weave - 1)) / sw->horizontal_weave;
int microoffset = vertical_subpass & (sw->horizontal_weave - 1);
if (ydpi > 720)
ydpi = 720;
for (j = 0; j < sw->ncolors; j++)
{
if (lineactive[0].v[j] == 0)
{
lineoffs[0].v[j] = 0;
continue;
}
if (pass->logicalpassstart > sw->last_pass_offset)
{
int advance = pass->logicalpassstart - sw->last_pass_offset -
(sw->separation_rows - 1);
int alo = advance % 256;
int ahi = advance / 256;
if (!escp2_has_cap(model, MODEL_VARIABLE_DOT_MASK,
MODEL_VARIABLE_NORMAL))
{
int a3 = (advance >> 16) % 256;
int a4 = (advance >> 24) % 256;
ahi = ahi % 256;
fprintf(prn, "\033(v\004%c%c%c%c%c", 0, alo, ahi, a3, a4);
}
else
fprintf(prn, "\033(v\002%c%c%c", 0, alo, ahi);
sw->last_pass_offset = pass->logicalpassstart;
}
if (last_color != j)
{
if (!escp2_has_cap(model, MODEL_VARIABLE_DOT_MASK,
MODEL_VARIABLE_NORMAL))
;
else if (escp2_has_cap(model, MODEL_6COLOR_MASK, MODEL_6COLOR_YES))
fprintf(prn, "\033(r\002%c%c%c", 0, densities[j], colors[j]);
else
fprintf(prn, "\033r%c", colors[j]);
last_color = j;
}
if (escp2_has_cap(model, MODEL_1440DPI_MASK, MODEL_1440DPI_YES))
{
/* FIXME need a more general way of specifying column */
/* separation */
if (escp2_has_cap(model, MODEL_COMMAND_MASK, MODEL_COMMAND_1999) &&
!(escp2_has_cap(model, MODEL_VARIABLE_DOT_MASK,
MODEL_VARIABLE_NORMAL)))
{
int pos = ((hoffset * xdpi / ydpi) + microoffset);
if (pos > 0)
fprintf(prn, "\033($%c%c%c%c%c%c", 4, 0,
pos & 255, (pos >> 8) & 255,
(pos >> 16) & 255, (pos >> 24) & 255);
}
else
{
int pos = ((hoffset * 1440 / ydpi) + microoffset);
if (pos > 0)
fprintf(prn, "\033(\\%c%c%c%c%c%c", 4, 0, 160, 5,
pos & 255, pos >> 8);
}
}
else
{
int pos = (hoffset + microoffset);
if (pos > 0)
fprintf(prn, "\033\\%c%c", pos & 255, pos >> 8);
}
if (!escp2_has_cap(model, MODEL_VARIABLE_DOT_MASK,
MODEL_VARIABLE_NORMAL))
{
int ncolor = (densities[j] << 4) | colors[j];
int nlines = *linecount + pass->missingstartrows;
int nwidth = sw->bitwidth * ((lwidth + 7) / 8);
fprintf(prn, "\033i%c%c%c%c%c%c%c", ncolor, 1, sw->bitwidth,
nwidth & 255, nwidth >> 8, nlines & 255, nlines >> 8);
}
else
{
int ydotsep = 3600 / ydpi;
int xdotsep = 3600 / physical_xdpi;
if (escp2_has_cap(model, MODEL_720DPI_MODE_MASK,
MODEL_720DPI_600))
fprintf(prn, "\033.%c%c%c%c", 1, 8 * ydotsep, xdotsep,
*linecount + pass->missingstartrows);
else if (escp2_pseudo_separation_rows(model) > 0)
fprintf(prn, "\033.%c%c%c%c", 1,
ydotsep * escp2_pseudo_separation_rows(model) , xdotsep,
*linecount + pass->missingstartrows);
else
fprintf(prn, "\033.%c%c%c%c", 1, ydotsep * sw->separation_rows,
xdotsep, *linecount + pass->missingstartrows);
putc(lwidth & 255, prn); /* Width of raster line in pixels */
putc(lwidth >> 8, prn);
}
fwrite(bufs[0].v[j], lineoffs[0].v[j], 1, prn);
lineoffs[0].v[j] = 0;
putc('\r', prn);
}
*linecount = 0;
sw->last_pass = pass->pass;
pass->pass = -1;
}
static void
add_to_row(escp2_softweave_t *sw, int row, unsigned char *buf, size_t nbytes,
int plane, int density, int setactive,
lineoff_t *lineoffs, lineactive_t *lineactive,
const linebufs_t *bufs)
{
int color = get_color_by_params(plane, density);
memcpy(bufs[0].v[color] + lineoffs[0].v[color], buf, nbytes);
lineoffs[0].v[color] += nbytes;
if (setactive)
lineactive[0].v[color] = 1;
}
static void
escp2_flush(void *vsw, int model, int width, int hoffset,
int ydpi, int xdpi, int physical_xdpi, FILE *prn)
{
escp2_softweave_t *sw = (escp2_softweave_t *) vsw;
while (1)
{
pass_t *pass = get_pass_by_pass(sw, sw->last_pass + 1);
/*
* This ought to be pass->physpassend > sw->lineno
* but that causes rubbish to be output for some reason.
*/
if (pass->pass < 0 || pass->physpassend >= sw->lineno)
return;
flush_pass(sw, pass->pass, model, width, hoffset, ydpi, xdpi,
physical_xdpi, prn, pass->subpass);
}
}
static void
escp2_flush_all(void *vsw, int model, int width, int hoffset,
int ydpi, int xdpi, int physical_xdpi, FILE *prn)
{
escp2_softweave_t *sw = (escp2_softweave_t *) vsw;
while (1)
{
pass_t *pass = get_pass_by_pass(sw, sw->last_pass + 1);
/*
* This ought to be pass->physpassend > sw->lineno
* but that causes rubbish to be output for some reason.
*/
if (pass->pass < 0)
return;
flush_pass(sw, pass->pass, model, width, hoffset, ydpi, xdpi,
physical_xdpi, prn, pass->subpass);
}
}
static void
finalize_row(escp2_softweave_t *sw, int row, int model, int width,
int hoffset, int ydpi, int xdpi, int physical_xdpi,
FILE *prn)
{
int i;
#if 0
printf("Finalizing row %d...\n", row);
#endif
for (i = 0; i < sw->oversample; i++)
{
weave_t w;
int *lines = get_linecount(sw, row, i);
weave_parameters_by_row(sw, row, i, &w);
(*lines)++;
if (w.physpassend == row)
{
#if 0
printf("Pass=%d, physpassend=%d, row=%d, lineno=%d, trying to flush...\n", w.pass, w.physpassend, row, sw->lineno);
#endif
escp2_flush(sw, model, width, hoffset, ydpi, xdpi, physical_xdpi, prn);
}
}
}
static void
escp2_write_weave(void * vsw,
FILE *prn, /* I - Print file or command */
int length, /* I - Length of bitmap data */
int ydpi, /* I - Vertical resolution */
int model, /* I - Printer model */
int width, /* I - Printed width */
int offset, /* I - Offset from left side of page */
int xdpi,
int physical_xdpi,
const unsigned char *c,
const unsigned char *m,
const unsigned char *y,
const unsigned char *k,
const unsigned char *C,
const unsigned char *M)
{
escp2_softweave_t *sw = (escp2_softweave_t *) vsw;
static unsigned char *s[8];
static unsigned char *fold_buf;
static unsigned char *comp_buf;
lineoff_t *lineoffs[8];
lineactive_t *lineactives[8];
const linebufs_t *bufs[8];
int xlength = (length + sw->horizontal_weave - 1) / sw->horizontal_weave;
unsigned char *comp_ptr;
int i, j;
int setactive;
int h_passes = sw->horizontal_weave * sw->vertical_subpasses;
const unsigned char *cols[6];
cols[0] = k;
cols[1] = m;
cols[2] = c;
cols[3] = y;
cols[4] = M;
cols[5] = C;
if (!fold_buf)
fold_buf = malloc(COMPBUFWIDTH);
if (!comp_buf)
comp_buf = malloc(COMPBUFWIDTH);
if (sw->current_vertical_subpass == 0)
initialize_row(sw, sw->lineno, xlength);
for (i = 0; i < h_passes; i++)
{
int cpass = sw->current_vertical_subpass * h_passes;
if (!s[i])
s[i] = malloc(COMPBUFWIDTH);
lineoffs[i] = get_lineoffsets(sw, sw->lineno, cpass + i);
lineactives[i] = get_lineactive(sw, sw->lineno, cpass + i);
bufs[i] = get_linebases(sw, sw->lineno, cpass + i);
}
for (j = 0; j < sw->ncolors; j++)
{
if (cols[j])
{
const unsigned char *in;
if (sw->bitwidth == 2)
{
escp2_fold(cols[j], length, fold_buf);
in = fold_buf;
}
else
in = cols[j];
if (h_passes > 1)
{
switch (sw->horizontal_weave)
{
case 2:
escp2_unpack_2(length, sw->bitwidth, in, s[0], s[1]);
break;
case 4:
escp2_unpack_4(length, sw->bitwidth, in,
s[0], s[1], s[2], s[3]);
break;
case 8:
escp2_unpack_8(length, sw->bitwidth, in,
s[0], s[1], s[2], s[3],
s[4], s[5], s[6], s[7]);
break;
}
switch (sw->vertical_subpasses)
{
case 4:
switch (sw->horizontal_weave)
{
case 1:
escp2_split_4(length, sw->bitwidth, in,
s[0], s[1], s[2], s[3]);
break;
case 2:
escp2_split_4(length, sw->bitwidth, s[0],
s[0], s[2], s[4], s[6]);
escp2_split_4(length, sw->bitwidth, s[1],
s[1], s[3], s[5], s[7]);
break;
}
break;
case 2:
switch (sw->horizontal_weave)
{
case 1:
escp2_split_2(xlength, sw->bitwidth, in, s[0], s[1]);
break;
case 2:
escp2_split_2(xlength, sw->bitwidth, s[0], s[0], s[2]);
escp2_split_2(xlength, sw->bitwidth, s[1], s[1], s[3]);
break;
case 4:
escp2_split_2(xlength, sw->bitwidth, s[0], s[0], s[4]);
escp2_split_2(xlength, sw->bitwidth, s[1], s[1], s[5]);
escp2_split_2(xlength, sw->bitwidth, s[2], s[2], s[6]);
escp2_split_2(xlength, sw->bitwidth, s[3], s[3], s[7]);
break;
}
break;
/* case 1 is taken care of because the various unpack */
/* functions will do the trick themselves */
}
for (i = 0; i < h_passes; i++)
{
setactive = escp2_pack(s[i], sw->bitwidth * xlength,
comp_buf, &comp_ptr);
add_to_row(sw, sw->lineno, comp_buf, comp_ptr - comp_buf,
colors[j], densities[j], setactive,
lineoffs[i], lineactives[i], bufs[i]);
}
}
else
{
setactive = escp2_pack(in, length * sw->bitwidth,
comp_buf, &comp_ptr);
add_to_row(sw, sw->lineno, comp_buf, comp_ptr - comp_buf,
colors[j], densities[j], setactive,
lineoffs[0], lineactives[0], bufs[0]);
}
}
}
sw->current_vertical_subpass++;
if (sw->current_vertical_subpass >= sw->vertical_oversample)
{
finalize_row(sw, sw->lineno, model, width, offset, ydpi, xdpi,
physical_xdpi, prn);
sw->lineno++;
sw->current_vertical_subpass = 0;
}
}
#endif