mirror of https://github.com/GNOME/gimp.git
4365 lines
119 KiB
C
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
|