mirror of https://github.com/GNOME/gimp.git
1531 lines
39 KiB
C
1531 lines
39 KiB
C
/*
|
|
* "$Id$"
|
|
*
|
|
* Print plug-in CANON BJL 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.
|
|
*/
|
|
|
|
|
|
/* TODO-LIST
|
|
*
|
|
* * implement the left border
|
|
*
|
|
*/
|
|
|
|
#include <stdarg.h>
|
|
#include "print.h"
|
|
|
|
/*
|
|
* Local functions...
|
|
*/
|
|
|
|
typedef struct {
|
|
int model;
|
|
int max_width; /* maximum printable paper size */
|
|
int max_height;
|
|
int max_xdpi;
|
|
int max_ydpi;
|
|
int max_quality;
|
|
int border_left;
|
|
int border_right;
|
|
int border_top;
|
|
int border_bottom;
|
|
int inks; /* installable cartridges (CANON_INK_*) */
|
|
int slots; /* available paperslots */
|
|
int features; /* special bjl settings */
|
|
} canon_cap_t;
|
|
|
|
static void canon_write_line(FILE *, canon_cap_t, int,
|
|
unsigned char *, int,
|
|
unsigned char *, int,
|
|
unsigned char *, int,
|
|
unsigned char *, int,
|
|
unsigned char *, int,
|
|
unsigned char *, int,
|
|
unsigned char *, int,
|
|
int, int, int, int);
|
|
|
|
#define PHYSICAL_BPI 1440
|
|
#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)
|
|
|
|
|
|
/* Codes for possible ink-tank combinations.
|
|
* Each combo is represented by the colors that can be used with
|
|
* the installed ink-tank(s)
|
|
* Combinations of the codes represent the combinations allowed for a model
|
|
* Note that only preferrable combinations should be used
|
|
*/
|
|
#define CANON_INK_K 1
|
|
#define CANON_INK_CMY 2
|
|
#define CANON_INK_CMYK 4
|
|
#define CANON_INK_CcMmYK 8
|
|
#define CANON_INK_CcMmYy 16
|
|
#define CANON_INK_CcMmYyK 32
|
|
|
|
#define CANON_INK_BLACK_MASK (CANON_INK_K|CANON_INK_CMYK|\
|
|
CANON_INK_CcMmYK|CANON_INK_CcMmYyK)
|
|
|
|
#define CANON_INK_PHOTO_MASK (CANON_INK_CcMmYy|CANON_INK_CcMmYK|\
|
|
CANON_INK_CcMmYyK)
|
|
|
|
/* document feeding */
|
|
#define CANON_SLOT_ASF1 1
|
|
#define CANON_SLOT_ASF2 2
|
|
#define CANON_SLOT_MAN1 4
|
|
#define CANON_SLOT_MAN2 8
|
|
|
|
/* model peculiarities */
|
|
#define CANON_CAP_DMT 1<<0 /* Drop Modulation Technology */
|
|
#define CANON_CAP_MSB_FIRST 1<<1 /* how to send data */
|
|
#define CANON_CAP_CMD61 1<<2 /* uses command #0x61 */
|
|
#define CANON_CAP_CMD6d 1<<3 /* uses command #0x6d */
|
|
#define CANON_CAP_CMD70 1<<4 /* uses command #0x70 */
|
|
#define CANON_CAP_CMD72 1<<5 /* uses command #0x72 */
|
|
|
|
|
|
static canon_cap_t canon_model_capabilities[] =
|
|
{
|
|
/* default settings for unkown models */
|
|
|
|
{ -1, 8*72,11*72,180,180,20,20,20,20, CANON_INK_K, CANON_SLOT_ASF1, 0 },
|
|
|
|
/* tested models */
|
|
|
|
{ /* Canon BJC 4300 */
|
|
4300,
|
|
618, 936, /* 8.58" x 13 " */
|
|
1440, 720, 2,
|
|
11, 9, 10, 18,
|
|
CANON_INK_CMYK | CANON_INK_CcMmYK,
|
|
CANON_SLOT_ASF1 | CANON_SLOT_MAN1,
|
|
CANON_CAP_DMT
|
|
},
|
|
|
|
{ /* Canon BJC 4400 */
|
|
4400,
|
|
9.5*72, 14*72,
|
|
720, 360, 2,
|
|
11, 9, 10, 18,
|
|
CANON_INK_K | CANON_INK_CMYK | CANON_INK_CcMmYK,
|
|
CANON_SLOT_ASF1,
|
|
CANON_CAP_CMD61 | CANON_CAP_DMT
|
|
},
|
|
|
|
{ /* Canon BJC 6000 */
|
|
6000,
|
|
618, 936, /* 8.58" x 13 " */
|
|
1440, 720, 2,
|
|
11, 9, 10, 18,
|
|
CANON_INK_CMYK | CANON_INK_CcMmYK,
|
|
CANON_SLOT_ASF1 | CANON_SLOT_MAN1,
|
|
CANON_CAP_DMT
|
|
},
|
|
|
|
{ /* Canon BJC 8200 */
|
|
8200,
|
|
11*72, 17*72,
|
|
1200,1200, 4,
|
|
11, 9, 10, 18,
|
|
CANON_INK_CMYK | CANON_INK_CcMmYK,
|
|
CANON_SLOT_ASF1,
|
|
CANON_CAP_DMT | CANON_CAP_CMD72
|
|
},
|
|
|
|
/* untested models */
|
|
|
|
{ /* Canon BJC 1000 */
|
|
1000,
|
|
11*72, 17*72,
|
|
360, 360, 2,
|
|
11, 9, 10, 18,
|
|
CANON_INK_K | CANON_INK_CMY,
|
|
CANON_SLOT_ASF1,
|
|
CANON_CAP_CMD61
|
|
},
|
|
{ /* Canon BJC 2000 */
|
|
2000,
|
|
11*72, 17*72,
|
|
720, 360, 2,
|
|
11, 9, 10, 18,
|
|
CANON_INK_CMYK,
|
|
CANON_SLOT_ASF1,
|
|
CANON_CAP_CMD61
|
|
},
|
|
{ /* Canon BJC 3000 */
|
|
3000,
|
|
11*72, 17*72,
|
|
1440, 720, 2,
|
|
11, 9, 10, 18,
|
|
CANON_INK_CMYK | CANON_INK_CcMmYK,
|
|
CANON_SLOT_ASF1,
|
|
CANON_CAP_CMD61 | CANON_CAP_DMT
|
|
},
|
|
{ /* Canon BJC 6100 */
|
|
6100,
|
|
11*72, 17*72,
|
|
1440, 720, 2,
|
|
11, 9, 10, 18,
|
|
CANON_INK_CMYK | CANON_INK_CcMmYK,
|
|
CANON_SLOT_ASF1,
|
|
CANON_CAP_CMD61
|
|
},
|
|
{ /* Canon BJC 7000 */
|
|
7000,
|
|
11*72, 17*72,
|
|
1200, 600, 2,
|
|
11, 9, 10, 18,
|
|
CANON_INK_CMYK | CANON_INK_CcMmYyK,
|
|
CANON_SLOT_ASF1,
|
|
0
|
|
},
|
|
{ /* Canon BJC 7100 */
|
|
7100,
|
|
11*72, 17*72,
|
|
1200, 600, 2,
|
|
11, 9, 10, 18,
|
|
CANON_INK_CMYK | CANON_INK_CcMmYyK,
|
|
CANON_SLOT_ASF1,
|
|
0
|
|
},
|
|
|
|
/* extremely fuzzy models */
|
|
|
|
{ /* Canon BJC 5100 */
|
|
5100,
|
|
17*72, 22*72,
|
|
1440, 720, 2,
|
|
11, 9, 10, 18,
|
|
CANON_INK_CMYK | CANON_INK_CcMmYK,
|
|
CANON_SLOT_ASF1,
|
|
CANON_CAP_DMT
|
|
},
|
|
{ /* Canon BJC 5500 */
|
|
5500,
|
|
22*72, 34*72,
|
|
720, 360, 2,
|
|
11, 9, 10, 18,
|
|
CANON_INK_CMYK | CANON_INK_CcMmYK,
|
|
CANON_SLOT_ASF1,
|
|
CANON_CAP_CMD61
|
|
},
|
|
{ /* Canon BJC 6500 */
|
|
6500,
|
|
17*72, 22*72,
|
|
1440, 720, 2,
|
|
11, 9, 10, 18,
|
|
CANON_INK_CMYK | CANON_INK_CcMmYK,
|
|
CANON_SLOT_ASF1,
|
|
CANON_CAP_CMD61 | CANON_CAP_DMT
|
|
},
|
|
{ /* Canon BJC 8500 */
|
|
8500,
|
|
17*72, 22*72,
|
|
1200,1200, 2,
|
|
11, 9, 10, 18,
|
|
CANON_INK_CMYK | CANON_INK_CcMmYK,
|
|
CANON_SLOT_ASF1,
|
|
0
|
|
},
|
|
};
|
|
|
|
|
|
|
|
|
|
static canon_cap_t canon_get_model_capabilities(int model)
|
|
{
|
|
int i;
|
|
int models= sizeof(canon_model_capabilities) / sizeof(canon_cap_t);
|
|
for (i=0; i<models; i++) {
|
|
if (canon_model_capabilities[i].model == model) {
|
|
return canon_model_capabilities[i];
|
|
}
|
|
}
|
|
#ifdef DEBUG
|
|
fprintf(stderr,"canon: model %d not found in capabilities list.\n",model);
|
|
#endif
|
|
return canon_model_capabilities[0];
|
|
}
|
|
|
|
static int
|
|
canon_media_type(const char *name, canon_cap_t caps)
|
|
{
|
|
if (!strcmp(name,"Plain Paper")) return 1;
|
|
if (!strcmp(name,"Transparencies")) return 2;
|
|
if (!strcmp(name,"Back Print Film")) return 3;
|
|
if (!strcmp(name,"Fabric Sheets")) return 4;
|
|
if (!strcmp(name,"Envelope")) return 5;
|
|
if (!strcmp(name,"High Resolution Paper")) return 6;
|
|
if (!strcmp(name,"T-Shirt Transfers")) return 7;
|
|
if (!strcmp(name,"High Gloss Film")) return 8;
|
|
if (!strcmp(name,"Glossy Photo Paper")) return 9;
|
|
if (!strcmp(name,"Glossy Photo Cards")) return 10;
|
|
if (!strcmp(name,"Photo Paper Pro")) return 11;
|
|
|
|
#ifdef DEBUG
|
|
fprintf(stderr,"canon: Unknown media type '%s' - reverting to plain\n",name);
|
|
#endif
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
canon_source_type(const char *name, canon_cap_t caps)
|
|
{
|
|
if (!strcmp(name,"Auto Sheet Feeder")) return 4;
|
|
if (!strcmp(name,"Manual with Pause")) return 0;
|
|
if (!strcmp(name,"Manual without Pause")) return 1;
|
|
|
|
#ifdef DEBUG
|
|
fprintf(stderr,"canon: Unknown source type '%s' - reverting to auto\n",name);
|
|
#endif
|
|
return 4;
|
|
}
|
|
|
|
static int
|
|
canon_printhead_type(const char *name, canon_cap_t caps)
|
|
{
|
|
if (!strcmp(name,"Black")) return 0;
|
|
if (!strcmp(name,"Color")) return 1;
|
|
if (!strcmp(name,"Black/Color")) return 2;
|
|
if (!strcmp(name,"Photo/Color")) return 3;
|
|
if (!strcmp(name,"Photo")) return 4;
|
|
if (!strcmp(name,"Black/Photo Color")) return 5;
|
|
|
|
if (*name == 0) {
|
|
if (caps.inks & CANON_INK_CMYK) return 2;
|
|
if (caps.inks & CANON_INK_CMY) return 1;
|
|
if (caps.inks & CANON_INK_K) return 0;
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
fprintf(stderr,"canon: Unknown head combo '%s' - reverting to black\n",name);
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
static unsigned char
|
|
canon_size_type(const vars_t *v, canon_cap_t caps)
|
|
{
|
|
const papersize_t *pp = get_papersize_by_size(v->page_height, v->page_width);
|
|
if (pp)
|
|
{
|
|
const char *name = pp->name;
|
|
/* built ins: */
|
|
if (!strcmp(name,"A5")) return 0x01;
|
|
if (!strcmp(name,"A4")) return 0x03;
|
|
if (!strcmp(name,"B5")) return 0x08;
|
|
if (!strcmp(name,"Letter")) return 0x0d;
|
|
if (!strcmp(name,"Legal")) return 0x0f;
|
|
if (!strcmp(name,"Envelope 10")) return 0x16;
|
|
if (!strcmp(name,"Envelope DL")) return 0x17;
|
|
if (!strcmp(name,"Letter+")) return 0x2a;
|
|
if (!strcmp(name,"A4+")) return 0x2b;
|
|
if (!strcmp(name,"Canon 4x2")) return 0x2d;
|
|
/* custom */
|
|
|
|
#ifdef DEBUG
|
|
fprintf(stderr,"canon: Unknown paper size '%s' - using custom\n",name);
|
|
} else {
|
|
fprintf(stderr,"canon: Couldn't look up paper size %dx%d - "
|
|
"using custom\n",v->page_height, v->page_width);
|
|
#endif
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static char *
|
|
c_strdup(const char *s)
|
|
{
|
|
char *ret = malloc(strlen(s) + 1);
|
|
strcpy(ret, s);
|
|
return ret;
|
|
}
|
|
|
|
const char *
|
|
canon_default_resolution(const printer_t *printer)
|
|
{
|
|
canon_cap_t caps= canon_get_model_capabilities(printer->model);
|
|
if (!(caps.max_xdpi%300))
|
|
return "300x300 DPI";
|
|
else
|
|
return "180x180 DPI";
|
|
}
|
|
|
|
/*
|
|
* 'canon_parameters()' - Return the parameter values for the given parameter.
|
|
*/
|
|
|
|
char ** /* O - Parameter values */
|
|
canon_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;
|
|
char **p= 0,
|
|
**valptrs= 0;
|
|
|
|
static char *media_types[] =
|
|
{
|
|
("Plain Paper"),
|
|
("Transparencies"),
|
|
("Back Print Film"),
|
|
("Fabric Sheets"),
|
|
("Envelope"),
|
|
("High Resolution Paper"),
|
|
("T-Shirt Transfers"),
|
|
("High Gloss Film"),
|
|
("Glossy Photo Paper"),
|
|
("Glossy Photo Cards"),
|
|
("Photo Paper Pro")
|
|
};
|
|
static char *media_sources[] =
|
|
{
|
|
("Auto Sheet Feeder"),
|
|
("Manual with Pause"),
|
|
("Manual without Pause"),
|
|
};
|
|
|
|
canon_cap_t caps= canon_get_model_capabilities(printer->model);
|
|
|
|
if (count == NULL)
|
|
return (NULL);
|
|
|
|
*count = 0;
|
|
|
|
if (name == NULL)
|
|
return (NULL);
|
|
|
|
if (strcmp(name, "PageSize") == 0) {
|
|
int length_limit, width_limit;
|
|
const papersize_t *papersizes = get_papersizes();
|
|
valptrs = malloc(sizeof(char *) * known_papersizes());
|
|
*count = 0;
|
|
|
|
width_limit = caps.max_width;
|
|
length_limit = caps.max_height;
|
|
|
|
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)
|
|
{
|
|
int x= caps.max_xdpi, y= caps.max_ydpi;
|
|
int c= 0;
|
|
valptrs = malloc(sizeof(char *) * 10);
|
|
if (!(caps.max_xdpi%300)) {
|
|
|
|
if ( 300<=x && 300<=y)
|
|
valptrs[c++]= c_strdup("300x300 DPI");
|
|
if ( 300<=x && 300<=y && (caps.features&CANON_CAP_DMT))
|
|
valptrs[c++]= c_strdup("300x300 DPI DMT");
|
|
if ( 600<=x && 600<=y)
|
|
valptrs[c++]= c_strdup("600x600 DPI");
|
|
if ( 600<=x && 600<=y && (caps.features&CANON_CAP_DMT))
|
|
valptrs[c++]= c_strdup("600x600 DPI DMT");
|
|
if (1200==x && 600==y)
|
|
valptrs[c++]= c_strdup("1200x600 DPI");
|
|
if (1200<=x && 1200<=y)
|
|
valptrs[c++]= c_strdup("1200x1200 DPI");
|
|
|
|
} else if (!(caps.max_xdpi%180)) {
|
|
|
|
if ( 180<=x && 180<=y)
|
|
valptrs[c++]= c_strdup("180x180 DPI");
|
|
if ( 360<=x && 360<=y)
|
|
valptrs[c++]= c_strdup("360x360 DPI");
|
|
if ( 360<=x && 360<=y && (caps.features&CANON_CAP_DMT))
|
|
valptrs[c++]= c_strdup("360x360 DPI DMT");
|
|
if ( 720==x && 360==y)
|
|
valptrs[c++]= c_strdup("720x360 DPI");
|
|
if ( 720<=x && 720<=y)
|
|
valptrs[c++]= c_strdup("720x720 DPI");
|
|
if (1440==x && 720==y)
|
|
valptrs[c++]= c_strdup("1440x720 DPI");
|
|
if (1440<=x &&1440<=y)
|
|
valptrs[c++]= c_strdup("1440x1440 DPI");
|
|
|
|
} else {
|
|
#ifdef DEBUG
|
|
fprintf(stderr,"canon: unknown resolution multiplier for model %d\n",
|
|
caps.model);
|
|
#endif
|
|
return 0;
|
|
}
|
|
*count= c;
|
|
p= valptrs;
|
|
}
|
|
else if (strcmp(name, "InkType") == 0)
|
|
{
|
|
int c= 0;
|
|
valptrs = malloc(sizeof(char *) * 5);
|
|
if ((caps.inks & CANON_INK_K))
|
|
valptrs[c++]= c_strdup("Black");
|
|
if ((caps.inks & CANON_INK_CMY))
|
|
valptrs[c++]= c_strdup("Color");
|
|
if ((caps.inks & CANON_INK_CMYK))
|
|
valptrs[c++]= c_strdup("Black/Color");
|
|
if ((caps.inks & CANON_INK_CcMmYK))
|
|
valptrs[c++]= c_strdup("Photo/Color");
|
|
if ((caps.inks & CANON_INK_CcMmYy))
|
|
valptrs[c++]= c_strdup("Photo");
|
|
if ((caps.inks & CANON_INK_CcMmYyK))
|
|
valptrs[c++]= c_strdup("Black/Photo Color");
|
|
*count = c;
|
|
p = valptrs;
|
|
}
|
|
else if (strcmp(name, "MediaType") == 0)
|
|
{
|
|
*count = 11;
|
|
p = media_types;
|
|
}
|
|
else if (strcmp(name, "InputSlot") == 0)
|
|
{
|
|
*count = 3;
|
|
p = media_sources;
|
|
}
|
|
else
|
|
return (NULL);
|
|
|
|
valptrs = malloc(*count * sizeof(char *));
|
|
for (i = 0; i < *count; i ++)
|
|
valptrs[i] = c_strdup(p[i]);
|
|
|
|
return (valptrs);
|
|
}
|
|
|
|
|
|
/*
|
|
* 'canon_imageable_area()' - Return the imageable area of the page.
|
|
*/
|
|
|
|
void
|
|
canon_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 */
|
|
|
|
canon_cap_t caps= canon_get_model_capabilities(printer->model);
|
|
|
|
default_media_size(printer, v, &width, &length);
|
|
|
|
*left = caps.border_left;
|
|
*right = width - caps.border_right;
|
|
*top = length - caps.border_top;
|
|
*bottom = caps.border_bottom;
|
|
}
|
|
|
|
void
|
|
canon_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 */
|
|
{
|
|
canon_cap_t caps= canon_get_model_capabilities(printer->model);
|
|
*width = caps.max_width;
|
|
*length = caps.max_height;
|
|
}
|
|
|
|
/*
|
|
* 'canon_cmd()' - Sends a command with variable args
|
|
*/
|
|
static void
|
|
canon_cmd(FILE *prn, /* I - the printer */
|
|
char *ini, /* I - 2 bytes start code */
|
|
char cmd, /* I - command code */
|
|
int num, /* I - number of arguments */
|
|
... /* I - the args themselves */
|
|
)
|
|
{
|
|
static int bufsize= 0;
|
|
static unsigned char *buffer;
|
|
int i;
|
|
va_list ap;
|
|
|
|
if (!buffer || (num > bufsize)) {
|
|
if (buffer)
|
|
free(buffer);
|
|
buffer = malloc(num);
|
|
bufsize= num;
|
|
if (!buffer) {
|
|
#ifdef DEBUG
|
|
fprintf(stderr,"\ncanon: *** buffer allocation failed...\n");
|
|
fprintf(stderr,"canon: *** command 0x%02x with %d args dropped\n\n",
|
|
cmd,num);
|
|
#endif
|
|
return;
|
|
}
|
|
}
|
|
if (num) {
|
|
va_start(ap, num);
|
|
for (i=0; i<num; i++)
|
|
buffer[i]= (unsigned char) va_arg(ap, int);
|
|
va_end(ap);
|
|
}
|
|
|
|
fwrite(ini,2,1,prn);
|
|
if (cmd) {
|
|
fputc(cmd,prn);
|
|
fputc((num & 255),prn);
|
|
fputc((num >> 8 ),prn);
|
|
fwrite(buffer,num,1,prn);
|
|
}
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
#define PUT(WHAT,VAL,RES) fprintf(stderr,"canon: "WHAT" is %04x =% 5d = %f\" = %f mm\n",(VAL),(VAL),(VAL)/(1.*RES),(VAL)/(RES/25.4))
|
|
#else
|
|
#define PUT(WHAT,VAL,RES) do {} while (0)
|
|
#endif
|
|
|
|
static void
|
|
canon_init_printer(FILE *prn, canon_cap_t caps,
|
|
int output_type, const char *media_str,
|
|
const vars_t *v, int print_head,
|
|
const char *source_str,
|
|
int xdpi, int ydpi,
|
|
int page_width, int page_height,
|
|
int top, int left,
|
|
int use_dmt)
|
|
{
|
|
#define MEDIACODES 11
|
|
static unsigned char mediacode_63[] = {
|
|
0x00,0x00,0x02,0x03,0x04,0x08,0x07,0x03,0x06,0x05,0x05,0x09
|
|
};
|
|
static unsigned char mediacode_6c[] = {
|
|
0x00,0x00,0x02,0x03,0x04,0x08,0x07,0x03,0x06,0x05,0x0a,0x09
|
|
};
|
|
|
|
#define ESC28 "\x1b\x28"
|
|
#define ESC5b "\x1b\x5b"
|
|
#define ESC40 "\x1b\x40"
|
|
|
|
unsigned char
|
|
arg_63_1 = 0x00,
|
|
arg_63_2 = 0x00, /* plain paper */
|
|
arg_63_3 = caps.max_quality, /* output quality */
|
|
arg_6c_1 = 0x00,
|
|
arg_6c_2 = 0x01, /* plain paper */
|
|
arg_6d_1 = 0x03, /* color printhead? */
|
|
arg_6d_2 = 0x00, /* 00=color 02=b/w */
|
|
arg_6d_3 = 0x00, /* only 01 for bjc8200 */
|
|
arg_6d_a = 0x03, /* A4 paper */
|
|
arg_6d_b = 0x00,
|
|
arg_70_1 = 0x02, /* A4 printable area */
|
|
arg_70_2 = 0xa6,
|
|
arg_70_3 = 0x01,
|
|
arg_70_4 = 0xe0,
|
|
arg_74_1 = 0x01, /* 1 bit per pixel */
|
|
arg_74_2 = 0x00, /* */
|
|
arg_74_3 = 0x01; /* 01 <= 360 dpi 09 >= 720 dpi */
|
|
|
|
int media= canon_media_type(media_str,caps);
|
|
int source= canon_source_type(source_str,caps);
|
|
|
|
int printable_width= page_width*10/12;
|
|
int printable_height= page_height*10/12;
|
|
|
|
arg_6d_a= canon_size_type(v,caps);
|
|
if (!arg_6d_a) arg_6d_b= 1;
|
|
|
|
if (caps.model<3000)
|
|
arg_63_1= arg_6c_1= 0x10;
|
|
else
|
|
arg_63_1= arg_6c_1= 0x30;
|
|
|
|
if (output_type==OUTPUT_GRAY) arg_63_1|= 0x01;
|
|
arg_6c_1|= (source & 0x0f);
|
|
|
|
if (print_head==0) arg_6d_1= 0x03;
|
|
else if (print_head<=2) arg_6d_1= 0x02;
|
|
else if (print_head<=4) arg_6d_1= 0x04;
|
|
if (output_type==OUTPUT_GRAY) arg_6d_2= 0x02;
|
|
|
|
if (caps.model==8200) arg_6d_3= 0x01;
|
|
|
|
arg_70_1= (printable_height >> 8) & 0xff;
|
|
arg_70_2= (printable_height) & 0xff;
|
|
arg_70_3= (printable_width >> 8) & 0xff;
|
|
arg_70_4= (printable_width) & 0xff;
|
|
|
|
if (xdpi==1440) arg_74_2= 0x04;
|
|
if (ydpi>=720) arg_74_3= 0x09;
|
|
|
|
if (media<MEDIACODES) {
|
|
arg_63_2= mediacode_63[media];
|
|
arg_6c_2= mediacode_6c[media];
|
|
}
|
|
|
|
if (use_dmt) {
|
|
arg_74_1= 0x02;
|
|
arg_74_2= 0x80;
|
|
arg_74_3= 0x09;
|
|
}
|
|
|
|
/* workaround for the bjc8200 - not really understood */
|
|
if (caps.model==8200 && use_dmt) {
|
|
arg_74_1= 0xff;
|
|
arg_74_2= 0x90;
|
|
arg_74_3= 0x04;
|
|
}
|
|
|
|
/*
|
|
#ifdef DEBUG
|
|
fprintf(stderr,"canon: printable size = %dx%d (%dx%d) %02x%02x %02x%02x\n",
|
|
page_width,page_height,printable_width,printable_height,
|
|
arg_70_1,arg_70_2,arg_70_3,arg_70_4);
|
|
#endif
|
|
*/
|
|
|
|
/* init printer */
|
|
|
|
canon_cmd(prn,ESC5b,0x4b, 2, 0x00,0x0f);
|
|
if (caps.features & CANON_CAP_CMD61)
|
|
canon_cmd(prn,ESC28,0x61, 1, 0x01);
|
|
canon_cmd(prn,ESC28,0x62, 1, 0x01);
|
|
canon_cmd(prn,ESC28,0x71, 1, 0x01);
|
|
|
|
if (caps.features & CANON_CAP_CMD6d)
|
|
canon_cmd(prn,ESC28,0x6d,12, arg_6d_1,
|
|
0xff,0xff,0x00,0x00,0x07,0x00,
|
|
arg_6d_a,arg_6d_b,arg_6d_2,0x00,arg_6d_3);
|
|
|
|
/* set resolution */
|
|
|
|
canon_cmd(prn,ESC28,0x64, 4, (ydpi >> 8 ), (ydpi & 255),
|
|
(xdpi >> 8 ), (xdpi & 255));
|
|
|
|
canon_cmd(prn,ESC28,0x74, 3, arg_74_1, arg_74_2, arg_74_3);
|
|
|
|
canon_cmd(prn,ESC28,0x63, 3, arg_63_1, arg_63_2, arg_63_3);
|
|
|
|
if (caps.features & CANON_CAP_CMD70)
|
|
canon_cmd(prn,ESC28,0x70, 8, arg_70_1, arg_70_2, 0x00, 0x00,
|
|
arg_70_3, arg_70_4, 0x00, 0x00);
|
|
|
|
canon_cmd(prn,ESC28,0x6c, 2, arg_6c_1, arg_6c_2);
|
|
|
|
if (caps.features & CANON_CAP_CMD72)
|
|
canon_cmd(prn,ESC28,0x72, 1, 0x61); /* whatever for - 8200 might need it */
|
|
|
|
/* some linefeeds */
|
|
|
|
top= (top*ydpi)/72;
|
|
PUT("topskip ",top,ydpi);
|
|
canon_cmd(prn,ESC28,0x65, 2, (top >> 8 ),(top & 255));
|
|
}
|
|
|
|
void canon_deinit_printer(FILE *prn, canon_cap_t caps)
|
|
{
|
|
/* eject page */
|
|
fputc(0x0c,prn);
|
|
|
|
/* say goodbye */
|
|
canon_cmd(prn,ESC28,0x62,1,0);
|
|
if (caps.features & CANON_CAP_CMD61)
|
|
canon_cmd(prn,ESC28,0x61, 1, 0x00);
|
|
canon_cmd(prn,ESC40,0,0);
|
|
fflush(prn);
|
|
}
|
|
|
|
|
|
/*
|
|
* 'alloc_buffer()' allocates buffer and fills it with 0
|
|
*/
|
|
static unsigned char *canon_alloc_buffer(int size)
|
|
{
|
|
unsigned char *buf= malloc(size);
|
|
if (buf) memset(buf,0,size);
|
|
return buf;
|
|
}
|
|
|
|
/*
|
|
* 'advance_buffer()' - Move (num) lines of length (len) down one line
|
|
* and sets first line to 0s
|
|
* accepts NULL pointers as buf
|
|
* !!! buf must contain more than (num) lines !!!
|
|
* also sets first line to 0s if num<1
|
|
*/
|
|
static void
|
|
canon_advance_buffer(unsigned char *buf, int len, int num)
|
|
{
|
|
if (!buf || !len) return;
|
|
if (num>0) memmove(buf+len,buf,len*num);
|
|
memset(buf,0,len);
|
|
}
|
|
|
|
/*
|
|
* 'canon_print()' - Print an image to a CANON printer.
|
|
*/
|
|
void
|
|
canon_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;
|
|
const char *media_source = v->media_source;
|
|
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 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 */
|
|
*yellow, /* Yellow bitmap data */
|
|
*lcyan, /* Light cyan bitmap data */
|
|
*lmagenta, /* Light magenta bitmap data */
|
|
*lyellow; /* Light yellow bitmap data */
|
|
int delay_k,
|
|
delay_c,
|
|
delay_m,
|
|
delay_y,
|
|
delay_lc,
|
|
delay_lm,
|
|
delay_ly,
|
|
delay_max;
|
|
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 */
|
|
buf_length, /* Length of raster data buffer (dmt) */
|
|
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_dmt = 0;
|
|
void * dither;
|
|
double the_levels[] = { 0.5, 0.75, 1.0 };
|
|
vars_t nv;
|
|
|
|
canon_cap_t caps= canon_get_model_capabilities(model);
|
|
int printhead= canon_printhead_type(ink_type,caps);
|
|
|
|
memcpy(&nv, v, sizeof(vars_t));
|
|
/*
|
|
PUT("top ",top,72);
|
|
PUT("left ",left,72);
|
|
*/
|
|
|
|
/*
|
|
* 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);
|
|
|
|
/* force grayscale if image is grayscale
|
|
* or single black cartridge installed
|
|
*/
|
|
|
|
if (nv.image_type == IMAGE_MONOCHROME)
|
|
{
|
|
output_type = OUTPUT_GRAY;
|
|
}
|
|
|
|
if (printhead == 0 || caps.inks == CANON_INK_K)
|
|
output_type = OUTPUT_GRAY;
|
|
|
|
/*
|
|
* Choose the correct color conversion function...
|
|
*/
|
|
|
|
colorfunc = choose_colorfunc(output_type, image_bpp, cmap, &out_bpp, &nv);
|
|
|
|
/*
|
|
* Figure out the output resolution...
|
|
*/
|
|
|
|
sscanf(resolution,"%dx%d",&xdpi,&ydpi);
|
|
#ifdef DEBUG
|
|
fprintf(stderr,"canon: resolution=%dx%d\n",xdpi,ydpi);
|
|
#endif
|
|
|
|
if (!strcmp(resolution+(strlen(resolution)-3),"DMT") &&
|
|
(caps.features & CANON_CAP_DMT) &&
|
|
nv.image_type != IMAGE_MONOCHROME) {
|
|
use_dmt= 1;
|
|
#ifdef DEBUG
|
|
fprintf(stderr,"canon: using drop modulation technology\n");
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
* Compute the output size...
|
|
*/
|
|
|
|
canon_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);
|
|
|
|
default_media_size(printer, &nv, &n, &page_length);
|
|
|
|
/*
|
|
PUT("top ",top,72);
|
|
PUT("left ",left,72);
|
|
PUT("page_top ",page_top,72);
|
|
PUT("page_bottom",page_bottom,72);
|
|
PUT("page_left ",page_left,72);
|
|
PUT("page_right ",page_right,72);
|
|
PUT("page_width ",page_width,72);
|
|
PUT("page_height",page_height,72);
|
|
PUT("page_length",page_length,72);
|
|
PUT("out_width ", out_width,xdpi);
|
|
PUT("out_height", out_height,ydpi);
|
|
*/
|
|
|
|
Image_progress_init(image);
|
|
|
|
PUT("top ",top,72);
|
|
PUT("left ",left,72);
|
|
|
|
canon_init_printer(prn, caps, output_type, media_type,
|
|
&nv, printhead, media_source,
|
|
xdpi, ydpi, page_width, page_height,
|
|
top,left,use_dmt);
|
|
|
|
/*
|
|
* Convert image size to printer resolution...
|
|
*/
|
|
|
|
out_width = xdpi * out_width / 72;
|
|
out_height = ydpi * out_height / 72;
|
|
|
|
/*
|
|
PUT("out_width ", out_width,xdpi);
|
|
PUT("out_height", out_height,ydpi);
|
|
*/
|
|
|
|
left = xdpi * left / 72;
|
|
|
|
PUT("leftskip",left,xdpi);
|
|
|
|
if(xdpi==1440){
|
|
delay_k= 0;
|
|
delay_c= 112;
|
|
delay_m= 224;
|
|
delay_y= 336;
|
|
delay_lc= 112;
|
|
delay_lm= 224;
|
|
delay_ly= 0;
|
|
delay_max= 336;
|
|
#ifdef DEBUG
|
|
fprintf(stderr,"canon: delay on!\n");
|
|
#endif
|
|
} else {
|
|
delay_k= delay_c= delay_m= delay_y= delay_lc= delay_lm= delay_ly=0;
|
|
delay_max=0;
|
|
#ifdef DEBUG
|
|
fprintf(stderr,"canon: delay off!\n");
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
* Allocate memory for the raster data...
|
|
*/
|
|
|
|
length = (out_width + 7) / 8;
|
|
|
|
if (use_dmt) {
|
|
buf_length= length*2;
|
|
} else {
|
|
buf_length= length;
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
fprintf(stderr,"canon: buflength is %d!\n",buf_length);
|
|
#endif
|
|
|
|
if (output_type == OUTPUT_GRAY) {
|
|
black = canon_alloc_buffer(buf_length*(delay_k+1));
|
|
cyan = NULL;
|
|
magenta = NULL;
|
|
lcyan = NULL;
|
|
lmagenta= NULL;
|
|
yellow = NULL;
|
|
lyellow = NULL;
|
|
} else {
|
|
cyan = canon_alloc_buffer(buf_length*(delay_c+1));
|
|
magenta = canon_alloc_buffer(buf_length*(delay_m+1));
|
|
yellow = canon_alloc_buffer(buf_length*(delay_y+1));
|
|
|
|
if ((caps.inks & CANON_INK_BLACK_MASK))
|
|
black = canon_alloc_buffer(buf_length*(delay_k+1));
|
|
else
|
|
black = NULL;
|
|
|
|
if (printhead==3 && (caps.inks & (CANON_INK_PHOTO_MASK))) {
|
|
lcyan = canon_alloc_buffer(buf_length*(delay_lc+1));
|
|
lmagenta = canon_alloc_buffer(buf_length*(delay_lm+1));
|
|
if ((caps.inks & CANON_INK_CcMmYy) ||
|
|
(caps.inks & CANON_INK_CcMmYyK))
|
|
lyellow = canon_alloc_buffer(buf_length*(delay_lc+1));
|
|
else
|
|
lyellow = NULL;
|
|
} else {
|
|
lcyan = NULL;
|
|
lmagenta = NULL;
|
|
lyellow = NULL;
|
|
}
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
fprintf(stderr,"canon: driver will use colors ");
|
|
if (cyan) fputc('C',stderr);
|
|
if (lcyan) fputc('c',stderr);
|
|
if (magenta) fputc('M',stderr);
|
|
if (lmagenta) fputc('m',stderr);
|
|
if (yellow) fputc('Y',stderr);
|
|
if (lyellow) fputc('y',stderr);
|
|
if (black) fputc('K',stderr);
|
|
fprintf(stderr,"\n");
|
|
#endif
|
|
|
|
#ifdef DEBUG
|
|
fprintf(stderr,"density is %f\n",nv.density);
|
|
#endif
|
|
|
|
nv.density = (nv.density * ydpi) / (xdpi * 1.0);
|
|
if (nv.density > 1.0)
|
|
nv.density = 1.0;
|
|
compute_lut(256, &nv);
|
|
|
|
#ifdef DEBUG
|
|
fprintf(stderr,"density is %f\n",nv.density);
|
|
#endif
|
|
|
|
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);
|
|
dither_set_black_lower(dither, .8 / ((1 << (use_dmt+1)) - 1));
|
|
/*
|
|
if (use_glossy_film)
|
|
*/
|
|
dither_set_black_upper(dither, .999);
|
|
/*
|
|
else
|
|
dither_set_black_upper(dither, .999);
|
|
*/
|
|
|
|
if (!use_dmt) {
|
|
dither_set_light_inks(dither,
|
|
(lcyan) ? (0.3333) : (0.0),
|
|
(lmagenta)? (0.3333) : (0.0),
|
|
(lyellow) ? (0.3333) : (0.0), nv.density);
|
|
}
|
|
|
|
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:
|
|
dither_set_ink_spread(dither, 14);
|
|
break;
|
|
}
|
|
dither_set_density(dither, nv.density);
|
|
|
|
if (use_dmt)
|
|
{
|
|
dither_set_c_ranges_simple(dither, 3, the_levels, nv.density);
|
|
dither_set_m_ranges_simple(dither, 3, the_levels, nv.density);
|
|
dither_set_y_ranges_simple(dither, 3, the_levels, nv.density);
|
|
dither_set_k_ranges_simple(dither, 3, the_levels, nv.density);
|
|
}
|
|
/*
|
|
* Output the page...
|
|
*/
|
|
|
|
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;
|
|
|
|
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);
|
|
}
|
|
|
|
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);
|
|
|
|
#ifdef DEBUG
|
|
/* fprintf(stderr,","); */
|
|
#endif
|
|
|
|
canon_write_line(prn, caps, ydpi,
|
|
black, delay_k,
|
|
cyan, delay_c,
|
|
magenta, delay_m,
|
|
yellow, delay_y,
|
|
lcyan, delay_lc,
|
|
lmagenta, delay_lm,
|
|
lyellow, delay_ly,
|
|
length, out_width, left, use_dmt);
|
|
|
|
#ifdef DEBUG
|
|
/* fprintf(stderr,"!"); */
|
|
#endif
|
|
|
|
canon_advance_buffer(black, buf_length,delay_k);
|
|
canon_advance_buffer(cyan, buf_length,delay_c);
|
|
canon_advance_buffer(magenta, buf_length,delay_m);
|
|
canon_advance_buffer(yellow, buf_length,delay_y);
|
|
canon_advance_buffer(lcyan, buf_length,delay_lc);
|
|
canon_advance_buffer(lmagenta,buf_length,delay_lm);
|
|
canon_advance_buffer(lyellow, buf_length,delay_ly);
|
|
|
|
errval += errmod;
|
|
errline += errdiv;
|
|
if (errval >= out_height)
|
|
{
|
|
errval -= out_height;
|
|
errline ++;
|
|
}
|
|
}
|
|
Image_progress_conclude(image);
|
|
|
|
free_dither(dither);
|
|
|
|
/*
|
|
* Flush delayed buffers...
|
|
*/
|
|
|
|
if (delay_max) {
|
|
#ifdef DEBUG
|
|
fprintf(stderr,"\ncanon: flushing %d possibly delayed buffers\n",
|
|
delay_max);
|
|
#endif
|
|
for (y= 0; y<delay_max; y++) {
|
|
|
|
canon_write_line(prn, caps, ydpi,
|
|
black, delay_k,
|
|
cyan, delay_c,
|
|
magenta, delay_m,
|
|
yellow, delay_y,
|
|
lcyan, delay_lc,
|
|
lmagenta, delay_lm,
|
|
lyellow, delay_ly,
|
|
length, out_width, left, use_dmt);
|
|
|
|
#ifdef DEBUG
|
|
/* fprintf(stderr,"-"); */
|
|
#endif
|
|
|
|
canon_advance_buffer(black, buf_length,delay_k);
|
|
canon_advance_buffer(cyan, buf_length,delay_c);
|
|
canon_advance_buffer(magenta, buf_length,delay_m);
|
|
canon_advance_buffer(yellow, buf_length,delay_y);
|
|
canon_advance_buffer(lcyan, buf_length,delay_lc);
|
|
canon_advance_buffer(lmagenta,buf_length,delay_lm);
|
|
canon_advance_buffer(lyellow, buf_length,delay_ly);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Cleanup...
|
|
*/
|
|
|
|
free_lut(&nv);
|
|
free(in);
|
|
free(out);
|
|
|
|
if (black != NULL) free(black);
|
|
if (cyan != NULL) free(cyan);
|
|
if (magenta != NULL) free(magenta);
|
|
if (yellow != NULL) free(yellow);
|
|
if (lcyan != NULL) free(lcyan);
|
|
if (lmagenta != NULL) free(lmagenta);
|
|
if (lyellow != NULL) free(lyellow);
|
|
|
|
canon_deinit_printer(prn, caps);
|
|
}
|
|
|
|
/*
|
|
* 'canon_fold_lsb_msb()' fold 2 lines in order lsb/msb
|
|
*/
|
|
|
|
static void
|
|
canon_fold_lsb_msb(const unsigned char *line,
|
|
int single_length,
|
|
unsigned char *outbuf)
|
|
{
|
|
int i;
|
|
for (i = 0; i < single_length; i++) {
|
|
outbuf[0] =
|
|
((line[0] & (1 << 7)) >> 1) |
|
|
((line[0] & (1 << 6)) >> 2) |
|
|
((line[0] & (1 << 5)) >> 3) |
|
|
((line[0] & (1 << 4)) >> 4) |
|
|
((line[single_length] & (1 << 7)) >> 0) |
|
|
((line[single_length] & (1 << 6)) >> 1) |
|
|
((line[single_length] & (1 << 5)) >> 2) |
|
|
((line[single_length] & (1 << 4)) >> 3);
|
|
outbuf[1] =
|
|
((line[0] & (1 << 3)) << 3) |
|
|
((line[0] & (1 << 2)) << 2) |
|
|
((line[0] & (1 << 1)) << 1) |
|
|
((line[0] & (1 << 0)) << 0) |
|
|
((line[single_length] & (1 << 3)) << 4) |
|
|
((line[single_length] & (1 << 2)) << 3) |
|
|
((line[single_length] & (1 << 1)) << 2) |
|
|
((line[single_length] & (1 << 0)) << 1);
|
|
line++;
|
|
outbuf += 2;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* 'canon_fold_msb_lsb()' fold 2 lines in order msb/lsb
|
|
*/
|
|
|
|
static void
|
|
canon_fold_msb_lsb(const unsigned char *line,
|
|
int single_length,
|
|
unsigned char *outbuf)
|
|
{
|
|
int i;
|
|
for (i = 0; i < single_length; i++) {
|
|
outbuf[0] =
|
|
((line[0] & (1 << 7)) >> 0) |
|
|
((line[0] & (1 << 6)) >> 1) |
|
|
((line[0] & (1 << 5)) >> 2) |
|
|
((line[0] & (1 << 4)) >> 3) |
|
|
((line[single_length] & (1 << 7)) >> 1) |
|
|
((line[single_length] & (1 << 6)) >> 2) |
|
|
((line[single_length] & (1 << 5)) >> 3) |
|
|
((line[single_length] & (1 << 4)) >> 4);
|
|
outbuf[1] =
|
|
((line[0] & (1 << 3)) << 4) |
|
|
((line[0] & (1 << 2)) << 3) |
|
|
((line[0] & (1 << 1)) << 2) |
|
|
((line[0] & (1 << 0)) << 1) |
|
|
((line[single_length] & (1 << 3)) << 3) |
|
|
((line[single_length] & (1 << 2)) << 2) |
|
|
((line[single_length] & (1 << 1)) << 1) |
|
|
((line[single_length] & (1 << 0)) << 0);
|
|
line++;
|
|
outbuf += 2;
|
|
}
|
|
}
|
|
|
|
static void
|
|
canon_pack(unsigned char *line,
|
|
int length,
|
|
unsigned char *comp_buf,
|
|
unsigned char **comp_ptr)
|
|
{
|
|
unsigned char *start; /* Start of compressed data */
|
|
unsigned char repeat; /* Repeating char */
|
|
int count; /* Count of compressed bytes */
|
|
int tcount; /* Temporary count < 128 */
|
|
|
|
/*
|
|
* 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]))
|
|
{
|
|
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];
|
|
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* 'canon_write()' - Send graphics using TIFF packbits compression.
|
|
*/
|
|
|
|
static int
|
|
canon_write(FILE *prn, /* I - Print file or command */
|
|
canon_cap_t caps, /* I - Printer model */
|
|
unsigned char *line, /* I - Output bitmap data */
|
|
int length, /* I - Length of bitmap data */
|
|
int coloridx, /* I - Which color */
|
|
int ydpi, /* I - Vertical resolution */
|
|
int *empty, /* IO- Preceeding empty lines */
|
|
int width, /* I - Printed width */
|
|
int offset, /* I - Offset from left side */
|
|
int dmt)
|
|
{
|
|
unsigned char
|
|
comp_buf[COMPBUFWIDTH], /* Compression buffer */
|
|
in_fold[COMPBUFWIDTH],
|
|
*in_ptr= line,
|
|
*comp_ptr, *comp_data;
|
|
int newlength;
|
|
unsigned char color;
|
|
|
|
/* Don't send blank lines... */
|
|
|
|
if (line[0] == 0 && memcmp(line, line + 1, length - 1) == 0)
|
|
return 0;
|
|
|
|
/* fold lsb/msb pairs if drop modulation is active */
|
|
|
|
if (dmt) {
|
|
if (1) {
|
|
if (caps.features & CANON_CAP_MSB_FIRST)
|
|
canon_fold_msb_lsb(line,length,in_fold);
|
|
else
|
|
canon_fold_lsb_msb(line,length,in_fold);
|
|
in_ptr= in_fold;
|
|
}
|
|
length*= 2;
|
|
offset*= 2;
|
|
}
|
|
|
|
/* pack left border rounded to multiples of 8 dots */
|
|
|
|
comp_data= comp_buf;
|
|
if (offset) {
|
|
int offset2= (offset+4)/8;
|
|
while (offset2>0) {
|
|
unsigned char toffset = offset2 > 128 ? 128 : offset2;
|
|
comp_data[0] = 1 - toffset;
|
|
comp_data[1] = 0;
|
|
comp_data += 2;
|
|
offset2-= toffset;
|
|
}
|
|
}
|
|
|
|
canon_pack(in_ptr, length, comp_data, &comp_ptr);
|
|
newlength= comp_ptr - comp_buf;
|
|
|
|
/* send packed empty lines if any */
|
|
|
|
if (*empty) {
|
|
#ifdef DEBUG
|
|
/* fprintf(stderr,"<%d%c>",*empty,("CMYKcmy"[coloridx])); */
|
|
#endif
|
|
fwrite("\x1b\x28\x65\x02\x00", 5, 1, prn);
|
|
fputc((*empty) >> 8 , prn);
|
|
fputc((*empty) & 255, prn);
|
|
*empty= 0;
|
|
}
|
|
|
|
/* Send a line of raster graphics... */
|
|
|
|
fwrite("\x1b\x28\x41", 3, 1, prn);
|
|
putc((newlength+1) & 255, prn);
|
|
putc((newlength+1) >> 8, prn);
|
|
color= "CMYKcmy"[coloridx];
|
|
if (!color) color= 'K';
|
|
putc(color,prn);
|
|
fwrite(comp_buf, newlength, 1, prn);
|
|
putc('\x0d', prn);
|
|
return 1;
|
|
}
|
|
|
|
|
|
static void
|
|
canon_write_line(FILE *prn, /* I - Print file or command */
|
|
canon_cap_t caps, /* I - Printer model */
|
|
int ydpi, /* I - Vertical resolution */
|
|
unsigned char *k, /* I - Output bitmap data */
|
|
int dk, /* I - */
|
|
unsigned char *c, /* I - Output bitmap data */
|
|
int dc, /* I - */
|
|
unsigned char *m, /* I - Output bitmap data */
|
|
int dm, /* I - */
|
|
unsigned char *y, /* I - Output bitmap data */
|
|
int dy, /* I - */
|
|
unsigned char *lc, /* I - Output bitmap data */
|
|
int dlc, /* I - */
|
|
unsigned char *lm, /* I - Output bitmap data */
|
|
int dlm, /* I - */
|
|
unsigned char *ly, /* I - Output bitmap data */
|
|
int dly, /* I - */
|
|
int l, /* I - Length of bitmap data */
|
|
int width, /* I - Printed width */
|
|
int offset, /* I - horizontal offset */
|
|
int dmt)
|
|
{
|
|
static int empty= 0;
|
|
int written= 0;
|
|
|
|
if (k) written+=
|
|
canon_write(prn, caps, k+ dk*l, l, 3, ydpi, &empty, width, offset, dmt);
|
|
if (y) written+=
|
|
canon_write(prn, caps, y+ dy*l, l, 2, ydpi, &empty, width, offset, dmt);
|
|
if (m) written+=
|
|
canon_write(prn, caps, m+ dm*l, l, 1, ydpi, &empty, width, offset, dmt);
|
|
if (c) written+=
|
|
canon_write(prn, caps, c+ dc*l, l, 0, ydpi, &empty, width, offset, dmt);
|
|
if (ly) written+=
|
|
canon_write(prn, caps, ly+dly*l, l, 6, ydpi, &empty, width, offset, dmt);
|
|
if (lm) written+=
|
|
canon_write(prn, caps, lm+dlm*l, l, 5, ydpi, &empty, width, offset, dmt);
|
|
if (lc) written+=
|
|
canon_write(prn, caps, lc+dlc*l, l, 4, ydpi, &empty, width, offset, dmt);
|
|
|
|
if (written)
|
|
fwrite("\x1b\x28\x65\x02\x00\x00\x01", 7, 1, prn);
|
|
else
|
|
empty++;
|
|
}
|