From 9029901aac198a7bce7ad8dd3c8c2c00c58991cb Mon Sep 17 00:00:00 2001 From: akendrick <548951+akendrick@users.noreply.github.com> Date: Sun, 1 Nov 2026 18:49:47 -0700 Subject: [PATCH 1/5] Lengths in inches or millimetres (Settings) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit OpenQuad > Settings… switches every length the app shows and takes (safe edge, black outline, set sizes, print sizes, margins, the summary) between inches and millimetres; remembered in settings.json ("units"). Files, settings and the command line stay in inches. - Python: openquad.units; PrintSession.units in the summary; Settings.units - Swift core: LengthUnit, matched by new mm session vectors - App: Settings window, length steppers that step in 1 mm / 0.5 mm, mm sizes Co-Authored-By: Claude Opus 5.5 --- CHANGELOG.md | 3 ++ scripts/export_swift_vectors.py | 4 ++ src/openquad/session.py | 17 ++++-- src/openquad/settings.py | 1 + src/openquad/units.py | 52 +++++++++++++++++++ .../Sources/OpenQuad/OpenQuadApp.swift | 6 ++- .../Sources/OpenQuadUI/AppModel.swift | 18 ++++++- .../Sources/OpenQuadUI/BlockingTest.swift | 7 +-- .../Sources/OpenQuadUI/ContentView.swift | 33 +++++++----- .../Sources/OpenQuadUI/Guide.swift | 3 +- .../Sources/OpenQuadUI/Lengths.swift | 49 +++++++++++++++++ .../Tests/OpenQuadUITests/AppModelTests.swift | 15 ++++++ .../Sources/OpenQuadCore/Session.swift | 14 +++-- .../Sources/OpenQuadCore/Units.swift | 47 +++++++++++++++++ .../SessionParityTests.swift | 12 ++++- .../OpenQuadCoreTests/Vectors/session.json | 2 +- tests/test_session.py | 11 ++++ tests/test_settings.py | 7 +++ tests/test_units.py | 21 ++++++++ 19 files changed, 293 insertions(+), 29 deletions(-) create mode 100644 src/openquad/units.py create mode 100644 swift/OpenQuadApp/Sources/OpenQuadUI/Lengths.swift create mode 100644 swift/OpenQuadCore/Sources/OpenQuadCore/Units.swift create mode 100644 tests/test_units.py diff --git a/CHANGELOG.md b/CHANGELOG.md index 6b8f745..3bcae84 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,9 @@ versions follow [Semantic Versioning](https://semver.org/). ## [Unreleased] ### Added +- Millimetres: OpenQuad > Settings… (⌘,) shows and takes every length in the app (safe edge, black + outline, set sizes, print sizes, the summary) in inches or millimetres, remembered between + sessions. Files, settings and the command line stay in inches. - Ink-mixture chart for the blocking test: ten printable colours made from single inks and simple two-ink mixes (yellow, orange, red, magenta, blue, cyan, green, yellow-green, olive, black), each as a full patch and an 11-step wedge. Chosen in the app's blocking window (the diff --git a/scripts/export_swift_vectors.py b/scripts/export_swift_vectors.py index fb9804c..b46566c 100644 --- a/scripts/export_swift_vectors.py +++ b/scripts/export_swift_vectors.py @@ -836,6 +836,9 @@ def save(name: str, image: Any, **kwargs: Any) -> None: "safe_edge": 0.2, "outline": 0.15}, {"photo": "photo-grey16.tif", "mode": "negative", "max_size": [2.0, 3.0], "safe_edge": 0.25, "outline": 0.1}, + {"photo": "photo-grey16.tif", "mode": "negative", "max_size": [4.0, 5.0], + "safe_edge": 0.25, "outline": 0.0625, "units": "mm"}, + {"photo": "photo-grey16.tif", "fit": False, "ppi": 7.0, "units": "mm"}, ] # fmt: skip sessions = [] for config in configurations: @@ -856,6 +859,7 @@ def save(name: str, image: Any, **kwargs: Any) -> None: session.safe_edge = config.get("safe_edge", 0.25) session.max_size = tuple(config["max_size"]) if "max_size" in config else None session.outline = config.get("outline", 0.0) + session.set_units(config.get("units", "in")) session.printer = "Canon_MG3600_series" rendered = session.render(session._photo().pixels) sessions.append({**config, "ppi_used": session.effective_ppi(), diff --git a/src/openquad/session.py b/src/openquad/session.py index 3526f60..2585b8c 100644 --- a/src/openquad/session.py +++ b/src/openquad/session.py @@ -22,6 +22,7 @@ from openquad.paper import DEFAULT_MARGIN, PAPER_SIZES, box_ppi, fit_ppi, oriented, print_size from openquad.photo import Photo, load_photo from openquad.printing import PrintJob, Runner, run_command, send +from openquad.units import box, check, length, size FALLBACK_PPI = 300.0 @@ -54,6 +55,7 @@ class PrintSession: mirror: bool = False safe_edge: float = 0.25 outline: float = 0.0 # inches of black between the safe edge and the photo (0 = none) + units: str = "in" # how the summary shows lengths: "in" or "mm" # --- choosing things ------------------------------------------------------------ @@ -66,6 +68,9 @@ def open(self, path: str | Path) -> None: if self.photo.converted: self.notes.append("This is a colour image; it was converted to greyscale.") + def set_units(self, units: str) -> None: + self.units = check(units) + def set_preset(self, name: str) -> None: if name not in PRESETS: raise SessionError(f"unknown preset {name!r}") @@ -184,11 +189,14 @@ def _border(self) -> float: """Inches round the photo in a negative: the black outline plus the safe edge.""" return self.outline + self.safe_edge + def _length(self, inches: float) -> str: + return length(inches, self.units) + def _within(self) -> list[str]: if not (self.fit and self.max_size): return [] box_w, box_h = oriented(self.max_size, *self._photo().size) - return [f"Fit within: {box_w:g} x {box_h:g} in"] + return [f"Fit within: {box(box_w, box_h, self.units)}"] def summary(self) -> list[str]: """Lines for the print confirmation.""" @@ -196,14 +204,15 @@ def summary(self) -> list[str]: calibration = self.calibration_path.name if self.calibration_path else "none" if self.negative: process = self.process_path.name if self.process_path else "none (uncalibrated)" + outline = f" and a {self._length(self.outline)} black outline" if self.outline else "" return [ f"Photo: {self.source.name if self.source else 'untitled'}", "Output: digital negative", f"Printer: {self.printer or 'not chosen'}", f"Paper: {self.paper}", *self._within(), - f"Size: {width:.2f} x {height:.2f} in with a {self.safe_edge:g} in safe edge" - + (f" and a {self.outline:g} in black outline" if self.outline else ""), + f"Size: {size(width, height, self.units)} with a {self._length(self.safe_edge)} " + f"safe edge{outline}", f"Colour: {self.negative_colour}", f"Process curve: {process}", f"Mirrored: {'yes' if self.mirror else 'no'}", @@ -213,7 +222,7 @@ def summary(self) -> list[str]: f"Printer: {self.printer or 'not chosen'}", f"Paper: {self.paper}", *self._within(), - f"Size: {width:.2f} x {height:.2f} in at {self.effective_ppi():.0f} ppi", + f"Size: {size(width, height, self.units)} at {self.effective_ppi():.0f} ppi", f"Toning: {self.preset}", f"Calibration: {calibration}", ] diff --git a/src/openquad/settings.py b/src/openquad/settings.py index 1b1dbf4..014d1de 100644 --- a/src/openquad/settings.py +++ b/src/openquad/settings.py @@ -37,6 +37,7 @@ class Settings: process: str | None = None # digital negative process curve negative_colour: str = "green" max_size: list[float] | None = None # fit within (width, height) inches, e.g. the tissue + units: str = "in" # lengths shown in the app: "in" or "mm" @classmethod def load(cls, path: Path | None = None) -> Settings: diff --git a/src/openquad/units.py b/src/openquad/units.py new file mode 100644 index 0000000..f0bdb3e --- /dev/null +++ b/src/openquad/units.py @@ -0,0 +1,52 @@ +"""Lengths shown in inches or millimetres. + +OpenQuad works in inches throughout (files, settings, the command line); the unit only +changes what people see and type in the app and in a session's summary. +""" + +from __future__ import annotations + +UNITS = ("in", "mm") +MM_PER_INCH = 25.4 + + +def check(units: str) -> str: + if units not in UNITS: + raise ValueError(f"units must be one of {', '.join(UNITS)}, got {units!r}") + return units + + +def to_unit(inches: float, units: str) -> float: + """Inches as a number in `units`.""" + return inches * MM_PER_INCH if check(units) == "mm" else inches + + +def from_unit(value: float, units: str) -> float: + """A number in `units` as inches.""" + return value / MM_PER_INCH if check(units) == "mm" else value + + +def _trim(text: str) -> str: + return text.rstrip("0").rstrip(".") + + +def length(inches: float, units: str) -> str: + """A short length such as an edge: "0.25 in" or "6.35 mm" (to 0.01 mm).""" + if check(units) == "mm": + return f"{_trim(f'{inches * MM_PER_INCH:.2f}')} mm" + return f"{inches:g} in" + + +def box(width: float, height: float, units: str) -> str: + """A set size: "8 x 10 in" or "203.2 x 254 mm".""" + if check(units) == "mm": + w, h = (_trim(f"{v * MM_PER_INCH:.2f}") for v in (width, height)) + return f"{w} x {h} mm" + return f"{width:g} x {height:g} in" + + +def size(width: float, height: float, units: str) -> str: + """A printed size: "7.50 x 5.00 in" or "190.5 x 127.0 mm".""" + if check(units) == "mm": + return f"{width * MM_PER_INCH:.1f} x {height * MM_PER_INCH:.1f} mm" + return f"{width:.2f} x {height:.2f} in" diff --git a/swift/OpenQuadApp/Sources/OpenQuad/OpenQuadApp.swift b/swift/OpenQuadApp/Sources/OpenQuad/OpenQuadApp.swift index a074bd7..2b5a2d7 100644 --- a/swift/OpenQuadApp/Sources/OpenQuad/OpenQuadApp.swift +++ b/swift/OpenQuadApp/Sources/OpenQuad/OpenQuadApp.swift @@ -2,7 +2,7 @@ // // OpenQuad the app // OpenQuad --snapshot out.png [--photo PHOTO] [--negative] [--printer CUPS_QUEUE] [--max-size WxH] -// [--outline INCHES] +// [--outline INCHES] [--units in|mm] // OpenQuad --snapshot out.png --wizard calibration|process|blocking|guide [--scan SCAN] [--run RUN] // [--mixtures] (blocking: the ink-mixture chart) // draw the window to a PNG and quit (for checks) @@ -50,6 +50,9 @@ struct OpenQuadApp: App { Snapshot.content(model) } .defaultSize(width: 1100, height: 720) + Settings { + SettingsView(model: model) + } .commands { CommandGroup(replacing: .newItem) {} CommandGroup(replacing: .help) { @@ -83,6 +86,7 @@ enum Snapshot { if let size = value("--max-size")?.lowercased().split(separator: "x").compactMap({ Double($0) }), size.count == 2 { model.setMaxSize((size[0], size[1])) } + if let units = value("--units").flatMap(LengthUnit.init(rawValue:)) { model.setUnits(units) } if let outline = value("--outline").flatMap(Double.init) { model.setOutlineSize(outline) model.setOutline(true) diff --git a/swift/OpenQuadApp/Sources/OpenQuadUI/AppModel.swift b/swift/OpenQuadApp/Sources/OpenQuadUI/AppModel.swift index 3a36adc..b700c7d 100644 --- a/swift/OpenQuadApp/Sources/OpenQuadUI/AppModel.swift +++ b/swift/OpenQuadApp/Sources/OpenQuadUI/AppModel.swift @@ -109,6 +109,16 @@ public final class AppModel { } session.printer = settings.printer if let size = settings.maxSize, size.count == 2 { session.maxSize = (size[0], size[1]) } + session.units = settings.units + } + + /// Lengths shown and typed in the app (the session keeps inches). Remembered. + public var units: LengthUnit { settings.units } + + public func setUnits(_ units: LengthUnit) { + settings.units = units + session.units = units + try? settings.save(settingsURL) } private func remember() { @@ -242,7 +252,11 @@ public final class AppModel { // MARK: the blocking test and the calibration wizards - public func blockingTest() -> BlockingTestModel { BlockingTestModel(scannerHost: settings.scannerHost ?? "") } + public func blockingTest() -> BlockingTestModel { + let test = BlockingTestModel(scannerHost: settings.scannerHost ?? "") + test.units = settings.units + return test + } /// Make negatives in the colour the blocking test found best. public func useBlockingColour(_ colour: String, scannerHost: String) { @@ -293,7 +307,7 @@ public final class AppModel { public var sizeDescription: String { guard session.photo != nil, let (width, height) = try? session.sizeInches(), let ppi = try? session.effectivePPI() else { return "" } - var text = String(format: "%.2f x %.2f in at %.0f ppi", width, height, ppi) + var text = "\(units.size(width, height)) at \(String(format: "%.0f", ppi)) ppi" if (try? session.fitsOnPaper()) == false { text += "\nLarger than the paper: turn on Fit or lower the size." } return text } diff --git a/swift/OpenQuadApp/Sources/OpenQuadUI/BlockingTest.swift b/swift/OpenQuadApp/Sources/OpenQuadUI/BlockingTest.swift index 5c30eda..d27cea6 100644 --- a/swift/OpenQuadApp/Sources/OpenQuadUI/BlockingTest.swift +++ b/swift/OpenQuadApp/Sources/OpenQuadUI/BlockingTest.swift @@ -18,6 +18,8 @@ public final class BlockingTestModel: WizardModel { public var chart = ChartKind.standard public var mirror = false public var safeEdge = 0.25 + /// Lengths shown in the window (the app's setting). + public var units = LengthUnit.inches public private(set) var report: BlockingReport? public private(set) var scanName: String? @@ -127,9 +129,8 @@ public struct BlockingTestView: View { } .pickerStyle(.segmented) Toggle("Mirror the sheet", isOn: $model.mirror) - Stepper(value: $model.safeEdge, in: 0...1, step: 0.05) { - LabeledContent("Safe edge", value: String(format: "%.2f in", model.safeEdge)) - } + LengthStepper(title: "Safe edge", inches: model.safeEdge, range: 0...1, inchStep: 0.05, mmStep: 1, + units: model.units) { model.safeEdge = $0 } LabeledContent("Scanner") { ScannerField(model: model) } } .formStyle(.grouped) diff --git a/swift/OpenQuadApp/Sources/OpenQuadUI/ContentView.swift b/swift/OpenQuadApp/Sources/OpenQuadUI/ContentView.swift index 1d4a9cc..eaf71f4 100644 --- a/swift/OpenQuadApp/Sources/OpenQuadUI/ContentView.swift +++ b/swift/OpenQuadApp/Sources/OpenQuadUI/ContentView.swift @@ -73,7 +73,7 @@ public struct ContentView: View { Picker("Paper", selection: Binding(get: { model.session.paper }, set: { model.setPaper($0) })) { ForEach(paperOrder, id: \.self) { Text($0).tag($0) } } - Toggle("Fit to page (0.5 in margins)", isOn: Binding(get: { model.session.fit }, set: { model.setFit($0) })) + Toggle("Fit to page (\(model.units.length(model.session.margin)) margins)", isOn: Binding(get: { model.session.fit }, set: { model.setFit($0) })) if model.session.fit { fitWithin } TextField("Resolution (ppi)", text: $ppiText, prompt: Text("photo's own")) .disabled(model.session.fit) @@ -118,21 +118,26 @@ public struct ContentView: View { Text("A set size").tag(true) } if let size = model.session.maxSize { + let units = model.units LabeledContent(model.session.negative ? "Outer size" : "Size") { HStack(spacing: 6) { - TextField("Width", value: Binding(get: { size.0 }, set: { model.setMaxSize(($0, size.1)) }), + TextField("Width", value: Binding(get: { units.fromInches(size.0) }, + set: { model.setMaxSize((units.toInches($0), size.1)) }), format: .number.precision(.fractionLength(0...2))) .frame(width: 56) .multilineTextAlignment(.trailing) Text("×") - TextField("Height", value: Binding(get: { size.1 }, set: { model.setMaxSize((size.0, $0)) }), + TextField("Height", value: Binding(get: { units.fromInches(size.1) }, + set: { model.setMaxSize((size.0, units.toInches($0))) }), format: .number.precision(.fractionLength(0...2))) .frame(width: 56) .multilineTextAlignment(.trailing) - Text("in") + Text(units.rawValue) Menu("Sizes") { - ForEach([(4.0, 5.0), (5.0, 7.0), (6.0, 8.0), (8.0, 10.0), (11.0, 14.0)], id: \.0) { w, h in - Button(String(format: "%g × %g in", w, h)) { model.setMaxSize((w, h)) } + ForEach(Self.setSizes(units), id: \.0) { w, h in + Button(units == .millimetres ? String(format: "%g × %g mm", w, h) : String(format: "%g × %g in", w, h)) { + model.setMaxSize((units.toInches(w), units.toInches(h))) + } } } .fixedSize() @@ -170,6 +175,12 @@ public struct ContentView: View { } } + /// Usual tissue and paper sizes to offer, in the app's unit. + static func setSizes(_ units: LengthUnit) -> [(Double, Double)] { + units == .millimetres ? [(100, 125), (130, 180), (180, 240), (210, 297), (240, 300)] + : [(4, 5), (5, 7), (6, 8), (8, 10), (11, 14)] + } + @ViewBuilder private var negativeControls: some View { Picker("Ink colour", selection: Binding(get: { model.session.negativeColour }, set: { model.setNegativeColour($0) })) { ForEach(Negative.colourOrder, id: \.self) { Text($0.capitalized).tag($0) } @@ -180,14 +191,12 @@ public struct ContentView: View { Button("Calibrate a Process…", action: openProcessWizard) Button("Find the Best Blocking Colour…", action: openBlockingTest) Toggle("Mirror (flip left to right)", isOn: Binding(get: { model.session.mirror }, set: { model.setMirror($0) })) - Stepper(value: Binding(get: { model.session.safeEdge }, set: { model.setSafeEdge($0) }), in: 0...2, step: 0.05) { - LabeledContent("Safe edge", value: String(format: "%.2f in", model.session.safeEdge)) - } + LengthStepper(title: "Safe edge", inches: model.session.safeEdge, range: 0...2, inchStep: 0.05, mmStep: 1, + units: model.units) { model.setSafeEdge($0) } Toggle("Outline in black", isOn: Binding(get: { model.session.outline > 0 }, set: { model.setOutline($0) })) if model.session.outline > 0 { - Stepper(value: Binding(get: { model.outlineSize }, set: { model.setOutlineSize($0) }), in: 0.01...1, step: 0.01) { - LabeledContent("Outline width", value: String(format: "%.2f in", model.outlineSize)) - } + LengthStepper(title: "Outline width", inches: model.outlineSize, range: 0.01...1, inchStep: 0.01, mmStep: 0.5, + units: model.units) { model.setOutlineSize($0) } Text("A black border inside the safe edge, so photos with white or light edges still print with a frame.") .font(.caption) .foregroundStyle(.secondary) diff --git a/swift/OpenQuadApp/Sources/OpenQuadUI/Guide.swift b/swift/OpenQuadApp/Sources/OpenQuadUI/Guide.swift index 8572740..4852ce6 100644 --- a/swift/OpenQuadApp/Sources/OpenQuadUI/Guide.swift +++ b/swift/OpenQuadApp/Sources/OpenQuadUI/Guide.swift @@ -5,7 +5,7 @@ import SwiftUI public struct GuideView: View { /// Raise when the guide changes enough to show it again on launch. - public static let version = 8 + public static let version = 9 public static let showNotification = Notification.Name("OpenQuadShowGuide") struct Page { @@ -59,6 +59,7 @@ public struct GuideView: View { + "mirror setting was right.", "Outline in black adds a black border of the width you set between the safe edge and the " + "photo: a natural frame for photos with white or light edges.", + "Prefer millimetres? OpenQuad > Settings… (⌘,) switches every length in the app to mm.", "Tissue smaller than the page? Under Page, set Fit within to A set size (e.g. 8 × 10 in): " + "that becomes the negative's outer edge, safe edge included, and the photo shrinks to fit.", "Print on transparency film at 100% with your usual film settings."]), diff --git a/swift/OpenQuadApp/Sources/OpenQuadUI/Lengths.swift b/swift/OpenQuadApp/Sources/OpenQuadUI/Lengths.swift new file mode 100644 index 0000000..48a0c78 --- /dev/null +++ b/swift/OpenQuadApp/Sources/OpenQuadUI/Lengths.swift @@ -0,0 +1,49 @@ +// Lengths in the app's chosen unit (Settings: inches or millimetres). The model always +// keeps inches; these views convert for showing and typing. + +import OpenQuadCore +import SwiftUI + +/// A stepper for a length kept in inches, shown and stepped in `units`. +struct LengthStepper: View { + let title: String + let inches: Double + /// Allowed values, in inches. + let range: ClosedRange + let inchStep: Double + let mmStep: Double + let units: LengthUnit + let set: (Double) -> Void + + var body: some View { + let step = units == .millimetres ? mmStep : inchStep + Stepper(value: Binding(get: { units.fromInches(inches) }, + set: { set(units.toInches(($0 / step).rounded() * step)) }), + in: units.fromInches(range.lowerBound)...units.fromInches(range.upperBound), step: step) { + LabeledContent(title, value: units == .millimetres ? units.length(inches) : String(format: "%.2f in", inches)) + } + } +} + +/// The app's settings window (OpenQuad > Settings…). +public struct SettingsView: View { + @Bindable var model: AppModel + + public init(model: AppModel) { self.model = model } + + public var body: some View { + Form { + Picker("Lengths in", selection: Binding(get: { model.units }, set: { model.setUnits($0) })) { + Text("Inches").tag(LengthUnit.inches) + Text("Millimetres").tag(LengthUnit.millimetres) + } + .pickerStyle(.segmented) + Text("Safe edge, black outline, set sizes and print sizes are shown and typed in this unit.") + .font(.caption) + .foregroundStyle(.secondary) + } + .formStyle(.grouped) + .frame(width: 420) + .fixedSize() + } +} diff --git a/swift/OpenQuadApp/Tests/OpenQuadUITests/AppModelTests.swift b/swift/OpenQuadApp/Tests/OpenQuadUITests/AppModelTests.swift index 10981b0..c6ce751 100644 --- a/swift/OpenQuadApp/Tests/OpenQuadUITests/AppModelTests.swift +++ b/swift/OpenQuadApp/Tests/OpenQuadUITests/AppModelTests.swift @@ -87,6 +87,21 @@ struct AppModelTests { #expect(negative.width == 60 + 2 * (90 + 75)) // 0.3 in outline + 0.25 in safe edge at 300 ppi } + @Test func lengthsCanBeShownInMillimetresAndAreRemembered() throws { + let m = model() + #expect(m.units == .inches) + m.openPhoto(photo) // 60 x 40 px at 300 ppi + m.setFit(false) + m.setUnits(.millimetres) + #expect(m.sizeDescription.hasPrefix("5.1 x 3.4 mm at 300 ppi")) + m.setMode(.negative) + m.setSafeEdge(LengthUnit.millimetres.toInches(5)) + #expect(m.summary.joined().contains("with a 5 mm safe edge")) + #expect(model().units == .millimetres && model().session.units == .millimetres) + m.setUnits(.inches) + #expect(m.summary.joined().contains("with a 0.19685 in safe edge") && model().units == .inches) + } + @Test func negativesAndErrors() throws { let m = model() m.openPhoto(photo) diff --git a/swift/OpenQuadCore/Sources/OpenQuadCore/Session.swift b/swift/OpenQuadCore/Sources/OpenQuadCore/Session.swift index 461025c..fb5cf1a 100644 --- a/swift/OpenQuadCore/Sources/OpenQuadCore/Session.swift +++ b/swift/OpenQuadCore/Sources/OpenQuadCore/Session.swift @@ -39,6 +39,8 @@ public struct PrintSession: Sendable { public var safeEdge = 0.25 /// Inches of black between the safe edge and the photo (0 = none). public var outline = 0.0 + /// How the summary shows lengths. + public var units = LengthUnit.inches public init() {} @@ -198,11 +200,11 @@ public struct PrintSession: Sendable { public func summary() throws -> [String] { let (width, height) = try sizeInches() let photoName = source?.lastPathComponent ?? "untitled" - let size = String(format: "%.2f x %.2f in", width, height) + let size = units.size(width, height) var within: [String] = [] if fit, let maxSize, let photo { let (w, h) = Paper.oriented(maxSize, width: photo.width, height: photo.height) - within = [String(format: "Fit within: %g x %g in", w, h)] + within = ["Fit within: \(units.box(w, h))"] } if negative { return [ @@ -211,8 +213,8 @@ public struct PrintSession: Sendable { "Printer: \(printer ?? "not chosen")", "Paper: \(paper)", ] + within + [ - "Size: \(size) with a \(String(format: "%g", safeEdge)) in safe edge" - + (outline != 0 ? " and a \(String(format: "%g", outline)) in black outline" : ""), + "Size: \(size) with a \(units.length(safeEdge)) safe edge" + + (outline != 0 ? " and a \(units.length(outline)) black outline" : ""), "Colour: \(negativeColour)", "Process curve: \(processPath?.lastPathComponent ?? "none (uncalibrated)")", "Mirrored: \(mirror ? "yes" : "no")", @@ -265,6 +267,8 @@ public struct AppSettings: Sendable, Equatable { public var negativeColour = "green" /// Fit within (width, height) inches, e.g. the carbon tissue; nil for the page. public var maxSize: [Double]? + /// Lengths shown in the app. + public var units = LengthUnit.inches public init() {} @@ -291,6 +295,7 @@ public struct AppSettings: Sendable, Equatable { settings.process = object["process"] as? String settings.negativeColour = object["negative_colour"] as? String ?? "green" if let size = object["max_size"] as? [NSNumber], size.count == 2 { settings.maxSize = size.map(\.doubleValue) } + settings.units = (object["units"] as? String).flatMap(LengthUnit.init(rawValue:)) ?? .inches return settings } @@ -300,6 +305,7 @@ public struct AppSettings: Sendable, Equatable { "printer": printer ?? NSNull(), "scanner_host": scannerHost ?? NSNull(), "paper": paper, "calibration": calibration ?? NSNull(), "last_folder": lastFolder ?? NSNull(), "process": process ?? NSNull(), "negative_colour": negativeColour, "max_size": maxSize ?? NSNull(), + "units": units.rawValue, ] var data = try JSONSerialization.data(withJSONObject: object, options: [.prettyPrinted, .sortedKeys]) data.append(0x0a) diff --git a/swift/OpenQuadCore/Sources/OpenQuadCore/Units.swift b/swift/OpenQuadCore/Sources/OpenQuadCore/Units.swift new file mode 100644 index 0000000..1c39d0f --- /dev/null +++ b/swift/OpenQuadCore/Sources/OpenQuadCore/Units.swift @@ -0,0 +1,47 @@ +// Lengths shown in inches or millimetres. Mirrors openquad/units.py: OpenQuad works in +// inches throughout (files, settings); the unit only changes what people see and type. + +import Foundation + +public enum LengthUnit: String, CaseIterable, Sendable { + case inches = "in" + case millimetres = "mm" + + public static let mmPerInch = 25.4 + + /// Inches as a number in this unit. + public func fromInches(_ inches: Double) -> Double { self == .millimetres ? inches * Self.mmPerInch : inches } + + /// A number in this unit as inches. + public func toInches(_ value: Double) -> Double { self == .millimetres ? value / Self.mmPerInch : value } + + static func trim(_ text: String) -> String { + guard text.contains(".") else { return text } + var text = text + while text.hasSuffix("0") { text.removeLast() } + if text.hasSuffix(".") { text.removeLast() } + return text + } + + /// A short length such as an edge: "0.25 in" or "6.35 mm" (to 0.01 mm). + public func length(_ inches: Double) -> String { + self == .millimetres ? "\(Self.trim(String(format: "%.2f", inches * Self.mmPerInch))) mm" + : "\(String(format: "%g", inches)) in" + } + + /// A set size: "8 x 10 in" or "203.2 x 254 mm". + public func box(_ width: Double, _ height: Double) -> String { + if self == .millimetres { + let w = Self.trim(String(format: "%.2f", width * Self.mmPerInch)) + let h = Self.trim(String(format: "%.2f", height * Self.mmPerInch)) + return "\(w) x \(h) mm" + } + return String(format: "%g x %g in", width, height) + } + + /// A printed size: "7.50 x 5.00 in" or "190.5 x 127.0 mm". + public func size(_ width: Double, _ height: Double) -> String { + self == .millimetres ? String(format: "%.1f x %.1f mm", width * Self.mmPerInch, height * Self.mmPerInch) + : String(format: "%.2f x %.2f in", width, height) + } +} diff --git a/swift/OpenQuadCore/Tests/OpenQuadCoreTests/SessionParityTests.swift b/swift/OpenQuadCore/Tests/OpenQuadCoreTests/SessionParityTests.swift index 1c4a9a2..1849db8 100644 --- a/swift/OpenQuadCore/Tests/OpenQuadCoreTests/SessionParityTests.swift +++ b/swift/OpenQuadCore/Tests/OpenQuadCoreTests/SessionParityTests.swift @@ -46,6 +46,7 @@ struct SessionParity { session.safeEdge = (c["safe_edge"] as? NSNumber)?.doubleValue ?? 0.25 if let box = c["max_size"] as? [NSNumber] { session.maxSize = (box[0].doubleValue, box[1].doubleValue) } session.outline = (c["outline"] as? NSNumber)?.doubleValue ?? 0 + session.units = LengthUnit(rawValue: c["units"] as? String ?? "in")! session.printer = "Canon_MG3600_series" #expect(abs(try session.effectivePPI() - (c["ppi_used"] as! NSNumber).doubleValue) < 1e-9) @@ -97,9 +98,18 @@ struct SessionParity { settings.printer = "Canon_MG3600_series" settings.scannerHost = "876298000000.local:80" settings.negativeColour = "orange" + settings.units = .millimetres try settings.save(url) #expect(AppSettings.load(url) == settings) let text = try String(contentsOf: url, encoding: .utf8) - #expect(text.contains("\"scanner_host\"") && !text.contains("preset")) + #expect(text.contains("\"scanner_host\"") && !text.contains("preset") && text.contains("\"mm\"")) + } + + @Test func lengthsInEitherUnit() { + #expect(LengthUnit.inches.length(0.25) == "0.25 in" && LengthUnit.millimetres.length(0.25) == "6.35 mm") + #expect(LengthUnit.millimetres.length(LengthUnit.millimetres.toInches(5)) == "5 mm") + #expect(LengthUnit.inches.box(8, 10) == "8 x 10 in" && LengthUnit.millimetres.box(8, 10) == "203.2 x 254 mm") + #expect(LengthUnit.inches.size(7.5, 5) == "7.50 x 5.00 in" && LengthUnit.millimetres.size(7.5, 5) == "190.5 x 127.0 mm") + #expect(abs(LengthUnit.millimetres.fromInches(1) - 25.4) < 1e-12 && LengthUnit.inches.fromInches(0.37) == 0.37) } } diff --git a/swift/OpenQuadCore/Tests/OpenQuadCoreTests/Vectors/session.json b/swift/OpenQuadCore/Tests/OpenQuadCoreTests/Vectors/session.json index 3f13fee..faa6cf9 100644 --- a/swift/OpenQuadCore/Tests/OpenQuadCoreTests/Vectors/session.json +++ b/swift/OpenQuadCore/Tests/OpenQuadCoreTests/Vectors/session.json @@ -1 +1 @@ -{"photos":[{"file":"photo-grey.png","shape":[18,24],"pixels":[0,2827,5654,8481,11308,14135,16962,19789,22616,25443,28270,31097,34181,37008,39835,42662,45489,48316,51143,53970,56797,59624,62451,65535,0,2827,5654,8481,11308,14135,16962,19789,22616,25443,28270,31097,34181,37008,39835,42662,45489,48316,51143,53970,56797,59624,62451,65535,0,2827,5654,8481,11308,14135,16962,19789,22616,25443,28270,31097,34181,37008,39835,42662,45489,48316,51143,53970,56797,59624,62451,65535,0,2827,5654,8481,11308,14135,16962,19789,22616,25443,28270,31097,34181,37008,39835,42662,45489,48316,51143,53970,56797,59624,62451,65535,0,2827,5654,8481,11308,14135,16962,19789,22616,25443,28270,31097,34181,37008,39835,42662,45489,48316,51143,53970,56797,59624,62451,65535,0,2827,5654,8481,11308,14135,16962,19789,22616,25443,28270,31097,34181,37008,39835,42662,45489,48316,51143,53970,56797,59624,62451,65535,0,2827,5654,8481,11308,14135,16962,19789,22616,25443,28270,31097,34181,37008,39835,42662,45489,48316,51143,53970,56797,59624,62451,65535,0,2827,5654,8481,11308,14135,16962,19789,22616,25443,28270,31097,34181,37008,39835,42662,45489,48316,51143,53970,56797,59624,62451,65535,0,2827,5654,8481,11308,14135,16962,19789,22616,25443,28270,31097,34181,37008,39835,42662,45489,48316,51143,53970,56797,59624,62451,65535,0,2827,5654,8481,11308,14135,16962,19789,22616,25443,28270,31097,34181,37008,39835,42662,45489,48316,51143,53970,56797,59624,62451,65535,0,2827,5654,8481,11308,14135,16962,19789,22616,25443,28270,31097,34181,37008,39835,42662,45489,48316,51143,53970,56797,59624,62451,65535,0,2827,5654,8481,11308,14135,16962,19789,22616,25443,28270,31097,34181,37008,39835,42662,45489,48316,51143,53970,56797,59624,62451,65535,0,2827,5654,8481,11308,14135,16962,19789,22616,25443,28270,31097,34181,37008,39835,42662,45489,48316,51143,53970,56797,59624,62451,65535,0,2827,5654,8481,11308,14135,16962,19789,22616,25443,28270,31097,34181,37008,39835,42662,45489,48316,51143,53970,56797,59624,62451,65535,0,2827,5654,8481,11308,14135,16962,19789,22616,25443,28270,31097,34181,37008,39835,42662,45489,48316,51143,53970,56797,59624,62451,65535,0,2827,5654,8481,11308,14135,16962,19789,22616,25443,28270,31097,34181,37008,39835,42662,45489,48316,51143,53970,56797,59624,62451,65535,0,2827,5654,8481,11308,14135,16962,19789,22616,25443,28270,31097,34181,37008,39835,42662,45489,48316,51143,53970,56797,59624,62451,65535,0,2827,5654,8481,11308,14135,16962,19789,22616,25443,28270,31097,34181,37008,39835,42662,45489,48316,51143,53970,56797,59624,62451,65535],"dpi":[299.9994,299.9994],"converted":false,"cropped":false},{"file":"photo-rgb-grey.png","shape":[18,24],"pixels":[238,2774,5691,8427,11363,13971,16724,19735,22397,25700,28087,31281,34016,36935,39835,42478,45709,48371,50996,53989,56761,59863,62304,65351,19,2774,5619,8666,11181,14172,16816,19919,22543,25462,28216,30969,34200,37174,39597,42589,45361,48446,51070,54209,56779,59790,62286,65535,55,2723,5619,8243,11235,13878,16944,19735,22598,25370,28400,30895,34347,36824,40074,42644,45600,48555,51198,53823,56981,59624,62671,65516,0,2723,5453,8720,11125,13952,16908,19735,22855,25278,28436,31152,34071,37138,39890,42460,45251,48187,51382,54025,56963,59495,62341,65351,184,2846,5728,8298,11144,13878,16889,19661,22507,25425,28252,31061,34181,36806,39725,42735,45728,48389,51382,53952,56613,59551,62433,65480,0,2809,5857,8738,11051,14154,16908,19844,22855,25296,28344,31300,34053,37008,40055,42589,45655,48555,51216,53823,56908,59754,62599,65480,0,3049,5691,8463,11308,13878,16724,19587,22414,25407,28400,30895,34163,37008,39854,42589,45342,48243,50996,53989,56927,59440,62581,65516,0,2703,5769,8631,11529,13989,16743,19808,22616,25315,28325,30895,34420,36972,39578,42552,45251,48464,50941,53786,56540,59844,62378,65535,202,3049,5709,8224,11308,14100,17017,19643,22562,25462,28473,30950,34420,36824,40055,42698,45709,48243,51107,53805,56816,59367,62635,65462,184,2902,5709,8243,11382,14135,17128,19551,22855,25663,28050,31043,34016,37120,39707,42478,45489,48335,51179,53786,56559,59459,62396,65535,19,2723,5839,8243,11235,14062,17128,19919,22616,25480,28234,30895,34365,36972,39615,42792,45637,48555,50886,53860,56927,59551,62451,65351,55,3049,5548,8317,11089,13971,16760,20009,22378,25646,28289,31043,34071,37156,39908,42882,45269,48573,51088,54209,56963,59808,62524,65297,0,2626,5619,8536,11070,14338,16981,19973,22451,25480,28509,31300,34330,36806,39854,42792,45269,48096,51070,54006,57017,59660,62599,65516,73,2774,5636,8446,11474,14008,17074,19587,22836,25663,28436,31079,34347,37120,39983,42681,45269,48261,51179,54172,56742,59606,62322,65278,55,2902,5805,8684,11345,14209,17093,20046,22819,25296,28270,31281,34053,37063,40038,42810,45525,48500,51014,54043,56687,59367,62708,65516,0,2703,5875,8738,11529,14117,16724,19844,22414,25296,28142,31209,34254,36843,39578,42424,45416,48536,50996,53970,56816,59826,62231,65333,19,2755,5416,8374,11106,13916,16779,19919,22873,25407,28325,31317,34163,36954,39597,42442,45746,48261,51216,53915,56981,59660,62267,65351,202,3012,5709,8595,11458,13989,17201,19606,22873,25443,28289,31300,34311,36824,39578,42644,45471,48482,51273,54100,56577,59624,62708,65351],"dpi":null,"converted":true,"cropped":false},{"file":"photo-colour.png","shape":[18,24],"pixels":[20004,51931,45197,31721,29001,49960,29883,30349,28793,37632,57980,24992,29115,25524,33530,19881,43801,44336,23251,32502,45178,20057,41113,28519,24685,55850,26342,33246,23775,61970,35767,57209,48789,20245,48799,31359,54551,37715,29220,56383,17281,51563,15489,43931,53315,19758,54459,14262,35037,32478,38516,35477,51544,24273,55311,31966,26925,19291,42250,19441,25620,46095,25583,43990,26066,47113,17178,54015,40737,24912,4537,49967,34197,24653,43386,45464,46951,12793,55381,16687,28991,35200,39873,29140,52473,39206,24827,24276,20100,52143,44719,41457,31490,33001,34195,49676,12714,33862,40152,50064,51202,37942,54476,41114,27539,12277,47198,31214,44981,54838,39695,27247,35216,29028,48347,42389,18099,42490,27218,48631,40027,41628,39290,51977,36373,29165,31120,45934,27745,55674,45011,33361,28377,44639,34018,47080,16399,55779,44277,29962,27321,55620,47002,54854,57034,31002,37087,22295,49719,42759,31773,12270,47290,20596,48910,24954,25456,44271,59144,34675,24282,21718,29151,21187,42935,35622,24503,15385,49385,20919,40094,30982,32690,36318,22952,45706,32776,56342,23884,26403,37047,22242,21976,34167,52030,46957,10710,59989,34875,16014,18418,63782,29715,29394,30863,29327,48130,51054,27231,47157,40701,43314,34859,53857,24948,9951,28495,36877,32641,26948,46600,49434,58296,9074,31756,14748,52954,61921,58281,54425,33138,33573,40709,57895,39501,50935,21260,33950,28091,23711,42983,48839,35605,27466,30732,52417,28429,41185,45774,21742,16826,27137,53043,30717,26662,29546,32655,46381,26203,28826,53814,47099,45783,54394,48724,26419,38200,33113,34468,26965,14915,48925,46042,28954,47182,41859,37544,48254,22580,39194,15724,41098,15782,44708,18373,34234,44697,20231,39827,21417,60879,36920,49509,44215,45485,50293,56853,53008,45948,35748,19138,34400,40352,28612,53916,15105,49538,30146,13329,48946,35179,23585,22194,15697,43557,28380,37201,43609,35178,49065,31979,61224,19718,41208,34451,28236,20782,32282,23110,55080,16206,38232,21411,48696,56876,35139,44025,40494,45808,39721,21365,38839,38764,44221,13298,50380,52561,34849,30182,25843,30454,12125,18682,49974,29721,40139,25503,39964,41728,19119,15587,20109,41580,43044,58809,27476,29748,37415,53448,17350,46778,53178,31811,37478,35822,43379,13052,58645,33568,37676,26239,15851,42866,60075,6430,44481,42181,48035,56913,31531,16010,35337,23508,40934,24892,43758,28154,38113,28053,16826,31055,39373,52053,43600,32676,17533,5789,38278,28827,24158,26227,27290,40995,53740,30011,36237,57624,35749,37429,48815,34263,46957,15979,24727,40332,47492,33726,37325,35338,27799,27115,28649,32099,56872,43633,7112,54129,13069,47070,39435,34653,43515],"dpi":[240.00459999999998,240.00459999999998],"converted":true,"cropped":false},{"file":"photo-rgba.png","shape":[14,21],"pixels":[184,2846,5728,8298,11144,13878,16889,19661,22507,25425,28252,31061,34181,36806,39725,42735,45728,48389,51382,53952,56613,0,2809,5857,8738,11051,14154,16908,19844,22855,25296,28344,31300,34053,37008,40055,42589,45655,48555,51216,53823,56908,0,3049,5691,8463,11308,13878,16724,19587,22414,25407,28400,30895,34163,37008,39854,42589,45342,48243,50996,53989,56927,0,2703,5769,8631,11529,13989,16743,19808,22616,25315,28325,30895,34420,36972,39578,42552,45251,48464,50941,53786,56540,202,3049,5709,8224,11308,39716,41181,42499,43964,25462,28473,30950,34420,36824,40055,42698,45709,48243,51107,53805,56816,184,2902,5709,8243,11382,39734,41237,42453,44111,25663,28050,31043,34016,37120,39707,42478,45489,48335,51179,53786,56559,19,2723,5839,8243,11235,39698,41237,42638,43991,25480,28234,30895,34365,36972,39615,42792,45637,48555,50886,53860,56927,55,3049,5548,8317,11089,39652,41052,42683,43872,25646,28289,31043,34071,37156,39908,42882,45269,48573,51088,54209,56963,0,2626,5619,8536,11070,14338,16981,19973,22451,25480,28509,31300,34330,36806,39854,42792,45269,48096,51070,54006,57017,73,2774,5636,8446,11474,14008,17074,19587,22836,25663,28436,31079,34347,37120,39983,42681,45269,48261,51179,54172,56742,55,2902,5805,8684,11345,14209,17093,20046,22819,25296,28270,31281,34053,37063,40038,42810,45525,48500,51014,54043,56687,0,2703,5875,8738,11529,14117,16724,19844,22414,25296,28142,31209,34254,36843,39578,42424,45416,48536,50996,53970,56816,19,2755,5416,8374,11106,13916,16779,19919,22873,25407,28325,31317,34163,36954,39597,42442,45746,48261,51216,53915,56981,202,3012,5709,8595,11458,13989,17201,19606,22873,25443,28289,31300,34311,36824,39578,42644,45471,48482,51273,54100,56577],"dpi":null,"converted":true,"cropped":true},{"file":"photo-la.png","shape":[18,24],"pixels":[50115,50780,51445,52111,52776,53441,54106,54771,55436,56102,56767,57432,34181,37008,39835,42662,45489,48316,51143,53970,56797,59624,62451,65535,50115,50780,51445,52111,52776,53441,54106,54771,55436,56102,56767,57432,34181,37008,39835,42662,45489,48316,51143,53970,56797,59624,62451,65535,50115,50780,51445,52111,52776,53441,54106,54771,55436,56102,56767,57432,34181,37008,39835,42662,45489,48316,51143,53970,56797,59624,62451,65535,50115,50780,51445,52111,52776,53441,54106,54771,55436,56102,56767,57432,34181,37008,39835,42662,45489,48316,51143,53970,56797,59624,62451,65535,50115,50780,51445,52111,52776,53441,54106,54771,55436,56102,56767,57432,34181,37008,39835,42662,45489,48316,51143,53970,56797,59624,62451,65535,50115,50780,51445,52111,52776,53441,54106,54771,55436,56102,56767,57432,34181,37008,39835,42662,45489,48316,51143,53970,56797,59624,62451,65535,50115,50780,51445,52111,52776,53441,54106,54771,55436,56102,56767,57432,34181,37008,39835,42662,45489,48316,51143,53970,56797,59624,62451,65535,50115,50780,51445,52111,52776,53441,54106,54771,55436,56102,56767,57432,34181,37008,39835,42662,45489,48316,51143,53970,56797,59624,62451,65535,50115,50780,51445,52111,52776,53441,54106,54771,55436,56102,56767,57432,34181,37008,39835,42662,45489,48316,51143,53970,56797,59624,62451,65535,50115,50780,51445,52111,52776,53441,54106,54771,55436,56102,56767,57432,34181,37008,39835,42662,45489,48316,51143,53970,56797,59624,62451,65535,50115,50780,51445,52111,52776,53441,54106,54771,55436,56102,56767,57432,34181,37008,39835,42662,45489,48316,51143,53970,56797,59624,62451,65535,50115,50780,51445,52111,52776,53441,54106,54771,55436,56102,56767,57432,34181,37008,39835,42662,45489,48316,51143,53970,56797,59624,62451,65535,50115,50780,51445,52111,52776,53441,54106,54771,55436,56102,56767,57432,34181,37008,39835,42662,45489,48316,51143,53970,56797,59624,62451,65535,50115,50780,51445,52111,52776,53441,54106,54771,55436,56102,56767,57432,34181,37008,39835,42662,45489,48316,51143,53970,56797,59624,62451,65535,50115,50780,51445,52111,52776,53441,54106,54771,55436,56102,56767,57432,34181,37008,39835,42662,45489,48316,51143,53970,56797,59624,62451,65535,50115,50780,51445,52111,52776,53441,54106,54771,55436,56102,56767,57432,34181,37008,39835,42662,45489,48316,51143,53970,56797,59624,62451,65535,50115,50780,51445,52111,52776,53441,54106,54771,55436,56102,56767,57432,34181,37008,39835,42662,45489,48316,51143,53970,56797,59624,62451,65535,50115,50780,51445,52111,52776,53441,54106,54771,55436,56102,56767,57432,34181,37008,39835,42662,45489,48316,51143,53970,56797,59624,62451,65535],"dpi":null,"converted":false,"cropped":false},{"file":"photo-palette.png","shape":[18,24],"pixels":[20817,53199,40606,29555,29555,44975,29555,29555,29555,40606,44975,26471,26471,20817,40606,11565,43947,29555,15163,29555,29555,20817,29555,26214,26214,39321,29555,26471,26214,53199,40606,53199,40606,26214,44975,26214,44975,40606,29555,39321,15163,53199,11565,43947,40606,20817,44975,15163,29555,29555,36237,36237,40606,26471,53199,20817,26214,15163,29555,20817,26214,43947,26214,29555,20817,43947,11565,48573,43947,11565,15163,44975,29555,26471,40606,43947,43947,15163,48573,15163,29555,26214,29555,26471,48573,40606,26214,20817,11565,39321,40606,43947,26471,26214,40606,29555,11565,26471,43947,44975,53199,36237,48573,35466,20817,15163,40606,29555,35466,53199,43947,29555,40606,26471,44975,43947,11565,43947,29555,39321,35466,43947,35466,44975,29555,29555,29555,29555,26471,44975,48573,35466,26214,39321,26471,53199,20817,39321,35466,26471,26214,39321,35466,48573,44975,29555,29555,29555,53199,40606,26214,15163,40606,11565,43947,26471,20817,43947,53199,29555,15163,26214,20817,20817,44975,40606,26214,11565,39321,11565,29555,26471,29555,29555,26214,29555,29555,39321,29555,26214,40606,20817,11565,40606,40606,48573,15163,48573,40606,11565,11565,53199,29555,20817,26214,20817,43947,48573,29555,53199,29555,43947,26471,48573,29555,15163,35466,40606,26471,26214,43947,29555,48573,15163,29555,15163,39321,53199,48573,44975,35466,20817,40606,48573,40606,40606,29555,26471,29555,20817,43947,35466,29555,29555,29555,48573,26214,43947,40606,11565,11565,11565,44975,26214,26471,26214,20817,40606,26214,20817,40606,48573,44975,53199,39321,29555,36237,26214,36237,26214,20817,40606,44975,26471,39321,29555,40606,44975,26214,44975,11565,40606,15163,39321,11565,29555,39321,20817,43947,15163,48573,40606,44975,40606,44975,48573,48573,40606,40606,35466,15163,36237,35466,20817,40606,11565,44975,26471,15163,39321,26471,29555,26214,15163,44975,29555,26471,40606,35466,40606,26214,53199,26214,43947,26471,26214,15163,35466,26214,53199,15163,36237,15163,40606,44975,26214,44975,43947,43947,36237,20817,35466,35466,29555,15163,53199,53199,29555,29555,26214,29555,11565,11565,44975,20817,40606,20817,35466,35466,26214,15163,20817,43947,40606,44975,29555,35466,26471,53199,20817,44975,53199,29555,40606,26471,35466,15163,44975,36237,40606,11565,11565,40606,53199,15163,29555,40606,48573,48573,35466,11565,29555,29555,35466,29555,35466,20817,29555,20817,15163,26471,44975,48573,40606,36237,11565,15163,40606,20817,20817,29555,29555,35466,44975,29555,26471,48573,26471,36237,48573,29555,29555,15163,26214,26471,48573,36237,40606,26471,26214,20817,20817,20817,53199,40606,15163,44975,20817,44975,43947,26471,39321],"dpi":null,"converted":false,"cropped":false},{"file":"photo-grey16.tif","shape":[18,24],"pixels":[0,2849,5698,8548,11397,14246,17096,19945,22794,25644,28493,31342,34192,37041,39890,42740,45589,48438,51288,54137,56986,59836,62685,65535,0,2849,5698,8548,11397,14246,17096,19945,22794,25644,28493,31342,34192,37041,39890,42740,45589,48438,51288,54137,56986,59836,62685,65535,0,2849,5698,8548,11397,14246,17096,19945,22794,25644,28493,31342,34192,37041,39890,42740,45589,48438,51288,54137,56986,59836,62685,65535,0,2849,5698,8548,11397,14246,17096,19945,22794,25644,28493,31342,34192,37041,39890,42740,45589,48438,51288,54137,56986,59836,62685,65535,0,2849,5698,8548,11397,14246,17096,19945,22794,25644,28493,31342,34192,37041,39890,42740,45589,48438,51288,54137,56986,59836,62685,65535,0,2849,5698,8548,11397,14246,17096,19945,22794,25644,28493,31342,34192,37041,39890,42740,45589,48438,51288,54137,56986,59836,62685,65535,0,2849,5698,8548,11397,14246,17096,19945,22794,25644,28493,31342,34192,37041,39890,42740,45589,48438,51288,54137,56986,59836,62685,65535,0,2849,5698,8548,11397,14246,17096,19945,22794,25644,28493,31342,34192,37041,39890,42740,45589,48438,51288,54137,56986,59836,62685,65535,0,2849,5698,8548,11397,14246,17096,19945,22794,25644,28493,31342,34192,37041,39890,42740,45589,48438,51288,54137,56986,59836,62685,65535,0,2849,5698,8548,11397,14246,17096,19945,22794,25644,28493,31342,34192,37041,39890,42740,45589,48438,51288,54137,56986,59836,62685,65535,0,2849,5698,8548,11397,14246,17096,19945,22794,25644,28493,31342,34192,37041,39890,42740,45589,48438,51288,54137,56986,59836,62685,65535,0,2849,5698,8548,11397,14246,17096,19945,22794,25644,28493,31342,34192,37041,39890,42740,45589,48438,51288,54137,56986,59836,62685,65535,0,2849,5698,8548,11397,14246,17096,19945,22794,25644,28493,31342,34192,37041,39890,42740,45589,48438,51288,54137,56986,59836,62685,65535,0,2849,5698,8548,11397,14246,17096,19945,22794,25644,28493,31342,34192,37041,39890,42740,45589,48438,51288,54137,56986,59836,62685,65535,0,2849,5698,8548,11397,14246,17096,19945,22794,25644,28493,31342,34192,37041,39890,42740,45589,48438,51288,54137,56986,59836,62685,65535,0,2849,5698,8548,11397,14246,17096,19945,22794,25644,28493,31342,34192,37041,39890,42740,45589,48438,51288,54137,56986,59836,62685,65535,0,2849,5698,8548,11397,14246,17096,19945,22794,25644,28493,31342,34192,37041,39890,42740,45589,48438,51288,54137,56986,59836,62685,65535,0,2849,5698,8548,11397,14246,17096,19945,22794,25644,28493,31342,34192,37041,39890,42740,45589,48438,51288,54137,56986,59836,62685,65535],"dpi":[360.0,360.0],"converted":false,"cropped":false},{"file":"photo-rgba16.tif","shape":[18,22],"pixels":[5698,8548,11397,14246,17096,19945,22794,25644,28493,31342,34192,37041,39890,42740,45589,48438,51288,54137,56986,59836,62685,65535,5698,8548,11397,14246,17096,19945,22794,25644,28493,31342,34192,37041,39890,42740,45589,48438,51288,54137,56986,59836,62685,65535,5698,8548,11397,14246,17096,19945,22794,25644,28493,31342,34192,37041,39890,42740,45589,48438,51288,54137,56986,59836,62685,65535,5698,8548,11397,14246,17096,19945,22794,25644,28493,31342,34192,37041,39890,42740,45589,48438,51288,54137,56986,59836,62685,65535,5698,8548,11397,14246,17096,19945,22794,25644,28493,31342,34192,37041,39890,42740,45589,48438,51288,54137,56986,59836,62685,65535,5698,8548,11397,14246,17096,19945,22794,25644,28493,31342,34192,37041,39890,42740,45589,48438,51288,54137,56986,59836,62685,65535,5698,8548,11397,14246,17096,19945,22794,25644,28493,31342,34192,37041,39890,42740,45589,48438,51288,54137,56986,59836,62685,65535,5698,8548,11397,14246,17096,19945,22794,25644,28493,31342,34192,37041,39890,42740,45589,48438,51288,54137,56986,59836,62685,65535,5698,8548,11397,14246,17096,19945,22794,25644,28493,31342,34192,37041,39890,42740,45589,48438,51288,54137,56986,59836,62685,65535,5698,8548,11397,14246,17096,19945,22794,25644,28493,31342,34192,37041,39890,42740,45589,48438,51288,54137,56986,59836,62685,65535,5698,8548,11397,14246,17096,19945,22794,25644,28493,31342,34192,37041,39890,42740,45589,48438,51288,54137,56986,59836,62685,65535,5698,8548,11397,14246,17096,19945,22794,25644,28493,31342,34192,37041,39890,42740,45589,48438,51288,54137,56986,59836,62685,65535,5698,8548,11397,14246,17096,19945,22794,25644,28493,31342,34192,37041,39890,42740,45589,48438,51288,54137,56986,59836,62685,65535,5698,8548,11397,14246,17096,19945,22794,25644,28493,31342,34192,37041,39890,42740,45589,48438,51288,54137,56986,59836,62685,65535,5698,8548,11397,14246,17096,19945,22794,25644,28493,31342,34192,37041,39890,42740,45589,48438,51288,54137,56986,59836,62685,65535,5698,8548,11397,14246,17096,19945,22794,25644,28493,31342,34192,37041,39890,42740,45589,48438,51288,54137,56986,59836,62685,65535,5698,8548,11397,14246,17096,19945,22794,25644,28493,31342,34192,37041,39890,42740,45589,48438,51288,54137,56986,59836,62685,65535,5698,8548,11397,14246,17096,19945,22794,25644,28493,31342,34192,37041,39890,42740,45589,48438,51288,54137,56986,59836,62685,65535],"dpi":null,"converted":false,"cropped":true}],"calibration":"{\n \"format\": \"openquad-calibration\",\n \"version\": 1,\n \"printer\": \"Canon_MG3600_series\",\n \"paper\": \"Letter plain\",\n \"settings\": \"default quality, AirPrint queue; eSCL Document intent; shadow damping 0.5; tone linearized; tone linearized\",\n \"created\": \"2026-10-22T16:59:09+00:00\",\n \"levels\": [\n 0,\n 256,\n 512,\n 768,\n 1024,\n 1280,\n 1536,\n 1792,\n 2048,\n 2304,\n 2560,\n 2816,\n 3072,\n 3328,\n 3584,\n 3840,\n 4096,\n 4352,\n 4608,\n 4864,\n 5120,\n 5376,\n 5632,\n 5888,\n 6144,\n 6400,\n 6656,\n 6912,\n 7168,\n 7424,\n 7680,\n 7936,\n 8192,\n 8448,\n 8704,\n 8960,\n 9216,\n 9472,\n 9728,\n 9984,\n 10240,\n 10496,\n 10752,\n 11008,\n 11264,\n 11520,\n 11776,\n 12032,\n 12288,\n 12544,\n 12800,\n 13056,\n 13312,\n 13568,\n 13824,\n 14080,\n 14336,\n 14592,\n 14848,\n 15104,\n 15360,\n 15616,\n 15872,\n 16128,\n 16384,\n 16640,\n 16896,\n 17152,\n 17408,\n 17664,\n 17920,\n 18176,\n 18432,\n 18688,\n 18944,\n 19200,\n 19456,\n 19712,\n 19968,\n 20224,\n 20480,\n 20736,\n 20992,\n 21248,\n 21504,\n 21760,\n 22016,\n 22272,\n 22528,\n 22784,\n 23040,\n 23296,\n 23552,\n 23808,\n 24064,\n 24320,\n 24576,\n 24832,\n 25088,\n 25344,\n 25600,\n 25856,\n 26112,\n 26368,\n 26624,\n 26880,\n 27136,\n 27392,\n 27648,\n 27904,\n 28160,\n 28416,\n 28672,\n 28928,\n 29184,\n 29440,\n 29696,\n 29952,\n 30208,\n 30464,\n 30720,\n 30976,\n 31232,\n 31488,\n 31744,\n 32000,\n 32256,\n 32512,\n 32768,\n 33023,\n 33279,\n 33535,\n 33791,\n 34047,\n 34303,\n 34559,\n 34815,\n 35071,\n 35327,\n 35583,\n 35839,\n 36095,\n 36351,\n 36607,\n 36863,\n 37119,\n 37375,\n 37631,\n 37887,\n 38143,\n 38399,\n 38655,\n 38911,\n 39167,\n 39423,\n 39679,\n 39935,\n 40191,\n 40447,\n 40703,\n 40959,\n 41215,\n 41471,\n 41727,\n 41983,\n 42239,\n 42495,\n 42751,\n 43007,\n 43263,\n 43519,\n 43775,\n 44031,\n 44287,\n 44543,\n 44799,\n 45055,\n 45311,\n 45567,\n 45823,\n 46079,\n 46335,\n 46591,\n 46847,\n 47103,\n 47359,\n 47615,\n 47871,\n 48127,\n 48383,\n 48639,\n 48895,\n 49151,\n 49407,\n 49663,\n 49919,\n 50175,\n 50431,\n 50687,\n 50943,\n 51199,\n 51455,\n 51711,\n 51967,\n 52223,\n 52479,\n 52735,\n 52991,\n 53247,\n 53503,\n 53759,\n 54015,\n 54271,\n 54527,\n 54783,\n 55039,\n 55295,\n 55551,\n 55807,\n 56063,\n 56319,\n 56575,\n 56831,\n 57087,\n 57343,\n 57599,\n 57855,\n 58111,\n 58367,\n 58623,\n 58879,\n 59135,\n 59391,\n 59647,\n 59903,\n 60159,\n 60415,\n 60671,\n 60927,\n 61183,\n 61439,\n 61695,\n 61951,\n 62207,\n 62463,\n 62719,\n 62975,\n 63231,\n 63487,\n 63743,\n 63999,\n 64255,\n 64511,\n 64767,\n 65023,\n 65279,\n 65535\n ],\n \"curves\": {\n \"R\": [\n 0,\n 1249,\n 2498,\n 3742,\n 4127,\n 4375,\n 4491,\n 4607,\n 4723,\n 4839,\n 4955,\n 5074,\n 5199,\n 5332,\n 5472,\n 5620,\n 5782,\n 5961,\n 6125,\n 6270,\n 6428,\n 6597,\n 6779,\n 6976,\n 7189,\n 7409,\n 7636,\n 7871,\n 8112,\n 8361,\n 8618,\n 8890,\n 9192,\n 9514,\n 9850,\n 10196,\n 10540,\n 10882,\n 11220,\n 11556,\n 11889,\n 12219,\n 12548,\n 12875,\n 13148,\n 13368,\n 13573,\n 13776,\n 13978,\n 14231,\n 14495,\n 14758,\n 15020,\n 15279,\n 15536,\n 15792,\n 16052,\n 16425,\n 16805,\n 17182,\n 17556,\n 17919,\n 18282,\n 18641,\n 18998,\n 19296,\n 19545,\n 19784,\n 20022,\n 20259,\n 20495,\n 20729,\n 20961,\n 21198,\n 21432,\n 21667,\n 21899,\n 22130,\n 22359,\n 22594,\n 22853,\n 23115,\n 23376,\n 23634,\n 23892,\n 24177,\n 24487,\n 24797,\n 25105,\n 25411,\n 25716,\n 26006,\n 26233,\n 26445,\n 26655,\n 26864,\n 27042,\n 27220,\n 27397,\n 27572,\n 27748,\n 27922,\n 28097,\n 28269,\n 28442,\n 28614,\n 28786,\n 28957,\n 29131,\n 29311,\n 29517,\n 29725,\n 29932,\n 30138,\n 30344,\n 30549,\n 30754,\n 30958,\n 31161,\n 31363,\n 31566,\n 31770,\n 31975,\n 32179,\n 32382,\n 32585,\n 32789,\n 32995,\n 33199,\n 33403,\n 33606,\n 33809,\n 34013,\n 34263,\n 34513,\n 34762,\n 35011,\n 35258,\n 35504,\n 35749,\n 35994,\n 36242,\n 36487,\n 36654,\n 36822,\n 36989,\n 37156,\n 37321,\n 37487,\n 37652,\n 37818,\n 37983,\n 38147,\n 38310,\n 38474,\n 38637,\n 38800,\n 38962,\n 39173,\n 39388,\n 39593,\n 39794,\n 39997,\n 40197,\n 40396,\n 40596,\n 40795,\n 40993,\n 41192,\n 41397,\n 41613,\n 41829,\n 42044,\n 42258,\n 42473,\n 42687,\n 42918,\n 43157,\n 43395,\n 43634,\n 43844,\n 44043,\n 44242,\n 44441,\n 44638,\n 44837,\n 45034,\n 45232,\n 45428,\n 45624,\n 45820,\n 46016,\n 46227,\n 46458,\n 46692,\n 46925,\n 47156,\n 47389,\n 47620,\n 47851,\n 48082,\n 48312,\n 48541,\n 48771,\n 48999,\n 49228,\n 49485,\n 49775,\n 50090,\n 50412,\n 50734,\n 51054,\n 51374,\n 51693,\n 52012,\n 52330,\n 52648,\n 52922,\n 53152,\n 53381,\n 53610,\n 53839,\n 54068,\n 54296,\n 54522,\n 54750,\n 54977,\n 55204,\n 55429,\n 55656,\n 55882,\n 56132,\n 56466,\n 56844,\n 57222,\n 57598,\n 57974,\n 58348,\n 58722,\n 59097,\n 59470,\n 59836,\n 60180,\n 60523,\n 60866,\n 61209,\n 61622,\n 62059,\n 62493,\n 62904,\n 63284,\n 63662,\n 64037,\n 64412,\n 64787,\n 65161,\n 65535\n ],\n \"G\": [\n 0,\n 1185,\n 2370,\n 3551,\n 3946,\n 4216,\n 4365,\n 4513,\n 4662,\n 4811,\n 4960,\n 5112,\n 5273,\n 5443,\n 5622,\n 5812,\n 6020,\n 6250,\n 6460,\n 6646,\n 6848,\n 7065,\n 7298,\n 7551,\n 7824,\n 8107,\n 8399,\n 8700,\n 9009,\n 9327,\n 9657,\n 9976,\n 10260,\n 10513,\n 10775,\n 11048,\n 11316,\n 11584,\n 11850,\n 12113,\n 12374,\n 12634,\n 12892,\n 13147,\n 13391,\n 13627,\n 13857,\n 14087,\n 14315,\n 14599,\n 14897,\n 15194,\n 15489,\n 15780,\n 16071,\n 16360,\n 16652,\n 17057,\n 17470,\n 17879,\n 18284,\n 18677,\n 19071,\n 19460,\n 19847,\n 20152,\n 20387,\n 20610,\n 20832,\n 21053,\n 21271,\n 21490,\n 21707,\n 21927,\n 22145,\n 22363,\n 22579,\n 22795,\n 23008,\n 23228,\n 23474,\n 23723,\n 23971,\n 24217,\n 24463,\n 24734,\n 25030,\n 25324,\n 25618,\n 25909,\n 26199,\n 26476,\n 26697,\n 26902,\n 27108,\n 27312,\n 27486,\n 27660,\n 27831,\n 28003,\n 28175,\n 28345,\n 28515,\n 28684,\n 28852,\n 29020,\n 29188,\n 29354,\n 29525,\n 29700,\n 29904,\n 30109,\n 30314,\n 30518,\n 30722,\n 30926,\n 31127,\n 31329,\n 31530,\n 31730,\n 31930,\n 32133,\n 32336,\n 32537,\n 32738,\n 32938,\n 33128,\n 33315,\n 33500,\n 33684,\n 33868,\n 34052,\n 34237,\n 34464,\n 34690,\n 34915,\n 35141,\n 35364,\n 35588,\n 35810,\n 36031,\n 36265,\n 36506,\n 36670,\n 36834,\n 37000,\n 37164,\n 37326,\n 37489,\n 37653,\n 37815,\n 37977,\n 38138,\n 38300,\n 38461,\n 38621,\n 38782,\n 38941,\n 39149,\n 39361,\n 39561,\n 39756,\n 39954,\n 40149,\n 40343,\n 40538,\n 40732,\n 40925,\n 41119,\n 41319,\n 41530,\n 41740,\n 41950,\n 42159,\n 42368,\n 42577,\n 42798,\n 43026,\n 43253,\n 43481,\n 43681,\n 43872,\n 44061,\n 44250,\n 44440,\n 44629,\n 44818,\n 45006,\n 45194,\n 45380,\n 45568,\n 45754,\n 45957,\n 46180,\n 46406,\n 46631,\n 46855,\n 47079,\n 47303,\n 47527,\n 47749,\n 47972,\n 48194,\n 48415,\n 48636,\n 48858,\n 49105,\n 49380,\n 49667,\n 49957,\n 50246,\n 50534,\n 50823,\n 51110,\n 51397,\n 51684,\n 51970,\n 52218,\n 52456,\n 52704,\n 52955,\n 53206,\n 53457,\n 53706,\n 53954,\n 54203,\n 54452,\n 54700,\n 54947,\n 55196,\n 55442,\n 55700,\n 56006,\n 56343,\n 56680,\n 57016,\n 57351,\n 57686,\n 58020,\n 58355,\n 58689,\n 59029,\n 59385,\n 59739,\n 60093,\n 60448,\n 60874,\n 61325,\n 61775,\n 62236,\n 62707,\n 63181,\n 63652,\n 64124,\n 64595,\n 65066,\n 65535\n ],\n \"B\": [\n 0,\n 1212,\n 2423,\n 3630,\n 4022,\n 4284,\n 4421,\n 4558,\n 4694,\n 4831,\n 4968,\n 5107,\n 5256,\n 5413,\n 5577,\n 5751,\n 5942,\n 6154,\n 6346,\n 6517,\n 6703,\n 6903,\n 7117,\n 7348,\n 7599,\n 7859,\n 8127,\n 8404,\n 8687,\n 8980,\n 9283,\n 9560,\n 9769,\n 9919,\n 10075,\n 10237,\n 10397,\n 10556,\n 10713,\n 10870,\n 11026,\n 11179,\n 11333,\n 11485,\n 11673,\n 11899,\n 12134,\n 12368,\n 12600,\n 12890,\n 13194,\n 13498,\n 13799,\n 14096,\n 14392,\n 14687,\n 14981,\n 15300,\n 15619,\n 15935,\n 16249,\n 16554,\n 16859,\n 17160,\n 17460,\n 17700,\n 17890,\n 18070,\n 18250,\n 18428,\n 18606,\n 18782,\n 18958,\n 19136,\n 19313,\n 19490,\n 19665,\n 19839,\n 20012,\n 20199,\n 20452,\n 20714,\n 20975,\n 21235,\n 21494,\n 21779,\n 22090,\n 22400,\n 22709,\n 23016,\n 23321,\n 23617,\n 23874,\n 24120,\n 24365,\n 24609,\n 24816,\n 25023,\n 25228,\n 25433,\n 25638,\n 25841,\n 26044,\n 26246,\n 26447,\n 26648,\n 26847,\n 27046,\n 27250,\n 27457,\n 27666,\n 27874,\n 28082,\n 28288,\n 28494,\n 28699,\n 28904,\n 29108,\n 29311,\n 29513,\n 29716,\n 29921,\n 30126,\n 30330,\n 30533,\n 30736,\n 30945,\n 31158,\n 31367,\n 31579,\n 31788,\n 31997,\n 32208,\n 32466,\n 32723,\n 32981,\n 33237,\n 33492,\n 33746,\n 33999,\n 34251,\n 34517,\n 34790,\n 34977,\n 35164,\n 35351,\n 35537,\n 35723,\n 35907,\n 36092,\n 36276,\n 36461,\n 36644,\n 36826,\n 37009,\n 37192,\n 37373,\n 37554,\n 37791,\n 38030,\n 38251,\n 38464,\n 38678,\n 38891,\n 39103,\n 39315,\n 39526,\n 39737,\n 39948,\n 40166,\n 40395,\n 40625,\n 40853,\n 41081,\n 41309,\n 41535,\n 41762,\n 41989,\n 42215,\n 42441,\n 42641,\n 42830,\n 43019,\n 43207,\n 43395,\n 43584,\n 43771,\n 43959,\n 44145,\n 44331,\n 44517,\n 44703,\n 44897,\n 45102,\n 45307,\n 45513,\n 45716,\n 45920,\n 46124,\n 46327,\n 46530,\n 46733,\n 46935,\n 47137,\n 47338,\n 47539,\n 47764,\n 48017,\n 48282,\n 48552,\n 48821,\n 49089,\n 49357,\n 49625,\n 49891,\n 50157,\n 50423,\n 50656,\n 50917,\n 51206,\n 51498,\n 51791,\n 52084,\n 52375,\n 52666,\n 52957,\n 53247,\n 53537,\n 53825,\n 54115,\n 54404,\n 54709,\n 55075,\n 55482,\n 55889,\n 56295,\n 56699,\n 57103,\n 57507,\n 57910,\n 58312,\n 58711,\n 59099,\n 59485,\n 59871,\n 60258,\n 60724,\n 61216,\n 61705,\n 62192,\n 62672,\n 63152,\n 63629,\n 64106,\n 64583,\n 65060,\n 65535\n ]\n }\n}\n","sessions":[{"photo":"photo-grey16.tif","ppi_used":3.2,"size":[7.5,5.625],"fits":true,"summary":["Photo: photo-grey16.tif","Printer: Canon_MG3600_series","Paper: Letter","Size: 7.50 x 5.62 in at 3 ppi","Toning: neutral","Calibration: none"],"notes":[],"rendered_shape":[18,24,3],"rendered":[0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535]},{"photo":"photo-grey16.tif","preset":"black-red","calibration":true,"paper":"4x6","ppi_used":8.0,"size":[3.0,2.25],"fits":true,"summary":["Photo: photo-grey16.tif","Printer: Canon_MG3600_series","Paper: 4x6","Size: 3.00 x 2.25 in at 8 ppi","Toning: black-red","Calibration: canon-plain.oqcal"],"notes":[],"rendered_shape":[18,24,3],"rendered":[0,0,0,7483,8083,7837,14276,13996,12276,20675,19534,17217,25678,22077,19258,28912,23013,20016,31951,22797,19841,34975,21768,19007,37654,20413,17911,39883,18759,16617,42258,18367,16313,44547,20156,17703,46403,22285,19426,48227,25802,22903,49822,29216,26880,51461,33100,30914,53009,37318,35714,54432,41318,40165,56033,45721,44670,58677,50604,49154,61133,55225,54149,63501,59844,59600,64990,63953,63933,65535,65535,65535,0,0,0,7483,8083,7837,14276,13996,12276,20675,19534,17217,25678,22077,19258,28912,23013,20016,31951,22797,19841,34975,21768,19007,37654,20413,17911,39883,18759,16617,42258,18367,16313,44547,20156,17703,46403,22285,19426,48227,25802,22903,49822,29216,26880,51461,33100,30914,53009,37318,35714,54432,41318,40165,56033,45721,44670,58677,50604,49154,61133,55225,54149,63501,59844,59600,64990,63953,63933,65535,65535,65535,0,0,0,7483,8083,7837,14276,13996,12276,20675,19534,17217,25678,22077,19258,28912,23013,20016,31951,22797,19841,34975,21768,19007,37654,20413,17911,39883,18759,16617,42258,18367,16313,44547,20156,17703,46403,22285,19426,48227,25802,22903,49822,29216,26880,51461,33100,30914,53009,37318,35714,54432,41318,40165,56033,45721,44670,58677,50604,49154,61133,55225,54149,63501,59844,59600,64990,63953,63933,65535,65535,65535,0,0,0,7483,8083,7837,14276,13996,12276,20675,19534,17217,25678,22077,19258,28912,23013,20016,31951,22797,19841,34975,21768,19007,37654,20413,17911,39883,18759,16617,42258,18367,16313,44547,20156,17703,46403,22285,19426,48227,25802,22903,49822,29216,26880,51461,33100,30914,53009,37318,35714,54432,41318,40165,56033,45721,44670,58677,50604,49154,61133,55225,54149,63501,59844,59600,64990,63953,63933,65535,65535,65535,0,0,0,7483,8083,7837,14276,13996,12276,20675,19534,17217,25678,22077,19258,28912,23013,20016,31951,22797,19841,34975,21768,19007,37654,20413,17911,39883,18759,16617,42258,18367,16313,44547,20156,17703,46403,22285,19426,48227,25802,22903,49822,29216,26880,51461,33100,30914,53009,37318,35714,54432,41318,40165,56033,45721,44670,58677,50604,49154,61133,55225,54149,63501,59844,59600,64990,63953,63933,65535,65535,65535,0,0,0,7483,8083,7837,14276,13996,12276,20675,19534,17217,25678,22077,19258,28912,23013,20016,31951,22797,19841,34975,21768,19007,37654,20413,17911,39883,18759,16617,42258,18367,16313,44547,20156,17703,46403,22285,19426,48227,25802,22903,49822,29216,26880,51461,33100,30914,53009,37318,35714,54432,41318,40165,56033,45721,44670,58677,50604,49154,61133,55225,54149,63501,59844,59600,64990,63953,63933,65535,65535,65535,0,0,0,7483,8083,7837,14276,13996,12276,20675,19534,17217,25678,22077,19258,28912,23013,20016,31951,22797,19841,34975,21768,19007,37654,20413,17911,39883,18759,16617,42258,18367,16313,44547,20156,17703,46403,22285,19426,48227,25802,22903,49822,29216,26880,51461,33100,30914,53009,37318,35714,54432,41318,40165,56033,45721,44670,58677,50604,49154,61133,55225,54149,63501,59844,59600,64990,63953,63933,65535,65535,65535,0,0,0,7483,8083,7837,14276,13996,12276,20675,19534,17217,25678,22077,19258,28912,23013,20016,31951,22797,19841,34975,21768,19007,37654,20413,17911,39883,18759,16617,42258,18367,16313,44547,20156,17703,46403,22285,19426,48227,25802,22903,49822,29216,26880,51461,33100,30914,53009,37318,35714,54432,41318,40165,56033,45721,44670,58677,50604,49154,61133,55225,54149,63501,59844,59600,64990,63953,63933,65535,65535,65535,0,0,0,7483,8083,7837,14276,13996,12276,20675,19534,17217,25678,22077,19258,28912,23013,20016,31951,22797,19841,34975,21768,19007,37654,20413,17911,39883,18759,16617,42258,18367,16313,44547,20156,17703,46403,22285,19426,48227,25802,22903,49822,29216,26880,51461,33100,30914,53009,37318,35714,54432,41318,40165,56033,45721,44670,58677,50604,49154,61133,55225,54149,63501,59844,59600,64990,63953,63933,65535,65535,65535,0,0,0,7483,8083,7837,14276,13996,12276,20675,19534,17217,25678,22077,19258,28912,23013,20016,31951,22797,19841,34975,21768,19007,37654,20413,17911,39883,18759,16617,42258,18367,16313,44547,20156,17703,46403,22285,19426,48227,25802,22903,49822,29216,26880,51461,33100,30914,53009,37318,35714,54432,41318,40165,56033,45721,44670,58677,50604,49154,61133,55225,54149,63501,59844,59600,64990,63953,63933,65535,65535,65535,0,0,0,7483,8083,7837,14276,13996,12276,20675,19534,17217,25678,22077,19258,28912,23013,20016,31951,22797,19841,34975,21768,19007,37654,20413,17911,39883,18759,16617,42258,18367,16313,44547,20156,17703,46403,22285,19426,48227,25802,22903,49822,29216,26880,51461,33100,30914,53009,37318,35714,54432,41318,40165,56033,45721,44670,58677,50604,49154,61133,55225,54149,63501,59844,59600,64990,63953,63933,65535,65535,65535,0,0,0,7483,8083,7837,14276,13996,12276,20675,19534,17217,25678,22077,19258,28912,23013,20016,31951,22797,19841,34975,21768,19007,37654,20413,17911,39883,18759,16617,42258,18367,16313,44547,20156,17703,46403,22285,19426,48227,25802,22903,49822,29216,26880,51461,33100,30914,53009,37318,35714,54432,41318,40165,56033,45721,44670,58677,50604,49154,61133,55225,54149,63501,59844,59600,64990,63953,63933,65535,65535,65535,0,0,0,7483,8083,7837,14276,13996,12276,20675,19534,17217,25678,22077,19258,28912,23013,20016,31951,22797,19841,34975,21768,19007,37654,20413,17911,39883,18759,16617,42258,18367,16313,44547,20156,17703,46403,22285,19426,48227,25802,22903,49822,29216,26880,51461,33100,30914,53009,37318,35714,54432,41318,40165,56033,45721,44670,58677,50604,49154,61133,55225,54149,63501,59844,59600,64990,63953,63933,65535,65535,65535,0,0,0,7483,8083,7837,14276,13996,12276,20675,19534,17217,25678,22077,19258,28912,23013,20016,31951,22797,19841,34975,21768,19007,37654,20413,17911,39883,18759,16617,42258,18367,16313,44547,20156,17703,46403,22285,19426,48227,25802,22903,49822,29216,26880,51461,33100,30914,53009,37318,35714,54432,41318,40165,56033,45721,44670,58677,50604,49154,61133,55225,54149,63501,59844,59600,64990,63953,63933,65535,65535,65535,0,0,0,7483,8083,7837,14276,13996,12276,20675,19534,17217,25678,22077,19258,28912,23013,20016,31951,22797,19841,34975,21768,19007,37654,20413,17911,39883,18759,16617,42258,18367,16313,44547,20156,17703,46403,22285,19426,48227,25802,22903,49822,29216,26880,51461,33100,30914,53009,37318,35714,54432,41318,40165,56033,45721,44670,58677,50604,49154,61133,55225,54149,63501,59844,59600,64990,63953,63933,65535,65535,65535,0,0,0,7483,8083,7837,14276,13996,12276,20675,19534,17217,25678,22077,19258,28912,23013,20016,31951,22797,19841,34975,21768,19007,37654,20413,17911,39883,18759,16617,42258,18367,16313,44547,20156,17703,46403,22285,19426,48227,25802,22903,49822,29216,26880,51461,33100,30914,53009,37318,35714,54432,41318,40165,56033,45721,44670,58677,50604,49154,61133,55225,54149,63501,59844,59600,64990,63953,63933,65535,65535,65535,0,0,0,7483,8083,7837,14276,13996,12276,20675,19534,17217,25678,22077,19258,28912,23013,20016,31951,22797,19841,34975,21768,19007,37654,20413,17911,39883,18759,16617,42258,18367,16313,44547,20156,17703,46403,22285,19426,48227,25802,22903,49822,29216,26880,51461,33100,30914,53009,37318,35714,54432,41318,40165,56033,45721,44670,58677,50604,49154,61133,55225,54149,63501,59844,59600,64990,63953,63933,65535,65535,65535,0,0,0,7483,8083,7837,14276,13996,12276,20675,19534,17217,25678,22077,19258,28912,23013,20016,31951,22797,19841,34975,21768,19007,37654,20413,17911,39883,18759,16617,42258,18367,16313,44547,20156,17703,46403,22285,19426,48227,25802,22903,49822,29216,26880,51461,33100,30914,53009,37318,35714,54432,41318,40165,56033,45721,44670,58677,50604,49154,61133,55225,54149,63501,59844,59600,64990,63953,63933,65535,65535,65535]},{"photo":"photo-grey.png","fit":false,"ppi":12.5,"ppi_used":12.5,"size":[1.92,1.44],"fits":true,"summary":["Photo: photo-grey.png","Printer: Canon_MG3600_series","Paper: Letter","Size: 1.92 x 1.44 in at 12 ppi","Toning: neutral","Calibration: none"],"notes":[],"rendered_shape":[18,24,3],"rendered":[0,0,0,2827,2827,2827,5654,5654,5654,8481,8481,8481,11308,11308,11308,14135,14135,14135,16962,16962,16962,19789,19789,19789,22616,22616,22616,25443,25443,25443,28270,28270,28270,31097,31097,31097,34181,34181,34181,37008,37008,37008,39835,39835,39835,42662,42662,42662,45489,45489,45489,48316,48316,48316,51143,51143,51143,53970,53970,53970,56797,56797,56797,59624,59624,59624,62451,62451,62451,65535,65535,65535,0,0,0,2827,2827,2827,5654,5654,5654,8481,8481,8481,11308,11308,11308,14135,14135,14135,16962,16962,16962,19789,19789,19789,22616,22616,22616,25443,25443,25443,28270,28270,28270,31097,31097,31097,34181,34181,34181,37008,37008,37008,39835,39835,39835,42662,42662,42662,45489,45489,45489,48316,48316,48316,51143,51143,51143,53970,53970,53970,56797,56797,56797,59624,59624,59624,62451,62451,62451,65535,65535,65535,0,0,0,2827,2827,2827,5654,5654,5654,8481,8481,8481,11308,11308,11308,14135,14135,14135,16962,16962,16962,19789,19789,19789,22616,22616,22616,25443,25443,25443,28270,28270,28270,31097,31097,31097,34181,34181,34181,37008,37008,37008,39835,39835,39835,42662,42662,42662,45489,45489,45489,48316,48316,48316,51143,51143,51143,53970,53970,53970,56797,56797,56797,59624,59624,59624,62451,62451,62451,65535,65535,65535,0,0,0,2827,2827,2827,5654,5654,5654,8481,8481,8481,11308,11308,11308,14135,14135,14135,16962,16962,16962,19789,19789,19789,22616,22616,22616,25443,25443,25443,28270,28270,28270,31097,31097,31097,34181,34181,34181,37008,37008,37008,39835,39835,39835,42662,42662,42662,45489,45489,45489,48316,48316,48316,51143,51143,51143,53970,53970,53970,56797,56797,56797,59624,59624,59624,62451,62451,62451,65535,65535,65535,0,0,0,2827,2827,2827,5654,5654,5654,8481,8481,8481,11308,11308,11308,14135,14135,14135,16962,16962,16962,19789,19789,19789,22616,22616,22616,25443,25443,25443,28270,28270,28270,31097,31097,31097,34181,34181,34181,37008,37008,37008,39835,39835,39835,42662,42662,42662,45489,45489,45489,48316,48316,48316,51143,51143,51143,53970,53970,53970,56797,56797,56797,59624,59624,59624,62451,62451,62451,65535,65535,65535,0,0,0,2827,2827,2827,5654,5654,5654,8481,8481,8481,11308,11308,11308,14135,14135,14135,16962,16962,16962,19789,19789,19789,22616,22616,22616,25443,25443,25443,28270,28270,28270,31097,31097,31097,34181,34181,34181,37008,37008,37008,39835,39835,39835,42662,42662,42662,45489,45489,45489,48316,48316,48316,51143,51143,51143,53970,53970,53970,56797,56797,56797,59624,59624,59624,62451,62451,62451,65535,65535,65535,0,0,0,2827,2827,2827,5654,5654,5654,8481,8481,8481,11308,11308,11308,14135,14135,14135,16962,16962,16962,19789,19789,19789,22616,22616,22616,25443,25443,25443,28270,28270,28270,31097,31097,31097,34181,34181,34181,37008,37008,37008,39835,39835,39835,42662,42662,42662,45489,45489,45489,48316,48316,48316,51143,51143,51143,53970,53970,53970,56797,56797,56797,59624,59624,59624,62451,62451,62451,65535,65535,65535,0,0,0,2827,2827,2827,5654,5654,5654,8481,8481,8481,11308,11308,11308,14135,14135,14135,16962,16962,16962,19789,19789,19789,22616,22616,22616,25443,25443,25443,28270,28270,28270,31097,31097,31097,34181,34181,34181,37008,37008,37008,39835,39835,39835,42662,42662,42662,45489,45489,45489,48316,48316,48316,51143,51143,51143,53970,53970,53970,56797,56797,56797,59624,59624,59624,62451,62451,62451,65535,65535,65535,0,0,0,2827,2827,2827,5654,5654,5654,8481,8481,8481,11308,11308,11308,14135,14135,14135,16962,16962,16962,19789,19789,19789,22616,22616,22616,25443,25443,25443,28270,28270,28270,31097,31097,31097,34181,34181,34181,37008,37008,37008,39835,39835,39835,42662,42662,42662,45489,45489,45489,48316,48316,48316,51143,51143,51143,53970,53970,53970,56797,56797,56797,59624,59624,59624,62451,62451,62451,65535,65535,65535,0,0,0,2827,2827,2827,5654,5654,5654,8481,8481,8481,11308,11308,11308,14135,14135,14135,16962,16962,16962,19789,19789,19789,22616,22616,22616,25443,25443,25443,28270,28270,28270,31097,31097,31097,34181,34181,34181,37008,37008,37008,39835,39835,39835,42662,42662,42662,45489,45489,45489,48316,48316,48316,51143,51143,51143,53970,53970,53970,56797,56797,56797,59624,59624,59624,62451,62451,62451,65535,65535,65535,0,0,0,2827,2827,2827,5654,5654,5654,8481,8481,8481,11308,11308,11308,14135,14135,14135,16962,16962,16962,19789,19789,19789,22616,22616,22616,25443,25443,25443,28270,28270,28270,31097,31097,31097,34181,34181,34181,37008,37008,37008,39835,39835,39835,42662,42662,42662,45489,45489,45489,48316,48316,48316,51143,51143,51143,53970,53970,53970,56797,56797,56797,59624,59624,59624,62451,62451,62451,65535,65535,65535,0,0,0,2827,2827,2827,5654,5654,5654,8481,8481,8481,11308,11308,11308,14135,14135,14135,16962,16962,16962,19789,19789,19789,22616,22616,22616,25443,25443,25443,28270,28270,28270,31097,31097,31097,34181,34181,34181,37008,37008,37008,39835,39835,39835,42662,42662,42662,45489,45489,45489,48316,48316,48316,51143,51143,51143,53970,53970,53970,56797,56797,56797,59624,59624,59624,62451,62451,62451,65535,65535,65535,0,0,0,2827,2827,2827,5654,5654,5654,8481,8481,8481,11308,11308,11308,14135,14135,14135,16962,16962,16962,19789,19789,19789,22616,22616,22616,25443,25443,25443,28270,28270,28270,31097,31097,31097,34181,34181,34181,37008,37008,37008,39835,39835,39835,42662,42662,42662,45489,45489,45489,48316,48316,48316,51143,51143,51143,53970,53970,53970,56797,56797,56797,59624,59624,59624,62451,62451,62451,65535,65535,65535,0,0,0,2827,2827,2827,5654,5654,5654,8481,8481,8481,11308,11308,11308,14135,14135,14135,16962,16962,16962,19789,19789,19789,22616,22616,22616,25443,25443,25443,28270,28270,28270,31097,31097,31097,34181,34181,34181,37008,37008,37008,39835,39835,39835,42662,42662,42662,45489,45489,45489,48316,48316,48316,51143,51143,51143,53970,53970,53970,56797,56797,56797,59624,59624,59624,62451,62451,62451,65535,65535,65535,0,0,0,2827,2827,2827,5654,5654,5654,8481,8481,8481,11308,11308,11308,14135,14135,14135,16962,16962,16962,19789,19789,19789,22616,22616,22616,25443,25443,25443,28270,28270,28270,31097,31097,31097,34181,34181,34181,37008,37008,37008,39835,39835,39835,42662,42662,42662,45489,45489,45489,48316,48316,48316,51143,51143,51143,53970,53970,53970,56797,56797,56797,59624,59624,59624,62451,62451,62451,65535,65535,65535,0,0,0,2827,2827,2827,5654,5654,5654,8481,8481,8481,11308,11308,11308,14135,14135,14135,16962,16962,16962,19789,19789,19789,22616,22616,22616,25443,25443,25443,28270,28270,28270,31097,31097,31097,34181,34181,34181,37008,37008,37008,39835,39835,39835,42662,42662,42662,45489,45489,45489,48316,48316,48316,51143,51143,51143,53970,53970,53970,56797,56797,56797,59624,59624,59624,62451,62451,62451,65535,65535,65535,0,0,0,2827,2827,2827,5654,5654,5654,8481,8481,8481,11308,11308,11308,14135,14135,14135,16962,16962,16962,19789,19789,19789,22616,22616,22616,25443,25443,25443,28270,28270,28270,31097,31097,31097,34181,34181,34181,37008,37008,37008,39835,39835,39835,42662,42662,42662,45489,45489,45489,48316,48316,48316,51143,51143,51143,53970,53970,53970,56797,56797,56797,59624,59624,59624,62451,62451,62451,65535,65535,65535,0,0,0,2827,2827,2827,5654,5654,5654,8481,8481,8481,11308,11308,11308,14135,14135,14135,16962,16962,16962,19789,19789,19789,22616,22616,22616,25443,25443,25443,28270,28270,28270,31097,31097,31097,34181,34181,34181,37008,37008,37008,39835,39835,39835,42662,42662,42662,45489,45489,45489,48316,48316,48316,51143,51143,51143,53970,53970,53970,56797,56797,56797,59624,59624,59624,62451,62451,62451,65535,65535,65535]},{"photo":"photo-grey.png","fit":false,"ppi_used":299.9994,"size":[0.08000016000032001,0.060000120000240006],"fits":true,"summary":["Photo: photo-grey.png","Printer: Canon_MG3600_series","Paper: Letter","Size: 0.08 x 0.06 in at 300 ppi","Toning: neutral","Calibration: none"],"notes":[],"rendered_shape":[18,24,3],"rendered":[0,0,0,2827,2827,2827,5654,5654,5654,8481,8481,8481,11308,11308,11308,14135,14135,14135,16962,16962,16962,19789,19789,19789,22616,22616,22616,25443,25443,25443,28270,28270,28270,31097,31097,31097,34181,34181,34181,37008,37008,37008,39835,39835,39835,42662,42662,42662,45489,45489,45489,48316,48316,48316,51143,51143,51143,53970,53970,53970,56797,56797,56797,59624,59624,59624,62451,62451,62451,65535,65535,65535,0,0,0,2827,2827,2827,5654,5654,5654,8481,8481,8481,11308,11308,11308,14135,14135,14135,16962,16962,16962,19789,19789,19789,22616,22616,22616,25443,25443,25443,28270,28270,28270,31097,31097,31097,34181,34181,34181,37008,37008,37008,39835,39835,39835,42662,42662,42662,45489,45489,45489,48316,48316,48316,51143,51143,51143,53970,53970,53970,56797,56797,56797,59624,59624,59624,62451,62451,62451,65535,65535,65535,0,0,0,2827,2827,2827,5654,5654,5654,8481,8481,8481,11308,11308,11308,14135,14135,14135,16962,16962,16962,19789,19789,19789,22616,22616,22616,25443,25443,25443,28270,28270,28270,31097,31097,31097,34181,34181,34181,37008,37008,37008,39835,39835,39835,42662,42662,42662,45489,45489,45489,48316,48316,48316,51143,51143,51143,53970,53970,53970,56797,56797,56797,59624,59624,59624,62451,62451,62451,65535,65535,65535,0,0,0,2827,2827,2827,5654,5654,5654,8481,8481,8481,11308,11308,11308,14135,14135,14135,16962,16962,16962,19789,19789,19789,22616,22616,22616,25443,25443,25443,28270,28270,28270,31097,31097,31097,34181,34181,34181,37008,37008,37008,39835,39835,39835,42662,42662,42662,45489,45489,45489,48316,48316,48316,51143,51143,51143,53970,53970,53970,56797,56797,56797,59624,59624,59624,62451,62451,62451,65535,65535,65535,0,0,0,2827,2827,2827,5654,5654,5654,8481,8481,8481,11308,11308,11308,14135,14135,14135,16962,16962,16962,19789,19789,19789,22616,22616,22616,25443,25443,25443,28270,28270,28270,31097,31097,31097,34181,34181,34181,37008,37008,37008,39835,39835,39835,42662,42662,42662,45489,45489,45489,48316,48316,48316,51143,51143,51143,53970,53970,53970,56797,56797,56797,59624,59624,59624,62451,62451,62451,65535,65535,65535,0,0,0,2827,2827,2827,5654,5654,5654,8481,8481,8481,11308,11308,11308,14135,14135,14135,16962,16962,16962,19789,19789,19789,22616,22616,22616,25443,25443,25443,28270,28270,28270,31097,31097,31097,34181,34181,34181,37008,37008,37008,39835,39835,39835,42662,42662,42662,45489,45489,45489,48316,48316,48316,51143,51143,51143,53970,53970,53970,56797,56797,56797,59624,59624,59624,62451,62451,62451,65535,65535,65535,0,0,0,2827,2827,2827,5654,5654,5654,8481,8481,8481,11308,11308,11308,14135,14135,14135,16962,16962,16962,19789,19789,19789,22616,22616,22616,25443,25443,25443,28270,28270,28270,31097,31097,31097,34181,34181,34181,37008,37008,37008,39835,39835,39835,42662,42662,42662,45489,45489,45489,48316,48316,48316,51143,51143,51143,53970,53970,53970,56797,56797,56797,59624,59624,59624,62451,62451,62451,65535,65535,65535,0,0,0,2827,2827,2827,5654,5654,5654,8481,8481,8481,11308,11308,11308,14135,14135,14135,16962,16962,16962,19789,19789,19789,22616,22616,22616,25443,25443,25443,28270,28270,28270,31097,31097,31097,34181,34181,34181,37008,37008,37008,39835,39835,39835,42662,42662,42662,45489,45489,45489,48316,48316,48316,51143,51143,51143,53970,53970,53970,56797,56797,56797,59624,59624,59624,62451,62451,62451,65535,65535,65535,0,0,0,2827,2827,2827,5654,5654,5654,8481,8481,8481,11308,11308,11308,14135,14135,14135,16962,16962,16962,19789,19789,19789,22616,22616,22616,25443,25443,25443,28270,28270,28270,31097,31097,31097,34181,34181,34181,37008,37008,37008,39835,39835,39835,42662,42662,42662,45489,45489,45489,48316,48316,48316,51143,51143,51143,53970,53970,53970,56797,56797,56797,59624,59624,59624,62451,62451,62451,65535,65535,65535,0,0,0,2827,2827,2827,5654,5654,5654,8481,8481,8481,11308,11308,11308,14135,14135,14135,16962,16962,16962,19789,19789,19789,22616,22616,22616,25443,25443,25443,28270,28270,28270,31097,31097,31097,34181,34181,34181,37008,37008,37008,39835,39835,39835,42662,42662,42662,45489,45489,45489,48316,48316,48316,51143,51143,51143,53970,53970,53970,56797,56797,56797,59624,59624,59624,62451,62451,62451,65535,65535,65535,0,0,0,2827,2827,2827,5654,5654,5654,8481,8481,8481,11308,11308,11308,14135,14135,14135,16962,16962,16962,19789,19789,19789,22616,22616,22616,25443,25443,25443,28270,28270,28270,31097,31097,31097,34181,34181,34181,37008,37008,37008,39835,39835,39835,42662,42662,42662,45489,45489,45489,48316,48316,48316,51143,51143,51143,53970,53970,53970,56797,56797,56797,59624,59624,59624,62451,62451,62451,65535,65535,65535,0,0,0,2827,2827,2827,5654,5654,5654,8481,8481,8481,11308,11308,11308,14135,14135,14135,16962,16962,16962,19789,19789,19789,22616,22616,22616,25443,25443,25443,28270,28270,28270,31097,31097,31097,34181,34181,34181,37008,37008,37008,39835,39835,39835,42662,42662,42662,45489,45489,45489,48316,48316,48316,51143,51143,51143,53970,53970,53970,56797,56797,56797,59624,59624,59624,62451,62451,62451,65535,65535,65535,0,0,0,2827,2827,2827,5654,5654,5654,8481,8481,8481,11308,11308,11308,14135,14135,14135,16962,16962,16962,19789,19789,19789,22616,22616,22616,25443,25443,25443,28270,28270,28270,31097,31097,31097,34181,34181,34181,37008,37008,37008,39835,39835,39835,42662,42662,42662,45489,45489,45489,48316,48316,48316,51143,51143,51143,53970,53970,53970,56797,56797,56797,59624,59624,59624,62451,62451,62451,65535,65535,65535,0,0,0,2827,2827,2827,5654,5654,5654,8481,8481,8481,11308,11308,11308,14135,14135,14135,16962,16962,16962,19789,19789,19789,22616,22616,22616,25443,25443,25443,28270,28270,28270,31097,31097,31097,34181,34181,34181,37008,37008,37008,39835,39835,39835,42662,42662,42662,45489,45489,45489,48316,48316,48316,51143,51143,51143,53970,53970,53970,56797,56797,56797,59624,59624,59624,62451,62451,62451,65535,65535,65535,0,0,0,2827,2827,2827,5654,5654,5654,8481,8481,8481,11308,11308,11308,14135,14135,14135,16962,16962,16962,19789,19789,19789,22616,22616,22616,25443,25443,25443,28270,28270,28270,31097,31097,31097,34181,34181,34181,37008,37008,37008,39835,39835,39835,42662,42662,42662,45489,45489,45489,48316,48316,48316,51143,51143,51143,53970,53970,53970,56797,56797,56797,59624,59624,59624,62451,62451,62451,65535,65535,65535,0,0,0,2827,2827,2827,5654,5654,5654,8481,8481,8481,11308,11308,11308,14135,14135,14135,16962,16962,16962,19789,19789,19789,22616,22616,22616,25443,25443,25443,28270,28270,28270,31097,31097,31097,34181,34181,34181,37008,37008,37008,39835,39835,39835,42662,42662,42662,45489,45489,45489,48316,48316,48316,51143,51143,51143,53970,53970,53970,56797,56797,56797,59624,59624,59624,62451,62451,62451,65535,65535,65535,0,0,0,2827,2827,2827,5654,5654,5654,8481,8481,8481,11308,11308,11308,14135,14135,14135,16962,16962,16962,19789,19789,19789,22616,22616,22616,25443,25443,25443,28270,28270,28270,31097,31097,31097,34181,34181,34181,37008,37008,37008,39835,39835,39835,42662,42662,42662,45489,45489,45489,48316,48316,48316,51143,51143,51143,53970,53970,53970,56797,56797,56797,59624,59624,59624,62451,62451,62451,65535,65535,65535,0,0,0,2827,2827,2827,5654,5654,5654,8481,8481,8481,11308,11308,11308,14135,14135,14135,16962,16962,16962,19789,19789,19789,22616,22616,22616,25443,25443,25443,28270,28270,28270,31097,31097,31097,34181,34181,34181,37008,37008,37008,39835,39835,39835,42662,42662,42662,45489,45489,45489,48316,48316,48316,51143,51143,51143,53970,53970,53970,56797,56797,56797,59624,59624,59624,62451,62451,62451,65535,65535,65535]},{"photo":"photo-rgb-grey.png","fit":false,"ppi_used":300.0,"size":[0.08,0.06],"fits":true,"summary":["Photo: photo-rgb-grey.png","Printer: Canon_MG3600_series","Paper: Letter","Size: 0.08 x 0.06 in at 300 ppi","Toning: neutral","Calibration: none"],"notes":["This is a colour image; it was converted to greyscale."],"rendered_shape":[18,24,3],"rendered":[238,238,238,2774,2774,2774,5691,5691,5691,8427,8427,8427,11363,11363,11363,13971,13971,13971,16724,16724,16724,19735,19735,19735,22397,22397,22397,25700,25700,25700,28087,28087,28087,31281,31281,31281,34016,34016,34016,36935,36935,36935,39835,39835,39835,42478,42478,42478,45709,45709,45709,48371,48371,48371,50996,50996,50996,53989,53989,53989,56761,56761,56761,59863,59863,59863,62304,62304,62304,65351,65351,65351,19,19,19,2774,2774,2774,5619,5619,5619,8666,8666,8666,11181,11181,11181,14172,14172,14172,16816,16816,16816,19919,19919,19919,22543,22543,22543,25462,25462,25462,28216,28216,28216,30969,30969,30969,34200,34200,34200,37174,37174,37174,39597,39597,39597,42589,42589,42589,45361,45361,45361,48446,48446,48446,51070,51070,51070,54209,54209,54209,56779,56779,56779,59790,59790,59790,62286,62286,62286,65535,65535,65535,55,55,55,2723,2723,2723,5619,5619,5619,8243,8243,8243,11235,11235,11235,13878,13878,13878,16944,16944,16944,19735,19735,19735,22598,22598,22598,25370,25370,25370,28400,28400,28400,30895,30895,30895,34347,34347,34347,36824,36824,36824,40074,40074,40074,42644,42644,42644,45600,45600,45600,48555,48555,48555,51198,51198,51198,53823,53823,53823,56981,56981,56981,59624,59624,59624,62671,62671,62671,65516,65516,65516,0,0,0,2723,2723,2723,5453,5453,5453,8720,8720,8720,11125,11125,11125,13952,13952,13952,16908,16908,16908,19735,19735,19735,22855,22855,22855,25278,25278,25278,28436,28436,28436,31152,31152,31152,34071,34071,34071,37138,37138,37138,39890,39890,39890,42460,42460,42460,45251,45251,45251,48187,48187,48187,51382,51382,51382,54025,54025,54025,56963,56963,56963,59495,59495,59495,62341,62341,62341,65351,65351,65351,184,184,184,2846,2846,2846,5728,5728,5728,8298,8298,8298,11144,11144,11144,13878,13878,13878,16889,16889,16889,19661,19661,19661,22507,22507,22507,25425,25425,25425,28252,28252,28252,31061,31061,31061,34181,34181,34181,36806,36806,36806,39725,39725,39725,42735,42735,42735,45728,45728,45728,48389,48389,48389,51382,51382,51382,53952,53952,53952,56613,56613,56613,59551,59551,59551,62433,62433,62433,65480,65480,65480,0,0,0,2809,2809,2809,5857,5857,5857,8738,8738,8738,11051,11051,11051,14154,14154,14154,16908,16908,16908,19844,19844,19844,22855,22855,22855,25296,25296,25296,28344,28344,28344,31300,31300,31300,34053,34053,34053,37008,37008,37008,40055,40055,40055,42589,42589,42589,45655,45655,45655,48555,48555,48555,51216,51216,51216,53823,53823,53823,56908,56908,56908,59754,59754,59754,62599,62599,62599,65480,65480,65480,0,0,0,3049,3049,3049,5691,5691,5691,8463,8463,8463,11308,11308,11308,13878,13878,13878,16724,16724,16724,19587,19587,19587,22414,22414,22414,25407,25407,25407,28400,28400,28400,30895,30895,30895,34163,34163,34163,37008,37008,37008,39854,39854,39854,42589,42589,42589,45342,45342,45342,48243,48243,48243,50996,50996,50996,53989,53989,53989,56927,56927,56927,59440,59440,59440,62581,62581,62581,65516,65516,65516,0,0,0,2703,2703,2703,5769,5769,5769,8631,8631,8631,11529,11529,11529,13989,13989,13989,16743,16743,16743,19808,19808,19808,22616,22616,22616,25315,25315,25315,28325,28325,28325,30895,30895,30895,34420,34420,34420,36972,36972,36972,39578,39578,39578,42552,42552,42552,45251,45251,45251,48464,48464,48464,50941,50941,50941,53786,53786,53786,56540,56540,56540,59844,59844,59844,62378,62378,62378,65535,65535,65535,202,202,202,3049,3049,3049,5709,5709,5709,8224,8224,8224,11308,11308,11308,14100,14100,14100,17017,17017,17017,19643,19643,19643,22562,22562,22562,25462,25462,25462,28473,28473,28473,30950,30950,30950,34420,34420,34420,36824,36824,36824,40055,40055,40055,42698,42698,42698,45709,45709,45709,48243,48243,48243,51107,51107,51107,53805,53805,53805,56816,56816,56816,59367,59367,59367,62635,62635,62635,65462,65462,65462,184,184,184,2902,2902,2902,5709,5709,5709,8243,8243,8243,11382,11382,11382,14135,14135,14135,17128,17128,17128,19551,19551,19551,22855,22855,22855,25663,25663,25663,28050,28050,28050,31043,31043,31043,34016,34016,34016,37120,37120,37120,39707,39707,39707,42478,42478,42478,45489,45489,45489,48335,48335,48335,51179,51179,51179,53786,53786,53786,56559,56559,56559,59459,59459,59459,62396,62396,62396,65535,65535,65535,19,19,19,2723,2723,2723,5839,5839,5839,8243,8243,8243,11235,11235,11235,14062,14062,14062,17128,17128,17128,19919,19919,19919,22616,22616,22616,25480,25480,25480,28234,28234,28234,30895,30895,30895,34365,34365,34365,36972,36972,36972,39615,39615,39615,42792,42792,42792,45637,45637,45637,48555,48555,48555,50886,50886,50886,53860,53860,53860,56927,56927,56927,59551,59551,59551,62451,62451,62451,65351,65351,65351,55,55,55,3049,3049,3049,5548,5548,5548,8317,8317,8317,11089,11089,11089,13971,13971,13971,16760,16760,16760,20009,20009,20009,22378,22378,22378,25646,25646,25646,28289,28289,28289,31043,31043,31043,34071,34071,34071,37156,37156,37156,39908,39908,39908,42882,42882,42882,45269,45269,45269,48573,48573,48573,51088,51088,51088,54209,54209,54209,56963,56963,56963,59808,59808,59808,62524,62524,62524,65297,65297,65297,0,0,0,2626,2626,2626,5619,5619,5619,8536,8536,8536,11070,11070,11070,14338,14338,14338,16981,16981,16981,19973,19973,19973,22451,22451,22451,25480,25480,25480,28509,28509,28509,31300,31300,31300,34330,34330,34330,36806,36806,36806,39854,39854,39854,42792,42792,42792,45269,45269,45269,48096,48096,48096,51070,51070,51070,54006,54006,54006,57017,57017,57017,59660,59660,59660,62599,62599,62599,65516,65516,65516,73,73,73,2774,2774,2774,5636,5636,5636,8446,8446,8446,11474,11474,11474,14008,14008,14008,17074,17074,17074,19587,19587,19587,22836,22836,22836,25663,25663,25663,28436,28436,28436,31079,31079,31079,34347,34347,34347,37120,37120,37120,39983,39983,39983,42681,42681,42681,45269,45269,45269,48261,48261,48261,51179,51179,51179,54172,54172,54172,56742,56742,56742,59606,59606,59606,62322,62322,62322,65278,65278,65278,55,55,55,2902,2902,2902,5805,5805,5805,8684,8684,8684,11345,11345,11345,14209,14209,14209,17093,17093,17093,20046,20046,20046,22819,22819,22819,25296,25296,25296,28270,28270,28270,31281,31281,31281,34053,34053,34053,37063,37063,37063,40038,40038,40038,42810,42810,42810,45525,45525,45525,48500,48500,48500,51014,51014,51014,54043,54043,54043,56687,56687,56687,59367,59367,59367,62708,62708,62708,65516,65516,65516,0,0,0,2703,2703,2703,5875,5875,5875,8738,8738,8738,11529,11529,11529,14117,14117,14117,16724,16724,16724,19844,19844,19844,22414,22414,22414,25296,25296,25296,28142,28142,28142,31209,31209,31209,34254,34254,34254,36843,36843,36843,39578,39578,39578,42424,42424,42424,45416,45416,45416,48536,48536,48536,50996,50996,50996,53970,53970,53970,56816,56816,56816,59826,59826,59826,62231,62231,62231,65333,65333,65333,19,19,19,2755,2755,2755,5416,5416,5416,8374,8374,8374,11106,11106,11106,13916,13916,13916,16779,16779,16779,19919,19919,19919,22873,22873,22873,25407,25407,25407,28325,28325,28325,31317,31317,31317,34163,34163,34163,36954,36954,36954,39597,39597,39597,42442,42442,42442,45746,45746,45746,48261,48261,48261,51216,51216,51216,53915,53915,53915,56981,56981,56981,59660,59660,59660,62267,62267,62267,65351,65351,65351,202,202,202,3012,3012,3012,5709,5709,5709,8595,8595,8595,11458,11458,11458,13989,13989,13989,17201,17201,17201,19606,19606,19606,22873,22873,22873,25443,25443,25443,28289,28289,28289,31300,31300,31300,34311,34311,34311,36824,36824,36824,39578,39578,39578,42644,42644,42644,45471,45471,45471,48482,48482,48482,51273,51273,51273,54100,54100,54100,56577,56577,56577,59624,59624,59624,62708,62708,62708,65351,65351,65351]},{"photo":"photo-grey16.tif","mode":"negative","fit":false,"ppi":40.0,"negative_colour":"green","mirror":true,"safe_edge":0.25,"ppi_used":40.0,"size":[1.1,0.95],"fits":true,"summary":["Photo: photo-grey16.tif","Output: digital negative","Printer: Canon_MG3600_series","Paper: Letter","Size: 1.10 x 0.95 in with a 0.25 in safe edge","Colour: green","Process curve: none (uncalibrated)","Mirrored: yes"],"notes":[],"rendered_shape":[38,44,3],"rendered":[6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,7847,29716,13775,9378,30029,14656,11332,30502,15906,13564,31145,17477,15976,31960,19308,18505,32944,21345,21111,34090,23538,23771,35386,25851,26469,36823,28257,29195,38386,30733,31940,40063,33265,34703,41843,35842,37476,43711,38453,40260,45660,41092,43051,47679,43756,45849,49759,46437,48651,51893,49134,51458,54077,51845,54268,56301,54567,57081,58564,57297,59898,60860,60037,62715,63184,62783,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,7847,29716,13775,9378,30029,14656,11332,30502,15906,13564,31145,17477,15976,31960,19308,18505,32944,21345,21111,34090,23538,23771,35386,25851,26469,36823,28257,29195,38386,30733,31940,40063,33265,34703,41843,35842,37476,43711,38453,40260,45660,41092,43051,47679,43756,45849,49759,46437,48651,51893,49134,51458,54077,51845,54268,56301,54567,57081,58564,57297,59898,60860,60037,62715,63184,62783,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,7847,29716,13775,9378,30029,14656,11332,30502,15906,13564,31145,17477,15976,31960,19308,18505,32944,21345,21111,34090,23538,23771,35386,25851,26469,36823,28257,29195,38386,30733,31940,40063,33265,34703,41843,35842,37476,43711,38453,40260,45660,41092,43051,47679,43756,45849,49759,46437,48651,51893,49134,51458,54077,51845,54268,56301,54567,57081,58564,57297,59898,60860,60037,62715,63184,62783,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,7847,29716,13775,9378,30029,14656,11332,30502,15906,13564,31145,17477,15976,31960,19308,18505,32944,21345,21111,34090,23538,23771,35386,25851,26469,36823,28257,29195,38386,30733,31940,40063,33265,34703,41843,35842,37476,43711,38453,40260,45660,41092,43051,47679,43756,45849,49759,46437,48651,51893,49134,51458,54077,51845,54268,56301,54567,57081,58564,57297,59898,60860,60037,62715,63184,62783,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,7847,29716,13775,9378,30029,14656,11332,30502,15906,13564,31145,17477,15976,31960,19308,18505,32944,21345,21111,34090,23538,23771,35386,25851,26469,36823,28257,29195,38386,30733,31940,40063,33265,34703,41843,35842,37476,43711,38453,40260,45660,41092,43051,47679,43756,45849,49759,46437,48651,51893,49134,51458,54077,51845,54268,56301,54567,57081,58564,57297,59898,60860,60037,62715,63184,62783,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,7847,29716,13775,9378,30029,14656,11332,30502,15906,13564,31145,17477,15976,31960,19308,18505,32944,21345,21111,34090,23538,23771,35386,25851,26469,36823,28257,29195,38386,30733,31940,40063,33265,34703,41843,35842,37476,43711,38453,40260,45660,41092,43051,47679,43756,45849,49759,46437,48651,51893,49134,51458,54077,51845,54268,56301,54567,57081,58564,57297,59898,60860,60037,62715,63184,62783,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,7847,29716,13775,9378,30029,14656,11332,30502,15906,13564,31145,17477,15976,31960,19308,18505,32944,21345,21111,34090,23538,23771,35386,25851,26469,36823,28257,29195,38386,30733,31940,40063,33265,34703,41843,35842,37476,43711,38453,40260,45660,41092,43051,47679,43756,45849,49759,46437,48651,51893,49134,51458,54077,51845,54268,56301,54567,57081,58564,57297,59898,60860,60037,62715,63184,62783,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,7847,29716,13775,9378,30029,14656,11332,30502,15906,13564,31145,17477,15976,31960,19308,18505,32944,21345,21111,34090,23538,23771,35386,25851,26469,36823,28257,29195,38386,30733,31940,40063,33265,34703,41843,35842,37476,43711,38453,40260,45660,41092,43051,47679,43756,45849,49759,46437,48651,51893,49134,51458,54077,51845,54268,56301,54567,57081,58564,57297,59898,60860,60037,62715,63184,62783,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,7847,29716,13775,9378,30029,14656,11332,30502,15906,13564,31145,17477,15976,31960,19308,18505,32944,21345,21111,34090,23538,23771,35386,25851,26469,36823,28257,29195,38386,30733,31940,40063,33265,34703,41843,35842,37476,43711,38453,40260,45660,41092,43051,47679,43756,45849,49759,46437,48651,51893,49134,51458,54077,51845,54268,56301,54567,57081,58564,57297,59898,60860,60037,62715,63184,62783,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,7847,29716,13775,9378,30029,14656,11332,30502,15906,13564,31145,17477,15976,31960,19308,18505,32944,21345,21111,34090,23538,23771,35386,25851,26469,36823,28257,29195,38386,30733,31940,40063,33265,34703,41843,35842,37476,43711,38453,40260,45660,41092,43051,47679,43756,45849,49759,46437,48651,51893,49134,51458,54077,51845,54268,56301,54567,57081,58564,57297,59898,60860,60037,62715,63184,62783,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,7847,29716,13775,9378,30029,14656,11332,30502,15906,13564,31145,17477,15976,31960,19308,18505,32944,21345,21111,34090,23538,23771,35386,25851,26469,36823,28257,29195,38386,30733,31940,40063,33265,34703,41843,35842,37476,43711,38453,40260,45660,41092,43051,47679,43756,45849,49759,46437,48651,51893,49134,51458,54077,51845,54268,56301,54567,57081,58564,57297,59898,60860,60037,62715,63184,62783,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,7847,29716,13775,9378,30029,14656,11332,30502,15906,13564,31145,17477,15976,31960,19308,18505,32944,21345,21111,34090,23538,23771,35386,25851,26469,36823,28257,29195,38386,30733,31940,40063,33265,34703,41843,35842,37476,43711,38453,40260,45660,41092,43051,47679,43756,45849,49759,46437,48651,51893,49134,51458,54077,51845,54268,56301,54567,57081,58564,57297,59898,60860,60037,62715,63184,62783,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,7847,29716,13775,9378,30029,14656,11332,30502,15906,13564,31145,17477,15976,31960,19308,18505,32944,21345,21111,34090,23538,23771,35386,25851,26469,36823,28257,29195,38386,30733,31940,40063,33265,34703,41843,35842,37476,43711,38453,40260,45660,41092,43051,47679,43756,45849,49759,46437,48651,51893,49134,51458,54077,51845,54268,56301,54567,57081,58564,57297,59898,60860,60037,62715,63184,62783,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,7847,29716,13775,9378,30029,14656,11332,30502,15906,13564,31145,17477,15976,31960,19308,18505,32944,21345,21111,34090,23538,23771,35386,25851,26469,36823,28257,29195,38386,30733,31940,40063,33265,34703,41843,35842,37476,43711,38453,40260,45660,41092,43051,47679,43756,45849,49759,46437,48651,51893,49134,51458,54077,51845,54268,56301,54567,57081,58564,57297,59898,60860,60037,62715,63184,62783,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,7847,29716,13775,9378,30029,14656,11332,30502,15906,13564,31145,17477,15976,31960,19308,18505,32944,21345,21111,34090,23538,23771,35386,25851,26469,36823,28257,29195,38386,30733,31940,40063,33265,34703,41843,35842,37476,43711,38453,40260,45660,41092,43051,47679,43756,45849,49759,46437,48651,51893,49134,51458,54077,51845,54268,56301,54567,57081,58564,57297,59898,60860,60037,62715,63184,62783,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,7847,29716,13775,9378,30029,14656,11332,30502,15906,13564,31145,17477,15976,31960,19308,18505,32944,21345,21111,34090,23538,23771,35386,25851,26469,36823,28257,29195,38386,30733,31940,40063,33265,34703,41843,35842,37476,43711,38453,40260,45660,41092,43051,47679,43756,45849,49759,46437,48651,51893,49134,51458,54077,51845,54268,56301,54567,57081,58564,57297,59898,60860,60037,62715,63184,62783,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,7847,29716,13775,9378,30029,14656,11332,30502,15906,13564,31145,17477,15976,31960,19308,18505,32944,21345,21111,34090,23538,23771,35386,25851,26469,36823,28257,29195,38386,30733,31940,40063,33265,34703,41843,35842,37476,43711,38453,40260,45660,41092,43051,47679,43756,45849,49759,46437,48651,51893,49134,51458,54077,51845,54268,56301,54567,57081,58564,57297,59898,60860,60037,62715,63184,62783,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,7847,29716,13775,9378,30029,14656,11332,30502,15906,13564,31145,17477,15976,31960,19308,18505,32944,21345,21111,34090,23538,23771,35386,25851,26469,36823,28257,29195,38386,30733,31940,40063,33265,34703,41843,35842,37476,43711,38453,40260,45660,41092,43051,47679,43756,45849,49759,46437,48651,51893,49134,51458,54077,51845,54268,56301,54567,57081,58564,57297,59898,60860,60037,62715,63184,62783,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107]},{"photo":"photo-grey16.tif","mode":"negative","process":true,"safe_edge":0.1,"ppi_used":3.2876712328767126,"size":[7.5,5.675],"fits":true,"summary":["Photo: photo-grey16.tif","Output: digital negative","Printer: Canon_MG3600_series","Paper: Letter","Size: 7.50 x 5.67 in with a 0.1 in safe edge","Colour: orange","Process curve: session-process.oqproc","Mirrored: no"],"notes":[],"rendered_shape":[18,24,3],"rendered":[65535,65535,65535,64977,61156,60224,64599,57973,56289,64285,55165,52748,64015,52598,49443,63778,50215,46303,63568,47987,43287,63381,45898,40374,63215,43938,37548,63068,42103,34795,62937,40389,32106,62822,38798,29478,62720,37329,26901,62632,35986,24378,62555,34770,21904,62489,33684,19479,62433,32729,17107,62387,31907,14794,62349,31215,12548,62318,30653,10391,62295,30213,8357,62279,29890,6508,62267,29671,4947,62258,29491,3277,65535,65535,65535,64977,61156,60224,64599,57973,56289,64285,55165,52748,64015,52598,49443,63778,50215,46303,63568,47987,43287,63381,45898,40374,63215,43938,37548,63068,42103,34795,62937,40389,32106,62822,38798,29478,62720,37329,26901,62632,35986,24378,62555,34770,21904,62489,33684,19479,62433,32729,17107,62387,31907,14794,62349,31215,12548,62318,30653,10391,62295,30213,8357,62279,29890,6508,62267,29671,4947,62258,29491,3277,65535,65535,65535,64977,61156,60224,64599,57973,56289,64285,55165,52748,64015,52598,49443,63778,50215,46303,63568,47987,43287,63381,45898,40374,63215,43938,37548,63068,42103,34795,62937,40389,32106,62822,38798,29478,62720,37329,26901,62632,35986,24378,62555,34770,21904,62489,33684,19479,62433,32729,17107,62387,31907,14794,62349,31215,12548,62318,30653,10391,62295,30213,8357,62279,29890,6508,62267,29671,4947,62258,29491,3277,65535,65535,65535,64977,61156,60224,64599,57973,56289,64285,55165,52748,64015,52598,49443,63778,50215,46303,63568,47987,43287,63381,45898,40374,63215,43938,37548,63068,42103,34795,62937,40389,32106,62822,38798,29478,62720,37329,26901,62632,35986,24378,62555,34770,21904,62489,33684,19479,62433,32729,17107,62387,31907,14794,62349,31215,12548,62318,30653,10391,62295,30213,8357,62279,29890,6508,62267,29671,4947,62258,29491,3277,65535,65535,65535,64977,61156,60224,64599,57973,56289,64285,55165,52748,64015,52598,49443,63778,50215,46303,63568,47987,43287,63381,45898,40374,63215,43938,37548,63068,42103,34795,62937,40389,32106,62822,38798,29478,62720,37329,26901,62632,35986,24378,62555,34770,21904,62489,33684,19479,62433,32729,17107,62387,31907,14794,62349,31215,12548,62318,30653,10391,62295,30213,8357,62279,29890,6508,62267,29671,4947,62258,29491,3277,65535,65535,65535,64977,61156,60224,64599,57973,56289,64285,55165,52748,64015,52598,49443,63778,50215,46303,63568,47987,43287,63381,45898,40374,63215,43938,37548,63068,42103,34795,62937,40389,32106,62822,38798,29478,62720,37329,26901,62632,35986,24378,62555,34770,21904,62489,33684,19479,62433,32729,17107,62387,31907,14794,62349,31215,12548,62318,30653,10391,62295,30213,8357,62279,29890,6508,62267,29671,4947,62258,29491,3277,65535,65535,65535,64977,61156,60224,64599,57973,56289,64285,55165,52748,64015,52598,49443,63778,50215,46303,63568,47987,43287,63381,45898,40374,63215,43938,37548,63068,42103,34795,62937,40389,32106,62822,38798,29478,62720,37329,26901,62632,35986,24378,62555,34770,21904,62489,33684,19479,62433,32729,17107,62387,31907,14794,62349,31215,12548,62318,30653,10391,62295,30213,8357,62279,29890,6508,62267,29671,4947,62258,29491,3277,65535,65535,65535,64977,61156,60224,64599,57973,56289,64285,55165,52748,64015,52598,49443,63778,50215,46303,63568,47987,43287,63381,45898,40374,63215,43938,37548,63068,42103,34795,62937,40389,32106,62822,38798,29478,62720,37329,26901,62632,35986,24378,62555,34770,21904,62489,33684,19479,62433,32729,17107,62387,31907,14794,62349,31215,12548,62318,30653,10391,62295,30213,8357,62279,29890,6508,62267,29671,4947,62258,29491,3277,65535,65535,65535,64977,61156,60224,64599,57973,56289,64285,55165,52748,64015,52598,49443,63778,50215,46303,63568,47987,43287,63381,45898,40374,63215,43938,37548,63068,42103,34795,62937,40389,32106,62822,38798,29478,62720,37329,26901,62632,35986,24378,62555,34770,21904,62489,33684,19479,62433,32729,17107,62387,31907,14794,62349,31215,12548,62318,30653,10391,62295,30213,8357,62279,29890,6508,62267,29671,4947,62258,29491,3277,65535,65535,65535,64977,61156,60224,64599,57973,56289,64285,55165,52748,64015,52598,49443,63778,50215,46303,63568,47987,43287,63381,45898,40374,63215,43938,37548,63068,42103,34795,62937,40389,32106,62822,38798,29478,62720,37329,26901,62632,35986,24378,62555,34770,21904,62489,33684,19479,62433,32729,17107,62387,31907,14794,62349,31215,12548,62318,30653,10391,62295,30213,8357,62279,29890,6508,62267,29671,4947,62258,29491,3277,65535,65535,65535,64977,61156,60224,64599,57973,56289,64285,55165,52748,64015,52598,49443,63778,50215,46303,63568,47987,43287,63381,45898,40374,63215,43938,37548,63068,42103,34795,62937,40389,32106,62822,38798,29478,62720,37329,26901,62632,35986,24378,62555,34770,21904,62489,33684,19479,62433,32729,17107,62387,31907,14794,62349,31215,12548,62318,30653,10391,62295,30213,8357,62279,29890,6508,62267,29671,4947,62258,29491,3277,65535,65535,65535,64977,61156,60224,64599,57973,56289,64285,55165,52748,64015,52598,49443,63778,50215,46303,63568,47987,43287,63381,45898,40374,63215,43938,37548,63068,42103,34795,62937,40389,32106,62822,38798,29478,62720,37329,26901,62632,35986,24378,62555,34770,21904,62489,33684,19479,62433,32729,17107,62387,31907,14794,62349,31215,12548,62318,30653,10391,62295,30213,8357,62279,29890,6508,62267,29671,4947,62258,29491,3277,65535,65535,65535,64977,61156,60224,64599,57973,56289,64285,55165,52748,64015,52598,49443,63778,50215,46303,63568,47987,43287,63381,45898,40374,63215,43938,37548,63068,42103,34795,62937,40389,32106,62822,38798,29478,62720,37329,26901,62632,35986,24378,62555,34770,21904,62489,33684,19479,62433,32729,17107,62387,31907,14794,62349,31215,12548,62318,30653,10391,62295,30213,8357,62279,29890,6508,62267,29671,4947,62258,29491,3277,65535,65535,65535,64977,61156,60224,64599,57973,56289,64285,55165,52748,64015,52598,49443,63778,50215,46303,63568,47987,43287,63381,45898,40374,63215,43938,37548,63068,42103,34795,62937,40389,32106,62822,38798,29478,62720,37329,26901,62632,35986,24378,62555,34770,21904,62489,33684,19479,62433,32729,17107,62387,31907,14794,62349,31215,12548,62318,30653,10391,62295,30213,8357,62279,29890,6508,62267,29671,4947,62258,29491,3277,65535,65535,65535,64977,61156,60224,64599,57973,56289,64285,55165,52748,64015,52598,49443,63778,50215,46303,63568,47987,43287,63381,45898,40374,63215,43938,37548,63068,42103,34795,62937,40389,32106,62822,38798,29478,62720,37329,26901,62632,35986,24378,62555,34770,21904,62489,33684,19479,62433,32729,17107,62387,31907,14794,62349,31215,12548,62318,30653,10391,62295,30213,8357,62279,29890,6508,62267,29671,4947,62258,29491,3277,65535,65535,65535,64977,61156,60224,64599,57973,56289,64285,55165,52748,64015,52598,49443,63778,50215,46303,63568,47987,43287,63381,45898,40374,63215,43938,37548,63068,42103,34795,62937,40389,32106,62822,38798,29478,62720,37329,26901,62632,35986,24378,62555,34770,21904,62489,33684,19479,62433,32729,17107,62387,31907,14794,62349,31215,12548,62318,30653,10391,62295,30213,8357,62279,29890,6508,62267,29671,4947,62258,29491,3277,65535,65535,65535,64977,61156,60224,64599,57973,56289,64285,55165,52748,64015,52598,49443,63778,50215,46303,63568,47987,43287,63381,45898,40374,63215,43938,37548,63068,42103,34795,62937,40389,32106,62822,38798,29478,62720,37329,26901,62632,35986,24378,62555,34770,21904,62489,33684,19479,62433,32729,17107,62387,31907,14794,62349,31215,12548,62318,30653,10391,62295,30213,8357,62279,29890,6508,62267,29671,4947,62258,29491,3277,65535,65535,65535,64977,61156,60224,64599,57973,56289,64285,55165,52748,64015,52598,49443,63778,50215,46303,63568,47987,43287,63381,45898,40374,63215,43938,37548,63068,42103,34795,62937,40389,32106,62822,38798,29478,62720,37329,26901,62632,35986,24378,62555,34770,21904,62489,33684,19479,62433,32729,17107,62387,31907,14794,62349,31215,12548,62318,30653,10391,62295,30213,8357,62279,29890,6508,62267,29671,4947,62258,29491,3277]},{"photo":"photo-grey16.tif","mode":"negative","max_size":[2.0,3.0],"safe_edge":0.25,"ppi_used":12.0,"size":[2.5,2.0],"fits":true,"summary":["Photo: photo-grey16.tif","Output: digital negative","Printer: Canon_MG3600_series","Paper: Letter","Fit within: 3 x 2 in","Size: 2.50 x 2.00 in with a 0.25 in safe edge","Colour: green","Process curve: none (uncalibrated)","Mirrored: no"],"notes":[],"rendered_shape":[24,30,3],"rendered":[6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107]},{"photo":"photo-grey16.tif","max_size":[2.5,1.5],"ppi_used":12.0,"size":[2.0,1.5],"fits":true,"summary":["Photo: photo-grey16.tif","Printer: Canon_MG3600_series","Paper: Letter","Fit within: 2.5 x 1.5 in","Size: 2.00 x 1.50 in at 12 ppi","Toning: neutral","Calibration: none"],"notes":[],"rendered_shape":[18,24,3],"rendered":[0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535]},{"photo":"photo-grey16.tif","max_size":[40.0,30.0],"paper":"4x6","ppi_used":8.0,"size":[3.0,2.25],"fits":true,"summary":["Photo: photo-grey16.tif","Printer: Canon_MG3600_series","Paper: 4x6","Fit within: 40 x 30 in","Size: 3.00 x 2.25 in at 8 ppi","Toning: neutral","Calibration: none"],"notes":[],"rendered_shape":[18,24,3],"rendered":[0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535]},{"photo":"photo-grey16.tif","mode":"negative","fit":false,"ppi":20.0,"safe_edge":0.2,"outline":0.15,"ppi_used":20.0,"size":[1.9,1.6],"fits":true,"summary":["Photo: photo-grey16.tif","Output: digital negative","Printer: Canon_MG3600_series","Paper: Letter","Size: 1.90 x 1.60 in with a 0.2 in safe edge and a 0.15 in black outline","Colour: green","Process curve: none (uncalibrated)","Mirrored: no"],"notes":[],"rendered_shape":[32,38,3],"rendered":[6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,65535,65535,65535,65535,65535,65535,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,65535,65535,65535,65535,65535,65535,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,65535,65535,65535,65535,65535,65535,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,65535,65535,65535,65535,65535,65535,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,65535,65535,65535,65535,65535,65535,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,65535,65535,65535,65535,65535,65535,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,65535,65535,65535,65535,65535,65535,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,65535,65535,65535,65535,65535,65535,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,65535,65535,65535,65535,65535,65535,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,65535,65535,65535,65535,65535,65535,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,65535,65535,65535,65535,65535,65535,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,65535,65535,65535,65535,65535,65535,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,65535,65535,65535,65535,65535,65535,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,65535,65535,65535,65535,65535,65535,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,65535,65535,65535,65535,65535,65535,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,65535,65535,65535,65535,65535,65535,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,65535,65535,65535,65535,65535,65535,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,65535,65535,65535,65535,65535,65535,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107]},{"photo":"photo-grey16.tif","mode":"negative","max_size":[2.0,3.0],"safe_edge":0.25,"outline":0.1,"ppi_used":13.846153846153845,"size":[2.4333333333333336,2.0],"fits":true,"summary":["Photo: photo-grey16.tif","Output: digital negative","Printer: Canon_MG3600_series","Paper: Letter","Fit within: 3 x 2 in","Size: 2.43 x 2.00 in with a 0.25 in safe edge and a 0.1 in black outline","Colour: green","Process curve: none (uncalibrated)","Mirrored: no"],"notes":[],"rendered_shape":[26,32,3],"rendered":[6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107]}]} +{"photos":[{"file":"photo-grey.png","shape":[18,24],"pixels":[0,2827,5654,8481,11308,14135,16962,19789,22616,25443,28270,31097,34181,37008,39835,42662,45489,48316,51143,53970,56797,59624,62451,65535,0,2827,5654,8481,11308,14135,16962,19789,22616,25443,28270,31097,34181,37008,39835,42662,45489,48316,51143,53970,56797,59624,62451,65535,0,2827,5654,8481,11308,14135,16962,19789,22616,25443,28270,31097,34181,37008,39835,42662,45489,48316,51143,53970,56797,59624,62451,65535,0,2827,5654,8481,11308,14135,16962,19789,22616,25443,28270,31097,34181,37008,39835,42662,45489,48316,51143,53970,56797,59624,62451,65535,0,2827,5654,8481,11308,14135,16962,19789,22616,25443,28270,31097,34181,37008,39835,42662,45489,48316,51143,53970,56797,59624,62451,65535,0,2827,5654,8481,11308,14135,16962,19789,22616,25443,28270,31097,34181,37008,39835,42662,45489,48316,51143,53970,56797,59624,62451,65535,0,2827,5654,8481,11308,14135,16962,19789,22616,25443,28270,31097,34181,37008,39835,42662,45489,48316,51143,53970,56797,59624,62451,65535,0,2827,5654,8481,11308,14135,16962,19789,22616,25443,28270,31097,34181,37008,39835,42662,45489,48316,51143,53970,56797,59624,62451,65535,0,2827,5654,8481,11308,14135,16962,19789,22616,25443,28270,31097,34181,37008,39835,42662,45489,48316,51143,53970,56797,59624,62451,65535,0,2827,5654,8481,11308,14135,16962,19789,22616,25443,28270,31097,34181,37008,39835,42662,45489,48316,51143,53970,56797,59624,62451,65535,0,2827,5654,8481,11308,14135,16962,19789,22616,25443,28270,31097,34181,37008,39835,42662,45489,48316,51143,53970,56797,59624,62451,65535,0,2827,5654,8481,11308,14135,16962,19789,22616,25443,28270,31097,34181,37008,39835,42662,45489,48316,51143,53970,56797,59624,62451,65535,0,2827,5654,8481,11308,14135,16962,19789,22616,25443,28270,31097,34181,37008,39835,42662,45489,48316,51143,53970,56797,59624,62451,65535,0,2827,5654,8481,11308,14135,16962,19789,22616,25443,28270,31097,34181,37008,39835,42662,45489,48316,51143,53970,56797,59624,62451,65535,0,2827,5654,8481,11308,14135,16962,19789,22616,25443,28270,31097,34181,37008,39835,42662,45489,48316,51143,53970,56797,59624,62451,65535,0,2827,5654,8481,11308,14135,16962,19789,22616,25443,28270,31097,34181,37008,39835,42662,45489,48316,51143,53970,56797,59624,62451,65535,0,2827,5654,8481,11308,14135,16962,19789,22616,25443,28270,31097,34181,37008,39835,42662,45489,48316,51143,53970,56797,59624,62451,65535,0,2827,5654,8481,11308,14135,16962,19789,22616,25443,28270,31097,34181,37008,39835,42662,45489,48316,51143,53970,56797,59624,62451,65535],"dpi":[299.9994,299.9994],"converted":false,"cropped":false},{"file":"photo-rgb-grey.png","shape":[18,24],"pixels":[238,2774,5691,8427,11363,13971,16724,19735,22397,25700,28087,31281,34016,36935,39835,42478,45709,48371,50996,53989,56761,59863,62304,65351,19,2774,5619,8666,11181,14172,16816,19919,22543,25462,28216,30969,34200,37174,39597,42589,45361,48446,51070,54209,56779,59790,62286,65535,55,2723,5619,8243,11235,13878,16944,19735,22598,25370,28400,30895,34347,36824,40074,42644,45600,48555,51198,53823,56981,59624,62671,65516,0,2723,5453,8720,11125,13952,16908,19735,22855,25278,28436,31152,34071,37138,39890,42460,45251,48187,51382,54025,56963,59495,62341,65351,184,2846,5728,8298,11144,13878,16889,19661,22507,25425,28252,31061,34181,36806,39725,42735,45728,48389,51382,53952,56613,59551,62433,65480,0,2809,5857,8738,11051,14154,16908,19844,22855,25296,28344,31300,34053,37008,40055,42589,45655,48555,51216,53823,56908,59754,62599,65480,0,3049,5691,8463,11308,13878,16724,19587,22414,25407,28400,30895,34163,37008,39854,42589,45342,48243,50996,53989,56927,59440,62581,65516,0,2703,5769,8631,11529,13989,16743,19808,22616,25315,28325,30895,34420,36972,39578,42552,45251,48464,50941,53786,56540,59844,62378,65535,202,3049,5709,8224,11308,14100,17017,19643,22562,25462,28473,30950,34420,36824,40055,42698,45709,48243,51107,53805,56816,59367,62635,65462,184,2902,5709,8243,11382,14135,17128,19551,22855,25663,28050,31043,34016,37120,39707,42478,45489,48335,51179,53786,56559,59459,62396,65535,19,2723,5839,8243,11235,14062,17128,19919,22616,25480,28234,30895,34365,36972,39615,42792,45637,48555,50886,53860,56927,59551,62451,65351,55,3049,5548,8317,11089,13971,16760,20009,22378,25646,28289,31043,34071,37156,39908,42882,45269,48573,51088,54209,56963,59808,62524,65297,0,2626,5619,8536,11070,14338,16981,19973,22451,25480,28509,31300,34330,36806,39854,42792,45269,48096,51070,54006,57017,59660,62599,65516,73,2774,5636,8446,11474,14008,17074,19587,22836,25663,28436,31079,34347,37120,39983,42681,45269,48261,51179,54172,56742,59606,62322,65278,55,2902,5805,8684,11345,14209,17093,20046,22819,25296,28270,31281,34053,37063,40038,42810,45525,48500,51014,54043,56687,59367,62708,65516,0,2703,5875,8738,11529,14117,16724,19844,22414,25296,28142,31209,34254,36843,39578,42424,45416,48536,50996,53970,56816,59826,62231,65333,19,2755,5416,8374,11106,13916,16779,19919,22873,25407,28325,31317,34163,36954,39597,42442,45746,48261,51216,53915,56981,59660,62267,65351,202,3012,5709,8595,11458,13989,17201,19606,22873,25443,28289,31300,34311,36824,39578,42644,45471,48482,51273,54100,56577,59624,62708,65351],"dpi":null,"converted":true,"cropped":false},{"file":"photo-colour.png","shape":[18,24],"pixels":[20004,51931,45197,31721,29001,49960,29883,30349,28793,37632,57980,24992,29115,25524,33530,19881,43801,44336,23251,32502,45178,20057,41113,28519,24685,55850,26342,33246,23775,61970,35767,57209,48789,20245,48799,31359,54551,37715,29220,56383,17281,51563,15489,43931,53315,19758,54459,14262,35037,32478,38516,35477,51544,24273,55311,31966,26925,19291,42250,19441,25620,46095,25583,43990,26066,47113,17178,54015,40737,24912,4537,49967,34197,24653,43386,45464,46951,12793,55381,16687,28991,35200,39873,29140,52473,39206,24827,24276,20100,52143,44719,41457,31490,33001,34195,49676,12714,33862,40152,50064,51202,37942,54476,41114,27539,12277,47198,31214,44981,54838,39695,27247,35216,29028,48347,42389,18099,42490,27218,48631,40027,41628,39290,51977,36373,29165,31120,45934,27745,55674,45011,33361,28377,44639,34018,47080,16399,55779,44277,29962,27321,55620,47002,54854,57034,31002,37087,22295,49719,42759,31773,12270,47290,20596,48910,24954,25456,44271,59144,34675,24282,21718,29151,21187,42935,35622,24503,15385,49385,20919,40094,30982,32690,36318,22952,45706,32776,56342,23884,26403,37047,22242,21976,34167,52030,46957,10710,59989,34875,16014,18418,63782,29715,29394,30863,29327,48130,51054,27231,47157,40701,43314,34859,53857,24948,9951,28495,36877,32641,26948,46600,49434,58296,9074,31756,14748,52954,61921,58281,54425,33138,33573,40709,57895,39501,50935,21260,33950,28091,23711,42983,48839,35605,27466,30732,52417,28429,41185,45774,21742,16826,27137,53043,30717,26662,29546,32655,46381,26203,28826,53814,47099,45783,54394,48724,26419,38200,33113,34468,26965,14915,48925,46042,28954,47182,41859,37544,48254,22580,39194,15724,41098,15782,44708,18373,34234,44697,20231,39827,21417,60879,36920,49509,44215,45485,50293,56853,53008,45948,35748,19138,34400,40352,28612,53916,15105,49538,30146,13329,48946,35179,23585,22194,15697,43557,28380,37201,43609,35178,49065,31979,61224,19718,41208,34451,28236,20782,32282,23110,55080,16206,38232,21411,48696,56876,35139,44025,40494,45808,39721,21365,38839,38764,44221,13298,50380,52561,34849,30182,25843,30454,12125,18682,49974,29721,40139,25503,39964,41728,19119,15587,20109,41580,43044,58809,27476,29748,37415,53448,17350,46778,53178,31811,37478,35822,43379,13052,58645,33568,37676,26239,15851,42866,60075,6430,44481,42181,48035,56913,31531,16010,35337,23508,40934,24892,43758,28154,38113,28053,16826,31055,39373,52053,43600,32676,17533,5789,38278,28827,24158,26227,27290,40995,53740,30011,36237,57624,35749,37429,48815,34263,46957,15979,24727,40332,47492,33726,37325,35338,27799,27115,28649,32099,56872,43633,7112,54129,13069,47070,39435,34653,43515],"dpi":[240.00459999999998,240.00459999999998],"converted":true,"cropped":false},{"file":"photo-rgba.png","shape":[14,21],"pixels":[184,2846,5728,8298,11144,13878,16889,19661,22507,25425,28252,31061,34181,36806,39725,42735,45728,48389,51382,53952,56613,0,2809,5857,8738,11051,14154,16908,19844,22855,25296,28344,31300,34053,37008,40055,42589,45655,48555,51216,53823,56908,0,3049,5691,8463,11308,13878,16724,19587,22414,25407,28400,30895,34163,37008,39854,42589,45342,48243,50996,53989,56927,0,2703,5769,8631,11529,13989,16743,19808,22616,25315,28325,30895,34420,36972,39578,42552,45251,48464,50941,53786,56540,202,3049,5709,8224,11308,39716,41181,42499,43964,25462,28473,30950,34420,36824,40055,42698,45709,48243,51107,53805,56816,184,2902,5709,8243,11382,39734,41237,42453,44111,25663,28050,31043,34016,37120,39707,42478,45489,48335,51179,53786,56559,19,2723,5839,8243,11235,39698,41237,42638,43991,25480,28234,30895,34365,36972,39615,42792,45637,48555,50886,53860,56927,55,3049,5548,8317,11089,39652,41052,42683,43872,25646,28289,31043,34071,37156,39908,42882,45269,48573,51088,54209,56963,0,2626,5619,8536,11070,14338,16981,19973,22451,25480,28509,31300,34330,36806,39854,42792,45269,48096,51070,54006,57017,73,2774,5636,8446,11474,14008,17074,19587,22836,25663,28436,31079,34347,37120,39983,42681,45269,48261,51179,54172,56742,55,2902,5805,8684,11345,14209,17093,20046,22819,25296,28270,31281,34053,37063,40038,42810,45525,48500,51014,54043,56687,0,2703,5875,8738,11529,14117,16724,19844,22414,25296,28142,31209,34254,36843,39578,42424,45416,48536,50996,53970,56816,19,2755,5416,8374,11106,13916,16779,19919,22873,25407,28325,31317,34163,36954,39597,42442,45746,48261,51216,53915,56981,202,3012,5709,8595,11458,13989,17201,19606,22873,25443,28289,31300,34311,36824,39578,42644,45471,48482,51273,54100,56577],"dpi":null,"converted":true,"cropped":true},{"file":"photo-la.png","shape":[18,24],"pixels":[50115,50780,51445,52111,52776,53441,54106,54771,55436,56102,56767,57432,34181,37008,39835,42662,45489,48316,51143,53970,56797,59624,62451,65535,50115,50780,51445,52111,52776,53441,54106,54771,55436,56102,56767,57432,34181,37008,39835,42662,45489,48316,51143,53970,56797,59624,62451,65535,50115,50780,51445,52111,52776,53441,54106,54771,55436,56102,56767,57432,34181,37008,39835,42662,45489,48316,51143,53970,56797,59624,62451,65535,50115,50780,51445,52111,52776,53441,54106,54771,55436,56102,56767,57432,34181,37008,39835,42662,45489,48316,51143,53970,56797,59624,62451,65535,50115,50780,51445,52111,52776,53441,54106,54771,55436,56102,56767,57432,34181,37008,39835,42662,45489,48316,51143,53970,56797,59624,62451,65535,50115,50780,51445,52111,52776,53441,54106,54771,55436,56102,56767,57432,34181,37008,39835,42662,45489,48316,51143,53970,56797,59624,62451,65535,50115,50780,51445,52111,52776,53441,54106,54771,55436,56102,56767,57432,34181,37008,39835,42662,45489,48316,51143,53970,56797,59624,62451,65535,50115,50780,51445,52111,52776,53441,54106,54771,55436,56102,56767,57432,34181,37008,39835,42662,45489,48316,51143,53970,56797,59624,62451,65535,50115,50780,51445,52111,52776,53441,54106,54771,55436,56102,56767,57432,34181,37008,39835,42662,45489,48316,51143,53970,56797,59624,62451,65535,50115,50780,51445,52111,52776,53441,54106,54771,55436,56102,56767,57432,34181,37008,39835,42662,45489,48316,51143,53970,56797,59624,62451,65535,50115,50780,51445,52111,52776,53441,54106,54771,55436,56102,56767,57432,34181,37008,39835,42662,45489,48316,51143,53970,56797,59624,62451,65535,50115,50780,51445,52111,52776,53441,54106,54771,55436,56102,56767,57432,34181,37008,39835,42662,45489,48316,51143,53970,56797,59624,62451,65535,50115,50780,51445,52111,52776,53441,54106,54771,55436,56102,56767,57432,34181,37008,39835,42662,45489,48316,51143,53970,56797,59624,62451,65535,50115,50780,51445,52111,52776,53441,54106,54771,55436,56102,56767,57432,34181,37008,39835,42662,45489,48316,51143,53970,56797,59624,62451,65535,50115,50780,51445,52111,52776,53441,54106,54771,55436,56102,56767,57432,34181,37008,39835,42662,45489,48316,51143,53970,56797,59624,62451,65535,50115,50780,51445,52111,52776,53441,54106,54771,55436,56102,56767,57432,34181,37008,39835,42662,45489,48316,51143,53970,56797,59624,62451,65535,50115,50780,51445,52111,52776,53441,54106,54771,55436,56102,56767,57432,34181,37008,39835,42662,45489,48316,51143,53970,56797,59624,62451,65535,50115,50780,51445,52111,52776,53441,54106,54771,55436,56102,56767,57432,34181,37008,39835,42662,45489,48316,51143,53970,56797,59624,62451,65535],"dpi":null,"converted":false,"cropped":false},{"file":"photo-palette.png","shape":[18,24],"pixels":[20817,53199,40606,29555,29555,44975,29555,29555,29555,40606,44975,26471,26471,20817,40606,11565,43947,29555,15163,29555,29555,20817,29555,26214,26214,39321,29555,26471,26214,53199,40606,53199,40606,26214,44975,26214,44975,40606,29555,39321,15163,53199,11565,43947,40606,20817,44975,15163,29555,29555,36237,36237,40606,26471,53199,20817,26214,15163,29555,20817,26214,43947,26214,29555,20817,43947,11565,48573,43947,11565,15163,44975,29555,26471,40606,43947,43947,15163,48573,15163,29555,26214,29555,26471,48573,40606,26214,20817,11565,39321,40606,43947,26471,26214,40606,29555,11565,26471,43947,44975,53199,36237,48573,35466,20817,15163,40606,29555,35466,53199,43947,29555,40606,26471,44975,43947,11565,43947,29555,39321,35466,43947,35466,44975,29555,29555,29555,29555,26471,44975,48573,35466,26214,39321,26471,53199,20817,39321,35466,26471,26214,39321,35466,48573,44975,29555,29555,29555,53199,40606,26214,15163,40606,11565,43947,26471,20817,43947,53199,29555,15163,26214,20817,20817,44975,40606,26214,11565,39321,11565,29555,26471,29555,29555,26214,29555,29555,39321,29555,26214,40606,20817,11565,40606,40606,48573,15163,48573,40606,11565,11565,53199,29555,20817,26214,20817,43947,48573,29555,53199,29555,43947,26471,48573,29555,15163,35466,40606,26471,26214,43947,29555,48573,15163,29555,15163,39321,53199,48573,44975,35466,20817,40606,48573,40606,40606,29555,26471,29555,20817,43947,35466,29555,29555,29555,48573,26214,43947,40606,11565,11565,11565,44975,26214,26471,26214,20817,40606,26214,20817,40606,48573,44975,53199,39321,29555,36237,26214,36237,26214,20817,40606,44975,26471,39321,29555,40606,44975,26214,44975,11565,40606,15163,39321,11565,29555,39321,20817,43947,15163,48573,40606,44975,40606,44975,48573,48573,40606,40606,35466,15163,36237,35466,20817,40606,11565,44975,26471,15163,39321,26471,29555,26214,15163,44975,29555,26471,40606,35466,40606,26214,53199,26214,43947,26471,26214,15163,35466,26214,53199,15163,36237,15163,40606,44975,26214,44975,43947,43947,36237,20817,35466,35466,29555,15163,53199,53199,29555,29555,26214,29555,11565,11565,44975,20817,40606,20817,35466,35466,26214,15163,20817,43947,40606,44975,29555,35466,26471,53199,20817,44975,53199,29555,40606,26471,35466,15163,44975,36237,40606,11565,11565,40606,53199,15163,29555,40606,48573,48573,35466,11565,29555,29555,35466,29555,35466,20817,29555,20817,15163,26471,44975,48573,40606,36237,11565,15163,40606,20817,20817,29555,29555,35466,44975,29555,26471,48573,26471,36237,48573,29555,29555,15163,26214,26471,48573,36237,40606,26471,26214,20817,20817,20817,53199,40606,15163,44975,20817,44975,43947,26471,39321],"dpi":null,"converted":false,"cropped":false},{"file":"photo-grey16.tif","shape":[18,24],"pixels":[0,2849,5698,8548,11397,14246,17096,19945,22794,25644,28493,31342,34192,37041,39890,42740,45589,48438,51288,54137,56986,59836,62685,65535,0,2849,5698,8548,11397,14246,17096,19945,22794,25644,28493,31342,34192,37041,39890,42740,45589,48438,51288,54137,56986,59836,62685,65535,0,2849,5698,8548,11397,14246,17096,19945,22794,25644,28493,31342,34192,37041,39890,42740,45589,48438,51288,54137,56986,59836,62685,65535,0,2849,5698,8548,11397,14246,17096,19945,22794,25644,28493,31342,34192,37041,39890,42740,45589,48438,51288,54137,56986,59836,62685,65535,0,2849,5698,8548,11397,14246,17096,19945,22794,25644,28493,31342,34192,37041,39890,42740,45589,48438,51288,54137,56986,59836,62685,65535,0,2849,5698,8548,11397,14246,17096,19945,22794,25644,28493,31342,34192,37041,39890,42740,45589,48438,51288,54137,56986,59836,62685,65535,0,2849,5698,8548,11397,14246,17096,19945,22794,25644,28493,31342,34192,37041,39890,42740,45589,48438,51288,54137,56986,59836,62685,65535,0,2849,5698,8548,11397,14246,17096,19945,22794,25644,28493,31342,34192,37041,39890,42740,45589,48438,51288,54137,56986,59836,62685,65535,0,2849,5698,8548,11397,14246,17096,19945,22794,25644,28493,31342,34192,37041,39890,42740,45589,48438,51288,54137,56986,59836,62685,65535,0,2849,5698,8548,11397,14246,17096,19945,22794,25644,28493,31342,34192,37041,39890,42740,45589,48438,51288,54137,56986,59836,62685,65535,0,2849,5698,8548,11397,14246,17096,19945,22794,25644,28493,31342,34192,37041,39890,42740,45589,48438,51288,54137,56986,59836,62685,65535,0,2849,5698,8548,11397,14246,17096,19945,22794,25644,28493,31342,34192,37041,39890,42740,45589,48438,51288,54137,56986,59836,62685,65535,0,2849,5698,8548,11397,14246,17096,19945,22794,25644,28493,31342,34192,37041,39890,42740,45589,48438,51288,54137,56986,59836,62685,65535,0,2849,5698,8548,11397,14246,17096,19945,22794,25644,28493,31342,34192,37041,39890,42740,45589,48438,51288,54137,56986,59836,62685,65535,0,2849,5698,8548,11397,14246,17096,19945,22794,25644,28493,31342,34192,37041,39890,42740,45589,48438,51288,54137,56986,59836,62685,65535,0,2849,5698,8548,11397,14246,17096,19945,22794,25644,28493,31342,34192,37041,39890,42740,45589,48438,51288,54137,56986,59836,62685,65535,0,2849,5698,8548,11397,14246,17096,19945,22794,25644,28493,31342,34192,37041,39890,42740,45589,48438,51288,54137,56986,59836,62685,65535,0,2849,5698,8548,11397,14246,17096,19945,22794,25644,28493,31342,34192,37041,39890,42740,45589,48438,51288,54137,56986,59836,62685,65535],"dpi":[360.0,360.0],"converted":false,"cropped":false},{"file":"photo-rgba16.tif","shape":[18,22],"pixels":[5698,8548,11397,14246,17096,19945,22794,25644,28493,31342,34192,37041,39890,42740,45589,48438,51288,54137,56986,59836,62685,65535,5698,8548,11397,14246,17096,19945,22794,25644,28493,31342,34192,37041,39890,42740,45589,48438,51288,54137,56986,59836,62685,65535,5698,8548,11397,14246,17096,19945,22794,25644,28493,31342,34192,37041,39890,42740,45589,48438,51288,54137,56986,59836,62685,65535,5698,8548,11397,14246,17096,19945,22794,25644,28493,31342,34192,37041,39890,42740,45589,48438,51288,54137,56986,59836,62685,65535,5698,8548,11397,14246,17096,19945,22794,25644,28493,31342,34192,37041,39890,42740,45589,48438,51288,54137,56986,59836,62685,65535,5698,8548,11397,14246,17096,19945,22794,25644,28493,31342,34192,37041,39890,42740,45589,48438,51288,54137,56986,59836,62685,65535,5698,8548,11397,14246,17096,19945,22794,25644,28493,31342,34192,37041,39890,42740,45589,48438,51288,54137,56986,59836,62685,65535,5698,8548,11397,14246,17096,19945,22794,25644,28493,31342,34192,37041,39890,42740,45589,48438,51288,54137,56986,59836,62685,65535,5698,8548,11397,14246,17096,19945,22794,25644,28493,31342,34192,37041,39890,42740,45589,48438,51288,54137,56986,59836,62685,65535,5698,8548,11397,14246,17096,19945,22794,25644,28493,31342,34192,37041,39890,42740,45589,48438,51288,54137,56986,59836,62685,65535,5698,8548,11397,14246,17096,19945,22794,25644,28493,31342,34192,37041,39890,42740,45589,48438,51288,54137,56986,59836,62685,65535,5698,8548,11397,14246,17096,19945,22794,25644,28493,31342,34192,37041,39890,42740,45589,48438,51288,54137,56986,59836,62685,65535,5698,8548,11397,14246,17096,19945,22794,25644,28493,31342,34192,37041,39890,42740,45589,48438,51288,54137,56986,59836,62685,65535,5698,8548,11397,14246,17096,19945,22794,25644,28493,31342,34192,37041,39890,42740,45589,48438,51288,54137,56986,59836,62685,65535,5698,8548,11397,14246,17096,19945,22794,25644,28493,31342,34192,37041,39890,42740,45589,48438,51288,54137,56986,59836,62685,65535,5698,8548,11397,14246,17096,19945,22794,25644,28493,31342,34192,37041,39890,42740,45589,48438,51288,54137,56986,59836,62685,65535,5698,8548,11397,14246,17096,19945,22794,25644,28493,31342,34192,37041,39890,42740,45589,48438,51288,54137,56986,59836,62685,65535,5698,8548,11397,14246,17096,19945,22794,25644,28493,31342,34192,37041,39890,42740,45589,48438,51288,54137,56986,59836,62685,65535],"dpi":null,"converted":false,"cropped":true}],"calibration":"{\n \"format\": \"openquad-calibration\",\n \"version\": 1,\n \"printer\": \"Canon_MG3600_series\",\n \"paper\": \"Letter plain\",\n \"settings\": \"default quality, AirPrint queue; eSCL Document intent; shadow damping 0.5; tone linearized; tone linearized\",\n \"created\": \"2026-10-22T16:59:09+00:00\",\n \"levels\": [\n 0,\n 256,\n 512,\n 768,\n 1024,\n 1280,\n 1536,\n 1792,\n 2048,\n 2304,\n 2560,\n 2816,\n 3072,\n 3328,\n 3584,\n 3840,\n 4096,\n 4352,\n 4608,\n 4864,\n 5120,\n 5376,\n 5632,\n 5888,\n 6144,\n 6400,\n 6656,\n 6912,\n 7168,\n 7424,\n 7680,\n 7936,\n 8192,\n 8448,\n 8704,\n 8960,\n 9216,\n 9472,\n 9728,\n 9984,\n 10240,\n 10496,\n 10752,\n 11008,\n 11264,\n 11520,\n 11776,\n 12032,\n 12288,\n 12544,\n 12800,\n 13056,\n 13312,\n 13568,\n 13824,\n 14080,\n 14336,\n 14592,\n 14848,\n 15104,\n 15360,\n 15616,\n 15872,\n 16128,\n 16384,\n 16640,\n 16896,\n 17152,\n 17408,\n 17664,\n 17920,\n 18176,\n 18432,\n 18688,\n 18944,\n 19200,\n 19456,\n 19712,\n 19968,\n 20224,\n 20480,\n 20736,\n 20992,\n 21248,\n 21504,\n 21760,\n 22016,\n 22272,\n 22528,\n 22784,\n 23040,\n 23296,\n 23552,\n 23808,\n 24064,\n 24320,\n 24576,\n 24832,\n 25088,\n 25344,\n 25600,\n 25856,\n 26112,\n 26368,\n 26624,\n 26880,\n 27136,\n 27392,\n 27648,\n 27904,\n 28160,\n 28416,\n 28672,\n 28928,\n 29184,\n 29440,\n 29696,\n 29952,\n 30208,\n 30464,\n 30720,\n 30976,\n 31232,\n 31488,\n 31744,\n 32000,\n 32256,\n 32512,\n 32768,\n 33023,\n 33279,\n 33535,\n 33791,\n 34047,\n 34303,\n 34559,\n 34815,\n 35071,\n 35327,\n 35583,\n 35839,\n 36095,\n 36351,\n 36607,\n 36863,\n 37119,\n 37375,\n 37631,\n 37887,\n 38143,\n 38399,\n 38655,\n 38911,\n 39167,\n 39423,\n 39679,\n 39935,\n 40191,\n 40447,\n 40703,\n 40959,\n 41215,\n 41471,\n 41727,\n 41983,\n 42239,\n 42495,\n 42751,\n 43007,\n 43263,\n 43519,\n 43775,\n 44031,\n 44287,\n 44543,\n 44799,\n 45055,\n 45311,\n 45567,\n 45823,\n 46079,\n 46335,\n 46591,\n 46847,\n 47103,\n 47359,\n 47615,\n 47871,\n 48127,\n 48383,\n 48639,\n 48895,\n 49151,\n 49407,\n 49663,\n 49919,\n 50175,\n 50431,\n 50687,\n 50943,\n 51199,\n 51455,\n 51711,\n 51967,\n 52223,\n 52479,\n 52735,\n 52991,\n 53247,\n 53503,\n 53759,\n 54015,\n 54271,\n 54527,\n 54783,\n 55039,\n 55295,\n 55551,\n 55807,\n 56063,\n 56319,\n 56575,\n 56831,\n 57087,\n 57343,\n 57599,\n 57855,\n 58111,\n 58367,\n 58623,\n 58879,\n 59135,\n 59391,\n 59647,\n 59903,\n 60159,\n 60415,\n 60671,\n 60927,\n 61183,\n 61439,\n 61695,\n 61951,\n 62207,\n 62463,\n 62719,\n 62975,\n 63231,\n 63487,\n 63743,\n 63999,\n 64255,\n 64511,\n 64767,\n 65023,\n 65279,\n 65535\n ],\n \"curves\": {\n \"R\": [\n 0,\n 1249,\n 2498,\n 3742,\n 4127,\n 4375,\n 4491,\n 4607,\n 4723,\n 4839,\n 4955,\n 5074,\n 5199,\n 5332,\n 5472,\n 5620,\n 5782,\n 5961,\n 6125,\n 6270,\n 6428,\n 6597,\n 6779,\n 6976,\n 7189,\n 7409,\n 7636,\n 7871,\n 8112,\n 8361,\n 8618,\n 8890,\n 9192,\n 9514,\n 9850,\n 10196,\n 10540,\n 10882,\n 11220,\n 11556,\n 11889,\n 12219,\n 12548,\n 12875,\n 13148,\n 13368,\n 13573,\n 13776,\n 13978,\n 14231,\n 14495,\n 14758,\n 15020,\n 15279,\n 15536,\n 15792,\n 16052,\n 16425,\n 16805,\n 17182,\n 17556,\n 17919,\n 18282,\n 18641,\n 18998,\n 19296,\n 19545,\n 19784,\n 20022,\n 20259,\n 20495,\n 20729,\n 20961,\n 21198,\n 21432,\n 21667,\n 21899,\n 22130,\n 22359,\n 22594,\n 22853,\n 23115,\n 23376,\n 23634,\n 23892,\n 24177,\n 24487,\n 24797,\n 25105,\n 25411,\n 25716,\n 26006,\n 26233,\n 26445,\n 26655,\n 26864,\n 27042,\n 27220,\n 27397,\n 27572,\n 27748,\n 27922,\n 28097,\n 28269,\n 28442,\n 28614,\n 28786,\n 28957,\n 29131,\n 29311,\n 29517,\n 29725,\n 29932,\n 30138,\n 30344,\n 30549,\n 30754,\n 30958,\n 31161,\n 31363,\n 31566,\n 31770,\n 31975,\n 32179,\n 32382,\n 32585,\n 32789,\n 32995,\n 33199,\n 33403,\n 33606,\n 33809,\n 34013,\n 34263,\n 34513,\n 34762,\n 35011,\n 35258,\n 35504,\n 35749,\n 35994,\n 36242,\n 36487,\n 36654,\n 36822,\n 36989,\n 37156,\n 37321,\n 37487,\n 37652,\n 37818,\n 37983,\n 38147,\n 38310,\n 38474,\n 38637,\n 38800,\n 38962,\n 39173,\n 39388,\n 39593,\n 39794,\n 39997,\n 40197,\n 40396,\n 40596,\n 40795,\n 40993,\n 41192,\n 41397,\n 41613,\n 41829,\n 42044,\n 42258,\n 42473,\n 42687,\n 42918,\n 43157,\n 43395,\n 43634,\n 43844,\n 44043,\n 44242,\n 44441,\n 44638,\n 44837,\n 45034,\n 45232,\n 45428,\n 45624,\n 45820,\n 46016,\n 46227,\n 46458,\n 46692,\n 46925,\n 47156,\n 47389,\n 47620,\n 47851,\n 48082,\n 48312,\n 48541,\n 48771,\n 48999,\n 49228,\n 49485,\n 49775,\n 50090,\n 50412,\n 50734,\n 51054,\n 51374,\n 51693,\n 52012,\n 52330,\n 52648,\n 52922,\n 53152,\n 53381,\n 53610,\n 53839,\n 54068,\n 54296,\n 54522,\n 54750,\n 54977,\n 55204,\n 55429,\n 55656,\n 55882,\n 56132,\n 56466,\n 56844,\n 57222,\n 57598,\n 57974,\n 58348,\n 58722,\n 59097,\n 59470,\n 59836,\n 60180,\n 60523,\n 60866,\n 61209,\n 61622,\n 62059,\n 62493,\n 62904,\n 63284,\n 63662,\n 64037,\n 64412,\n 64787,\n 65161,\n 65535\n ],\n \"G\": [\n 0,\n 1185,\n 2370,\n 3551,\n 3946,\n 4216,\n 4365,\n 4513,\n 4662,\n 4811,\n 4960,\n 5112,\n 5273,\n 5443,\n 5622,\n 5812,\n 6020,\n 6250,\n 6460,\n 6646,\n 6848,\n 7065,\n 7298,\n 7551,\n 7824,\n 8107,\n 8399,\n 8700,\n 9009,\n 9327,\n 9657,\n 9976,\n 10260,\n 10513,\n 10775,\n 11048,\n 11316,\n 11584,\n 11850,\n 12113,\n 12374,\n 12634,\n 12892,\n 13147,\n 13391,\n 13627,\n 13857,\n 14087,\n 14315,\n 14599,\n 14897,\n 15194,\n 15489,\n 15780,\n 16071,\n 16360,\n 16652,\n 17057,\n 17470,\n 17879,\n 18284,\n 18677,\n 19071,\n 19460,\n 19847,\n 20152,\n 20387,\n 20610,\n 20832,\n 21053,\n 21271,\n 21490,\n 21707,\n 21927,\n 22145,\n 22363,\n 22579,\n 22795,\n 23008,\n 23228,\n 23474,\n 23723,\n 23971,\n 24217,\n 24463,\n 24734,\n 25030,\n 25324,\n 25618,\n 25909,\n 26199,\n 26476,\n 26697,\n 26902,\n 27108,\n 27312,\n 27486,\n 27660,\n 27831,\n 28003,\n 28175,\n 28345,\n 28515,\n 28684,\n 28852,\n 29020,\n 29188,\n 29354,\n 29525,\n 29700,\n 29904,\n 30109,\n 30314,\n 30518,\n 30722,\n 30926,\n 31127,\n 31329,\n 31530,\n 31730,\n 31930,\n 32133,\n 32336,\n 32537,\n 32738,\n 32938,\n 33128,\n 33315,\n 33500,\n 33684,\n 33868,\n 34052,\n 34237,\n 34464,\n 34690,\n 34915,\n 35141,\n 35364,\n 35588,\n 35810,\n 36031,\n 36265,\n 36506,\n 36670,\n 36834,\n 37000,\n 37164,\n 37326,\n 37489,\n 37653,\n 37815,\n 37977,\n 38138,\n 38300,\n 38461,\n 38621,\n 38782,\n 38941,\n 39149,\n 39361,\n 39561,\n 39756,\n 39954,\n 40149,\n 40343,\n 40538,\n 40732,\n 40925,\n 41119,\n 41319,\n 41530,\n 41740,\n 41950,\n 42159,\n 42368,\n 42577,\n 42798,\n 43026,\n 43253,\n 43481,\n 43681,\n 43872,\n 44061,\n 44250,\n 44440,\n 44629,\n 44818,\n 45006,\n 45194,\n 45380,\n 45568,\n 45754,\n 45957,\n 46180,\n 46406,\n 46631,\n 46855,\n 47079,\n 47303,\n 47527,\n 47749,\n 47972,\n 48194,\n 48415,\n 48636,\n 48858,\n 49105,\n 49380,\n 49667,\n 49957,\n 50246,\n 50534,\n 50823,\n 51110,\n 51397,\n 51684,\n 51970,\n 52218,\n 52456,\n 52704,\n 52955,\n 53206,\n 53457,\n 53706,\n 53954,\n 54203,\n 54452,\n 54700,\n 54947,\n 55196,\n 55442,\n 55700,\n 56006,\n 56343,\n 56680,\n 57016,\n 57351,\n 57686,\n 58020,\n 58355,\n 58689,\n 59029,\n 59385,\n 59739,\n 60093,\n 60448,\n 60874,\n 61325,\n 61775,\n 62236,\n 62707,\n 63181,\n 63652,\n 64124,\n 64595,\n 65066,\n 65535\n ],\n \"B\": [\n 0,\n 1212,\n 2423,\n 3630,\n 4022,\n 4284,\n 4421,\n 4558,\n 4694,\n 4831,\n 4968,\n 5107,\n 5256,\n 5413,\n 5577,\n 5751,\n 5942,\n 6154,\n 6346,\n 6517,\n 6703,\n 6903,\n 7117,\n 7348,\n 7599,\n 7859,\n 8127,\n 8404,\n 8687,\n 8980,\n 9283,\n 9560,\n 9769,\n 9919,\n 10075,\n 10237,\n 10397,\n 10556,\n 10713,\n 10870,\n 11026,\n 11179,\n 11333,\n 11485,\n 11673,\n 11899,\n 12134,\n 12368,\n 12600,\n 12890,\n 13194,\n 13498,\n 13799,\n 14096,\n 14392,\n 14687,\n 14981,\n 15300,\n 15619,\n 15935,\n 16249,\n 16554,\n 16859,\n 17160,\n 17460,\n 17700,\n 17890,\n 18070,\n 18250,\n 18428,\n 18606,\n 18782,\n 18958,\n 19136,\n 19313,\n 19490,\n 19665,\n 19839,\n 20012,\n 20199,\n 20452,\n 20714,\n 20975,\n 21235,\n 21494,\n 21779,\n 22090,\n 22400,\n 22709,\n 23016,\n 23321,\n 23617,\n 23874,\n 24120,\n 24365,\n 24609,\n 24816,\n 25023,\n 25228,\n 25433,\n 25638,\n 25841,\n 26044,\n 26246,\n 26447,\n 26648,\n 26847,\n 27046,\n 27250,\n 27457,\n 27666,\n 27874,\n 28082,\n 28288,\n 28494,\n 28699,\n 28904,\n 29108,\n 29311,\n 29513,\n 29716,\n 29921,\n 30126,\n 30330,\n 30533,\n 30736,\n 30945,\n 31158,\n 31367,\n 31579,\n 31788,\n 31997,\n 32208,\n 32466,\n 32723,\n 32981,\n 33237,\n 33492,\n 33746,\n 33999,\n 34251,\n 34517,\n 34790,\n 34977,\n 35164,\n 35351,\n 35537,\n 35723,\n 35907,\n 36092,\n 36276,\n 36461,\n 36644,\n 36826,\n 37009,\n 37192,\n 37373,\n 37554,\n 37791,\n 38030,\n 38251,\n 38464,\n 38678,\n 38891,\n 39103,\n 39315,\n 39526,\n 39737,\n 39948,\n 40166,\n 40395,\n 40625,\n 40853,\n 41081,\n 41309,\n 41535,\n 41762,\n 41989,\n 42215,\n 42441,\n 42641,\n 42830,\n 43019,\n 43207,\n 43395,\n 43584,\n 43771,\n 43959,\n 44145,\n 44331,\n 44517,\n 44703,\n 44897,\n 45102,\n 45307,\n 45513,\n 45716,\n 45920,\n 46124,\n 46327,\n 46530,\n 46733,\n 46935,\n 47137,\n 47338,\n 47539,\n 47764,\n 48017,\n 48282,\n 48552,\n 48821,\n 49089,\n 49357,\n 49625,\n 49891,\n 50157,\n 50423,\n 50656,\n 50917,\n 51206,\n 51498,\n 51791,\n 52084,\n 52375,\n 52666,\n 52957,\n 53247,\n 53537,\n 53825,\n 54115,\n 54404,\n 54709,\n 55075,\n 55482,\n 55889,\n 56295,\n 56699,\n 57103,\n 57507,\n 57910,\n 58312,\n 58711,\n 59099,\n 59485,\n 59871,\n 60258,\n 60724,\n 61216,\n 61705,\n 62192,\n 62672,\n 63152,\n 63629,\n 64106,\n 64583,\n 65060,\n 65535\n ]\n }\n}\n","sessions":[{"photo":"photo-grey16.tif","ppi_used":3.2,"size":[7.5,5.625],"fits":true,"summary":["Photo: photo-grey16.tif","Printer: Canon_MG3600_series","Paper: Letter","Size: 7.50 x 5.62 in at 3 ppi","Toning: neutral","Calibration: none"],"notes":[],"rendered_shape":[18,24,3],"rendered":[0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535]},{"photo":"photo-grey16.tif","preset":"black-red","calibration":true,"paper":"4x6","ppi_used":8.0,"size":[3.0,2.25],"fits":true,"summary":["Photo: photo-grey16.tif","Printer: Canon_MG3600_series","Paper: 4x6","Size: 3.00 x 2.25 in at 8 ppi","Toning: black-red","Calibration: canon-plain.oqcal"],"notes":[],"rendered_shape":[18,24,3],"rendered":[0,0,0,7483,8083,7837,14276,13996,12276,20675,19534,17217,25678,22077,19258,28912,23013,20016,31951,22797,19841,34975,21768,19007,37654,20413,17911,39883,18759,16617,42258,18367,16313,44547,20156,17703,46403,22285,19426,48227,25802,22903,49822,29216,26880,51461,33100,30914,53009,37318,35714,54432,41318,40165,56033,45721,44670,58677,50604,49154,61133,55225,54149,63501,59844,59600,64990,63953,63933,65535,65535,65535,0,0,0,7483,8083,7837,14276,13996,12276,20675,19534,17217,25678,22077,19258,28912,23013,20016,31951,22797,19841,34975,21768,19007,37654,20413,17911,39883,18759,16617,42258,18367,16313,44547,20156,17703,46403,22285,19426,48227,25802,22903,49822,29216,26880,51461,33100,30914,53009,37318,35714,54432,41318,40165,56033,45721,44670,58677,50604,49154,61133,55225,54149,63501,59844,59600,64990,63953,63933,65535,65535,65535,0,0,0,7483,8083,7837,14276,13996,12276,20675,19534,17217,25678,22077,19258,28912,23013,20016,31951,22797,19841,34975,21768,19007,37654,20413,17911,39883,18759,16617,42258,18367,16313,44547,20156,17703,46403,22285,19426,48227,25802,22903,49822,29216,26880,51461,33100,30914,53009,37318,35714,54432,41318,40165,56033,45721,44670,58677,50604,49154,61133,55225,54149,63501,59844,59600,64990,63953,63933,65535,65535,65535,0,0,0,7483,8083,7837,14276,13996,12276,20675,19534,17217,25678,22077,19258,28912,23013,20016,31951,22797,19841,34975,21768,19007,37654,20413,17911,39883,18759,16617,42258,18367,16313,44547,20156,17703,46403,22285,19426,48227,25802,22903,49822,29216,26880,51461,33100,30914,53009,37318,35714,54432,41318,40165,56033,45721,44670,58677,50604,49154,61133,55225,54149,63501,59844,59600,64990,63953,63933,65535,65535,65535,0,0,0,7483,8083,7837,14276,13996,12276,20675,19534,17217,25678,22077,19258,28912,23013,20016,31951,22797,19841,34975,21768,19007,37654,20413,17911,39883,18759,16617,42258,18367,16313,44547,20156,17703,46403,22285,19426,48227,25802,22903,49822,29216,26880,51461,33100,30914,53009,37318,35714,54432,41318,40165,56033,45721,44670,58677,50604,49154,61133,55225,54149,63501,59844,59600,64990,63953,63933,65535,65535,65535,0,0,0,7483,8083,7837,14276,13996,12276,20675,19534,17217,25678,22077,19258,28912,23013,20016,31951,22797,19841,34975,21768,19007,37654,20413,17911,39883,18759,16617,42258,18367,16313,44547,20156,17703,46403,22285,19426,48227,25802,22903,49822,29216,26880,51461,33100,30914,53009,37318,35714,54432,41318,40165,56033,45721,44670,58677,50604,49154,61133,55225,54149,63501,59844,59600,64990,63953,63933,65535,65535,65535,0,0,0,7483,8083,7837,14276,13996,12276,20675,19534,17217,25678,22077,19258,28912,23013,20016,31951,22797,19841,34975,21768,19007,37654,20413,17911,39883,18759,16617,42258,18367,16313,44547,20156,17703,46403,22285,19426,48227,25802,22903,49822,29216,26880,51461,33100,30914,53009,37318,35714,54432,41318,40165,56033,45721,44670,58677,50604,49154,61133,55225,54149,63501,59844,59600,64990,63953,63933,65535,65535,65535,0,0,0,7483,8083,7837,14276,13996,12276,20675,19534,17217,25678,22077,19258,28912,23013,20016,31951,22797,19841,34975,21768,19007,37654,20413,17911,39883,18759,16617,42258,18367,16313,44547,20156,17703,46403,22285,19426,48227,25802,22903,49822,29216,26880,51461,33100,30914,53009,37318,35714,54432,41318,40165,56033,45721,44670,58677,50604,49154,61133,55225,54149,63501,59844,59600,64990,63953,63933,65535,65535,65535,0,0,0,7483,8083,7837,14276,13996,12276,20675,19534,17217,25678,22077,19258,28912,23013,20016,31951,22797,19841,34975,21768,19007,37654,20413,17911,39883,18759,16617,42258,18367,16313,44547,20156,17703,46403,22285,19426,48227,25802,22903,49822,29216,26880,51461,33100,30914,53009,37318,35714,54432,41318,40165,56033,45721,44670,58677,50604,49154,61133,55225,54149,63501,59844,59600,64990,63953,63933,65535,65535,65535,0,0,0,7483,8083,7837,14276,13996,12276,20675,19534,17217,25678,22077,19258,28912,23013,20016,31951,22797,19841,34975,21768,19007,37654,20413,17911,39883,18759,16617,42258,18367,16313,44547,20156,17703,46403,22285,19426,48227,25802,22903,49822,29216,26880,51461,33100,30914,53009,37318,35714,54432,41318,40165,56033,45721,44670,58677,50604,49154,61133,55225,54149,63501,59844,59600,64990,63953,63933,65535,65535,65535,0,0,0,7483,8083,7837,14276,13996,12276,20675,19534,17217,25678,22077,19258,28912,23013,20016,31951,22797,19841,34975,21768,19007,37654,20413,17911,39883,18759,16617,42258,18367,16313,44547,20156,17703,46403,22285,19426,48227,25802,22903,49822,29216,26880,51461,33100,30914,53009,37318,35714,54432,41318,40165,56033,45721,44670,58677,50604,49154,61133,55225,54149,63501,59844,59600,64990,63953,63933,65535,65535,65535,0,0,0,7483,8083,7837,14276,13996,12276,20675,19534,17217,25678,22077,19258,28912,23013,20016,31951,22797,19841,34975,21768,19007,37654,20413,17911,39883,18759,16617,42258,18367,16313,44547,20156,17703,46403,22285,19426,48227,25802,22903,49822,29216,26880,51461,33100,30914,53009,37318,35714,54432,41318,40165,56033,45721,44670,58677,50604,49154,61133,55225,54149,63501,59844,59600,64990,63953,63933,65535,65535,65535,0,0,0,7483,8083,7837,14276,13996,12276,20675,19534,17217,25678,22077,19258,28912,23013,20016,31951,22797,19841,34975,21768,19007,37654,20413,17911,39883,18759,16617,42258,18367,16313,44547,20156,17703,46403,22285,19426,48227,25802,22903,49822,29216,26880,51461,33100,30914,53009,37318,35714,54432,41318,40165,56033,45721,44670,58677,50604,49154,61133,55225,54149,63501,59844,59600,64990,63953,63933,65535,65535,65535,0,0,0,7483,8083,7837,14276,13996,12276,20675,19534,17217,25678,22077,19258,28912,23013,20016,31951,22797,19841,34975,21768,19007,37654,20413,17911,39883,18759,16617,42258,18367,16313,44547,20156,17703,46403,22285,19426,48227,25802,22903,49822,29216,26880,51461,33100,30914,53009,37318,35714,54432,41318,40165,56033,45721,44670,58677,50604,49154,61133,55225,54149,63501,59844,59600,64990,63953,63933,65535,65535,65535,0,0,0,7483,8083,7837,14276,13996,12276,20675,19534,17217,25678,22077,19258,28912,23013,20016,31951,22797,19841,34975,21768,19007,37654,20413,17911,39883,18759,16617,42258,18367,16313,44547,20156,17703,46403,22285,19426,48227,25802,22903,49822,29216,26880,51461,33100,30914,53009,37318,35714,54432,41318,40165,56033,45721,44670,58677,50604,49154,61133,55225,54149,63501,59844,59600,64990,63953,63933,65535,65535,65535,0,0,0,7483,8083,7837,14276,13996,12276,20675,19534,17217,25678,22077,19258,28912,23013,20016,31951,22797,19841,34975,21768,19007,37654,20413,17911,39883,18759,16617,42258,18367,16313,44547,20156,17703,46403,22285,19426,48227,25802,22903,49822,29216,26880,51461,33100,30914,53009,37318,35714,54432,41318,40165,56033,45721,44670,58677,50604,49154,61133,55225,54149,63501,59844,59600,64990,63953,63933,65535,65535,65535,0,0,0,7483,8083,7837,14276,13996,12276,20675,19534,17217,25678,22077,19258,28912,23013,20016,31951,22797,19841,34975,21768,19007,37654,20413,17911,39883,18759,16617,42258,18367,16313,44547,20156,17703,46403,22285,19426,48227,25802,22903,49822,29216,26880,51461,33100,30914,53009,37318,35714,54432,41318,40165,56033,45721,44670,58677,50604,49154,61133,55225,54149,63501,59844,59600,64990,63953,63933,65535,65535,65535,0,0,0,7483,8083,7837,14276,13996,12276,20675,19534,17217,25678,22077,19258,28912,23013,20016,31951,22797,19841,34975,21768,19007,37654,20413,17911,39883,18759,16617,42258,18367,16313,44547,20156,17703,46403,22285,19426,48227,25802,22903,49822,29216,26880,51461,33100,30914,53009,37318,35714,54432,41318,40165,56033,45721,44670,58677,50604,49154,61133,55225,54149,63501,59844,59600,64990,63953,63933,65535,65535,65535]},{"photo":"photo-grey.png","fit":false,"ppi":12.5,"ppi_used":12.5,"size":[1.92,1.44],"fits":true,"summary":["Photo: photo-grey.png","Printer: Canon_MG3600_series","Paper: Letter","Size: 1.92 x 1.44 in at 12 ppi","Toning: neutral","Calibration: none"],"notes":[],"rendered_shape":[18,24,3],"rendered":[0,0,0,2827,2827,2827,5654,5654,5654,8481,8481,8481,11308,11308,11308,14135,14135,14135,16962,16962,16962,19789,19789,19789,22616,22616,22616,25443,25443,25443,28270,28270,28270,31097,31097,31097,34181,34181,34181,37008,37008,37008,39835,39835,39835,42662,42662,42662,45489,45489,45489,48316,48316,48316,51143,51143,51143,53970,53970,53970,56797,56797,56797,59624,59624,59624,62451,62451,62451,65535,65535,65535,0,0,0,2827,2827,2827,5654,5654,5654,8481,8481,8481,11308,11308,11308,14135,14135,14135,16962,16962,16962,19789,19789,19789,22616,22616,22616,25443,25443,25443,28270,28270,28270,31097,31097,31097,34181,34181,34181,37008,37008,37008,39835,39835,39835,42662,42662,42662,45489,45489,45489,48316,48316,48316,51143,51143,51143,53970,53970,53970,56797,56797,56797,59624,59624,59624,62451,62451,62451,65535,65535,65535,0,0,0,2827,2827,2827,5654,5654,5654,8481,8481,8481,11308,11308,11308,14135,14135,14135,16962,16962,16962,19789,19789,19789,22616,22616,22616,25443,25443,25443,28270,28270,28270,31097,31097,31097,34181,34181,34181,37008,37008,37008,39835,39835,39835,42662,42662,42662,45489,45489,45489,48316,48316,48316,51143,51143,51143,53970,53970,53970,56797,56797,56797,59624,59624,59624,62451,62451,62451,65535,65535,65535,0,0,0,2827,2827,2827,5654,5654,5654,8481,8481,8481,11308,11308,11308,14135,14135,14135,16962,16962,16962,19789,19789,19789,22616,22616,22616,25443,25443,25443,28270,28270,28270,31097,31097,31097,34181,34181,34181,37008,37008,37008,39835,39835,39835,42662,42662,42662,45489,45489,45489,48316,48316,48316,51143,51143,51143,53970,53970,53970,56797,56797,56797,59624,59624,59624,62451,62451,62451,65535,65535,65535,0,0,0,2827,2827,2827,5654,5654,5654,8481,8481,8481,11308,11308,11308,14135,14135,14135,16962,16962,16962,19789,19789,19789,22616,22616,22616,25443,25443,25443,28270,28270,28270,31097,31097,31097,34181,34181,34181,37008,37008,37008,39835,39835,39835,42662,42662,42662,45489,45489,45489,48316,48316,48316,51143,51143,51143,53970,53970,53970,56797,56797,56797,59624,59624,59624,62451,62451,62451,65535,65535,65535,0,0,0,2827,2827,2827,5654,5654,5654,8481,8481,8481,11308,11308,11308,14135,14135,14135,16962,16962,16962,19789,19789,19789,22616,22616,22616,25443,25443,25443,28270,28270,28270,31097,31097,31097,34181,34181,34181,37008,37008,37008,39835,39835,39835,42662,42662,42662,45489,45489,45489,48316,48316,48316,51143,51143,51143,53970,53970,53970,56797,56797,56797,59624,59624,59624,62451,62451,62451,65535,65535,65535,0,0,0,2827,2827,2827,5654,5654,5654,8481,8481,8481,11308,11308,11308,14135,14135,14135,16962,16962,16962,19789,19789,19789,22616,22616,22616,25443,25443,25443,28270,28270,28270,31097,31097,31097,34181,34181,34181,37008,37008,37008,39835,39835,39835,42662,42662,42662,45489,45489,45489,48316,48316,48316,51143,51143,51143,53970,53970,53970,56797,56797,56797,59624,59624,59624,62451,62451,62451,65535,65535,65535,0,0,0,2827,2827,2827,5654,5654,5654,8481,8481,8481,11308,11308,11308,14135,14135,14135,16962,16962,16962,19789,19789,19789,22616,22616,22616,25443,25443,25443,28270,28270,28270,31097,31097,31097,34181,34181,34181,37008,37008,37008,39835,39835,39835,42662,42662,42662,45489,45489,45489,48316,48316,48316,51143,51143,51143,53970,53970,53970,56797,56797,56797,59624,59624,59624,62451,62451,62451,65535,65535,65535,0,0,0,2827,2827,2827,5654,5654,5654,8481,8481,8481,11308,11308,11308,14135,14135,14135,16962,16962,16962,19789,19789,19789,22616,22616,22616,25443,25443,25443,28270,28270,28270,31097,31097,31097,34181,34181,34181,37008,37008,37008,39835,39835,39835,42662,42662,42662,45489,45489,45489,48316,48316,48316,51143,51143,51143,53970,53970,53970,56797,56797,56797,59624,59624,59624,62451,62451,62451,65535,65535,65535,0,0,0,2827,2827,2827,5654,5654,5654,8481,8481,8481,11308,11308,11308,14135,14135,14135,16962,16962,16962,19789,19789,19789,22616,22616,22616,25443,25443,25443,28270,28270,28270,31097,31097,31097,34181,34181,34181,37008,37008,37008,39835,39835,39835,42662,42662,42662,45489,45489,45489,48316,48316,48316,51143,51143,51143,53970,53970,53970,56797,56797,56797,59624,59624,59624,62451,62451,62451,65535,65535,65535,0,0,0,2827,2827,2827,5654,5654,5654,8481,8481,8481,11308,11308,11308,14135,14135,14135,16962,16962,16962,19789,19789,19789,22616,22616,22616,25443,25443,25443,28270,28270,28270,31097,31097,31097,34181,34181,34181,37008,37008,37008,39835,39835,39835,42662,42662,42662,45489,45489,45489,48316,48316,48316,51143,51143,51143,53970,53970,53970,56797,56797,56797,59624,59624,59624,62451,62451,62451,65535,65535,65535,0,0,0,2827,2827,2827,5654,5654,5654,8481,8481,8481,11308,11308,11308,14135,14135,14135,16962,16962,16962,19789,19789,19789,22616,22616,22616,25443,25443,25443,28270,28270,28270,31097,31097,31097,34181,34181,34181,37008,37008,37008,39835,39835,39835,42662,42662,42662,45489,45489,45489,48316,48316,48316,51143,51143,51143,53970,53970,53970,56797,56797,56797,59624,59624,59624,62451,62451,62451,65535,65535,65535,0,0,0,2827,2827,2827,5654,5654,5654,8481,8481,8481,11308,11308,11308,14135,14135,14135,16962,16962,16962,19789,19789,19789,22616,22616,22616,25443,25443,25443,28270,28270,28270,31097,31097,31097,34181,34181,34181,37008,37008,37008,39835,39835,39835,42662,42662,42662,45489,45489,45489,48316,48316,48316,51143,51143,51143,53970,53970,53970,56797,56797,56797,59624,59624,59624,62451,62451,62451,65535,65535,65535,0,0,0,2827,2827,2827,5654,5654,5654,8481,8481,8481,11308,11308,11308,14135,14135,14135,16962,16962,16962,19789,19789,19789,22616,22616,22616,25443,25443,25443,28270,28270,28270,31097,31097,31097,34181,34181,34181,37008,37008,37008,39835,39835,39835,42662,42662,42662,45489,45489,45489,48316,48316,48316,51143,51143,51143,53970,53970,53970,56797,56797,56797,59624,59624,59624,62451,62451,62451,65535,65535,65535,0,0,0,2827,2827,2827,5654,5654,5654,8481,8481,8481,11308,11308,11308,14135,14135,14135,16962,16962,16962,19789,19789,19789,22616,22616,22616,25443,25443,25443,28270,28270,28270,31097,31097,31097,34181,34181,34181,37008,37008,37008,39835,39835,39835,42662,42662,42662,45489,45489,45489,48316,48316,48316,51143,51143,51143,53970,53970,53970,56797,56797,56797,59624,59624,59624,62451,62451,62451,65535,65535,65535,0,0,0,2827,2827,2827,5654,5654,5654,8481,8481,8481,11308,11308,11308,14135,14135,14135,16962,16962,16962,19789,19789,19789,22616,22616,22616,25443,25443,25443,28270,28270,28270,31097,31097,31097,34181,34181,34181,37008,37008,37008,39835,39835,39835,42662,42662,42662,45489,45489,45489,48316,48316,48316,51143,51143,51143,53970,53970,53970,56797,56797,56797,59624,59624,59624,62451,62451,62451,65535,65535,65535,0,0,0,2827,2827,2827,5654,5654,5654,8481,8481,8481,11308,11308,11308,14135,14135,14135,16962,16962,16962,19789,19789,19789,22616,22616,22616,25443,25443,25443,28270,28270,28270,31097,31097,31097,34181,34181,34181,37008,37008,37008,39835,39835,39835,42662,42662,42662,45489,45489,45489,48316,48316,48316,51143,51143,51143,53970,53970,53970,56797,56797,56797,59624,59624,59624,62451,62451,62451,65535,65535,65535,0,0,0,2827,2827,2827,5654,5654,5654,8481,8481,8481,11308,11308,11308,14135,14135,14135,16962,16962,16962,19789,19789,19789,22616,22616,22616,25443,25443,25443,28270,28270,28270,31097,31097,31097,34181,34181,34181,37008,37008,37008,39835,39835,39835,42662,42662,42662,45489,45489,45489,48316,48316,48316,51143,51143,51143,53970,53970,53970,56797,56797,56797,59624,59624,59624,62451,62451,62451,65535,65535,65535]},{"photo":"photo-grey.png","fit":false,"ppi_used":299.9994,"size":[0.08000016000032001,0.060000120000240006],"fits":true,"summary":["Photo: photo-grey.png","Printer: Canon_MG3600_series","Paper: Letter","Size: 0.08 x 0.06 in at 300 ppi","Toning: neutral","Calibration: none"],"notes":[],"rendered_shape":[18,24,3],"rendered":[0,0,0,2827,2827,2827,5654,5654,5654,8481,8481,8481,11308,11308,11308,14135,14135,14135,16962,16962,16962,19789,19789,19789,22616,22616,22616,25443,25443,25443,28270,28270,28270,31097,31097,31097,34181,34181,34181,37008,37008,37008,39835,39835,39835,42662,42662,42662,45489,45489,45489,48316,48316,48316,51143,51143,51143,53970,53970,53970,56797,56797,56797,59624,59624,59624,62451,62451,62451,65535,65535,65535,0,0,0,2827,2827,2827,5654,5654,5654,8481,8481,8481,11308,11308,11308,14135,14135,14135,16962,16962,16962,19789,19789,19789,22616,22616,22616,25443,25443,25443,28270,28270,28270,31097,31097,31097,34181,34181,34181,37008,37008,37008,39835,39835,39835,42662,42662,42662,45489,45489,45489,48316,48316,48316,51143,51143,51143,53970,53970,53970,56797,56797,56797,59624,59624,59624,62451,62451,62451,65535,65535,65535,0,0,0,2827,2827,2827,5654,5654,5654,8481,8481,8481,11308,11308,11308,14135,14135,14135,16962,16962,16962,19789,19789,19789,22616,22616,22616,25443,25443,25443,28270,28270,28270,31097,31097,31097,34181,34181,34181,37008,37008,37008,39835,39835,39835,42662,42662,42662,45489,45489,45489,48316,48316,48316,51143,51143,51143,53970,53970,53970,56797,56797,56797,59624,59624,59624,62451,62451,62451,65535,65535,65535,0,0,0,2827,2827,2827,5654,5654,5654,8481,8481,8481,11308,11308,11308,14135,14135,14135,16962,16962,16962,19789,19789,19789,22616,22616,22616,25443,25443,25443,28270,28270,28270,31097,31097,31097,34181,34181,34181,37008,37008,37008,39835,39835,39835,42662,42662,42662,45489,45489,45489,48316,48316,48316,51143,51143,51143,53970,53970,53970,56797,56797,56797,59624,59624,59624,62451,62451,62451,65535,65535,65535,0,0,0,2827,2827,2827,5654,5654,5654,8481,8481,8481,11308,11308,11308,14135,14135,14135,16962,16962,16962,19789,19789,19789,22616,22616,22616,25443,25443,25443,28270,28270,28270,31097,31097,31097,34181,34181,34181,37008,37008,37008,39835,39835,39835,42662,42662,42662,45489,45489,45489,48316,48316,48316,51143,51143,51143,53970,53970,53970,56797,56797,56797,59624,59624,59624,62451,62451,62451,65535,65535,65535,0,0,0,2827,2827,2827,5654,5654,5654,8481,8481,8481,11308,11308,11308,14135,14135,14135,16962,16962,16962,19789,19789,19789,22616,22616,22616,25443,25443,25443,28270,28270,28270,31097,31097,31097,34181,34181,34181,37008,37008,37008,39835,39835,39835,42662,42662,42662,45489,45489,45489,48316,48316,48316,51143,51143,51143,53970,53970,53970,56797,56797,56797,59624,59624,59624,62451,62451,62451,65535,65535,65535,0,0,0,2827,2827,2827,5654,5654,5654,8481,8481,8481,11308,11308,11308,14135,14135,14135,16962,16962,16962,19789,19789,19789,22616,22616,22616,25443,25443,25443,28270,28270,28270,31097,31097,31097,34181,34181,34181,37008,37008,37008,39835,39835,39835,42662,42662,42662,45489,45489,45489,48316,48316,48316,51143,51143,51143,53970,53970,53970,56797,56797,56797,59624,59624,59624,62451,62451,62451,65535,65535,65535,0,0,0,2827,2827,2827,5654,5654,5654,8481,8481,8481,11308,11308,11308,14135,14135,14135,16962,16962,16962,19789,19789,19789,22616,22616,22616,25443,25443,25443,28270,28270,28270,31097,31097,31097,34181,34181,34181,37008,37008,37008,39835,39835,39835,42662,42662,42662,45489,45489,45489,48316,48316,48316,51143,51143,51143,53970,53970,53970,56797,56797,56797,59624,59624,59624,62451,62451,62451,65535,65535,65535,0,0,0,2827,2827,2827,5654,5654,5654,8481,8481,8481,11308,11308,11308,14135,14135,14135,16962,16962,16962,19789,19789,19789,22616,22616,22616,25443,25443,25443,28270,28270,28270,31097,31097,31097,34181,34181,34181,37008,37008,37008,39835,39835,39835,42662,42662,42662,45489,45489,45489,48316,48316,48316,51143,51143,51143,53970,53970,53970,56797,56797,56797,59624,59624,59624,62451,62451,62451,65535,65535,65535,0,0,0,2827,2827,2827,5654,5654,5654,8481,8481,8481,11308,11308,11308,14135,14135,14135,16962,16962,16962,19789,19789,19789,22616,22616,22616,25443,25443,25443,28270,28270,28270,31097,31097,31097,34181,34181,34181,37008,37008,37008,39835,39835,39835,42662,42662,42662,45489,45489,45489,48316,48316,48316,51143,51143,51143,53970,53970,53970,56797,56797,56797,59624,59624,59624,62451,62451,62451,65535,65535,65535,0,0,0,2827,2827,2827,5654,5654,5654,8481,8481,8481,11308,11308,11308,14135,14135,14135,16962,16962,16962,19789,19789,19789,22616,22616,22616,25443,25443,25443,28270,28270,28270,31097,31097,31097,34181,34181,34181,37008,37008,37008,39835,39835,39835,42662,42662,42662,45489,45489,45489,48316,48316,48316,51143,51143,51143,53970,53970,53970,56797,56797,56797,59624,59624,59624,62451,62451,62451,65535,65535,65535,0,0,0,2827,2827,2827,5654,5654,5654,8481,8481,8481,11308,11308,11308,14135,14135,14135,16962,16962,16962,19789,19789,19789,22616,22616,22616,25443,25443,25443,28270,28270,28270,31097,31097,31097,34181,34181,34181,37008,37008,37008,39835,39835,39835,42662,42662,42662,45489,45489,45489,48316,48316,48316,51143,51143,51143,53970,53970,53970,56797,56797,56797,59624,59624,59624,62451,62451,62451,65535,65535,65535,0,0,0,2827,2827,2827,5654,5654,5654,8481,8481,8481,11308,11308,11308,14135,14135,14135,16962,16962,16962,19789,19789,19789,22616,22616,22616,25443,25443,25443,28270,28270,28270,31097,31097,31097,34181,34181,34181,37008,37008,37008,39835,39835,39835,42662,42662,42662,45489,45489,45489,48316,48316,48316,51143,51143,51143,53970,53970,53970,56797,56797,56797,59624,59624,59624,62451,62451,62451,65535,65535,65535,0,0,0,2827,2827,2827,5654,5654,5654,8481,8481,8481,11308,11308,11308,14135,14135,14135,16962,16962,16962,19789,19789,19789,22616,22616,22616,25443,25443,25443,28270,28270,28270,31097,31097,31097,34181,34181,34181,37008,37008,37008,39835,39835,39835,42662,42662,42662,45489,45489,45489,48316,48316,48316,51143,51143,51143,53970,53970,53970,56797,56797,56797,59624,59624,59624,62451,62451,62451,65535,65535,65535,0,0,0,2827,2827,2827,5654,5654,5654,8481,8481,8481,11308,11308,11308,14135,14135,14135,16962,16962,16962,19789,19789,19789,22616,22616,22616,25443,25443,25443,28270,28270,28270,31097,31097,31097,34181,34181,34181,37008,37008,37008,39835,39835,39835,42662,42662,42662,45489,45489,45489,48316,48316,48316,51143,51143,51143,53970,53970,53970,56797,56797,56797,59624,59624,59624,62451,62451,62451,65535,65535,65535,0,0,0,2827,2827,2827,5654,5654,5654,8481,8481,8481,11308,11308,11308,14135,14135,14135,16962,16962,16962,19789,19789,19789,22616,22616,22616,25443,25443,25443,28270,28270,28270,31097,31097,31097,34181,34181,34181,37008,37008,37008,39835,39835,39835,42662,42662,42662,45489,45489,45489,48316,48316,48316,51143,51143,51143,53970,53970,53970,56797,56797,56797,59624,59624,59624,62451,62451,62451,65535,65535,65535,0,0,0,2827,2827,2827,5654,5654,5654,8481,8481,8481,11308,11308,11308,14135,14135,14135,16962,16962,16962,19789,19789,19789,22616,22616,22616,25443,25443,25443,28270,28270,28270,31097,31097,31097,34181,34181,34181,37008,37008,37008,39835,39835,39835,42662,42662,42662,45489,45489,45489,48316,48316,48316,51143,51143,51143,53970,53970,53970,56797,56797,56797,59624,59624,59624,62451,62451,62451,65535,65535,65535,0,0,0,2827,2827,2827,5654,5654,5654,8481,8481,8481,11308,11308,11308,14135,14135,14135,16962,16962,16962,19789,19789,19789,22616,22616,22616,25443,25443,25443,28270,28270,28270,31097,31097,31097,34181,34181,34181,37008,37008,37008,39835,39835,39835,42662,42662,42662,45489,45489,45489,48316,48316,48316,51143,51143,51143,53970,53970,53970,56797,56797,56797,59624,59624,59624,62451,62451,62451,65535,65535,65535]},{"photo":"photo-rgb-grey.png","fit":false,"ppi_used":300.0,"size":[0.08,0.06],"fits":true,"summary":["Photo: photo-rgb-grey.png","Printer: Canon_MG3600_series","Paper: Letter","Size: 0.08 x 0.06 in at 300 ppi","Toning: neutral","Calibration: none"],"notes":["This is a colour image; it was converted to greyscale."],"rendered_shape":[18,24,3],"rendered":[238,238,238,2774,2774,2774,5691,5691,5691,8427,8427,8427,11363,11363,11363,13971,13971,13971,16724,16724,16724,19735,19735,19735,22397,22397,22397,25700,25700,25700,28087,28087,28087,31281,31281,31281,34016,34016,34016,36935,36935,36935,39835,39835,39835,42478,42478,42478,45709,45709,45709,48371,48371,48371,50996,50996,50996,53989,53989,53989,56761,56761,56761,59863,59863,59863,62304,62304,62304,65351,65351,65351,19,19,19,2774,2774,2774,5619,5619,5619,8666,8666,8666,11181,11181,11181,14172,14172,14172,16816,16816,16816,19919,19919,19919,22543,22543,22543,25462,25462,25462,28216,28216,28216,30969,30969,30969,34200,34200,34200,37174,37174,37174,39597,39597,39597,42589,42589,42589,45361,45361,45361,48446,48446,48446,51070,51070,51070,54209,54209,54209,56779,56779,56779,59790,59790,59790,62286,62286,62286,65535,65535,65535,55,55,55,2723,2723,2723,5619,5619,5619,8243,8243,8243,11235,11235,11235,13878,13878,13878,16944,16944,16944,19735,19735,19735,22598,22598,22598,25370,25370,25370,28400,28400,28400,30895,30895,30895,34347,34347,34347,36824,36824,36824,40074,40074,40074,42644,42644,42644,45600,45600,45600,48555,48555,48555,51198,51198,51198,53823,53823,53823,56981,56981,56981,59624,59624,59624,62671,62671,62671,65516,65516,65516,0,0,0,2723,2723,2723,5453,5453,5453,8720,8720,8720,11125,11125,11125,13952,13952,13952,16908,16908,16908,19735,19735,19735,22855,22855,22855,25278,25278,25278,28436,28436,28436,31152,31152,31152,34071,34071,34071,37138,37138,37138,39890,39890,39890,42460,42460,42460,45251,45251,45251,48187,48187,48187,51382,51382,51382,54025,54025,54025,56963,56963,56963,59495,59495,59495,62341,62341,62341,65351,65351,65351,184,184,184,2846,2846,2846,5728,5728,5728,8298,8298,8298,11144,11144,11144,13878,13878,13878,16889,16889,16889,19661,19661,19661,22507,22507,22507,25425,25425,25425,28252,28252,28252,31061,31061,31061,34181,34181,34181,36806,36806,36806,39725,39725,39725,42735,42735,42735,45728,45728,45728,48389,48389,48389,51382,51382,51382,53952,53952,53952,56613,56613,56613,59551,59551,59551,62433,62433,62433,65480,65480,65480,0,0,0,2809,2809,2809,5857,5857,5857,8738,8738,8738,11051,11051,11051,14154,14154,14154,16908,16908,16908,19844,19844,19844,22855,22855,22855,25296,25296,25296,28344,28344,28344,31300,31300,31300,34053,34053,34053,37008,37008,37008,40055,40055,40055,42589,42589,42589,45655,45655,45655,48555,48555,48555,51216,51216,51216,53823,53823,53823,56908,56908,56908,59754,59754,59754,62599,62599,62599,65480,65480,65480,0,0,0,3049,3049,3049,5691,5691,5691,8463,8463,8463,11308,11308,11308,13878,13878,13878,16724,16724,16724,19587,19587,19587,22414,22414,22414,25407,25407,25407,28400,28400,28400,30895,30895,30895,34163,34163,34163,37008,37008,37008,39854,39854,39854,42589,42589,42589,45342,45342,45342,48243,48243,48243,50996,50996,50996,53989,53989,53989,56927,56927,56927,59440,59440,59440,62581,62581,62581,65516,65516,65516,0,0,0,2703,2703,2703,5769,5769,5769,8631,8631,8631,11529,11529,11529,13989,13989,13989,16743,16743,16743,19808,19808,19808,22616,22616,22616,25315,25315,25315,28325,28325,28325,30895,30895,30895,34420,34420,34420,36972,36972,36972,39578,39578,39578,42552,42552,42552,45251,45251,45251,48464,48464,48464,50941,50941,50941,53786,53786,53786,56540,56540,56540,59844,59844,59844,62378,62378,62378,65535,65535,65535,202,202,202,3049,3049,3049,5709,5709,5709,8224,8224,8224,11308,11308,11308,14100,14100,14100,17017,17017,17017,19643,19643,19643,22562,22562,22562,25462,25462,25462,28473,28473,28473,30950,30950,30950,34420,34420,34420,36824,36824,36824,40055,40055,40055,42698,42698,42698,45709,45709,45709,48243,48243,48243,51107,51107,51107,53805,53805,53805,56816,56816,56816,59367,59367,59367,62635,62635,62635,65462,65462,65462,184,184,184,2902,2902,2902,5709,5709,5709,8243,8243,8243,11382,11382,11382,14135,14135,14135,17128,17128,17128,19551,19551,19551,22855,22855,22855,25663,25663,25663,28050,28050,28050,31043,31043,31043,34016,34016,34016,37120,37120,37120,39707,39707,39707,42478,42478,42478,45489,45489,45489,48335,48335,48335,51179,51179,51179,53786,53786,53786,56559,56559,56559,59459,59459,59459,62396,62396,62396,65535,65535,65535,19,19,19,2723,2723,2723,5839,5839,5839,8243,8243,8243,11235,11235,11235,14062,14062,14062,17128,17128,17128,19919,19919,19919,22616,22616,22616,25480,25480,25480,28234,28234,28234,30895,30895,30895,34365,34365,34365,36972,36972,36972,39615,39615,39615,42792,42792,42792,45637,45637,45637,48555,48555,48555,50886,50886,50886,53860,53860,53860,56927,56927,56927,59551,59551,59551,62451,62451,62451,65351,65351,65351,55,55,55,3049,3049,3049,5548,5548,5548,8317,8317,8317,11089,11089,11089,13971,13971,13971,16760,16760,16760,20009,20009,20009,22378,22378,22378,25646,25646,25646,28289,28289,28289,31043,31043,31043,34071,34071,34071,37156,37156,37156,39908,39908,39908,42882,42882,42882,45269,45269,45269,48573,48573,48573,51088,51088,51088,54209,54209,54209,56963,56963,56963,59808,59808,59808,62524,62524,62524,65297,65297,65297,0,0,0,2626,2626,2626,5619,5619,5619,8536,8536,8536,11070,11070,11070,14338,14338,14338,16981,16981,16981,19973,19973,19973,22451,22451,22451,25480,25480,25480,28509,28509,28509,31300,31300,31300,34330,34330,34330,36806,36806,36806,39854,39854,39854,42792,42792,42792,45269,45269,45269,48096,48096,48096,51070,51070,51070,54006,54006,54006,57017,57017,57017,59660,59660,59660,62599,62599,62599,65516,65516,65516,73,73,73,2774,2774,2774,5636,5636,5636,8446,8446,8446,11474,11474,11474,14008,14008,14008,17074,17074,17074,19587,19587,19587,22836,22836,22836,25663,25663,25663,28436,28436,28436,31079,31079,31079,34347,34347,34347,37120,37120,37120,39983,39983,39983,42681,42681,42681,45269,45269,45269,48261,48261,48261,51179,51179,51179,54172,54172,54172,56742,56742,56742,59606,59606,59606,62322,62322,62322,65278,65278,65278,55,55,55,2902,2902,2902,5805,5805,5805,8684,8684,8684,11345,11345,11345,14209,14209,14209,17093,17093,17093,20046,20046,20046,22819,22819,22819,25296,25296,25296,28270,28270,28270,31281,31281,31281,34053,34053,34053,37063,37063,37063,40038,40038,40038,42810,42810,42810,45525,45525,45525,48500,48500,48500,51014,51014,51014,54043,54043,54043,56687,56687,56687,59367,59367,59367,62708,62708,62708,65516,65516,65516,0,0,0,2703,2703,2703,5875,5875,5875,8738,8738,8738,11529,11529,11529,14117,14117,14117,16724,16724,16724,19844,19844,19844,22414,22414,22414,25296,25296,25296,28142,28142,28142,31209,31209,31209,34254,34254,34254,36843,36843,36843,39578,39578,39578,42424,42424,42424,45416,45416,45416,48536,48536,48536,50996,50996,50996,53970,53970,53970,56816,56816,56816,59826,59826,59826,62231,62231,62231,65333,65333,65333,19,19,19,2755,2755,2755,5416,5416,5416,8374,8374,8374,11106,11106,11106,13916,13916,13916,16779,16779,16779,19919,19919,19919,22873,22873,22873,25407,25407,25407,28325,28325,28325,31317,31317,31317,34163,34163,34163,36954,36954,36954,39597,39597,39597,42442,42442,42442,45746,45746,45746,48261,48261,48261,51216,51216,51216,53915,53915,53915,56981,56981,56981,59660,59660,59660,62267,62267,62267,65351,65351,65351,202,202,202,3012,3012,3012,5709,5709,5709,8595,8595,8595,11458,11458,11458,13989,13989,13989,17201,17201,17201,19606,19606,19606,22873,22873,22873,25443,25443,25443,28289,28289,28289,31300,31300,31300,34311,34311,34311,36824,36824,36824,39578,39578,39578,42644,42644,42644,45471,45471,45471,48482,48482,48482,51273,51273,51273,54100,54100,54100,56577,56577,56577,59624,59624,59624,62708,62708,62708,65351,65351,65351]},{"photo":"photo-grey16.tif","mode":"negative","fit":false,"ppi":40.0,"negative_colour":"green","mirror":true,"safe_edge":0.25,"ppi_used":40.0,"size":[1.1,0.95],"fits":true,"summary":["Photo: photo-grey16.tif","Output: digital negative","Printer: Canon_MG3600_series","Paper: Letter","Size: 1.10 x 0.95 in with a 0.25 in safe edge","Colour: green","Process curve: none (uncalibrated)","Mirrored: yes"],"notes":[],"rendered_shape":[38,44,3],"rendered":[6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,7847,29716,13775,9378,30029,14656,11332,30502,15906,13564,31145,17477,15976,31960,19308,18505,32944,21345,21111,34090,23538,23771,35386,25851,26469,36823,28257,29195,38386,30733,31940,40063,33265,34703,41843,35842,37476,43711,38453,40260,45660,41092,43051,47679,43756,45849,49759,46437,48651,51893,49134,51458,54077,51845,54268,56301,54567,57081,58564,57297,59898,60860,60037,62715,63184,62783,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,7847,29716,13775,9378,30029,14656,11332,30502,15906,13564,31145,17477,15976,31960,19308,18505,32944,21345,21111,34090,23538,23771,35386,25851,26469,36823,28257,29195,38386,30733,31940,40063,33265,34703,41843,35842,37476,43711,38453,40260,45660,41092,43051,47679,43756,45849,49759,46437,48651,51893,49134,51458,54077,51845,54268,56301,54567,57081,58564,57297,59898,60860,60037,62715,63184,62783,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,7847,29716,13775,9378,30029,14656,11332,30502,15906,13564,31145,17477,15976,31960,19308,18505,32944,21345,21111,34090,23538,23771,35386,25851,26469,36823,28257,29195,38386,30733,31940,40063,33265,34703,41843,35842,37476,43711,38453,40260,45660,41092,43051,47679,43756,45849,49759,46437,48651,51893,49134,51458,54077,51845,54268,56301,54567,57081,58564,57297,59898,60860,60037,62715,63184,62783,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,7847,29716,13775,9378,30029,14656,11332,30502,15906,13564,31145,17477,15976,31960,19308,18505,32944,21345,21111,34090,23538,23771,35386,25851,26469,36823,28257,29195,38386,30733,31940,40063,33265,34703,41843,35842,37476,43711,38453,40260,45660,41092,43051,47679,43756,45849,49759,46437,48651,51893,49134,51458,54077,51845,54268,56301,54567,57081,58564,57297,59898,60860,60037,62715,63184,62783,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,7847,29716,13775,9378,30029,14656,11332,30502,15906,13564,31145,17477,15976,31960,19308,18505,32944,21345,21111,34090,23538,23771,35386,25851,26469,36823,28257,29195,38386,30733,31940,40063,33265,34703,41843,35842,37476,43711,38453,40260,45660,41092,43051,47679,43756,45849,49759,46437,48651,51893,49134,51458,54077,51845,54268,56301,54567,57081,58564,57297,59898,60860,60037,62715,63184,62783,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,7847,29716,13775,9378,30029,14656,11332,30502,15906,13564,31145,17477,15976,31960,19308,18505,32944,21345,21111,34090,23538,23771,35386,25851,26469,36823,28257,29195,38386,30733,31940,40063,33265,34703,41843,35842,37476,43711,38453,40260,45660,41092,43051,47679,43756,45849,49759,46437,48651,51893,49134,51458,54077,51845,54268,56301,54567,57081,58564,57297,59898,60860,60037,62715,63184,62783,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,7847,29716,13775,9378,30029,14656,11332,30502,15906,13564,31145,17477,15976,31960,19308,18505,32944,21345,21111,34090,23538,23771,35386,25851,26469,36823,28257,29195,38386,30733,31940,40063,33265,34703,41843,35842,37476,43711,38453,40260,45660,41092,43051,47679,43756,45849,49759,46437,48651,51893,49134,51458,54077,51845,54268,56301,54567,57081,58564,57297,59898,60860,60037,62715,63184,62783,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,7847,29716,13775,9378,30029,14656,11332,30502,15906,13564,31145,17477,15976,31960,19308,18505,32944,21345,21111,34090,23538,23771,35386,25851,26469,36823,28257,29195,38386,30733,31940,40063,33265,34703,41843,35842,37476,43711,38453,40260,45660,41092,43051,47679,43756,45849,49759,46437,48651,51893,49134,51458,54077,51845,54268,56301,54567,57081,58564,57297,59898,60860,60037,62715,63184,62783,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,7847,29716,13775,9378,30029,14656,11332,30502,15906,13564,31145,17477,15976,31960,19308,18505,32944,21345,21111,34090,23538,23771,35386,25851,26469,36823,28257,29195,38386,30733,31940,40063,33265,34703,41843,35842,37476,43711,38453,40260,45660,41092,43051,47679,43756,45849,49759,46437,48651,51893,49134,51458,54077,51845,54268,56301,54567,57081,58564,57297,59898,60860,60037,62715,63184,62783,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,7847,29716,13775,9378,30029,14656,11332,30502,15906,13564,31145,17477,15976,31960,19308,18505,32944,21345,21111,34090,23538,23771,35386,25851,26469,36823,28257,29195,38386,30733,31940,40063,33265,34703,41843,35842,37476,43711,38453,40260,45660,41092,43051,47679,43756,45849,49759,46437,48651,51893,49134,51458,54077,51845,54268,56301,54567,57081,58564,57297,59898,60860,60037,62715,63184,62783,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,7847,29716,13775,9378,30029,14656,11332,30502,15906,13564,31145,17477,15976,31960,19308,18505,32944,21345,21111,34090,23538,23771,35386,25851,26469,36823,28257,29195,38386,30733,31940,40063,33265,34703,41843,35842,37476,43711,38453,40260,45660,41092,43051,47679,43756,45849,49759,46437,48651,51893,49134,51458,54077,51845,54268,56301,54567,57081,58564,57297,59898,60860,60037,62715,63184,62783,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,7847,29716,13775,9378,30029,14656,11332,30502,15906,13564,31145,17477,15976,31960,19308,18505,32944,21345,21111,34090,23538,23771,35386,25851,26469,36823,28257,29195,38386,30733,31940,40063,33265,34703,41843,35842,37476,43711,38453,40260,45660,41092,43051,47679,43756,45849,49759,46437,48651,51893,49134,51458,54077,51845,54268,56301,54567,57081,58564,57297,59898,60860,60037,62715,63184,62783,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,7847,29716,13775,9378,30029,14656,11332,30502,15906,13564,31145,17477,15976,31960,19308,18505,32944,21345,21111,34090,23538,23771,35386,25851,26469,36823,28257,29195,38386,30733,31940,40063,33265,34703,41843,35842,37476,43711,38453,40260,45660,41092,43051,47679,43756,45849,49759,46437,48651,51893,49134,51458,54077,51845,54268,56301,54567,57081,58564,57297,59898,60860,60037,62715,63184,62783,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,7847,29716,13775,9378,30029,14656,11332,30502,15906,13564,31145,17477,15976,31960,19308,18505,32944,21345,21111,34090,23538,23771,35386,25851,26469,36823,28257,29195,38386,30733,31940,40063,33265,34703,41843,35842,37476,43711,38453,40260,45660,41092,43051,47679,43756,45849,49759,46437,48651,51893,49134,51458,54077,51845,54268,56301,54567,57081,58564,57297,59898,60860,60037,62715,63184,62783,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,7847,29716,13775,9378,30029,14656,11332,30502,15906,13564,31145,17477,15976,31960,19308,18505,32944,21345,21111,34090,23538,23771,35386,25851,26469,36823,28257,29195,38386,30733,31940,40063,33265,34703,41843,35842,37476,43711,38453,40260,45660,41092,43051,47679,43756,45849,49759,46437,48651,51893,49134,51458,54077,51845,54268,56301,54567,57081,58564,57297,59898,60860,60037,62715,63184,62783,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,7847,29716,13775,9378,30029,14656,11332,30502,15906,13564,31145,17477,15976,31960,19308,18505,32944,21345,21111,34090,23538,23771,35386,25851,26469,36823,28257,29195,38386,30733,31940,40063,33265,34703,41843,35842,37476,43711,38453,40260,45660,41092,43051,47679,43756,45849,49759,46437,48651,51893,49134,51458,54077,51845,54268,56301,54567,57081,58564,57297,59898,60860,60037,62715,63184,62783,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,7847,29716,13775,9378,30029,14656,11332,30502,15906,13564,31145,17477,15976,31960,19308,18505,32944,21345,21111,34090,23538,23771,35386,25851,26469,36823,28257,29195,38386,30733,31940,40063,33265,34703,41843,35842,37476,43711,38453,40260,45660,41092,43051,47679,43756,45849,49759,46437,48651,51893,49134,51458,54077,51845,54268,56301,54567,57081,58564,57297,59898,60860,60037,62715,63184,62783,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,7847,29716,13775,9378,30029,14656,11332,30502,15906,13564,31145,17477,15976,31960,19308,18505,32944,21345,21111,34090,23538,23771,35386,25851,26469,36823,28257,29195,38386,30733,31940,40063,33265,34703,41843,35842,37476,43711,38453,40260,45660,41092,43051,47679,43756,45849,49759,46437,48651,51893,49134,51458,54077,51845,54268,56301,54567,57081,58564,57297,59898,60860,60037,62715,63184,62783,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107]},{"photo":"photo-grey16.tif","mode":"negative","process":true,"safe_edge":0.1,"ppi_used":3.2876712328767126,"size":[7.5,5.675],"fits":true,"summary":["Photo: photo-grey16.tif","Output: digital negative","Printer: Canon_MG3600_series","Paper: Letter","Size: 7.50 x 5.67 in with a 0.1 in safe edge","Colour: orange","Process curve: session-process.oqproc","Mirrored: no"],"notes":[],"rendered_shape":[18,24,3],"rendered":[65535,65535,65535,64977,61156,60224,64599,57973,56289,64285,55165,52748,64015,52598,49443,63778,50215,46303,63568,47987,43287,63381,45898,40374,63215,43938,37548,63068,42103,34795,62937,40389,32106,62822,38798,29478,62720,37329,26901,62632,35986,24378,62555,34770,21904,62489,33684,19479,62433,32729,17107,62387,31907,14794,62349,31215,12548,62318,30653,10391,62295,30213,8357,62279,29890,6508,62267,29671,4947,62258,29491,3277,65535,65535,65535,64977,61156,60224,64599,57973,56289,64285,55165,52748,64015,52598,49443,63778,50215,46303,63568,47987,43287,63381,45898,40374,63215,43938,37548,63068,42103,34795,62937,40389,32106,62822,38798,29478,62720,37329,26901,62632,35986,24378,62555,34770,21904,62489,33684,19479,62433,32729,17107,62387,31907,14794,62349,31215,12548,62318,30653,10391,62295,30213,8357,62279,29890,6508,62267,29671,4947,62258,29491,3277,65535,65535,65535,64977,61156,60224,64599,57973,56289,64285,55165,52748,64015,52598,49443,63778,50215,46303,63568,47987,43287,63381,45898,40374,63215,43938,37548,63068,42103,34795,62937,40389,32106,62822,38798,29478,62720,37329,26901,62632,35986,24378,62555,34770,21904,62489,33684,19479,62433,32729,17107,62387,31907,14794,62349,31215,12548,62318,30653,10391,62295,30213,8357,62279,29890,6508,62267,29671,4947,62258,29491,3277,65535,65535,65535,64977,61156,60224,64599,57973,56289,64285,55165,52748,64015,52598,49443,63778,50215,46303,63568,47987,43287,63381,45898,40374,63215,43938,37548,63068,42103,34795,62937,40389,32106,62822,38798,29478,62720,37329,26901,62632,35986,24378,62555,34770,21904,62489,33684,19479,62433,32729,17107,62387,31907,14794,62349,31215,12548,62318,30653,10391,62295,30213,8357,62279,29890,6508,62267,29671,4947,62258,29491,3277,65535,65535,65535,64977,61156,60224,64599,57973,56289,64285,55165,52748,64015,52598,49443,63778,50215,46303,63568,47987,43287,63381,45898,40374,63215,43938,37548,63068,42103,34795,62937,40389,32106,62822,38798,29478,62720,37329,26901,62632,35986,24378,62555,34770,21904,62489,33684,19479,62433,32729,17107,62387,31907,14794,62349,31215,12548,62318,30653,10391,62295,30213,8357,62279,29890,6508,62267,29671,4947,62258,29491,3277,65535,65535,65535,64977,61156,60224,64599,57973,56289,64285,55165,52748,64015,52598,49443,63778,50215,46303,63568,47987,43287,63381,45898,40374,63215,43938,37548,63068,42103,34795,62937,40389,32106,62822,38798,29478,62720,37329,26901,62632,35986,24378,62555,34770,21904,62489,33684,19479,62433,32729,17107,62387,31907,14794,62349,31215,12548,62318,30653,10391,62295,30213,8357,62279,29890,6508,62267,29671,4947,62258,29491,3277,65535,65535,65535,64977,61156,60224,64599,57973,56289,64285,55165,52748,64015,52598,49443,63778,50215,46303,63568,47987,43287,63381,45898,40374,63215,43938,37548,63068,42103,34795,62937,40389,32106,62822,38798,29478,62720,37329,26901,62632,35986,24378,62555,34770,21904,62489,33684,19479,62433,32729,17107,62387,31907,14794,62349,31215,12548,62318,30653,10391,62295,30213,8357,62279,29890,6508,62267,29671,4947,62258,29491,3277,65535,65535,65535,64977,61156,60224,64599,57973,56289,64285,55165,52748,64015,52598,49443,63778,50215,46303,63568,47987,43287,63381,45898,40374,63215,43938,37548,63068,42103,34795,62937,40389,32106,62822,38798,29478,62720,37329,26901,62632,35986,24378,62555,34770,21904,62489,33684,19479,62433,32729,17107,62387,31907,14794,62349,31215,12548,62318,30653,10391,62295,30213,8357,62279,29890,6508,62267,29671,4947,62258,29491,3277,65535,65535,65535,64977,61156,60224,64599,57973,56289,64285,55165,52748,64015,52598,49443,63778,50215,46303,63568,47987,43287,63381,45898,40374,63215,43938,37548,63068,42103,34795,62937,40389,32106,62822,38798,29478,62720,37329,26901,62632,35986,24378,62555,34770,21904,62489,33684,19479,62433,32729,17107,62387,31907,14794,62349,31215,12548,62318,30653,10391,62295,30213,8357,62279,29890,6508,62267,29671,4947,62258,29491,3277,65535,65535,65535,64977,61156,60224,64599,57973,56289,64285,55165,52748,64015,52598,49443,63778,50215,46303,63568,47987,43287,63381,45898,40374,63215,43938,37548,63068,42103,34795,62937,40389,32106,62822,38798,29478,62720,37329,26901,62632,35986,24378,62555,34770,21904,62489,33684,19479,62433,32729,17107,62387,31907,14794,62349,31215,12548,62318,30653,10391,62295,30213,8357,62279,29890,6508,62267,29671,4947,62258,29491,3277,65535,65535,65535,64977,61156,60224,64599,57973,56289,64285,55165,52748,64015,52598,49443,63778,50215,46303,63568,47987,43287,63381,45898,40374,63215,43938,37548,63068,42103,34795,62937,40389,32106,62822,38798,29478,62720,37329,26901,62632,35986,24378,62555,34770,21904,62489,33684,19479,62433,32729,17107,62387,31907,14794,62349,31215,12548,62318,30653,10391,62295,30213,8357,62279,29890,6508,62267,29671,4947,62258,29491,3277,65535,65535,65535,64977,61156,60224,64599,57973,56289,64285,55165,52748,64015,52598,49443,63778,50215,46303,63568,47987,43287,63381,45898,40374,63215,43938,37548,63068,42103,34795,62937,40389,32106,62822,38798,29478,62720,37329,26901,62632,35986,24378,62555,34770,21904,62489,33684,19479,62433,32729,17107,62387,31907,14794,62349,31215,12548,62318,30653,10391,62295,30213,8357,62279,29890,6508,62267,29671,4947,62258,29491,3277,65535,65535,65535,64977,61156,60224,64599,57973,56289,64285,55165,52748,64015,52598,49443,63778,50215,46303,63568,47987,43287,63381,45898,40374,63215,43938,37548,63068,42103,34795,62937,40389,32106,62822,38798,29478,62720,37329,26901,62632,35986,24378,62555,34770,21904,62489,33684,19479,62433,32729,17107,62387,31907,14794,62349,31215,12548,62318,30653,10391,62295,30213,8357,62279,29890,6508,62267,29671,4947,62258,29491,3277,65535,65535,65535,64977,61156,60224,64599,57973,56289,64285,55165,52748,64015,52598,49443,63778,50215,46303,63568,47987,43287,63381,45898,40374,63215,43938,37548,63068,42103,34795,62937,40389,32106,62822,38798,29478,62720,37329,26901,62632,35986,24378,62555,34770,21904,62489,33684,19479,62433,32729,17107,62387,31907,14794,62349,31215,12548,62318,30653,10391,62295,30213,8357,62279,29890,6508,62267,29671,4947,62258,29491,3277,65535,65535,65535,64977,61156,60224,64599,57973,56289,64285,55165,52748,64015,52598,49443,63778,50215,46303,63568,47987,43287,63381,45898,40374,63215,43938,37548,63068,42103,34795,62937,40389,32106,62822,38798,29478,62720,37329,26901,62632,35986,24378,62555,34770,21904,62489,33684,19479,62433,32729,17107,62387,31907,14794,62349,31215,12548,62318,30653,10391,62295,30213,8357,62279,29890,6508,62267,29671,4947,62258,29491,3277,65535,65535,65535,64977,61156,60224,64599,57973,56289,64285,55165,52748,64015,52598,49443,63778,50215,46303,63568,47987,43287,63381,45898,40374,63215,43938,37548,63068,42103,34795,62937,40389,32106,62822,38798,29478,62720,37329,26901,62632,35986,24378,62555,34770,21904,62489,33684,19479,62433,32729,17107,62387,31907,14794,62349,31215,12548,62318,30653,10391,62295,30213,8357,62279,29890,6508,62267,29671,4947,62258,29491,3277,65535,65535,65535,64977,61156,60224,64599,57973,56289,64285,55165,52748,64015,52598,49443,63778,50215,46303,63568,47987,43287,63381,45898,40374,63215,43938,37548,63068,42103,34795,62937,40389,32106,62822,38798,29478,62720,37329,26901,62632,35986,24378,62555,34770,21904,62489,33684,19479,62433,32729,17107,62387,31907,14794,62349,31215,12548,62318,30653,10391,62295,30213,8357,62279,29890,6508,62267,29671,4947,62258,29491,3277,65535,65535,65535,64977,61156,60224,64599,57973,56289,64285,55165,52748,64015,52598,49443,63778,50215,46303,63568,47987,43287,63381,45898,40374,63215,43938,37548,63068,42103,34795,62937,40389,32106,62822,38798,29478,62720,37329,26901,62632,35986,24378,62555,34770,21904,62489,33684,19479,62433,32729,17107,62387,31907,14794,62349,31215,12548,62318,30653,10391,62295,30213,8357,62279,29890,6508,62267,29671,4947,62258,29491,3277]},{"photo":"photo-grey16.tif","mode":"negative","max_size":[2.0,3.0],"safe_edge":0.25,"ppi_used":12.0,"size":[2.5,2.0],"fits":true,"summary":["Photo: photo-grey16.tif","Output: digital negative","Printer: Canon_MG3600_series","Paper: Letter","Fit within: 3 x 2 in","Size: 2.50 x 2.00 in with a 0.25 in safe edge","Colour: green","Process curve: none (uncalibrated)","Mirrored: no"],"notes":[],"rendered_shape":[24,30,3],"rendered":[6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107]},{"photo":"photo-grey16.tif","max_size":[2.5,1.5],"ppi_used":12.0,"size":[2.0,1.5],"fits":true,"summary":["Photo: photo-grey16.tif","Printer: Canon_MG3600_series","Paper: Letter","Fit within: 2.5 x 1.5 in","Size: 2.00 x 1.50 in at 12 ppi","Toning: neutral","Calibration: none"],"notes":[],"rendered_shape":[18,24,3],"rendered":[0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535]},{"photo":"photo-grey16.tif","max_size":[40.0,30.0],"paper":"4x6","ppi_used":8.0,"size":[3.0,2.25],"fits":true,"summary":["Photo: photo-grey16.tif","Printer: Canon_MG3600_series","Paper: 4x6","Fit within: 40 x 30 in","Size: 3.00 x 2.25 in at 8 ppi","Toning: neutral","Calibration: none"],"notes":[],"rendered_shape":[18,24,3],"rendered":[0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535]},{"photo":"photo-grey16.tif","mode":"negative","fit":false,"ppi":20.0,"safe_edge":0.2,"outline":0.15,"ppi_used":20.0,"size":[1.9,1.6],"fits":true,"summary":["Photo: photo-grey16.tif","Output: digital negative","Printer: Canon_MG3600_series","Paper: Letter","Size: 1.90 x 1.60 in with a 0.2 in safe edge and a 0.15 in black outline","Colour: green","Process curve: none (uncalibrated)","Mirrored: no"],"notes":[],"rendered_shape":[32,38,3],"rendered":[6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,65535,65535,65535,65535,65535,65535,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,65535,65535,65535,65535,65535,65535,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,65535,65535,65535,65535,65535,65535,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,65535,65535,65535,65535,65535,65535,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,65535,65535,65535,65535,65535,65535,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,65535,65535,65535,65535,65535,65535,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,65535,65535,65535,65535,65535,65535,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,65535,65535,65535,65535,65535,65535,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,65535,65535,65535,65535,65535,65535,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,65535,65535,65535,65535,65535,65535,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,65535,65535,65535,65535,65535,65535,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,65535,65535,65535,65535,65535,65535,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,65535,65535,65535,65535,65535,65535,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,65535,65535,65535,65535,65535,65535,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,65535,65535,65535,65535,65535,65535,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,65535,65535,65535,65535,65535,65535,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,65535,65535,65535,65535,65535,65535,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,65535,65535,65535,65535,65535,65535,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107]},{"photo":"photo-grey16.tif","mode":"negative","max_size":[2.0,3.0],"safe_edge":0.25,"outline":0.1,"ppi_used":13.846153846153845,"size":[2.4333333333333336,2.0],"fits":true,"summary":["Photo: photo-grey16.tif","Output: digital negative","Printer: Canon_MG3600_series","Paper: Letter","Fit within: 3 x 2 in","Size: 2.43 x 2.00 in with a 0.25 in safe edge and a 0.1 in black outline","Colour: green","Process curve: none (uncalibrated)","Mirrored: no"],"notes":[],"rendered_shape":[26,32,3],"rendered":[6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107]},{"photo":"photo-grey16.tif","mode":"negative","max_size":[4.0,5.0],"safe_edge":0.25,"outline":0.0625,"units":"mm","ppi_used":5.485714285714286,"size":[5.0,3.90625],"fits":true,"summary":["Photo: photo-grey16.tif","Output: digital negative","Printer: Canon_MG3600_series","Paper: Letter","Fit within: 127 x 101.6 mm","Size: 127.0 x 99.2 mm with a 6.35 mm safe edge and a 1.59 mm black outline","Colour: green","Process curve: none (uncalibrated)","Mirrored: no"],"notes":[],"rendered_shape":[20,26,3],"rendered":[6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,6553,29491,13107,6553,29491,13107,65535,65535,65535,62715,63184,62783,59898,60860,60037,57081,58564,57297,54268,56301,54567,51458,54077,51845,48651,51893,49134,45849,49759,46437,43051,47679,43756,40260,45660,41092,37476,43711,38453,34703,41843,35842,31940,40063,33265,29195,38386,30733,26469,36823,28257,23771,35386,25851,21111,34090,23538,18505,32944,21345,15976,31960,19308,13564,31145,17477,11332,30502,15906,9378,30029,14656,7847,29716,13775,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107,6553,29491,13107]},{"photo":"photo-grey16.tif","fit":false,"ppi":7.0,"units":"mm","ppi_used":7.0,"size":[3.4285714285714284,2.5714285714285716],"fits":true,"summary":["Photo: photo-grey16.tif","Printer: Canon_MG3600_series","Paper: Letter","Size: 87.1 x 65.3 mm at 7 ppi","Toning: neutral","Calibration: none"],"notes":[],"rendered_shape":[18,24,3],"rendered":[0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535,0,0,0,2849,2849,2849,5698,5698,5698,8548,8548,8548,11397,11397,11397,14246,14246,14246,17096,17096,17096,19945,19945,19945,22794,22794,22794,25644,25644,25644,28493,28493,28493,31342,31342,31342,34192,34192,34192,37041,37041,37041,39890,39890,39890,42740,42740,42740,45589,45589,45589,48438,48438,48438,51288,51288,51288,54137,54137,54137,56986,56986,56986,59836,59836,59836,62685,62685,62685,65535,65535,65535]}]} diff --git a/tests/test_session.py b/tests/test_session.py index 510c95c..71e3b7a 100644 --- a/tests/test_session.py +++ b/tests/test_session.py @@ -182,3 +182,14 @@ def test_black_outline_is_part_of_the_negatives_size(tmp_path: Path) -> None: assert any("and a 0.1 in black outline" in line for line in session.summary()) session.fit, session.max_size = True, (4.0, 5.0) # the box holds photo, outline and edge assert session.size_inches()[1] == pytest.approx(5.0) + + +def test_summary_shows_lengths_in_millimetres(tmp_path: Path) -> None: + session = opened(tmp_path, mode="negative", fit=False, ppi=100.0, safe_edge=0.25, outline=0.1) + session.set_units("mm") + size = next(line for line in session.summary() if line.startswith("Size:")) + assert size == "Size: 94.0 x 119.4 mm with a 6.35 mm safe edge and a 2.54 mm black outline" + session.fit, session.max_size = True, (4.0, 5.0) + assert "Fit within: 101.6 x 127 mm" in session.summary() + with pytest.raises(ValueError, match="units"): + session.set_units("cm") diff --git a/tests/test_settings.py b/tests/test_settings.py index 0cd4958..ad94f80 100644 --- a/tests/test_settings.py +++ b/tests/test_settings.py @@ -52,3 +52,10 @@ def test_max_size_is_remembered(tmp_path: Path) -> None: Settings(max_size=[8.0, 10.0]).save(path) assert Settings.load(path).max_size == [8.0, 10.0] assert Settings.load(tmp_path / "missing.json").max_size is None + + +def test_units_are_remembered(tmp_path: Path) -> None: + path = tmp_path / "settings.json" + assert Settings.load(path).units == "in" + Settings(units="mm").save(path) + assert Settings.load(path).units == "mm" diff --git a/tests/test_units.py b/tests/test_units.py new file mode 100644 index 0000000..ae892cc --- /dev/null +++ b/tests/test_units.py @@ -0,0 +1,21 @@ +import pytest + +from openquad.units import box, from_unit, length, size, to_unit + + +def test_lengths_in_either_unit() -> None: + assert length(0.25, "in") == "0.25 in" + assert length(0.25, "mm") == "6.35 mm" + assert length(from_unit(5.0, "mm"), "mm") == "5 mm" + assert box(8.0, 10.0, "in") == "8 x 10 in" + assert box(8.0, 10.0, "mm") == "203.2 x 254 mm" + assert size(7.5, 5.0, "in") == "7.50 x 5.00 in" + assert size(7.5, 5.0, "mm") == "190.5 x 127.0 mm" + + +def test_conversion_round_trips() -> None: + assert to_unit(1.0, "mm") == pytest.approx(25.4) + assert from_unit(to_unit(0.37, "mm"), "mm") == pytest.approx(0.37) + assert to_unit(0.37, "in") == 0.37 + with pytest.raises(ValueError, match="units"): + length(1.0, "cm") From 7494f1963006b38d63ac2fe424d1de024f34bf43 Mon Sep 17 00:00:00 2001 From: akendrick <548951+akendrick@users.noreply.github.com> Date: Sun, 1 Nov 2026 21:59:15 -0700 Subject: [PATCH 2/5] Saved negative setups: switch between calibrated processes in one step MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Save Setup… (negative mode) keeps the process curve (copied in beside the setup), ink colour, mirror, safe edge, black outline, printer and paper under a name; the Setup menu applies one and shows which setup the settings match. Stored as .oqsetup JSON in OpenQuad's setups folder. Co-Authored-By: Claude Opus 5.5 --- CHANGELOG.md | 4 + .../Sources/OpenQuad/OpenQuadApp.swift | 7 +- .../Sources/OpenQuadUI/AppModel.swift | 68 ++++++++- .../Sources/OpenQuadUI/ContentView.swift | 35 +++++ .../Sources/OpenQuadUI/Guide.swift | 6 +- .../Tests/OpenQuadUITests/AppModelTests.swift | 40 ++++++ .../Sources/OpenQuadCore/NegativeSetups.swift | 135 ++++++++++++++++++ .../Tests/OpenQuadCoreTests/SetupTests.swift | 47 ++++++ 8 files changed, 337 insertions(+), 5 deletions(-) create mode 100644 swift/OpenQuadCore/Sources/OpenQuadCore/NegativeSetups.swift create mode 100644 swift/OpenQuadCore/Tests/OpenQuadCoreTests/SetupTests.swift diff --git a/CHANGELOG.md b/CHANGELOG.md index 3bcae84..55ded76 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,10 @@ versions follow [Semantic Versioning](https://semver.org/). ## [Unreleased] ### Added +- Saved negative setups: Save Setup… in negative mode remembers the process curve (a copy is kept + with the setup), ink colour, mirror, safe edge, black outline, printer and paper under a name + such as "Cyanotype on Pictorico"; the Setup menu switches all of them at once, and shows which + setup the current settings match. Kept as .oqsetup files in OpenQuad's setups folder. - Millimetres: OpenQuad > Settings… (⌘,) shows and takes every length in the app (safe edge, black outline, set sizes, print sizes, the summary) in inches or millimetres, remembered between sessions. Files, settings and the command line stay in inches. diff --git a/swift/OpenQuadApp/Sources/OpenQuad/OpenQuadApp.swift b/swift/OpenQuadApp/Sources/OpenQuad/OpenQuadApp.swift index 2b5a2d7..f9fe9f7 100644 --- a/swift/OpenQuadApp/Sources/OpenQuad/OpenQuadApp.swift +++ b/swift/OpenQuadApp/Sources/OpenQuad/OpenQuadApp.swift @@ -2,7 +2,7 @@ // // OpenQuad the app // OpenQuad --snapshot out.png [--photo PHOTO] [--negative] [--printer CUPS_QUEUE] [--max-size WxH] -// [--outline INCHES] [--units in|mm] +// [--outline INCHES] [--units in|mm] [--setups FOLDER] [--setup NAME] // OpenQuad --snapshot out.png --wizard calibration|process|blocking|guide [--scan SCAN] [--run RUN] // [--mixtures] (blocking: the ink-mixture chart) // draw the window to a PNG and quit (for checks) @@ -79,10 +79,13 @@ enum Snapshot { let settings = FileManager.default.temporaryDirectory.appendingPathComponent("openquad-snapshot-settings.json") try? FileManager.default.removeItem(at: settings) // The real calibrations, so the snapshot shows what this Mac has. - let model = AppModel(settingsURL: settings, libraryFolder: AppSettings.dataDirectory().appendingPathComponent("calibrations")) + let model = AppModel(settingsURL: settings, libraryFolder: AppSettings.dataDirectory().appendingPathComponent("calibrations"), + setupsFolder: value("--setups").map { URL(fileURLWithPath: $0) } + ?? AppSettings.dataDirectory().appendingPathComponent("setups")) if let photo = value("--photo") { model.openPhoto(URL(fileURLWithPath: photo)) } if arguments.contains("--negative") { model.setMode(.negative) } if let printer = value("--printer") { model.setPrinter(printer) } + if let name = value("--setup"), let setup = model.setups.first(where: { $0.name == name }) { model.applySetup(setup) } if let size = value("--max-size")?.lowercased().split(separator: "x").compactMap({ Double($0) }), size.count == 2 { model.setMaxSize((size[0], size[1])) } diff --git a/swift/OpenQuadApp/Sources/OpenQuadUI/AppModel.swift b/swift/OpenQuadApp/Sources/OpenQuadUI/AppModel.swift index b700c7d..3281905 100644 --- a/swift/OpenQuadApp/Sources/OpenQuadUI/AppModel.swift +++ b/swift/OpenQuadApp/Sources/OpenQuadUI/AppModel.swift @@ -31,13 +31,19 @@ public final class AppModel { /// Saved calibrations to choose from: the newest of each printer and paper. public private(set) var calibrations: [LibraryEntry] = [] public let library: CalibrationLibrary + /// Saved negative setups (process curve, colour, mirror, edges, printer, paper). + public let setupLibrary: SetupLibrary + public private(set) var setups: [NegativeSetup] = [] let settingsURL: URL private var previewToken = 0 - public init(settingsURL: URL = AppSettings.defaultURL(), libraryFolder: URL? = nil) { + public init(settingsURL: URL = AppSettings.defaultURL(), libraryFolder: URL? = nil, setupsFolder: URL? = nil) { self.settingsURL = settingsURL library = CalibrationLibrary(folder: libraryFolder ?? settingsURL.deletingLastPathComponent().appendingPathComponent("calibrations")) + setupLibrary = SetupLibrary(folder: setupsFolder + ?? settingsURL.deletingLastPathComponent().appendingPathComponent("setups")) + setups = setupLibrary.all() settings = AppSettings.load(settingsURL) restore() refreshLibrary() @@ -208,6 +214,66 @@ public final class AppModel { refreshPreview() } + // MARK: saved negative setups + + /// The saved setup the negative settings match right now, if any. + public var currentSetup: NegativeSetup? { + setups.first { setup in + let curve = setupLibrary.processURL(setup)?.resolvingSymlinksInPath() + return setup.colour == session.negativeColour && setup.mirror == session.mirror + && abs(setup.safeEdge - session.safeEdge) < 1e-9 && abs(setup.outline - session.outline) < 1e-9 + && curve == session.processPath?.resolvingSymlinksInPath() + && setup.printer == session.printer && setup.paper == session.paper + } + } + + /// Switch to a saved setup: its curve, colour, mirror, edges, printer and paper. + public func applySetup(_ setup: NegativeSetup) { + setMode(.negative) + setPaper(setup.paper) + setPrinter(setup.printer) + if let curve = setupLibrary.processURL(setup) { + setProcess(curve) + } else { + setProcess(nil) + setNegativeColour(setup.colour) + } + session.mirror = setup.mirror + setSafeEdge(setup.safeEdge) + if setup.outline > 0 { outlineSize = setup.outline } + setOutline(setup.outline > 0) + } + + /// A name to offer when saving: "Carbon, green, Letter". + public var suggestedSetupName: String { + let process = session.process.map(\.process).flatMap { $0.isEmpty ? nil : $0.capitalized } ?? "Negative" + return "\(process), \(session.negativeColour), \(session.paper)" + } + + /// Save the negative settings as a setup (replacing one of the same name). + public func saveSetup(named name: String) { + attempt { + let setup = NegativeSetup(name: name, colour: session.negativeColour, mirror: session.mirror, + safeEdge: session.safeEdge, outline: session.outline, + printer: session.printer, paper: session.paper) + try setupLibrary.save(setup, process: session.processPath) + setups = setupLibrary.all() + // Point at the setup's own copy of the curve, so the setup shows as chosen. + if let saved = setups.first(where: { $0.name == name.trimmingCharacters(in: .whitespacesAndNewlines) }), + let curve = setupLibrary.processURL(saved) { + try session.setProcess(curve) + remember() + } + } + } + + public func deleteSetup(_ setup: NegativeSetup) { + attempt { + try setupLibrary.delete(setup) + setups = setupLibrary.all() + } + } + public func setPaper(_ paper: String) { attempt { try session.setPaper(paper) diff --git a/swift/OpenQuadApp/Sources/OpenQuadUI/ContentView.swift b/swift/OpenQuadApp/Sources/OpenQuadUI/ContentView.swift index eaf71f4..2268343 100644 --- a/swift/OpenQuadApp/Sources/OpenQuadUI/ContentView.swift +++ b/swift/OpenQuadApp/Sources/OpenQuadUI/ContentView.swift @@ -10,6 +10,9 @@ public struct ContentView: View { @Bindable var model: AppModel @State private var ppiText = "" @State private var showGuide = false + @State private var savingSetup = false + @State private var setupName = "" + @State private var deletingSetup: NegativeSetup? @AppStorage("guideSeen") private var guideSeen = 0 let guideOnLaunch: Bool @@ -28,6 +31,23 @@ public struct ContentView: View { } .frame(minWidth: 820, minHeight: 600) .sheet(isPresented: $showGuide) { GuideView { guideSeen = GuideView.version } } + .alert("Save Negative Setup", isPresented: $savingSetup) { + TextField("Name", text: $setupName) + Button("Save") { model.saveSetup(named: setupName) } + .disabled(setupName.trimmingCharacters(in: .whitespaces).isEmpty) + Button("Cancel", role: .cancel) {} + } message: { + Text("Remembers the process curve, ink colour, mirror, safe edge, black outline, printer and paper. " + + "A setup with the same name is replaced.") + } + .confirmationDialog("Delete the setup “\(deletingSetup?.name ?? "")”?", isPresented: Binding( + get: { deletingSetup != nil }, set: { if !$0 { deletingSetup = nil } })) { + Button("Delete", role: .destructive) { + if let setup = deletingSetup { model.deleteSetup(setup) } + } + } message: { + Text("Its copy of the process curve goes too. Your own curve files are not touched.") + } .toolbar { ToolbarItem { Button { showGuide = true } label: { Label("How to Use OpenQuad", systemImage: "questionmark.circle") } @@ -182,6 +202,21 @@ public struct ContentView: View { } @ViewBuilder private var negativeControls: some View { + Picker("Setup", selection: Binding(get: { model.currentSetup?.name ?? "" }, set: { name in + if let setup = model.setups.first(where: { $0.name == name }) { model.applySetup(setup) } + })) { + Text(model.setups.isEmpty ? "None saved" : "Custom").tag("") + ForEach(model.setups) { Text($0.name).tag($0.name) } + } + HStack { + Button("Save Setup…") { + setupName = model.currentSetup?.name ?? model.suggestedSetupName + savingSetup = true + } + if let current = model.currentSetup { + Button("Delete Setup…") { deletingSetup = current } + } + } Picker("Ink colour", selection: Binding(get: { model.session.negativeColour }, set: { model.setNegativeColour($0) })) { ForEach(Negative.colourOrder, id: \.self) { Text($0.capitalized).tag($0) } } diff --git a/swift/OpenQuadApp/Sources/OpenQuadUI/Guide.swift b/swift/OpenQuadApp/Sources/OpenQuadUI/Guide.swift index 4852ce6..f32f3ec 100644 --- a/swift/OpenQuadApp/Sources/OpenQuadUI/Guide.swift +++ b/swift/OpenQuadApp/Sources/OpenQuadUI/Guide.swift @@ -5,7 +5,7 @@ import SwiftUI public struct GuideView: View { /// Raise when the guide changes enough to show it again on launch. - public static let version = 9 + public static let version = 10 public static let showNotification = Notification.Name("OpenQuadShowGuide") struct Page { @@ -52,7 +52,9 @@ public struct GuideView: View { Page(symbol: "film", title: "Digital negatives", text: "Output: Digital negative turns the photo into a negative for contact printing, in black or a " + "colour that blocks UV.", - steps: ["Ink colour: the colour to print the negative in (the blocking test finds the best one).", + steps: ["Setup: switch between saved setups (curve, colour, mirror, edges, printer and paper) in one step. " + + "Once a process is calibrated, Save Setup… keeps it under a name, e.g. Cyanotype on Pictorico.", + "Ink colour: the colour to print the negative in (the blocking test finds the best one).", "Process curve: shapes the tones for your process (made by Calibrate a Process…).", "Mirror if the film's printed side must face the tissue.", "The safe edge frames the photo; the F cut into it reads correctly in the print when the " diff --git a/swift/OpenQuadApp/Tests/OpenQuadUITests/AppModelTests.swift b/swift/OpenQuadApp/Tests/OpenQuadUITests/AppModelTests.swift index c6ce751..85d1b3b 100644 --- a/swift/OpenQuadApp/Tests/OpenQuadUITests/AppModelTests.swift +++ b/swift/OpenQuadApp/Tests/OpenQuadUITests/AppModelTests.swift @@ -102,6 +102,46 @@ struct AppModelTests { #expect(m.summary.joined().contains("with a 0.19685 in safe edge") && model().units == .inches) } + @Test func negativeSetupsAreSavedAndSwitchedBetween() throws { + let m = model() + #expect(m.setups.isEmpty && m.currentSetup == nil) + let curve = folder.appendingPathComponent("cyanotype-curve.oqproc") + try ProcessCurve.identity(colour: "orange").encode().write(to: curve) + m.openPhoto(photo) + m.setMode(.negative) + m.setProcess(curve) + m.setMirror(true) + m.setSafeEdge(0.3) + m.setOutlineSize(0.05) + m.setOutline(true) + m.setPaper("A4") + m.setPrinter("Epson_ET_2900") + #expect(m.suggestedSetupName == "Carbon, orange, A4") + m.saveSetup(named: "Cyanotype") + #expect(m.error == nil && m.setups.map(\.name) == ["Cyanotype"] && m.currentSetup?.name == "Cyanotype") + #expect(m.session.processPath?.lastPathComponent == "cyanotype.oqproc") // the setup's own copy + + m.setProcess(nil) + m.setNegativeColour("black") + m.setMirror(false) + m.setSafeEdge(0.25) + m.setOutline(false) + m.setPaper("Letter") + m.setPrinter(nil) + #expect(m.currentSetup == nil) + m.saveSetup(named: "Carbon black") + #expect(m.setups.map(\.name) == ["Carbon black", "Cyanotype"] && m.currentSetup?.name == "Carbon black") + + m.applySetup(m.setups[1]) + #expect(m.currentSetup?.name == "Cyanotype") + #expect(m.session.negativeColour == "orange" && m.session.mirror && m.session.safeEdge == 0.3) + #expect(m.session.outline == 0.05 && m.session.paper == "A4" && m.session.printer == "Epson_ET_2900") + let again = model() // a new window sees the same setups + #expect(again.setups.count == 2) + again.deleteSetup(again.setups[1]) + #expect(again.setups.map(\.name) == ["Carbon black"]) + } + @Test func negativesAndErrors() throws { let m = model() m.openPhoto(photo) diff --git a/swift/OpenQuadCore/Sources/OpenQuadCore/NegativeSetups.swift b/swift/OpenQuadCore/Sources/OpenQuadCore/NegativeSetups.swift new file mode 100644 index 0000000..e2c8e2e --- /dev/null +++ b/swift/OpenQuadCore/Sources/OpenQuadCore/NegativeSetups.swift @@ -0,0 +1,135 @@ +// Saved digital-negative setups ("Cyanotype on Pictorico"): the process curve, ink +// colour, mirror, safe edge, black outline, printer and paper that go together, so the +// app can switch between calibrated processes in one step. Each setup is an .oqsetup +// file in the app's setups folder, with a copy of its process curve beside it, so it +// keeps working if the original curve file is moved or deleted. + +import Foundation + +public struct NegativeSetup: Sendable, Equatable, Identifiable { + public var name: String + public var colour: String + /// The process curve's file name in the setups folder, or nil for none. + public var process: String? + public var mirror: Bool + /// Inches. + public var safeEdge: Double + /// Inches of black outline (0 for none). + public var outline: Double + /// The CUPS queue, or nil to choose in the macOS print panel. + public var printer: String? + public var paper: String + public var created: String + + public var id: String { name } + + public init(name: String, colour: String, process: String? = nil, mirror: Bool = false, safeEdge: Double = 0.25, + outline: Double = 0, printer: String? = nil, paper: String = "Letter", created: String = "") { + self.name = name + self.colour = colour + self.process = process + self.mirror = mirror + self.safeEdge = safeEdge + self.outline = outline + self.printer = printer + self.paper = paper + self.created = created + } + + struct File: Codable { + var format: String + var version: Int + var name: String + var colour: String + var process: String? + var mirror: Bool + var safe_edge: Double + var outline: Double + var printer: String? + var paper: String + var created: String? + } + + public static func decode(_ data: Data) throws -> NegativeSetup { + let file: File + do { file = try JSONDecoder().decode(File.self, from: data) } catch { + throw FileFormatError(description: "not valid JSON: \(error)") + } + guard file.format == "openquad-setup" else { throw FileFormatError(description: "not an OpenQuad negative setup") } + guard file.version == 1 else { throw FileFormatError(description: "unsupported setup version \(file.version)") } + guard Negative.colours[file.colour] != nil else { throw FileFormatError(description: "unknown negative colour \(file.colour)") } + guard Paper.sizes[file.paper] != nil else { throw FileFormatError(description: "unknown paper \(file.paper)") } + return NegativeSetup(name: file.name, colour: file.colour, process: file.process, mirror: file.mirror, + safeEdge: min(max(file.safe_edge, 0), 2), outline: min(max(file.outline, 0), 1), + printer: file.printer, paper: file.paper, created: file.created ?? "") + } + + public func encode() throws -> Data { + let file = File(format: "openquad-setup", version: 1, name: name, colour: colour, process: process, mirror: mirror, + safe_edge: safeEdge, outline: outline, printer: printer, paper: paper, created: created) + let encoder = JSONEncoder() + encoder.outputFormatting = [.prettyPrinted, .sortedKeys] + return try encoder.encode(file) + } +} + +public struct SetupLibrary: Sendable { + public let folder: URL + + public init(folder: URL = AppSettings.dataDirectory().appendingPathComponent("setups")) { + self.folder = folder.resolvingSymlinksInPath() + } + + /// "cyanotype-on-pictorico" from "Cyanotype on Pictorico". + static func slug(_ name: String) -> String { + let words = name.lowercased().split { !$0.isLetter && !$0.isNumber } + return words.isEmpty ? "setup" : words.joined(separator: "-") + } + + func url(_ name: String) -> URL { folder.appendingPathComponent("\(Self.slug(name)).oqsetup") } + + /// The setup's own copy of its process curve, if it has one. + public func processURL(_ setup: NegativeSetup) -> URL? { + setup.process.map { folder.appendingPathComponent($0) } + } + + /// Every saved setup, by name. + public func all() -> [NegativeSetup] { + let files = (try? FileManager.default.contentsOfDirectory(at: folder, includingPropertiesForKeys: nil)) ?? [] + return files.filter { $0.pathExtension == "oqsetup" } + .compactMap { try? NegativeSetup.decode(Data(contentsOf: $0)) } + .sorted { $0.name.localizedStandardCompare($1.name) == .orderedAscending } + } + + /// Save `setup` (replacing one of the same name), copying the process curve at + /// `process` in beside it. Returns the setup as saved. + @discardableResult + public func save(_ setup: NegativeSetup, process: URL?) throws -> NegativeSetup { + let name = setup.name.trimmingCharacters(in: .whitespacesAndNewlines) + guard !name.isEmpty else { throw FileFormatError(description: "the setup needs a name") } + try FileManager.default.createDirectory(at: folder, withIntermediateDirectories: true) + var saved = setup + saved.name = name + saved.process = nil + if let process { + let data = try Data(contentsOf: process) + _ = try ProcessCurve.decode(data) + let file = "\(Self.slug(name)).oqproc" + if process.resolvingSymlinksInPath() != folder.appendingPathComponent(file) { + try data.write(to: folder.appendingPathComponent(file), options: .atomic) + } + saved.process = file + } else { + try? FileManager.default.removeItem(at: folder.appendingPathComponent("\(Self.slug(name)).oqproc")) + } + if saved.created.isEmpty { saved.created = ISO8601DateFormatter().string(from: Date()) } + try saved.encode().write(to: url(name), options: .atomic) + return saved + } + + /// Remove a setup and its copy of the process curve. + public func delete(_ setup: NegativeSetup) throws { + try FileManager.default.removeItem(at: url(setup.name)) + if let curve = processURL(setup) { try? FileManager.default.removeItem(at: curve) } + } +} diff --git a/swift/OpenQuadCore/Tests/OpenQuadCoreTests/SetupTests.swift b/swift/OpenQuadCore/Tests/OpenQuadCoreTests/SetupTests.swift new file mode 100644 index 0000000..a4b37a5 --- /dev/null +++ b/swift/OpenQuadCore/Tests/OpenQuadCoreTests/SetupTests.swift @@ -0,0 +1,47 @@ +// Saved negative setups: saving with a copy of the curve, listing, replacing, deleting. + +import Foundation +import Testing +@testable import OpenQuadCore + +@Suite("Negative setups") +struct SetupTests { + @Test func savesWithItsOwnCopyOfTheCurve() throws { + let folder = try temporaryFolder() + let library = SetupLibrary(folder: folder.appendingPathComponent("setups")) + #expect(library.all().isEmpty) + let curveFile = folder.appendingPathComponent("cyanotype.oqproc") + try ProcessCurve.identity(colour: "orange").encode().write(to: curveFile) + let setup = NegativeSetup(name: " Cyanotype on Pictorico ", colour: "orange", mirror: true, safeEdge: 0.3, + outline: 0.08, printer: "Epson_ET_2900", paper: "A4") + let saved = try library.save(setup, process: curveFile) + #expect(saved.name == "Cyanotype on Pictorico" && saved.process == "cyanotype-on-pictorico.oqproc" && !saved.created.isEmpty) + try FileManager.default.removeItem(at: curveFile) // the setup keeps working without the original + let listed = try #require(library.all().first) + #expect(listed == saved) + let copy = try #require(library.processURL(listed)) + #expect(try ProcessCurve.decode(Data(contentsOf: copy)).colour == "orange") + + var black = NegativeSetup(name: "Carbon", colour: "black") + black = try library.save(black, process: nil) + #expect(library.all().map(\.name) == ["Carbon", "Cyanotype on Pictorico"] && black.process == nil) + var changed = listed + changed.mirror = false + try library.save(changed, process: copy) // re-saving with its own curve + #expect(library.all().count == 2 && library.all()[1].mirror == false) + #expect(FileManager.default.fileExists(atPath: copy.path)) + try library.delete(library.all()[1]) + #expect(library.all().map(\.name) == ["Carbon"] && !FileManager.default.fileExists(atPath: copy.path)) + } + + @Test func badSetupsAreRefused() throws { + let library = SetupLibrary(folder: try temporaryFolder()) + #expect(throws: FileFormatError.self) { try library.save(NegativeSetup(name: " ", colour: "green"), process: nil) } + let good = try NegativeSetup(name: "x", colour: "green").encode() + let text = String(decoding: good, as: UTF8.self) + for (from, to) in [("\"green\"", "\"purple\""), ("\"Letter\"", "\"Tabloid\""), ("openquad-setup", "other")] { + #expect(throws: FileFormatError.self) { try NegativeSetup.decode(Data(text.replacingOccurrences(of: from, with: to).utf8)) } + } + #expect(SetupLibrary.slug("B&W / 8×10!") == "b-w-8-10") + } +} From cfd58aef634ac50d9b7e942ab201f4ff43c26b7d Mon Sep 17 00:00:00 2001 From: akendrick <548951+akendrick@users.noreply.github.com> Date: Mon, 2 Nov 2026 08:26:14 -0700 Subject: [PATCH 3/5] Contact sheets: up to 16 photos as thumbnails on one sheet MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A new window (File > New Contact Sheet…, or Make a Contact Sheet… under Photo) arranges up to 16 photos on a sheet the size of the page's printable room, portrait or landscape, on black or white, whole or cropped to fill each cell, with optional file names and a 21-step greyscale wedge. Use Sheet makes it the photo in the print window, to print as is or as a digital negative. - Python: openquad.contactsheet (exact integer box resizing), `openquad contact-sheet` - Swift core: ContactSheet, matched pixel for pixel by new vectors - App: ContactSheetModel/View, printable room from the print window, guide v11 Co-Authored-By: Claude Opus 5.5 --- CHANGELOG.md | 5 + README.md | 14 + scripts/export_swift_vectors.py | 47 +++ src/openquad/cli.py | 40 +++ src/openquad/contactsheet.py | 213 +++++++++++++ .../Sources/OpenQuad/OpenQuadApp.swift | 20 +- .../Sources/OpenQuadUI/AppModel.swift | 28 ++ .../Sources/OpenQuadUI/ContactSheetView.swift | 286 ++++++++++++++++++ .../Sources/OpenQuadUI/ContentView.swift | 19 +- .../Sources/OpenQuadUI/Guide.swift | 11 +- .../Tests/OpenQuadUITests/AppModelTests.swift | 47 +++ .../Sources/OpenQuadCore/ContactSheet.swift | 220 ++++++++++++++ .../Sources/OpenQuadCore/Photo.swift | 11 + .../ContactSheetParityTests.swift | 85 ++++++ .../Vectors/contactsheet.json | 1 + tests/test_contactsheet.py | 119 ++++++++ tests/test_swift_vectors.py | 3 +- 17 files changed, 1163 insertions(+), 6 deletions(-) create mode 100644 src/openquad/contactsheet.py create mode 100644 swift/OpenQuadApp/Sources/OpenQuadUI/ContactSheetView.swift create mode 100644 swift/OpenQuadCore/Sources/OpenQuadCore/ContactSheet.swift create mode 100644 swift/OpenQuadCore/Tests/OpenQuadCoreTests/ContactSheetParityTests.swift create mode 100644 swift/OpenQuadCore/Tests/OpenQuadCoreTests/Vectors/contactsheet.json create mode 100644 tests/test_contactsheet.py diff --git a/CHANGELOG.md b/CHANGELOG.md index 55ded76..7d44d83 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,11 @@ versions follow [Semantic Versioning](https://semver.org/). ## [Unreleased] ### Added +- Contact sheets: File > New Contact Sheet… (⇧⌘N, or Make a Contact Sheet… under Photo) arranges up + to 16 photos as thumbnails on one sheet the size of the page (inside its margins, safe edge and + outline), portrait or landscape, on black or white, each whole or cropped to fill its cell, with + optional file names and a 21-step greyscale wedge. Use Sheet makes it the photo to print, as an + inkjet print or a digital negative. Command line: `openquad contact-sheet PHOTOS... -o sheet.tif`. - Saved negative setups: Save Setup… in negative mode remembers the process curve (a copy is kept with the setup), ink colour, mirror, safe edge, black outline, printer and paper under a name such as "Cyanotype on Pictorico"; the Setup menu switches all of them at once, and shows which diff --git a/README.md b/README.md index 85c1d51..ea1598e 100644 --- a/README.md +++ b/README.md @@ -43,6 +43,8 @@ opens on first launch (and later from **Help** or the **?** button). did the goals get met? - **Digital negatives:** make a negative and try the blocking test and process calibration, if you contact print (carbon, or another UV process). +- **Contact sheets:** File > New Contact Sheet… (⇧⌘N) puts up to 16 photos on one sheet, to print + or to make a negative of. - **The guide:** is anything unclear or missing? ### Reporting problems @@ -156,6 +158,18 @@ openquad chart carbon-chart2.jpg --process carbon.oqproc -o carbon-v2.oqproc openquad negative photo.tif -o neg.tif --process carbon-v2.oqproc --fit Letter ``` +### Contact sheets + +Up to 16 photos as thumbnails on one greyscale sheet, which then prints like any photo (or becomes a +negative): + +```bash +openquad contact-sheet frames/*.tif -o sheet.tif --size 7.5x10 --wedge --labels +openquad negative sheet.tif -o sheet-neg.tif --colour green --fit Letter +``` + +`--background white`, `--crop` (fill every cell) and `--gap INCHES` change the layout. + ## Development ```bash diff --git a/scripts/export_swift_vectors.py b/scripts/export_swift_vectors.py index b46566c..23d80e0 100644 --- a/scripts/export_swift_vectors.py +++ b/scripts/export_swift_vectors.py @@ -966,6 +966,52 @@ def wizards_vectors(directory: Path) -> dict[str, Any]: } +def _sheet_photo(width: int, height: int, seed: int) -> Any: + """A made-up photo both languages build the same way.""" + y, x = np.mgrid[0:height, 0:width] + return ((x * 977 + y * 613 + seed * 4999) % 65536).astype(np.uint16) + + +def contactsheet_vectors() -> dict[str, Any]: + """Contact sheet grids, cells, resizing and whole sheets (without file names).""" + from openquad.contactsheet import SheetLayout, cells, grid, make_sheet, resize + + sample = _sheet_photo(7, 5, 3) + resizes = [] + for region, size in (((0, 0, 7, 5), (3, 2)), ((1, 1, 5, 3), (2, 2)), ((0, 0, 7, 5), (11, 8)), + ((2, 0, 3, 5), (3, 5)), ((0, 0, 7, 5), (1, 1))): # fmt: skip + resizes.append({"region": list(region), "size": list(size), + "pixels": _ints(resize(sample, region, size))}) # fmt: skip + grids = [] + grid_cases = [ + (4, 1.5, (1000, 1000), 0, 0), (3, 3.0, (300, 1000), 0, 0), (16, 1.0, (1000, 1000), 10, 0), + (7, 0.6667, (900, 600), 8, 12), (11, 1.25, (450, 600), 9, 0), + ] # fmt: skip + for count, aspect, room, gap, label in grid_cases: + found = grid(count, aspect, room, gap, label) + grids.append({"count": count, "aspect": aspect, "room": list(room), "gap": gap, + "label": label, "grid": list(found)}) # fmt: skip + sizes = [(60, 40), (40, 60), (75, 50), (30, 30), (90, 30)] + cases = [] + sheet_cases: list[tuple[list[tuple[int, int]], dict[str, Any], float]] = [ + (sizes, {"width": 3.0, "height": 4.0, "gap": 0.1}, 40.0), + (sizes, {"width": 3.0, "height": 4.0, "gap": 0.1, "background": "white", "crop": True, + "wedge": True}, 40.0), + (sizes * 3 + [(50, 70)], {"width": 7.5, "height": 10.0, "wedge": True}, 30.0), + ([(4, 3)], {"width": 2.0, "height": 2.0, "gap": 0.0}, 50.0), + (sizes[:3], {"width": 4.0, "height": 3.0, "labels": True, "gap": 0.2}, 45.0), + ] # fmt: skip + for photos, layout, dpi in sheet_cases: + sheet_layout = SheetLayout(**{**layout, "labels": False}) + boxes, wedge = cells(photos, SheetLayout(**layout), dpi) + pixels = [_sheet_photo(w, h, i) for i, (w, h) in enumerate(photos)] + cases.append({"sizes": [list(p) for p in photos], "layout": layout, "dpi": dpi, + "cells": [[b.left, b.top, b.width, b.height] for b in boxes], + "wedge": list(wedge) if wedge else None, + "sheet": _digest(make_sheet(pixels, None, sheet_layout, dpi))}) # fmt: skip + return {"sample": _ints(sample), "resizes": resizes, "grids": grids, "cases": cases} + + def export(directory: Path) -> list[Path]: directory.mkdir(parents=True, exist_ok=True) written = [] @@ -979,6 +1025,7 @@ def export(directory: Path) -> list[Path]: ("paper", paper_vectors()), ("calibration", calibration_vectors()), ("builds", builds_vectors()), + ("contactsheet", contactsheet_vectors()), ): path = directory / f"{name}.json" path.write_text(json.dumps(data, separators=(",", ":")) + "\n", encoding="utf-8") diff --git a/src/openquad/cli.py b/src/openquad/cli.py index 07d9c68..5e871e4 100644 --- a/src/openquad/cli.py +++ b/src/openquad/cli.py @@ -29,6 +29,7 @@ tone_errors, ) from openquad.composite import DEFAULT_PRESET, PRESETS, composite +from openquad.contactsheet import BACKGROUNDS, MAX_PHOTOS, SheetLayout, make_sheet from openquad.escl import INTENTS, Fetch, ScanError, ScanSettings, http_fetch, scan from openquad.greybalance import ( Calibration, @@ -172,6 +173,30 @@ def build_parser() -> argparse.ArgumentParser: help="with --fit: also keep within W x H inches, safe edge included " "(e.g. 8x10 for the tissue; turned to match the photo)") # fmt: skip + sheet = commands.add_parser("contact-sheet", help="up to 16 photos as thumbnails on one sheet") + sheet.add_argument("inputs", type=Path, nargs="+", metavar="PHOTO", help="photos (1-16)") + sheet.add_argument("-o", "--output", type=Path, required=True, help="greyscale TIFF to write") + sheet.add_argument( + "--size", + metavar="WxH", + type=_inches_pair, + default=(7.5, 10.0), + help="sheet size in inches (default 7.5x10: Letter inside 0.5 in margins)", + ) + sheet.add_argument("--dpi", type=float, default=DEFAULT_DPI, help="resolution (default 300)") + sheet.add_argument("--gap", type=float, default=0.15, help="inches between photos (0.15)") + sheet.add_argument( + "--background", + choices=BACKGROUNDS, + default="black", + help="sheet background (default black)", + ) + sheet.add_argument("--crop", action="store_true", help="crop photos to fill their cells") + sheet.add_argument( + "--wedge", action="store_true", help="a 21-step greyscale wedge at the bottom" + ) + sheet.add_argument("--labels", action="store_true", help="file names under the photos") + prt = commands.add_parser("print", help="print a TIFF through the printer's normal driver") prt.add_argument("input", type=Path, help="TIFF to print") prt.add_argument("--printer", required=True, help="CUPS printer name (see 'printers')") @@ -388,6 +413,19 @@ def _inches_pair(text: str) -> tuple[float, float]: return (width, height) +def _contact_sheet(args: argparse.Namespace) -> None: + if len(args.inputs) > MAX_PHOTOS: + raise ValueError(f"a contact sheet takes up to {MAX_PHOTOS} photos, got {len(args.inputs)}") + layout = SheetLayout( + width=args.size[0], height=args.size[1], gap=args.gap, background=args.background, + crop=args.crop, wedge=args.wedge, labels=args.labels, + ) # fmt: skip + photos = [load_photo(path).pixels for path in args.inputs] + sheet = make_sheet(photos, [path.name for path in args.inputs], layout, args.dpi) + save_grey(args.output, GreyImage(sheet, dpi=(args.dpi, args.dpi))) + print(f"wrote {args.output} ({len(photos)} photos on {args.size[0]:g} x {args.size[1]:g} in)") + + def _negative(args: argparse.Namespace) -> None: photo = load_photo(args.input) process = load_process(args.process) if args.process else None @@ -554,6 +592,8 @@ def main( _presets() elif args.command == "negative": _negative(args) + elif args.command == "contact-sheet": + _contact_sheet(args) elif args.command == "blocking": _blocking(args) elif args.command == "chart": diff --git a/src/openquad/contactsheet.py b/src/openquad/contactsheet.py new file mode 100644 index 0000000..6d30f34 --- /dev/null +++ b/src/openquad/contactsheet.py @@ -0,0 +1,213 @@ +"""Contact sheets: up to 16 photos as thumbnails on one sheet, for proofing or a +negative of them all. + +The sheet is a greyscale image (0 black .. 65535 white) the size of the printable +area, so it prints like any photo: as an inkjet print, or as a digital negative. +Thumbnails sit in an even grid on a black or white background, each either whole +(fitted inside its cell) or cropped to fill the cell, with an optional file name +under it and an optional 21-step greyscale wedge along the bottom. + +Resizing is an exact integer box average, so the Swift version gives identical +pixels. File names are drawn with each platform's own font, so they are left out of +the comparison (``labels=False`` gives identical sheets). +""" + +from __future__ import annotations + +import math +from dataclasses import dataclass + +import numpy as np +from numpy.typing import NDArray +from PIL import Image, ImageDraw, ImageFont + +from openquad.targets import wedge_levels + +MAX_VALUE = 65535 +MAX_PHOTOS = 16 +WEDGE_STEPS = 21 +BACKGROUNDS = ("black", "white") + + +@dataclass(frozen=True) +class SheetLayout: + """A contact sheet's size and options; lengths in inches.""" + + width: float = 7.5 + height: float = 10.0 + gap: float = 0.15 # between thumbnails and round the edge + background: str = "black" # or "white" + crop: bool = False # fill each cell (cropping) instead of showing whole photos + wedge: bool = False # a 21-step greyscale wedge along the bottom + labels: bool = False # the file name under each thumbnail + wedge_height: float = 0.3 + label_height: float = 0.18 + + def __post_init__(self) -> None: + if self.background not in BACKGROUNDS: + raise ValueError(f"background must be black or white, got {self.background!r}") + if not (self.width > 0 and self.height > 0): + raise ValueError("the sheet must have a positive size") + if not 0.0 <= self.gap <= 1.0: + raise ValueError(f"gap must be 0-1 in, got {self.gap}") + + +@dataclass(frozen=True) +class Cell: + """Where one photo's thumbnail goes, in pixels: its box (left, top, width, height).""" + + left: int + top: int + width: int + height: int + + +def grid(count: int, aspect: float, room: tuple[int, int], gap: int, label: int) -> tuple[int, int]: + """(columns, rows) that make thumbnails of this mean aspect (width / height) largest.""" + best, best_score = (1, count), -1.0 + for columns in range(1, count + 1): + rows = math.ceil(count / columns) + cell_w = (room[0] - gap * (columns - 1)) // columns + box_h = (room[1] - gap * (rows - 1)) // rows - label + if cell_w < 1 or box_h < 1: + continue + score = min(cell_w, box_h * aspect) * min(cell_w / aspect, box_h) + if score > best_score: + best, best_score = (columns, rows), score + return best + + +def _px(inches: float, dpi: float) -> int: + return round(inches * dpi) + + +def cells( + sizes: list[tuple[int, int]], layout: SheetLayout, dpi: float +) -> tuple[list[Cell], tuple[int, int, int, int] | None]: + """Each photo's thumbnail box, and the wedge's box (or None), for photos of these sizes.""" + if not 1 <= len(sizes) <= MAX_PHOTOS: + raise ValueError(f"a contact sheet takes 1-{MAX_PHOTOS} photos, got {len(sizes)}") + width, height, gap = _px(layout.width, dpi), _px(layout.height, dpi), _px(layout.gap, dpi) + label = _px(layout.label_height, dpi) if layout.labels else 0 + wedge_h = _px(layout.wedge_height, dpi) if layout.wedge else 0 + room_w = width - 2 * gap + room_h = height - 2 * gap - (wedge_h + gap if layout.wedge else 0) + if room_w < 1 or room_h < 1: + raise ValueError("no room for photos on a sheet this small") + aspect = sum(w / h for w, h in sizes) / len(sizes) + columns, rows = grid(len(sizes), aspect, (room_w, room_h), gap, label) + cell_w = (room_w - gap * (columns - 1)) // columns + cell_h = (room_h - gap * (rows - 1)) // rows + if cell_w < 1 or cell_h - label < 1: + raise ValueError("no room for photos on a sheet this small") + left0 = gap + (room_w - (columns * cell_w + (columns - 1) * gap)) // 2 + top0 = gap + (room_h - (rows * cell_h + (rows - 1) * gap)) // 2 + boxes = [] + for index in range(len(sizes)): + row, column = divmod(index, columns) + boxes.append( + Cell( + left0 + column * (cell_w + gap), top0 + row * (cell_h + gap), cell_w, cell_h - label + ) + ) + wedge = None + if layout.wedge: + step = room_w // WEDGE_STEPS + wedge = (gap + (room_w - step * WEDGE_STEPS) // 2, height - gap - wedge_h, step, wedge_h) + return boxes, wedge + + +def _spans(start: int, length: int, out: int) -> NDArray[np.int64]: + """The first source index of each of `out` boxes covering [start, start + length).""" + return start + (np.arange(out, dtype=np.int64) * length) // out + + +def resize( + pixels: NDArray[np.uint16], region: tuple[int, int, int, int], size: tuple[int, int] +) -> NDArray[np.uint16]: + """`region` (left, top, width, height) of a photo resized to `size` (width, height): + each output pixel is the rounded mean of the source pixels its box covers (the + nearest source pixel when enlarging).""" + left, top, region_w, region_h = region + out_w, out_h = size + xs, ys = _spans(left, region_w, out_w), _spans(top, region_h, out_h) + source = pixels[top : top + region_h, left : left + region_w].astype(np.int64) + if out_w <= region_w: + across = np.add.reduceat(source, xs - left, axis=1) + x_count = np.diff(np.append(xs, left + region_w)) + else: + across, x_count = source[:, xs - left], np.ones(out_w, dtype=np.int64) + if out_h <= region_h: + both = np.add.reduceat(across, ys - top, axis=0) + y_count = np.diff(np.append(ys, top + region_h)) + else: + both, y_count = across[ys - top, :], np.ones(out_h, dtype=np.int64) + count = y_count[:, None] * x_count[None, :] + out: NDArray[np.uint16] = ((both + count // 2) // count).astype(np.uint16) + return out + + +def thumbnail( + pixels: NDArray[np.uint16], cell: Cell, crop: bool +) -> tuple[NDArray[np.uint16], int, int]: + """The photo sized for its cell, and its (left, top) on the sheet (centred in the cell).""" + height, width = pixels.shape + if crop: # the largest centred part of the photo with the cell's shape + if width * cell.height > height * cell.width: + region_w, region_h = max(1, (height * cell.width) // cell.height), height + else: + region_w, region_h = width, max(1, (width * cell.height) // cell.width) + region = ((width - region_w) // 2, (height - region_h) // 2, region_w, region_h) + return resize(pixels, region, (cell.width, cell.height)), cell.left, cell.top + if width * cell.height > height * cell.width: # wider than the cell: width limits + out_w, out_h = cell.width, max(1, round(height * cell.width / width)) + else: + out_w, out_h = max(1, round(width * cell.height / height)), cell.height + left = cell.left + (cell.width - out_w) // 2 + top = cell.top + (cell.height - out_h) // 2 + return resize(pixels, (0, 0, width, height), (out_w, out_h)), left, top + + +def make_sheet( + photos: list[NDArray[np.uint16]], + names: list[str] | None = None, + layout: SheetLayout | None = None, + dpi: float = 300.0, +) -> NDArray[np.uint16]: + """The contact sheet at `dpi`, greyscale (0 black .. 65535 white).""" + layout = layout or SheetLayout() + if any(photo.ndim != 2 for photo in photos): + raise ValueError("photos must be greyscale") + boxes, wedge = cells([(p.shape[1], p.shape[0]) for p in photos], layout, dpi) + fill = 0 if layout.background == "black" else MAX_VALUE + sheet = np.full((_px(layout.height, dpi), _px(layout.width, dpi)), fill, dtype=np.uint16) + for photo, cell in zip(photos, boxes, strict=True): + thumb, left, top = thumbnail(photo, cell, layout.crop) + sheet[top : top + thumb.shape[0], left : left + thumb.shape[1]] = thumb + if wedge: + left, top, step, wedge_h = wedge + for index, level in enumerate(wedge_levels(WEDGE_STEPS)[::-1]): # black to white + sheet[top : top + wedge_h, left + index * step : left + (index + 1) * step] = level + if layout.labels and names: + _draw_labels(sheet, names, boxes, layout, dpi) + return sheet + + +def _draw_labels( + sheet: NDArray[np.uint16], names: list[str], boxes: list[Cell], layout: SheetLayout, dpi: float +) -> None: + """File names under the thumbnails, in white on black (black on white).""" + mask = Image.new("L", (sheet.shape[1], sheet.shape[0]), 0) + draw = ImageDraw.Draw(mask) + font = ImageFont.load_default(size=max(6, round(layout.label_height * dpi * 0.6))) + for name, cell in zip(names, boxes, strict=False): + text = name + while text and draw.textlength(text, font=font) > cell.width: + text = text[:-1] + if text != name and len(text) > 1: + text = text[:-1] + "…" + draw.text( + (cell.left, cell.top + cell.height + round(0.03 * dpi)), text, fill=255, font=font + ) + covered = np.asarray(mask) > 127 + sheet[covered] = MAX_VALUE if layout.background == "black" else 0 diff --git a/swift/OpenQuadApp/Sources/OpenQuad/OpenQuadApp.swift b/swift/OpenQuadApp/Sources/OpenQuad/OpenQuadApp.swift index f9fe9f7..45dd83a 100644 --- a/swift/OpenQuadApp/Sources/OpenQuad/OpenQuadApp.swift +++ b/swift/OpenQuadApp/Sources/OpenQuad/OpenQuadApp.swift @@ -3,7 +3,9 @@ // OpenQuad the app // OpenQuad --snapshot out.png [--photo PHOTO] [--negative] [--printer CUPS_QUEUE] [--max-size WxH] // [--outline INCHES] [--units in|mm] [--setups FOLDER] [--setup NAME] -// OpenQuad --snapshot out.png --wizard calibration|process|blocking|guide [--scan SCAN] [--run RUN] +// OpenQuad --snapshot out.png --wizard calibration|process|blocking|guide|contact-sheet [--scan SCAN] [--run RUN] +// [--photos P1,P2,...] [--landscape] [--white] [--wedge] [--labels] [--crop] +// (contact-sheet) // [--mixtures] (blocking: the ink-mixture chart) // draw the window to a PNG and quit (for checks) // OpenQuad --scan-test HOST RESULT scan once from the app (with its own network @@ -54,7 +56,10 @@ struct OpenQuadApp: App { SettingsView(model: model) } .commands { - CommandGroup(replacing: .newItem) {} + CommandGroup(replacing: .newItem) { + Button("New Contact Sheet…") { NotificationCenter.default.post(name: ContentView.contactSheetNotification, object: nil) } + .keyboardShortcut("n", modifiers: [.command, .shift]) + } CommandGroup(replacing: .help) { Button("How to Use OpenQuad") { NotificationCenter.default.post(name: GuideView.showNotification, object: nil) } .keyboardShortcut("?") @@ -134,6 +139,17 @@ enum Snapshot { return AnyView(BlockingTestView(model: test) { _ in }) case "guide": return AnyView(GuideView()) + case "contact-sheet": + let sheet = ContactSheetModel(room: (7.5, 10), folder: folder) + if arguments.contains("--landscape") { sheet.setLandscape(true) } + sheet.update { + $0.background = arguments.contains("--white") ? .white : .black + $0.wedge = arguments.contains("--wedge") + $0.labels = arguments.contains("--labels") + $0.crop = arguments.contains("--crop") + } + sheet.add((value("--photos") ?? "").split(separator: ",").map { URL(fileURLWithPath: String($0)) }) + return AnyView(ContactSheetView(model: sheet) { _ in }) default: return nil } diff --git a/swift/OpenQuadApp/Sources/OpenQuadUI/AppModel.swift b/swift/OpenQuadApp/Sources/OpenQuadUI/AppModel.swift index 3281905..e2a12b2 100644 --- a/swift/OpenQuadApp/Sources/OpenQuadUI/AppModel.swift +++ b/swift/OpenQuadApp/Sources/OpenQuadUI/AppModel.swift @@ -214,6 +214,34 @@ public final class AppModel { refreshPreview() } + // MARK: contact sheets + + /// The printable room (width, height) in inches: the page inside its margins, less the + /// safe edge and outline for a negative, and within a set size if one is on. + public var printableRoom: (Double, Double) { + let (paperW, paperH) = Paper.sizes[session.paper] ?? (8.5, 11) + let border = session.negative ? session.safeEdge + session.outline : 0 + var width = paperW - 2 * session.margin - 2 * border, height = paperH - 2 * session.margin - 2 * border + if session.fit, let box = session.maxSize { + let (short, long) = (min(box.0, box.1) - 2 * border, max(box.0, box.1) - 2 * border) + (width, height) = (min(width, short), min(height, long)) + } + return (max(width, 0.5), max(height, 0.5)) + } + + /// Where made contact sheets are kept. + public var contactSheetFolder: URL { settingsURL.deletingLastPathComponent().appendingPathComponent("contact-sheets") } + + public func contactSheet() -> ContactSheetModel { + ContactSheetModel(room: printableRoom, units: units, folder: contactSheetFolder) + } + + /// Print a made sheet: it becomes the photo, fitted to the page it was made for. + public func useContactSheet(_ url: URL) { + openPhoto(url) + setFit(true) + } + // MARK: saved negative setups /// The saved setup the negative settings match right now, if any. diff --git a/swift/OpenQuadApp/Sources/OpenQuadUI/ContactSheetView.swift b/swift/OpenQuadApp/Sources/OpenQuadUI/ContactSheetView.swift new file mode 100644 index 0000000..7e63f31 --- /dev/null +++ b/swift/OpenQuadApp/Sources/OpenQuadUI/ContactSheetView.swift @@ -0,0 +1,286 @@ +// The contact sheet window: choose up to 16 photos, arrange them as thumbnails on one +// sheet (black or white, whole or cropped, with names and a greyscale wedge if wanted), +// then use the sheet as the photo to print, as an inkjet print or a digital negative. + +import AppKit +import OpenQuadCore +import SwiftUI +import UniformTypeIdentifiers + +@MainActor +@Observable +public final class ContactSheetModel { + public struct Entry: Identifiable { + public let id = UUID() + public let url: URL + /// Greyscale, shrunk to at most `longestSide` pixels (plenty for a thumbnail). + public let photo: Photo + } + + nonisolated static let longestSide = 2400 + + public private(set) var entries: [Entry] = [] + public var layout = SheetLayout() + public var landscape = false + public var busy = false + public var error: String? + public private(set) var preview: CGImage? + /// The printable room (width, height) in inches, portrait, from the print window. + public let room: (Double, Double) + public let units: LengthUnit + let folder: URL + private var previewToken = 0 + + public init(room: (Double, Double), units: LengthUnit = .inches, folder: URL) { + self.room = (min(room.0, room.1), max(room.0, room.1)) + self.units = units + self.folder = folder + applySize() + } + + /// The sheet's size in inches, turned for landscape. + public var size: (Double, Double) { landscape ? (room.1, room.0) : room } + + func applySize() { + (layout.width, layout.height) = size + refresh() + } + + public func setLandscape(_ on: Bool) { + landscape = on + applySize() + } + + public func update(_ change: (inout SheetLayout) -> Void) { + change(&layout) + refresh() + } + + public var canAdd: Bool { entries.count < ContactSheet.maxPhotos } + + /// Add photos (up to 16 in all), in the background. + public func add(_ urls: [URL]) { + let room = ContactSheet.maxPhotos - entries.count + let chosen = Array(urls.prefix(room)) + if urls.count > room { error = "A contact sheet takes up to \(ContactSheet.maxPhotos) photos; the rest were left out." } + guard !chosen.isEmpty else { return } + busy = true + Task { + let loaded = await Task.detached(priority: .userInitiated) { + chosen.map { url in Result { (url, try Self.shrunk(Photos.load(url))) } } + }.value + busy = false + for result in loaded { + switch result { + case .success(let (url, photo)): entries.append(Entry(url: url, photo: photo)) + case .failure(let failure): error = "Couldn't open a photo: \(failure)" + } + } + refresh() + } + } + + nonisolated static func shrunk(_ photo: Photo) -> Photo { + let long = max(photo.width, photo.height) + guard long > longestSide else { return photo } + let width = max(1, photo.width * longestSide / long), height = max(1, photo.height * longestSide / long) + var small = photo + small.pixels = ContactSheet.resize(photo.pixels, photoWidth: photo.width, region: (0, 0, photo.width, photo.height), + size: (width, height)) + (small.width, small.height) = (width, height) + return small + } + + public func remove(_ entry: Entry) { + entries.removeAll { $0.id == entry.id } + refresh() + } + + public func move(from source: IndexSet, to destination: Int) { + entries.move(fromOffsets: source, toOffset: destination) + refresh() + } + + var photos: [([UInt16], Int, Int)] { entries.map { ($0.photo.pixels, $0.photo.width, $0.photo.height) } } + var names: [String] { entries.map(\.url.lastPathComponent) } + + /// Redraw the preview (at screen resolution, off the main thread). + func refresh() { + previewToken += 1 + let token = previewToken, photos = photos, names = names, layout = layout + guard !photos.isEmpty else { + preview = nil + return + } + let dpi = 900 / max(layout.width, layout.height) + Task { + let sheet = await Task.detached(priority: .userInitiated) { + try? ContactSheet.make(photos, names: names, layout: layout, dpi: dpi) + }.value + guard token == previewToken else { return } + preview = sheet.flatMap { Self.greyImage($0.pixels, width: $0.width, height: $0.height) } + if sheet == nil { error = "No room for these photos on a sheet this small." } + } + } + + nonisolated static func greyImage(_ pixels: [UInt16], width: Int, height: Int) -> CGImage? { + guard let provider = CGDataProvider(data: Data(pixels.map { UInt8($0 >> 8) }) as CFData) else { return nil } + return CGImage(width: width, height: height, bitsPerComponent: 8, bitsPerPixel: 8, bytesPerRow: width, + space: CGColorSpaceCreateDeviceGray(), bitmapInfo: CGBitmapInfo(rawValue: CGImageAlphaInfo.none.rawValue), + provider: provider, decode: nil, shouldInterpolate: true, intent: .defaultIntent) + } + + /// Make the full sheet at 300 ppi, save it as a 16-bit TIFF in OpenQuad's contact + /// sheets folder, and hand its file to `done`. + public func make(dpi: Double = 300, done: @escaping (URL) -> Void) { + let photos = photos, names = names, layout = layout, landscape = landscape + let format = DateFormatter() + format.dateFormat = "yyyy-MM-dd-HHmmss" + let url = folder.appendingPathComponent("contact-sheet-\(format.string(from: Date())).tif") + busy = true + error = nil + Task { + let result = await Task.detached(priority: .userInitiated) { + Result { + var sheet = try ContactSheet.make(photos, names: names, layout: layout, dpi: dpi) + if landscape { // turned to stand up on the portrait page, like any landscape print + sheet = (ContactSheet.turnedLeft(sheet.pixels, width: sheet.width, height: sheet.height), + sheet.height, sheet.width) + } + try FileManager.default.createDirectory(at: url.deletingLastPathComponent(), withIntermediateDirectories: true) + try ImageFiles.saveGrey(url, GreyImage(width: sheet.width, height: sheet.height, pixels: sheet.pixels, + dpi: (dpi, dpi))) + return url + } + }.value + busy = false + switch result { + case .success(let url): done(url) + case .failure(let failure): error = "Couldn't make the sheet: \(failure)" + } + } + } +} + +public struct ContactSheetView: View { + @Bindable var model: ContactSheetModel + let use: (URL) -> Void + let close: () -> Void + + public init(model: ContactSheetModel, use: @escaping (URL) -> Void, close: @escaping () -> Void = {}) { + self.model = model + self.use = use + self.close = close + } + + public var body: some View { + HSplitView { + controls + .frame(minWidth: 320, idealWidth: 360, maxWidth: 440) + ZStack { + Color(nsColor: .underPageBackgroundColor) + if let image = model.preview { + Image(decorative: image, scale: 1) + .resizable() + .interpolation(.high) + .aspectRatio(contentMode: .fit) + .shadow(radius: 4) + .padding(24) + } else { + ContentUnavailableView("Add photos to begin", systemImage: "square.grid.3x3", + description: Text("Up to \(ContactSheet.maxPhotos) photos, arranged on one sheet.")) + } + } + .frame(minWidth: 360) + .dropDestination(for: URL.self) { urls, _ in + model.add(urls) + return true + } + } + .background(Color(nsColor: .windowBackgroundColor)) + } + + private var controls: some View { + VStack(spacing: 0) { + Form { + Section("Photos (\(model.entries.count) of \(ContactSheet.maxPhotos))") { + Button("Add Photos…", action: addPhotos) + .disabled(!model.canAdd || model.busy) + List { + ForEach(model.entries) { entry in + HStack { + Text(entry.url.lastPathComponent).lineLimit(1).truncationMode(.middle) + Spacer() + Button { + model.remove(entry) + } label: { + Image(systemName: "minus.circle") + } + .buttonStyle(.borderless) + .help("Remove from the sheet") + } + } + .onMove { model.move(from: $0, to: $1) } + } + .frame(minHeight: 120, maxHeight: 220) + Text("Drag to reorder, or drop photos on the sheet.") + .font(.caption) + .foregroundStyle(.secondary) + } + Section("Sheet") { + Picker("Orientation", selection: Binding(get: { model.landscape }, set: { model.setLandscape($0) })) { + Text("Portrait").tag(false) + Text("Landscape").tag(true) + } + .pickerStyle(.segmented) + LabeledContent("Size", value: "\(model.units.size(model.size.0, model.size.1))") + Picker("Background", selection: Binding(get: { model.layout.background }, + set: { value in model.update { $0.background = value } })) { + Text("Black").tag(SheetLayout.Background.black) + Text("White").tag(SheetLayout.Background.white) + } + .pickerStyle(.segmented) + Toggle("Crop photos to fill their cells", isOn: Binding(get: { model.layout.crop }, + set: { value in model.update { $0.crop = value } })) + Toggle("File names", isOn: Binding(get: { model.layout.labels }, + set: { value in model.update { $0.labels = value } })) + Toggle("Greyscale step wedge", isOn: Binding(get: { model.layout.wedge }, + set: { value in model.update { $0.wedge = value } })) + LengthStepper(title: "Space between", inches: model.layout.gap, range: 0...1, inchStep: 0.05, mmStep: 1, + units: model.units) { value in model.update { $0.gap = value } } + Text("The sheet fills the print window's page, inside its margins (and the safe edge and outline, for " + + "a negative); a landscape sheet is turned to fit. Use it there as a print or a digital negative.") + .font(.caption) + .foregroundStyle(.secondary) + .fixedSize(horizontal: false, vertical: true) + } + if let error = model.error { + Text(error).foregroundStyle(.red) + } + } + .formStyle(.grouped) + Divider() + HStack { + if model.busy { ProgressView().controlSize(.small) } + Spacer() + Button("Cancel", action: close) + Button("Use Sheet") { + model.make { url in + use(url) + close() + } + } + .keyboardShortcut(.defaultAction) + .disabled(model.entries.isEmpty || model.busy) + } + .padding() + } + } + + private func addPhotos() { + let panel = NSOpenPanel() + panel.allowedContentTypes = [.image] + panel.allowsMultipleSelection = true + if panel.runModal() == .OK { model.add(panel.urls) } + } +} diff --git a/swift/OpenQuadApp/Sources/OpenQuadUI/ContentView.swift b/swift/OpenQuadApp/Sources/OpenQuadUI/ContentView.swift index 2268343..9d61d31 100644 --- a/swift/OpenQuadApp/Sources/OpenQuadUI/ContentView.swift +++ b/swift/OpenQuadApp/Sources/OpenQuadUI/ContentView.swift @@ -55,6 +55,7 @@ public struct ContentView: View { } } .onReceive(NotificationCenter.default.publisher(for: GuideView.showNotification)) { _ in showGuide = true } + .onReceive(NotificationCenter.default.publisher(for: ContentView.contactSheetNotification)) { _ in openContactSheet() } .onAppear { model.loadPrinters() if guideOnLaunch && guideSeen < GuideView.version { showGuide = true } // first launch: walk through the app @@ -67,8 +68,11 @@ public struct ContentView: View { VStack(spacing: 0) { Form { Section("Photo") { - Button("Open Photo…", action: openPhoto) - .keyboardShortcut("o") + HStack { + Button("Open Photo…", action: openPhoto) + .keyboardShortcut("o") + Button("Make a Contact Sheet…", action: openContactSheet) + } Text(model.photoDescription) .font(.callout) .foregroundStyle(.secondary) @@ -272,6 +276,17 @@ public struct ContentView: View { // MARK: actions + /// Posted by File > New Contact Sheet…. + public static let contactSheetNotification = Notification.Name("OpenQuadContactSheet") + + private func openContactSheet() { + let sheet = model.contactSheet(), app = model + WizardWindows.show("contact-sheet", title: "Contact Sheet", size: CGSize(width: 1000, height: 760), + minSize: CGSize(width: 760, height: 520)) { close in + ContactSheetView(model: sheet, use: { app.useContactSheet($0) }, close: close) + } + } + private func openCalibrationWizard() { let wizard = model.calibrationWizard(), app = model WizardWindows.show("calibrate-printer", title: "Calibrate a Printer", size: CGSize(width: 980, height: 820), diff --git a/swift/OpenQuadApp/Sources/OpenQuadUI/Guide.swift b/swift/OpenQuadApp/Sources/OpenQuadUI/Guide.swift index f32f3ec..38e4897 100644 --- a/swift/OpenQuadApp/Sources/OpenQuadUI/Guide.swift +++ b/swift/OpenQuadApp/Sources/OpenQuadUI/Guide.swift @@ -5,7 +5,7 @@ import SwiftUI public struct GuideView: View { /// Raise when the guide changes enough to show it again on launch. - public static let version = 10 + public static let version = 11 public static let showNotification = Notification.Name("OpenQuadShowGuide") struct Page { @@ -65,6 +65,15 @@ public struct GuideView: View { "Tissue smaller than the page? Under Page, set Fit within to A set size (e.g. 8 × 10 in): " + "that becomes the negative's outer edge, safe edge included, and the photo shrinks to fit.", "Print on transparency film at 100% with your usual film settings."]), + Page(symbol: "square.grid.3x3", title: "Contact sheets", + text: "File > New Contact Sheet… (⇧⌘N) puts up to 16 photos on one sheet, to proof them or to make one " + + "negative of them all.", + steps: ["Add Photos… (or drop them on the sheet); drag the list to change the order.", + "Choose portrait or landscape, a black or white background, whole photos or cropped to fill, " + + "file names, and a greyscale step wedge to check the print's tones.", + "The sheet fills the page you chose in the print window (for a negative, inside its safe edge " + + "and outline). Set the page and output first.", + "Use Sheet makes it the photo in the print window: print it, or print it as a negative."]), Page(symbol: "square.grid.3x3.square", title: "Find the best blocking colour", text: "Find the Best Blocking Colour… (in negative mode) prints a sheet of every negative colour.", steps: ["Choose the chart: Standard (six colours) or Ink mixtures (ten colours your printer makes " diff --git a/swift/OpenQuadApp/Tests/OpenQuadUITests/AppModelTests.swift b/swift/OpenQuadApp/Tests/OpenQuadUITests/AppModelTests.swift index 85d1b3b..1937098 100644 --- a/swift/OpenQuadApp/Tests/OpenQuadUITests/AppModelTests.swift +++ b/swift/OpenQuadApp/Tests/OpenQuadUITests/AppModelTests.swift @@ -142,6 +142,53 @@ struct AppModelTests { #expect(again.setups.map(\.name) == ["Carbon black"]) } + @Test func contactSheetFillsThePrintableRoomAndBecomesThePhoto() async throws { + let m = model() + #expect(m.printableRoom == (7.5, 10)) // Letter inside 0.5 in margins + m.setMode(.negative) + m.setSafeEdge(0.25) + #expect(m.printableRoom == (7, 9.5)) + m.setMaxSize((4, 5)) + #expect(m.printableRoom == (3.5, 4.5)) // the tissue, less the safe edge + m.setMaxSize(nil) + + let sheet = m.contactSheet() + #expect(sheet.size == (7, 9.5) && sheet.entries.isEmpty && sheet.preview == nil) + sheet.setLandscape(true) + #expect(sheet.size == (9.5, 7) && sheet.layout.width == 9.5) + let urls = (0..<3).map { folder.appendingPathComponent("p\($0).tif") } + for (i, url) in urls.enumerated() { + try ImageFiles.saveGrey(url, GreyImage(width: 30 + 10 * i, height: 20, pixels: Array(repeating: UInt16(20000 * i), count: (30 + 10 * i) * 20))) + } + sheet.add(urls + [folder.appendingPathComponent("missing.tif")]) + for _ in 0..<300 where sheet.busy || sheet.preview == nil { try await Task.sleep(for: .milliseconds(10)) } + #expect(sheet.entries.map(\.url.lastPathComponent) == ["p0.tif", "p1.tif", "p2.tif"] && sheet.error != nil) + #expect(sheet.preview != nil) + sheet.move(from: [2], to: 0) + #expect(sheet.entries.first?.url.lastPathComponent == "p2.tif") + sheet.remove(sheet.entries[1]) + #expect(sheet.entries.count == 2) + sheet.add(Array(repeating: urls[0], count: 20)) // only 14 more fit + for _ in 0..<300 where sheet.busy { try await Task.sleep(for: .milliseconds(10)) } + #expect(sheet.entries.count == 16 && !sheet.canAdd) + + var made: URL? + sheet.make(dpi: 20) { made = $0 } + for _ in 0..<300 where made == nil { try await Task.sleep(for: .milliseconds(10)) } + let url = try #require(made) + #expect(url.deletingLastPathComponent() == m.contactSheetFolder && url.lastPathComponent.hasPrefix("contact-sheet-")) + m.useContactSheet(url) + #expect(m.session.photo?.width == 140 && m.session.photo?.height == 190 && m.session.fit) // turned to stand up + let (width, height) = try m.session.sizeInches() // fills the room, plus the safe edge + #expect(abs(width - 7.5) < 1e-9 && abs(height - 10) < 1e-9) + } + + @Test func bigPhotosAreShrunkForTheSheet() { + let big = Photo(width: 4800, height: 100, pixels: Array(repeating: 1000, count: 4800 * 100), dpi: nil) + let small = ContactSheetModel.shrunk(big) + #expect(small.width == 2400 && small.height == 50 && small.pixels.count == 2400 * 50 && small.pixels[0] == 1000) + } + @Test func negativesAndErrors() throws { let m = model() m.openPhoto(photo) diff --git a/swift/OpenQuadCore/Sources/OpenQuadCore/ContactSheet.swift b/swift/OpenQuadCore/Sources/OpenQuadCore/ContactSheet.swift new file mode 100644 index 0000000..340ff62 --- /dev/null +++ b/swift/OpenQuadCore/Sources/OpenQuadCore/ContactSheet.swift @@ -0,0 +1,220 @@ +// Contact sheets: up to 16 photos as thumbnails on one sheet. Mirrors +// openquad/contactsheet.py. The sheet is a greyscale image the size of the printable +// area, so it prints like any photo (an inkjet print or a digital negative). Resizing is +// an exact integer box average, so the pixels match Python's; file names are drawn with +// the system font (Python uses Pillow's), so `labels: false` gives the identical sheet. + +import CoreText +import Foundation + +public struct SheetLayout: Sendable, Equatable { + public enum Background: String, CaseIterable, Sendable { + case black, white + } + + /// Inches. + public var width: Double + public var height: Double + /// Inches between thumbnails and round the edge. + public var gap: Double + public var background: Background + /// Fill each cell (cropping) instead of showing whole photos. + public var crop: Bool + /// A 21-step greyscale wedge along the bottom. + public var wedge: Bool + /// The file name under each thumbnail. + public var labels: Bool + public var wedgeHeight = 0.3 + public var labelHeight = 0.18 + + public init(width: Double = 7.5, height: Double = 10, gap: Double = 0.15, background: Background = .black, + crop: Bool = false, wedge: Bool = false, labels: Bool = false) { + self.width = width + self.height = height + self.gap = gap + self.background = background + self.crop = crop + self.wedge = wedge + self.labels = labels + } +} + +public struct SheetCell: Sendable, Equatable { + public let left: Int + public let top: Int + public let width: Int + public let height: Int +} + +public struct ContactSheetError: Error, Equatable, CustomStringConvertible { + public let description: String +} + +public enum ContactSheet { + public static let maxPhotos = 16 + public static let wedgeSteps = 21 + + /// (columns, rows) that make thumbnails of this mean aspect (width / height) largest. + public static func grid(count: Int, aspect: Double, room: (Int, Int), gap: Int, label: Int) -> (Int, Int) { + var best = (1, count), bestScore = -1.0 + for columns in 1...max(1, count) { + let rows = (count + columns - 1) / columns + let cellW = (room.0 - gap * (columns - 1)) / columns + let boxH = (room.1 - gap * (rows - 1)) / rows - label + if cellW < 1 || boxH < 1 { continue } + let score = min(Double(cellW), Double(boxH) * aspect) * min(Double(cellW) / aspect, Double(boxH)) + if score > bestScore { (best, bestScore) = ((columns, rows), score) } + } + return best + } + + static func px(_ inches: Double, _ dpi: Double) -> Int { pyRound(inches * dpi) } + + /// Each photo's thumbnail box, and the wedge's (left, top, step width, height), for + /// photos of these (width, height) sizes. + public static func cells(sizes: [(Int, Int)], layout: SheetLayout, dpi: Double) throws + -> ([SheetCell], (Int, Int, Int, Int)?) { + guard (1...maxPhotos).contains(sizes.count) else { + throw ContactSheetError(description: "a contact sheet takes 1-\(maxPhotos) photos, got \(sizes.count)") + } + let width = px(layout.width, dpi), height = px(layout.height, dpi), gap = px(layout.gap, dpi) + let label = layout.labels ? px(layout.labelHeight, dpi) : 0 + let wedgeH = layout.wedge ? px(layout.wedgeHeight, dpi) : 0 + let roomW = width - 2 * gap + let roomH = height - 2 * gap - (layout.wedge ? wedgeH + gap : 0) + let noRoom = ContactSheetError(description: "no room for photos on a sheet this small") + guard roomW >= 1, roomH >= 1 else { throw noRoom } + let aspect = sizes.reduce(0.0) { $0 + Double($1.0) / Double($1.1) } / Double(sizes.count) + let (columns, rows) = grid(count: sizes.count, aspect: aspect, room: (roomW, roomH), gap: gap, label: label) + let cellW = (roomW - gap * (columns - 1)) / columns + let cellH = (roomH - gap * (rows - 1)) / rows + guard cellW >= 1, cellH - label >= 1 else { throw noRoom } + let left0 = gap + (roomW - (columns * cellW + (columns - 1) * gap)) / 2 + let top0 = gap + (roomH - (rows * cellH + (rows - 1) * gap)) / 2 + let boxes = sizes.indices.map { index in + let (row, column) = index.quotientAndRemainder(dividingBy: columns) + return SheetCell(left: left0 + column * (cellW + gap), top: top0 + row * (cellH + gap), + width: cellW, height: cellH - label) + } + var wedge: (Int, Int, Int, Int)? + if layout.wedge { + let step = roomW / wedgeSteps + wedge = (gap + (roomW - step * wedgeSteps) / 2, height - gap - wedgeH, step, wedgeH) + } + return (boxes, wedge) + } + + /// `region` (left, top, width, height) of a photo (`photoWidth` wide) resized to `size`: + /// each output pixel is the rounded mean of the source pixels its box covers (the + /// nearest source pixel when enlarging). + public static func resize(_ pixels: [UInt16], photoWidth: Int, region: (Int, Int, Int, Int), + size: (Int, Int)) -> [UInt16] { + let (left, top, regionW, regionH) = region + let (outW, outH) = size + func spans(_ start: Int, _ length: Int, _ out: Int) -> [(Int, Int)] { + (0..= out ? (a, start + (i + 1) * length / out) : (a, a + 1) + } + } + let xs = spans(left, regionW, outW), ys = spans(top, regionH, outH) + // Sums across each output column's box, row by row (exact integers). + var across = [Int](repeating: 0, count: regionH * outW) + for y in 0.. ([UInt16], Int, Int, Int, Int) { + if crop { // the largest centred part of the photo with the cell's shape + let (regionW, regionH) = width * cell.height > height * cell.width + ? (max(1, height * cell.width / cell.height), height) : (width, max(1, width * cell.height / cell.width)) + let region = ((width - regionW) / 2, (height - regionH) / 2, regionW, regionH) + return (resize(pixels, photoWidth: width, region: region, size: (cell.width, cell.height)), + cell.width, cell.height, cell.left, cell.top) + } + let (outW, outH) = width * cell.height > height * cell.width + ? (cell.width, max(1, pyRound(Double(height * cell.width) / Double(width)))) + : (max(1, pyRound(Double(width * cell.height) / Double(height))), cell.height) + return (resize(pixels, photoWidth: width, region: (0, 0, width, height), size: (outW, outH)), outW, outH, + cell.left + (cell.width - outW) / 2, cell.top + (cell.height - outH) / 2) + } + + /// The contact sheet at `dpi`: greyscale (0 black .. 65535 white), row-major, with its + /// (width, height) in pixels. `photos` are (pixels, width, height). + public static func make(_ photos: [([UInt16], Int, Int)], names: [String] = [], layout: SheetLayout = SheetLayout(), + dpi: Double = 300) throws -> (pixels: [UInt16], width: Int, height: Int) { + let (boxes, wedge) = try cells(sizes: photos.map { ($0.1, $0.2) }, layout: layout, dpi: dpi) + let width = px(layout.width, dpi), height = px(layout.height, dpi) + let fill = UInt16(layout.background == .black ? 0 : maxValue) + var sheet = [UInt16](repeating: fill, count: width * height) + for ((pixels, w, h), cell) in zip(photos, boxes) { + let (thumb, tw, th, left, top) = thumbnail(pixels, width: w, height: h, cell: cell, crop: layout.crop) + for y in 0.. [UInt16] { + var out = [UInt16](repeating: 0, count: pixels.count) // height wide, width tall + for y in 0.. String { + let font = CTFontCreateWithName("Helvetica" as CFString, size, nil) + func measure(_ s: String) -> Double { + let line = CTLineCreateWithAttributedString(NSAttributedString(string: s, attributes: [ + NSAttributedString.Key(kCTFontAttributeName as String): font, + ])) + return CTLineGetTypographicBounds(line, nil, nil, nil) + } + var shown = text + while !shown.isEmpty && measure(shown) > width { shown.removeLast() } + if shown != text && shown.count > 1 { shown = String(shown.dropLast()) + "…" } + return shown + } +} diff --git a/swift/OpenQuadCore/Sources/OpenQuadCore/Photo.swift b/swift/OpenQuadCore/Sources/OpenQuadCore/Photo.swift index 42e945b..304fb3f 100644 --- a/swift/OpenQuadCore/Sources/OpenQuadCore/Photo.swift +++ b/swift/OpenQuadCore/Sources/OpenQuadCore/Photo.swift @@ -19,6 +19,17 @@ public struct Photo: Sendable { public var cropped = false public var size: (width: Int, height: Int) { (width, height) } + + public init(width: Int, height: Int, pixels: [UInt16], dpi: (Double, Double)? = nil, converted: Bool = false, + cropped: Bool = false) { + precondition(pixels.count == width * height, "pixels must be width x height") + self.width = width + self.height = height + self.pixels = pixels + self.dpi = dpi + self.converted = converted + self.cropped = cropped + } } public enum Photos { diff --git a/swift/OpenQuadCore/Tests/OpenQuadCoreTests/ContactSheetParityTests.swift b/swift/OpenQuadCore/Tests/OpenQuadCoreTests/ContactSheetParityTests.swift new file mode 100644 index 0000000..ba5c463 --- /dev/null +++ b/swift/OpenQuadCore/Tests/OpenQuadCoreTests/ContactSheetParityTests.swift @@ -0,0 +1,85 @@ +// Contact sheets matched against openquad/contactsheet.py: grids, cells, resizing and +// whole sheets (without file names, which each side draws with its own font). + +import CryptoKit +import Foundation +import Testing +@testable import OpenQuadCore + +/// The made-up photo export_swift_vectors.py builds the same way. +func sheetPhoto(_ width: Int, _ height: Int, _ seed: Int) -> [UInt16] { + var pixels = [UInt16](repeating: 0, count: width * height) + for y in 0.. String { + let bytes = pixels.flatMap { [UInt8($0 & 0xff), UInt8($0 >> 8)] } + return SHA256.hash(data: Data(bytes)).map { String(format: "%02x", $0) }.joined() +} + +@Suite("Contact sheet parity") +struct ContactSheetParityTests { + @Test func resizingMatches() throws { + let v = try vectors("contactsheet") + let sample = sheetPhoto(7, 5, 3) + #expect(sample.map(Int.init) == (v["sample"] as! [NSNumber]).map(\.intValue)) + for r in v["resizes"] as! [[String: Any]] { + let region = (r["region"] as! [NSNumber]).map(\.intValue), size = (r["size"] as! [NSNumber]).map(\.intValue) + let out = ContactSheet.resize(sample, photoWidth: 7, region: (region[0], region[1], region[2], region[3]), + size: (size[0], size[1])) + #expect(out.map(Int.init) == (r["pixels"] as! [NSNumber]).map(\.intValue), "\(region) -> \(size)") + } + } + + @Test func gridsMatch() throws { + for g in try vectors("contactsheet")["grids"] as! [[String: Any]] { + let room = (g["room"] as! [NSNumber]).map(\.intValue) + let found = ContactSheet.grid(count: (g["count"] as! NSNumber).intValue, aspect: (g["aspect"] as! NSNumber).doubleValue, + room: (room[0], room[1]), gap: (g["gap"] as! NSNumber).intValue, + label: (g["label"] as! NSNumber).intValue) + #expect([found.0, found.1] == (g["grid"] as! [NSNumber]).map(\.intValue)) + } + } + + @Test func sheetsMatch() throws { + let cases = try vectors("contactsheet")["cases"] as! [[String: Any]] + #expect(cases.count == 5) + for c in cases { + let sizes = (c["sizes"] as! [[NSNumber]]).map { ($0[0].intValue, $0[1].intValue) } + let l = c["layout"] as! [String: Any] + var layout = SheetLayout(width: (l["width"] as! NSNumber).doubleValue, height: (l["height"] as! NSNumber).doubleValue) + if let gap = l["gap"] as? NSNumber { layout.gap = gap.doubleValue } + if let background = l["background"] as? String { layout.background = SheetLayout.Background(rawValue: background)! } + layout.crop = l["crop"] as? Bool ?? false + layout.wedge = l["wedge"] as? Bool ?? false + layout.labels = l["labels"] as? Bool ?? false + let dpi = (c["dpi"] as! NSNumber).doubleValue + let (boxes, wedge) = try ContactSheet.cells(sizes: sizes, layout: layout, dpi: dpi) + #expect(boxes.map { [$0.left, $0.top, $0.width, $0.height] } == (c["cells"] as! [[NSNumber]]).map { $0.map(\.intValue) }) + let expectedWedge = (c["wedge"] as? [NSNumber])?.map(\.intValue) + #expect(wedge.map { [$0.0, $0.1, $0.2, $0.3] } == expectedWedge) + layout.labels = false + let photos = sizes.enumerated().map { i, size in (sheetPhoto(size.0, size.1, i), size.0, size.1) } + let sheet = try ContactSheet.make(photos, layout: layout, dpi: dpi) + let digest = c["sheet"] as! [String: Any] + #expect([sheet.height, sheet.width] == (digest["shape"] as! [NSNumber]).map(\.intValue)) + #expect(sha256(sheet.pixels) == digest["sha256"] as? String) + } + } + + @Test func labelsTooManyPhotosAndNoRoom() throws { + let photo = (sheetPhoto(30, 20, 0), 30, 20) + let named = try ContactSheet.make([photo], names: ["frame-01.tif"], layout: SheetLayout(width: 3, height: 3, labels: true), + dpi: 100) + #expect(named.pixels.contains(65535)) + #expect(ContactSheet.turnedLeft([1, 2, 3, 4, 5, 6], width: 3, height: 2) == [3, 6, 2, 5, 1, 4]) + #expect(ContactSheet.fitted(String(repeating: "x", count: 200), width: 50, size: 10).hasSuffix("…")) + #expect(throws: ContactSheetError.self) { try ContactSheet.make(Array(repeating: photo, count: 17)) } + #expect(throws: ContactSheetError.self) { + try ContactSheet.make([photo], layout: SheetLayout(width: 0.2, height: 0.2, gap: 0.1), dpi: 100) + } + } +} diff --git a/swift/OpenQuadCore/Tests/OpenQuadCoreTests/Vectors/contactsheet.json b/swift/OpenQuadCore/Tests/OpenQuadCoreTests/Vectors/contactsheet.json new file mode 100644 index 0000000..4753b95 --- /dev/null +++ b/swift/OpenQuadCore/Tests/OpenQuadCoreTests/Vectors/contactsheet.json @@ -0,0 +1 @@ +{"sample":[14997,15974,16951,17928,18905,19882,20859,15610,16587,17564,18541,19518,20495,21472,16223,17200,18177,19154,20131,21108,22085,16836,17813,18790,19767,20744,21721,22698,17449,18426,19403,20380,21357,22334,23311],"resizes":[{"region":[0,0,7,5],"size":[3,2],"pixels":[15792,17746,20189,17325,19279,21721]},{"region":[1,1,5,3],"size":[2,2],"pixels":[17076,19518,17995,20438]},{"region":[0,0,7,5],"size":[11,8],"pixels":[14997,14997,15974,15974,16951,17928,17928,18905,19882,19882,20859,14997,14997,15974,15974,16951,17928,17928,18905,19882,19882,20859,15610,15610,16587,16587,17564,18541,18541,19518,20495,20495,21472,15610,15610,16587,16587,17564,18541,18541,19518,20495,20495,21472,16223,16223,17200,17200,18177,19154,19154,20131,21108,21108,22085,16836,16836,17813,17813,18790,19767,19767,20744,21721,21721,22698,16836,16836,17813,17813,18790,19767,19767,20744,21721,21721,22698,17449,17449,18426,18426,19403,20380,20380,21357,22334,22334,23311]},{"region":[2,0,3,5],"size":[3,5],"pixels":[16951,17928,18905,17564,18541,19518,18177,19154,20131,18790,19767,20744,19403,20380,21357]},{"region":[0,0,7,5],"size":[1,1],"pixels":[19154]}],"grids":[{"count":4,"aspect":1.5,"room":[1000,1000],"gap":0,"label":0,"grid":[2,2]},{"count":3,"aspect":3.0,"room":[300,1000],"gap":0,"label":0,"grid":[1,3]},{"count":16,"aspect":1.0,"room":[1000,1000],"gap":10,"label":0,"grid":[4,4]},{"count":7,"aspect":0.6667,"room":[900,600],"gap":8,"label":12,"grid":[4,2]},{"count":11,"aspect":1.25,"room":[450,600],"gap":9,"label":0,"grid":[3,4]}],"cases":[{"sizes":[[60,40],[40,60],[75,50],[30,30],[90,30]],"layout":{"width":3.0,"height":4.0,"gap":0.1},"dpi":40.0,"cells":[[4,4,54,48],[62,4,54,48],[4,56,54,48],[62,56,54,48],[4,108,54,48]],"wedge":null,"sheet":{"shape":[160,120],"sha256":"14d6ed947ee510878a1e3411a65327b29e962b7c64828472a20808c35a62aeab"}},{"sizes":[[60,40],[40,60],[75,50],[30,30],[90,30]],"layout":{"width":3.0,"height":4.0,"gap":0.1,"background":"white","crop":true,"wedge":true},"dpi":40.0,"cells":[[4,5,54,42],[62,5,54,42],[4,51,54,42],[62,51,54,42],[4,97,54,42]],"wedge":[7,144,5,12],"sheet":{"shape":[160,120],"sha256":"6495482f74f9575c4f9958972a751bd96aed4084a21e933dcbf23832bbbec095"}},{"sizes":[[60,40],[40,60],[75,50],[30,30],[90,30],[60,40],[40,60],[75,50],[30,30],[90,30],[60,40],[40,60],[75,50],[30,30],[90,30],[50,70]],"layout":{"width":7.5,"height":10.0,"wedge":true},"dpi":30.0,"cells":[[5,4,69,43],[78,4,69,43],[151,4,69,43],[5,51,69,43],[78,51,69,43],[151,51,69,43],[5,98,69,43],[78,98,69,43],[151,98,69,43],[5,145,69,43],[78,145,69,43],[151,145,69,43],[5,192,69,43],[78,192,69,43],[151,192,69,43],[5,239,69,43]],"wedge":[7,287,10,9],"sheet":{"shape":[300,225],"sha256":"ce50fa647989801dde91c8c253c226297c607cbb960938f9f316bed5b389c9a8"}},{"sizes":[[4,3]],"layout":{"width":2.0,"height":2.0,"gap":0.0},"dpi":50.0,"cells":[[0,0,100,100]],"wedge":null,"sheet":{"shape":[100,100],"sha256":"276a7d7b96bf6552aaca9b5a4a8be38d196a367cc8b169021d9501a8ce665be8"}},{"sizes":[[60,40],[40,60],[75,50]],"layout":{"width":4.0,"height":3.0,"labels":true,"gap":0.2},"dpi":45.0,"cells":[[9,9,76,46],[94,9,76,46],[9,72,76,46]],"wedge":null,"sheet":{"shape":[135,180],"sha256":"335ce94c5a59dec4f6348952703c0cac5092f42303b8b264627b4b61e70e92a3"}}]} diff --git a/tests/test_contactsheet.py b/tests/test_contactsheet.py new file mode 100644 index 0000000..2a5d4ce --- /dev/null +++ b/tests/test_contactsheet.py @@ -0,0 +1,119 @@ +from pathlib import Path + +import numpy as np +import pytest +import tifffile + +from openquad.cli import main +from openquad.contactsheet import ( + MAX_PHOTOS, + Cell, + SheetLayout, + cells, + grid, + make_sheet, + resize, + thumbnail, +) +from openquad.imageio import read_dpi + + +def photo(width: int, height: int, value: int = 30000) -> np.ndarray: + return np.full((height, width), value, dtype=np.uint16) + + +def test_resize_is_an_exact_box_average() -> None: + a = (np.arange(12, dtype=np.uint16) * 1000).reshape(3, 4) + assert resize(a, (0, 0, 4, 3), (2, 1)).tolist() == [[4500, 6500]] + assert resize(a, (1, 1, 2, 2), (1, 1)).tolist() == [[7500]] # a region + assert resize(a, (0, 0, 4, 3), (8, 6))[0].tolist() == [0, 0, 1000, 1000, 2000, 2000, 3000, 3000] + assert np.array_equal(resize(a, (0, 0, 4, 3), (4, 3)), a) + + +def test_grid_suits_the_photos_shape() -> None: + assert grid(4, 1.5, (1000, 1000), 0, 0) == (2, 2) + assert grid(3, 3.0, (300, 1000), 0, 0) == (1, 3) # wide photos stack on a tall sheet + assert grid(16, 1.0, (1000, 1000), 10, 0) == (4, 4) + + +def test_cells_fill_the_sheet_inside_the_gap() -> None: + layout = SheetLayout(width=4.0, height=4.0, gap=0.1) + boxes, wedge = cells([(30, 20)] * 4, layout, dpi=100) + assert wedge is None and len(boxes) == 4 + assert boxes[0] == Cell(10, 10, 185, 185) and boxes[3] == Cell(205, 205, 185, 185) + boxes, wedge = cells( + [(30, 20)] * 4, SheetLayout(width=4.0, height=4.0, gap=0.1, wedge=True), 100 + ) + assert wedge is not None and wedge[1] + wedge[3] == 390 # along the bottom, inside the gap + assert max(b.top + b.height for b in boxes) <= wedge[1] - 10 + with pytest.raises(ValueError, match="1-16 photos"): + cells([(10, 10)] * (MAX_PHOTOS + 1), layout, 100) + with pytest.raises(ValueError, match="no room"): + cells([(10, 10)], SheetLayout(width=0.2, height=0.2, gap=0.1), 100) + + +def test_thumbnails_fit_whole_or_crop_to_fill() -> None: + wide = photo(300, 100) + cell = Cell(0, 0, 100, 100) + whole, left, top = thumbnail(wide, cell, crop=False) + assert whole.shape == (33, 100) and (left, top) == (0, 33) + filled, left, top = thumbnail(wide, cell, crop=True) + assert filled.shape == (100, 100) and (left, top) == (0, 0) + + +def test_sheet_background_wedge_and_photos() -> None: + layout = SheetLayout(width=3.0, height=4.0, gap=0.1, wedge=True) + sheet = make_sheet([photo(30, 20, 40000), photo(20, 30, 20000)], layout=layout, dpi=50) + assert sheet.shape == (200, 150) and sheet[0, 0] == 0 # black background + assert {40000, 20000} <= set(np.unique(sheet).tolist()) + _, wedge = cells([(30, 20), (20, 30)], layout, 50) + assert wedge is not None + left, top, step, _ = wedge + assert sheet[top, left] == 0 and sheet[top, left + 20 * step] == 65535 # black to white + white = make_sheet( + [photo(30, 20)], layout=SheetLayout(width=3.0, height=4.0, background="white"), dpi=50 + ) + assert white[0, 0] == 65535 + + +def test_labels_are_drawn_in_the_opposite_tone() -> None: + layout = SheetLayout(width=3.0, height=3.0, labels=True) + plain = make_sheet([photo(30, 20)], ["a.tif"], SheetLayout(width=3.0, height=3.0), dpi=100) + named = make_sheet([photo(30, 20)], ["frame-01.tif"], layout, dpi=100) + assert np.any(named == 65535) and not np.any(plain == 65535) + long_name = make_sheet( + [photo(30, 20)] * 16, ["x" * 200] * 16, layout, dpi=100 + ) # trimmed to fit + assert long_name.shape == (300, 300) + + +@pytest.mark.parametrize( + ("kwargs", "message"), + [({"background": "grey"}, "background"), ({"width": 0.0}, "positive"), ({"gap": 2.0}, "gap")], +) +def test_layout_is_checked(kwargs: dict[str, object], message: str) -> None: + with pytest.raises(ValueError, match=message): + SheetLayout(**kwargs) # type: ignore[arg-type] + + +def test_needs_greyscale() -> None: + with pytest.raises(ValueError, match="greyscale"): + make_sheet([np.zeros((4, 4, 3), dtype=np.uint16)]) + + +def test_contact_sheet_command(tmp_path: Path, capsys: pytest.CaptureFixture[str]) -> None: + paths = [] + for i in range(3): + path = tmp_path / f"p{i}.tif" + tifffile.imwrite(path, photo(60, 40, 10000 * (i + 1))) + paths.append(str(path)) + out = tmp_path / "sheet.tif" + args = ["contact-sheet", *paths, "-o", str(out), "--size", "4x5", "--dpi", "100"] + assert main([*args, "--background", "white", "--wedge", "--crop"]) == 0 + sheet = tifffile.imread(out) + assert sheet.shape == (500, 400) and sheet[0, 0] == 65535 + assert read_dpi(out) == pytest.approx((100.0, 100.0)) + assert "3 photos" in capsys.readouterr().out + with pytest.raises(SystemExit): + main([*args[:-4], "-o", str(out), "--size", "big"]) + assert main(["contact-sheet", *([paths[0]] * 17), "-o", str(out)]) == 1 diff --git a/tests/test_swift_vectors.py b/tests/test_swift_vectors.py index 6bd9867..693bb68 100644 --- a/tests/test_swift_vectors.py +++ b/tests/test_swift_vectors.py @@ -66,6 +66,7 @@ def test_main_writes_all_files(tmp_path: Path, capsys) -> None: # type: ignore[ "chart-tilted.png", "colour.json", "composite.json", + "contactsheet.json", "curves.json", "devices.json", "grey16-cm.tif", @@ -95,4 +96,4 @@ def test_main_writes_all_files(tmp_path: Path, capsys) -> None: # type: ignore[ "wedge-single.png", "wizards.json", ] - assert capsys.readouterr().out.count("wrote") == 38 + assert capsys.readouterr().out.count("wrote") == 39 From 8c784270921d1bc9ac43b0492c0f348b2aaeed41 Mon Sep 17 00:00:00 2001 From: akendrick <548951+akendrick@users.noreply.github.com> Date: Mon, 2 Nov 2026 09:04:10 -0700 Subject: [PATCH 4/5] Guide test: count the new Contact sheets page Co-Authored-By: Claude Opus 5.5 --- swift/OpenQuadApp/Tests/OpenQuadUITests/GapsTests.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/swift/OpenQuadApp/Tests/OpenQuadUITests/GapsTests.swift b/swift/OpenQuadApp/Tests/OpenQuadUITests/GapsTests.swift index 7d5dbfc..389006c 100644 --- a/swift/OpenQuadApp/Tests/OpenQuadUITests/GapsTests.swift +++ b/swift/OpenQuadApp/Tests/OpenQuadUITests/GapsTests.swift @@ -62,9 +62,9 @@ struct GapsTests { @Test func guideCoversEveryPart() { let titles = GuideView.pages.map(\.title) - #expect(titles.count == 7 && titles.first == "Welcome to OpenQuad") - for part in ["Print a photo", "Calibrate your printer", "Digital negatives", "Find the best blocking colour", - "Calibrate the process"] { + #expect(titles.count == 8 && titles.first == "Welcome to OpenQuad") + for part in ["Print a photo", "Calibrate your printer", "Digital negatives", "Contact sheets", + "Find the best blocking colour", "Calibrate the process"] { #expect(titles.contains(part)) } #expect(GuideView.pages.allSatisfy { !$0.steps.isEmpty }) From 1c40c1936603492b5d5bade72542e63e338f915a Mon Sep 17 00:00:00 2001 From: akendrick <548951+akendrick@users.noreply.github.com> Date: Mon, 2 Nov 2026 09:11:18 -0700 Subject: [PATCH 5/5] Tabbed window and a contact sheet progress bar MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit One window with five toolbar tabs (⌘1–⌘5): Print, Negative, Contact Sheet, Printer Calibration and Process Calibration. Each keeps its own work; Print and Negative each remember their own photo, printer and paper. Finished calibrations, blocking colours, process curves and contact sheets hand off to the tab that uses them. On quit, OpenQuad asks whether to keep open work for next time, and reopens on the last tab. Contact sheets load photos one at a time behind a progress bar with an estimate of the time left. Co-Authored-By: Claude Opus 5.5 --- CHANGELOG.md | 15 +- README.md | 6 +- src/openquad/settings.py | 3 + .../Sources/OpenQuad/OpenQuadApp.swift | 83 ++-- .../Sources/OpenQuadUI/AppModel.swift | 62 ++- .../Sources/OpenQuadUI/BlockingTest.swift | 9 +- .../Sources/OpenQuadUI/ContactSheetView.swift | 153 ++++++-- .../Sources/OpenQuadUI/ContentView.swift | 96 ++--- .../Sources/OpenQuadUI/Guide.swift | 67 ++-- .../Sources/OpenQuadUI/Lengths.swift | 6 +- .../OpenQuadApp/Sources/OpenQuadUI/Tabs.swift | 368 ++++++++++++++++++ .../Sources/OpenQuadUI/Wizards.swift | 18 +- .../Tests/OpenQuadUITests/GapsTests.swift | 9 +- .../Tests/OpenQuadUITests/TabsTests.swift | 149 +++++++ .../Sources/OpenQuadCore/Session.swift | 6 + .../SessionParityTests.swift | 2 + tests/test_settings.py | 5 +- 17 files changed, 846 insertions(+), 211 deletions(-) create mode 100644 swift/OpenQuadApp/Sources/OpenQuadUI/Tabs.swift create mode 100644 swift/OpenQuadApp/Tests/OpenQuadUITests/TabsTests.swift diff --git a/CHANGELOG.md b/CHANGELOG.md index 7d44d83..2e3cfa8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,11 +6,20 @@ versions follow [Semantic Versioning](https://semver.org/). ## [Unreleased] ### Added -- Contact sheets: File > New Contact Sheet… (⇧⌘N, or Make a Contact Sheet… under Photo) arranges up +- Tabs: the Mac app is one window with five tabs along the toolbar (⌘1–⌘5): Print, Negative, + Contact Sheet, Printer Calibration and Process Calibration (blocking colour, then process curve). + Each tab keeps its own work, so one printer can be calibrating while another prints; the Print + and Negative tabs each remember their own photo, printer and paper. A finished calibration, + blocking colour or process curve offers to go straight to the tab that uses it, and a contact + sheet goes to Print It or Make a Negative. On quitting, OpenQuad asks whether to keep the open + photos and contact sheet for next time; it reopens on the last tab used. +- Contact sheets show a progress bar while photos open, with each photo's name and an estimate of + the time left. +- Contact sheets: the Contact Sheet tab (⇧⌘N) arranges up to 16 photos as thumbnails on one sheet the size of the page (inside its margins, safe edge and outline), portrait or landscape, on black or white, each whole or cropped to fill its cell, with - optional file names and a 21-step greyscale wedge. Use Sheet makes it the photo to print, as an - inkjet print or a digital negative. Command line: `openquad contact-sheet PHOTOS... -o sheet.tif`. + optional file names and a 21-step greyscale wedge. Print It or Make a Negative sends it to that + tab. Command line: `openquad contact-sheet PHOTOS... -o sheet.tif`. - Saved negative setups: Save Setup… in negative mode remembers the process curve (a copy is kept with the setup), ink colour, mirror, safe edge, black outline, printer and paper under a name such as "Cyanotype on Pictorico"; the Setup menu switches all of them at once, and shows which diff --git a/README.md b/README.md index ea1598e..07b500b 100644 --- a/README.md +++ b/README.md @@ -43,8 +43,10 @@ opens on first launch (and later from **Help** or the **?** button). did the goals get met? - **Digital negatives:** make a negative and try the blocking test and process calibration, if you contact print (carbon, or another UV process). -- **Contact sheets:** File > New Contact Sheet… (⇧⌘N) puts up to 16 photos on one sheet, to print - or to make a negative of. +- **Contact sheets:** the Contact Sheet tab (⌘3) puts up to 16 photos on one sheet, to print or + to make a negative of. +- **Tabs:** Print, Negative, Contact Sheet, Printer Calibration and Process Calibration each keep + their own work. Does moving between them while working feel natural? - **The guide:** is anything unclear or missing? ### Reporting problems diff --git a/src/openquad/settings.py b/src/openquad/settings.py index 014d1de..70f91ab 100644 --- a/src/openquad/settings.py +++ b/src/openquad/settings.py @@ -38,6 +38,9 @@ class Settings: negative_colour: str = "green" max_size: list[float] | None = None # fit within (width, height) inches, e.g. the tissue units: str = "in" # lengths shown in the app: "in" or "mm" + # The Mac app's Negative tab keeps its own printer and paper (None: as above). + negative_printer: str | None = None + negative_paper: str | None = None @classmethod def load(cls, path: Path | None = None) -> Settings: diff --git a/swift/OpenQuadApp/Sources/OpenQuad/OpenQuadApp.swift b/swift/OpenQuadApp/Sources/OpenQuad/OpenQuadApp.swift index 45dd83a..175167e 100644 --- a/swift/OpenQuadApp/Sources/OpenQuad/OpenQuadApp.swift +++ b/swift/OpenQuadApp/Sources/OpenQuad/OpenQuadApp.swift @@ -1,7 +1,8 @@ // OpenQuad for macOS. // // OpenQuad the app -// OpenQuad --snapshot out.png [--photo PHOTO] [--negative] [--printer CUPS_QUEUE] [--max-size WxH] +// OpenQuad --snapshot out.png [--tab print|negative|contact-sheet|printer-calibration|process-calibration] +// [--photo PHOTO] [--negative] [--printer CUPS_QUEUE] [--max-size WxH] [--notice TEXT] // [--outline INCHES] [--units in|mm] [--setups FOLDER] [--setup NAME] // OpenQuad --snapshot out.png --wizard calibration|process|blocking|guide|contact-sheet [--scan SCAN] [--run RUN] // [--photos P1,P2,...] [--landscape] [--white] [--wedge] [--labels] [--crop] @@ -34,32 +35,47 @@ final class AppDelegate: NSObject, NSApplicationDelegate { } func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { true } + + /// Offer to keep the open photos for next time. + func applicationShouldTerminate(_ sender: NSApplication) -> NSApplication.TerminateReply { + MainActor.assumeIsolated { (OpenQuadApp.root?.confirmQuit() ?? true) ? .terminateNow : .terminateCancel } + } } @main struct OpenQuadApp: App { @NSApplicationDelegateAdaptor(AppDelegate.self) private var delegate - @State private var model = Snapshot.model() + @State private var root = Snapshot.root() + /// For the app delegate's quit question. + @MainActor static var root: AppRoot? init() { // Options like "--negative --max-size 4x5" would otherwise leave "4x5" looking like a // file to open, and then the print window doesn't open at launch. UserDefaults.standard.register(defaults: ["NSTreatUnknownArgumentsAsOpen": "NO"]) + Self.root = root } var body: some Scene { Window("OpenQuad (Beta)", id: "print") { - Snapshot.content(model) + Snapshot.content(root) } .defaultSize(width: 1100, height: 720) Settings { - SettingsView(model: model) + SettingsView(root: root) } .commands { CommandGroup(replacing: .newItem) { - Button("New Contact Sheet…") { NotificationCenter.default.post(name: ContentView.contactSheetNotification, object: nil) } + Button("New Contact Sheet…") { root.show(.contactSheet) } .keyboardShortcut("n", modifiers: [.command, .shift]) } + CommandGroup(before: .toolbar) { + ForEach(AppTab.allCases) { tab in + Button(tab.title) { root.show(tab) } + .keyboardShortcut(tab.shortcut, modifiers: .command) + } + Divider() + } CommandGroup(replacing: .help) { Button("How to Use OpenQuad") { NotificationCenter.default.post(name: GuideView.showNotification, object: nil) } .keyboardShortcut("?") @@ -78,33 +94,51 @@ enum Snapshot { return arguments[i + 1] } - static func model() -> AppModel { - guard value("--snapshot") != nil else { return AppModel() } + static func root() -> AppRoot { + guard value("--snapshot") != nil else { return AppRoot() } // A throwaway settings file, so snapshots never change the user's settings. - let settings = FileManager.default.temporaryDirectory.appendingPathComponent("openquad-snapshot-settings.json") - try? FileManager.default.removeItem(at: settings) + let folder = FileManager.default.temporaryDirectory.appendingPathComponent("openquad-snapshot") + try? FileManager.default.removeItem(at: folder) + let negative = arguments.contains("--negative") + let tab = value("--tab").flatMap(AppTab.init(rawValue:)) ?? (negative ? .negative : .print) // The real calibrations, so the snapshot shows what this Mac has. - let model = AppModel(settingsURL: settings, libraryFolder: AppSettings.dataDirectory().appendingPathComponent("calibrations"), - setupsFolder: value("--setups").map { URL(fileURLWithPath: $0) } - ?? AppSettings.dataDirectory().appendingPathComponent("setups")) + let root = AppRoot(settingsURL: folder.appendingPathComponent("settings.json"), + libraryFolder: AppSettings.dataDirectory().appendingPathComponent("calibrations"), + setupsFolder: value("--setups").map { URL(fileURLWithPath: $0) } + ?? AppSettings.dataDirectory().appendingPathComponent("setups"), + tab: tab, restoreWorkspace: false) + root.askOnQuit = false + let model = tab == .negative ? root.negativeModel : root.printModel + if let units = value("--units").flatMap(LengthUnit.init(rawValue:)) { root.setUnits(units) } if let photo = value("--photo") { model.openPhoto(URL(fileURLWithPath: photo)) } - if arguments.contains("--negative") { model.setMode(.negative) } if let printer = value("--printer") { model.setPrinter(printer) } if let name = value("--setup"), let setup = model.setups.first(where: { $0.name == name }) { model.applySetup(setup) } if let size = value("--max-size")?.lowercased().split(separator: "x").compactMap({ Double($0) }), size.count == 2 { model.setMaxSize((size[0], size[1])) } - if let units = value("--units").flatMap(LengthUnit.init(rawValue:)) { model.setUnits(units) } if let outline = value("--outline").flatMap(Double.init) { model.setOutlineSize(outline) model.setOutline(true) } - return model + if let notice = value("--notice") { root.notice = notice } + if tab == .contactSheet { fillSheet(root.contactSheet) } + return root + } + + static func fillSheet(_ sheet: ContactSheetModel) { + if arguments.contains("--landscape") { sheet.setLandscape(true) } + sheet.update { + $0.background = arguments.contains("--white") ? .white : .black + $0.wedge = arguments.contains("--wedge") + $0.labels = arguments.contains("--labels") + $0.crop = arguments.contains("--crop") + } + sheet.add((value("--photos") ?? "").split(separator: ",").map { URL(fileURLWithPath: String($0)) }) } /// The print window, or (for a snapshot) one of the wizards, filled in from a scan. - static func content(_ model: AppModel) -> AnyView { - wizard ?? AnyView(ContentView(model: model, guideOnLaunch: value("--snapshot") == nil)) + static func content(_ root: AppRoot) -> AnyView { + wizard ?? AnyView(RootView(root: root, guideOnLaunch: value("--snapshot") == nil)) } /// Built once: the scene's body is evaluated again on every change. @@ -141,15 +175,8 @@ enum Snapshot { return AnyView(GuideView()) case "contact-sheet": let sheet = ContactSheetModel(room: (7.5, 10), folder: folder) - if arguments.contains("--landscape") { sheet.setLandscape(true) } - sheet.update { - $0.background = arguments.contains("--white") ? .white : .black - $0.wedge = arguments.contains("--wedge") - $0.labels = arguments.contains("--labels") - $0.crop = arguments.contains("--crop") - } - sheet.add((value("--photos") ?? "").split(separator: ",").map { URL(fileURLWithPath: String($0)) }) - return AnyView(ContactSheetView(model: sheet) { _ in }) + fillSheet(sheet) + return AnyView(ContactSheetView(model: sheet) { _, _ in }) default: return nil } @@ -159,7 +186,9 @@ enum Snapshot { guard let output = value("--snapshot") else { return } let wait = Double(value("--wait") ?? "") ?? (value("--wizard") == nil ? 2.5 : 8.0) // a wizard reads its scan DispatchQueue.main.asyncAfter(deadline: .now() + wait) { - guard let view = NSApp.windows.first(where: { $0.isVisible })?.contentView, + // The frame view, so the toolbar (the tab bar) is in the picture too. + guard let content = NSApp.windows.first(where: { $0.isVisible })?.contentView, + let view = Optional(content.superview ?? content), let rep = view.bitmapImageRepForCachingDisplay(in: view.bounds) else { let windows = NSApp.windows.map { "\($0.title) visible=\($0.isVisible) frame=\($0.frame)" } FileHandle.standardError.write(Data("no window to snapshot; windows: \(windows)\n".utf8)) diff --git a/swift/OpenQuadApp/Sources/OpenQuadUI/AppModel.swift b/swift/OpenQuadApp/Sources/OpenQuadUI/AppModel.swift index e2a12b2..8da0e71 100644 --- a/swift/OpenQuadApp/Sources/OpenQuadUI/AppModel.swift +++ b/swift/OpenQuadApp/Sources/OpenQuadUI/AppModel.swift @@ -16,9 +16,16 @@ public let presetLabels: [(String, String)] = [ public let paperOrder = ["Letter", "Legal", "A4", "A5", "4x6", "5x7", "8x10"] +/// Which tab a model serves: the Print tab or the Negative tab. Each keeps its own photo, +/// printer and paper; the rest of the settings are shared. +public enum TabRole: Sendable { + case print, negative +} + @MainActor @Observable public final class AppModel { + public let role: TabRole public private(set) var session = PrintSession() public private(set) var settings: AppSettings public private(set) var preview: CGImage? @@ -26,6 +33,8 @@ public final class AppModel { public var error: String? /// The last thing that happened (e.g. a print job sent), for the status line. public var status: String? + /// A new process curve is in use: offer to save it as a setup (Negative tab). + public var setupOffer: String? /// CUPS printers on this Mac, for printing without the print panel. public private(set) var printers: [String] = [] /// Saved calibrations to choose from: the newest of each printer and paper. @@ -37,7 +46,9 @@ public final class AppModel { let settingsURL: URL private var previewToken = 0 - public init(settingsURL: URL = AppSettings.defaultURL(), libraryFolder: URL? = nil, setupsFolder: URL? = nil) { + public init(settingsURL: URL = AppSettings.defaultURL(), libraryFolder: URL? = nil, setupsFolder: URL? = nil, + role: TabRole = .print) { + self.role = role self.settingsURL = settingsURL library = CalibrationLibrary(folder: libraryFolder ?? settingsURL.deletingLastPathComponent().appendingPathComponent("calibrations")) @@ -47,6 +58,14 @@ public final class AppModel { settings = AppSettings.load(settingsURL) restore() refreshLibrary() + session.setMode(role == .negative ? .negative : .print) + } + + /// Change the settings file: re-read it first, as the other tab may have changed it. + private func saveSettings(_ change: (inout AppSettings) -> Void) { + settings = AppSettings.load(settingsURL) + change(&settings) + try? settings.save(settingsURL) } /// Re-read the calibrations folder (after a wizard or an import). @@ -104,7 +123,7 @@ public final class AppModel { } private func restore() { - try? session.setPaper(settings.paper) + try? session.setPaper(role == .negative ? settings.negativePaper ?? settings.paper : settings.paper) if let path = settings.calibration, FileManager.default.fileExists(atPath: path) { try? session.setCalibration(URL(fileURLWithPath: path)) } @@ -113,7 +132,7 @@ public final class AppModel { } else { try? session.setNegativeColour(settings.negativeColour) } - session.printer = settings.printer + session.printer = role == .negative ? settings.negativePrinter ?? settings.printer : settings.printer if let size = settings.maxSize, size.count == 2 { session.maxSize = (size[0], size[1]) } session.units = settings.units } @@ -122,18 +141,26 @@ public final class AppModel { public var units: LengthUnit { settings.units } public func setUnits(_ units: LengthUnit) { - settings.units = units session.units = units - try? settings.save(settingsURL) + saveSettings { $0.units = units } } + /// Take up the unit the other tab chose. + public func followUnits() { session.units = AppSettings.load(settingsURL).units } + private func remember() { - settings.paper = session.paper - settings.calibration = session.calibrationPath?.path - settings.process = session.processPath?.path - settings.negativeColour = session.negativeColour - settings.lastFolder = session.source?.deletingLastPathComponent().path ?? settings.lastFolder - try? settings.save(settingsURL) + let session = session + saveSettings { settings in + if session.negative { + settings.negativePaper = session.paper + settings.process = session.processPath?.path + settings.negativeColour = session.negativeColour + } else { + settings.paper = session.paper + settings.calibration = session.calibrationPath?.path + } + settings.lastFolder = session.source?.deletingLastPathComponent().path ?? settings.lastFolder + } } private func attempt(_ work: () throws -> Void) { @@ -314,8 +341,8 @@ public final class AppModel { /// A CUPS printer to print to directly, or nil to choose in the macOS print panel. public func setPrinter(_ name: String?) { session.printer = name - settings.printer = name - try? settings.save(settingsURL) + let negative = role == .negative + saveSettings { if negative { $0.negativePrinter = name } else { $0.printer = name } } matchCalibration() } @@ -329,8 +356,7 @@ public final class AppModel { public func setMaxSize(_ size: (Double, Double)?) { if let size, !(size.0 > 0 && size.1 > 0) { return } session.maxSize = size - settings.maxSize = size.map { [$0.0, $0.1] } - try? settings.save(settingsURL) + saveSettings { $0.maxSize = size.map { [$0.0, $0.1] } } refreshPreview() } @@ -354,7 +380,7 @@ public final class AppModel { /// Make negatives in the colour the blocking test found best. public func useBlockingColour(_ colour: String, scannerHost: String) { - if !scannerHost.isEmpty { settings.scannerHost = scannerHost } + if !scannerHost.isEmpty { saveSettings { $0.scannerHost = scannerHost } } session.setMode(.negative) if let process = session.process, process.colour != colour { error = "The process curve is for \(process.colour) negatives; clear it to use \(colour)." @@ -379,13 +405,13 @@ public final class AppModel { } public func finishCalibration(_ path: URL, scannerHost: String) { - if !scannerHost.isEmpty { settings.scannerHost = scannerHost } + if !scannerHost.isEmpty { saveSettings { $0.scannerHost = scannerHost } } setCalibration(path) if let entry = currentCalibration { status = "Using \(entry.label)." } } public func finishProcess(_ path: URL, scannerHost: String) { - if !scannerHost.isEmpty { settings.scannerHost = scannerHost } + if !scannerHost.isEmpty { saveSettings { $0.scannerHost = scannerHost } } setProcess(path) } diff --git a/swift/OpenQuadApp/Sources/OpenQuadUI/BlockingTest.swift b/swift/OpenQuadApp/Sources/OpenQuadUI/BlockingTest.swift index d27cea6..a2fee36 100644 --- a/swift/OpenQuadApp/Sources/OpenQuadUI/BlockingTest.swift +++ b/swift/OpenQuadApp/Sources/OpenQuadUI/BlockingTest.swift @@ -105,10 +105,11 @@ struct BlockingChart: View { public struct BlockingTestView: View { @Bindable var model: BlockingTestModel let use: (String) -> Void - let close: () -> Void + /// Closes the window it is in; nil inside a tab (no Close button). + let close: (() -> Void)? @State private var resultView = 0 - public init(model: BlockingTestModel, use: @escaping (String) -> Void, close: @escaping () -> Void = {}) { + public init(model: BlockingTestModel, use: @escaping (String) -> Void, close: (() -> Void)? = nil) { self.model = model self.use = use self.close = close @@ -173,10 +174,10 @@ public struct BlockingTestView: View { if let error = model.error { Text(error).foregroundStyle(.red) } HStack { Spacer() - Button("Close", action: close) + if let close { Button("Close", action: close) } Button(model.best.map { "Use \($0.capitalized) for Negatives" } ?? "Use the Best Colour") { if let best = model.best { use(best) } - close() + close?() } .buttonStyle(.borderedProminent) .disabled(model.best == nil) diff --git a/swift/OpenQuadApp/Sources/OpenQuadUI/ContactSheetView.swift b/swift/OpenQuadApp/Sources/OpenQuadUI/ContactSheetView.swift index 7e63f31..0e92c5e 100644 --- a/swift/OpenQuadApp/Sources/OpenQuadUI/ContactSheetView.swift +++ b/swift/OpenQuadApp/Sources/OpenQuadUI/ContactSheetView.swift @@ -25,21 +25,40 @@ public final class ContactSheetModel { public var busy = false public var error: String? public private(set) var preview: CGImage? - /// The printable room (width, height) in inches, portrait, from the print window. - public let room: (Double, Double) - public let units: LengthUnit + /// The printable room (width, height) in inches, portrait: the Print tab's page. + public private(set) var room: (Double, Double) + /// The Negative tab's room (inside its safe edge and outline), if different. + public private(set) var negativeRoom: (Double, Double)? let folder: URL private var previewToken = 0 + public var units: LengthUnit + + static func portrait(_ room: (Double, Double)) -> (Double, Double) { (min(room.0, room.1), max(room.0, room.1)) } + public init(room: (Double, Double), units: LengthUnit = .inches, folder: URL) { - self.room = (min(room.0, room.1), max(room.0, room.1)) + self.room = Self.portrait(room) self.units = units self.folder = folder applySize() } /// The sheet's size in inches, turned for landscape. - public var size: (Double, Double) { landscape ? (room.1, room.0) : room } + public var size: (Double, Double) { size(for: .print) } + + /// The sheet's size for the Print or Negative tab's page. + public func size(for role: TabRole) -> (Double, Double) { + let room = role == .negative ? negativeRoom ?? room : room + return landscape ? (room.1, room.0) : room + } + + /// The Print and Negative tabs' pages, as they are now. + public func setRooms(print: (Double, Double), negative: (Double, Double)) { + let (print, negative) = (Self.portrait(print), Self.portrait(negative)) + guard print != room || negative != negativeRoom ?? room else { return } + (room, negativeRoom) = (print, negative) + applySize() + } func applySize() { (layout.width, layout.height) = size @@ -56,27 +75,64 @@ public final class ContactSheetModel { refresh() } - public var canAdd: Bool { entries.count < ContactSheet.maxPhotos } + public var canAdd: Bool { entries.count + queue.count < ContactSheet.maxPhotos } + + /// Photos being opened: how many are done, of how many, since when. + public struct Loading: Equatable { + public var done: Int + public var total: Int + public let started: Date + /// The file being opened now. + public var current: String + + /// Seconds left, from the time per photo so far (nil until one is done). + public func secondsLeft(now: Date = Date()) -> Double? { + guard done > 0 else { return nil } + return now.timeIntervalSince(started) / Double(done) * Double(total - done) + } + + /// "Opening frame-03.tif (3 of 12) · about 8 s left". + public func description(now: Date = Date()) -> String { + var text = "Opening \(current) (\(done + 1) of \(total))" + if let left = secondsLeft(now: now) { + text += left < 60 ? " · about \(max(1, Int(left.rounded()))) s left" + : " · about \(Int((left / 60).rounded())) min left" + } + return text + } + } + + public private(set) var loading: Loading? + private var queue: [URL] = [] - /// Add photos (up to 16 in all), in the background. + /// Add photos (up to 16 in all), opened one at a time in the background; each shows on + /// the sheet as soon as it is ready. public func add(_ urls: [URL]) { - let room = ContactSheet.maxPhotos - entries.count - let chosen = Array(urls.prefix(room)) + let room = ContactSheet.maxPhotos - entries.count - queue.count + let chosen = Array(urls.prefix(max(0, room))) if urls.count > room { error = "A contact sheet takes up to \(ContactSheet.maxPhotos) photos; the rest were left out." } guard !chosen.isEmpty else { return } + queue += chosen + if loading != nil { // already opening: these join the queue + loading?.total += chosen.count + return + } + loading = Loading(done: 0, total: queue.count, started: Date(), current: queue[0].lastPathComponent) busy = true Task { - let loaded = await Task.detached(priority: .userInitiated) { - chosen.map { url in Result { (url, try Self.shrunk(Photos.load(url))) } } - }.value - busy = false - for result in loaded { + while !queue.isEmpty { + let url = queue.removeFirst() + loading?.current = url.lastPathComponent + let result = await Task.detached(priority: .userInitiated) { Result { try Self.shrunk(Photos.load(url)) } }.value switch result { - case .success(let (url, photo)): entries.append(Entry(url: url, photo: photo)) - case .failure(let failure): error = "Couldn't open a photo: \(failure)" + case .success(let photo): entries.append(Entry(url: url, photo: photo)) + case .failure(let failure): error = "Couldn't open \(url.lastPathComponent): \(failure)" } + loading?.done += 1 + refresh() } - refresh() + loading = nil + busy = false } } @@ -130,10 +186,12 @@ public final class ContactSheetModel { provider: provider, decode: nil, shouldInterpolate: true, intent: .defaultIntent) } - /// Make the full sheet at 300 ppi, save it as a 16-bit TIFF in OpenQuad's contact - /// sheets folder, and hand its file to `done`. - public func make(dpi: Double = 300, done: @escaping (URL) -> Void) { - let photos = photos, names = names, layout = layout, landscape = landscape + /// Make the full sheet at 300 ppi for the Print or Negative tab's page, save it as a + /// 16-bit TIFF in OpenQuad's contact sheets folder, and hand its file to `done`. + public func make(dpi: Double = 300, for role: TabRole = .print, done: @escaping (URL) -> Void) { + var sized = layout + (sized.width, sized.height) = size(for: role) + let photos = photos, names = names, landscape = landscape, layout = sized let format = DateFormatter() format.dateFormat = "yyyy-MM-dd-HHmmss" let url = folder.appendingPathComponent("contact-sheet-\(format.string(from: Date())).tif") @@ -164,10 +222,12 @@ public final class ContactSheetModel { public struct ContactSheetView: View { @Bindable var model: ContactSheetModel - let use: (URL) -> Void - let close: () -> Void + /// Hands the made sheet to the Print or Negative tab. + let use: (URL, TabRole) -> Void + /// Closes the window it is in; nil inside a tab (no Close button). + let close: (() -> Void)? - public init(model: ContactSheetModel, use: @escaping (URL) -> Void, close: @escaping () -> Void = {}) { + public init(model: ContactSheetModel, use: @escaping (URL, TabRole) -> Void, close: (() -> Void)? = nil) { self.model = model self.use = use self.close = close @@ -205,7 +265,7 @@ public struct ContactSheetView: View { Form { Section("Photos (\(model.entries.count) of \(ContactSheet.maxPhotos))") { Button("Add Photos…", action: addPhotos) - .disabled(!model.canAdd || model.busy) + .disabled(!model.canAdd) List { ForEach(model.entries) { entry in HStack { @@ -248,8 +308,8 @@ public struct ContactSheetView: View { set: { value in model.update { $0.wedge = value } })) LengthStepper(title: "Space between", inches: model.layout.gap, range: 0...1, inchStep: 0.05, mmStep: 1, units: model.units) { value in model.update { $0.gap = value } } - Text("The sheet fills the print window's page, inside its margins (and the safe edge and outline, for " - + "a negative); a landscape sheet is turned to fit. Use it there as a print or a digital negative.") + Text("The sheet fills the Print or Negative tab's page, inside its margins (and the safe edge and " + + "outline, for a negative); a landscape sheet is turned to fit.") .font(.caption) .foregroundStyle(.secondary) .fixedSize(horizontal: false, vertical: true) @@ -260,23 +320,42 @@ public struct ContactSheetView: View { } .formStyle(.grouped) Divider() - HStack { - if model.busy { ProgressView().controlSize(.small) } - Spacer() - Button("Cancel", action: close) - Button("Use Sheet") { - model.make { url in - use(url) - close() + if let loading = model.loading { + VStack(alignment: .leading, spacing: 4) { + ProgressView(value: Double(loading.done), total: Double(max(loading.total, 1))) + TimelineView(.periodic(from: .now, by: 1)) { context in + Text(loading.description(now: context.date)) + .font(.callout) + .foregroundStyle(.secondary) + .lineLimit(1) + .truncationMode(.middle) } } - .keyboardShortcut(.defaultAction) - .disabled(model.entries.isEmpty || model.busy) + .padding([.horizontal, .top]) + } + HStack { + if model.busy && model.loading == nil { ProgressView().controlSize(.small) } + Spacer() + if let close { Button("Cancel", action: close) } + Button("Make a Negative") { make(for: .negative) } + .disabled(model.entries.isEmpty || model.busy) + .help("Make the sheet for the Negative tab's page and open it there") + Button("Print It") { make(for: .print) } + .keyboardShortcut(.defaultAction) + .disabled(model.entries.isEmpty || model.busy) + .help("Make the sheet for the Print tab's page and open it there") } .padding() } } + private func make(for role: TabRole) { + model.make(for: role) { url in + use(url, role) + close?() + } + } + private func addPhotos() { let panel = NSOpenPanel() panel.allowedContentTypes = [.image] diff --git a/swift/OpenQuadApp/Sources/OpenQuadUI/ContentView.swift b/swift/OpenQuadApp/Sources/OpenQuadUI/ContentView.swift index 9d61d31..9f19bd1 100644 --- a/swift/OpenQuadApp/Sources/OpenQuadUI/ContentView.swift +++ b/swift/OpenQuadApp/Sources/OpenQuadUI/ContentView.swift @@ -1,5 +1,5 @@ -// The print window: open a photo, choose toning or a digital negative, set the page, -// preview, and print through the macOS print panel. +// The Print and Negative tabs: open a photo, choose toning (Print) or the negative's +// settings (Negative), set the page, preview, and print. import AppKit import OpenQuadCore @@ -9,17 +9,15 @@ import UniformTypeIdentifiers public struct ContentView: View { @Bindable var model: AppModel @State private var ppiText = "" - @State private var showGuide = false @State private var savingSetup = false @State private var setupName = "" @State private var deletingSetup: NegativeSetup? - @AppStorage("guideSeen") private var guideSeen = 0 + /// Switch to another tab (e.g. to calibrate). + let goTo: (AppTab) -> Void - let guideOnLaunch: Bool - - public init(model: AppModel, guideOnLaunch: Bool = true) { + public init(model: AppModel, goTo: @escaping (AppTab) -> Void = { _ in }) { self.model = model - self.guideOnLaunch = guideOnLaunch + self.goTo = goTo } public var body: some View { @@ -30,7 +28,6 @@ public struct ContentView: View { .frame(minWidth: 420, maxWidth: .infinity, maxHeight: .infinity) } .frame(minWidth: 820, minHeight: 600) - .sheet(isPresented: $showGuide) { GuideView { guideSeen = GuideView.version } } .alert("Save Negative Setup", isPresented: $savingSetup) { TextField("Name", text: $setupName) Button("Save") { model.saveSetup(named: setupName) } @@ -48,18 +45,7 @@ public struct ContentView: View { } message: { Text("Its copy of the process curve goes too. Your own curve files are not touched.") } - .toolbar { - ToolbarItem { - Button { showGuide = true } label: { Label("How to Use OpenQuad", systemImage: "questionmark.circle") } - .help("How to use OpenQuad") - } - } - .onReceive(NotificationCenter.default.publisher(for: GuideView.showNotification)) { _ in showGuide = true } - .onReceive(NotificationCenter.default.publisher(for: ContentView.contactSheetNotification)) { _ in openContactSheet() } - .onAppear { - model.loadPrinters() - if guideOnLaunch && guideSeen < GuideView.version { showGuide = true } // first launch: walk through the app - } + .onAppear { model.loadPrinters() } } // MARK: the controls @@ -68,22 +54,14 @@ public struct ContentView: View { VStack(spacing: 0) { Form { Section("Photo") { - HStack { - Button("Open Photo…", action: openPhoto) - .keyboardShortcut("o") - Button("Make a Contact Sheet…", action: openContactSheet) - } + Button("Open Photo…", action: openPhoto) + .keyboardShortcut("o") Text(model.photoDescription) .font(.callout) .foregroundStyle(.secondary) .textSelection(.enabled) } - Section("Output") { - Picker("Output", selection: Binding(get: { model.session.mode }, set: { model.setMode($0) })) { - Text("Print").tag(OutputMode.print) - Text("Digital negative").tag(OutputMode.negative) - } - .pickerStyle(.segmented) + Section(model.session.negative ? "Negative" : "Toning and calibration") { if model.session.negative { negativeControls } else { printControls } } Section("Page") { @@ -195,7 +173,7 @@ public struct ContentView: View { Button("Import…") { if let url = Self.askOpen(types: [UTType(filenameExtension: "oqcal")].compactMap { $0 }) { model.importCalibration(url) } } - Button("Calibrate This Printer…", action: openCalibrationWizard) + Button("Calibrate This Printer…") { goTo(.printerCalibration) } } } @@ -206,6 +184,20 @@ public struct ContentView: View { } @ViewBuilder private var negativeControls: some View { + if let offer = model.setupOffer { + HStack { + Text(offer).font(.callout) + Spacer() + Button("Save Setup…") { + setupName = model.suggestedSetupName + savingSetup = true + model.setupOffer = nil + } + Button("Not Now") { model.setupOffer = nil } + } + .padding(8) + .background(Color.accentColor.opacity(0.12), in: RoundedRectangle(cornerRadius: 6)) + } Picker("Setup", selection: Binding(get: { model.currentSetup?.name ?? "" }, set: { name in if let setup = model.setups.first(where: { $0.name == name }) { model.applySetup(setup) } })) { @@ -227,8 +219,7 @@ public struct ContentView: View { .disabled(model.session.process != nil) // the process curve decides the colour fileRow("Process curve", model.session.processPath, types: ["oqproc"], choose: { model.setProcess($0) }, clear: { model.setProcess(nil) }) - Button("Calibrate a Process…", action: openProcessWizard) - Button("Find the Best Blocking Colour…", action: openBlockingTest) + Button("Calibrate a Process…") { goTo(.processCalibration) } Toggle("Mirror (flip left to right)", isOn: Binding(get: { model.session.mirror }, set: { model.setMirror($0) })) LengthStepper(title: "Safe edge", inches: model.session.safeEdge, range: 0...2, inchStep: 0.05, mmStep: 1, units: model.units) { model.setSafeEdge($0) } @@ -276,41 +267,6 @@ public struct ContentView: View { // MARK: actions - /// Posted by File > New Contact Sheet…. - public static let contactSheetNotification = Notification.Name("OpenQuadContactSheet") - - private func openContactSheet() { - let sheet = model.contactSheet(), app = model - WizardWindows.show("contact-sheet", title: "Contact Sheet", size: CGSize(width: 1000, height: 760), - minSize: CGSize(width: 760, height: 520)) { close in - ContactSheetView(model: sheet, use: { app.useContactSheet($0) }, close: close) - } - } - - private func openCalibrationWizard() { - let wizard = model.calibrationWizard(), app = model - WizardWindows.show("calibrate-printer", title: "Calibrate a Printer", size: CGSize(width: 980, height: 820), - minSize: CGSize(width: 760, height: 560)) { close in - CalibrationWizardView(model: wizard, use: { app.finishCalibration($0, scannerHost: wizard.scannerHost) }, close: close) - } - } - - private func openProcessWizard() { - let wizard = model.processWizard(), app = model - WizardWindows.show("calibrate-process", title: "Calibrate a Process", size: CGSize(width: 980, height: 860), - minSize: CGSize(width: 760, height: 600)) { close in - ProcessWizardView(model: wizard, use: { app.finishProcess($0, scannerHost: wizard.scannerHost) }, close: close) - } - } - - private func openBlockingTest() { - let test = model.blockingTest(), app = model - WizardWindows.show("blocking-test", title: "Blocking Test", size: CGSize(width: 900, height: 820), - minSize: CGSize(width: 700, height: 560)) { close in - BlockingTestView(model: test, use: { app.useBlockingColour($0, scannerHost: test.scannerHost) }, close: close) - } - } - private func openPhoto() { let types: [UTType] = [.tiff, .png, .jpeg] if let url = Self.askOpen(types: types, folder: model.settings.lastFolder) { model.openPhoto(url) } diff --git a/swift/OpenQuadApp/Sources/OpenQuadUI/Guide.swift b/swift/OpenQuadApp/Sources/OpenQuadUI/Guide.swift index 38e4897..e7df8c5 100644 --- a/swift/OpenQuadApp/Sources/OpenQuadUI/Guide.swift +++ b/swift/OpenQuadApp/Sources/OpenQuadUI/Guide.swift @@ -1,11 +1,11 @@ -// "How to Use OpenQuad": a short walk through the app, shown on first launch and from -// the Help menu or the toolbar. +// "How to Use OpenQuad": a short walk through the app's tabs, shown on first launch +// (and when it changes) and from the Help menu or the toolbar. import SwiftUI public struct GuideView: View { /// Raise when the guide changes enough to show it again on launch. - public static let version = 11 + public static let version = 12 public static let showNotification = Notification.Name("OpenQuadShowGuide") struct Page { @@ -18,16 +18,18 @@ public struct GuideView: View { static let pages: [Page] = [ Page(symbol: "printer.fill", title: "Welcome to OpenQuad", text: "OpenQuad prints black-and-white photos with accurate, neutral tones on an ordinary inkjet printer, " - + "and makes digital negatives for contact printing (carbon transfer).", - steps: ["Open a photo, choose how it should print, and print.", - "Calibrate your printer once, with its scanner, so greys print neutral and evenly spaced.", - "For carbon: find the best negative colour, then calibrate the process.", + + "and makes digital negatives for contact printing (carbon, cyanotype and other UV processes).", + steps: ["The tabs at the top (⌘1 to ⌘5) are the five parts of the app: Print, Negative, Contact Sheet, " + + "Printer Calibration and Process Calibration.", + "Each tab keeps its own work while you use the others: calibrate one printer, print on another " + + "and refine a process at the same time.", + "When you quit, OpenQuad asks whether to keep your open photos for next time.", "This is a beta. Please report anything that goes wrong, or reads unclearly, at " + "github.com/akendrick/openquad/issues."]), - Page(symbol: "photo", title: "Print a photo", - text: "Everything is on the left; the preview on the right shows how the print should look.", + Page(symbol: "printer", title: "Print a photo", + text: "The Print tab: everything is on the left; the preview on the right shows how the print should look.", steps: ["Open Photo… (⌘O): greyscale or colour, any size. Colour photos are converted to grey.", - "Output: Print. Toning stays Neutral unless you choose a duotone; it's never remembered.", + "Toning stays Neutral unless you choose a duotone; it's never remembered.", "Calibration: pick one of your saved calibrations (Import… adds a file). Choosing a printer " + "under Page picks its newest calibration for that paper.", "Page: paper, Fit to page, or turn Fit off and give a resolution. Print size shows the result.", @@ -35,8 +37,8 @@ public struct GuideView: View { + "same quality settings every time. Or pick a printer to print straight to it.", "Save Print File… writes the finished 16-bit file to print from another app at 100%."]), Page(symbol: "slider.horizontal.3", title: "Calibrate your printer", - text: "Calibrate This Printer… opens its own window. Calibration goes in rounds; each round is Print, Scan, " - + "Result, and the blue card always says which step you're on and highlights the button for it.", + text: "The Printer Calibration tab (or Calibrate This Printer… in Print). Calibration goes in rounds; each " + + "round is Print, Scan, Result, and the blue card always says which step you're on.", steps: ["Choose the printer, paper (and type), how you'll print and the scanner, then Start. Print the same " + "way every time, or the calibration won't fit.", "Print: the comparison page has two wedges, the top one uncorrected (one square), the bottom one " @@ -45,20 +47,17 @@ public struct GuideView: View { + "macOS asks to let OpenQuad find devices on your network: choose Allow.", "Result: the card says what to do. Usually Improve Grey Balance first (colour casts), then Even " + "Out Tone (lightness), printing and scanning again after each to check it.", - "The rounds table shows every round's numbers, so you can see progress. When both goals are met, " - + "Use This Calibration saves it under the printer's name.", - "Stopped halfway? Continue a Previous Run picks up exactly where you left off. Show Log opens " - + "the log at the side."]), + "When both goals are met, Use This Calibration saves it and the Print tab uses it (if it prints " + + "on that printer). New Calibration in the toolbar starts again.", + "Stopped halfway? Continue a Previous Run picks up exactly where you left off."]), Page(symbol: "film", title: "Digital negatives", - text: "Output: Digital negative turns the photo into a negative for contact printing, in black or a " - + "colour that blocks UV.", + text: "The Negative tab turns a photo into a negative for contact printing, in black or a colour that " + + "blocks UV. It has its own photo, printer and paper.", steps: ["Setup: switch between saved setups (curve, colour, mirror, edges, printer and paper) in one step. " + "Once a process is calibrated, Save Setup… keeps it under a name, e.g. Cyanotype on Pictorico.", - "Ink colour: the colour to print the negative in (the blocking test finds the best one).", - "Process curve: shapes the tones for your process (made by Calibrate a Process…).", - "Mirror if the film's printed side must face the tissue.", - "The safe edge frames the photo; the F cut into it reads correctly in the print when the " - + "mirror setting was right.", + "Ink colour and Process curve: both come from the Process Calibration tab.", + "Mirror if the film's printed side must face the tissue. The F cut into the safe edge reads " + + "correctly in the print when the mirror setting was right.", "Outline in black adds a black border of the width you set between the safe edge and the " + "photo: a natural frame for photos with white or light edges.", "Prefer millimetres? OpenQuad > Settings… (⌘,) switches every length in the app to mm.", @@ -66,34 +65,34 @@ public struct GuideView: View { + "that becomes the negative's outer edge, safe edge included, and the photo shrinks to fit.", "Print on transparency film at 100% with your usual film settings."]), Page(symbol: "square.grid.3x3", title: "Contact sheets", - text: "File > New Contact Sheet… (⇧⌘N) puts up to 16 photos on one sheet, to proof them or to make one " + text: "The Contact Sheet tab (⇧⌘N) puts up to 16 photos on one sheet, to proof them or to make one " + "negative of them all.", - steps: ["Add Photos… (or drop them on the sheet); drag the list to change the order.", + steps: ["Add Photos… (or drop them on the sheet); a bar shows each photo opening and the time left. Drag " + + "the list to change the order.", "Choose portrait or landscape, a black or white background, whole photos or cropped to fill, " + "file names, and a greyscale step wedge to check the print's tones.", - "The sheet fills the page you chose in the print window (for a negative, inside its safe edge " - + "and outline). Set the page and output first.", - "Use Sheet makes it the photo in the print window: print it, or print it as a negative."]), + "Print It makes the sheet for the Print tab's page and opens it there; Make a Negative makes it " + + "for the Negative tab's page (inside its safe edge and outline)."]), Page(symbol: "square.grid.3x3.square", title: "Find the best blocking colour", - text: "Find the Best Blocking Colour… (in negative mode) prints a sheet of every negative colour.", + text: "Process Calibration, step 1: a sheet of every negative colour, to find the one that blocks UV best.", steps: ["Choose the chart: Standard (six colours) or Ink mixtures (ten colours your printer makes " + "from single inks and simple mixes). Print it on film and expose it at your usual time.", "Develop it, let it dry, and scan the print (or read a scan file).", "OpenQuad reads the print any way up, tilted or mirrored, and reports which colours block " + "fully and how many distinct steps each gives.", - "Use the best colour for your negatives."]), + "Use the best colour: the Negative tab prints in it, and step 2 calibrates in it."]), Page(symbol: "chart.line.uptrend.xyaxis", title: "Calibrate the process", - text: "Calibrate a Process… prints process charts (101 tones each) on one page, one chart per colour.", + text: "Process Calibration, step 2: process charts (101 tones each) on one page, one chart per colour.", steps: ["Start, then print the chart page on film (or print it from another app at 100% and say so).", "Contact print it at your usual exposure, develop, dry, and scan the print.", "Each colour's measured tones are drawn against the target; Refine the Curves and repeat " + "until every patch is within 3 L*.", - "Use This Colour's Curve: your negatives then print with tones on target."]), + "Use This Colour's Curve: the Negative tab uses it and offers to save it as a setup."]), Page(symbol: "lightbulb", title: "Good to know", text: "A few things that make results repeatable.", steps: ["Scans are made in Document mode with fixed settings so days compare; Photo mode alters colour.", - "Calibration runs, scans and measurements are kept in ~/Library/Application Support/OpenQuad, " - + "shared with the OpenQuad command-line tools.", + "Calibration runs, scans, setups and contact sheets are kept in ~/Library/Application Support/" + + "OpenQuad, shared with the OpenQuad command-line tools.", "Nothing is printed or scanned without you confirming it first.", "Open this guide again any time from Help ▸ How to Use OpenQuad or the ? button."]), ] diff --git a/swift/OpenQuadApp/Sources/OpenQuadUI/Lengths.swift b/swift/OpenQuadApp/Sources/OpenQuadUI/Lengths.swift index 48a0c78..cc0d953 100644 --- a/swift/OpenQuadApp/Sources/OpenQuadUI/Lengths.swift +++ b/swift/OpenQuadApp/Sources/OpenQuadUI/Lengths.swift @@ -27,13 +27,13 @@ struct LengthStepper: View { /// The app's settings window (OpenQuad > Settings…). public struct SettingsView: View { - @Bindable var model: AppModel + @Bindable var root: AppRoot - public init(model: AppModel) { self.model = model } + public init(root: AppRoot) { self.root = root } public var body: some View { Form { - Picker("Lengths in", selection: Binding(get: { model.units }, set: { model.setUnits($0) })) { + Picker("Lengths in", selection: Binding(get: { root.printModel.units }, set: { root.setUnits($0) })) { Text("Inches").tag(LengthUnit.inches) Text("Millimetres").tag(LengthUnit.millimetres) } diff --git a/swift/OpenQuadApp/Sources/OpenQuadUI/Tabs.swift b/swift/OpenQuadApp/Sources/OpenQuadUI/Tabs.swift new file mode 100644 index 0000000..1a94e61 --- /dev/null +++ b/swift/OpenQuadApp/Sources/OpenQuadUI/Tabs.swift @@ -0,0 +1,368 @@ +// The window's five tabs: Print, Negative, Contact Sheet, Printer Calibration and +// Process Calibration. Each keeps its own work while you use the others (calibrate one +// printer, print on another, refine a process), and results are handed between them. + +import AppKit +import OpenQuadCore +import SwiftUI + +public enum AppTab: String, CaseIterable, Identifiable, Sendable { + case print + case negative + case contactSheet = "contact-sheet" + case printerCalibration = "printer-calibration" + case processCalibration = "process-calibration" + + public var id: String { rawValue } + + public var title: String { + switch self { + case .print: "Print" + case .negative: "Negative" + case .contactSheet: "Contact Sheet" + case .printerCalibration: "Printer Calibration" + case .processCalibration: "Process Calibration" + } + } + + public var symbol: String { + switch self { + case .print: "printer" + case .negative: "film" + case .contactSheet: "square.grid.3x3" + case .printerCalibration: "slider.horizontal.3" + case .processCalibration: "chart.line.uptrend.xyaxis" + } + } + + /// ⌘1 to ⌘5. + public var shortcut: KeyEquivalent { KeyEquivalent(Character(String((Self.allCases.firstIndex(of: self) ?? 0) + 1))) } +} + +/// What can be kept for next time: each tab's photo and the contact sheet. +public struct Workspace: Codable, Equatable, Sendable { + public var printPhoto: String? + public var negativePhoto: String? + public var sheetPhotos: [String] = [] + public var sheetLandscape = false + public var sheetBackground = "black" + public var sheetCrop = false + public var sheetWedge = false + public var sheetLabels = false + public var sheetGap = 0.15 + + public var isEmpty: Bool { printPhoto == nil && negativePhoto == nil && sheetPhotos.isEmpty } +} + +@MainActor +@Observable +public final class AppRoot { + public var tab: AppTab { + didSet { + UserDefaults.standard.set(tab.rawValue, forKey: Self.tabKey) + arrived(at: tab) + } + } + public let printModel: AppModel + public let negativeModel: AppModel + public let contactSheet: ContactSheetModel + /// The calibration runs, made when their tab is first opened. + public private(set) var calibration: CalibrationWizardModel? + public private(set) var process: ProcessWizardModel? + public private(set) var blocking: BlockingTestModel? + /// Process Calibration's two steps: the blocking colour, then the curve. + public enum ProcessStep: String, CaseIterable, Sendable { + case blocking = "1. Blocking colour" + case curve = "2. Process curve" + } + public var processStep = ProcessStep.blocking + /// What a hand-off between tabs just changed, shown under the tab bar. + public var notice: String? + /// Ask on quit whether to keep the photos for next time (off for snapshots and tests). + public var askOnQuit = true + + static let tabKey = "selectedTab" + let workspaceURL: URL + + public init(settingsURL: URL = AppSettings.defaultURL(), libraryFolder: URL? = nil, setupsFolder: URL? = nil, + tab: AppTab? = nil, restoreWorkspace: Bool = true) { + printModel = AppModel(settingsURL: settingsURL, libraryFolder: libraryFolder, setupsFolder: setupsFolder, role: .print) + negativeModel = AppModel(settingsURL: settingsURL, libraryFolder: libraryFolder, setupsFolder: setupsFolder, + role: .negative) + contactSheet = ContactSheetModel(room: printModel.printableRoom, units: printModel.units, + folder: printModel.contactSheetFolder) + workspaceURL = settingsURL.deletingLastPathComponent().appendingPathComponent("workspace.json") + self.tab = tab ?? UserDefaults.standard.string(forKey: Self.tabKey).flatMap(AppTab.init(rawValue:)) ?? .print + if restoreWorkspace { restore() } + arrived(at: self.tab) + } + + public func show(_ tab: AppTab) { self.tab = tab } + + /// Lengths in inches or millimetres, everywhere. + public func setUnits(_ units: LengthUnit) { + printModel.setUnits(units) + negativeModel.followUnits() + contactSheet.units = units + blocking?.units = units + } + + /// Bring a tab up to date with the others when it is shown. + func arrived(at tab: AppTab) { + switch tab { + case .print: printModel.followUnits() + case .negative: negativeModel.followUnits() + case .contactSheet: + contactSheet.units = printModel.units + contactSheet.setRooms(print: printModel.printableRoom, negative: negativeModel.printableRoom) + case .printerCalibration: + if calibration == nil { calibration = printModel.calibrationWizard() } + case .processCalibration: + if blocking == nil { blocking = negativeModel.blockingTest() } + if process == nil { process = negativeModel.processWizard() } + } + } + + /// Start a fresh printer calibration (for the Print tab's printer and paper). + public func newCalibration() { calibration = printModel.calibrationWizard() } + + /// Start a fresh process calibration and blocking test. + public func newProcess() { + blocking = negativeModel.blockingTest() + process = negativeModel.processWizard() + processStep = .blocking + } + + // MARK: hand-offs between tabs + + /// A finished printer calibration: used in the Print tab when it prints on that printer + /// (negatives are shaped by their process curve instead). + public func useCalibration(_ path: URL, scannerHost: String) { + let entry = CalibrationLibrary.entry(path) + let label = entry?.label ?? path.lastPathComponent + if let printer = entry?.printer, let current = printModel.session.printer, current != printer { + printModel.refreshLibrary() + notice = "Saved \(label). The Print tab prints on \(LibraryEntry.printerName(current)); " + + "choose \(LibraryEntry.printerName(printer)) there to use it." + } else { + printModel.finishCalibration(path, scannerHost: scannerHost) + notice = "The Print tab now uses \(label)." + } + tab = .print + } + + /// The blocking test's best colour: used for negatives, and the colour the process + /// curve is calibrated in. + public func useBlockingColour(_ colour: String, scannerHost: String) { + negativeModel.useBlockingColour(colour, scannerHost: scannerHost) + process?.colours = [colour] + process?.useColour = colour + processStep = .curve + notice = "Negatives now print in \(colour). Next: calibrate the process curve in \(colour)." + } + + /// A finished process curve: used in the Negative tab, with an offer to save a setup. + public func useProcess(_ path: URL, scannerHost: String) { + negativeModel.finishProcess(path, scannerHost: scannerHost) + negativeModel.setupOffer = "Using the new curve \(path.lastPathComponent). Save it as a setup to switch back to it later?" + notice = "The Negative tab now uses \(path.lastPathComponent)." + tab = .negative + } + + /// A made contact sheet, opened in the Print or Negative tab. + public func useContactSheet(_ url: URL, for role: TabRole) { + (role == .negative ? negativeModel : printModel).useContactSheet(url) + notice = "The contact sheet is open in the \(role == .negative ? "Negative" : "Print") tab." + tab = role == .negative ? .negative : .print + } + + // MARK: keeping work for next time + + /// What would be kept now. + public var workspace: Workspace { + var kept = Workspace() + kept.printPhoto = printModel.session.source?.path + kept.negativePhoto = negativeModel.session.source?.path + kept.sheetPhotos = contactSheet.entries.map(\.url.path) + kept.sheetLandscape = contactSheet.landscape + kept.sheetBackground = contactSheet.layout.background.rawValue + kept.sheetCrop = contactSheet.layout.crop + kept.sheetWedge = contactSheet.layout.wedge + kept.sheetLabels = contactSheet.layout.labels + kept.sheetGap = contactSheet.layout.gap + return kept + } + + public func keepWorkspace() throws { + let encoder = JSONEncoder() + encoder.outputFormatting = [.prettyPrinted, .sortedKeys] + try FileManager.default.createDirectory(at: workspaceURL.deletingLastPathComponent(), withIntermediateDirectories: true) + try encoder.encode(workspace).write(to: workspaceURL, options: .atomic) + } + + public func forgetWorkspace() { try? FileManager.default.removeItem(at: workspaceURL) } + + /// Reopen kept work (once: it is asked about again at the next quit). + func restore() { + guard let data = try? Data(contentsOf: workspaceURL), + let kept = try? JSONDecoder().decode(Workspace.self, from: data) else { return } + forgetWorkspace() + let exists = { (path: String) in FileManager.default.fileExists(atPath: path) } + if let path = kept.printPhoto, exists(path) { printModel.openPhoto(URL(fileURLWithPath: path)) } + if let path = kept.negativePhoto, exists(path) { negativeModel.openPhoto(URL(fileURLWithPath: path)) } + contactSheet.setLandscape(kept.sheetLandscape) + contactSheet.update { + $0.background = SheetLayout.Background(rawValue: kept.sheetBackground) ?? .black + $0.crop = kept.sheetCrop + $0.wedge = kept.sheetWedge + $0.labels = kept.sheetLabels + $0.gap = min(max(kept.sheetGap, 0), 1) + } + contactSheet.add(kept.sheetPhotos.filter(exists).map { URL(fileURLWithPath: $0) }) + } + + /// On quit: if there is work open, ask whether to keep it. False cancels the quit. + public func confirmQuit() -> Bool { + guard askOnQuit, !workspace.isEmpty else { + forgetWorkspace() + return true + } + let alert = NSAlert() + alert.messageText = "Keep your photos for next time?" + alert.informativeText = "OpenQuad can reopen the photos in Print and Negative and the contact sheet's photos " + + "the next time it starts, so you can carry on where you left off." + alert.addButton(withTitle: "Keep for Next Time") + alert.addButton(withTitle: "Start Fresh") + alert.addButton(withTitle: "Cancel") + switch alert.runModal() { + case .alertFirstButtonReturn: + try? keepWorkspace() + return true + case .alertSecondButtonReturn: + forgetWorkspace() + return true + default: + return false + } + } +} + +/// The window: the tab bar in the toolbar and the chosen tab's page. +public struct RootView: View { + @Bindable var root: AppRoot + @State private var showGuide = false + @AppStorage("guideSeen") private var guideSeen = 0 + let guideOnLaunch: Bool + + public init(root: AppRoot, guideOnLaunch: Bool = true) { + self.root = root + self.guideOnLaunch = guideOnLaunch + } + + public var body: some View { + VStack(spacing: 0) { + if let notice = root.notice { + HStack { + Image(systemName: "checkmark.circle").foregroundStyle(.green) + Text(notice).font(.callout) + Spacer() + Button { root.notice = nil } label: { Image(systemName: "xmark") } + .buttonStyle(.borderless) + .help("Dismiss") + } + .padding(.horizontal) + .padding(.vertical, 6) + .background(Color.green.opacity(0.08)) + Divider() + } + page + .frame(maxWidth: .infinity, maxHeight: .infinity) + } + .frame(minWidth: 900, minHeight: 620) + .toolbar { + ToolbarItem(placement: .principal) { TabBar(selection: $root.tab) } + ToolbarItem(placement: .primaryAction) { + Button { showGuide = true } label: { Label("How to Use OpenQuad", systemImage: "questionmark.circle") } + .help("How to use OpenQuad") + } + } + .navigationTitle("") + .sheet(isPresented: $showGuide) { GuideView { guideSeen = GuideView.version } } + .onReceive(NotificationCenter.default.publisher(for: GuideView.showNotification)) { _ in showGuide = true } + .onAppear { + if guideOnLaunch && guideSeen < GuideView.version { showGuide = true } // first launch: walk through the app + } + } + + @ViewBuilder private var page: some View { + switch root.tab { + case .print: + ContentView(model: root.printModel, goTo: root.show).id(AppTab.print) + case .negative: + ContentView(model: root.negativeModel, goTo: root.show).id(AppTab.negative) + case .contactSheet: + ContactSheetView(model: root.contactSheet) { url, role in root.useContactSheet(url, for: role) } + case .printerCalibration: + if let wizard = root.calibration { + CalibrationWizardView(model: wizard) { root.useCalibration($0, scannerHost: wizard.scannerHost) } + .id(ObjectIdentifier(wizard)) + .toolbar { + ToolbarItem { Button("New Calibration", action: root.newCalibration).help("Start again for the Print tab's printer and paper") } + } + } + case .processCalibration: + VStack(spacing: 0) { + Picker("Step", selection: $root.processStep) { + ForEach(AppRoot.ProcessStep.allCases, id: \.self) { Text($0.rawValue).tag($0) } + } + .pickerStyle(.segmented) + .labelsHidden() + .frame(maxWidth: 420) + .padding(10) + Divider() + switch root.processStep { + case .blocking: + if let test = root.blocking { + BlockingTestView(model: test) { root.useBlockingColour($0, scannerHost: test.scannerHost) } + .id(ObjectIdentifier(test)) + } + case .curve: + if let wizard = root.process { + ProcessWizardView(model: wizard) { root.useProcess($0, scannerHost: wizard.scannerHost) } + .id(ObjectIdentifier(wizard)) + } + } + } + .toolbar { + ToolbarItem { Button("New Process", action: root.newProcess).help("Start the blocking test and curve again") } + } + } + } +} + +/// Five labelled icons, the chosen one highlighted. +struct TabBar: View { + @Binding var selection: AppTab + + var body: some View { + HStack(spacing: 6) { + ForEach(AppTab.allCases) { tab in + Button { selection = tab } label: { + VStack(spacing: 2) { + Image(systemName: tab.symbol).font(.system(size: 15)) + Text(tab.title).font(.caption) + } + .frame(minWidth: 112) + .padding(.vertical, 3) + .contentShape(Rectangle()) + .foregroundStyle(selection == tab ? Color.accentColor : .secondary) + .background(selection == tab ? Color.accentColor.opacity(0.14) : .clear, + in: RoundedRectangle(cornerRadius: 6)) + } + .buttonStyle(.plain) + .help("\(tab.title) (⌘\(AppTab.allCases.firstIndex(of: tab)! + 1))") + .accessibilityAddTraits(selection == tab ? .isSelected : []) + } + } + } +} diff --git a/swift/OpenQuadApp/Sources/OpenQuadUI/Wizards.swift b/swift/OpenQuadApp/Sources/OpenQuadUI/Wizards.swift index 573ae4f..effe00d 100644 --- a/swift/OpenQuadApp/Sources/OpenQuadUI/Wizards.swift +++ b/swift/OpenQuadApp/Sources/OpenQuadUI/Wizards.swift @@ -431,10 +431,11 @@ func confirm(_ title: String, _ question: String) -> Bool { public struct CalibrationWizardView: View { @Bindable var model: CalibrationWizardModel let use: (URL) -> Void - let close: () -> Void + /// Closes the window it is in; nil inside a tab (no Close button). + let close: (() -> Void)? @State private var editingSetup = false - public init(model: CalibrationWizardModel, use: @escaping (URL) -> Void, close: @escaping () -> Void = {}) { + public init(model: CalibrationWizardModel, use: @escaping (URL) -> Void, close: (() -> Void)? = nil) { self.model = model self.use = use self.close = close @@ -459,7 +460,7 @@ public struct CalibrationWizardView: View { HStack { if model.busy { ProgressView().controlSize(.small) } Spacer() - Button("Close", action: close) + if let close { Button("Close", action: close) } } } } @@ -549,7 +550,7 @@ public struct CalibrationWizardView: View { improve: { model.improve($0) }, use: { if let path = model.calibrationPath { use(path) } - close() + close?() }) } @@ -783,9 +784,10 @@ struct RoundsTable: View { public struct ProcessWizardView: View { @Bindable var model: ProcessWizardModel let use: (URL) -> Void - let close: () -> Void + /// Closes the window it is in; nil inside a tab (no Close button). + let close: (() -> Void)? - public init(model: ProcessWizardModel, use: @escaping (URL) -> Void, close: @escaping () -> Void = {}) { + public init(model: ProcessWizardModel, use: @escaping (URL) -> Void, close: (() -> Void)? = nil) { self.model = model self.use = use self.close = close @@ -836,7 +838,7 @@ public struct ProcessWizardView: View { if let error = model.error { Text(error).foregroundStyle(.red) } HStack { Spacer() - Button("Close", action: close) + if let close { Button("Close", action: close) } Picker("Use", selection: $model.useColour) { ForEach(model.run?.colours ?? [], id: \.self) { Text($0.capitalized).tag($0) } } @@ -844,7 +846,7 @@ public struct ProcessWizardView: View { .disabled(!model.started) Button("Use This Colour's Curve") { if let path = model.curvePath { use(path) } - close() + close?() } .buttonStyle(.borderedProminent) .disabled(!model.started) diff --git a/swift/OpenQuadApp/Tests/OpenQuadUITests/GapsTests.swift b/swift/OpenQuadApp/Tests/OpenQuadUITests/GapsTests.swift index 7d5dbfc..f1d0206 100644 --- a/swift/OpenQuadApp/Tests/OpenQuadUITests/GapsTests.swift +++ b/swift/OpenQuadApp/Tests/OpenQuadUITests/GapsTests.swift @@ -62,11 +62,14 @@ struct GapsTests { @Test func guideCoversEveryPart() { let titles = GuideView.pages.map(\.title) - #expect(titles.count == 7 && titles.first == "Welcome to OpenQuad") - for part in ["Print a photo", "Calibrate your printer", "Digital negatives", "Find the best blocking colour", - "Calibrate the process"] { + #expect(titles.count == 8 && titles.first == "Welcome to OpenQuad") + for part in ["Print a photo", "Calibrate your printer", "Digital negatives", "Contact sheets", + "Find the best blocking colour", "Calibrate the process"] { #expect(titles.contains(part)) } #expect(GuideView.pages.allSatisfy { !$0.steps.isEmpty }) + for tab in AppTab.allCases where tab != .print { // every tab is explained + #expect(GuideView.pages.contains { $0.text.contains(tab.title) || $0.steps.joined().contains(tab.title) }) + } } } diff --git a/swift/OpenQuadApp/Tests/OpenQuadUITests/TabsTests.swift b/swift/OpenQuadApp/Tests/OpenQuadUITests/TabsTests.swift new file mode 100644 index 0000000..22083e8 --- /dev/null +++ b/swift/OpenQuadApp/Tests/OpenQuadUITests/TabsTests.swift @@ -0,0 +1,149 @@ +// The tabbed window's model: each tab's own work, hand-offs between tabs, and keeping +// the open photos for next time. + +import Foundation +import OpenQuadCore +import Testing +@testable import OpenQuadUI + +@MainActor +@Suite("Tabs") +struct TabsTests { + let folder: URL + let photo: URL + + init() throws { + folder = FileManager.default.temporaryDirectory.appendingPathComponent("openquad-tabs-\(UUID().uuidString)") + try FileManager.default.createDirectory(at: folder, withIntermediateDirectories: true) + photo = folder.appendingPathComponent("ramp.tif") + try ImageFiles.saveGrey(photo, GreyImage(width: 60, height: 40, pixels: (0..<2400).map { UInt16(($0 % 60) * 1110) }, + dpi: (300, 300))) + } + + func root(tab: AppTab = .print, restore: Bool = true) -> AppRoot { + let root = AppRoot(settingsURL: folder.appendingPathComponent("settings.json"), tab: tab, restoreWorkspace: restore) + root.askOnQuit = false + return root + } + + @Test func eachTabKeepsItsOwnPhotoPrinterAndPaper() { + let r = root() + #expect(r.printModel.role == .print && !r.printModel.session.negative) + #expect(r.negativeModel.role == .negative && r.negativeModel.session.negative) + r.printModel.openPhoto(photo) + r.printModel.setPrinter("Canon_MG3600_series") + r.negativeModel.setPrinter("Epson_ET_2900") + r.negativeModel.setPaper("A4") + r.printModel.setPaper("Letter") + #expect(r.negativeModel.session.photo == nil && r.printModel.session.photo != nil) + let again = root() // both remembered, neither overwriting the other + #expect(again.printModel.session.printer == "Canon_MG3600_series" && again.printModel.session.paper == "Letter") + #expect(again.negativeModel.session.printer == "Epson_ET_2900" && again.negativeModel.session.paper == "A4") + } + + @Test func tabsAreRememberedAndSetUpWhenShown() { + let r = root(tab: .print) + #expect(r.calibration == nil && r.process == nil && r.blocking == nil) + r.show(.processCalibration) + #expect(r.process != nil && r.blocking != nil && r.processStep == .blocking) + r.show(.printerCalibration) + #expect(r.calibration != nil) + #expect(UserDefaults.standard.string(forKey: AppRoot.tabKey) == "printer-calibration") + let first = r.calibration + r.newCalibration() + #expect(r.calibration !== first) + #expect(AppTab.allCases.map(\.title) == ["Print", "Negative", "Contact Sheet", "Printer Calibration", "Process Calibration"]) + #expect(AppTab.processCalibration.shortcut == "5") + } + + @Test func unitsReachEveryTab() { + let r = root() + r.show(.processCalibration) + r.setUnits(.millimetres) + #expect(r.printModel.units == .millimetres && r.negativeModel.session.units == .millimetres) + #expect(r.contactSheet.units == .millimetres && r.blocking?.units == .millimetres) + r.setUnits(.inches) + } + + @Test func blockingColourAndProcessCurveHandOff() throws { + let r = root(tab: .processCalibration) + r.useBlockingColour("orange", scannerHost: "") + #expect(r.negativeModel.session.negativeColour == "orange") + #expect(r.process?.colours == ["orange"] && r.process?.useColour == "orange" && r.processStep == .curve) + #expect(r.notice?.contains("orange") == true) + let curve = folder.appendingPathComponent("carbon.oqproc") + try ProcessCurve.identity(colour: "orange").encode().write(to: curve) + r.useProcess(curve, scannerHost: "") + #expect(r.tab == .negative && r.negativeModel.session.processPath == curve) + #expect(r.negativeModel.setupOffer != nil && r.notice?.contains("carbon.oqproc") == true) + #expect(r.printModel.session.processPath == nil) // the Print tab doesn't make negatives + } + + @Test func printerCalibrationGoesToThePrintTabOnThatPrinter() throws { + let r = root(tab: .printerCalibration) + let levels: [UInt16] = [0, 32768, 65535] + let calibration = try Calibration(levels: levels, curves: [[0, 30000, 65535], [0, 32768, 65535], [0, 34000, 65535]], + printer: "Canon_MG3600_series", paper: "Letter plain") + let path = folder.appendingPathComponent("calibrations/canon.oqcal") + try FileManager.default.createDirectory(at: path.deletingLastPathComponent(), withIntermediateDirectories: true) + try calibration.encode().write(to: path) + r.printModel.setPrinter("Epson_ET_2900") + r.useCalibration(path, scannerHost: "") + #expect(r.tab == .print && r.printModel.session.calibrationPath == nil) + #expect(r.notice?.contains("choose Canon MG3600") == true) + r.printModel.setPrinter("Canon_MG3600_series") + r.useCalibration(path, scannerHost: "") + #expect(r.printModel.session.calibrationPath?.lastPathComponent == "canon.oqcal") + #expect(r.notice?.hasPrefix("The Print tab now uses") == true) + } + + @Test func contactSheetsOpenInTheChosenTab() async throws { + let r = root(tab: .contactSheet) + r.negativeModel.setSafeEdge(0.5) + r.show(.contactSheet) + #expect(r.contactSheet.size(for: .print) == (7.5, 10) && r.contactSheet.size(for: .negative) == (6.5, 9)) + r.contactSheet.add([photo, photo]) + for _ in 0..<300 where r.contactSheet.busy { try await Task.sleep(for: .milliseconds(10)) } + var made: URL? + r.contactSheet.make(dpi: 20, for: .negative) { made = $0 } + for _ in 0..<300 where made == nil { try await Task.sleep(for: .milliseconds(10)) } + r.useContactSheet(try #require(made), for: .negative) + #expect(r.tab == .negative && r.negativeModel.session.photo?.width == 130 && r.printModel.session.photo == nil) + } + + @Test func workIsKeptForNextTimeOnlyWhenAsked() async throws { + let r = root() + #expect(r.workspace.isEmpty) + r.printModel.openPhoto(photo) + r.negativeModel.openPhoto(photo) + r.contactSheet.setLandscape(true) + r.contactSheet.update { $0.background = .white; $0.wedge = true } + r.contactSheet.add([photo]) + for _ in 0..<300 where r.contactSheet.busy { try await Task.sleep(for: .milliseconds(10)) } + try r.keepWorkspace() + + let next = root() + #expect(next.printModel.session.source == photo && next.negativeModel.session.source == photo) + for _ in 0..<300 where next.contactSheet.busy { try await Task.sleep(for: .milliseconds(10)) } + #expect(next.contactSheet.entries.count == 1 && next.contactSheet.landscape) + #expect(next.contactSheet.layout.background == .white && next.contactSheet.layout.wedge) + #expect(root().printModel.session.photo == nil) // reopened once; asked again at the next quit + + try r.keepWorkspace() + r.forgetWorkspace() // Start Fresh + #expect(root().printModel.session.photo == nil) + #expect(r.confirmQuit()) // not asking (tests): quits, keeping nothing + } + + @Test func loadingEstimatesTheTimeLeft() { + let start = Date(timeIntervalSince1970: 0) + var loading = ContactSheetModel.Loading(done: 0, total: 12, started: start, current: "frame-01.tif") + #expect(loading.description(now: start.addingTimeInterval(1)) == "Opening frame-01.tif (1 of 12)") + loading.done = 3 + loading.current = "frame-04.tif" + #expect(loading.secondsLeft(now: start.addingTimeInterval(6)) == 18) + #expect(loading.description(now: start.addingTimeInterval(6)) == "Opening frame-04.tif (4 of 12) · about 18 s left") + loading.done = 1 + #expect(loading.description(now: start.addingTimeInterval(30)).hasSuffix("about 6 min left")) + } +} diff --git a/swift/OpenQuadCore/Sources/OpenQuadCore/Session.swift b/swift/OpenQuadCore/Sources/OpenQuadCore/Session.swift index fb5cf1a..4068779 100644 --- a/swift/OpenQuadCore/Sources/OpenQuadCore/Session.swift +++ b/swift/OpenQuadCore/Sources/OpenQuadCore/Session.swift @@ -269,6 +269,9 @@ public struct AppSettings: Sendable, Equatable { public var maxSize: [Double]? /// Lengths shown in the app. public var units = LengthUnit.inches + /// The Negative tab's own printer and paper (nil: the ones above). + public var negativePrinter: String? + public var negativePaper: String? public init() {} @@ -296,6 +299,8 @@ public struct AppSettings: Sendable, Equatable { settings.negativeColour = object["negative_colour"] as? String ?? "green" if let size = object["max_size"] as? [NSNumber], size.count == 2 { settings.maxSize = size.map(\.doubleValue) } settings.units = (object["units"] as? String).flatMap(LengthUnit.init(rawValue:)) ?? .inches + settings.negativePrinter = object["negative_printer"] as? String + settings.negativePaper = (object["negative_paper"] as? String).flatMap { Paper.sizes[$0] != nil ? $0 : nil } return settings } @@ -306,6 +311,7 @@ public struct AppSettings: Sendable, Equatable { "calibration": calibration ?? NSNull(), "last_folder": lastFolder ?? NSNull(), "process": process ?? NSNull(), "negative_colour": negativeColour, "max_size": maxSize ?? NSNull(), "units": units.rawValue, + "negative_printer": negativePrinter ?? NSNull(), "negative_paper": negativePaper ?? NSNull(), ] var data = try JSONSerialization.data(withJSONObject: object, options: [.prettyPrinted, .sortedKeys]) data.append(0x0a) diff --git a/swift/OpenQuadCore/Tests/OpenQuadCoreTests/SessionParityTests.swift b/swift/OpenQuadCore/Tests/OpenQuadCoreTests/SessionParityTests.swift index 1849db8..53d002e 100644 --- a/swift/OpenQuadCore/Tests/OpenQuadCoreTests/SessionParityTests.swift +++ b/swift/OpenQuadCore/Tests/OpenQuadCoreTests/SessionParityTests.swift @@ -99,6 +99,8 @@ struct SessionParity { settings.scannerHost = "876298000000.local:80" settings.negativeColour = "orange" settings.units = .millimetres + settings.negativePrinter = "Epson_ET_2900" + settings.negativePaper = "A4" try settings.save(url) #expect(AppSettings.load(url) == settings) let text = try String(contentsOf: url, encoding: .utf8) diff --git a/tests/test_settings.py b/tests/test_settings.py index ad94f80..74b17e0 100644 --- a/tests/test_settings.py +++ b/tests/test_settings.py @@ -57,5 +57,6 @@ def test_max_size_is_remembered(tmp_path: Path) -> None: def test_units_are_remembered(tmp_path: Path) -> None: path = tmp_path / "settings.json" assert Settings.load(path).units == "in" - Settings(units="mm").save(path) - assert Settings.load(path).units == "mm" + Settings(units="mm", negative_printer="Epson", negative_paper="A4").save(path) + loaded = Settings.load(path) + assert (loaded.units, loaded.negative_printer, loaded.negative_paper) == ("mm", "Epson", "A4")