diff --git a/package.json b/package.json index 705966a..9589fb4 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "iccery", "private": true, - "version": "0.4.0", + "version": "0.3.4", "type": "module", "scripts": { "fetch-argyll": "node scripts/fetch-argyll.mjs", diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 5e15d2a..9318cc3 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "iccery" -version = "0.4.0" +version = "0.3.4" description = "Modern Printer Profiling UI frontend for ArgyllCMS" authors = ["Gordon"] edition = "2021" diff --git a/src-tauri/src/commands.rs b/src-tauri/src/commands.rs index 9d324d8..b102778 100644 --- a/src-tauri/src/commands.rs +++ b/src-tauri/src/commands.rs @@ -319,6 +319,7 @@ pub struct PrinttargConfig { pub bit_depth: u8, // 8 or 16 #[serde(default = "default_dpi")] pub dpi: u32, // TIFF resolution, defaults to 300 DPI + pub custom_label: Option, // Custom chart label / description metadata string (-d) pub basename: String, // Must match the .ti1 basename from Stage 1 pub cwd: String, // Working directory where the .ti1 file resides } @@ -370,6 +371,11 @@ pub fn build_printtarg_args(config: &PrinttargConfig) -> Vec { config.page_size.clone(), ]; + if let Some(ref label) = config.custom_label { + args.push("-d".to_string()); + args.push(label.clone()); + } + if config.bit_depth == 16 { args.push("-T".to_string()); } else { @@ -850,6 +856,7 @@ mod tests { page_size: "A4".to_string(), bit_depth: 8, dpi: 100, + custom_label: None, basename: "my_profile".to_string(), cwd: "/tmp".to_string(), }; @@ -864,6 +871,7 @@ mod tests { page_size: "Letter".to_string(), bit_depth: 16, dpi: 300, + custom_label: None, basename: "cmyk_profile".to_string(), cwd: "/home/user".to_string(), }; @@ -878,6 +886,7 @@ mod tests { page_size: "200x400".to_string(), bit_depth: 8, dpi: 150, + custom_label: None, basename: "custom_target".to_string(), cwd: "/tmp".to_string(), }; @@ -885,6 +894,36 @@ mod tests { assert_eq!(args, vec!["-v", "-u", "-i", "SS", "-p", "200x400", "-t", "150", "custom_target"]); } + #[test] + fn test_build_printtarg_args_with_custom_label() { + let config = PrinttargConfig { + instrument: "i1".to_string(), + page_size: "A4".to_string(), + bit_depth: 8, + dpi: 300, + custom_label: Some("ICCery - Pro900 - Luster - 29/08/2026 12:00".to_string()), + basename: "my_profile".to_string(), + cwd: "/tmp".to_string(), + }; + let args = build_printtarg_args(&config); + assert_eq!( + args, + vec![ + "-v", + "-u", + "-i", + "i1", + "-p", + "A4", + "-d", + "ICCery - Pro900 - Luster - 29/08/2026 12:00", + "-t", + "300", + "my_profile" + ] + ); + } + #[test] fn test_build_chartread_args_auto() { let config = ChartreadConfig { diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index d9f51ca..a64731f 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -1,7 +1,7 @@ { "$schema": "https://schema.tauri.app/config/2", "productName": "ICCery", - "version": "0.4.0", + "version": "0.3.4", "identifier": "com.gronod.iccery", "build": { "frontendDist": "../src" diff --git a/src/index.html b/src/index.html index 207bd9f..26a023c 100644 --- a/src/index.html +++ b/src/index.html @@ -181,6 +181,43 @@ + + +
+
+ + +
+

Printed below test patches to identify hardware, ink, and media used for this profiling run.

+ +
+
+ + +
+
+ + +
+
+ +
+
+ + +
+
+ + +
+
+ + +
+ + +
+
diff --git a/src/js/printtarg.js b/src/js/printtarg.js index 61f6520..6cf1911 100644 --- a/src/js/printtarg.js +++ b/src/js/printtarg.js @@ -9,6 +9,8 @@ let stage1Cwd = ""; let currentManifest = null; let discoveredPrinters = []; +let updateLabelPreviewFn = null; + /** * Called by targen.js (or app.js) after Stage 1 completes. * Passes the basename and working directory forward. @@ -17,6 +19,9 @@ export function setStage1Result(basename, cwd) { stage1Basename = basename || wizardState.basename; stage1Cwd = cwd || wizardState.cwd; wizardState.setTarget(stage1Basename, stage1Cwd); + if (updateLabelPreviewFn) { + updateLabelPreviewFn(); + } } export function initPrinttarg() { @@ -34,6 +39,93 @@ export function initPrinttarg() { const galleryInfo = document.getElementById("galleryInfo"); const galleryGrid = document.getElementById("galleryGrid"); + // Target Label & Metadata elements (printtarg -d) + const targetMetadataPrinter = document.getElementById("targetMetadataPrinter"); + const targetMetadataInkSet = document.getElementById("targetMetadataInkSet"); + const targetMetadataDriverPaper = document.getElementById("targetMetadataDriverPaper"); + const targetMetadataActualPaper = document.getElementById("targetMetadataActualPaper"); + const targetLabelPreview = document.getElementById("targetLabelPreview"); + const btnToggleLabelEdit = document.getElementById("btnToggleLabelEdit"); + + let isManualLabelOverride = false; + + /** + * Format current local date & time into standard DD/MM/YYYY HH:MM format. + */ + function formatTimestamp(d = new Date()) { + const pad = (n) => String(n).padStart(2, "0"); + const day = pad(d.getDate()); + const month = pad(d.getMonth() + 1); + const year = d.getFullYear(); + const hours = pad(d.getHours()); + const mins = pad(d.getMinutes()); + return `${day}/${month}/${year} ${hours}:${mins}`; + } + + /** + * Assemble dynamic label string from Stage 1 run name and metadata inputs. + */ + function assembleTargetLabel() { + const parts = ["ICCery"]; + const runName = stage1Basename || wizardState.basename || ""; + if (runName.trim()) { + parts.push(runName.trim()); + } + + const printer = targetMetadataPrinter ? targetMetadataPrinter.value.trim() : ""; + if (printer) parts.push(printer); + + const inkSet = targetMetadataInkSet ? targetMetadataInkSet.value.trim() : ""; + if (inkSet) parts.push(inkSet); + + const driverPaper = targetMetadataDriverPaper ? targetMetadataDriverPaper.value.trim() : ""; + if (driverPaper) parts.push(driverPaper); + + const actualPaper = targetMetadataActualPaper ? targetMetadataActualPaper.value.trim() : ""; + if (actualPaper) parts.push(actualPaper); + + parts.push(formatTimestamp()); + return parts.join(" - "); + } + + function updateLabelPreview() { + if (!targetLabelPreview) return; + if (!isManualLabelOverride) { + targetLabelPreview.value = assembleTargetLabel(); + } + } + updateLabelPreviewFn = updateLabelPreview; + updateLabelPreview(); + + // Bind input listeners for dynamic label assembly + [targetMetadataPrinter, targetMetadataInkSet, targetMetadataDriverPaper, targetMetadataActualPaper].forEach(input => { + if (input) { + input.addEventListener("input", () => { + updateLabelPreview(); + }); + } + }); + + // Toggle between auto-assembled preview and manual edit + if (btnToggleLabelEdit && targetLabelPreview) { + btnToggleLabelEdit.addEventListener("click", () => { + isManualLabelOverride = !isManualLabelOverride; + if (isManualLabelOverride) { + targetLabelPreview.removeAttribute("readonly"); + targetLabelPreview.style.background = "var(--bg-color)"; + targetLabelPreview.style.borderColor = "var(--accent-color, #3b82f6)"; + btnToggleLabelEdit.textContent = "↺ Reset Auto"; + targetLabelPreview.focus(); + } else { + targetLabelPreview.setAttribute("readonly", true); + targetLabelPreview.style.background = "var(--bg-color)"; + targetLabelPreview.style.borderColor = "var(--border-color, #333)"; + btnToggleLabelEdit.textContent = "✏️ Edit Label"; + updateLabelPreview(); + } + }); + } + // Raw Printing UI elements const rawPrintPanel = document.getElementById("rawPrintPanel"); const printerSelect = document.getElementById("printerSelect"); @@ -302,11 +394,19 @@ export function initPrinttarg() { }); const dpi = tiffDpi && tiffDpi.value ? parseInt(tiffDpi.value, 10) || 300 : 300; + + // Obtain custom label string + let customLabel = null; + if (targetLabelPreview && targetLabelPreview.value.trim()) { + customLabel = targetLabelPreview.value.trim(); + } + const config = { instrument: instrumentSelect.value, page_size: pageSize, bit_depth: bitDepth, dpi: dpi, + custom_label: customLabel, basename: stage1Basename, cwd: stage1Cwd, };