DNP: Continuous & Discrete Panorama Processing

* Image must be submitted as a single, full-sized page
   (eg 6x14/6x20 on DS620)
 * Backend splits image into the necessary 2 or 3 panels w/ 2" overlap
 * Backend blends the overlapping areas together
 * Discrete panoramas work the same way, only no overlap and are larger

 Successfully tested on the DS620!
This commit is contained in:
Solomon Peachy 2023-12-23 21:01:03 -05:00
parent 581602539f
commit e74960ad84
6 changed files with 781 additions and 114 deletions

View file

@ -110,7 +110,8 @@ BACKENDS = canonselphy canonselphyneo dnpds40 hiti kodak605 kodak1400 kodak6800
# List of data files
DATAFILES = $(wildcard hiti_data/*bin) $(wildcard lib70x/data/*raw) \
$(wildcard lib70x/data/*cpc) $(wildcard lib70x/data/*lut) \
$(wildcard lib70x/data/*dat) $(wildcard lib70x/data/*csv)
$(wildcard lib70x/data/*dat) $(wildcard lib70x/data/*csv) \
$(wildcard dnp_data/*csv)
# For the s6145, mitsu70x, mitsud90, and mitsu9550 backends
ifneq (,$(findstring mingw,$(CC)))
@ -201,6 +202,10 @@ $(DATAFILES_TMP)/%: hiti_data/% | $(DATAFILES_TMP)
@$(E) " LN " $@
$(Q)$(LN) -sf ../$< $@
$(DATAFILES_TMP)/%: dnp_data/% | $(DATAFILES_TMP)
@$(E) " LN " $@
$(Q)$(LN) -sf ../$< $@
$(DATAFILES_TMP)/%: lib70x/data/% | $(DATAFILES_TMP)
@$(E) " LN " $@
$(Q)$(LN) -sf ../$< $@

View file

@ -60,16 +60,24 @@ struct dnpds40_printjob {
int can_rewind;
int buffcntrl;
int rows;
int is_pano;
int buf_needed;
int cut_paper;
};
#define MAX_PRINTJOB_LEN (((ctx->native_width*ctx->max_height+1024+54+10))*3+1024) /* Worst-case, YMC */
#define MAX_PANOPRINTJOB_LEN ((((ctx->native_width*ctx->max_height+1024+54+10))*3+1024)*3) /* Worst-case, YMC */
#define MFG_DNP 0
#define MFG_CITIZEN 1
#define MFG_MITSUBISHI 2
#define MFG_FUJIFILM 3
#define MFG_OTHER 4
#define USE_PANODATA_FILES
struct dnpds40_ctx {
struct dyesub_connection *conn;
@ -230,6 +238,25 @@ struct dnpds40_cmd {
#define MULTICUT_S_8x10_75 26
#define MULTICUT_S_8x4X3 28 // different than roll type.
/* Special panorama sizes */
#define MULTICUT_PANO_6x14 9000
#define MULTICUT_PANO_6x20 9001
#define MULTICUT_PANO_8x18 9010
#define MULTICUT_PANO_8x26 9011
#define MULTICUT_PANO_8x22 9012
#define MULTICUT_PANO_8x32 9013
#define MULTICUT_PANO_A4x21 9014
#define MULTICUT_PANO_A4x31 9015
#define MULTICUT_PANO_6x16 9020
#define MULTICUT_PANO_6x24 9021
#define MULTICUT_PANO_8x20 9030
#define MULTICUT_PANO_8x30 9031
#define MULTICUT_PANO_8x24 9032
#define MULTICUT_PANO_8x36 9033
#define MULTICUT_PANO_A4x2 9034
#define MULTICUT_PANO_A4x3 9035
#ifndef min
#define min(__x, __y) ((__x) < (__y)) ? __x : __y
#endif
@ -244,6 +271,510 @@ static int legacy_qw410_read_parse(struct dnpds40_printjob *job, int data_fd, in
static void dnpds40_cleanup_job(const void *vjob);
static int dnpds40_query_markers(void *vctx, struct marker **markers, int *count);
/* Panorama crap */
struct panodata_row {
uint16_t start_row;
double rhYMC[3];
double lhYMC[3];
};
#define DNP_PANO_MAXROWS 64
struct dnp_panodata {
uint16_t elements;
struct panodata_row rows[DNP_PANO_MAXROWS];
};
#ifdef USE_PANODATA_FILES
#define PANODATA_DS620 "LUTData_0010.csv"
#define PANODATA_DS820 "LUTData820_0010.csv"
static struct dnp_panodata *dnp_read_panodata(const char *filename)
{
struct dnp_panodata *pano = NULL;
FILE *f;
char buf[4096];
int line;
char *ptr;
const char *delim = " ,\t\n";
if (!filename)
return NULL;
pano = malloc(sizeof(struct dnp_panodata));
if (!pano)
return NULL;
pano->elements = 0;
snprintf(buf, sizeof(buf), "%s/%s", corrtable_path, filename);
f = fopen(buf, "r");
if (!f)
goto done_free;
/* Skip the first four lines */
for (line = 0; line < DNP_PANO_MAXROWS ; line++) {
if (fgets(buf, sizeof(buf), f) == NULL)
break;
ptr = strtok(buf, delim);
if (!ptr)
goto abort;
if (strcmp("REC", ptr))
continue;
ptr = strtok(NULL, delim);
if (!ptr)
goto abort;
pano->rows[pano->elements].start_row = strtol(ptr, NULL, 10);
ptr = strtok(NULL, delim);
if (!ptr)
goto abort;
pano->rows[pano->elements].rhYMC[0] = strtod(ptr,NULL);
ptr = strtok(NULL, delim);
if (!ptr)
goto abort;
pano->rows[pano->elements].rhYMC[1] = strtod(ptr,NULL);
ptr = strtok(NULL, delim);
if (!ptr)
goto abort;
pano->rows[pano->elements].rhYMC[2] = strtod(ptr,NULL);
ptr = strtok(NULL, delim);
if (!ptr)
goto abort;
pano->rows[pano->elements].lhYMC[0] = strtod(ptr,NULL);
ptr = strtok(NULL, delim);
if (!ptr)
goto abort;
pano->rows[pano->elements].lhYMC[1] = strtod(ptr,NULL);
ptr = strtok(NULL, delim);
if (!ptr)
goto abort;
pano->rows[pano->elements].lhYMC[2] = strtod(ptr,NULL);
pano->elements++;
}
if (pano->elements < 20)
goto abort;
fclose(f);
#if 0
f = fopen("/tmp/panodata.h", "w");
fprintf(f, "static struct dnp_panodata panodata = {\n");
fprintf(f, "\t.elements = %d,\n", pano->elements);
for (int i = 0 ; i < pano->elements ; i++) {
fprintf(f, "\t.rows[%2u] = { %4u, { %1.10f, %1.10f, %1.10f }, { %1.10f, %1.10f, %1.10f} },\n",
i,
pano->rows[i].start_row,
pano->rows[i].rhYMC[0],
pano->rows[i].rhYMC[1],
pano->rows[i].rhYMC[2],
pano->rows[i].lhYMC[0],
pano->rows[i].lhYMC[1],
pano->rows[i].lhYMC[2]);
}
fprintf(f, "};\n");
fclose(f);
exit(1);
#endif
return pano;
abort:
fclose(f);
done_free:
free(pano);
return NULL;
}
void dnp_free_panodata (struct dnp_panodata *pano)
{
if (pano)
free(pano);
}
#else /* !USE_PANODATA_FILES */
#include "backend_panodata.h"
#define dnp_read_panodata(__fname) &panodata
#define dnp_free_panodata(__pano)
#endif
#define PROCESS_PIXEL(__corr) \
outdata[r * cols + c] = 255 - ((255 - (double)indata[r * cols + c]) * (__corr))
static void dnp_applypano_plane(const struct dnp_panodata *pano,
const uint8_t *indata, uint8_t *outdata,
uint16_t rows, const uint16_t cols, const uint16_t pad_rows,
const uint16_t dpi, int overlap, const int plane,
const int rh, const int lh)
{
uint16_t r, c;
/* Fill the start margin with white */
if (pad_rows) {
memset(outdata, 0xff, pad_rows * cols);
outdata += pad_rows * cols;
}
for (r = 0 ; r < rows; r++) {
const struct panodata_row *lhc = pano ? &pano->rows[0] : NULL;
const struct panodata_row *rhc = pano ? &pano->rows[pano->elements - 1] : NULL;
if (rh && r < overlap) {
/* Row is in RH overlap portion of panel */
int i;
int row = (overlap - r);
if (dpi == 600)
row /= 2;
for (i = 0 ; i < pano->elements-1 ; i++) {
if (row >= pano->rows[i].start_row && row < pano->rows[i+1].start_row)
break;
}
rhc = &pano->rows[i];
} else if (lh && (rows -r) < overlap) {
/* Row is in LH overlap portion of panel */
int i;
int row = (rows -r);
if (dpi == 600)
row /= 2;
for (i = 0 ; i < pano->elements-1 ; i++) {
if (row >= pano->rows[i].start_row && row < pano->rows[i+1].start_row)
break;
}
lhc = &pano->rows[i];
} else {
/* No processing on row, pass through as-is */
memcpy(&outdata[r * cols], &indata[r * cols], cols);
continue;
}
if (rh && rhc && r < overlap) {
/* Fade RH row */
if (plane == 'Y')
for (c = 0 ; c < cols ; c++) {
PROCESS_PIXEL(rhc->rhYMC[0]);
}
else if (plane == 'M') {
for (c = 0 ; c < cols ; c++) {
PROCESS_PIXEL(rhc->rhYMC[1]);
}
} else {
for (c = 0 ; c < cols ; c++) {
PROCESS_PIXEL(rhc->rhYMC[2]);
}
}
} else if (lh && lhc && (rows -r) < overlap) {
/* Fade LH row */
if (plane == 'Y')
for (c = 0 ; c < cols ; c++) {
PROCESS_PIXEL(lhc->lhYMC[0]);
}
else if (plane == 'M') {
for (c = 0 ; c < cols ; c++) {
PROCESS_PIXEL(lhc->lhYMC[1]);
}
} else {
for (c = 0 ; c < cols ; c++) {
PROCESS_PIXEL(lhc->lhYMC[2]);
}
}
}
}
/* Fill the tail margin with white */
if (pad_rows)
memset(&outdata[rows * cols], 0xff, pad_rows * cols);
}
static int dnp_panorama_splitjob(struct dnpds40_ctx *ctx,
const struct dnpds40_printjob *injob,
struct dnpds40_printjob **newjobs)
{
struct dnp_panodata *pano = NULL;
int overlap = injob->dpi * 2;
uint16_t out_rows = 0;
uint16_t in_rows = 0;
uint8_t num_panels = 0;
uint32_t new_multicut = 0;
uint16_t pad_rows = 0;
in_rows = injob->dpi == 600 ? injob->rows / 2 : injob->rows;
if (ctx->conn->type == P_DNP_DS620) {
out_rows = 2436;
new_multicut = MULTICUT_6x8;
if (in_rows == 4236) {
num_panels = 2;
pad_rows = 18;
} else if (in_rows == 6036) {
num_panels = 3;
pad_rows = 18;
} else if (in_rows == 2436*2) {
num_panels = 2;
overlap = 0;
} else if (in_rows == 2436*3) {
num_panels = 3;
overlap = 0;
} else {
ERROR("Invalid panorama size (%d rows)\n", injob->rows);
goto bail;
}
} else if (ctx->conn->type == P_DNP_DS820) {
if (ctx->media == 600) { /* A4 */
if (in_rows == 5436) {
new_multicut = MULTICUT_A4x10;
out_rows = 3036;
pad_rows = 18;
num_panels = 2;
} else if (in_rows == 7836) {
new_multicut = MULTICUT_A4x10;
out_rows = 3036;
pad_rows = 18;
num_panels = 3;
} else if (in_rows == 3036*2) {
new_multicut = MULTICUT_A4x10;
num_panels = 2;
out_rows = 3036;
overlap = 0;
} else if (in_rows == 3036*3) {
new_multicut = MULTICUT_A4x10;
num_panels = 3;
out_rows = 3036;
overlap = 0;
} else if (in_rows == 6452) {
new_multicut = MULTICUT_A4;
num_panels = 2;
pad_rows = 18;
out_rows = 3544;
} else if (in_rows == 9360) {
new_multicut = MULTICUT_A4;
num_panels = 3;
pad_rows = 18;
out_rows = 3544;
} else if (in_rows == 3544*2) {
new_multicut = MULTICUT_A4;
num_panels = 3;
out_rows = 3544;
overlap = 0;
} else if (in_rows == 3544*3) {
new_multicut = MULTICUT_A4;
num_panels = 3;
out_rows = 3544;
overlap = 0;
} else {
ERROR("Invalid panorama size (%d rows)\n", injob->rows);
goto bail;
}
} else { // 8x10/8x12
if (in_rows == 5436) {
new_multicut = MULTICUT_8x10;
num_panels = 2;
pad_rows = 18;
out_rows = 3036;
} else if (in_rows == 7836) {
new_multicut = MULTICUT_8x10;
num_panels = 3;
pad_rows = 18;
out_rows = 3036;
} else if (in_rows == 3036*2) {
new_multicut = MULTICUT_8x10;
num_panels = 2;
overlap = 0;
out_rows = 3036;
} else if (in_rows == 3036*3) {
new_multicut = MULTICUT_8x10;
num_panels = 3;
overlap = 0;
out_rows = 3036;
} else if (in_rows == 6636) {
new_multicut = MULTICUT_8x12;
num_panels = 2;
pad_rows = 18;
out_rows = 3636;
} else if (in_rows == 9636) {
new_multicut = MULTICUT_8x12;
num_panels = 3;
pad_rows = 18;
out_rows = 3636;
} else if (in_rows == 3636*2) {
new_multicut = MULTICUT_8x12;
num_panels = 2;
out_rows = 3636;
overlap = 0;
} else if (in_rows == 3636*3) {
new_multicut = MULTICUT_8x12;
num_panels = 3;
out_rows = 3636;
overlap = 0;
} else {
ERROR("Invalid panorama size (%d rows)\n", injob->rows);
goto bail;
}
}
}
/* Double everything up for >300dpi */
if (injob->dpi == 600) {
out_rows *= 2;
overlap *= 2;
pad_rows *= 2;
}
if (overlap) {
#ifdef USE_PANODATA_FILES
const char *filename = NULL;
if (ctx->conn->type == P_DNP_DS620)
filename = PANODATA_DS620;
else if (ctx->conn->type == P_DNP_DS820)
filename = PANODATA_DS820;
if (!filename || !(pano = dnp_read_panodata(filename))) {
ERROR("Failure to load panorama LUT file (%s)\n", filename);
goto bail;
}
#else
pano = dnp_read_panodata(NULL);
#endif
DEBUG("Splitting continuous panorama job... (%d panels of %d+%d rows, %d overlap)\n", num_panels, out_rows - 2*pad_rows, 2*pad_rows, overlap);
} else {
DEBUG("Splitting discrete panel panorama job...(%d panels of %d rows)\n", num_panels, out_rows);
}
for (int panel = 0 ; panel < num_panels ; panel++) {
int lh = (panel < (num_panels -1));
int rh = (panel > 0);
/* Create new job */
newjobs[panel] = malloc(sizeof(struct dnpds40_printjob));
if (!newjobs[panel]) {
ERROR("Memory allocation failure");
return CUPS_BACKEND_RETRY_CURRENT;
}
struct dnpds40_printjob *newjob = newjobs[panel];
memcpy(newjob, injob, sizeof(struct dnpds40_printjob));
newjob->common.copies = 1;
newjob->is_pano = lh; /* All but last */
newjob->databuf = malloc(MAX_PRINTJOB_LEN);
if (!newjob->databuf) {
dnpds40_cleanup_job(newjob);
newjobs[panel] = NULL;
ERROR("Memory allocation failure!\n");
return CUPS_BACKEND_RETRY_CURRENT;
}
newjob->datalen = 0;
newjob->multicut = new_multicut;
newjob->rows = out_rows;
uint32_t plane_len = out_rows * ctx->native_width + 1088;
/* Copy data blocks from injob */
uint8_t *ptr = injob->databuf;
while(ptr && ptr < (injob->databuf + injob->datalen)) {
uint32_t i;
int copy = 1;
if(!memcmp("IMAGE YPLANE", ptr +2, 12) ||
!memcmp("IMAGE MPLANE", ptr +2, 12) ||
!memcmp("IMAGE CPLANE", ptr +2, 12) ) {
if (ptr[8] == 'Y') {
/* Insert CONT_PANORAMA _before_ the image data */
int cont = (panel == num_panels-1) ? 0 : 1;
int lap = overlap;
if (injob->dpi == 600)
lap /= 2;
lap /= 3; /* Convert pixels into inches * 100 */
if (overlap) {
/* Continuous panorama */
newjob->datalen += sprintf((char*)newjob->databuf + newjob->datalen, "\033PCNTRL CONT_PANORAMA 00000008%04u%04u", cont, lap);
} else {
/* Discrete panel */
newjob->cutter = 1000;
}
}
uint8_t *bmp_hdr;
DEBUG("Panel %d plane %c\n", panel, ptr[8]);
newjob->datalen += sprintf((char*)newjob->databuf + newjob->datalen,
"\033PIMAGE %cPLANE %08u", ptr[8], plane_len);
/* Copy over old bitmap header*/
memcpy(newjob->databuf + newjob->datalen, ptr + 32, 1088);
bmp_hdr = newjob->databuf + newjob->datalen;
/* Mangle BMP header for new size and row count */
i = cpu_to_le32(plane_len);
memcpy(bmp_hdr + 2, &i, sizeof(i));
i = cpu_to_le32(out_rows);
memcpy(bmp_hdr + 22, &i, sizeof(i));
/* Split panorama */
dnp_applypano_plane(pano,
ptr + 32 + 1088 + (pad_rows * ctx->native_width) + (panel * (out_rows - pad_rows*2 - overlap) * ctx->native_width),
newjob->databuf + newjob->datalen + 1088,
out_rows - pad_rows*2, ctx->native_width, pad_rows, injob->dpi, overlap, ptr[8], rh, lh);
newjob->datalen += plane_len;
/* Don't copy anything else from source */
copy = 0;
} else if(!memcmp("CNTRL QTY", ptr + 2, 9)) {
/* Ignore copy count */
copy = 0;
} else if(!memcmp("CNTRL CUTTER", ptr + 2, 12) ||
!memcmp("CNTRL FULL_CUTTER_SET", ptr + 2, 21)) {
/* Ignore all cutter commands */
copy = 0;
} else if (!memcmp("CNTRL START", ptr + 2, 11)) {
}
/* Work out how much to copy from source, and increment source pointer */
char buf[10];
buf[8] = 0;
memcpy(buf, ptr + 24, 8);
i = atoi(buf) + 32;
if (copy) {
memcpy(newjob->databuf + newjob->datalen, ptr, i);
newjob->datalen += i;
}
ptr += i;
}
#if 0
{
char buf[32];
sprintf(buf, "/tmp/dump%d.raw", panel);
FILE *f = fopen(buf, "wb");
fwrite(newjob->databuf, newjob->datalen, 1, f);
fclose(f);
}
#endif
}
dnp_free_panodata(pano);
return CUPS_BACKEND_OK;
bail:
dnp_free_panodata(pano);
return CUPS_BACKEND_FAILED;
}
#define JOB_EQUIV(__x) if (job1->__x != job2->__x) goto done
/* NOTE: Does _not_ free the input jobs */
@ -1562,8 +2093,6 @@ static int dnpds40_query_status(struct dnpds40_ctx *ctx)
return count;
}
#define MAX_PRINTJOB_LEN (((ctx->native_width*ctx->max_height+1024+54+10))*3+1024) /* Worst-case, YMC */
static int dnpds40_read_parse(void *vctx, const void **vjob, int data_fd, int copies) {
struct dnpds40_ctx *ctx = vctx;
int run = 1;
@ -1593,7 +2122,7 @@ static int dnpds40_read_parse(void *vctx, const void **vjob, int data_fd, int co
the end of the job.
*/
job->databuf = malloc(MAX_PRINTJOB_LEN);
job->databuf = malloc(MAX_PANOPRINTJOB_LEN);
if (!job->databuf) {
dnpds40_cleanup_job(job);
ERROR("Memory allocation failure!\n");
@ -1605,7 +2134,7 @@ static int dnpds40_read_parse(void *vctx, const void **vjob, int data_fd, int co
uint32_t remain;
/* Make sure we won't overflow... */
if (job->datalen + sizeof(struct dnpds40_cmd) > MAX_PRINTJOB_LEN) {
if (job->datalen + sizeof(struct dnpds40_cmd) > MAX_PANOPRINTJOB_LEN) {
ERROR("Buffer overflow when parsing printjob! (%d+%lu)\n",
job->datalen, sizeof(struct dnpds40_cmd));
dnpds40_cleanup_job(job);
@ -1678,7 +2207,7 @@ static int dnpds40_read_parse(void *vctx, const void **vjob, int data_fd, int co
remain = j;
/* Make sure we won't overflow... */
if (job->datalen + remain > MAX_PRINTJOB_LEN) {
if (job->datalen + remain > MAX_PANOPRINTJOB_LEN) {
ERROR("Buffer overflow when parsing printjob! (%d+%d)\n",
job->datalen, remain);
dnpds40_cleanup_job(job);
@ -1689,7 +2218,7 @@ static int dnpds40_read_parse(void *vctx, const void **vjob, int data_fd, int co
i = read(data_fd, job->databuf + job->datalen + sizeof(struct dnpds40_cmd),
remain);
if (i < 0) {
ERROR("Data Read Error: %d (%d/%d @%d/%d)\n", i, remain, j, job->datalen,MAX_PRINTJOB_LEN);
ERROR("Data Read Error: %d (%d/%d @%d/%d)\n", i, remain, j, job->datalen,MAX_PANOPRINTJOB_LEN);
dnpds40_cleanup_job(job);
return i;
}
@ -1712,6 +2241,10 @@ static int dnpds40_read_parse(void *vctx, const void **vjob, int data_fd, int co
memcpy(buf, job->databuf + job->datalen + 32, 8);
job->cutter = atoi(buf);
/* We'll insert it ourselves later */
if (job->cutter == 1000)
job->is_pano = 1;
continue;
}
if(!memcmp("CNTRL BUFFCNTRL", job->databuf + job->datalen+2, 15)) {
@ -1740,7 +2273,7 @@ static int dnpds40_read_parse(void *vctx, const void **vjob, int data_fd, int co
job->multicut = atoi(buf);
/* Backend automatically handles rewind support, so
ignore application requests to use it. */
if (job->multicut > 400)
if (job->multicut > 400 && job->multicut < 1000)
job->multicut -= 400;
/* We'll insert this ourselves later. */
@ -1804,6 +2337,10 @@ static int dnpds40_read_parse(void *vctx, const void **vjob, int data_fd, int co
dnpds40_cleanup_job(job);
return CUPS_BACKEND_CANCEL;
}
/* Capture number of rows */
memcpy(&y_ppm, job->databuf + job->datalen + 32 + 22, sizeof(y_ppm));
job->rows = le32_to_cpu(y_ppm);
}
if(!memcmp("CNTRL PRINTSPEED", job->databuf + job->datalen + 2, 16)) {
if (!ctx->supports_printspeed) {
@ -1821,6 +2358,8 @@ static int dnpds40_read_parse(void *vctx, const void **vjob, int data_fd, int co
ERROR("Printer does not support Continuous Panorama, aborting!\n");
continue;
}
memcpy(buf, job->databuf + job->datalen + 32 + 4, 4);
job->is_pano = atoi(buf);
}
/* This is the last block.. */
@ -1830,6 +2369,85 @@ static int dnpds40_read_parse(void *vctx, const void **vjob, int data_fd, int co
/* Add in the size of this chunk */
job->datalen += sizeof(struct dnpds40_cmd) + j;
}
/* Figure out the number of buffers we need. */
job->buf_needed = 1;
if (job->dpi == 600) {
switch(ctx->conn->type) {
case P_DNP_DS620:
if (job->multicut == MULTICUT_6x9 ||
job->multicut == MULTICUT_6x4_5X2)
job->buf_needed = 2;
break;
case P_DNP_DS80: /* DS80/CX-W */
if (job->matte && (job->multicut == MULTICUT_8xA4LEN ||
job->multicut == MULTICUT_8x4X3 ||
job->multicut == MULTICUT_8x8_8x4 ||
job->multicut == MULTICUT_8x6X2 ||
job->multicut == MULTICUT_8x12))
job->buf_needed = 2;
break;
case P_DNP_DS80D:
if (job->matte) {
int mcut = job->multicut;
if (mcut > MULTICUT_S_BACK)
mcut -= MULTICUT_S_BACK;
else if (mcut > MULTICUT_S_FRONT)
mcut -= MULTICUT_S_FRONT;
if (mcut == MULTICUT_8xA4LEN ||
mcut == MULTICUT_8x4X3 ||
mcut == MULTICUT_8x8_8x4 ||
mcut == MULTICUT_8x6X2 ||
mcut == MULTICUT_8x12)
job->buf_needed = 2;
if (mcut == MULTICUT_S_8x12 ||
mcut == MULTICUT_S_8x6X2 ||
mcut == MULTICUT_S_8x4X3)
job->buf_needed = 2;
}
break;
case P_DNP_DS820:
// Nothing; all sizes only need 1 buffer
break;
case P_CITIZEN_CW01:
job->buf_needed = 2;
break;
default: /* DS40/CX/RX1/CY/everything else */
if (job->matte) {
if (job->multicut == MULTICUT_6x8 ||
job->multicut == MULTICUT_6x9 ||
job->multicut == MULTICUT_6x4X2 ||
job->multicut == MULTICUT_5x7 ||
job->multicut == MULTICUT_5x3_5X2)
job->buf_needed = 2;
} else {
if (job->multicut == MULTICUT_6x8 ||
job->multicut == MULTICUT_6x9 ||
job->multicut == MULTICUT_6x4X2)
job->buf_needed = 1;
}
break;
}
}
if (job->multicut >= MULTICUT_PANO_6x14)
{
int rval = dnp_panorama_splitjob(ctx, job, (struct dnpds40_printjob**)vjob);
/* Clean up original job regardless */
dnpds40_cleanup_job(job);
if (rval)
return rval;
/* And continue validating everything based on the 1st job */
job = (struct dnpds40_printjob*) *vjob;
}
parsed:
/* If we have no data.. don't bother */
if (!job->datalen) {
@ -1838,7 +2456,7 @@ parsed:
}
/* Use the larger of the copy arguments */
if (job->common.copies < copies)
if (!job->is_pano && job->common.copies < copies)
job->common.copies = copies;
/* Make sure advanced matte modes are supported */
@ -1919,70 +2537,6 @@ parsed:
}
}
/* Figure out the number of buffers we need. */
job->buf_needed = 1;
if (job->dpi == 600) {
switch(ctx->conn->type) {
case P_DNP_DS620:
if (job->multicut == MULTICUT_6x9 ||
job->multicut == MULTICUT_6x4_5X2)
job->buf_needed = 2;
break;
case P_DNP_DS80: /* DS80/CX-W */
if (job->matte && (job->multicut == MULTICUT_8xA4LEN ||
job->multicut == MULTICUT_8x4X3 ||
job->multicut == MULTICUT_8x8_8x4 ||
job->multicut == MULTICUT_8x6X2 ||
job->multicut == MULTICUT_8x12))
job->buf_needed = 2;
break;
case P_DNP_DS80D:
if (job->matte) {
int mcut = job->multicut;
if (mcut > MULTICUT_S_BACK)
mcut -= MULTICUT_S_BACK;
else if (mcut > MULTICUT_S_FRONT)
mcut -= MULTICUT_S_FRONT;
if (mcut == MULTICUT_8xA4LEN ||
mcut == MULTICUT_8x4X3 ||
mcut == MULTICUT_8x8_8x4 ||
mcut == MULTICUT_8x6X2 ||
mcut == MULTICUT_8x12)
job->buf_needed = 2;
if (mcut == MULTICUT_S_8x12 ||
mcut == MULTICUT_S_8x6X2 ||
mcut == MULTICUT_S_8x4X3)
job->buf_needed = 2;
}
break;
case P_DNP_DS820:
// Nothing; all sizes only need 1 buffer
break;
case P_CITIZEN_CW01:
job->buf_needed = 2;
break;
default: /* DS40/CX/RX1/CY/everything else */
if (job->matte) {
if (job->multicut == MULTICUT_6x8 ||
job->multicut == MULTICUT_6x9 ||
job->multicut == MULTICUT_6x4X2 ||
job->multicut == MULTICUT_5x7 ||
job->multicut == MULTICUT_5x3_5X2)
job->buf_needed = 2;
} else {
if (job->multicut == MULTICUT_6x8 ||
job->multicut == MULTICUT_6x9 ||
job->multicut == MULTICUT_6x4X2)
job->buf_needed = 1;
}
break;
}
}
if (job->dpi == 334 && ctx->conn->type != P_CITIZEN_CW01)
{
ERROR("Illegal resolution (%u) for printer!\n", job->dpi);
@ -2246,7 +2800,7 @@ skip_multicut:
}
/* Panorama sanity checking */
if (job->cutter == 1000 || ctx->pano) {
if (job->is_pano) {
if (!ctx->supports_pano) {
ERROR("Printer does not support panorama printing, aborting!\n");
dnpds40_cleanup_job(job);
@ -2268,13 +2822,6 @@ skip_multicut:
return CUPS_BACKEND_CANCEL;
}
}
ctx->pano++;
/* Hard limit of 3 panels */
if (job->cutter == 1000 && ctx->pano >= 3) {
WARNING("Panoramas limited to three panels!\n");
job->cutter = 0;
}
if (job->fullcut) {
ERROR("Cannot use full cutter control in panorama mode!\n");
@ -2501,6 +3048,33 @@ top:
WARNING("Printer does not have sufficient remaining media (%d) to complete job (%d)\n", copies, count);
}
/* Ensure we can complete panorama */
if (ctx->pano && (count < 3)) {
ERROR("Printer does not have sufficent media for panorama job, aborting job!\n");
return CUPS_BACKEND_CANCEL;
}
/* If we're printing a panorama, query state before _first_ page */
if (job->is_pano && ctx->pano == 0) {
int i;
dnpds40_build_cmd(&cmd, "INFO", "PANORAMA_PRINT", 0);
resp = dnpds40_resp_cmd(ctx, &cmd, &len);
if (!resp)
return CUPS_BACKEND_FAILED;
dnpds40_cleanup_string((char*)resp, len);
i = atoi((char*)resp);
free(resp);
if (i != 0) {
INFO("Printer Not ready for panorama printing, waiting.. (%d)\n", i);
sleep(1);
goto top;
}
}
if (job->is_pano)
ctx->pano++;
/* Work around a bug in older gutenprint releases. */
if (ctx->last_multicut >= 200 && ctx->last_multicut < 300 &&
multicut >= 200 && multicut < 300) {
@ -2511,13 +3085,17 @@ top:
/* Store our last multicut state */
ctx->last_multicut = multicut;
/* For continuous panorama jobs we only want to send this stuff on the FIRST page */
if (ctx->pano > 1 && !job->cutter)
goto skip_pageparams;
/* Tell printer how many copies to make */
snprintf(buf, sizeof(buf), "%07d\r", manual_copies || ctx->pano ? 1 : copies);
snprintf(buf, sizeof(buf), "%07d\r", manual_copies ? 1 : copies);
dnpds40_build_cmd(&cmd, "CNTRL", "QTY", 8);
if ((ret = dnpds40_do_cmd(ctx, &cmd, (uint8_t*)buf, 8)))
return CUPS_BACKEND_FAILED;
if (!manual_copies || ctx->pano)
if (!manual_copies)
copies = 1;
/* Job resumption on correctable errors */
@ -2573,13 +3151,16 @@ top:
}
/* Program in the multicut setting, if one exists */
if (multicut) {
/* Do _NOT_ send for continuous panoramas! */
if ((!job->is_pano || job->cutter) && multicut) {
snprintf(buf, sizeof(buf), "%08d", multicut);
dnpds40_build_cmd(&cmd, "IMAGE", "MULTICUT", 8);
if ((ret = dnpds40_do_cmd(ctx, &cmd, (uint8_t*)buf, 8)))
return CUPS_BACKEND_FAILED;
}
skip_pageparams:
/* Finally, send the stream over as individual data chunks */
ptr = job->databuf;
while(ptr && ptr < (job->databuf + job->datalen)) {
@ -2597,7 +3178,7 @@ top:
sleep(1); /* Give things a moment */
/* Reset panorama state if we've sent the last panel in the set */
if (job->cutter != 1000 && ctx->pano)
if (!job->is_pano && ctx->pano)
ctx->pano = 0;
/* Reset partial matte state if necessary */
@ -4018,7 +4599,7 @@ static const char *dnpds40_prefixes[] = {
const struct dyesub_backend dnpds40_backend = {
.name = "DNP DS-series / Citizen C-series",
.version = "0.152",
.version = "0.153",
.uri_prefixes = dnpds40_prefixes,
.cmdline_usage = dnpds40_cmdline,
.cmdline_arg = dnpds40_cmdline_arg,

24
backend_panodata.h Normal file
View file

@ -0,0 +1,24 @@
static struct dnp_panodata panodata = {
.elements = 21,
.rows[ 0] = { 0, { 1.0000000000, 1.0000000000, 1.0000000000 }, { 0.2000000000, 0.2000000000, 0.2000000000} },
.rows[ 1] = { 30, { 0.9933580000, 0.9963060000, 0.9946110000 }, { 0.2950650000, 0.2950650000, 0.2950650000} },
.rows[ 2] = { 60, { 0.9800000000, 0.9850000000, 0.9850000000 }, { 0.3900000000, 0.3900000000, 0.3900000000} },
.rows[ 3] = { 90, { 0.9540200000, 0.9602540000, 0.9677210000 }, { 0.4879980000, 0.4879980000, 0.4879980000} },
.rows[ 4] = { 120, { 0.9182812500, 0.9282812500, 0.9460937500 }, { 0.5800000000, 0.5800000000, 0.5800000000} },
.rows[ 5] = { 150, { 0.8730900000, 0.8920840000, 0.9206270000 }, { 0.6683700000, 0.6683700000, 0.6683700000} },
.rows[ 6] = { 180, { 0.8276562500, 0.8543750000, 0.8910937500 }, { 0.7400000000, 0.7400000000, 0.7400000000} },
.rows[ 7] = { 210, { 0.7800400000, 0.8030000000, 0.8550000000 }, { 0.8004440000, 0.8004440000, 0.8004440000} },
.rows[ 8] = { 240, { 0.7348437500, 0.7550000000, 0.8160000000 }, { 0.8450000000, 0.8450000000, 0.8450000000} },
.rows[ 9] = { 270, { 0.6750000000, 0.7020000000, 0.7785180000 }, { 0.8855640000, 0.8855640000, 0.8855640000} },
.rows[10] = { 300, { 0.6120000000, 0.6450000000, 0.7321875000 }, { 0.9150000000, 0.9150000000, 0.9150000000} },
.rows[11] = { 330, { 0.5617422160, 0.5950000000, 0.6879300400 }, { 0.9359207970, 0.9359207970, 0.9359207970} },
.rows[12] = { 360, { 0.5112158120, 0.5430000000, 0.6430933460 }, { 0.9533652920, 0.9533652920, 0.9533652920} },
.rows[13] = { 390, { 0.4626856430, 0.4970173200, 0.5963030420 }, { 0.9663907840, 0.9663907840, 0.9663907840} },
.rows[14] = { 420, { 0.4104687500, 0.4482812500, 0.5496875000 }, { 0.9770000000, 0.9770000000, 0.9770000000} },
.rows[15] = { 450, { 0.3518815000, 0.3938775000, 0.4979980000 }, { 0.9847240000, 0.9847240000, 0.9847240000} },
.rows[16] = { 480, { 0.2965625000, 0.3413281250, 0.4407812500 }, { 0.9900000000, 0.9900000000, 0.9900000000} },
.rows[17] = { 510, { 0.2393955000, 0.2762305000, 0.3738025000 }, { 0.9956110000, 0.9956110000, 0.9956110000} },
.rows[18] = { 540, { 0.1855468750, 0.2163281250, 0.3063281250 }, { 1.0000000000, 1.0000000000, 1.0000000000} },
.rows[19] = { 570, { 0.1243430000, 0.1441130000, 0.2241130000 }, { 1.0000000000, 1.0000000000, 1.0000000000} },
.rows[20] = { 600, { 0.0800000000, 0.0800000000, 0.1450000000 }, { 1.0000000000, 1.0000000000, 1.0000000000} },
};

View file

@ -0,0 +1,25 @@
#FORMAT ,Major,Minor,,,,,
FORMAT,1,0,,,,,
RECNUM,64,,,,,,
#Header,,(Rh)Y, (Rh)M, (Rh)C, (Lh)Y, (Lh)M, (Lh)C
REC,0,1,1,1,0.2,0.2,0.2
REC,30,0.993358,0.996306,0.994611,0.295065,0.295065,0.295065
REC,60,0.98,0.985,0.985,0.39,0.39,0.39
REC,90,0.95402,0.960254,0.967721,0.487998,0.487998,0.487998
REC,120,0.91828125,0.92828125,0.94609375,0.58,0.58,0.58
REC,150,0.87309,0.892084,0.920627,0.66837,0.66837,0.66837
REC,180,0.82765625,0.854375,0.89109375,0.74,0.74,0.74
REC,210,0.78004,0.803,0.855,0.800444,0.800444,0.800444
REC,240,0.73484375,0.755,0.816,0.845,0.845,0.845
REC,270,0.675,0.702,0.778518,0.885564,0.885564,0.885564
REC,300,0.612,0.645,0.7321875,0.915,0.915,0.915
REC,330,0.561742216,0.595,0.68793004,0.935920797,0.935920797,0.935920797
REC,360,0.511215812,0.543,0.643093346,0.953365292,0.953365292,0.953365292
REC,390,0.462685643,0.49701732,0.596303042,0.966390784,0.966390784,0.966390784
REC,420,0.41046875,0.44828125,0.5496875,0.977,0.977,0.977
REC,450,0.3518815,0.3938775,0.497998,0.984724,0.984724,0.984724
REC,480,0.2965625,0.341328125,0.44078125,0.99,0.99,0.99
REC,510,0.2393955,0.2762305,0.3738025,0.995611,0.995611,0.995611
REC,540,0.185546875,0.216328125,0.306328125,1,1,1
REC,570,0.124343,0.144113,0.224113,1,1,1
REC,600,0.08,0.08,0.145,1,1,1
1 #FORMAT Major Minor
2 FORMAT 1 0
3 RECNUM 64
4 #Header (Rh)Y (Rh)M (Rh)C (Lh)Y (Lh)M (Lh)C
5 REC 0 1 1 1 0.2 0.2 0.2
6 REC 30 0.993358 0.996306 0.994611 0.295065 0.295065 0.295065
7 REC 60 0.98 0.985 0.985 0.39 0.39 0.39
8 REC 90 0.95402 0.960254 0.967721 0.487998 0.487998 0.487998
9 REC 120 0.91828125 0.92828125 0.94609375 0.58 0.58 0.58
10 REC 150 0.87309 0.892084 0.920627 0.66837 0.66837 0.66837
11 REC 180 0.82765625 0.854375 0.89109375 0.74 0.74 0.74
12 REC 210 0.78004 0.803 0.855 0.800444 0.800444 0.800444
13 REC 240 0.73484375 0.755 0.816 0.845 0.845 0.845
14 REC 270 0.675 0.702 0.778518 0.885564 0.885564 0.885564
15 REC 300 0.612 0.645 0.7321875 0.915 0.915 0.915
16 REC 330 0.561742216 0.595 0.68793004 0.935920797 0.935920797 0.935920797
17 REC 360 0.511215812 0.543 0.643093346 0.953365292 0.953365292 0.953365292
18 REC 390 0.462685643 0.49701732 0.596303042 0.966390784 0.966390784 0.966390784
19 REC 420 0.41046875 0.44828125 0.5496875 0.977 0.977 0.977
20 REC 450 0.3518815 0.3938775 0.497998 0.984724 0.984724 0.984724
21 REC 480 0.2965625 0.341328125 0.44078125 0.99 0.99 0.99
22 REC 510 0.2393955 0.2762305 0.3738025 0.995611 0.995611 0.995611
23 REC 540 0.185546875 0.216328125 0.306328125 1 1 1
24 REC 570 0.124343 0.144113 0.224113 1 1 1
25 REC 600 0.08 0.08 0.145 1 1 1

25
dnp_data/LUTData_0010.csv Normal file
View file

@ -0,0 +1,25 @@
#FORMAT ,Major,Minor,,,,,
FORMAT,1,0,,,,,
RECNUM,64,,,,,,
#Header,,(Rh)Y, (Rh)M, (Rh)C, (Lh)Y, (Lh)M, (Lh)C
REC,0,1,1,1,0.2,0.2,0.2
REC,30,0.993358,0.996306,0.994611,0.295065,0.295065,0.295065
REC,60,0.98,0.985,0.985,0.39,0.39,0.39
REC,90,0.95402,0.960254,0.967721,0.487998,0.487998,0.487998
REC,120,0.91828125,0.92828125,0.94609375,0.58,0.58,0.58
REC,150,0.87309,0.892084,0.920627,0.66837,0.66837,0.66837
REC,180,0.82765625,0.854375,0.89109375,0.74,0.74,0.74
REC,210,0.78004,0.803,0.855,0.800444,0.800444,0.800444
REC,240,0.73484375,0.755,0.816,0.845,0.845,0.845
REC,270,0.675,0.702,0.778518,0.885564,0.885564,0.885564
REC,300,0.612,0.645,0.7321875,0.915,0.915,0.915
REC,330,0.561742216,0.595,0.68793004,0.935920797,0.935920797,0.935920797
REC,360,0.511215812,0.543,0.643093346,0.953365292,0.953365292,0.953365292
REC,390,0.462685643,0.49701732,0.596303042,0.966390784,0.966390784,0.966390784
REC,420,0.41046875,0.44828125,0.5496875,0.977,0.977,0.977
REC,450,0.3518815,0.3938775,0.497998,0.984724,0.984724,0.984724
REC,480,0.2965625,0.341328125,0.44078125,0.99,0.99,0.99
REC,510,0.2393955,0.2762305,0.3738025,0.995611,0.995611,0.995611
REC,540,0.185546875,0.216328125,0.306328125,1,1,1
REC,570,0.124343,0.144113,0.224113,1,1,1
REC,600,0.08,0.08,0.145,1,1,1
1 #FORMAT Major Minor
2 FORMAT 1 0
3 RECNUM 64
4 #Header (Rh)Y (Rh)M (Rh)C (Lh)Y (Lh)M (Lh)C
5 REC 0 1 1 1 0.2 0.2 0.2
6 REC 30 0.993358 0.996306 0.994611 0.295065 0.295065 0.295065
7 REC 60 0.98 0.985 0.985 0.39 0.39 0.39
8 REC 90 0.95402 0.960254 0.967721 0.487998 0.487998 0.487998
9 REC 120 0.91828125 0.92828125 0.94609375 0.58 0.58 0.58
10 REC 150 0.87309 0.892084 0.920627 0.66837 0.66837 0.66837
11 REC 180 0.82765625 0.854375 0.89109375 0.74 0.74 0.74
12 REC 210 0.78004 0.803 0.855 0.800444 0.800444 0.800444
13 REC 240 0.73484375 0.755 0.816 0.845 0.845 0.845
14 REC 270 0.675 0.702 0.778518 0.885564 0.885564 0.885564
15 REC 300 0.612 0.645 0.7321875 0.915 0.915 0.915
16 REC 330 0.561742216 0.595 0.68793004 0.935920797 0.935920797 0.935920797
17 REC 360 0.511215812 0.543 0.643093346 0.953365292 0.953365292 0.953365292
18 REC 390 0.462685643 0.49701732 0.596303042 0.966390784 0.966390784 0.966390784
19 REC 420 0.41046875 0.44828125 0.5496875 0.977 0.977 0.977
20 REC 450 0.3518815 0.3938775 0.497998 0.984724 0.984724 0.984724
21 REC 480 0.2965625 0.341328125 0.44078125 0.99 0.99 0.99
22 REC 510 0.2393955 0.2762305 0.3738025 0.995611 0.995611 0.995611
23 REC 540 0.185546875 0.216328125 0.306328125 1 1 1
24 REC 570 0.124343 0.144113 0.224113 1 1 1
25 REC 600 0.08 0.08 0.145 1 1 1

View file

@ -23,7 +23,8 @@ fi
# D90
case "${model}" in
kodak-6900|kodak-6950)
overlap=636 # 100 + 36
pad=36
overlap=600
if [ "${printsize}" eq "6x20" ] ; then
cols=1844
inrows=6036
@ -59,6 +60,7 @@ case "${model}" in
;;
kodak-8810)
cols=2464
pad=24
overlap=360 ### XXX probably wrong?
if [ "${printsize}" eq "8x14" ] ; then
inrows=4224
@ -85,8 +87,9 @@ case "${model}" in
;;
mitsubishi-d90dw)
cols=1852
pad=28
drows=2428
overlap=628 # 600 + 28
overlap=600
if [ "${printsize}" eq "6x20" ] ; then
inrows=6028
elif [ "${printsize}" eq "6x14" ] ; then
@ -99,11 +102,12 @@ case "${model}" in
dnp-ds620)
cols=1844
drows=2436
pad=36
overlap=600
if [ "${printsize}" eq "6x20" ] ; then
inrows=6108
inrows=6036
elif [ "${printsize}" eq "6x14" ] ; then
inrows=4272
inrows=4236
else
echo "DS620 supportx 6x20 and 6x14 only"
exit 1
@ -111,21 +115,28 @@ case "${model}" in
;;
dnp-ds820)
overlap=600
pad=36
cols=2448
if [ "${printsize}" eq "8x18" ] ; then
drows=3036
inrows=5472
inrows=5436
elif [ "${printsize}" eq "8x26" ] ; then
drows=3036
inrows=7908
inrows=7836
elif [ "${printsize}" eq "8x22" ] ; then
drows=3636
inrows=6672
inrows=6636
elif [ "${printsize}" eq "8x32" ] ; then
drows=3636
inrows=9708
inrows=9636
elif [ "${printsize}" eq "A4x2" ] ; then
drows=3544
inrows=6452
elif [ "${printsize}" eq "A4x3" ] ; then
drows=3544
inrows=9360
else
echo "DS820 supportx 8x18, 8x26, 8x22, and 8x32 only"
echo "DS820 supportx 8x18, 8x26, 8x22, 8x32, A4x21, A4x31 only"
fi
;;
*)
@ -135,11 +146,12 @@ case "${model}" in
esac
# For 600dpi, double everything!
if [ ${dpi} == 600 ] ; then
if [ ${dpi} -gt 300 ] ; then
overlap=`expr ${overlap} * 2`
cols=`expr ${cols} * 2`
drows=`expr ${drows} * 2`
inrows=`expr ${inrows} * 2`
pad=`expr ${pad} * 2`
fi
# Calculate page count XXX is this sane?
@ -153,8 +165,11 @@ fadeoutname=fade_out_${cols}.pgm
gm convert -size ${cols}x${overlap} gradient:white-black ${fadeinname}
gm convert -size ${cols}x${overlap} gradient:black-white ${fadeoutname}
# Subtract off padding from rows.
drows=`expr ${drows} - ${pad} - ${pad}`
# Generate panels
src_offset=0
src_offset=`expr $pad / 2`
panels=''
for panel in `seq 1 ${pages}` ; do
echo "generating $panel / $pages"
@ -163,34 +178,26 @@ for panel in `seq 1 ${pages}` ; do
panels="${panels} ${panelname}"
# Generate panel
gm convert ${infile} -crop ${cols}x${drows}+0+${src_offset} ${panelname}
rows=`expr ${drows} + ${pad} + ${pad}`
gm convert ${infile} -crop ${cols}x${rows}+0+${src_offset} ${panelname}
## XXX panel needs to have WHITE margin of ${pad rows} on either end
# perhaps add to fades?
# need a tail too.
# Increment offset
src_offset=`expr ${src_offset} + ${drows}`;
src_offset=`expr ${src_offset} - ${overlap}`;
# First page fades out only
if [ ${panel} == 1 ] ; then
# All but last panel fades out
if [ ${panel} -lt ${pages} ] ; then
gm composite -compose screen -gravity south ${fadeoutname} ${panelname} ${panelname}
fi
# Middle pages fade in and out
# All but first panel fades in
if [ ${panel} -gt 1 ] ; then
if [ ${panel} -lt ${pages} ] ; then
gm composite -compose screen -gravity south ${fadeoutname} ${panelname} ${panelname}
fi
fi
if [ ${panel} -gt 1 ] ; then
if [ ${panel} -lt ${pages} ] ; then
gm composite -compose screen -gravity north ${fadeinname} ${panelname} ${panelname}
fi
fi
# Last page fades in only
if [ ${panel} == ${pages} ] ; then
gm composite -compose screen -gravity north ${fadeinname} ${panelname} ${panelname}
fi
done
# Clean up templates