Skip to content

Instantly share code, notes, and snippets.

@defremov
Last active October 10, 2021 20:10
Show Gist options
  • Save defremov/eda5e00596f2eded8b85 to your computer and use it in GitHub Desktop.
Save defremov/eda5e00596f2eded8b85 to your computer and use it in GitHub Desktop.
Add print quality settings to foo2hbpl1 driver for HBPL1 printers, http://www.dechifro.org/hbpl/
diff --git a/foo2hbpl1.c b/foo2hbpl1.c
index fb4f448..d0ad6cd 100644
--- a/foo2hbpl1.c
+++ b/foo2hbpl1.c
@@ -52,11 +52,38 @@ static char Version[] = "$Id: foo2hbpl1.c,v 1.3 2014/03/30 05:08:32 rick Exp $";
/*
* Command line options
*/
-int MediaCode = 0;
+char *ClutFilePath = NULL;
+int DocType = 0;
+int OutputColor = 0;
+int DraftMode = 0;
+int NumCopies = 1;
+int Trapping = 0;
+int Screen = 0;
+int MediaCode = 1;
char *Username = NULL;
char *Filename = NULL;
int Clip[] = { 8,8,8,8 };
+char *cb_cmyk = "CMYK";
+char *cb_lmh = "LMH";
+char ColorBalance[] =
+/* +--- L = Low
+ |+-- M = Medium
+ ||+- H = High
+ ||| */
+ "333" /* C = Cyan */
+ "333" /* M = Magenta */
+ "333" /* Y = Yellow */
+ "333"; /* K = Black */
+/*
+ 0 = Lighter (-3)
+ 1 = Lighter (-2)
+ 2 = Lighter (-1)
+ * 3 = Normal
+ 4 = Darker (+1)
+ 5 = Darker (+2)
+ 6 = Darker (+3) */
+
void
usage(void)
{
@@ -73,15 +100,73 @@ usage(void)
" | foo2hbpl1 >testpage.zc\n"
"\n"
"Options:\n"
-"-m media Media code to send to printer [1 or 6]\n"
-" 1=plain, 2=bond, 3=lwcard, 4=lwgcard, 5=labels,\n"
-" 6=envelope, 7=recycled, 8=plain2, 9=bond2,\n"
-" 10=lwcard2, 11=lwgcard2, 12=recycled2\n"
+"-a values Color balance adjustment [default: %s]\n"
+" Argument is a string of 12 adjustment values\n"
+" in range of 0..6 each:\n"
+" 0 = Lighter (-3)\n"
+" 1 = Lighter (-2)\n"
+" 2 = Lighter (-1)\n"
+" 3 = Normal\n"
+" 4 = Darker (+1)\n"
+" 5 = Darker (+2)\n"
+" 6 = Darker (+3)\n"
+" in the following order:\n"
+" |C|C|C|M|M|M|Y|Y|Y|K|K|K|\n"
+" |l|m|h|l|m|h|l|m|h|l|m|h|\n"
+" where C=Cyan, M=Magenta, Y=Yellow, K=Black,\n"
+" l=Low, m=Medium, h=High.\n"
+"-c Print ppmraw in color mode.\n"
+" If not set print in black and white.\n"
+" Has no effect if document type (-i option) is 0\n"
+"-i type Document type code for print quality\n"
+" adjustment of ppmraw input [default: %d]\n"
+" 0=No adjustment, 1=Standard, 2=Photos,\n"
+" 3=Presentation, 4=Web Pages, 5=POP, 6=None\n"
+"-l path Pathname of the file containing color\n"
+" look-up tables. Must be specified for\n"
+" document types 1..5 in color mode.\n"
+"-m media Media code to send to printer [default: %d]\n"
+" 1=Plain\n"
+" 2=Plain, side 2\n"
+" 3=Bond\n"
+" 4=Bond, side 2\n"
+" 5=Recycled\n"
+" 6=Recycled, side 2\n"
+" 7=Labels\n"
+" 8=Lightweight Cardstock\n"
+" 9=Lightweight Cardstock, side 2\n"
+" 10=Lightweight Glossy Cardstock\n"
+" 11=Lightweight Glossy Cardstock, side 2\n"
+" 12=Letterhead\n"
+" 13=Letterhead, side 2\n"
+" 14=Pre-Printed\n"
+" 15=Pre-Printed, side 2\n"
+" 16=Hole Punched\n"
+" 17=Hole Punched, side 2\n"
+" 18=Colored\n"
+" 19=Colored, side 2\n"
+" 20=Custom Type\n"
+" 21=Custom Type, side 2\n"
+" 22=Special\n"
+" 23=Special, side 2\n"
+" 24=Envelope\n"
+"-n copies Number of copies, 1..100 [default: %d]\n"
+"-s type Screen type code [default: %d]\n"
+" 0=Auto, 1=Fineness, 2=Standard, 3=Gradation\n"
+"-t Print ppmraw in draft mode.\n"
+" Has no effect if document type (-i option) is 0\n"
"-u left,top,right,bottom\n"
-" Erase margins of specified width [%d,%d,%d,%d]\n"
+" Erase margins of specified width\n"
+" [default: %d,%d,%d,%d]\n"
"-J filename Filename string to send to printer\n"
+"-T Turn trapping on.\n"
"-U username Username string to send to printer\n"
"-V Version %s\n"
+ , ColorBalance
+ , DocType
+ , MediaCode
+ , NumCopies
+ , Screen
, Clip[0], Clip[1], Clip[2], Clip[3]
, Version);
}
@@ -98,6 +183,37 @@ error(int fatal, char *fmt, ...)
if (fatal) exit(fatal);
}
+enum doc_type_id {
+ DOC_NORMAL,
+ DOC_PHOTO,
+ DOC_PRESENTATION,
+ DOC_WEB,
+ DOC_POP,
+ DOC_NONE
+};
+
+struct doc_type_jobattr
+{
+ int color, mono;
+} screen_jobattr_index[] = {
+ {61, 64}, // Fineness
+ {62, 65}, // Standard
+ {63, 66} // Gradation
+ };
+
+static const struct doc_type
+{
+ int clut_id;
+ struct doc_type_jobattr jobattr;
+} doc_type_index[] = {
+ { 0, {11, 33}}, // Normal
+ { 2, {14, 33}}, // Photo
+ { 3, {15, 33}}, // Presentation
+ { 5, {17, 33}}, // Web
+ { 7, {19, 33}}, // POP
+ {18, {31, 33}} // Off
+ };
+
struct stream
{
unsigned char *buf;
@@ -262,20 +378,38 @@ start_doc(int color)
struct tm *tmp;
char datestr[16], timestr[16];
char cname[128] = "My Computer";
+ int i, doc_type_id;
+ static const char *doc_type_jobattr_cprucr[] = {"CPR", "UCR"};
+ static const char *doc_type_jobattr_trcscr[] = {"TRC", "SCR"};
+ static const char *doc_type_jobattr_prefix = "TGI";
+ int doc_type_jobattr = 0;
+ const struct doc_type_jobattr *s_doc_type_jobattr = NULL;
char *mname[] =
- { "",
- "NORMAL",
- "THICK",
- "HIGHQUALITY",
- "COAT2",
- "LABEL",
- "ENVELOPE",
- "RECYCLED",
- "NORMALREV",
- "THICKSIDE2",
- "HIGHQUALITYREV",
- "COATEDPAPER2REV",
- "RECYCLEREV",
+ {
+ "NORMAL",
+ "NORMALREV",
+ "HIGHQUALITY",
+ "HIGHQUALITYREV",
+ "RECYCLE",
+ "RECYCLEREV",
+ "LABEL",
+ "THICK",
+ "THICKSIDE2",
+ "COATEDPAPER2",
+ "COATEDPAPER2REV",
+ "LETTERHEAD",
+ "LETTERHEADREV",
+ "PREPRINTED",
+ "PREPRINTEDREV",
+ "PREPUNCHED",
+ "PREPUNCHEDREV",
+ "COLOR",
+ "COLORREV",
+ "USER1",
+ "USER1REV",
+ "SPECIAL",
+ "SPECIALREV",
+ "ENVELOPE"
};
t = time(NULL);
@@ -296,54 +430,98 @@ start_doc(int color)
/* Lines end with \n, not \r\n */
printf(
- "\033%%-12345X@PJL SET STRINGCODESET=UTF8\n"
- "@PJL COMMENT DATE=%s\n"
- "@PJL COMMENT TIME=%s\n"
- "@PJL COMMENT DNAME=%s\n"
- "@PJL JOB MODE=PRINTER\n"
- "@PJL SET JOBATTR=\"@LUNA=%s\"\n"
- "@PJL SET JOBATTR=\"@TRCH=OFF\"\n"
- "@PJL SET DUPLEX=OFF\n"
- "@PJL SET BINDING=LONGEDGE\n"
- "@PJL SET IWAMANUALDUP=OFF\n"
- "@PJL SET JOBATTR=\"@MSIP=%s\"\n"
- "@PJL SET RENDERMODE=%s\n"
- "@PJL SET ECONOMODE=OFF\n"
- "@PJL SET RET=ON\n"
- "@PJL SET JOBATTR=\"@IREC=OFF\"\n"
- "@PJL SET JOBATTR=\"@TRAP=ON\"\n"
- "@PJL SET JOBATTR=\"@JOAU=%s\"\n"
- "@PJL SET JOBATTR=\"@CNAM=%s\"\n"
- "@PJL SET COPIES=1\n"
- "@PJL SET QTY=1\n"
- "@PJL SET PAPERDIRECTION=SEF\n"
- "@PJL SET RESOLUTION=600\n"
- "@PJL SET BITSPERPIXEL=8\n"
- "@PJL SET JOBATTR=\"@DRDM=XRC\"\n"
- "@PJL SET JOBATTR=\"@TSCR=11\"\n"
- "@PJL SET JOBATTR=\"@GSCR=11\"\n"
- "@PJL SET JOBATTR=\"@ISCR=12\"\n"
- "@PJL SET JOBATTR=\"@TTRC=11\"\n"
- "@PJL SET JOBATTR=\"@GTRC=11\"\n"
- "@PJL SET JOBATTR=\"@ITRC=12\"\n"
- "@PJL SET JOBATTR=\"@TCPR=11\"\n"
- "@PJL SET JOBATTR=\"@GCPR=11\"\n"
- "@PJL SET JOBATTR=\"@ICPR=12\"\n"
- "@PJL SET JOBATTR=\"@TUCR=11\"\n"
- "@PJL SET JOBATTR=\"@GUCR=11\"\n"
- "@PJL SET JOBATTR=\"@IUCR=12\"\n"
- "@PJL SET JOBATTR=\"@BSPM=OFF\"\n"
- "@PJL SET JOBATTR=\"@TDFT=0\"\n"
- "@PJL SET JOBATTR=\"@GDFT=0\"\n"
- "@PJL SET JOBATTR=\"@IDFT=0\"\n"
- "@PJL ENTER LANGUAGE=HBPL\n"
- , datestr, timestr
- , Filename ? Filename : ""
- , Username ? Username : ""
- , mname[MediaCode]
- , color ? "COLOR" : "GRAYSCALE"
- , Username ? Username : ""
- , cname);
+ "\033%%-12345X@PJL JOB MODE=PRINTER\n"
+ "@PJL SET STRINGCODESET=UTF8\n"
+ );
+
+ printf("@PJL COMMENT DATE=%s\n", datestr);
+ printf("@PJL COMMENT TIME=%s\n", timestr);
+ printf("@PJL COMMENT DNAME=%s\n", Filename ? Filename : "");
+ printf("@PJL SET JOBATTR=\"@LUNA=%s\"\n", Username ? Username : "");
+ printf("@PJL SET COPIES=%d\n", NumCopies);
+
+ printf(
+ "@PJL SET JOBATTR=\"@TRCH=OFF\"\n"
+ "@PJL SET DUPLEX=OFF\n"
+ );
+
+ for (i = 0; i < 12; i++) {
+ printf("@PJL SET JOBATTR=\"@AJ%c%c=%c\"\n",
+ cb_cmyk[i / 3], cb_lmh[i % 3], ColorBalance[i]);
+ }
+
+ printf("@PJL SET JOBATTR=\"@APSP=OFF\"\n");
+
+ printf("@PJL SET JOBATTR=\"@MSIP=%s\"\n", mname[MediaCode - 1]);
+ printf("@PJL SET RENDERMODE=%s\n", color ? "COLOR" : "GRAYSCALE");
+ printf("@PJL SET ECONOMODE=%s\n", DraftMode ? "ON" : "OFF");
+
+ printf("@PJL SET JOBATTR=\"@IREC=OFF\"\n");
+
+ printf("@PJL SET JOBATTR=\"@TRAP=%s\"\n",
+ color && Trapping ? "ON" : "OFF");
+
+ // "ON" only if 'Image Enhancement' option is enabled in original Xerox's driver.
+ printf("@PJL SET RET=%s\n", "OFF");
+
+ printf(
+ "@PJL SET JOBATTR=\"@TDFT=0\"\n"
+ "@PJL SET JOBATTR=\"@GDFT=0\"\n"
+ "@PJL SET JOBATTR=\"@IDFT=0\"\n"
+ "@PJL SET JOBATTR=\"@NLPP=1\"\n"
+ "@PJL SET JOBATTR=\"@HOAD=IC0A809\"\n"
+ );
+
+ printf("@PJL SET JOBATTR=\"@JOAU=%s\"\n", Username ? Username : "");
+ printf("@PJL SET JOBATTR=\"@CNAM=%s\"\n", cname);
+
+ printf(
+ "@PJL SET OUTBIN=FACEDOWN\n"
+ "@PJL SET JOBATTR=\"@PODR=NORMAL\"\n"
+ "@PJL SET SLIPSHEET=OFF\n"
+ "@PJL SET PAPERDIRECTION=SEF\n"
+ "@PJL SET RESOLUTION=600\n"
+ "@PJL SET BITSPERPIXEL=8\n"
+ "@PJL SET JOBATTR=\"@DRDM=RASTER\"\n"
+ );
+
+ doc_type_id = DocType == 0 ? 0 : DocType - 1;
+
+ if (color) {
+ for (i = 0; i < 6; i++) {
+ printf("@PJL SET JOBATTR=\"@%c%s=%d\"\n",
+ doc_type_jobattr_prefix[i % 3],
+ doc_type_jobattr_cprucr[i / 3],
+ doc_type_index[doc_type_id].jobattr.color);
+ }
+ }
+
+ if (Screen == 0) {
+ s_doc_type_jobattr = &doc_type_index[doc_type_id].jobattr;
+ } else {
+ s_doc_type_jobattr = &screen_jobattr_index[Screen - 1];
+ }
+ doc_type_jobattr = color ?
+ s_doc_type_jobattr->color : s_doc_type_jobattr->mono;
+ for (i = 0; i < 6; i++) {
+ printf("@PJL SET JOBATTR=\"@%c%s=%d\"\n",
+ doc_type_jobattr_prefix[i % 3],
+ doc_type_jobattr_trcscr[i / 3],
+ doc_type_jobattr);
+ }
+
+ if (!color) {
+ printf("@PJL SET JOBATTR=\"@PBLK=OFF\"\n");
+ }
+
+ printf("@PJL SET JOBATTR=\"@BANR=DEVICE\"\n");
+
+ if (doc_type_id == DOC_NONE) {
+ printf("@PJL SET JOBATTR=\"@FCMS=ON\"\n");
+ }
+
+ printf("@PJL ENTER LANGUAGE=HBPL\n");
+
fwrite (reca, 1, sizeof reca, stdout);
}
@@ -401,11 +579,14 @@ encode_page(int color, int width, int height, char *image)
int paper = 510, hsel = 0, off = 0, bit = 0, stat = 0;
int margin = width-96;
- for (i = 0; i < sizeof papers / sizeof *papers; i++)
- if (abs(width-papers[i+1]) < 36 && abs(height-papers[i+2]) < 36)
+ for (i = 0; i < sizeof papers / sizeof *papers; i+=3) {
+ if (abs(width-papers[i+1]) < 36 && abs(height-papers[i+2]) < 36) {
paper = papers[i];
+ break;
+ }
+ }
if (!MediaCode)
- MediaCode = paper & 1 ? 6 : 1;
+ MediaCode = paper & 1 ? 24 : 1;
if (!pagenum)
start_doc(color);
head[12] = paper >> 1;
@@ -532,6 +713,421 @@ encode_page(int color, int width, int height, char *image)
#undef BP
#undef put_token
+#define CLUT_BLK0_OFFSET 0x374
+#define CLUT_OFFSET 0x308
+#define CLUT_SIZE (17 * 17 * 17 * 4)
+#define CLUT_BLK_SIZE ((CLUT_OFFSET) + (CLUT_SIZE))
+#define FILE_CLUT_OFFSET(i) ((CLUT_BLK0_OFFSET) + (CLUT_BLK_SIZE) * (i) + (CLUT_OFFSET))
+
+#define CLUT_X_FACT (1 * 4)
+#define CLUT_Y_FACT (17 * 4)
+#define CLUT_Z_FACT (17 * 17 * 4)
+
+#define RGB_TO_GRAY(r, g, b) ((1229 * (r) + 2417 * (g) + 451 * (b)) >> 12)
+
+unsigned char*
+load_clut(const int clut_id, const char *clut_fname)
+{
+ unsigned char *clut;
+ FILE *clut_fp;
+
+ if ((clut = malloc(CLUT_SIZE * sizeof(char))) == NULL) {
+ error(1, "Can't allocate memory for CLUT\n");
+ }
+
+ if (!(clut_fp = fopen(clut_fname, "r"))) {
+ error(1, "Can't open '%s' for reading\n", clut_fname);
+ }
+
+ if (fseek(clut_fp, FILE_CLUT_OFFSET(clut_id), SEEK_SET) != 0
+ || fread(clut, sizeof(char), CLUT_SIZE, clut_fp) < CLUT_SIZE) {
+ fclose(clut_fp);
+ error(1, "Can't read CLUT #%d from '%s'\n", clut_id, clut_fname);
+ }
+
+ fclose(clut_fp);
+
+ return clut;
+}
+
+// Borrowed from Little Color Management System, http://www.littlecms.com
+// Copyright (c) 1998-2012 Marti Maria Saguer
+// Licensed under the MIT license
+// http://opensource.org/licenses/mit-license.php
+
+// Tetrahedral interpolation, using Sakamoto algorithm.
+void
+rgb_to_kcmy(const unsigned char clut[], unsigned char kcmy[], const unsigned char rgb[])
+{
+ int i;
+ int rx, ry, rz;
+ int x0, y0, z0;
+ int x1, y1, z1;
+ const unsigned char *plane;
+ int c0, c1, c2, c3;
+
+ rx = rgb[0] & 0xf; ry = rgb[1] & 0xf; rz = rgb[2] & 0xf;
+
+ if (rgb[0] == 255) {
+ x0 = CLUT_X_FACT << 4; x1 = 0;
+ } else {
+ x0 = (rgb[0] >> 4) * (x1 = CLUT_X_FACT);
+ }
+
+ if (rgb[1] == 255) {
+ y0 = CLUT_Y_FACT << 4; y1 = 0;
+ } else {
+ y0 = (rgb[1] >> 4) * (y1 = CLUT_Y_FACT);
+ }
+
+ if (rgb[2] == 255) {
+ z0 = CLUT_Z_FACT << 4; z1 = 0;
+ } else {
+ z0 = (rgb[2] >> 4) * (z1 = CLUT_Z_FACT);
+ }
+
+ clut = &clut[x0 + y0 + z0];
+
+ if (rx >= ry) {
+ if (ry >= rz) {
+ y1 += x1;
+ z1 += y1;
+ for (i = 0; i < 4; i++) {
+ plane = &clut[(i - 1) & 3]; // in KCMY order
+ c1 = plane[x1];
+ c2 = plane[y1];
+ c3 = plane[z1];
+ c0 = plane[0];
+ c3 -= c2;
+ c2 -= c1;
+ c1 -= c0;
+ kcmy[i] = c0 + ((c1 * rx + c2 * ry + c3 * rz) >> 4);
+ }
+ } else if (rz >= rx) {
+ x1 += z1;
+ y1 += x1;
+ for (i = 0; i < 4; i++) {
+ plane = &clut[(i - 1) & 3];
+ c1 = plane[x1];
+ c2 = plane[y1];
+ c3 = plane[z1];
+ c0 = plane[0];
+ c2 -= c1;
+ c1 -= c3;
+ c3 -= c0;
+ kcmy[i] = c0 + ((c1 * rx + c2 * ry + c3 * rz) >> 4);
+ }
+ } else {
+ z1 += x1;
+ y1 += z1;
+ for (i = 0; i < 4; i++) {
+ plane = &clut[(i - 1) & 3];
+ c1 = plane[x1];
+ c2 = plane[y1];
+ c3 = plane[z1];
+ c0 = plane[0];
+ c2 -= c3;
+ c3 -= c1;
+ c1 -= c0;
+ kcmy[i] = c0 + ((c1 * rx + c2 * ry + c3 * rz) >> 4);
+ }
+ }
+ } else {
+ if (rx >= rz) {
+ x1 += y1;
+ z1 += x1;
+ for (i = 0; i < 4; i++) {
+ plane = &clut[(i - 1) & 3];
+ c1 = plane[x1];
+ c2 = plane[y1];
+ c3 = plane[z1];
+ c0 = plane[0];
+ c3 -= c1;
+ c1 -= c2;
+ c2 -= c0;
+ kcmy[i] = c0 + ((c1 * rx + c2 * ry + c3 * rz) >> 4);
+ }
+ } else if (ry >= rz) {
+ z1 += y1;
+ x1 += z1;
+ for (i = 0; i < 4; i++) {
+ plane = &clut[(i - 1) & 3];
+ c1 = plane[x1];
+ c2 = plane[y1];
+ c3 = plane[z1];
+ c0 = plane[0];
+ c1 -= c3;
+ c3 -= c2;
+ c2 -= c0;
+ kcmy[i] = c0 + ((c1 * rx + c2 * ry + c3 * rz) >> 4);
+ }
+ } else {
+ y1 += z1;
+ x1 += y1;
+ for (i = 0; i < 4; i++) {
+ plane = &clut[(i - 1) & 3];
+ c1 = plane[x1];
+ c2 = plane[y1];
+ c3 = plane[z1];
+ c0 = plane[0];
+ c1 -= c2;
+ c2 -= c3;
+ c3 -= c0;
+ kcmy[i] = c0 + ((c1 * rx + c2 * ry + c3 * rz) >> 4);
+ }
+ }
+ }
+
+ return;
+}
+
+enum proc_mode {
+ PROC_BITMAP,
+ PROC_GRAY,
+ PROC_RGB_NOADJ,
+ PROC_RGB_ADJ_COLOR,
+ PROC_RGB_ADJ_COLOR_NONE,
+ PROC_RGB_ADJ_COLOR_DRAFT,
+ PROC_RGB_ADJ_COLOR_NONE_DRAFT,
+ PROC_RGB_ADJ_MONO,
+ PROC_RGB_ADJ_MONO_DRAFT,
+ PROC_CMYK
+};
+
+enum margin_pos {
+ LEFT,
+ TOP,
+ RIGHT,
+ BOTTOM,
+};
+
+static unsigned char trc_rgb_color_std[] = {
+ 0, 0, 0, 0, 0, 0, 1, 1, 2, 2, 2, 3, 3, 4, 5, 6, 7, 8, 9, 10, 12, 13, 14,
+ 15, 16, 18, 19, 20, 21, 22, 23, 25, 26, 27, 28, 29, 31, 32, 33, 34, 35,
+ 36, 37, 38, 40, 41, 42, 43, 44, 45, 46, 47, 48, 50, 51, 52, 53, 54, 55,
+ 56, 57, 58, 59, 60, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 74, 75,
+ 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 90, 91, 92, 93, 94,
+ 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109,
+ 110, 111, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124,
+ 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138,
+ 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152,
+ 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166,
+ 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180,
+ 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194,
+ 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208,
+ 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222,
+ 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236,
+ 237, 238, 239, 240, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249,
+ 250, 251, 252, 253, 254, 255
+};
+
+// Identity transformation
+static unsigned char trc_rgb_color_none[] = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
+ 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37,
+ 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55,
+ 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73,
+ 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91,
+ 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107,
+ 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121,
+ 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135,
+ 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149,
+ 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163,
+ 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177,
+ 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191,
+ 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205,
+ 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219,
+ 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233,
+ 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247,
+ 248, 249, 250, 251, 252, 253, 254, 255
+};
+
+static unsigned char trc_rgb_gray_std[] = {
+ 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 2, 3, 4, 6, 7, 10, 12, 13, 15, 16, 19, 20,
+ 23, 23, 26, 27, 28, 31, 32, 34, 35, 36, 38, 40, 41, 43, 44, 45, 46, 48,
+ 50, 51, 52, 54, 55, 56, 57, 59, 61, 62, 63, 64, 66, 67, 68, 69, 70, 71,
+ 74, 75, 76, 77, 78, 79, 80, 81, 83, 84, 85, 86, 87, 88, 90, 91, 92, 93,
+ 94, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109,
+ 110, 111, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124,
+ 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138,
+ 139, 140, 141, 142, 143, 144, 145, 145, 146, 147, 148, 149, 150, 151,
+ 152, 153, 154, 155, 156, 157, 158, 159, 159, 160, 161, 162, 163, 164,
+ 165, 166, 167, 168, 169, 169, 170, 171, 172, 173, 174, 175, 176, 177,
+ 178, 178, 179, 180, 181, 182, 183, 184, 185, 185, 186, 187, 188, 189,
+ 190, 191, 192, 192, 193, 194, 195, 196, 197, 198, 198, 199, 200, 201,
+ 202, 203, 204, 204, 205, 206, 207, 208, 209, 209, 210, 211, 212, 213,
+ 214, 215, 215, 216, 217, 218, 219, 220, 220, 221, 222, 223, 224, 225,
+ 225, 226, 227, 228, 229, 229, 230, 231, 232, 233, 234, 234, 235, 236,
+ 237, 238, 238, 239, 240, 240, 241, 241, 242, 243, 244, 245, 245, 246,
+ 247, 248, 249, 249, 250, 251, 252, 253, 253, 254, 255
+};
+
+static unsigned char trc_rgb_gray_none[] = {
+ 0, 1, 1, 2, 2, 3, 4, 6, 7, 8, 10, 11, 13, 15, 16, 18, 20, 21, 23, 24,
+ 26, 27, 29, 30, 32, 33, 34, 36, 37, 39, 40, 41, 43, 44, 45, 47, 48, 49,
+ 50, 52, 53, 54, 55, 57, 58, 59, 60, 62, 63, 64, 65, 66, 68, 69, 70, 71,
+ 72, 73, 75, 76, 77, 78, 79, 80, 81, 82, 84, 85, 86, 87, 88, 89, 90, 91,
+ 92, 93, 94, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108,
+ 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122,
+ 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136,
+ 137, 138, 139, 140, 141, 142, 143, 144, 144, 145, 146, 147, 148, 149,
+ 150, 151, 152, 153, 154, 155, 156, 157, 158, 158, 159, 160, 161, 162,
+ 163, 164, 165, 166, 167, 168, 168, 169, 170, 171, 172, 173, 174, 175,
+ 176, 177, 177, 178, 179, 180, 181, 182, 183, 184, 184, 185, 186, 187,
+ 188, 189, 190, 191, 191, 192, 193, 194, 195, 196, 197, 197, 198, 199,
+ 200, 201, 202, 203, 203, 204, 205, 206, 207, 208, 208, 209, 210, 211,
+ 212, 213, 214, 214, 215, 216, 217, 218, 219, 219, 220, 221, 222, 223,
+ 224, 224, 225, 226, 227, 228, 228, 229, 230, 231, 232, 233, 233, 234,
+ 235, 236, 237, 237, 238, 239, 240, 241, 241, 242, 243, 244, 245, 245,
+ 246, 247, 248, 249, 249, 250, 251, 252, 253, 253, 254, 255
+};
+
+static unsigned char trc_draft[] = {
+ 0, 0, 1, 2, 2, 3, 4, 4, 5, 6, 7, 7, 8, 9, 9, 10, 11, 11, 12, 13, 14, 14,
+ 15, 16, 16, 17, 18, 18, 19, 20, 21, 21, 22, 23, 23, 24, 25, 25, 26, 27,
+ 28, 28, 29, 30, 30, 31, 32, 32, 33, 34, 35, 35, 36, 37, 37, 38, 39, 39,
+ 40, 41, 42, 42, 43, 44, 44, 45, 46, 46, 47, 48, 49, 49, 50, 51, 51, 52,
+ 53, 53, 54, 55, 56, 56, 57, 58, 58, 59, 60, 60, 61, 62, 62, 63, 64, 65,
+ 65, 66, 67, 67, 68, 69, 70, 70, 71, 72, 72, 73, 74, 74, 75, 76, 77, 77,
+ 78, 79, 79, 80, 81, 81, 82, 83, 84, 84, 85, 86, 86, 87, 88, 88, 89, 90,
+ 91, 91, 92, 93, 93, 94, 95, 95, 96, 97, 98, 98, 99, 100, 100, 101, 102,
+ 102, 103, 104, 105, 105, 106, 107, 107, 108, 109, 109, 110, 111, 112,
+ 112, 113, 114, 114, 115, 116, 116, 117, 118, 118, 119, 120, 121, 121,
+ 122, 123, 123, 124, 125, 125, 126, 127, 128, 128, 129, 130, 130, 131,
+ 132, 133, 133, 134, 135, 135, 136, 137, 137, 138, 139, 140, 140, 141,
+ 142, 142, 143, 144, 144, 145, 146, 147, 147, 148, 149, 149, 150, 151,
+ 151, 152, 153, 154, 154, 155, 156, 156, 157, 158, 158, 159, 160, 161,
+ 161, 162, 163, 163, 164, 165, 165, 166, 167, 168, 168, 169, 170, 170,
+ 171, 172, 172, 173, 174, 175, 175, 176, 177, 177, 178
+};
+
+void
+detect_rgb_content(unsigned char *const image,
+ const int wide, const int high, const int margins[4],
+ int *is_color, int *is_blank)
+{
+ const int deep = 3;
+ const int byte = wide * deep;
+ int i, m[4];
+ int start_row, end_row;
+ int start_col, end_col;
+ int start_col_off, end_col_off;
+ unsigned char *rowp, *end_rowp, *startp, *endp, *p;
+ int color_detected = 0;
+ int gray_detected = 0;
+
+ for (i = 0; i < 4; i++) {
+ m[i] = margins[i] < 0 ? 0 : margins[i];
+ }
+
+ start_row = m[TOP];
+ end_row = high - m[BOTTOM];
+ start_col = m[LEFT];
+ end_col = wide - m[RIGHT];
+
+ if (start_row < end_row && start_col < end_col) {
+ end_rowp = image + (end_row - 1) * byte;
+ start_col_off = start_col * deep;
+ end_col_off = (end_col - 1) * deep;
+
+ for (rowp = image + start_row * byte;; rowp += byte) {
+ startp = rowp + start_col_off;
+ endp = rowp + end_col_off;
+
+ for (p = startp;; p += deep) {
+ if (p[0] != p[1] || p[1] != p[2]) {
+ color_detected = 1;
+ goto end_search;
+ } else if (p[0] != 255) {
+ gray_detected = 1;
+ }
+ if (p == endp) {
+ break;
+ }
+ }
+ if (rowp == end_rowp) {
+ break;
+ }
+ }
+ }
+
+end_search: *is_color = color_detected;
+ *is_blank = !(color_detected || gray_detected);
+
+ return;
+}
+
+void
+apply_trapping(unsigned char *image, int wide, int high, const int margins[4])
+{
+ int byte;
+ int i, j, k, m[4], n[24];
+ int skip_mlr, eff_byte;
+ unsigned char *p, *row_endp, *img_endp, *np;
+
+ for (i = 0; i < 4; i++) {
+ m[i] = margins[i] > 1 ? margins[i] : 2;
+ }
+
+ if (m[TOP] < high - m[BOTTOM] && m[LEFT] < wide - m[RIGHT]) {
+
+ byte = wide * 4;
+
+ // Array `n` contains relative offsets
+ // of the neighbor pixels in a 5x5 window.
+ //
+ // +----+----+----+----+----+
+ // | 0 | 1 | 2 | 3 | 4 |
+ // +----+----+----+----+----+
+ // | 5 | 6 | 7 | 8 | 9 |
+ // +----+----+---------+----+
+ // | 10 | 11 | p | 12 | 13 |
+ // +----+----+---------+----+
+ // | 14 | 15 | 16 | 17 | 18 |
+ // +----+----+----+----+----+
+ // | 19 | 20 | 21 | 22 | 23 |
+ // +----+----+----+----+----+
+
+ for (k = 0, i = -2; i < 3; i++) {
+ for (j = -2; j < 3; j++) {
+ if (i || j) {
+ n[k++] = byte * i + 4 * j;
+ }
+ }
+ }
+
+ p = image + m[TOP] * byte + m[LEFT] * 4;
+ img_endp = image + (high - m[BOTTOM]) * byte - m[RIGHT] * 4;
+ skip_mlr = (m[LEFT] + m[RIGHT]) * 4;
+ eff_byte = byte - skip_mlr;
+ row_endp = p + eff_byte;
+
+ for (; p != img_endp; p += 4) {
+ if (p == row_endp) {
+ p += skip_mlr;
+ row_endp = p + eff_byte;
+ }
+
+ if (p[0] < 204) {
+ continue;
+ }
+
+ for (i = 0; i < 24; i++) {
+ np = p + n[i];
+ if (np[0] < 204) {
+ for (j = 1; j < 4; j++) {
+ if (p[j] < np[j]) {
+ p[j] = np[j];
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return;
+}
+
int
getint(FILE *fp)
{
@@ -557,6 +1153,15 @@ do_file(FILE *fp)
int wide, deep, byte, row, col, i, k;
char tupl[128], line[128];
unsigned char *image, *sp, *dp;
+ int buf_size, ibuf_size;
+ unsigned char *sstart, *dstart;
+ int doc_type_id = 0;
+ const struct doc_type *s_doc_type;
+ unsigned char *clut = NULL;
+ enum proc_mode proc_mode;
+ unsigned char *trc = trc_rgb_color_none;
+ int is_color = 0;
+ int is_blank = 0;
while ((type = fgetc(fp)) != EOF)
{
@@ -566,12 +1171,37 @@ do_file(FILE *fp)
{
case '4':
deep = 1 + (ideep = 0);
+ proc_mode = PROC_BITMAP;
goto six;
case '5':
deep = ideep = 1;
+ proc_mode = PROC_GRAY;
goto six;
case '6':
- deep = 1 + (ideep = 3);
+ if (DocType != 0) {
+ doc_type_id = DocType - 1;
+ if (OutputColor) {
+ deep = 1 + (ideep = 3);
+ if (doc_type_id == DOC_NONE) {
+ proc_mode = DraftMode ?
+ PROC_RGB_ADJ_COLOR_NONE_DRAFT : PROC_RGB_ADJ_COLOR_NONE;
+ } else {
+ if (!ClutFilePath) {
+ error(1, "CLUT file path (option -l) is not set.\n");
+ }
+ proc_mode = DraftMode ?
+ PROC_RGB_ADJ_COLOR_DRAFT : PROC_RGB_ADJ_COLOR;
+ }
+ } else {
+ ideep = 3;
+ deep = 1;
+ proc_mode = DraftMode ?
+ PROC_RGB_ADJ_MONO_DRAFT : PROC_RGB_ADJ_MONO;
+ }
+ } else {
+ deep = 1 + (ideep = 3);
+ proc_mode = PROC_RGB_NOADJ;
+ }
six: iwide = getint(fp);
ihigh = getint(fp);
imax = type == '4' ? 255 : getint(fp);
@@ -592,6 +1222,7 @@ six: iwide = getint(fp);
strcpy (tupl, line + 9);
} while (strcmp(line, "ENDHDR\n"));
if (ideep != 4 || strcmp(tupl, "CMYK\n")) goto fail;
+ proc_mode = PROC_CMYK;
break;
default:
goto fail;
@@ -603,37 +1234,118 @@ six: iwide = getint(fp);
else
ibyte = wide >> 3;
byte = wide * deep;
- image = calloc (ihigh+2, byte);
+
+ buf_size = (ibyte > byte ? ibyte : byte) * ihigh + byte * 2;
+
+ if ((image = malloc(buf_size)) == NULL) {
+ error(1, "Can't allocate memory for page buffer\n");
+ }
+
+ dstart = image + byte;
+ ibuf_size = ibyte * ihigh;
+ sstart = image + (buf_size - ibuf_size);
+
+ if (fread (sstart, ibuf_size, 1, fp) != 1) {
+ error(1, "Error reading image data\n");
+ }
+
+ if (ideep == 3 && DocType != 0) {
+ detect_rgb_content(sstart, iwide, ihigh, Clip,
+ &is_color, &is_blank);
+
+ if (doc_type_id == DOC_NONE) {
+ trc = is_color ? trc_rgb_color_none : trc_rgb_gray_none;
+ } else {
+ s_doc_type = &doc_type_index[doc_type_id];
+ clut = load_clut(s_doc_type->clut_id, ClutFilePath);
+ trc = is_color ? trc_rgb_color_std : trc_rgb_gray_std;
+ }
+ }
+
for (row = 1; row <= ihigh; row++)
{
- i = fread (image, ibyte, 1, fp);
- sp = image;
- dp = image + row*byte;
+ sp = sstart;
+ dp = dstart;
for (col = 0; col < iwide; col++)
{
dp += deep;
- switch (ideep)
+ switch (proc_mode)
{
- case 0:
- *dp = ((image[col >> 3] >> (~col & 7)) & 1) * 255;
+ case PROC_BITMAP:
+ *dp = ((sp[col >> 3] >> (~col & 7)) & 1) * 255;
break;
- case 1:
+ case PROC_GRAY:
*dp = ~*sp;
break;
- case 3:
+ case PROC_RGB_NOADJ:
for (k = sp[2], i = 0; i < 2; i++)
if (k < sp[i]) k = sp[i];
*dp = ~k;
for (i = 0; i < 3; i++)
dp[i+1] = k ? (k - sp[i]) * 255 / k : 255;
break;
- case 4:
+ case PROC_RGB_ADJ_COLOR:
+ for (i = 0; i < 3; i++) {
+ sp[i] = trc[sp[i]];
+ }
+ rgb_to_kcmy(clut, dp, sp);
+ break;
+ case PROC_RGB_ADJ_COLOR_NONE:
+ for (i = 0; i < 3; i++) {
+ sp[i] = trc[sp[i]];
+ }
+ for (k = sp[2], i = 0; i < 2; i++)
+ if (k < sp[i]) k = sp[i];
+ *dp = ~k;
+ for (i = 0; i < 3; i++)
+ dp[i+1] = k - sp[i];
+ break;
+ case PROC_RGB_ADJ_COLOR_DRAFT:
+ for (i = 0; i < 3; i++) {
+ sp[i] = trc[sp[i]];
+ }
+ rgb_to_kcmy(clut, dp, sp);
+ for (i = 0; i < 4; i++) {
+ dp[i] = trc_draft[dp[i]];
+ }
+ break;
+ case PROC_RGB_ADJ_COLOR_NONE_DRAFT:
+ for (i = 0; i < 3; i++) {
+ sp[i] = trc[sp[i]];
+ }
+ for (k = sp[2], i = 0; i < 2; i++)
+ if (k < sp[i]) k = sp[i];
+ *dp = ~k;
+ for (i = 0; i < 3; i++)
+ dp[i+1] = k - sp[i];
+ for (i = 0; i < 4; i++) {
+ dp[i] = trc_draft[dp[i]];
+ }
+ break;
+ case PROC_RGB_ADJ_MONO:
+ for (i = 0; i < 3; i++) {
+ sp[i] = trc[sp[i]];
+ }
+ *dp = ~RGB_TO_GRAY(sp[0], sp[1], sp[2]);
+ break;
+ case PROC_RGB_ADJ_MONO_DRAFT:
+ for (i = 0; i < 3; i++) {
+ sp[i] = trc[sp[i]];
+ }
+ *dp = ~RGB_TO_GRAY(sp[0], sp[1], sp[2]);
+ for (i = 0; i < 4; i++) {
+ dp[i] = trc_draft[dp[i]];
+ }
+ break;
+ case PROC_CMYK:
for (i=0; i < 4; i++)
dp[i] = sp[((i-1) & 3)];
break;
}
sp += ideep;
}
+ sstart += ibyte;
+ dstart += byte;
for (i = 0; i < deep*Clip[0]; i++)
image[row*byte + deep+i] = 0;
for (i = deep*(iwide-Clip[2]); i < byte; i++)
@@ -641,8 +1353,14 @@ six: iwide = getint(fp);
}
memset(image+deep, 0, byte*(Clip[1]+1));
memset(image+deep + byte*(ihigh-Clip[3]+1), 0, byte*Clip[3]);
+ if (deep == 4 && Trapping) {
+ apply_trapping(image + byte + deep, iwide, ihigh, Clip);
+ }
encode_page(deep > 1, iwide, ihigh, (char *) image);
free(image);
+ if (ideep == 3 && DocType != 0 && doc_type_id != DOC_NONE) {
+ free(clut);
+ }
}
return;
fail:
@@ -654,15 +1372,61 @@ main(int argc, char *argv[])
{
int c, i;
- while ( (c = getopt(argc, argv, "m:u:J:U:V")) != EOF)
+ while ( (c = getopt(argc, argv, "a:ci:l:m:s:tu:J:TU:V")) != EOF)
switch (c)
{
- case 'm': MediaCode = atoi(optarg); break;
+ case 'a':
+ for (i = 0; i < 12 && optarg[i]; i++) {
+ if (optarg[i] >= '0' && optarg[i] <= '6') {
+ ColorBalance[i] = optarg[i];
+ } else {
+ error(1, "Color balance values must be in range 0..6\n");
+ }
+ }
+ break;
+ case 'c':
+ OutputColor = 1;
+ break;
+ case 'i':
+ if (sscanf(optarg, "%d", &DocType) != 1
+ || DocType < 0 || DocType > 6
+ ) {
+ error(1, "Document type code must be in range 1..6.\n");
+ }
+ break;
+ case 'l': if (optarg[0]) ClutFilePath = optarg; break;
+ case 'm':
+ if (sscanf(optarg, "%d", &MediaCode) != 1
+ || MediaCode < 1 || MediaCode > 24
+ ) {
+ error(1, "Media code must be in range 1..24.\n");
+ }
+ break;
+ case 'n':
+ if (sscanf(optarg, "%d", &NumCopies) != 1
+ || NumCopies < 1 || NumCopies > 24
+ ) {
+ error(1, "Number of copies must be in range 1..100.\n");
+ }
+ break;
+ case 's':
+ if (sscanf(optarg, "%d", &Screen) != 1
+ || Screen < 0 || Screen > 3
+ ) {
+ error(1, "Screen type code must be in range 0..3.\n");
+ }
+ break;
+ case 't':
+ DraftMode = 1;
+ break;
case 'u': if (sscanf(optarg, "%d,%d,%d,%d",
Clip, Clip+1, Clip+2, Clip+3) != 4)
error(1, "Must specify four clipping margins!\n");
break;
case 'J': if (optarg[0]) Filename = optarg; break;
+ case 'T':
+ Trapping = 1;
+ break;
case 'U': if (optarg[0]) Username = optarg; break;
case 'V': printf("%s\n", Version); return 0;
default: usage(); return 1;
@defremov
Copy link
Author

I tried this patch with Ubuntu 19.10 Eoan (beta). But I can't see the new settings. Does it work with cups 2.2.11?

It doesn't as CUPS has no means to discover that those new settings are available. They must first be described to CUPS in a certain way, which no one, as far as I know, has bothered to do yet. Still, you can print with this driver from the command line using lp and ghostscript. Or even better, install the original one from Xerox.

@Norbert01
Copy link

Unfortunately the xerox driver are only 32-bit which the new Ubuntu version doesen't support.

@defremov
Copy link
Author

Unfortunately the xerox driver are only 32-bit which the new Ubuntu version doesen't support.

I have googled up a bit the situation with Ubuntu, they seem to promise that they will support 32-bit printer drivers.

@Norbert01
Copy link

yeah, got the xerox driver working.

In the xerox ppd are some good examples how modify the ppd.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment