Skip to content

Commit

Permalink
fix: dzi viewer would loop forever due to some faulty math (#43)
Browse files Browse the repository at this point in the history
  • Loading branch information
froyo-np authored Nov 21, 2024
1 parent 3bb0274 commit 18bfce8
Show file tree
Hide file tree
Showing 3 changed files with 28 additions and 9 deletions.
2 changes: 1 addition & 1 deletion packages/dzi/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@alleninstitute/vis-dzi",
"version": "0.0.4",
"version": "0.0.5",
"contributors": [
{
"name": "Lane Sawyer",
Expand Down
11 changes: 11 additions & 0 deletions packages/dzi/src/loader.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ describe('tiling math', () => {
const pretend_max_image_width = 512;
expect(firstSuitableLayer(pretend_max_image_width, 4096)).toEqual(9);
});
it('never picks a layer that cant exist (negative layer indexes)', () => {
expect(firstSuitableLayer(512, 0.00001)).toEqual(0);
});
});
it('divide 512 into 2 chunks', () => {
const intervals = tileWithOverlap(512, 256, 1);
Expand Down Expand Up @@ -51,6 +54,14 @@ describe('tiling math', () => {
const size = imageSizeAtLayer(highsmith, 9);
expect(size).toEqual([220, 289]);
});
it('tilesInLayer does not loop indefinitly when given a nonsensical layer index', () => {
const size = imageSizeAtLayer(highsmith, -1);
expect(size).toEqual(imageSizeAtLayer(highsmith, 0));
});
it('tilesInLayer does not loop indefinitly when given a NAN layer index', () => {
const size = imageSizeAtLayer(highsmith, Number.NaN);
expect(size).toEqual(imageSizeAtLayer(highsmith, 0));
});
it('matches observed image dimensions (https://openseadragon.github.io/example-images/highsmith/highsmith.dzi) at layer 9', () => {
const tiles = tilesInLayer(highsmith, 9);
expect(tiles.length).toBe(2);
Expand Down
24 changes: 16 additions & 8 deletions packages/dzi/src/loader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ export function getVisibleTiles(dzi: DziImage, camera: { view: box2D; screenSize
export function firstSuitableLayer(imageWidth: number, screenWidth: number) {
const idealLayer = Math.ceil(Math.log2(screenWidth));
const biggestRealLayer = Math.ceil(Math.log2(imageWidth));
return Math.min(biggestRealLayer, idealLayer);
return Math.max(0, Math.min(biggestRealLayer, idealLayer));
}

/**
Expand Down Expand Up @@ -121,14 +121,22 @@ export function tileWithOverlap(total: number, step: number, overlap: number): I
function boxFromRowCol(row: Interval, col: Interval) {
return Box2D.create([col.min, row.min], [col.max, row.max]);
}

const logBaseHalf = (x: number) => Math.log2(x) / Math.log2(0.5);

export function imageSizeAtLayer(dzi: DziImage, layer: number) {
const { size } = dzi;
const layerMaxSize = 2 ** layer;
let total: vec2 = [size.width, size.height];
while (total[0] > layerMaxSize || total[1] > layerMaxSize) {
total = Vec2.ceil(Vec2.scale(total, 1 / 2));
}
return total;
const { size: dim } = dzi;
const layerMaxSize = 2 ** (isFinite(layer) ? Math.max(0, layer) : 0);
const size: vec2 = [dim.width, dim.height];
// the question is how many times do we need to divide size
// by 2 to make it less than layerMaxSize?
// solve for N, X = the larger the image dimensions:
// X * (0.5^N) <= maxLayerSize ...
// 0.5^N = maxLayerSize/X ...
// log_0.5(maxLayerSize/X) = N
const bigger = Math.max(size[0], size[1]);
const N = Math.ceil(logBaseHalf(layerMaxSize / bigger));
return Vec2.ceil(Vec2.scale(size, 0.5 ** N));
}
export function tilesInLayer(dzi: DziImage, layer: number): box2D[][] {
const { overlap, tileSize } = dzi;
Expand Down

0 comments on commit 18bfce8

Please sign in to comment.