History

fix(web): sample the SnapShot band at the one frame aspect every surface uses

sampleSnapShotBottomColor accepted a frame aspect but cached by URL alone, so a second aspect would have read the first one's result. Every surface renders the capture in the same frame, so the parameter is gone and the per-URL cache is correct by construction.

Julius Marminge committed 2 months ago

Commit a534f651 parent 57a00a61 file · +7 −11Browse files

Unified · Split

apps/web/src/lib/snapShotOverlayTone.ts+7−11
@@ -107,7 +107,7 @@ export function coverCrop( · 106 unmodified lines
107 return { x: 0, y: (height - cropHeight) / 2, width, height: cropHeight };107 return { x: 0, y: (height - cropHeight) / 2, width, height: cropHeight };
108}108}
109 109
110function readBottomBand(image: HTMLImageElement, frameAspect: number): RgbColor | null {110function readBottomBand(image: HTMLImageElement): RgbColor | null {
111 const { naturalWidth: width, naturalHeight: height } = image;111 const { naturalWidth: width, naturalHeight: height } = image;
112 if (width === 0 || height === 0) return null;112 if (width === 0 || height === 0) return null;
113 const canvas = document.createElement("canvas");113 const canvas = document.createElement("canvas");
@@ -115,7 +115,7 @@ function readBottomBand(image: HTMLImageElement, frameAspect: number): RgbColor · 1 unmodified line
115 canvas.height = SAMPLE_HEIGHT;115 canvas.height = SAMPLE_HEIGHT;
116 const context = canvas.getContext("2d", { willReadFrequently: true });116 const context = canvas.getContext("2d", { willReadFrequently: true });
117 if (context === null) return null;117 if (context === null) return null;
118 const crop = coverCrop(width, height, frameAspect);118 const crop = coverCrop(width, height, SNAP_SHOT_FRAME_ASPECT);
119 const bandHeight = Math.max(1, crop.height * SAMPLE_BAND);119 const bandHeight = Math.max(1, crop.height * SAMPLE_BAND);
120 // Drawing the band into a tiny canvas lets the rasterizer do the averaging.120 // Drawing the band into a tiny canvas lets the rasterizer do the averaging.
121 context.drawImage(121 context.drawImage(
@@ -139,22 +139,18 @@ function readBottomBand(image: HTMLImageElement, frameAspect: number): RgbColor · 17 unmodified lines
139 139
140/**140/**
141 * Average color of the bottom band of the region the thumbnail frame shows, or141 * Average color of the bottom band of the region the thumbnail frame shows, or
142 * null when the image cannot be loaded or read. Results are memoized per URL142 * null when the image cannot be loaded or read. Every surface renders the
143 * so the surfaces that show the same capture decode it once.143 * capture in the same frame, so results are memoized per URL and the surfaces
144 * that show the same capture decode it once.
144 */145 */
145export function sampleSnapShotBottomColor(146export function sampleSnapShotBottomColor(src: string): Promise<RgbColor | null> {
146 src: string,
147 frameAspect = SNAP_SHOT_FRAME_ASPECT,
148): Promise<RgbColor | null> {
149 const cached = sampleCache.get(src);147 const cached = sampleCache.get(src);
150 if (cached) return cached;148 if (cached) return cached;
151 const pending = new Promise<RgbColor | null>((resolve) => {149 const pending = new Promise<RgbColor | null>((resolve) => {
152 const image = new Image();150 const image = new Image();
153 image.crossOrigin = "anonymous";151 image.crossOrigin = "anonymous";
154 image.decoding = "async";152 image.decoding = "async";
155 image.addEventListener("load", () => resolve(readBottomBand(image, frameAspect)), {153 image.addEventListener("load", () => resolve(readBottomBand(image)), { once: true });
156 once: true,
157 });
158 image.addEventListener("error", () => resolve(null), { once: true });154 image.addEventListener("error", () => resolve(null), { once: true });
159 image.src = src;155 image.src = src;
160 });156 });

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t