Compare commits

...

2 commits

Author SHA1 Message Date
Solomon Peachy 81193f9675 mitsu70x: Move full image procesisng pipeline into read_parse
No need to call main_loop to validate the full flow
2024-01-11 21:34:55 -05:00
Solomon Peachy 69344f821a mitsud90: Move all image processing to before pano splitting
...and out of the main_loop() which now only does some final sanity
checks and sets up the job
2024-01-11 21:30:35 -05:00
2 changed files with 222 additions and 230 deletions

View file

@ -1,7 +1,7 @@
/*
* Mitsubishi CP-D70/D707 Photo Printer CUPS backend
*
* (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:
*
@ -1108,55 +1108,53 @@ repeat:
job->datalen += i;
remain -= i;
}
goto bypass_raw;
}
} else { /* Non-RAW mode! */
remain = job->rows * job->cols * 3;
DEBUG("Reading in %d bytes of 8bpp BGR data\n", remain);
/* Non-RAW mode! */
remain = job->rows * job->cols * 3;
DEBUG("Reading in %d bytes of 8bpp BGR data\n", remain);
job->spoolbuflen = 0;
job->spoolbuf = malloc(remain);
if (!job->spoolbuf) {
ERROR("Memory allocation failure!\n");
mitsu70x_cleanup_job(job);
return CUPS_BACKEND_RETRY_CURRENT;
}
job->spoolbuflen = 0;
job->spoolbuf = malloc(remain);
if (!job->spoolbuf) {
ERROR("Memory allocation failure!\n");
mitsu70x_cleanup_job(job);
return CUPS_BACKEND_RETRY_CURRENT;
}
/* Read in the BGR data */
while (remain) {
i = read(data_fd, job->spoolbuf + job->spoolbuflen, remain);
if (i == 0) {
mitsu70x_cleanup_job(job);
return CUPS_BACKEND_CANCEL;
}
if (i < 0) {
mitsu70x_cleanup_job(job);
return CUPS_BACKEND_CANCEL;
}
job->spoolbuflen += i;
remain -= i;
}
/* Read in the BGR data */
while (remain) {
i = read(data_fd, job->spoolbuf + job->spoolbuflen, remain);
if (i == 0) {
if (!ctx->lib.dl_handle) {
ERROR("!!! Image Processing Library not found, aborting!\n");
mitsu70x_cleanup_job(job);
return CUPS_BACKEND_CANCEL;
}
if (i < 0) {
mitsu70x_cleanup_job(job);
return CUPS_BACKEND_CANCEL;
}
job->spoolbuflen += i;
remain -= i;
}
if (!ctx->lib.dl_handle) {
ERROR("!!! Image Processing Library not found, aborting!\n");
mitsu70x_cleanup_job(job);
return CUPS_BACKEND_CANCEL;
}
/* Run through basic LUT, if present and enabled */
if (job->lutfname) {
int ret = mitsu_apply3dlut_packed(&ctx->lib, job->lutfname,
job->spoolbuf, job->cols,
job->rows, job->cols * 3,
COLORCONV_BGR);
if (ret) {
mitsu70x_cleanup_job(job);
return ret;
/* Run through basic LUT, if present and enabled */
if (job->lutfname) {
int ret = mitsu_apply3dlut_packed(&ctx->lib, job->lutfname,
job->spoolbuf, job->cols,
job->rows, job->cols * 3,
COLORCONV_BGR);
if (ret) {
mitsu70x_cleanup_job(job);
return ret;
}
}
}
bypass_raw:
/* Validate size and deck placement */
for (i = 0 ; i < ctx->num_decks ; i++) {
switch (ctx->medias[i]) {
case 0x0: // 4x8 (DS480 only)
@ -1241,6 +1239,101 @@ bypass_raw:
}
}
/* Process RGB data if needed */
if (!job->raw_format) {
struct BandImage input;
uint8_t rew[2] = { 1, 1 }; /* 1 for rewind ok (default!) */
/* Load in the CPC file, if needed */
if (job->cpcfname && job->cpcfname != ctx->last_cpcfname) {
char full[2048];
ctx->last_cpcfname = job->cpcfname;
if (ctx->lib.cpcdata)
ctx->lib.DestroyCPCData(ctx->lib.cpcdata);
snprintf(full, sizeof(full), "%s/%s", corrtable_path, job->cpcfname);
ctx->lib.cpcdata = ctx->lib.GetCPCData(full);
if (!ctx->lib.cpcdata) {
ERROR("Unable to load CPC file '%s'\n", full);
mitsu70x_cleanup_job(job);
return CUPS_BACKEND_CANCEL;
}
}
/* Load in the secondary CPC, if needed */
if (job->ecpcfname != ctx->last_ecpcfname) {
char full[2048];
ctx->last_ecpcfname = job->ecpcfname;
if (ctx->lib.ecpcdata)
ctx->lib.DestroyCPCData(ctx->lib.ecpcdata);
snprintf(full, sizeof(full), "%s/%s", corrtable_path, job->ecpcfname);
if (job->ecpcfname) {
ctx->lib.ecpcdata = ctx->lib.GetCPCData(full);
if (!ctx->lib.ecpcdata) {
ERROR("Unable to load CPC file '%s'\n", full);
mitsu70x_cleanup_job(job);
return CUPS_BACKEND_CANCEL;
}
} else {
ctx->lib.ecpcdata = NULL;
}
}
/* Convert using image processing library */
input.origin_rows = input.origin_cols = 0;
input.rows = job->rows;
input.cols = job->cols;
input.imgbuf = job->spoolbuf;
input.bytes_per_row = job->cols * 3;
ctx->output.origin_rows = ctx->output.origin_cols = 0;
ctx->output.rows = job->rows;
ctx->output.cols = job->cols;
ctx->output.imgbuf = job->databuf + job->datalen;
ctx->output.bytes_per_row = job->cols * 3 * 2;
DEBUG("Running print data through processing library\n");
if (ctx->lib.DoImageEffect(ctx->lib.cpcdata, ctx->lib.ecpcdata,
&input, &ctx->output, job->sharpen, job->reverse, rew)) {
ERROR("Image Processing failed, aborting!\n");
mitsu70x_cleanup_job(job);
return CUPS_BACKEND_CANCEL;
}
/* Twiddle rewind stuff if needed */
if (ctx->conn->type != P_MITSU_D70X) {
mhdr.rewind[0] = !rew[0];
mhdr.rewind[1] = !rew[1];
DEBUG("Rewind Inhibit? %02x %02x\n", mhdr.rewind[0], mhdr.rewind[1]);
}
/* Move up the pointer to after the image data */
job->datalen += 3*job->planelen;
/* Clean up */
free(job->spoolbuf);
job->spoolbuf = NULL;
job->spoolbuflen = 0;
/* Now that we've filled everything in, read matte from file */
if (job->matte) {
int ret = mitsu_readlamdata(job->laminatefname, LAMINATE_STRIDE,
job->databuf, &job->datalen,
be16_to_cpu(mhdr.lamrows), be16_to_cpu(mhdr.lamcols), 2);
if (ret) {
mitsu70x_cleanup_job(job);
return ret;
}
/* Zero out the tail end of the buffer. */
ret = be16_to_cpu(mhdr.lamcols) * be16_to_cpu(mhdr.lamrows) * 2;
memset(job->databuf + job->datalen, 0, job->matte - ret);
}
}
/* Return what we found */
*vjob = job;
@ -1781,101 +1874,6 @@ static int mitsu70x_main_loop(void *vctx, const void *vjob, int wait_for_return)
/* Keep track of deck requested */
reqdeck = hdr->deck;
if (job->raw_format)
goto bypass;
struct BandImage input;
uint8_t rew[2] = { 1, 1 }; /* 1 for rewind ok (default!) */
/* Load in the CPC file, if needed */
if (job->cpcfname && job->cpcfname != ctx->last_cpcfname) {
char full[2048];
ctx->last_cpcfname = job->cpcfname;
if (ctx->lib.cpcdata)
ctx->lib.DestroyCPCData(ctx->lib.cpcdata);
snprintf(full, sizeof(full), "%s/%s", corrtable_path, job->cpcfname);
ctx->lib.cpcdata = ctx->lib.GetCPCData(full);
if (!ctx->lib.cpcdata) {
ERROR("Unable to load CPC file '%s'\n", full);
return CUPS_BACKEND_CANCEL;
}
}
/* Load in the secondary CPC, if needed */
if (job->ecpcfname != ctx->last_ecpcfname) {
char full[2048];
ctx->last_ecpcfname = job->ecpcfname;
if (ctx->lib.ecpcdata)
ctx->lib.DestroyCPCData(ctx->lib.ecpcdata);
snprintf(full, sizeof(full), "%s/%s", corrtable_path, job->ecpcfname);
if (job->ecpcfname) {
ctx->lib.ecpcdata = ctx->lib.GetCPCData(full);
if (!ctx->lib.ecpcdata) {
ERROR("Unable to load CPC file '%s'\n", full);
return CUPS_BACKEND_CANCEL;
}
} else {
ctx->lib.ecpcdata = NULL;
}
}
/* Convert using image processing library */
input.origin_rows = input.origin_cols = 0;
input.rows = job->rows;
input.cols = job->cols;
input.imgbuf = job->spoolbuf;
input.bytes_per_row = job->cols * 3;
ctx->output.origin_rows = ctx->output.origin_cols = 0;
ctx->output.rows = job->rows;
ctx->output.cols = job->cols;
ctx->output.imgbuf = job->databuf + job->datalen;
ctx->output.bytes_per_row = job->cols * 3 * 2;
DEBUG("Running print data through processing library\n");
if (ctx->lib.DoImageEffect(ctx->lib.cpcdata, ctx->lib.ecpcdata,
&input, &ctx->output, job->sharpen, job->reverse, rew)) {
ERROR("Image Processing failed, aborting!\n");
return CUPS_BACKEND_CANCEL;
}
/* Twiddle rewind stuff if needed */
if (ctx->conn->type != P_MITSU_D70X) {
hdr->rewind[0] = !rew[0];
hdr->rewind[1] = !rew[1];
DEBUG("Rewind Inhibit? %02x %02x\n", hdr->rewind[0], hdr->rewind[1]);
}
/* Move up the pointer to after the image data */
job->datalen += 3*job->planelen;
/* Clean up */
free(job->spoolbuf);
job->spoolbuf = NULL;
job->spoolbuflen = 0;
/* Now that we've filled everything in, read matte from file */
if (job->matte) {
ret = mitsu_readlamdata(job->laminatefname, LAMINATE_STRIDE,
job->databuf, &job->datalen,
be16_to_cpu(hdr->lamrows), be16_to_cpu(hdr->lamcols), 2);
if (ret)
return ret;
/* Zero out the tail end of the buffer. */
ret = be16_to_cpu(hdr->lamcols) * be16_to_cpu(hdr->lamrows) * 2;
memset(job->databuf + job->datalen, 0, job->matte - ret);
}
bypass:
/* Bypass */
if (test_mode >= TEST_MODE_NOPRINT)
return CUPS_BACKEND_OK;
INFO("Waiting for printer idle...\n");
/* Ensure printer is awake */
@ -2618,8 +2616,7 @@ static const char *mitsu70x_prefixes[] = {
/* Exported */
const struct dyesub_backend mitsu70x_backend = {
.name = "Mitsubishi CP-D70 family",
.version = "0.108" " (lib " LIBMITSU_VER ")",
.flags = BACKEND_FLAG_DUMMYPRINT,
.version = "0.109" " (lib " LIBMITSU_VER ")",
.uri_prefixes = mitsu70x_prefixes,
.cmdline_usage = mitsu70x_cmdline,
.cmdline_arg = mitsu70x_cmdline_arg,

View file

@ -1006,6 +1006,31 @@ static int mitsud90_panorama_splitjob(struct mitsud90_printjob *injob, struct mi
return CUPS_BACKEND_OK;
}
static int cpm1_fillmatte(struct mitsud90_printjob *job)
{
int ret;
int rows, cols;
struct mitsud90_plane_hdr *phdr = (struct mitsud90_plane_hdr *) job->databuf;
rows = be16_to_cpu(job->hdr.rows) + 12;
cols = be16_to_cpu(job->hdr.cols);
/* Fill in matte data */
ret = mitsu_readlamdata(CPM1_LAMINATE_FILE, CPM1_LAMINATE_STRIDE,
job->databuf, &job->datalen,
rows, cols, 1);
if (ret)
return ret;
/* Update plane header and overall length */
phdr->lamcols = cpu_to_be16(cols);
phdr->lamrows = cpu_to_be16(rows);
return CUPS_BACKEND_OK;
}
static int mitsud90_read_parse(void *vctx, const void **vjob, int data_fd, int copies) {
struct mitsud90_ctx *ctx = vctx;
int i, remain;
@ -1072,11 +1097,10 @@ static int mitsud90_read_parse(void *vctx, const void **vjob, int data_fd, int c
job->is_pano = 1;
job->hdr.zero_b[3] = 0;
job->hdr.pano.on = 0; /* Will get inserted later */
} else if (be16_to_cpu(job->hdr.rows > 2729)) {
} 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;
@ -1228,7 +1252,7 @@ read_data:
}
}
/* CP-M1 has... other considerations */
/* Apply 3D Lut if requested and the printer can't handle it */
if (((ctx->conn->type == P_MITSU_M1 ||
ctx->conn->type == P_FUJI_ASK500) && !job->is_raw) ||
(ctx->conn->type == P_MITSU_D90 && job->is_pano)) {
@ -1266,95 +1290,12 @@ read_data:
job->hdr.colorcorr = 1; // XXX not sure if right for ASK500?
}
if (job->is_pano) {
int rval;
// XXX do any print sharpening here! If possible..
rval = mitsud90_panorama_splitjob(job, (struct mitsud90_printjob**)vjob);
/* Clean up original parsed job regardless */
mitsud90_cleanup_job(job);
return rval;
} else {
*vjob = job;
}
/* All further work is in main loop */
if (test_mode >= TEST_MODE_NOPRINT)
mitsud90_main_loop(ctx, job, 1);
return CUPS_BACKEND_OK;
}
static int cpm1_fillmatte(struct mitsud90_printjob *job)
{
int ret;
int rows, cols;
struct mitsud90_plane_hdr *phdr = (struct mitsud90_plane_hdr *) job->databuf;
rows = be16_to_cpu(job->hdr.rows) + 12;
cols = be16_to_cpu(job->hdr.cols);
/* Fill in matte data */
ret = mitsu_readlamdata(CPM1_LAMINATE_FILE, CPM1_LAMINATE_STRIDE,
job->databuf, &job->datalen,
rows, cols, 1);
if (ret)
return ret;
/* Update plane header and overall length */
phdr->lamcols = cpu_to_be16(cols);
phdr->lamrows = cpu_to_be16(rows);
return CUPS_BACKEND_OK;
}
static int mitsud90_main_loop(void *vctx, const void *vjob, int wait_for_return) {
struct mitsud90_ctx *ctx = vctx;
struct mitsud90_status_resp resp;
uint8_t last_status[2] = {0xff, 0xff};
int sent;
int ret;
int copies;
struct mitsud90_printjob *job = (struct mitsud90_printjob *)vjob;
if (!ctx)
return CUPS_BACKEND_FAILED;
if (!job)
return CUPS_BACKEND_FAILED;
copies = job->common.copies;
/* Handle panorama state */
if (ctx->conn->type == P_MITSU_D90) {
if (job->hdr.pano.on) {
ctx->pano_page++;
if (be16_to_cpu(job->hdr.pano.page) != ctx->pano_page) {
ERROR("Invalid panorama state (page %d of %d)\n",
ctx->pano_page, be16_to_cpu(job->hdr.pano.page));
return CUPS_BACKEND_FAILED;
}
if (copies > 1) {
WARNING("Cannot print non-collated copies of a panorama job\n");
copies = 1;
}
} else if (ctx->pano_page) {
/* Clean up panorama state */
WARNING("Dangling panorama state!\n");
ctx->pano_page = 0;
}
} else {
ctx->pano_page = 0;
}
if ((ctx->conn->type == P_MITSU_M1 ||
ctx->conn->type == P_FUJI_ASK500) && !job->is_raw) {
struct BandImage input;
struct BandImage output;
struct M1CPCData *cpc;
int ret;
input.origin_rows = input.origin_cols = 0;
input.rows = be16_to_cpu(job->hdr.rows);
@ -1366,6 +1307,7 @@ static int mitsud90_main_loop(void *vctx, const void *vjob, int wait_for_return)
uint8_t *convbuf = malloc(input.rows * input.cols * sizeof(uint16_t) * 3 + (job->hdr.overcoat? (input.rows + 12) * input.cols + CPM1_LAMINATE_STRIDE / 2 : 0) + sizeof(struct mitsud90_plane_hdr));
if (!convbuf) {
ERROR("Memory allocation Failure!\n");
mitsud90_cleanup_job(job);
return CUPS_BACKEND_RETRY_CURRENT;
}
@ -1418,6 +1360,7 @@ static int mitsud90_main_loop(void *vctx, const void *vjob, int wait_for_return)
if (!cpc) {
ERROR("Cannot read data tables\n");
free(convbuf);
mitsud90_cleanup_job(job);
return CUPS_BACKEND_FAILED;
}
@ -1436,6 +1379,7 @@ static int mitsud90_main_loop(void *vctx, const void *vjob, int wait_for_return)
ERROR("CLocalEnhancer failed (out of memory?)\n");
free(convbuf);
ctx->lib.M1_DestroyCPCData(cpc);
mitsud90_cleanup_job(job);
return CUPS_BACKEND_RETRY_CURRENT;
}
}
@ -1473,9 +1417,60 @@ static int mitsud90_main_loop(void *vctx, const void *vjob, int wait_for_return)
}
}
/* Bypass */
if (test_mode >= TEST_MODE_NOPRINT)
return CUPS_BACKEND_OK;
if (job->is_pano) {
int rval;
// XXX do any print sharpening here! If possible..
rval = mitsud90_panorama_splitjob(job, (struct mitsud90_printjob**)vjob);
/* Clean up original parsed job regardless */
mitsud90_cleanup_job(job);
return rval;
} else {
*vjob = job;
}
return CUPS_BACKEND_OK;
}
static int mitsud90_main_loop(void *vctx, const void *vjob, int wait_for_return) {
struct mitsud90_ctx *ctx = vctx;
struct mitsud90_status_resp resp;
uint8_t last_status[2] = {0xff, 0xff};
int sent;
int ret;
int copies;
struct mitsud90_printjob *job = (struct mitsud90_printjob *)vjob;
if (!ctx)
return CUPS_BACKEND_FAILED;
if (!job)
return CUPS_BACKEND_FAILED;
copies = job->common.copies;
/* Handle panorama state */
if (ctx->conn->type == P_MITSU_D90) {
if (job->hdr.pano.on) {
ctx->pano_page++;
if (be16_to_cpu(job->hdr.pano.page) != ctx->pano_page) {
ERROR("Invalid panorama state (page %d of %d)\n",
ctx->pano_page, be16_to_cpu(job->hdr.pano.page));
return CUPS_BACKEND_FAILED;
}
if (copies > 1) {
WARNING("Cannot print non-collated copies of a panorama job\n");
copies = 1;
}
} else if (ctx->pano_page) {
/* Clean up panorama state */
WARNING("Dangling panorama state!\n");
ctx->pano_page = 0;
}
} else {
ctx->pano_page = 0;
}
INFO("Waiting for printer idle...\n");
@ -2485,10 +2480,10 @@ const struct dyesub_backend mitsud90_backend = {
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 MM == 0 for no margin cut, 1 for margin cut
QQ RR SS HH VV 00 00 00 00 00 ZZ 00 JJ II 09 7c QQ == 02 matte (D90) or 03 (M1), 00 glossy,
09 4c 00 00 02 58 00 0c 00 06 00 00 00 00 00 00 RR == 00 auto, (D90: 03 == fine, 02 == superfine), (M1: 05 == Fast)
Z0 Z1 Z2 00 00 00 00 00 00 00 00 00 00 00 00 00 SS == 00 colorcorr, 01 == none (always 01 on M1)
Z0 Z1 Z2 00 00 00 00 00 00 00 00 00 00 00 00 00 SS == 00 colorcorr, 01 == none (always 01 on M1 or D90 if LUT done in driver)
HH/VV sharpening for Horiz/Vert, 0-8, 0 is off, 4 is normal (always 00 on M1)
TT is waittime (100 max, always 100 on D90)
ZZ is 0x02 on M1, D90 see below
ZZ is 0x02 on M1, D90 see PANORAMA below
Z0 is 0x01 (M1 windows) (00 Linux and d90 UNK!)
Z1 is RGB Rate (M1)
Z2 is OP Rate (M1)
@ -2504,7 +2499,7 @@ const struct dyesub_backend mitsud90_backend = {
9x6div3 == 2724 02 03 90 01 00 07 14 00 00 00 00 00 00
9x6div4 == 2628 03 02 97 01 00 05 22 00 00 07 ad 00 00
from [ZZ 00 03 03] onwards, only shows in 8x20" PANORAMA prints. Assume 2" overlap.
PANORAMA: from [ZZ 00 03 03] onwards, only shows in PANORAMA prints. Assume 2" overlap.
ZZ == 00 (normal) or 01 (panorama)
JJ == 02 03 (num of panorama panels)
II == 01 02 03 (which panel # in panorama!)