fix(library): draw a .tif tile on the wall's own route
Two things kept a scanned `.tif` off the wall, and both had to be fixed for its tile to come out as a picture. CanvasKit was never up on the catalogue's route: the studio boots it when the workspace mounts, but a visitor who only ever opens the library never does, so the JPEG inside the file had no decoder and the tile was drawn as nothing. The `.tif` branch now brings the engine up itself. And the pixels were being read out of that JPEG through an image `readPixels` handed a buffer of ours, which CanvasKit answers by throwing rather than filling — the frame came back black to a check on the return value. It now takes the buffer CanvasKit hands back, the form the canvas calls in this repo have always used. Measured in the browser on a 5472x3648 JPEG-compressed scan: the tile went from 2378 bytes of solid black to 68670 bytes at mean 189.2 sd 74.6, against the 189.3/74.6 the same picture's uncompressed copy yields. `scripts/tiff-decode-check.mjs` gains the fixture that was broken — a JPEG-compressed strip — judged by how far a channel strays from the libvips reference rather than by equality, since that strip is lossy. Its bundle now re-exports the shim alongside the reader so the two are one module instance and the fixture's JPEG has a decoder behind it.
This commit is contained in:
@@ -54,7 +54,7 @@ import LibRaw from 'libraw-wasm';
|
||||
import { sensorWhite } from './sensorWhite';
|
||||
import { f32ToF16 } from './halfFloat';
|
||||
import { toneMatch, FLAT_TONE, MATCH_GRID } from './previewMatch';
|
||||
import { Skia } from './skiaShim';
|
||||
import { Skia, initSkia } from './skiaShim';
|
||||
import { decodeTiff } from './tiffDecode';
|
||||
|
||||
// What `imageData()` returns for the settings below: 16-bit, 3 channels, black
|
||||
@@ -371,7 +371,13 @@ export async function rawThumbnail(bytes: Uint8Array, fileName?: string): Promis
|
||||
// hiding in it — scanning the bytes for one finds the frame's own pixel data
|
||||
// and hands back three hundred kilobytes of it dressed as a JPEG, which is
|
||||
// what the wall used to keep as the frame's tile and draw as nothing.
|
||||
if (fileName && /\.(tiff?)$/i.test(fileName)) return tiffThumbnail(bytes);
|
||||
if (fileName && /\.(tiff?)$/i.test(fileName)) {
|
||||
// CanvasKit is what draws the JPEG inside one, and the catalogue has a route
|
||||
// of its own: the studio boots the engine, a visitor who only ever opens the
|
||||
// wall never does, and a tile read before it is up draws as nothing.
|
||||
if (!Skia) await initSkia({ locateFile: (file) => `/wasm/${file}` });
|
||||
return tiffThumbnail(bytes);
|
||||
}
|
||||
|
||||
const fast = extractEmbeddedJpeg(bytes);
|
||||
if (fast) return fast;
|
||||
|
||||
@@ -238,19 +238,23 @@ export function decodeTiff(bytes: Uint8Array, maxSide: number): TiffFrame | null
|
||||
const w = image.width();
|
||||
const h = image.height();
|
||||
if (!w || !h) return null;
|
||||
const data = new Uint8Array(w * h * 4);
|
||||
const done = image.readPixels(
|
||||
0, 0,
|
||||
{
|
||||
width: w,
|
||||
height: h,
|
||||
colorType: Skia.ColorType.RGBA_8888,
|
||||
alphaType: Skia.AlphaType.Unpremul,
|
||||
colorSpace: Skia.ColorSpace.SRGB,
|
||||
},
|
||||
data, w * 4,
|
||||
);
|
||||
return done ? { kind: 'rgba', width: w, height: h, data } : null;
|
||||
// CanvasKit's image `readPixels` only takes its own buffer: handed one of
|
||||
// ours it throws, and the frame came back black to a check on its return
|
||||
// value (measured on a 5472x128 strip of a JPEG-compressed scan).
|
||||
const px = image.readPixels(0, 0, {
|
||||
width: w,
|
||||
height: h,
|
||||
colorType: Skia.ColorType.RGBA_8888,
|
||||
alphaType: Skia.AlphaType.Unpremul,
|
||||
colorSpace: Skia.ColorSpace.SRGB,
|
||||
});
|
||||
if (!px) return null;
|
||||
return {
|
||||
kind: 'rgba',
|
||||
width: w,
|
||||
height: h,
|
||||
data: new Uint8Array(px.buffer, px.byteOffset, px.byteLength),
|
||||
};
|
||||
} finally {
|
||||
image.delete();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user