feat: implement reference image comparison tools and upload functionality
This commit is contained in:
parent
bac6d4c107
commit
fb72ef6dc4
1 changed files with 64 additions and 0 deletions
|
|
@ -290,6 +290,70 @@ src/
|
|||
- Excel export (multi-sheet styled workbook)
|
||||
- Deadline tracking (approaching/overdue detection + notifications)
|
||||
|
||||
### Phase 3b: Reference Image Comparison (Markup Review)
|
||||
- **Reference image upload** — attach reference/approved images to any revision round. Stored via the existing `attachments` JSON field on `Revision`, with file upload to local storage (Phase 1) or S3/Cloud (production). Supports PNG, JPG, WebP up to 10MB.
|
||||
- **Current render upload** — upload the current WIP render alongside the reference for direct comparison. Each revision round can have a "reference" image and a "current" image.
|
||||
- **A-B comparison slider** — draggable vertical divider overlaying reference (left) and current (right) images. User drags to reveal/hide each side. Built as a `<ImageCompareSlider>` component using pointer events + CSS clip-path. No external dependency needed.
|
||||
- **Toggle mode** — click/tap to flip between reference and current image (full-frame swap with crossfade transition). Keyboard shortcut: `Space` to toggle. Useful on smaller screens where the slider is impractical.
|
||||
- **Side-by-side mode** — display both images at equal size in a horizontal split. Synced zoom/pan so both images move together. Default on wide screens.
|
||||
- **Zoom & pan** — scroll-to-zoom with pinch support. Pan by click-drag when zoomed. Zoom level synced across both images in all comparison modes.
|
||||
- **Image gallery per revision** — revision rounds accumulate images over time. Gallery shows all uploaded images for the stage across rounds, with round number labels. Quick-select any past round's image as the reference for comparison.
|
||||
- **Context in StageDetailSheet** — new "Compare" tab in the stage detail sheet (alongside existing Revisions and Comments tabs). Comparison tools live here. Selecting a revision round auto-loads its images.
|
||||
- **Lightweight markup overlay** (optional enhancement) — basic annotation tools (arrow, rectangle, freehand, text pin) drawn on top of the current image. Annotations saved as JSON on the revision. Not a full drawing app — just enough to point at problems.
|
||||
|
||||
#### Data Model Changes
|
||||
```
|
||||
// Extend Revision.attachments JSON schema:
|
||||
{
|
||||
referenceImage?: { url: string, filename: string, size: number, uploadedAt: string },
|
||||
currentImage?: { url: string, filename: string, size: number, uploadedAt: string },
|
||||
annotations?: Array<{ type: "arrow"|"rect"|"freehand"|"pin", points: number[], text?: string, color: string }>
|
||||
}
|
||||
```
|
||||
|
||||
#### New API Endpoints
|
||||
```
|
||||
POST /api/stages/:stageId/revisions/:revisionId/upload — multipart form upload (reference or current image)
|
||||
DELETE /api/stages/:stageId/revisions/:revisionId/upload — remove an uploaded image
|
||||
```
|
||||
|
||||
#### New Components
|
||||
```
|
||||
src/components/revisions/
|
||||
├── image-compare-slider.tsx — A-B slider with drag handle
|
||||
├── image-toggle.tsx — Toggle/crossfade between two images
|
||||
├── image-side-by-side.tsx — Synced side-by-side with zoom/pan
|
||||
├── image-upload-zone.tsx — Drag-and-drop upload for reference/current
|
||||
├── revision-image-gallery.tsx — Browse images across revision rounds
|
||||
├── compare-tab.tsx — Orchestrator: mode selector + comparison view
|
||||
└── markup-overlay.tsx — Lightweight annotation layer (optional)
|
||||
```
|
||||
|
||||
#### PNG Transparency Handling
|
||||
CG renders are typically PNGs with transparent backgrounds and semi-transparent drop shadows. When two transparent PNGs are layered in comparison modes (slider, toggle, overlay), the shadows multiply and produce incorrect visual results — making review unreliable.
|
||||
|
||||
**Solution: server-side alpha compositing on upload.**
|
||||
- On the upload endpoint, detect if the image is a PNG with an alpha channel (check IHDR color type via `sharp` or raw buffer inspection).
|
||||
- If alpha is present, composite the image onto a solid **white (#FFFFFF) background** using `sharp.flatten({ background: '#FFFFFF' })` before storing.
|
||||
- Store the flattened version as the comparison-ready image. Optionally keep the original transparent PNG as a separate `originalUrl` for download purposes.
|
||||
- JPG and WebP uploads (no alpha) skip this step — no processing needed.
|
||||
- This happens once at upload time, not at render time — avoids per-view processing cost and ensures all comparison modes work correctly without CSS hacks.
|
||||
|
||||
```
|
||||
// Upload processing pipeline (pseudo):
|
||||
const img = sharp(buffer);
|
||||
const metadata = await img.metadata();
|
||||
if (metadata.format === 'png' && metadata.hasAlpha) {
|
||||
buffer = await img.flatten({ background: '#FFFFFF' }).png().toBuffer();
|
||||
}
|
||||
```
|
||||
|
||||
#### UX Notes
|
||||
- Images are almost never reviewed in isolation — the reference comparison is the primary review workflow. The compare tab should be the default/first tab when images exist.
|
||||
- Default to slider mode on desktop, toggle mode on mobile.
|
||||
- Reference images persist across rounds (the approved reference doesn't change until a new one is set). Current images update each round.
|
||||
- Empty state: prompt to upload a reference image with a clear CTA. Show how comparison works with a placeholder illustration.
|
||||
|
||||
### Phase 4: Polish
|
||||
- Command palette (Cmd+K search)
|
||||
- Bulk operations (multi-select in table → bulk status/assignment/priority)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue