mitsud90: Theoretically we support continuous panoramas now
This required substantial rework of the "common" rgb8 pano split code to add blending support (modeled after the DNP stuff) along with MANY bugfixes. The Sinfonia pano code (used by the EK8810 and EK69xx) also needed to be tweaked, but that isn't expected to work on real printers yet due to unknown control protocol bits.
This commit is contained in:
parent
e4b678ea08
commit
03ca5ce596
102
backend_common.c
102
backend_common.c
|
@ -29,7 +29,7 @@
|
|||
#include <signal.h>
|
||||
#include <strings.h> /* For strncasecmp */
|
||||
|
||||
#define BACKEND_VERSION "0.127"
|
||||
#define BACKEND_VERSION "0.128"
|
||||
|
||||
#ifndef CORRTABLE_PATH
|
||||
#ifdef PACKAGE_DATA_DIR
|
||||
|
@ -1958,31 +1958,91 @@ const void *dyesub_joblist_popjob(struct dyesub_joblist *list)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
int dyesub_pano_split_rgb8(const uint8_t *src, uint16_t cols,
|
||||
uint16_t src_rows, uint8_t numpanels,
|
||||
uint16_t overlap_rows, uint16_t max_rows,
|
||||
uint8_t *panels[3],
|
||||
uint16_t panel_rows[3])
|
||||
#include "backend_panodata.h"
|
||||
#define PROCESS_PIXEL(__corr, __offset) \
|
||||
data[(r * cols * 3) + c + __offset] = 255 - ((255 - (double)data[(r * cols *3) + c +__offset]) * (__corr))
|
||||
|
||||
static void dyesub_pano_process_rgb8(const struct dnp_panodata *pano,
|
||||
uint8_t *data, int lh, int rh,
|
||||
uint16_t cols, uint16_t rows,
|
||||
uint16_t overlap, uint16_t pad_rows)
|
||||
{
|
||||
/* Do nothing if there's no point */
|
||||
if (numpanels < 2 || src_rows <= max_rows)
|
||||
return CUPS_BACKEND_OK;
|
||||
/* Skip over start margin in source */
|
||||
data += pad_rows * cols * 3;
|
||||
|
||||
/* Work out panel sizes if not specified */
|
||||
if (panel_rows[0] == 0) {
|
||||
panel_rows[0] = max_rows;
|
||||
panel_rows[1] = src_rows - panel_rows[0] + overlap_rows;
|
||||
if (numpanels > 2)
|
||||
panel_rows[2] = src_rows - panel_rows[0] - panel_rows[1] + overlap_rows*2;
|
||||
for (int r = 0 ; r < rows ; r++) {
|
||||
if (rh && r < overlap) {
|
||||
const struct panodata_row *rhc;
|
||||
int i, c;
|
||||
int row = (overlap - r);
|
||||
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];
|
||||
for (c = 0 ; c < cols ; c++) {
|
||||
PROCESS_PIXEL(rhc->rhYMC[2],0); /* R/C */
|
||||
PROCESS_PIXEL(rhc->rhYMC[1],1); /* G/M */
|
||||
PROCESS_PIXEL(rhc->rhYMC[0],2); /* B/Y */
|
||||
}
|
||||
} else if (lh && (rows - r) < overlap) {
|
||||
const struct panodata_row *lhc;
|
||||
int i, c;
|
||||
int row = (rows -r);
|
||||
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];
|
||||
for (c = 0 ; c < cols ; c++) {
|
||||
PROCESS_PIXEL(lhc->rhYMC[2],0); /* R/C */
|
||||
PROCESS_PIXEL(lhc->rhYMC[1],1); /* G/M */
|
||||
PROCESS_PIXEL(lhc->rhYMC[0],2); /* B/Y */
|
||||
}
|
||||
}
|
||||
|
||||
/* Next row */
|
||||
data += cols * 3;
|
||||
}
|
||||
}
|
||||
|
||||
/* Copy panel data */
|
||||
memcpy(panels[0], src, cols * panel_rows[0] * 3);
|
||||
memcpy(panels[1], src + ((panel_rows[0] - overlap_rows) * cols) * 3, cols * panel_rows[1] * 3);
|
||||
if (numpanels > 2)
|
||||
memcpy(panels[2], src + ((panel_rows[0] - overlap_rows + panel_rows[1] - overlap_rows) * cols) * 3, cols * panel_rows[2] * 3);
|
||||
void dyesub_pano_split_rgb8(const uint8_t *src, uint16_t cols, uint8_t numpanels,
|
||||
uint16_t overlap_rows, uint16_t pad_rows,
|
||||
uint16_t *panel_rows, uint8_t **panels)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
return CUPS_BACKEND_OK;
|
||||
INFO("Splitting job into %d panel continuous panorama\n", numpanels);
|
||||
|
||||
/* Skip over start margin in source */
|
||||
src += pad_rows * cols * 3;
|
||||
|
||||
for (i = 0 ; i < numpanels ; i++) {
|
||||
int lh = (i < (numpanels -1));
|
||||
int rh = (i > 0);
|
||||
uint8_t *out = panels[i];
|
||||
|
||||
/* Fill start margin with white */
|
||||
if (pad_rows) {
|
||||
memset(out, 0xff, pad_rows * cols * 3);
|
||||
out += pad_rows * cols * 3;
|
||||
}
|
||||
|
||||
/* Copy over panel data */
|
||||
memcpy(out, src, panel_rows[i] * cols * 3);
|
||||
src += (panel_rows[i] - overlap_rows) * cols * 3; /* Factor in overlap */
|
||||
out += panel_rows[i] * cols * 3;
|
||||
|
||||
/* Fill end margin with white */
|
||||
if (pad_rows) {
|
||||
memset(out, 0xff, pad_rows * cols * 3);
|
||||
out += pad_rows * cols * 3;
|
||||
}
|
||||
|
||||
dyesub_pano_process_rgb8(&panodata, panels[i], lh, rh,
|
||||
cols, panel_rows[i] - overlap_rows * 2,
|
||||
overlap_rows, pad_rows);
|
||||
}
|
||||
}
|
||||
|
||||
int dyesub_joblist_canwait(struct dyesub_joblist *list)
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* CUPS Backend common code
|
||||
*
|
||||
* (c) 2013-2023 Solomon Peachy <pizza@shaftnet.org>
|
||||
* (c) 2013-2024 Solomon Peachy <pizza@shaftnet.org>
|
||||
*
|
||||
* The latest version of this program can be found at:
|
||||
*
|
||||
|
@ -246,6 +246,19 @@ struct dyesub_job_common {
|
|||
int can_combine;
|
||||
};
|
||||
|
||||
/* Panorama stuff */
|
||||
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];
|
||||
};
|
||||
|
||||
/* Exported functions */
|
||||
int send_data(struct dyesub_connection *conn, const uint8_t *buf, int len);
|
||||
int read_data(struct dyesub_connection *conn,
|
||||
|
@ -283,11 +296,9 @@ int dyesub_joblist_canwait(struct dyesub_joblist *list);
|
|||
#define BACKEND_FLAG_BADISERIAL 0x00000001
|
||||
#define BACKEND_FLAG_DUMMYPRINT 0x00000002
|
||||
|
||||
int dyesub_pano_split_rgb8(const uint8_t *src, uint16_t cols,
|
||||
uint16_t src_rows, uint8_t numpanels,
|
||||
uint16_t overlap_rows, uint16_t max_rows,
|
||||
uint8_t *panels[3],
|
||||
uint16_t panel_rows[3]);
|
||||
void dyesub_pano_split_rgb8(const uint8_t *src, uint16_t cols, uint8_t numpanels,
|
||||
uint16_t overlap_rows, uint16_t pad_rows,
|
||||
uint16_t *panel_rows, uint8_t **panels);
|
||||
|
||||
/* Backend Functions */
|
||||
struct dyesub_backend {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* Citizen / DNP Photo Printer CUPS backend
|
||||
*
|
||||
* (c) 2013-2023 Solomon Peachy <pizza@shaftnet.org>
|
||||
* (c) 2013-2024 Solomon Peachy <pizza@shaftnet.org>
|
||||
*
|
||||
* Development of this backend was sponsored by:
|
||||
*
|
||||
|
@ -272,18 +272,6 @@ 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"
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* Mitsubishi CP-D90DW Photo Printer CUPS backend
|
||||
*
|
||||
* (c) 2019-2023 Solomon Peachy <pizza@shaftnet.org>
|
||||
* (c) 2019-2024 Solomon Peachy <pizza@shaftnet.org>
|
||||
*
|
||||
* The latest version of this program can be found at:
|
||||
*
|
||||
|
@ -924,11 +924,12 @@ static int mitsud90_panorama_splitjob(struct mitsud90_printjob *injob, struct mi
|
|||
{
|
||||
uint8_t *panels[3] = { NULL, NULL, NULL };
|
||||
uint16_t panel_rows[3] = { 0, 0, 0 };
|
||||
uint16_t overlap_rows;
|
||||
uint16_t overlap_rows = 600;
|
||||
uint16_t pad_rows = 14;
|
||||
uint8_t numpanels;
|
||||
uint16_t cols;
|
||||
uint16_t inrows;
|
||||
uint16_t max_rows;
|
||||
uint16_t max_rows = 2428; /* 6x8" only */
|
||||
int i;
|
||||
|
||||
cols = be16_to_cpu(injob->hdr.cols);
|
||||
|
@ -937,23 +938,21 @@ static int mitsud90_panorama_splitjob(struct mitsud90_printjob *injob, struct mi
|
|||
/* Work out parameters */
|
||||
if (inrows == 6028) {
|
||||
numpanels = 3;
|
||||
overlap_rows = 600 + 28;
|
||||
max_rows = 2428;
|
||||
} else if (inrows == 4228) {
|
||||
numpanels = 2;
|
||||
max_rows = 2428;
|
||||
overlap_rows = 600 + 28;
|
||||
} else {
|
||||
ERROR("Invalid panorama row count (%d)\n", inrows);
|
||||
return CUPS_BACKEND_CANCEL;
|
||||
}
|
||||
|
||||
/* Work out which number of rows per panel */
|
||||
if (!panel_rows[0]) {
|
||||
panel_rows[0] = max_rows;
|
||||
panel_rows[1] = inrows - panel_rows[0] + overlap_rows;
|
||||
if (numpanels > 2)
|
||||
panel_rows[2] = inrows - panel_rows[0] - panel_rows[1] + overlap_rows + overlap_rows;
|
||||
/* Work out panel sizes... */
|
||||
for (int src_rows = inrows - 2 * pad_rows, i = 0 ; src_rows > 0; ) {
|
||||
panel_rows[i] = (src_rows < max_rows) ? src_rows : max_rows - 2*pad_rows;
|
||||
src_rows -= panel_rows[i];
|
||||
i++;
|
||||
|
||||
if (i < numpanels)
|
||||
src_rows += overlap_rows;
|
||||
}
|
||||
|
||||
/* Allocate and set up new jobs and buffers */
|
||||
|
@ -963,7 +962,8 @@ static int mitsud90_panorama_splitjob(struct mitsud90_printjob *injob, struct mi
|
|||
ERROR("Memory allocation failure");
|
||||
return CUPS_BACKEND_RETRY_CURRENT;
|
||||
}
|
||||
panels[i] = malloc(cols * panel_rows[i] * 3) + sizeof(struct mitsud90_plane_hdr);
|
||||
panel_rows[i] += 2 * pad_rows;
|
||||
panels[i] = malloc((cols * panel_rows[i] * 3) + sizeof(struct mitsud90_plane_hdr));
|
||||
if (!panels[i]) {
|
||||
ERROR("Memory allocation failure");
|
||||
return CUPS_BACKEND_RETRY_CURRENT;
|
||||
|
@ -981,6 +981,7 @@ static int mitsud90_panorama_splitjob(struct mitsud90_printjob *injob, struct mi
|
|||
newjobs[i]->hdr.pano.unk[1] = 0x0c;
|
||||
newjobs[i]->hdr.pano.unk[3] = 0x06;
|
||||
newjobs[i]->has_footer = 0;
|
||||
panel_rows[i] -= 2 * pad_rows;
|
||||
|
||||
/* Fill in plane header differences */
|
||||
memcpy(newjobs[i]->databuf, injob->databuf, sizeof(struct mitsud90_plane_hdr));
|
||||
|
@ -993,14 +994,11 @@ static int mitsud90_panorama_splitjob(struct mitsud90_printjob *injob, struct mi
|
|||
/* Last panel gets the footer, if any */
|
||||
newjobs[numpanels - 1]->has_footer = injob->has_footer;
|
||||
|
||||
dyesub_pano_split_rgb8(injob->databuf, cols, inrows,
|
||||
numpanels, overlap_rows, max_rows,
|
||||
panels, panel_rows);
|
||||
dyesub_pano_split_rgb8(injob->databuf, cols, numpanels,
|
||||
overlap_rows, pad_rows,
|
||||
panel_rows, panels);
|
||||
|
||||
// XXX process buffers!
|
||||
// pano_process_rgb8(numpanels, cols, overlap_rows, panels, panel_rows);
|
||||
|
||||
return CUPS_BACKEND_OK;
|
||||
return CUPS_BACKEND_OK;
|
||||
}
|
||||
|
||||
static int mitsud90_read_parse(void *vctx, const void **vjob, int data_fd, int copies) {
|
||||
|
@ -1068,8 +1066,12 @@ static int mitsud90_read_parse(void *vctx, const void **vjob, int data_fd, int c
|
|||
if (job->hdr.zero_b[3] && job->hdr.pano.on == 0x03) {
|
||||
job->is_pano = 1;
|
||||
job->hdr.zero_b[3] = 0;
|
||||
job->hdr.pano.on = 0x01;
|
||||
job->hdr.pano.on = 0; /* Will get inserted later */
|
||||
} else if (be16_to_cpu(job->hdr.rows > 2729)) {
|
||||
job->is_pano = 1;
|
||||
job->hdr.pano.on = 0;
|
||||
}
|
||||
|
||||
} else if (ctx->conn->type == P_MITSU_W5000) {
|
||||
struct mitsuw5k_job_hdr *hdr = (struct mitsuw5k_job_hdr*) &job->hdr;
|
||||
|
||||
|
@ -1099,7 +1101,7 @@ static int mitsud90_read_parse(void *vctx, const void **vjob, int data_fd, int c
|
|||
be16_to_cpu(job->hdr.pano.rows2 != (2428-0x30)) ||
|
||||
be16_to_cpu(job->hdr.pano.overlap != 600)
|
||||
) {
|
||||
ERROR("Invalid panorama parameters");
|
||||
ERROR("Invalid panorama job parameters\n");
|
||||
mitsud90_cleanup_job(job);
|
||||
return CUPS_BACKEND_CANCEL;
|
||||
}
|
||||
|
@ -1266,8 +1268,6 @@ read_data:
|
|||
/* Clean up original parsed job regardless */
|
||||
mitsud90_cleanup_job(job);
|
||||
|
||||
// XXX process panels!
|
||||
|
||||
return rval;
|
||||
} else {
|
||||
*vjob = job;
|
||||
|
@ -2424,7 +2424,7 @@ static const char *mitsud90_prefixes[] = {
|
|||
/* Exported */
|
||||
const struct dyesub_backend mitsud90_backend = {
|
||||
.name = "Mitsubishi CP-D90/CP-M1/CP-W5000",
|
||||
.version = "0.46" " (lib " LIBMITSU_VER ")",
|
||||
.version = "0.47" " (lib " LIBMITSU_VER ")",
|
||||
.uri_prefixes = mitsud90_prefixes,
|
||||
.cmdline_arg = mitsud90_cmdline_arg,
|
||||
.cmdline_usage = mitsud90_cmdline,
|
||||
|
|
|
@ -212,6 +212,7 @@ int sinfonia_panorama_splitjob(struct sinfonia_printjob *injob,
|
|||
uint16_t panel_rows[3] = { 0, 0, 0 };
|
||||
uint8_t numpanels;
|
||||
uint16_t overlap_rows;
|
||||
uint16_t pad_rows;
|
||||
uint16_t inrows;
|
||||
uint16_t cols;
|
||||
|
||||
|
@ -231,13 +232,14 @@ int sinfonia_panorama_splitjob(struct sinfonia_printjob *injob,
|
|||
else
|
||||
numpanels = 2;
|
||||
|
||||
overlap_rows = 600 + 36;
|
||||
pad_rows = 18;
|
||||
overlap_rows = 600;
|
||||
|
||||
if (numpanels == 3) {
|
||||
if (inrows > 4536) // 5x15
|
||||
overlap_rows = 100 + 36;
|
||||
overlap_rows = 100;
|
||||
else
|
||||
overlap_rows = 600 + 36;
|
||||
overlap_rows = 600;
|
||||
}
|
||||
break;
|
||||
case 1844: /* EK6900/6950 */
|
||||
|
@ -246,7 +248,8 @@ int sinfonia_panorama_splitjob(struct sinfonia_printjob *injob,
|
|||
return CUPS_BACKEND_CANCEL;
|
||||
}
|
||||
|
||||
overlap_rows = 600 + 36;
|
||||
pad_rows = 18;
|
||||
overlap_rows = 600;
|
||||
|
||||
if (inrows > 4236) // ie 6x14
|
||||
numpanels = 3;
|
||||
|
@ -259,7 +262,8 @@ int sinfonia_panorama_splitjob(struct sinfonia_printjob *injob,
|
|||
ERROR("Bad pano input\n");
|
||||
return CUPS_BACKEND_CANCEL;
|
||||
}
|
||||
overlap_rows = 600 + 24;
|
||||
pad_rows = 12;
|
||||
overlap_rows = 600;
|
||||
|
||||
if (max_rows == 3024) { /* 8x10 media */
|
||||
if (inrows > 5424) // 8x18
|
||||
|
@ -276,18 +280,18 @@ int sinfonia_panorama_splitjob(struct sinfonia_printjob *injob,
|
|||
if (numpanels == 3) {
|
||||
if (max_rows == 3024) {
|
||||
if (inrows == 6024) // 8x20
|
||||
overlap_rows = 24;
|
||||
overlap_rows = 0;
|
||||
} else {
|
||||
if (inrows == 10824) // 8x36
|
||||
overlap_rows = 24;
|
||||
overlap_rows = 0;
|
||||
}
|
||||
} else {
|
||||
if (max_rows == 3024) {
|
||||
if (inrows == 9024) // 8x30
|
||||
overlap_rows = 24;
|
||||
overlap_rows = 0;
|
||||
} else {
|
||||
if (inrows == 7224) // 8x24
|
||||
overlap_rows = 24;
|
||||
overlap_rows = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -297,12 +301,14 @@ int sinfonia_panorama_splitjob(struct sinfonia_printjob *injob,
|
|||
return CUPS_BACKEND_CANCEL;
|
||||
}
|
||||
|
||||
/* Work out which number of rows per panel */
|
||||
if (!panel_rows[0]) {
|
||||
panel_rows[0] = max_rows;
|
||||
panel_rows[1] = inrows - panel_rows[0] + overlap_rows;
|
||||
if (numpanels > 2)
|
||||
panel_rows[2] = inrows - panel_rows[0] - panel_rows[1] + overlap_rows + overlap_rows;
|
||||
/* Work out panel sizes... */
|
||||
for (int src_rows = inrows - 2 * pad_rows, i = 0 ; src_rows > 0; ) {
|
||||
panel_rows[i] = (src_rows < max_rows) ? src_rows : max_rows - 2*pad_rows;
|
||||
src_rows -= panel_rows[i];
|
||||
i++;
|
||||
|
||||
if (i < numpanels)
|
||||
src_rows += overlap_rows;
|
||||
}
|
||||
|
||||
/* Allocate and set up new jobs and buffers */
|
||||
|
@ -312,6 +318,7 @@ int sinfonia_panorama_splitjob(struct sinfonia_printjob *injob,
|
|||
ERROR("Memory allocation failure");
|
||||
return CUPS_BACKEND_RETRY_CURRENT;
|
||||
}
|
||||
panel_rows[i] += 2 * pad_rows;
|
||||
panels[i] = malloc(cols * panel_rows[i] * 3);
|
||||
if (!panels[i]) {
|
||||
ERROR("Memory allocation failure");
|
||||
|
@ -322,15 +329,13 @@ int sinfonia_panorama_splitjob(struct sinfonia_printjob *injob,
|
|||
newjobs[i]->databuf = panels[i];
|
||||
newjobs[i]->jp.rows = panel_rows[i];
|
||||
// XXX what else?
|
||||
// fill in contents here instead?
|
||||
|
||||
panel_rows[i] -= 2 * pad_rows;
|
||||
}
|
||||
|
||||
dyesub_pano_split_rgb8(injob->databuf, cols, inrows,
|
||||
numpanels, overlap_rows, max_rows,
|
||||
panels, panel_rows);
|
||||
|
||||
// XXX postprocess buffers!
|
||||
// pano_process_rgb8(numpanels, cols, overlap_rows, panels, panel_rows);
|
||||
dyesub_pano_split_rgb8(injob->databuf, cols, numpanels,
|
||||
overlap_rows, pad_rows,
|
||||
panel_rows, panels);
|
||||
|
||||
return CUPS_BACKEND_OK;
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#define LIBSINFONIA_VER "0.19.1"
|
||||
#define LIBSINFONIA_VER "0.20"
|
||||
|
||||
#define SINFONIA_HDR1_LEN 0x10
|
||||
#define SINFONIA_HDR2_LEN 0x64
|
||||
|
|
|
@ -129,14 +129,8 @@ case "${model}" in
|
|||
elif [ "${printsize}" eq "8x32" ] ; then
|
||||
drows=3636
|
||||
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, 8x32, A4x21, A4x31 only"
|
||||
echo "DS820 supportx 8x18, 8x26, 8x22, and 8x32 only"
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
|
|
Loading…
Reference in a new issue