From f59a1bf609592ebe78597ae67a826db20aa2dc6e Mon Sep 17 00:00:00 2001
From: Blayne Chard <bchard@linz.govt.nz>
Date: Wed, 29 Jan 2025 16:16:35 +1300
Subject: [PATCH] refactor: default to libvips for lzw decoding

---
 .../pipeline/__tests__/decompress.lzw.test.ts   | 17 +++++++----------
 .../src/pipeline/decompressor.lzw.ts            | 12 +-----------
 .../tiler-sharp/src/pipeline/decompressors.ts   |  4 ++--
 packages/tiler-sharp/src/pipeline/lzw/lzw.ts    |  1 -
 4 files changed, 10 insertions(+), 24 deletions(-)

diff --git a/packages/tiler-sharp/src/pipeline/__tests__/decompress.lzw.test.ts b/packages/tiler-sharp/src/pipeline/__tests__/decompress.lzw.test.ts
index b27b03261..90d889cc1 100644
--- a/packages/tiler-sharp/src/pipeline/__tests__/decompress.lzw.test.ts
+++ b/packages/tiler-sharp/src/pipeline/__tests__/decompress.lzw.test.ts
@@ -1,20 +1,17 @@
 import assert from 'node:assert';
 import { createHash } from 'node:crypto';
-import { writeFileSync } from 'node:fs';
 import { before, describe, it } from 'node:test';
 
 import { fsa, LogConfig } from '@basemaps/shared';
-// import { TestTiff } from '@basemaps/test';
+import { TestTiff } from '@basemaps/test';
 import { Tiff } from '@cogeotiff/core';
 
-import { LzwDecompressor, LzwDecompressorSharp } from '../decompressor.lzw.js';
+import { LzwDecompressorJs, LzwDecompressorSharp } from '../decompressor.lzw.js';
 
 describe('decompressor.lzw', () => {
   let tiff: Tiff;
   before(async () => {
-    tiff = await Tiff.create(
-      fsa.source(fsa.toUrl('file:///home/blacha/data/elevation/nz-8m-dem-2012/8m-dem-small/qd.lzw.tiff')),
-    );
+    tiff = await Tiff.create(fsa.source(TestTiff.CompressLzw));
   });
 
   it('should decode a 64x64 lzw tile', async () => {
@@ -22,6 +19,7 @@ describe('decompressor.lzw', () => {
     const hashes: Record<string, { hash: string; duration: number }> = {};
     const hashesSharp: Record<string, { hash: string; duration: number }> = {};
 
+    let tileCount = 0;
     for (const img of tiff.images) {
       const imageId = img.id;
       for (let x = 0; x < img.tileCount.x; x++) {
@@ -46,7 +44,7 @@ describe('decompressor.lzw', () => {
           };
 
           const startTimeB = performance.now();
-          const retB = await LzwDecompressor.decompress({
+          const retB = await LzwDecompressorJs.decompress({
             tiff,
             imageId,
             x,
@@ -61,11 +59,10 @@ describe('decompressor.lzw', () => {
           };
 
           assert.equal(hashLzw, hashSharp, tileId);
+          tileCount++;
         }
       }
+      assert.equal(tileCount, 1);
     }
-    // writeFileSync('./hashes.json', JSON.stringify(hashes, null, 2));
-
-    // writeFileSync('./hashesSharp.json', JSON.stringify(hashesSharp, null, 2));
   });
 });
diff --git a/packages/tiler-sharp/src/pipeline/decompressor.lzw.ts b/packages/tiler-sharp/src/pipeline/decompressor.lzw.ts
index a0dae6f02..1062e968d 100644
--- a/packages/tiler-sharp/src/pipeline/decompressor.lzw.ts
+++ b/packages/tiler-sharp/src/pipeline/decompressor.lzw.ts
@@ -51,25 +51,19 @@ async function toDecompressedInterleaved(
   throw new Error('Output has missmatched tile size');
 }
 
-export const LzwDecompressor: Decompressor = {
+export const LzwDecompressorJs: Decompressor = {
   type: 'application/lzw',
   async decompress(ctx: DecompressionContext): Promise<DecompressedInterleaved> {
     // TODO: this decompressor is very slow it can take over 100ms+ to deocode a 512x512 tile
     // for comparison the lerc decompressor takes <1ms for the same amount of data.
 
-    console.time('decompress-js');
     const bytes = decompress(ctx.bytes);
-    console.timeEnd('decompress-js');
-
-    // console.log(ctx.tiff.source.url.href);
     return toDecompressedInterleaved(bytes, ctx);
   },
 };
 export const LzwDecompressorSharp: Decompressor = {
   type: 'application/lzw',
   async decompress(ctx: DecompressionContext): Promise<DecompressedInterleaved> {
-    // TODO: this decompressor is very slow it can take over 100ms+ to deocode a 512x512 tile
-    // for comparison the lerc decompressor takes <1ms for the same amount of data.
     const image = ctx.tiff.images[ctx.imageId];
     const [bitsPerSample, sampleFormat] = await Promise.all([
       image.fetch(TiffTag.BitsPerSample),
@@ -80,11 +74,7 @@ export const LzwDecompressorSharp: Decompressor = {
 
     const depth = tiffToDepth(bitsPerSample, sampleFormat?.[0]);
 
-    console.time('decompress-sharp');
     const bytes = await decodeLzwTiff(image, depth, bitsPerSample.length, ctx.bytes);
-    console.timeEnd('decompress-sharp');
-
-    // console.log(ctx.tiff.source.url.href);
     return toDecompressedInterleaved(bytes.decoded, ctx);
   },
 };
diff --git a/packages/tiler-sharp/src/pipeline/decompressors.ts b/packages/tiler-sharp/src/pipeline/decompressors.ts
index 9c3cacb07..64d5ee33f 100644
--- a/packages/tiler-sharp/src/pipeline/decompressors.ts
+++ b/packages/tiler-sharp/src/pipeline/decompressors.ts
@@ -2,9 +2,9 @@ import { Compression } from '@cogeotiff/core';
 
 import { Decompressor } from './decompressor.js';
 import { LercDecompressor } from './decompressor.lerc.js';
-import { LzwDecompressor } from './decompressor.lzw.js';
+import { LzwDecompressorSharp } from './decompressor.lzw.js';
 
 export const Decompressors: Record<string, Decompressor> = {
   [Compression.Lerc]: LercDecompressor,
-  [Compression.Lzw]: LzwDecompressor,
+  [Compression.Lzw]: LzwDecompressorSharp,
 };
diff --git a/packages/tiler-sharp/src/pipeline/lzw/lzw.ts b/packages/tiler-sharp/src/pipeline/lzw/lzw.ts
index f0b667d58..0e521e25d 100644
--- a/packages/tiler-sharp/src/pipeline/lzw/lzw.ts
+++ b/packages/tiler-sharp/src/pipeline/lzw/lzw.ts
@@ -111,7 +111,6 @@ export function decompress(input: ArrayBuffer): Uint8Array {
       appendReversed(result, oldVal);
       result.push(oldVal[oldVal.length - 1]);
       addToDictionary(oldCode as number, oldVal[oldVal.length - 1]);
-      // console.log(oldCode, oldVal[oldVal.length - 1]);
       oldCode = code;
     }