diff --git a/packages/core/data/east_coast_phase3_2023_AY31_1000_3335.tif.gz b/packages/core/data/east_coast_phase3_2023_AY31_1000_3335.tif.gz new file mode 100644 index 00000000..f8ca667b Binary files /dev/null and b/packages/core/data/east_coast_phase3_2023_AY31_1000_3335.tif.gz differ diff --git a/packages/core/src/__benchmark__/source.file.ts b/packages/core/src/__benchmark__/source.file.ts index 77670378..4e5ba232 100644 --- a/packages/core/src/__benchmark__/source.file.ts +++ b/packages/core/src/__benchmark__/source.file.ts @@ -1,13 +1,20 @@ -import { readFile, stat } from 'fs/promises'; +import { readFile, stat } from 'node:fs/promises'; +import { gunzip } from 'node:zlib'; +import { promisify } from 'node:util'; import { Source } from '../source.js'; +const gunzipP = promisify(gunzip); + export class TestFileSource implements Source { url: URL; data: Promise; constructor(fileName: URL) { this.url = fileName; - this.data = readFile(this.url); + this.data = readFile(this.url).then((buf) => { + if (this.url.pathname.endsWith('gz')) return gunzipP(buf); + return buf; + }); } async fetch(offset: number, length: number): Promise { diff --git a/packages/core/src/__test__/cog.read.test.ts b/packages/core/src/__test__/cog.read.test.ts index f91ccf59..ae9cf442 100644 --- a/packages/core/src/__test__/cog.read.test.ts +++ b/packages/core/src/__test__/cog.read.test.ts @@ -82,4 +82,37 @@ describe('CogRead', () => { assert.equal(im.tagsGeo.get(TiffTagGeo.GeogCitationGeoKey), 'NZGD2000'); assert.deepEqual(await im.fetch(TiffTag.StripByteCounts), [8064, 8064, 8064, 8064, 8064, 8064, 8064, 5040]); }); + + it('should read sub array ifds', async () => { + const source = new TestFileSource( + new URL('../../data/east_coast_phase3_2023_AY31_1000_3335.tif.gz', import.meta.url), + ); + const tiff = await CogTiff.create(source); + + assert.equal(tiff.images.length, 5); + const im = tiff.images[0]; + + assert.equal(im.isGeoTagsLoaded, true); + assert.equal(im.epsg, 2193); + assert.equal(im.compression, TiffMimeType.Lzw); + + const geoTags = [...im.tagsGeo.keys()].map((key) => TiffTagGeo[key]); + assert.deepEqual(geoTags, [ + 'GTModelTypeGeoKey', + 'GTRasterTypeGeoKey', + 'GTCitationGeoKey', + 'GeographicTypeGeoKey', + 'GeogAngularUnitsGeoKey', + 'GeogEllipsoidGeoKey', + 'GeogSemiMajorAxisGeoKey', + 'GeogSemiMinorAxisGeoKey', + 'GeogInvFlatteningGeoKey', + 'GeogTOWGS84GeoKey', + 'ProjectedCSTypeGeoKey', + 'PCSCitationGeoKey', + 'ProjLinearUnitsGeoKey', + ]); + + assert.deepEqual(im.tagsGeo.get(TiffTagGeo.GeogTOWGS84GeoKey), [0, 0, 0, 0, 0, 0, 0]); + }); }); diff --git a/packages/core/src/cog.tiff.image.ts b/packages/core/src/cog.tiff.image.ts index 3cff2743..d07f82ab 100644 --- a/packages/core/src/cog.tiff.image.ts +++ b/packages/core/src/cog.tiff.image.ts @@ -133,6 +133,7 @@ export class CogTiffImage { if (sourceTag.value == null) return; const geoTags = sourceTag.value as Uint16Array; if (typeof geoTags === 'number') throw new Error('Invalid geo tags found'); + for (let i = 4; i <= geoTags[3] * 4; i += 4) { const key = geoTags[i] as TiffTagGeo; const locationTagId = geoTags[i + 1]; @@ -149,6 +150,9 @@ export class CogTiffImage { const count = geoTags[i + 2]; if (typeof tag.value === 'string') { this.tagsGeo.set(key, tag.value.slice(offset, offset + count - 1).trim()); + } else if (Array.isArray(tag.value)) { + if (count === 1) this.tagsGeo.set(key, tag.value[offset]); + else this.tagsGeo.set(key, tag.value.slice(offset, offset + count) as any); } else { throw new Error('Failed to extract GeoTiffTags'); }