diff options
| author | Adam Soltys <[email protected]> | 2026-10-05 10:20:53 -0700 |
|---|---|---|
| committer | Adam Soltys <[email protected]> | 2026-10-05 10:20:53 -0700 |
| commit | 1037f1793377b5159108efebc985b9e449eaef31 (patch) | |
| tree | 95bd8a6a15f1f45799cabeeee183f43395f2a200 | |
| parent | 0611d3b3b3e94089218da867e4530234f9248d3f (diff) | |
| download | coinosv3-1037f1793377b5159108efebc985b9e449eaef31.tar.gz coinosv3-1037f1793377b5159108efebc985b9e449eaef31.zip | |
Images grid tiles are cut from the feed's own decode: scrolling All fills the tile cache (3/30 → 22/30 tiles instant on #art)
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01YRC6aKhwAud231ot9FPmhi
| -rw-r--r-- | src/features/messages.js | 38 |
1 files changed, 22 insertions, 16 deletions
diff --git a/src/features/messages.js b/src/features/messages.js index d18a0b2..86b6c75 100644 --- a/src/features/messages.js +++ b/src/features/messages.js @@ -5486,6 +5486,9 @@ export function messagesFeature(ctx) { let bmp; try { bmp = await createImageBitmap(blob); } catch { return null; } const dims = { width: bmp.width, height: bmp.height }; + // the Images grid's square comes from the same decode: scrolling the + // feed fills the grid's cache, no second download + if (!/gif/i.test(blob.type) && !tileThumbs.has(url)) await tileFromBitmap(url, bmp).catch(() => {}); // small enough already, or animated (a GIF's copy would be one frame): // remember the shape and paint the original const keep = bmp.width <= MEDIA_THUMB_W * 1.25 || /gif/i.test(blob.type); @@ -10122,22 +10125,25 @@ export function messagesFeature(ctx) { if (/gif/i.test(blob.type)) return; // animated: the tile shows the original let bmp; try { bmp = await createImageBitmap(blob); } catch { return; } - try { - const side = Math.min(bmp.width, bmp.height); - const px = Math.min(TILE_PX, side); - const sq = await createImageBitmap(bmp, (bmp.width - side) / 2, (bmp.height - side) / 2, side, side, - { resizeWidth: px, resizeHeight: px, resizeQuality: 'high' }); - const c = new OffscreenCanvas(px, px); - c.getContext('2d').drawImage(sq, 0, 0); - try { sq.close(); } catch {} - let out = await c.convertToBlob({ type: 'image/webp', quality: 0.8 }); - if (!/webp/.test(out.type)) out = await c.convertToBlob({ type: 'image/jpeg', quality: 0.8 }); - tileThumbs.set(url, URL.createObjectURL(out)); - const store = await tileStore(); - await store.put(tileKey(url), new Response(out, { headers: { 'content-type': out.type } })); - const keys = await store.keys(); - if (keys.length > TILE_MAX) for (const k of keys.slice(0, keys.length - TILE_MAX + 100)) store.delete(k); - } catch {} finally { try { bmp.close(); } catch {} } + try { await tileFromBitmap(url, bmp); } catch {} finally { try { bmp.close(); } catch {} } + } + // A tile's square, cut from a decoded picture and kept (the caller closes it). + async function tileFromBitmap(url, bmp) { + if (typeof OffscreenCanvas === 'undefined' || typeof caches === 'undefined') return; + const side = Math.min(bmp.width, bmp.height); + const px = Math.min(TILE_PX, side); + const sq = await createImageBitmap(bmp, (bmp.width - side) / 2, (bmp.height - side) / 2, side, side, + { resizeWidth: px, resizeHeight: px, resizeQuality: 'high' }); + const c = new OffscreenCanvas(px, px); + c.getContext('2d').drawImage(sq, 0, 0); + try { sq.close(); } catch {} + let out = await c.convertToBlob({ type: 'image/webp', quality: 0.8 }); + if (!/webp/.test(out.type)) out = await c.convertToBlob({ type: 'image/jpeg', quality: 0.8 }); + tileThumbs.set(url, URL.createObjectURL(out)); + const store = await tileStore(); + await store.put(tileKey(url), new Response(out, { headers: { 'content-type': out.type } })); + const keys = await store.keys(); + if (keys.length > TILE_MAX) for (const k of keys.slice(0, keys.length - TILE_MAX + 100)) store.delete(k); } // newest first, a few at a time; the grid repaints as a batch lands function queueTileThumbs(urls) { |
