fix(capture): punch tape cutout in-place; drop maskedPreview swap
ca983c4 painted mask via offscreen createImageData→drawImage and swapped
Measure to an async alpha PNG. On some clients that left the Zoom/Pan
stage showing only the CSS checkerboard with no slab pixels.
Paint the approved mask by mutating the photo bitmap in place (same as
Mask/SessionCapture): tape mode clears non-slab alpha so the stage grid
shows through; bbox mode still paints opaque checkerboard. Measure binds
source+bitset like Axis — no createMaskedPreviewBlob race. onMount redraw
covers the canvas-bind tick race.
This commit is contained in:
@@ -8,7 +8,6 @@
|
||||
import PhotoStage from './PhotoStage.svelte';
|
||||
import { getCropFill, setCropFill } from '../settings/cropFill';
|
||||
import { cropMarginFraction } from '../png/crop';
|
||||
import { createMaskedPreviewBlob } from '../png/maskedPreview';
|
||||
import { getTaxonomy } from '../api/slabs';
|
||||
import { speciesLeavesFromTaxonomy } from '../create/settings/speciesLeaves';
|
||||
import {
|
||||
@@ -44,40 +43,6 @@
|
||||
$: tape = state.axis.tape;
|
||||
$: tiltShown = Math.round(tape.tiltDeg * 10) / 10;
|
||||
|
||||
let maskedPreview: Blob | null = null;
|
||||
let previewError = '';
|
||||
let previewGeneration = 0;
|
||||
let previewSource: Blob | null = null;
|
||||
let previewMask: Uint8Array | null = null;
|
||||
let previewW = 0;
|
||||
let previewH = 0;
|
||||
|
||||
// Build the tape photo once from the oriented source plus the approved mask.
|
||||
// Never fall back to the raw source here: tape alignment must show the same
|
||||
// background-removed slab footprint that was approved in Mask.
|
||||
$: {
|
||||
const sourceBlob = state.source.blob;
|
||||
const bitset = state.approvedMask.bitset;
|
||||
const width = state.source.widthPx;
|
||||
const height = state.source.heightPx;
|
||||
if (sourceBlob !== previewSource || bitset !== previewMask || width !== previewW || height !== previewH) {
|
||||
previewSource = sourceBlob;
|
||||
previewMask = bitset;
|
||||
previewW = width;
|
||||
previewH = height;
|
||||
maskedPreview = null;
|
||||
previewError = '';
|
||||
const generation = ++previewGeneration;
|
||||
void createMaskedPreviewBlob(sourceBlob, bitset)
|
||||
.then((blob) => {
|
||||
if (generation === previewGeneration) maskedPreview = blob;
|
||||
})
|
||||
.catch(() => {
|
||||
if (generation === previewGeneration) previewError = 'Could not build the background-removed preview.';
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
let lineupUrls: string[] = [];
|
||||
let lineupItems: PhotosReadyLineupItem[] = [];
|
||||
|
||||
@@ -128,7 +93,6 @@
|
||||
});
|
||||
|
||||
onDestroy(() => {
|
||||
previewGeneration += 1;
|
||||
for (const u of lineupUrls) URL.revokeObjectURL(u);
|
||||
});
|
||||
|
||||
@@ -228,12 +192,14 @@
|
||||
{/if}
|
||||
</p>
|
||||
|
||||
<!-- Cutout first: source + maskBitset paints checkerboard immediately (tape mode).
|
||||
When createMaskedPreviewBlob finishes, swap to alpha PNG (same footprint). -->
|
||||
<!-- Same binding as Mask/Axis: oriented source + approved bitset.
|
||||
PhotoStage tape mode punches non-slab alpha so the stage CSS checkerboard
|
||||
shows through — no async createMaskedPreviewBlob swap (that path could
|
||||
leave an empty/transparent canvas if encode hung or composited wrong). -->
|
||||
<PhotoStage
|
||||
mode="tape"
|
||||
blob={maskedPreview ?? state.source.blob}
|
||||
maskBitset={maskedPreview ? null : state.approvedMask.bitset}
|
||||
blob={state.source.blob}
|
||||
maskBitset={state.approvedMask.bitset}
|
||||
{maskW}
|
||||
{maskH}
|
||||
{tape}
|
||||
@@ -241,9 +207,6 @@
|
||||
{gestureMode}
|
||||
onTapeChange={onTapeChange}
|
||||
/>
|
||||
{#if previewError}
|
||||
<p class="preview-err" role="status">{previewError}</p>
|
||||
{/if}
|
||||
|
||||
<div class="controls">
|
||||
<div>
|
||||
@@ -451,7 +414,6 @@
|
||||
.mode-btn.active { background: #00e5ff; color: #002; }
|
||||
.mode-hint { margin: 0 0 10px; }
|
||||
.nudge { color: #e8a; font-size: 0.74rem; margin: 6px 0 0; line-height: 1.45; }
|
||||
.preview-err { color: #ffb4a2; font-size: 0.85rem; margin: 8px 0 0; }
|
||||
.controls { margin-top: 16px; display: flex; flex-direction: column; gap: 14px; }
|
||||
.ctl-label { font-size: 0.78rem; color: #aaa; margin: 0 0 6px; }
|
||||
.ctl-label .sub { font-size: 0.7rem; color: #777; }
|
||||
|
||||
Reference in New Issue
Block a user