Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ to this page; replace that summary when preparing the next release.

## Unreleased

- **Engine-aware 360/720 DPI support (driver 41.19, issue #95).** Settings now accepts reported 360 and 720 DPI square modes and keeps generic printer resolutions separate from PWG Raster and Apple Raster capabilities. This prevents a generic high-resolution mode from being offered to a raster decoder that did not advertise it, while preserving the existing marked 300* compatibility override for confirmed printers. Asymmetric modes such as 1440x720 remain intentionally hidden until MintPRINT can represent independent X/Y DPI.

- **Large jobs tolerate slow printer back-pressure (driver 41.18).** The
document-body upload now allows up to three minutes without TCP progress,
while connection, control-message and final-response timeouts remain short.
Expand Down
2 changes: 2 additions & 0 deletions docs/MINTPRINT_PREFS.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@ remain safely one-sided. See `docs/DUPLEX_PRINTING.md`.

## DPI compatibility option

DPI choices are engine-aware. Settings accepts reported square 300/360/600/720 DPI modes, uses `pwg-raster-document-resolution-supported` for PWG Raster when present, and `RS...` values from `urf-supported` for Apple Raster. Other engines use the generic `printer-resolution-supported` list. If a printer omits a format-specific list, MintPRINT falls back to the generic list for compatibility with older printers and cached profiles. Asymmetric resolutions are not shown yet because the current driver stores one capture DPI for both axes.

Query normally fills the **DPI** cycle from the printer's reported
`printer-resolution-supported` and PWG Raster resolution attributes. Some
printers under-report this list: the Canon TS8300 series advertises only 600
Expand Down
6 changes: 5 additions & 1 deletion driver/config.c
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,11 @@ LONG mp_config_load(struct MPConfig *cfg)
if (mp_cfg_starts(g_config_line, "RESOLUTION=")) {
value = g_config_line + 11;
n = mp_cfg_parse_ulong(value, &ok);
cfg->resolution = (ok && n == 600UL) ? 600 : 300;
if (ok && (n == 300UL || n == 360UL ||
n == 600UL || n == 720UL))
cfg->resolution = (UWORD)n;
else
cfg->resolution = 300;
continue;
}

Expand Down
2 changes: 1 addition & 1 deletion driver/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ struct MPConfig {
UWORD port;
char path[MP_CONFIG_PATH_MAX];
BOOL debug;
UWORD resolution; /* capture DPI: 300 or 600, see RESOLUTION= */
UWORD resolution; /* capture DPI: 300/360/600/720, see RESOLUTION= */
char engine[MP_CONFIG_ENGINE_MAX];
char media[MP_CONFIG_OPTION_MAX];
char source[MP_CONFIG_OPTION_MAX];
Expand Down
13 changes: 7 additions & 6 deletions driver/driver_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@
* MP_DRIVER_REV (the version half) only bumps for something that
* warrants a new version number outright, not on every rebuild. */
#define MP_DRIVER_REV 41
#define MP_DRIVER_SUBREV 18
#define MP_DRIVER_SUBREV 19

struct ExecBase *SysBase = NULL;
struct DosLibrary *DOSBase = NULL;
Expand Down Expand Up @@ -2374,11 +2374,12 @@ LONG PRT_STDARGS Render(LONG ct, LONG x, LONG y, LONG status, ...)
* here. 4096x6144 @ 300dpi are the historical bounds; at
* 600dpi they are doubled so common paper sizes (e.g. A4
* at 600dpi is ~4960x7014 dots) aren't clipped. */
BOOL hires = (g_config.resolution == 600);
PED->ped_MaxXDots = hires ? 8192 : 4096;
PED->ped_MaxYDots = hires ? 12288 : 6144;
PED->ped_XDotsInch = hires ? 600 : 300;
PED->ped_YDotsInch = hires ? 600 : 300;
ULONG dpi = g_config.resolution ?
(ULONG)g_config.resolution : 300UL;
PED->ped_MaxXDots = (4096UL * dpi + 150UL) / 300UL;
PED->ped_MaxYDots = (6144UL * dpi + 150UL) / 300UL;
PED->ped_XDotsInch = (UWORD)dpi;
PED->ped_YDotsInch = (UWORD)dpi;
PED->ped_NumRows = 1;
}
mp_log_3("Render pre-master special/maxX/maxY", x,
Expand Down
139 changes: 117 additions & 22 deletions src/MintPrintSettings.c
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,10 @@ int num_supported_print_modes = 0;
#define MP_MAX_DPI_OPTIONS MP_DPI_MAX_OPTIONS
int supported_dpi[MP_MAX_DPI_OPTIONS];
int num_supported_dpi = 0;
int supported_pwg_dpi[MP_MAX_DPI_OPTIONS];
int num_supported_pwg_dpi = 0;
int supported_urf_dpi[MP_MAX_DPI_OPTIONS];
int num_supported_urf_dpi = 0;
static struct MPDpiOptions mp_dpi_options = {
{ 300, 0 }, { 0, 0 }, 1, 0, 300
};
Expand Down Expand Up @@ -402,34 +406,42 @@ void store_int_value(int dest[MAX_VALUES], int *count, int val) {
dest[(*count)++] = val;
}

static void mp_add_supported_dpi(int dpi) {
static BOOL mp_dpi_value_supported(int dpi) {
return dpi == 300 || dpi == 360 || dpi == 600 || dpi == 720;
}

static void mp_add_supported_dpi_to(int *dest, int *count, int dpi) {
int i;

if (dpi != 300 && dpi != 600) return;
for (i = 0; i < num_supported_dpi; ++i) {
if (supported_dpi[i] == dpi) return;
if (!dest || !count || !mp_dpi_value_supported(dpi)) return;
for (i = 0; i < *count; ++i) {
if (dest[i] == dpi) return;
}
if (num_supported_dpi < MP_MAX_DPI_OPTIONS)
supported_dpi[num_supported_dpi++] = dpi;
if (*count < MP_MAX_DPI_OPTIONS)
dest[(*count)++] = dpi;
}

static int mp_normalise_ipp_dpi(ULONG resolution, UBYTE units) {
ULONG dpi = resolution;

if (units == 4) {
/* IPP dpcm -> dpi. Tolerances below absorb the integer rounding
* used by printers for 118dpcm/236dpcm (roughly 300/600dpi). */
/* IPP dpcm -> dpi. Real printers commonly round the dpcm
* figure, so keep a small tolerance around known modes. */
dpi = (resolution * 254UL + 50UL) / 100UL;
} else if (units != 3) {
return 0;
}

if (dpi >= 295UL && dpi <= 305UL) return 300;
if (dpi >= 355UL && dpi <= 365UL) return 360;
if (dpi >= 595UL && dpi <= 605UL) return 600;
if (dpi >= 715UL && dpi <= 725UL) return 720;
return 0;
}

static void mp_add_ipp_resolution(const UBYTE *raw, int value_len) {
static void mp_add_ipp_resolution_to(const UBYTE *raw, int value_len,
int *dest, int *count,
const char *scope) {
ULONG xres;
ULONG yres;
int xdpi;
Expand All @@ -444,11 +456,38 @@ static void mp_add_ipp_resolution(const UBYTE *raw, int value_len) {
xdpi = mp_normalise_ipp_dpi(xres, raw[8]);
ydpi = mp_normalise_ipp_dpi(yres, raw[8]);

/* The driver currently has one DPI setting for both axes, so do not
* advertise asymmetric printer resolutions it cannot represent. */
/* MintPRINT currently stores one capture DPI for both axes.
* Ignore asymmetric modes (for example Epson 1440x720) until
* the config and raster writers can represent X/Y separately. */
if (xdpi && xdpi == ydpi) {
mp_add_supported_dpi(xdpi);
printf("Printer supports %d DPI\n", xdpi);
mp_add_supported_dpi_to(dest, count, xdpi);
printf("%s supports %d DPI\n", scope ? scope : "Printer", xdpi);
}
}

static void mp_add_urf_resolutions(const char *value) {
const char *p;

if (!value || value[0] != 'R' || value[1] != 'S') return;
p = value + 2;
while (*p) {
ULONG dpi = 0;
BOOL any = FALSE;

while (*p >= '0' && *p <= '9') {
dpi = dpi * 10UL + (ULONG)(*p - '0');
any = TRUE;
++p;
}
if (any && dpi <= 32767UL &&
mp_dpi_value_supported((int)dpi)) {
mp_add_supported_dpi_to(supported_urf_dpi,
&num_supported_urf_dpi,
(int)dpi);
printf("Apple Raster supports %lu DPI\n", dpi);
}
if (*p != '-') break;
++p;
}
}

Expand Down Expand Up @@ -1676,7 +1715,9 @@ static void apply_saved_option_state(struct Window *win) {
TAG_DONE);
}

if (num_supported_dpi == 0) {
if (num_supported_dpi == 0 &&
num_supported_pwg_dpi == 0 &&
num_supported_urf_dpi == 0) {
g = find_gadget_by_id(GAD_RESOLUTION);
if (g)
GT_SetGadgetAttrs(g, win, NULL,
Expand Down Expand Up @@ -3085,11 +3126,28 @@ void update_print_mode_dropdown(struct Window *win) {

void update_dpi_dropdown(struct Window *win) {
struct Gadget *g;
const int *reported = supported_dpi;
int reported_count = num_supported_dpi;
int i;
int count;
BOOL has_compat = FALSE;

mp_dpi_build_options(supported_dpi, num_supported_dpi,
/* Generic printer-resolution-supported is not automatically a
* promise that a particular raster decoder accepts every mode.
* Prefer format-specific capabilities when the printer supplied
* them; fall back to the generic list for older/less-complete
* printers and legacy capability caches. */
if (strcmp(driver_engine_buffer, "pwg-raster") == 0 &&
num_supported_pwg_dpi > 0) {
reported = supported_pwg_dpi;
reported_count = num_supported_pwg_dpi;
} else if (strcmp(driver_engine_buffer, "urf") == 0 &&
num_supported_urf_dpi > 0) {
reported = supported_urf_dpi;
reported_count = num_supported_urf_dpi;
}

mp_dpi_build_options(reported, reported_count,
mp_dpi_engine_allows_compat(driver_engine_buffer),
driver_resolution,
driver_resolution_explicit ? 1 : 0,
Expand Down Expand Up @@ -3122,7 +3180,7 @@ void update_dpi_dropdown(struct Window *win) {
GT_SetGadgetAttrs(g, win, NULL,
GTCY_Labels, (ULONG)resolution_labels,
GTCY_Active, (ULONG)mp_dpi_options.active,
GA_Disabled, num_supported_dpi > 0 ? FALSE : TRUE,
GA_Disabled, reported_count > 0 ? FALSE : TRUE,
TAG_DONE);
RefreshGList(g, win, NULL, 1);
GT_RefreshWindow(win, NULL);
Expand Down Expand Up @@ -3470,6 +3528,8 @@ static void mp_cache_clear_capabilities(void) {
num_supported_print_modes = 0;
num_supported_quality = 0;
num_supported_dpi = 0;
num_supported_pwg_dpi = 0;
num_supported_urf_dpi = 0;
num_media_tray_mappings = 0;
has_media_ready = FALSE;
jpeg_constraints_queried = FALSE;
Expand Down Expand Up @@ -3594,6 +3654,16 @@ static BOOL mp_cache_write_file(CONST_STRPTR filename,
FPuts(fh, line);
}

for (i = 0; i < num_supported_pwg_dpi; ++i) {
snprintf(line, sizeof(line), "PWG_DPI=%d\n", supported_pwg_dpi[i]);
FPuts(fh, line);
}

for (i = 0; i < num_supported_urf_dpi; ++i) {
snprintf(line, sizeof(line), "URF_DPI=%d\n", supported_urf_dpi[i]);
FPuts(fh, line);
}

Close(fh);
return TRUE;
}
Expand Down Expand Up @@ -3766,8 +3836,18 @@ static BOOL mp_cache_load_file(CONST_STRPTR filename) {
mp_cap_cache_line + 8);
num_supported_quality++;
}
} else if (strncmp(mp_cap_cache_line, "PWG_DPI=", 8) == 0) {
mp_add_supported_dpi_to(supported_pwg_dpi,
&num_supported_pwg_dpi,
atoi(mp_cap_cache_line + 8));
} else if (strncmp(mp_cap_cache_line, "URF_DPI=", 8) == 0) {
mp_add_supported_dpi_to(supported_urf_dpi,
&num_supported_urf_dpi,
atoi(mp_cap_cache_line + 8));
} else if (strncmp(mp_cap_cache_line, "DPI=", 4) == 0) {
mp_add_supported_dpi(atoi(mp_cap_cache_line + 4));
mp_add_supported_dpi_to(supported_dpi,
&num_supported_dpi,
atoi(mp_cap_cache_line + 4));
}
}

Expand Down Expand Up @@ -8019,6 +8099,8 @@ int query_printer_attributes(const char *ip, int port, char *response, int maxle
num_supported_print_modes = 0;
num_supported_quality = 0;
num_supported_dpi = 0;
num_supported_pwg_dpi = 0;
num_supported_urf_dpi = 0;
num_media_tray_mappings = 0;
has_media_ready = FALSE;
jpeg_constraints_queried = TRUE;
Expand Down Expand Up @@ -8114,6 +8196,7 @@ int query_printer_attributes(const char *ip, int port, char *response, int maxle
"print-scaling-supported", "print-quality-supported",
"printer-resolution-default", "printer-resolution-supported",
"pwg-raster-document-resolution-supported",
"urf-supported",
"pwg-raster-document-sheet-back",
"document-format-supported", "printer-make-and-model",
"sides-supported", "operations-supported",
Expand Down Expand Up @@ -8692,11 +8775,23 @@ int query_printer_attributes(const char *ip, int port, char *response, int maxle
pwg_sheet_back_value);
}
} else if ((strcmp(name, "printer-resolution-default") == 0 ||
strcmp(name, "printer-resolution-supported") == 0 ||
strcmp(name, "pwg-raster-document-resolution-supported") == 0) &&
value_tag == 0x32 && value_len == 9) {
mp_add_ipp_resolution((const UBYTE *)ipp_start + pos - value_len,
value_len);
strcmp(name, "printer-resolution-supported") == 0) &&
value_tag == 0x32 && value_len == 9) {
mp_add_ipp_resolution_to(
(const UBYTE *)ipp_start + pos - value_len,
value_len, supported_dpi, &num_supported_dpi,
"Printer");
} else if (strcmp(name,
"pwg-raster-document-resolution-supported") == 0 &&
value_tag == 0x32 && value_len == 9) {
mp_add_ipp_resolution_to(
(const UBYTE *)ipp_start + pos - value_len,
value_len, supported_pwg_dpi,
&num_supported_pwg_dpi, "PWG Raster");
} else if (strcmp(name, "urf-supported") == 0 &&
(value_tag == 0x44 || value_tag == 0x41 ||
value_tag == 0x42)) {
mp_add_urf_resolutions(value);
} else if (strcmp(name, "print-quality-supported") == 0 &&
value_tag == 0x23 && value_len == 4) {
/* print-quality-supported is an IPP enum (RFC 8011
Expand Down
2 changes: 1 addition & 1 deletion src/dpi_options.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ int mp_dpi_engine_allows_compat(const char *engine)

static int mp_dpi_valid(int dpi)
{
return dpi == 300 || dpi == 600;
return dpi == 300 || dpi == 360 || dpi == 600 || dpi == 720;
}

static int mp_dpi_find(const struct MPDpiOptions *options, int dpi)
Expand Down
2 changes: 1 addition & 1 deletion src/dpi_options.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#ifndef MINTPRINT_DPI_OPTIONS_H
#define MINTPRINT_DPI_OPTIONS_H

#define MP_DPI_MAX_OPTIONS 2
#define MP_DPI_MAX_OPTIONS 8

struct MPDpiOptions {
int values[MP_DPI_MAX_OPTIONS];
Expand Down
27 changes: 27 additions & 0 deletions tests/test_dpi_options.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ int main(void)
struct MPDpiOptions options;
int only_600[] = { 600 };
int both[] = { 300, 600 };
int epson_generic[] = { 360, 720 };
int epson_pwg[] = { 360 };
int four_modes[] = { 300, 360, 600, 720 };

assert(mp_dpi_engine_allows_compat("pwg-raster"));
assert(mp_dpi_engine_allows_compat("urf"));
Expand Down Expand Up @@ -40,6 +43,30 @@ int main(void)
assert(options.values[0] == 300 && options.compatibility[0] == 0);
assert(options.selected == 300);


mp_dpi_build_options(epson_generic, 2, 0, 300, 0, &options);
assert(options.count == 2);
assert(options.values[0] == 360 && options.compatibility[0] == 0);
assert(options.values[1] == 720 && options.compatibility[1] == 0);
assert(options.active == 0 && options.selected == 360);

mp_dpi_build_options(epson_generic, 2, 0, 720, 1, &options);
assert(options.active == 1 && options.selected == 720);

mp_dpi_build_options(epson_pwg, 1, 1, 300, 0, &options);
assert(options.count == 2);
assert(options.values[0] == 360 && options.compatibility[0] == 0);
assert(options.values[1] == 300 && options.compatibility[1] == 1);
assert(options.active == 0 && options.selected == 360);

mp_dpi_build_options(four_modes, 4, 1, 360, 1, &options);
assert(options.count == 4);
assert(options.values[0] == 300);
assert(options.values[1] == 360);
assert(options.values[2] == 600);
assert(options.values[3] == 720);
assert(options.active == 1 && options.selected == 360);

puts("DPI option tests passed");
return 0;
}
Loading