Releases: jboneng/pyopticfilm
Releases · jboneng/pyopticfilm
Release list
v1.3.3
[1.3.3] - 2026-08-30
Added
- Model-lock tests (
tests/model_lock/): frozen 8200i SE driver-path oracles (geometry, crop mapping, dummy trim, slope-table feed order, ME configure, Scan Lab window kwargs). Other-model fixes must specialize that model rather than retarget these asserts. Run withuv run pytest -m model_lock.
Fixed
- ME short/long width mismatch: content-aware ENDPIXEL dummy trim could drop a different column count on short vs long (and IR) because edge DN differs — especially at 3600 dpi where the cap is larger. Multi-pass now discovers the drop on the short/first colour plane and reuses it for long and IR assemble so merge/align see matching widths. Single-pass stays content-aware.
v1.3.2
[1.3.2] - 2026-08-30
Fixed
- Scan Lab Prescan crop: a click or too-small rubber-band no longer clears a committed crop (right-click to clear). Scan builds the hardware window on the GUI thread and logs
crop appliedvsfull windowso a dropped crop cannot silently scan the safe window (including ME/IR passes). - Scan Lab Prescan crop X mapping: the rubber-band is in mirrored display space. Mapping now flips X back to TA so Color short / ME / IR match the box (cropping the right film base no longer cuts the left).
- Left-edge frame clip: a fixed ENDPIXEL dummy drop was removing 16/24 px of film gate after
mirror_x. Assemble now trims only columns that look like USB dummy, capped at the old width. - 8200i SE horizontal framing: image STR/END are shifted by 96 native clocks (
optical_end_inactive_native) toward ENDPIXEL so dummy-trim +mirror_xno longer clips the film gate on the left while showing extra holder on the right. USB span /line_bytesstay the same; shading still tracks the image window. - 8200i SE positioning slope tables: SilverFast uploads
SLOPE_TABLE_SLOWfor the first (reference) feed andSLOPE_TABLE_FASTfor the second (final positioning) feed — 39/39 capture pairs. pyopticfilm previously used the fast ramp for both. The V2-onlyuse_slow_final_positioning_feedflag is no longer onModel8200iSE(8100 V2 still uses fast-then-slow).
Changed
- 8200i SE priming default:
default_gl128_primeis nowFalse(same as the 8100 V2).Scanner.scan()withgl128_primeunset skips the discarded first-scan AGOHOME-park pass. Explicitgl128_prime=Truestill primes.
Contributors
- @TobbyTravel for default priming off on the 8100 V2 and for scoping the slow-second-feed slope-table fix to V2.
v1.3.1
[1.3.1] - 2026-08-29
Added
- Manual exposure overrides (GL128):
Scanner.scan(single_pass_exposure=..., me_short_exposure=..., me_long_exposure=...)send an exactREG_EXPOSUREfor the retained single-pass, ME short, or ME long pass, bypassing adaptive selection, PPI clamp, andme_hardware_max_exposure.me_long_exposuretakes precedence overme_exposure_mode. Values are validated for the 24-bit register range (1–0xFFFFFF); out-of-range values raiseValueError. All three default toNone(unchanged behavior) and never apply to the discarded GL128 priming pass. Scan Lab exposes matching Manual exposure overrides fields. - GL128 priming-pass override:
Scanner.scan(gl128_prime=False)skips the discarded first-scan AGOHOME-park pass for that call (debug/testing only — expect ~30 px of first-scan position drift). Skipping does not mark the scanner as primed, so a later call without the override still primes normally.ScanStatus/on_statusgains"prime_skipped". Defaults toTrue(unchanged behavior). Scan Lab Disable priming pass (debug) applies to Prescan and Scan.
Fixed
- Cropped 8200i SE ENDPIXEL dummy suffix: STR/END are computed in native 7200 dpi clocks (session 03 origin STR 242 / END 10610; same crop keeps STR/END at 1800 and 3600). The last ~24 output columns at 1800 (96 native clocks; image left after
mirror_x) are a per-line USB dummy suffix plus the invert-white transition — shrinkingENDPIXELdoes not remove them. Decode drops that fixed width after shading; USBline_bytesstays locked to the programmed span. Heuristic post-decode edge trim is not used (pcap 7200 URB-wider-than-span trim stays). IR column flatten still uses inset edge levels and a gain cap so residual edge samples cannot blow up to ~56k. Pass registration fills shift borders from interior columns instead of replicating padding (which widened the IR bright band and caused NegPy ICE over-repaint). Scan Lab surfaces IR align shift in the status bar / IR caption. - OpticFilm 8100 (V2) geometry/timing: five constants inherited from the 8200i SE without V2 capture proof are now V2-specific —
feed_to_scan_steps13128 (was 13704; fixes ~1 mm clipped at the top of full-frame scans), 7200 dpiLPERIOD16035 (was 15963), 7200 white-shading strip dummy clock 0x10 (was 0x17),max_image_lincnt_by_feed2{13128: 29012} (was SE preview entry 4836), andladder_feed2_steps13128 (was SE 13560). - GL128 consecutive-scan AFE strip timeout: after an image pass, stationary AFE START could hang for 5s at status
0xcd(home, buffer empty, lamp on, motor still enabled). Scan Lab reportedAFE strip: no stationary data ready within 5s (last status=0xcd)— including 1800→3600 with the same crop (DPI cache miss remesures calib). Stationary acquires now abort START, confirm SCAN/motor-off from hardware (park leaves0x02armed), program session-03 dark-strip clocks, write SCAN absolutely, and retry START once. Colour shading remesure reuses existing AFE codes when the last search was colour.
Changed
- GL128 AFE zero-collapse recovery logs now name which offset/gain components collapsed, which fallback was used, and warn when image colour may be degraded.
Contributors
- @TobbyTravel for OpticFilm 8100 (V2) capture-derived geometry/timing fixes and for GL128 manual exposure overrides, priming-pass skip, and improved AFE zero-collapse diagnostics.
v1.3.0
[1.3.0] - 2026-08-27
Added
- GL128 first-scan priming: before the first retained scan after open, run a discarded small pass (default 600 dpi, area
(0, 0, 1, 0.12)) so image-passAGOHOMEparks the carriage for repeatable start position. Override withPOF_GL128_PRIME(fullor<dpi>:x0,y0,x1,y1). - Adaptive ME long exposure (GL128): after the short colour pass, choose a frame-specific long
REG_EXPOSUREfrom RGB dense percentiles, then clamp through a separate safety envelope (42k–85k, max ratio 7×). Failures fall back to fixed 42000. Opt out withme_exposure_mode="fixed". - Scan Lab Fixed 42k long (A/B) checkbox; USB/status log shows proposed / selected long exposure and clamp reason.
MeScanDebug.exposure_proposed/exposure_reasonfor lab observability.- Optional
on_statuscallback onScanner.scanand exportedScanStatus("priming"/"scanning") so hosts can show GL128 priming; Scan Lab status bar and USB log surface it.
Fixed
- GL128 discarded priming pass always forces
geometry=None,apply_calib=False, andmode="color", so hosts that pass bring-upgeometry(e.g. Scan Lab) no longer stretch the prime into a full request-PPI shading+scan cycle. - GL128 adaptive quiet USB drain now sleeps the full
LPERIODdeficit (plus a small lag) instead of capping at 3 ms/line, so 7200 dpi image creep is no longer ~15% ahead of the ASIC line clock.
Changed
- GL128 multi-exposure colour-long
REG_EXPOSUREis clamped by PPI (8200i SE + 8100 V2): max 42000 at 7200 dpi (SilverFast known-good); 14000–85000 at other resolutions. - PyPI development status classifier is now 4 - Beta (was 3 - Alpha).
- README now points the "Latest release" link at v1.3.0.
- README and
docs/now document the hardware-tested set as 8200i SE + 8100 (V2) (and distinguish GL845 810007b3:130cfrom GL128 8100 V207b3:1824). - Comments, docstrings, and user-facing errors now describe the two-model scan-ready set; Scan Lab README matches. Internal bring-up helper renamed
is_opticfilm_8200i_se→is_gl128_opticfilm. - ME long-pass pixel clocks are selected via an explicit long-pass flag (not only
exposure >= 42000);REG_EXPOSUREis hard-clamped tome_hardware_max_exposureat configure time.
Contributors
- @TobbyTravel for GL128 first-scan priming and for OpticFilm 8100 (V2) exposure-ladder research showing
REG_EXPOSUREhas no hardware ceiling and that the multi-exposure long bin should be raised toward film-dependent ~56–64k targets (not a 42k limit).
v1.2.0
[1.2.0] - 2026-08-24
Added
- OpticFilm 8100 (V2) (
07b3:1824) support: GL128 sibling of the 8200i SE, hardware-validated for single-pass and multi-exposure colour scans. The 8100 V2 has no infrared channel / iSRD, soinfrared=Trueandmode="infrared"raise a clearScanError(multi-exposure short+long bracket remains available). Model8100V2/MODEL_8100_V2(subclass ofModel8200iSE; register tables, geometry and motor clamps inherited from the capture-validated SE).- IR capability guard in
Gl128ScanSession.runfor models withsupports_infrared=False. examples/scan.py: barebones interactive Python CLI example for enumerating scanners, selecting a device, choosing PPI, optionally enabling ME / IR where supported, and saving 16-bit TIFF output.
Changed
- Scan validation set is now 8200i SE + 8100 (V2); tests updated from "SE only" to the two-model validated set.
- README hardware support docs now cover the newly validated 8100 V2 path.
Contributors
- @TobbyTravel for the OpticFilm 8100 (V2) enablement, validation updates, version bump, and release documentation polish.
v1.1.2
[1.1.2] - 2026-08-22
Added
- Multi-exposure (ME) scanning for OpticFilm 8200i SE (GL128): short and long colour passes with host SNR/IVW merge into the deliverable
ScanImage.rgb. MeScanDebugandScanner.last_me_debugfor lab-only bracket planes, fusion stats, and pass alignment shifts (not part of the publicScanImagetype).- Scan Lab (
tools/scanlab/): PyQt6 bring-up GUI (mock or real SE), prescan crop, IR pass, ME tabs, USB log, pcap decode, calib cache controls, and adaptive quiet-drain toggle. docs/negpy-integration.md: integrator guide for scan orientation,ScanImagecontract, and NegPy migration notes.- Adaptive quiet USB drain default on GL128 (
DEFAULT_IMAGE_USB_PACE_S, line-aligned throttle in bulk acquire). tools/audit_me_bracket: bracket TIFF audit;--alignreports estimated pass shift and post-align luma residual.- Mock scanner tests and expanded geometry / pipeline test coverage.
opencv-python-headlessin thelabdependency group for ME/IR pass registration in Scan Lab.
Fixed
- Scan orientation on
mirror_xmodels (8200i SE): left–right correction inImagePipeline.assemble(); prescan crop no longer applies a compensating X flip. - ME shadow colour fringes from short/long misregistration: improved OpenCV phase-correlation alignment (AREA downsampling, ROI refinement), merge guard at misaligned edges, and chunked IVW merge to avoid float32 OOM at 3600+ dpi.
- High-PPI memory use in the image pipeline (integer oversample sums, chunked host calib / film-base makeup / border clamp).
- 8200i SE IR scans: correct colour DVDSET handling, flattened green IR plane on
ScanImage.ir, grayscale preview in Scan Lab. - Scan Lab: crop UI limited to Prescan tab; missing
busy_changedworker signal; effective crop status in status bar.
Changed
ScanImageslimmed to NegPy-facing fields only (rgb,dpi,device_model, optionalir). ME bracket data moved toScanner.last_me_debug.- ME short/long planes stay linear on the bracket; film-base makeup runs once on the merged deliverable.
- Non-SE bring-up: short Y travel clamps, USB planar RGB toggle, and SANE-aligned session improvements for experimental models.
Notes for integrators
- Forward-only orientation fix: scans saved before 1.1.2 may still appear mirrored on disk; rescan if orientation matters.
- NegPy / other apps: consume
ScanImage.rgb/iras returned; do not apply an extra[:, ::-1]flip or prescan crop mirror compensation. See docs/negpy-integration.md. - Breaking: removed
ScanImageME fields (rgb_short,rgb_long,exposure_*,merge_*,align_shift_*). UseScanner.last_me_debugfor bracket inspection.