diff options
Diffstat (limited to 'src/main/print-olympus.c')
-rw-r--r-- | src/main/print-olympus.c | 786 |
1 files changed, 629 insertions, 157 deletions
diff --git a/src/main/print-olympus.c b/src/main/print-olympus.c index 59c8d0c..95eb64c 100644 --- a/src/main/print-olympus.c +++ b/src/main/print-olympus.c @@ -1,9 +1,10 @@ /* * - * Print plug-in DyeSub driver (formerly Olympus driver) for the GIMP. + * Print plug-in DyeSub driver (formerly Olympus driver) for Gutenprint * - * Copyright 2003 - 2006 - * Michael Mraka (Michael.Mraka@linux.cz) + * Copyright 2003-2006 Michael Mraka (Michael.Mraka@linux.cz) + * + * Copyright 2007-2017 Solomon Peachy (pizza@shaftnet.org) * * The plug-in is based on the code of the RAW plugin for the GIMP of * Michael Sweet (mike@easysw.com) and Robert Krawitz (rlk@alum.mit.edu) @@ -41,6 +42,10 @@ #define inline __inline__ #endif +#define MITSU70X_8BPP +//#define S6145_YMC +//#define CANONSELPHYNEO_CMY + #define DYESUB_FEATURE_NONE 0x00000000 #define DYESUB_FEATURE_FULL_WIDTH 0x00000001 #define DYESUB_FEATURE_FULL_HEIGHT 0x00000002 @@ -53,15 +58,15 @@ #define DYESUB_FEATURE_12BPP 0x00000100 #define DYESUB_FEATURE_16BPP 0x00000200 #define DYESUB_FEATURE_BIGENDIAN 0x00000400 -#define DYESUB_FEATURE_RGBtoYCBCR 0x00000800 -#define DYESUB_FEATURE_DUPLEX 0x00001000 -#define DYESUB_FEATURE_MONOCHROME 0x00002000 /* Monochrome only..? */ +#define DYESUB_FEATURE_DUPLEX 0x00000800 +#define DYESUB_FEATURE_MONOCHROME 0x00001000 +#ifndef CANONSELPHYNEO_CMY +#define DYESUB_FEATURE_RGBtoYCBCR 0x00002000 +#endif #define DYESUB_PORTRAIT 0 #define DYESUB_LANDSCAPE 1 -#define MITSU70X_8BPP - #ifndef MIN # define MIN(a,b) (((a) < (b)) ? (a) : (b)) #endif /* !MIN */ @@ -221,7 +226,10 @@ typedef struct int gamma; int flags; int comment; - char usercomment[34]; + int contrast; + int sharpen; + int brightness; + char usercomment[40]; char commentbuf[19]; /* With one extra byte for null termination */ } mitsu_p95d_privdata_t; @@ -279,7 +287,7 @@ typedef struct /* printer specific parameters */ const dyesub_resolution_list_t *resolution; const dyesub_pagesize_list_t *pages; const dyesub_printsize_list_t *printsize; - int block_size; + int block_size; /* Really # of rows in a block */ int features; void (*printer_init_func)(stp_vars_t *); void (*printer_end_func)(stp_vars_t *); @@ -1149,7 +1157,7 @@ static const dyesub_pagesize_t cp910_page[] = { { "Postcard", "Postcard 100x148mm", PT(1248,300)+1, PT(1872,300)+1, 13, 13, 16, 19, DYESUB_PORTRAIT}, { "w253h337", "CP_L 89x119mm", PT(1152,300)+1, PT(1472,300)+1, 13, 13, 15, 15, DYESUB_PORTRAIT}, - { "w155h244", "Card 54x86mm", PT(1088,300)+1, PT(668,300)+1, 13, 13, 15, 15, DYESUB_LANDSCAPE}, + { "w155h244", "Card 54x86mm", PT(668,300)+1, PT(1088,300)+1, 13, 13, 15, 15, DYESUB_LANDSCAPE}, }; LIST(dyesub_pagesize_list_t, cp910_page_list, dyesub_pagesize_t, cp910_page); @@ -1180,7 +1188,12 @@ static void cp910_printer_init_func(stp_vars_t *v) 0x50 ))); stp_putc(pg, v); - dyesub_nputc(v, '\0', 5); + dyesub_nputc(v, '\0', 4); +#ifdef CANONSELPHYNEO_CMY + stp_putc(0x01, v); +#else + stp_putc(0x00, v); +#endif stp_put32_le(pd->w_size, v); stp_put32_le(pd->h_size, v); @@ -1981,7 +1994,7 @@ static const dyesub_pagesize_t kodak_1400_page[] = */ { "w612h864", "8.5x12", PT(2560,301)+1, PT(3010,301)+72*2, PT(76,301)+1, PT(76,301), 72, 72, DYESUB_PORTRAIT}, /* 8x12 */ { "Legal", "8.5x14", PT(2560,301)+1, PT(3612,301)+72*2, PT(35,301)+1, PT(35,301)+1, 72, 72, DYESUB_PORTRAIT}, /* 8x14 */ - { "A4", "A4", PT(2560,301)+1, PT(3010,301)+72*2, PT(76,301)+1, PT(76,301), 0, 0, DYESUB_PORTRAIT}, /* A4, indentical to 8x12 */ + { "A4", "A4", PT(2560,301)+1, PT(3010,301)+72*2, PT(76,301)+1, PT(76,301), 0, 0, DYESUB_PORTRAIT}, /* A4, identical to 8x12 */ }; LIST(dyesub_pagesize_list_t, kodak_1400_page_list, dyesub_pagesize_t, kodak_1400_page); @@ -2481,7 +2494,7 @@ static const stp_parameter_t kodak_8500_parameters[] = }, { "MatteIntensity", N_("Matte Intensity"), "Color=No,Category=Advanced Printer Setup", - N_("Strengh of matte lamination pattern (-5 through +5)"), + N_("Strength of matte lamination pattern (-5 through +5)"), STP_PARAMETER_TYPE_INT, STP_PARAMETER_CLASS_FEATURE, STP_PARAMETER_LEVEL_BASIC, 1, 1, STP_CHANNEL_NONE, 1, 0 }, @@ -2893,7 +2906,10 @@ static int mitsu_p95d_parse_parameters(stp_vars_t *v) if (pd->copies > 200) pd->copies = 200; - + + pd->privdata.m95d.brightness = stp_get_int_parameter(v, "P95Brightness"); + pd->privdata.m95d.contrast = stp_get_int_parameter(v, "P95Contrast"); + if (!strcmp(gamma, "Printer")) { pd->privdata.m95d.gamma = 0x00; } else if (!strcmp(gamma, "T1")) { @@ -3051,7 +3067,10 @@ static void mitsu_p95d_printer_init(stp_vars_t *v) stp_putc(0x00, v); dyesub_nputc(v, 0x00, 5); stp_putc(pd->privdata.m95d.gamma, v); - dyesub_nputc(v, 0x00, 3); + stp_putc(pd->privdata.m95d.brightness, v); + stp_putc(pd->privdata.m95d.contrast, v); + stp_putc(0x00, v); + if (pd->privdata.m95d.gamma == 0x10) { stp_zfwrite(p95d_lut, 1, sizeof(p95d_lut), v); /* XXX only for K95HG? */ } else { @@ -3086,6 +3105,363 @@ static void mitsu_p95d_printer_end(stp_vars_t *v) stp_putc(0x50, v); } +/* Mitsubishi P93D/DW */ + +static const dyesub_media_t mitsu_p93d_medias[] = +{ + {"Standard", N_("Standard (KP61B)"), {1, "\x02"}}, + {"HighDensity", N_("High Density (KP65HM)"), {1, "\x00"}}, + {"HighGlossy", N_("High Glossy (KP91HG)"), {1, "\x01"}}, +}; + +LIST(dyesub_media_list_t, mitsu_p93d_media_list, dyesub_media_t, mitsu_p93d_medias); + +static const dyesub_stringitem_t mitsu_p93d_gammas[] = +{ + { "T1", N_ ("Table 1") }, + { "T2", N_ ("Table 2") }, + { "T3", N_ ("Table 3") }, + { "T4", N_ ("Table 4") }, + { "T5", N_ ("Table 5") }, +}; +LIST(dyesub_stringlist_t, mitsu_p93d_gamma_list, dyesub_stringitem_t, mitsu_p93d_gammas); + +static const stp_parameter_t mitsu_p93d_parameters[] = +{ + { + "P93Gamma", N_("Printer Gamma Correction"), "Color=No,Category=Advanced Printer Setup", + N_("Printer Gamma Correction"), + STP_PARAMETER_TYPE_STRING_LIST, STP_PARAMETER_CLASS_FEATURE, + STP_PARAMETER_LEVEL_ADVANCED, 1, 1, STP_CHANNEL_NONE, 1, 0 + }, + { + "Buzzer", N_("Printer Buzzer"), "Color=No,Category=Advanced Printer Setup", + N_("Printer Buzzer"), + STP_PARAMETER_TYPE_STRING_LIST, STP_PARAMETER_CLASS_FEATURE, + STP_PARAMETER_LEVEL_ADVANCED, 1, 1, STP_CHANNEL_NONE, 1, 0 + }, + { + "PaperSaving", N_("Paper Saving Mode"), "Color=Yes,Category=Advanced Printer Setup", + N_("Paper Saving Mode"), + STP_PARAMETER_TYPE_BOOLEAN, STP_PARAMETER_CLASS_FEATURE, + STP_PARAMETER_LEVEL_BASIC, 1, 1, STP_CHANNEL_NONE, 1, 0 + }, + { + "Comment", N_("Generate Comment"), "Color=No,Category=Advanced Printer Setup", + N_("Generate Comment"), + STP_PARAMETER_TYPE_STRING_LIST, STP_PARAMETER_CLASS_FEATURE, + STP_PARAMETER_LEVEL_ADVANCED, 1, 1, STP_CHANNEL_NONE, 1, 0 + }, + { + "ClearMemory", N_("Clear Memory"), "Color=No,Category=Advanced Printer Setup", + N_("Clear Memory"), + STP_PARAMETER_TYPE_BOOLEAN, STP_PARAMETER_CLASS_FEATURE, + STP_PARAMETER_LEVEL_ADVANCED, 1, 1, STP_CHANNEL_NONE, 1, 0 + }, + { + "ContinuousPrint", N_("Continuous Printing"), "Color=No,Category=Advanced Printer Setup", + N_("Continuous Printing"), + STP_PARAMETER_TYPE_BOOLEAN, STP_PARAMETER_CLASS_FEATURE, + STP_PARAMETER_LEVEL_ADVANCED, 1, 1, STP_CHANNEL_NONE, 1, 0 + }, + { + "P93Brightness", N_("Brightness"), "Color=No,Category=Advanced Printer Setup", + N_("Printer Brightness Adjustment"), + STP_PARAMETER_TYPE_INT, STP_PARAMETER_CLASS_FEATURE, + STP_PARAMETER_LEVEL_ADVANCED, 1, 1, STP_CHANNEL_NONE, 1, 0 + }, + { + "P93Contrast", N_("Contrast"), "Color=No,Category=Advanced Printer Setup", + N_("Printer Contrast Adjustment"), + STP_PARAMETER_TYPE_INT, STP_PARAMETER_CLASS_FEATURE, + STP_PARAMETER_LEVEL_ADVANCED, 1, 1, STP_CHANNEL_NONE, 1, 0 + }, + { + "Sharpen", N_("Image Sharpening"), "Color=No,Category=Advanced Printer Setup", + N_("Sharpening to apply to image (1 is soft, 1 is normal, 2 is hard"), + STP_PARAMETER_TYPE_INT, STP_PARAMETER_CLASS_FEATURE, + STP_PARAMETER_LEVEL_BASIC, 1, 1, STP_CHANNEL_NONE, 1, 0 + }, + { + "UserComment", N_("User Comment"), "Color=No,Category=Advanced Printer Setup", + N_("User-specified comment (0-40 characters from 0x20->0x7E), null terminated if under 40 characters long"), + STP_PARAMETER_TYPE_RAW, STP_PARAMETER_CLASS_FEATURE, + STP_PARAMETER_LEVEL_ADVANCED, 0, 1, STP_CHANNEL_NONE, 1, 0 + }, +}; +#define mitsu_p93d_parameter_count (sizeof(mitsu_p93d_parameters) / sizeof(const stp_parameter_t)) + +static int +mitsu_p93d_load_parameters(const stp_vars_t *v, const char *name, + stp_parameter_t *description) +{ + int i; + const dyesub_cap_t *caps = dyesub_get_model_capabilities( + stp_get_model_id(v)); + + if (caps->parameter_count && caps->parameters) + { + for (i = 0; i < caps->parameter_count; i++) + if (strcmp(name, caps->parameters[i].name) == 0) + { + stp_fill_parameter_settings(description, &(caps->parameters[i])); + break; + } + } + + if (strcmp(name, "P93Gamma") == 0) + { + description->bounds.str = stp_string_list_create(); + + const dyesub_stringlist_t *mlist = &mitsu_p93d_gamma_list; + for (i = 0; i < mlist->n_items; i++) + { + const dyesub_stringitem_t *m = &(mlist->item[i]); + stp_string_list_add_string(description->bounds.str, + m->name, m->text); /* Do *not* want this translated, otherwise use gettext(m->text) */ + } + description->deflt.str = stp_string_list_param(description->bounds.str, 0)->name; + description->is_active = 1; + } else if (strcmp(name, "Buzzer") == 0) { + description->bounds.str = stp_string_list_create(); + + const dyesub_stringlist_t *mlist = &mitsu_p95d_buzzer_list; + for (i = 0; i < mlist->n_items; i++) + { + const dyesub_stringitem_t *m = &(mlist->item[i]); + stp_string_list_add_string(description->bounds.str, + m->name, m->text); /* Do *not* want this translated, otherwise use gettext(m->text) */ + } + description->deflt.str = stp_string_list_param(description->bounds.str, 2)->name; + description->is_active = 1; + } else if (strcmp(name, "PaperSaving") == 0) { + description->deflt.boolean = 0; + description->is_active = 1; + } else if (strcmp(name, "Comment") == 0) { + description->bounds.str = stp_string_list_create(); + + const dyesub_stringlist_t *mlist = &mitsu_p95d_comment_list; + for (i = 0; i < mlist->n_items; i++) + { + const dyesub_stringitem_t *m = &(mlist->item[i]); + stp_string_list_add_string(description->bounds.str, + m->name, m->text); /* Do *not* want this translated, otherwise use gettext(m->text) */ + } + description->deflt.str = stp_string_list_param(description->bounds.str, 0)->name; + description->is_active = 1; + } else if (strcmp(name, "ClearMemory") == 0) { + description->is_active = 1; + description->deflt.boolean = 0; + } else if (strcmp(name, "ContinuousPrint") == 0) { + description->is_active = 1; + description->deflt.boolean = 0; + } else if (strcmp(name, "P93Brightness") == 0) { + description->deflt.integer = 0; + description->bounds.integer.lower = -127; + description->bounds.integer.upper = 127; + description->is_active = 1; + } else if (strcmp(name, "P93Contrast") == 0) { + description->deflt.integer = 0; + description->bounds.integer.lower = -127; + description->bounds.integer.upper = 127; + description->is_active = 1; + } else if (strcmp(name, "Sharpen") == 0) { + description->deflt.integer = 1; + description->bounds.integer.lower = 0; + description->bounds.integer.upper = 2; + description->is_active = 1; + } else if (strcmp(name, "UserComment") == 0) { + description->is_active = 1; + } + else + { + return 0; + } + return 1; +} + +static int mitsu_p93d_parse_parameters(stp_vars_t *v) +{ + dyesub_privdata_t *pd = get_privdata(v); + const char *gamma = stp_get_string_parameter(v, "P93Gamma"); + const char *buzzer = stp_get_string_parameter(v, "Buzzer"); + const char *comment = stp_get_string_parameter(v, "Comment"); + const stp_raw_t *usercomment = NULL; + + /* Sanity check */ + if (stp_check_raw_parameter(v, "UserComment", STP_PARAMETER_ACTIVE)) { + usercomment = stp_get_raw_parameter(v, "UserComment"); + if (usercomment->bytes > 40) { + stp_eprintf(v, _("StpUserComment must be between 0 and 40 bytes!\n")); + return 0; + } + } + + /* No need to set global params if there's no privdata yet */ + if (!pd) + return 1; + + /* Parse options */ + pd->privdata.m95d.clear_mem = stp_get_boolean_parameter(v, "ClearMemory"); + pd->privdata.m95d.cont_print = stp_get_boolean_parameter(v, "ContinuousPrint"); + + if (pd->copies > 200) + pd->copies = 200; + + if (!strcmp(gamma, "T1")) { + pd->privdata.m95d.gamma = 0x00; + } else if (!strcmp(gamma, "T2")) { + pd->privdata.m95d.gamma = 0x01; + } else if (!strcmp(gamma, "T3")) { + pd->privdata.m95d.gamma = 0x02; + } else if (!strcmp(gamma, "T4")) { + pd->privdata.m95d.gamma = 0x03; + } else if (!strcmp(gamma, "T5")) { + pd->privdata.m95d.gamma = 0x04; + } + + if (!strcmp(buzzer, "Off")) { + pd->privdata.m95d.flags |= 0x00; + } else if (!strcmp(buzzer, "Low")) { + pd->privdata.m95d.flags |= 0x02; + } else if (!strcmp(buzzer, "High")) { + pd->privdata.m95d.flags |= 0x03; + } + + pd->privdata.m95d.brightness = stp_get_int_parameter(v, "P93Brightness"); + pd->privdata.m95d.contrast = stp_get_int_parameter(v, "P93Contrast"); + pd->privdata.m95d.sharpen = stp_get_int_parameter(v, "Sharpen"); + + if (stp_get_boolean_parameter(v, "PaperSaving")) { + pd->privdata.m95d.flags |= 0x04; + } + + if (!strcmp(comment, "Off")) { + memset(pd->privdata.m95d.commentbuf, 0, sizeof(pd->privdata.m95d.commentbuf)); + pd->privdata.m95d.comment = 0; + } else if (!strcmp(comment, "Settings")) { + memset(pd->privdata.m95d.commentbuf, 0, sizeof(pd->privdata.m95d.commentbuf)); + pd->privdata.m95d.comment = 1; + } else if (!strcmp(comment, "Date")) { + struct tm tmp; + time_t t; + t = time(NULL); + localtime_r(&t, &tmp); + strftime(pd->privdata.m95d.commentbuf, sizeof(pd->privdata.m95d.commentbuf), " %F", &tmp); + pd->privdata.m95d.comment = 2; + } else if (!strcmp(comment, "DateTime")) { + struct tm tmp; + time_t t; + t = time(NULL); + localtime_r(&t, &tmp); + strftime(pd->privdata.m95d.commentbuf, sizeof(pd->privdata.m95d.commentbuf), " %F %R", &tmp); + pd->privdata.m95d.comment = 3; + } + + if (usercomment) { + if (strncmp("None", usercomment->data, usercomment->bytes)) { + int i; + memcpy(pd->privdata.m95d.usercomment, usercomment->data, usercomment->bytes); + if (usercomment->bytes < 40) + pd->privdata.m95d.usercomment[usercomment->bytes] = 0; + for (i = 0 ; i < usercomment->bytes ; i++) { + if (pd->privdata.m95d.usercomment[i] < 0x20 || + pd->privdata.m95d.usercomment[i] > 0x7F) + pd->privdata.m95d.usercomment[i] = 0x20; + } + } + } else { + memset(pd->privdata.m95d.usercomment, 0x20, sizeof(pd->privdata.m95d.usercomment)); + } + + return 1; +} + +static void mitsu_p93d_printer_init(stp_vars_t *v) +{ + dyesub_privdata_t *pd = get_privdata(v); + + /* Header */ + stp_putc(0x1b, v); + stp_putc(0x51, v); + + /* Clear memory */ + if (pd->privdata.m95d.clear_mem) { + stp_putc(0x1b, v); + stp_putc(0x5a, v); + stp_putc(0x43, v); + stp_putc(0x00, v); + } + + /* Page Setup */ + stp_putc(0x1b, v); + stp_putc(0x57, v); + stp_putc(0x20, v); + stp_putc(0x2e, v); + stp_putc(0x00, v); + stp_putc(0x0a, v); + dyesub_nputc(v, 0x00, 8); + stp_put16_be(pd->w_size, v); /* Columns */ + stp_put16_be(pd->h_size, v); /* Rows */ + + /* This is only set under Windows if a "custom" size is selected, + but the USB comms always show it set to 1... */ + if (!strcmp(pd->pagesize,"Custom")) + stp_putc(0x01, v); + else + stp_putc(0x00, v); + dyesub_nputc(v, 0x00, 31); + + /* Print Options */ + stp_putc(0x1b, v); + stp_putc(0x57, v); + stp_putc(0x21, v); + stp_putc(0x2e, v); + stp_putc(0x00, v); + stp_putc(0x4a, v); + stp_putc(0xaa, v); + stp_putc(0x00, v); + stp_putc(0x00, v); + stp_zfwrite((pd->media->seq).data, 1, 1, v); /* Media Type */ + stp_putc(0x00, v); + stp_putc(0x00, v); + stp_putc(0x00, v); + if (pd->privdata.m95d.cont_print) + stp_putc(0xff, v); + else + stp_putc(pd->copies, v); + stp_putc(0x00, v); + stp_putc(pd->privdata.m95d.comment, v); + stp_zfwrite(pd->privdata.m95d.commentbuf, 1, sizeof(pd->privdata.m95d.commentbuf) -1, v); + dyesub_nputc(v, 0x00, 3); + stp_putc(0x02, v); + dyesub_nputc(v, 0x00, 11); + stp_putc(pd->privdata.m95d.flags, v); + + /* Gamma */ + stp_putc(0x1b, v); + stp_putc(0x57, v); + stp_putc(0x22, v); + stp_putc(0x2e, v); + stp_putc(0x00, v); + stp_putc(0xd5, v); + dyesub_nputc(v, 0x00, 6); + + stp_putc(pd->privdata.m95d.sharpen, v); // XXX + stp_putc(0x00, v); + stp_putc(pd->privdata.m95d.gamma, v); + stp_putc(0x00, v); + stp_putc(pd->privdata.m95d.brightness, v); + stp_putc(0x00, v); + stp_putc(pd->privdata.m95d.contrast, v); + dyesub_nputc(v, 0x00, 31); + + /* User Comment */ + stp_putc(0x1b, v); + stp_putc(0x58, v); + stp_zfwrite(pd->privdata.m95d.usercomment, 1, sizeof(pd->privdata.m95d.usercomment), v); +} + /* Mitsubishi CP3020D/DU/DE */ static const dyesub_pagesize_t mitsu_cp3020d_page[] = { @@ -4243,10 +4619,11 @@ static void mitsu_cpd70k60_printer_init(stp_vars_t *v, unsigned char model) stp_putc(pd->privdata.m70x.sharpen, v); stp_putc(0x01, v); /* Mark as 8bpp BGR rather than 16bpp YMC cooked */ stp_putc(pd->privdata.m70x.use_lut, v); /* Use LUT? */ + stp_putc(0x01, v); /* Tell the backend the data's in the proper order */ #else - dyesub_nputc(v, 0x00, 15); + dyesub_nputc(v, 0x00, 16); #endif - dyesub_nputc(v, 0x00, 448); /* Pad to 512-byte block */ + dyesub_nputc(v, 0x00, 447); /* Pad to 512-byte block */ } static void mitsu_cpd70x_printer_init(stp_vars_t *v) @@ -4994,7 +5371,7 @@ static const stp_parameter_t shinko_chcs1245_parameters[] = }, { "MatteIntensity", N_("Matte Intensity"), "Color=No,Category=Advanced Printer Setup", - N_("Strengh of matte lamination pattern (-25 through +25)"), + N_("Strength of matte lamination pattern (-25 through +25)"), STP_PARAMETER_TYPE_INT, STP_PARAMETER_CLASS_FEATURE, STP_PARAMETER_LEVEL_BASIC, 1, 1, STP_CHANNEL_NONE, 1, 0 }, @@ -5381,7 +5758,11 @@ static void shinko_chcs6145_printer_init(stp_vars_t *v) stp_put32_le(0x00, v); stp_put32_le(0x00, v); +#ifdef S6145_YMC + stp_put32_le(0x01, v); +#else stp_put32_le(0x00, v); +#endif } /* Ciaat Brava 21 */ @@ -6691,20 +7072,34 @@ static const dyesub_cap_t dyesub_model_capabilities[] = NULL, NULL, NULL, 0, NULL, NULL, }, - { /* Canon CP820, CP910 */ + { /* Canon CP820, CP910, CP1000, CP1200 */ 1011, +#ifdef CANONSELPHYNEO_CMY + &cmy_ink_list, +#else &rgb_ink_list, +#endif &res_300dpi_list, &cp910_page_list, &cp910_printsize_list, SHRT_MAX, +#ifdef CANONSELPHYNEO_CMY + DYESUB_FEATURE_FULL_WIDTH | DYESUB_FEATURE_FULL_HEIGHT + | DYESUB_FEATURE_BORDERLESS | DYESUB_FEATURE_WHITE_BORDER + | DYESUB_FEATURE_PLANE_INTERLACE, +#else DYESUB_FEATURE_FULL_WIDTH | DYESUB_FEATURE_FULL_HEIGHT | DYESUB_FEATURE_BORDERLESS | DYESUB_FEATURE_WHITE_BORDER | DYESUB_FEATURE_PLANE_INTERLACE | DYESUB_FEATURE_RGBtoYCBCR, +#endif &cp910_printer_init_func, NULL, NULL, NULL, NULL, NULL, +#ifdef CANONSELPHYNEO_CMY + cpx00_adjust_curves, +#else NULL, +#endif NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, @@ -7135,7 +7530,7 @@ static const dyesub_cap_t dyesub_model_capabilities[] = &mitsu_cpd70x_printsize_list, SHRT_MAX, #ifdef MITSU70X_8BPP - DYESUB_FEATURE_FULL_WIDTH | DYESUB_FEATURE_FULL_HEIGHT, + DYESUB_FEATURE_FULL_WIDTH | DYESUB_FEATURE_FULL_HEIGHT | DYESUB_FEATURE_PLANE_LEFTTORIGHT, &mitsu_cpd70x_printer_init, NULL, #else DYESUB_FEATURE_FULL_WIDTH | DYESUB_FEATURE_FULL_HEIGHT @@ -7165,7 +7560,7 @@ static const dyesub_cap_t dyesub_model_capabilities[] = &mitsu_cpk60_printsize_list, SHRT_MAX, #ifdef MITSU70X_8BPP - DYESUB_FEATURE_FULL_WIDTH | DYESUB_FEATURE_FULL_HEIGHT, + DYESUB_FEATURE_FULL_WIDTH | DYESUB_FEATURE_FULL_HEIGHT | DYESUB_FEATURE_PLANE_LEFTTORIGHT, &mitsu_cpk60_printer_init, NULL, #else DYESUB_FEATURE_FULL_WIDTH | DYESUB_FEATURE_FULL_HEIGHT @@ -7195,7 +7590,7 @@ static const dyesub_cap_t dyesub_model_capabilities[] = &mitsu_cpd80_printsize_list, SHRT_MAX, #ifdef MITSU70X_8BPP - DYESUB_FEATURE_FULL_WIDTH | DYESUB_FEATURE_FULL_HEIGHT, + DYESUB_FEATURE_FULL_WIDTH | DYESUB_FEATURE_FULL_HEIGHT | DYESUB_FEATURE_PLANE_LEFTTORIGHT, &mitsu_cpd70x_printer_init, NULL, #else DYESUB_FEATURE_FULL_WIDTH | DYESUB_FEATURE_FULL_HEIGHT @@ -7225,7 +7620,7 @@ static const dyesub_cap_t dyesub_model_capabilities[] = &kodak305_printsize_list, SHRT_MAX, #ifdef MITSU70X_8BPP - DYESUB_FEATURE_FULL_WIDTH | DYESUB_FEATURE_FULL_HEIGHT, + DYESUB_FEATURE_FULL_WIDTH | DYESUB_FEATURE_FULL_HEIGHT | DYESUB_FEATURE_PLANE_LEFTTORIGHT, &kodak305_printer_init, NULL, #else DYESUB_FEATURE_FULL_WIDTH | DYESUB_FEATURE_FULL_HEIGHT @@ -7250,7 +7645,7 @@ static const dyesub_cap_t dyesub_model_capabilities[] = &mitsu_cpd90_page_list, &mitsu_cpd90_printsize_list, SHRT_MAX, - DYESUB_FEATURE_FULL_WIDTH | DYESUB_FEATURE_FULL_HEIGHT, + DYESUB_FEATURE_FULL_WIDTH | DYESUB_FEATURE_FULL_HEIGHT | DYESUB_FEATURE_PLANE_LEFTTORIGHT, &mitsu_cpd90_printer_init, &mitsu_cpd90_printer_end, NULL, NULL, NULL, NULL, /* No block funcs */ @@ -7311,7 +7706,7 @@ static const dyesub_cap_t dyesub_model_capabilities[] = &fuji_ask300_printsize_list, SHRT_MAX, #ifdef MITSU70X_8BPP - DYESUB_FEATURE_FULL_WIDTH | DYESUB_FEATURE_FULL_HEIGHT, + DYESUB_FEATURE_FULL_WIDTH | DYESUB_FEATURE_FULL_HEIGHT | DYESUB_FEATURE_PLANE_LEFTTORIGHT, &mitsu_cpd70x_printer_init, NULL, #else DYESUB_FEATURE_FULL_WIDTH | DYESUB_FEATURE_FULL_HEIGHT @@ -7390,6 +7785,26 @@ static const dyesub_cap_t dyesub_model_capabilities[] = mitsu9500_load_parameters, mitsu9500_parse_parameters, }, + { /* Mitsubishi P93D/DW */ + 4116, + &w_ink_list, + &res_325dpi_list, + &mitsu_p95d_page_list, + &mitsu_p95d_printsize_list, + SHRT_MAX, + DYESUB_FEATURE_FULL_WIDTH | DYESUB_FEATURE_FULL_HEIGHT + | DYESUB_FEATURE_MONOCHROME, + &mitsu_p93d_printer_init, &mitsu_p95d_printer_end, + &mitsu_p95d_plane_start, NULL, + NULL, NULL, /* No block funcs */ + NULL, + NULL, &mitsu_p93d_media_list, + NULL, NULL, + mitsu_p93d_parameters, + mitsu_p93d_parameter_count, + mitsu_p93d_load_parameters, + mitsu_p93d_parse_parameters, + }, { /* Shinko CHC-S9045 (experimental) */ 5000, &rgb_ink_list, @@ -7459,11 +7874,18 @@ static const dyesub_cap_t dyesub_model_capabilities[] = }, { /* Shinko/Sinfonia CHC-S6145 */ 5004, +#ifdef S6145_YMC + &ymc_ink_list, +#else &rgb_ink_list, +#endif &res_300dpi_list, &shinko_chcs6145_page_list, &shinko_chcs6145_printsize_list, SHRT_MAX, +#ifdef S6145_YMC + DYESUB_FEATURE_PLANE_INTERLACE | +#endif DYESUB_FEATURE_FULL_WIDTH | DYESUB_FEATURE_FULL_HEIGHT, &shinko_chcs6145_printer_init, &shinko_chcs2145_printer_end, NULL, NULL, /* No planes */ @@ -7475,11 +7897,18 @@ static const dyesub_cap_t dyesub_model_capabilities[] = }, { /* CIAAT Brava 21 (aka CHC-S6145D) */ 5005, +#ifdef S6145_YMC + &ymc_ink_list, +#else &rgb_ink_list, +#endif &res_300dpi_list, &ciaat_brava21_page_list, &ciaat_brava21_printsize_list, SHRT_MAX, +#ifdef S6145_YMC + DYESUB_FEATURE_PLANE_INTERLACE | +#endif DYESUB_FEATURE_FULL_WIDTH | DYESUB_FEATURE_FULL_HEIGHT, &shinko_chcs6145_printer_init, &shinko_chcs2145_printer_end, NULL, NULL, /* No planes */ @@ -8232,7 +8661,15 @@ static void dyesub_swap_ints(int *a, int *b) { int t = *a; - *a = *b; + *a = *b; + *b = t; +} + +static void +dyesub_swap_doubles(double *a, double *b) +{ + double t = *a; + *a = *b; *b = t; } @@ -8278,15 +8715,12 @@ dyesub_exec_check(stp_vars_t *v, return 1; } - -static int +/* FIXME: This function is badly named. It actually picks the best single + "point" on the original image to use for the desired output pixel. */ +static double dyesub_interpolate(int oldval, int oldsize, int newsize) { - /* - * This is simple linear interpolation algorithm. - * When imagesize <> printsize I need rescale image somehow... :-/ - */ - return (int)(oldval * newsize / oldsize); + return ((double)oldval * (double)newsize / (double)oldsize); } static void @@ -8345,121 +8779,127 @@ dyesub_read_image(stp_vars_t *v, return image_data; } -static int -dyesub_print_pixel(stp_vars_t *v, - dyesub_print_vars_t *pv, - const dyesub_cap_t *caps, - int row, - int col, - int plane) -{ - unsigned short ink[MAX_INK_CHANNELS], *out; - int i, j, b; - - if (pv->print_mode == DYESUB_LANDSCAPE) - { /* "rotate" image */ - dyesub_swap_ints(&col, &row); - row = (pv->imgw_px - 1) - row; - } +static void +dyesub_render_pixel(unsigned short *src, char *dest, + dyesub_print_vars_t *pv, + const dyesub_cap_t *caps, + int plane) +{ + unsigned short ink[MAX_INK_CHANNELS]; /* What is sent to printer */ - out = &(pv->image_data[row][col * pv->out_channels]); + int i; + int start, end; - for (i = 0; i < pv->ink_channels; i++) + /* Only compute one color at a time */ + if (pv->plane_interlacing || pv->row_interlacing) { - if (pv->out_channels == pv->ink_channels) - { /* copy out_channel (image) to equiv ink_channel (printer) */ - if (dyesub_feature(caps, DYESUB_FEATURE_RGBtoYCBCR)) { - /* Convert RGB -> YCbCr (JPEG YCbCr444 coefficients) */ - double R, G, B; - R = out[0]; - G = out[1]; - B = out[2]; - - if (i == 0) /* Y */ - ink[i] = R * 0.299 + G * 0.587 + B * 0.114; - else if (i == 1) /* Cb */ - ink[i] = R * -0.168736 + G * -0.331264 + B * 0.5 + 32768; - else if (i == 2) /* Cr */ - ink[i] = R * 0.5 + G * -0.418688 + B * -0.081312 + 32768; - - /* FIXME: Natively support YCbCr "inks" in the - Gutenprint core and allow that as an input - into the dyesub driver. */ - } else { - ink[i] = out[i]; - } - } - else if (pv->out_channels < pv->ink_channels) - { /* several ink_channels (printer) "share" same out_channel (image) */ - ink[i] = out[i * pv->out_channels / pv->ink_channels]; - } - else /* (pv->out_channels > pv->ink_channels) */ - { /* merge several out_channels (image) into ink_channel (printer) */ - int avg = 0; - for (j = 0; j < pv->out_channels / pv->ink_channels; j++) - avg += out[j + i * pv->out_channels / pv->ink_channels]; - ink[i] = avg * pv->ink_channels / pv->out_channels; - } + start = plane; + end = plane + 1; + } + else + { + start = 0; + end = pv->ink_channels; } - - /* Downscale 16bpp to output bpp */ - /* FIXME: Do we want to round? */ - if (pv->bytes_per_ink_channel == 1) + + /* copy out_channel (image) to equiv ink_channel (printer) */ + for (i = start; i < end; i++) { - unsigned char *ink_u8 = (unsigned char *) ink; - for (i = 0; i < pv->ink_channels; i++) { +#ifndef CANONSELPHYNEO_CMY + if (dyesub_feature(caps, DYESUB_FEATURE_RGBtoYCBCR)) + { + /* Convert RGB -> YCbCr (JPEG YCbCr444 coefficients) */ + double R, G, B; + R = src[0]; + G = src[1]; + B = src[2]; + + if (i == 0) /* Y */ + ink[i] = R * 0.299 + G * 0.587 + B * 0.114; + else if (i == 1) /* Cb */ + ink[i] = R * -0.168736 + G * -0.331264 + B * 0.5 + (1 << (16 -1)); // Math is 16bpp here. + else if (i == 2) /* Cr */ + ink[i] = R * 0.5 + G * -0.418688 + B * -0.081312 + (1 << (16 -1)); // Math is 16bpp here. + /* FIXME: Natively support YCbCr "inks" in the + Gutenprint core and allow that as an input + into the dyesub driver. */ + } + else +#endif + { + ink[i] = src[i]; + } + + /* Downscale 16bpp to output bpp */ + if (pv->bytes_per_ink_channel == 1) + { + unsigned char *ink_u8 = (unsigned char *) ink; +#ifndef CANONSELPHYNEO_CMY #if 0 - if (dyesub_feature(caps, DYESUB_FEATURE_RGBtoYCBCR)) - ink_u8[i] = ink[i] >> 8; - else + /* FIXME: Do we want to round? */ + if (dyesub_feature(caps, DYESUB_FEATURE_RGBtoYCBCR)) + ink_u8[i] = ink[i] >> 8; + else #endif - ink_u8[i] = ink[i] / 257; - } - } - else if (pv->bits_per_ink_channel != 16) - { - for (i = 0; i < pv->ink_channels; i++) - ink[i] = ink[i] >> (16 - pv->bits_per_ink_channel); - } +#endif + ink_u8[i] = ink[i] / 257; + } + else /* ie 2 bytes per channel */ + { + /* Scale down to output bits */ + if (pv->bits_per_ink_channel != 16) + ink[i] = ink[i] >> (16 - pv->bits_per_ink_channel); - /* Byteswap as needed */ - if (pv->bytes_per_ink_channel == 2 && pv->byteswap) - for (i = 0; i < pv->ink_channels; i++) - ink[i] = ((ink[i] >> 8) & 0xff) | ((ink[i] & 0xff) << 8); + /* Byteswap if needed */ + if (pv->byteswap) + ink[i] = ((ink[i] >> 8) & 0xff) | ((ink[i] & 0xff) << 8); + } + } + /* If we use plane or row interlacing, only write the plane's channel */ if (pv->plane_interlacing || pv->row_interlacing) - stp_zfwrite((char *) ink + (plane * pv->bytes_per_ink_channel), - pv->bytes_per_ink_channel, 1, v); - else - /* print inks in correct order, eg. RGB BGR */ - for (b = 0; b < pv->ink_channels; b++) - stp_zfwrite((char *) ink + (pv->bytes_per_ink_channel * (pv->ink_order[b]-1)), - pv->bytes_per_ink_channel, 1, v); - - return 1; + memcpy(dest, (char *) ink + (plane * pv->bytes_per_ink_channel), + pv->bytes_per_ink_channel); + else /* Otherwise, print the full set of inks, in order (eg RGB or BGR) */ + for (i = 0; i < pv->ink_channels; i++) + memcpy(dest + i*pv->bytes_per_ink_channel, + (char *) ink + (pv->bytes_per_ink_channel * (pv->ink_order[i]-1)), + pv->bytes_per_ink_channel); } -static int -dyesub_print_row(stp_vars_t *v, - dyesub_print_vars_t *pv, - const dyesub_cap_t *caps, - int row, - int plane) -{ - int ret = 0; - int w, col; +static void +dyesub_render_row(stp_vars_t *v, + dyesub_print_vars_t *pv, + const dyesub_cap_t *caps, + double in_row, + char *dest, + int bytes_per_pixel, + int plane) +{ + int w; + unsigned short *src; for (w = 0; w < pv->outw_px; w++) { - col = dyesub_interpolate(w, pv->outw_px, pv->imgw_px); + double row = in_row; + double col = dyesub_interpolate(w, pv->outw_px, pv->imgw_px); if (pv->plane_lefttoright) - ret = dyesub_print_pixel(v, pv, caps, row, pv->imgw_px - col - 1, plane); - else - ret = dyesub_print_pixel(v, pv, caps, row, col, plane); - if (ret > 1) - break; + col = pv->imgw_px - col - 1; + if (pv->print_mode == DYESUB_LANDSCAPE) + { /* "rotate" image */ + dyesub_swap_doubles(&col, &row); + row = (pv->imgw_px - 1) - row; + } + // XXX FIXME: This is "point" interpolation. Be smarter! + // eg: Average (average all pixels that touch this one) + // BiLinear (scale based on linear interpolation) + // BiCubic (scale based on weighted average, based on proximity) + // Lanczos (awesome!! but slow) + src = &(pv->image_data[(int)row][(int)col * pv->out_channels]); + + dyesub_render_pixel(src, dest + w*bytes_per_pixel, + pv, caps, plane); } - return ret; } static int @@ -8469,16 +8909,36 @@ dyesub_print_plane(stp_vars_t *v, const dyesub_cap_t *caps, int plane) { - - - int ret = 0; - int h, row, p; - int out_bytes = ((pv->plane_interlacing || pv->row_interlacing) ? 1 : pv->ink_channels) + int h; + int bpp = ((pv->plane_interlacing || pv->row_interlacing) ? 1 : pv->ink_channels) * pv->bytes_per_ink_channel; + size_t rowlen = pv->prnw_px * bpp; + char *destrow = stp_malloc(rowlen); /* Allocate a buffer for the rendered rows */ + if (!destrow) + return 0; /* ? out of memory ? */ + + /* Pre-Fill in the blank bits of the row. */ + if (dyesub_feature(caps, DYESUB_FEATURE_FULL_WIDTH)) + { + /* FIXME: This is broken for bpp != 1 and packed data -- but no such models exist. */ + /* empty part left of image area */ + if (pv->outl_px > 0) + { + memset(destrow, pv->empty_byte[plane], bpp * pv->outl_px); + } + /* empty part right of image area */ + if (pv->outr_px < pv->prnw_px) + { + memset(destrow + rowlen - bpp * (pv->prnw_px - pv->outr_px), + pv->empty_byte[plane], + bpp * (pv->prnw_px - pv->outr_px)); + } + } for (h = 0; h <= pv->prnb_px - pv->prnt_px; h++) { - p = pv->row_interlacing ? 0 : plane; + int p = pv->row_interlacing ? 0 : plane; + double row; do { @@ -8493,31 +8953,25 @@ dyesub_print_plane(stp_vars_t *v, dyesub_exec(v, caps->block_init_func, "caps->block_init"); } + /* Generate a single row */ if (h + pv->prnt_px < pv->outt_px || h + pv->prnt_px >= pv->outb_px) { /* empty part above or below image area */ - dyesub_nputc(v, pv->empty_byte[plane], out_bytes * pv->prnw_px); + memset(destrow, pv->empty_byte[plane], rowlen); + /* FIXME: This is also broken for bpp != 1 and packed data */ + /* FIXME: Also this is inefficient; it won't change once generated.. */ } else { - if (dyesub_feature(caps, DYESUB_FEATURE_FULL_WIDTH) - && pv->outl_px > 0) - { /* empty part left of image area */ - dyesub_nputc(v, pv->empty_byte[plane], out_bytes * pv->outl_px); - } - row = dyesub_interpolate(h + pv->prnt_px - pv->outt_px, - pv->outh_px, pv->imgh_px); + pv->outh_px, pv->imgh_px); + stp_deprintf(STP_DBG_DYESUB, - "dyesub_print_plane: h = %d, row = %d\n", h, row); - ret = dyesub_print_row(v, pv, caps, row, p); - - if (dyesub_feature(caps, DYESUB_FEATURE_FULL_WIDTH) - && pv->outr_px < pv->prnw_px) - { /* empty part right of image area */ - dyesub_nputc(v, pv->empty_byte[plane], out_bytes - * (pv->prnw_px - pv->outr_px)); - } + "dyesub_print_plane: h = %d, row = %f\n", h, row); + + dyesub_render_row(v, pv, caps, row, destrow + bpp * pv->outl_px, bpp, p); } + /* And send it out */ + stp_zfwrite(destrow, rowlen, 1, v); if (h + pv->prnt_px == pd->block_max_h) { /* block end */ @@ -8526,7 +8980,9 @@ dyesub_print_plane(stp_vars_t *v, } while (pv->row_interlacing && ++p < pv->ink_channels); } - return ret; + + stp_free(destrow); + return 1; } /* @@ -8676,6 +9132,16 @@ dyesub_do_print(stp_vars_t *v, stp_image_t *image) stp_channel_add(v, i, 0, 1.0); pv.out_channels = stp_color_init(v, image, 65536); + /* If there's a mismatch in channels, that is ALWAYS a problem */ + if (pv.out_channels != pv.ink_channels) + { + stp_deprintf(STP_DBG_DYESUB, + "Input and output channel count mismatch! (%d vs %d)\n", pv.out_channels, pv.ink_channels); + stp_image_conclude(image); + stp_free(pd); + return 2; + } + if (dyesub_feature(caps, DYESUB_FEATURE_12BPP)) { pv.bytes_per_ink_channel = 2; pv.bits_per_ink_channel = 12; @@ -8699,11 +9165,16 @@ dyesub_do_print(stp_vars_t *v, stp_image_t *image) pv.image_data = dyesub_read_image(v, &pv, image); if (ink_type) { +#ifndef CANONSELPHYNEO_CMY if (dyesub_feature(caps, DYESUB_FEATURE_RGBtoYCBCR)) { pv.empty_byte[0] = 0xff; /* Y */ pv.empty_byte[1] = 0x80; /* Cb */ pv.empty_byte[2] = 0x80; /* Cr */ - } else if (strcmp(ink_type, "RGB") == 0 || strcmp(ink_type, "BGR") == 0 || strcmp(ink_type, "Whitescale") == 0) { + } else +#endif + if (strcmp(ink_type, "RGB") == 0 || + strcmp(ink_type, "BGR") == 0 || + strcmp(ink_type, "Whitescale") == 0) { pv.empty_byte[0] = 0xff; pv.empty_byte[1] = 0xff; pv.empty_byte[2] = 0xff; @@ -8725,6 +9196,7 @@ dyesub_do_print(stp_vars_t *v, stp_image_t *image) if (!pv.image_data) { stp_image_conclude(image); + stp_free(pd); return 2; } /* /FIXME */ |