@cogeotiff/core 8.0.1 → 8.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,7 @@
1
1
  import { getUint } from './util/bytes.js';
2
2
  import { CogTiff } from './cog.tiff.js';
3
3
  import { TiffCompression, TiffMimeType } from './const/tiff.mime.js';
4
- import { TagId, TagGeoId } from './const/tiff.tag.id.js';
4
+ import { TiffTag, TiffTagGeo } from './const/tiff.tag.id.js';
5
5
  import { Tag, TagInline, TagOffset } from './read/tiff.tag.js';
6
6
  import { BoundingBox, Size } from './vector.js';
7
7
  import { fetchLazy, getValueAt } from './read/tiff.tag.factory.js';
@@ -21,18 +21,18 @@ export interface CogTiffImageTiledCount {
21
21
 
22
22
  /** Tags that are commonly accessed for geotiffs */
23
23
  export const ImportantTags = new Set([
24
- TagId.Compression,
25
- TagId.ImageHeight,
26
- TagId.ImageWidth,
27
- TagId.ModelPixelScale,
28
- TagId.ModelTiePoint,
29
- TagId.ModelTransformation,
30
- TagId.TileHeight,
31
- TagId.TileWidth,
32
- TagId.GeoKeyDirectory,
33
- TagId.GeoAsciiParams,
34
- TagId.GeoDoubleParams,
35
- TagId.TileOffsets,
24
+ TiffTag.Compression,
25
+ TiffTag.ImageHeight,
26
+ TiffTag.ImageWidth,
27
+ TiffTag.ModelPixelScale,
28
+ TiffTag.ModelTiePoint,
29
+ TiffTag.ModelTransformation,
30
+ TiffTag.TileHeight,
31
+ TiffTag.TileWidth,
32
+ TiffTag.GeoKeyDirectory,
33
+ TiffTag.GeoAsciiParams,
34
+ TiffTag.GeoDoubleParams,
35
+ TiffTag.TileOffsets,
36
36
  ]);
37
37
 
38
38
  /**
@@ -47,7 +47,7 @@ export interface CogTiffImageTileSize {
47
47
 
48
48
  export class CogTiffImage {
49
49
  /** All IFD tags that have been read for the image */
50
- tags: Map<TagId, Tag>;
50
+ tags: Map<TiffTag, Tag>;
51
51
 
52
52
  /** Id of the tif image, generally the image index inside the tif */
53
53
  id: number;
@@ -57,9 +57,9 @@ export class CogTiffImage {
57
57
  /** Has loadGeoTiffTags been called */
58
58
  isGeoTagsLoaded = false;
59
59
  /** Sub tags stored in TiffTag.GeoKeyDirectory */
60
- tagsGeo: Map<TagGeoId, string | number> = new Map();
60
+ tagsGeo: Map<TiffTagGeo, string | number> = new Map();
61
61
 
62
- constructor(tiff: CogTiff, id: number, tags: Map<TagId, Tag>) {
62
+ constructor(tiff: CogTiff, id: number, tags: Map<TiffTag, Tag>) {
63
63
  this.tiff = tiff;
64
64
  this.id = id;
65
65
  this.tags = tags;
@@ -72,20 +72,20 @@ export class CogTiffImage {
72
72
  */
73
73
  async init(loadGeoTags = true): Promise<void> {
74
74
  const requiredTags = [
75
- this.fetch(TagId.Compression),
76
- this.fetch(TagId.ImageHeight),
77
- this.fetch(TagId.ImageWidth),
78
- this.fetch(TagId.ModelPixelScale),
79
- this.fetch(TagId.ModelTiePoint),
80
- this.fetch(TagId.ModelTransformation),
81
- this.fetch(TagId.TileHeight),
82
- this.fetch(TagId.TileWidth),
75
+ this.fetch(TiffTag.Compression),
76
+ this.fetch(TiffTag.ImageHeight),
77
+ this.fetch(TiffTag.ImageWidth),
78
+ this.fetch(TiffTag.ModelPixelScale),
79
+ this.fetch(TiffTag.ModelTiePoint),
80
+ this.fetch(TiffTag.ModelTransformation),
81
+ this.fetch(TiffTag.TileHeight),
82
+ this.fetch(TiffTag.TileWidth),
83
83
  ];
84
84
 
85
85
  if (loadGeoTags) {
86
- requiredTags.push(this.fetch(TagId.GeoKeyDirectory));
87
- requiredTags.push(this.fetch(TagId.GeoAsciiParams));
88
- requiredTags.push(this.fetch(TagId.GeoDoubleParams));
86
+ requiredTags.push(this.fetch(TiffTag.GeoKeyDirectory));
87
+ requiredTags.push(this.fetch(TiffTag.GeoAsciiParams));
88
+ requiredTags.push(this.fetch(TiffTag.GeoDoubleParams));
89
89
  }
90
90
 
91
91
  await Promise.all(requiredTags);
@@ -95,7 +95,7 @@ export class CogTiffImage {
95
95
  /**
96
96
  * Get the value of a TiffTag if it exists null otherwise
97
97
  */
98
- value<T>(tag: TagId): T | null {
98
+ value<T>(tag: TiffTag): T | null {
99
99
  const sourceTag = this.tags.get(tag);
100
100
  if (sourceTag == null) return null;
101
101
  if (sourceTag.type === 'offset' && sourceTag.isLoaded === false) return null;
@@ -108,7 +108,7 @@ export class CogTiffImage {
108
108
  async loadGeoTiffTags(): Promise<void> {
109
109
  // Already loaded
110
110
  if (this.isGeoTagsLoaded) return;
111
- const sourceTag = this.tags.get(TagId.GeoKeyDirectory);
111
+ const sourceTag = this.tags.get(TiffTag.GeoKeyDirectory);
112
112
  if (sourceTag == null) {
113
113
  this.isGeoTagsLoaded = true;
114
114
  return;
@@ -116,9 +116,9 @@ export class CogTiffImage {
116
116
  if (sourceTag.type === 'lazy' && sourceTag.value == null) {
117
117
  // Load all the required keys
118
118
  await Promise.all([
119
- this.fetch(TagId.GeoKeyDirectory),
120
- this.fetch(TagId.GeoAsciiParams),
121
- this.fetch(TagId.GeoDoubleParams),
119
+ this.fetch(TiffTag.GeoKeyDirectory),
120
+ this.fetch(TiffTag.GeoAsciiParams),
121
+ this.fetch(TiffTag.GeoDoubleParams),
122
122
  ]);
123
123
  }
124
124
  this.isGeoTagsLoaded = true;
@@ -126,7 +126,7 @@ export class CogTiffImage {
126
126
  const geoTags = sourceTag.value as Uint16Array;
127
127
  if (typeof geoTags === 'number') throw new Error('Invalid geo tags found');
128
128
  for (let i = 4; i <= geoTags[3] * 4; i += 4) {
129
- const key = geoTags[i] as TagGeoId;
129
+ const key = geoTags[i] as TiffTagGeo;
130
130
  const location = geoTags[i + 1];
131
131
 
132
132
  const offset = geoTags[i + 3];
@@ -149,7 +149,7 @@ export class CogTiffImage {
149
149
  /**
150
150
  * Get the associated GeoTiffTags
151
151
  */
152
- valueGeo(tag: TagGeoId): string | number | undefined {
152
+ valueGeo(tag: TiffTagGeo): string | number | undefined {
153
153
  if (this.isGeoTagsLoaded === false) throw new Error('loadGeoTiffTags() has not been called');
154
154
  return this.tagsGeo.get(tag);
155
155
  }
@@ -158,7 +158,7 @@ export class CogTiffImage {
158
158
  * Load a tag, if it is not currently loaded, fetch the required data for the tag.
159
159
  * @param tag tag to fetch
160
160
  */
161
- public async fetch<T>(tag: TagId): Promise<T | null> {
161
+ public async fetch<T>(tag: TiffTag): Promise<T | null> {
162
162
  const sourceTag = this.tags.get(tag);
163
163
  if (sourceTag == null) return null;
164
164
  if (sourceTag.type === 'inline') return sourceTag.value as unknown as T;
@@ -173,18 +173,18 @@ export class CogTiffImage {
173
173
  * @returns origin point of the image
174
174
  */
175
175
  get origin(): [number, number, number] {
176
- const tiePoints: number[] | null = this.value<number[]>(TagId.ModelTiePoint);
176
+ const tiePoints: number[] | null = this.value<number[]>(TiffTag.ModelTiePoint);
177
177
  if (tiePoints != null && tiePoints.length === 6) {
178
178
  return [tiePoints[3], tiePoints[4], tiePoints[5]];
179
179
  }
180
180
 
181
- const modelTransformation = this.value<number[]>(TagId.ModelTransformation);
181
+ const modelTransformation = this.value<number[]>(TiffTag.ModelTransformation);
182
182
  if (modelTransformation != null) {
183
183
  return [modelTransformation[3], modelTransformation[7], modelTransformation[11]];
184
184
  }
185
185
 
186
186
  // If this is a sub image, use the origin from the top level image
187
- if (this.value(TagId.NewSubFileType) === 1 && this.id !== 0) {
187
+ if (this.value(TiffTag.NewSubFileType) === 1 && this.id !== 0) {
188
188
  return this.tiff.images[0].origin;
189
189
  }
190
190
 
@@ -193,10 +193,11 @@ export class CogTiffImage {
193
193
 
194
194
  /** Is there enough geo information on this image to figure out where its actually located */
195
195
  get isGeoLocated(): boolean {
196
- const isImageLocated = this.value(TagId.ModelPixelScale) != null || this.value(TagId.ModelTransformation) != null;
196
+ const isImageLocated =
197
+ this.value(TiffTag.ModelPixelScale) != null || this.value(TiffTag.ModelTransformation) != null;
197
198
  if (isImageLocated) return true;
198
199
  // If this is a sub image, use the isGeoLocated from the top level image
199
- if (this.value(TagId.NewSubFileType) === 1 && this.id !== 0) return this.tiff.images[0].isGeoLocated;
200
+ if (this.value(TiffTag.NewSubFileType) === 1 && this.id !== 0) return this.tiff.images[0].isGeoLocated;
200
201
  return false;
201
202
  }
202
203
 
@@ -206,17 +207,17 @@ export class CogTiffImage {
206
207
  * @returns [x,y,z] pixel scale
207
208
  */
208
209
  get resolution(): [number, number, number] {
209
- const modelPixelScale: number[] | null = this.value(TagId.ModelPixelScale);
210
+ const modelPixelScale: number[] | null = this.value(TiffTag.ModelPixelScale);
210
211
  if (modelPixelScale != null) {
211
212
  return [modelPixelScale[0], -modelPixelScale[1], modelPixelScale[2]];
212
213
  }
213
- const modelTransformation: number[] | null = this.value(TagId.ModelTransformation);
214
+ const modelTransformation: number[] | null = this.value(TiffTag.ModelTransformation);
214
215
  if (modelTransformation != null) {
215
216
  return [modelTransformation[0], modelTransformation[5], modelTransformation[10]];
216
217
  }
217
218
 
218
219
  // If this is a sub image, use the resolution from the top level image
219
- if (this.value(TagId.NewSubFileType) === 1 && this.id !== 0) {
220
+ if (this.value(TiffTag.NewSubFileType) === 1 && this.id !== 0) {
220
221
  const firstImg = this.tiff.images[0];
221
222
  const [resX, resY, resZ] = firstImg.resolution;
222
223
  const firstImgSize = firstImg.size;
@@ -259,7 +260,7 @@ export class CogTiffImage {
259
260
  * @returns Compression type eg webp
260
261
  */
261
262
  get compression(): TiffMimeType | null {
262
- const compression = this.value(TagId.Compression);
263
+ const compression = this.value(TiffTag.Compression);
263
264
  if (compression == null || typeof compression !== 'number') return null;
264
265
  return TiffCompression[compression];
265
266
  }
@@ -270,7 +271,7 @@ export class CogTiffImage {
270
271
  * @returns EPSG Code if it exists
271
272
  */
272
273
  get epsg(): number | null {
273
- const projection = this.valueGeo(TagGeoId.ProjectedCSTypeGeoKey) as number;
274
+ const projection = this.valueGeo(TiffTagGeo.ProjectedCSTypeGeoKey) as number;
274
275
  if (projection === InvalidProjectionCode) return null;
275
276
  return projection;
276
277
  }
@@ -282,8 +283,8 @@ export class CogTiffImage {
282
283
  */
283
284
  get size(): Size {
284
285
  return {
285
- width: this.value<number>(TagId.ImageWidth) as number,
286
- height: this.value<number>(TagId.ImageHeight) as number,
286
+ width: this.value<number>(TiffTag.ImageWidth) as number,
287
+ height: this.value<number>(TiffTag.ImageHeight) as number,
287
288
  };
288
289
  }
289
290
 
@@ -291,7 +292,7 @@ export class CogTiffImage {
291
292
  * Determine if this image is tiled
292
293
  */
293
294
  public isTiled(): boolean {
294
- return this.value(TagId.TileWidth) !== null;
295
+ return this.value(TiffTag.TileWidth) !== null;
295
296
  }
296
297
 
297
298
  /**
@@ -299,8 +300,8 @@ export class CogTiffImage {
299
300
  */
300
301
  get tileSize(): CogTiffImageTileSize {
301
302
  return {
302
- width: this.value<number>(TagId.TileWidth) as number,
303
- height: this.value<number>(TagId.TileHeight) as number,
303
+ width: this.value<number>(TiffTag.TileWidth) as number,
304
+ height: this.value<number>(TiffTag.TileHeight) as number,
304
305
  };
305
306
  }
306
307
 
@@ -323,7 +324,7 @@ export class CogTiffImage {
323
324
  * @returns file offset to where the tiffs are stored
324
325
  */
325
326
  get tileOffset(): TagOffset {
326
- const tileOffset = this.tags.get(TagId.TileOffsets) as TagOffset;
327
+ const tileOffset = this.tags.get(TiffTag.TileOffsets) as TagOffset;
327
328
  if (tileOffset == null) throw new Error('No tile offsets found');
328
329
  return tileOffset;
329
330
  }
@@ -336,7 +337,7 @@ export class CogTiffImage {
336
337
  * @returns number of strips present
337
338
  */
338
339
  get stripCount(): number {
339
- const tileOffset = this.tags.get(TagId.StripByteCounts) as TagOffset;
340
+ const tileOffset = this.tags.get(TiffTag.StripByteCounts) as TagOffset;
340
341
  if (tileOffset == null) return 0;
341
342
  return tileOffset.count;
342
343
  }
@@ -359,8 +360,8 @@ export class CogTiffImage {
359
360
  async getStrip(index: number): Promise<{ mimeType: TiffMimeType; bytes: ArrayBuffer } | null> {
360
361
  if (this.isTiled()) throw new Error('Cannot read stripes, tiff is tiled: ' + index);
361
362
 
362
- const byteCounts = this.tags.get(TagId.StripByteCounts) as TagOffset;
363
- const offsets = this.tags.get(TagId.StripOffsets) as TagOffset;
363
+ const byteCounts = this.tags.get(TiffTag.StripByteCounts) as TagOffset;
364
+ const offsets = this.tags.get(TiffTag.StripOffsets) as TagOffset;
364
365
 
365
366
  if (index >= byteCounts.count) throw new Error('Cannot read strip, index out of bounds');
366
367
 
@@ -375,7 +376,7 @@ export class CogTiffImage {
375
376
  private getJpegHeader(bytes: ArrayBuffer): ArrayBuffer {
376
377
  // Both the JPEGTable and the Bytes with have the start of image and end of image markers
377
378
  // StartOfImage 0xffd8 EndOfImage 0xffd9
378
- const tables = this.value<number[]>(TagId.JPEGTables);
379
+ const tables = this.value<number[]>(TiffTag.JPEGTables);
379
380
  if (tables == null) throw new Error('Unable to find Jpeg header');
380
381
 
381
382
  // Remove EndOfImage marker
@@ -392,7 +393,7 @@ export class CogTiffImage {
392
393
  byteCount: number,
393
394
  ): Promise<{ mimeType: TiffMimeType; bytes: ArrayBuffer } | null> {
394
395
  const mimeType = this.compression;
395
- if (mimeType == null) throw new Error('Unsupported compression: ' + this.value(TagId.Compression));
396
+ if (mimeType == null) throw new Error('Unsupported compression: ' + this.value(TiffTag.Compression));
396
397
  if (byteCount === 0) return null;
397
398
 
398
399
  const bytes = await this.tiff.source.fetch(offset, byteCount);
@@ -417,7 +418,7 @@ export class CogTiffImage {
417
418
  const tiles = this.tileSize;
418
419
 
419
420
  if (tiles == null) throw new Error('Tiff is not tiled');
420
- if (mimeType == null) throw new Error('Unsupported compression: ' + this.value(TagId.Compression));
421
+ if (mimeType == null) throw new Error('Unsupported compression: ' + this.value(TiffTag.Compression));
421
422
 
422
423
  // TODO support GhostOptionTileOrder
423
424
  const nyTiles = Math.ceil(size.height / tiles.height);
@@ -476,7 +477,7 @@ export class CogTiffImage {
476
477
  return { offset, imageSize: getUint(new DataView(bytes), 0, leaderBytes, this.tiff.isLittleEndian) };
477
478
  }
478
479
 
479
- const byteCounts = this.tags.get(TagId.TileByteCounts) as TagOffset;
480
+ const byteCounts = this.tags.get(TiffTag.TileByteCounts) as TagOffset;
480
481
  if (byteCounts == null) throw new Error('No tile byte counts found');
481
482
  const [offset, imageSize] = await Promise.all([
482
483
  getOffset(this.tiff, this.tileOffset, index),
package/src/cog.tiff.ts CHANGED
@@ -1,8 +1,8 @@
1
1
  import { CogTiffImage } from './cog.tiff.image.js';
2
2
  import { TiffEndian } from './const/tiff.endian.js';
3
- import { TagId } from './const/tiff.tag.id.js';
3
+ import { TiffTag } from './const/tiff.tag.id.js';
4
4
  import { TiffVersion } from './const/tiff.version.js';
5
- import { TiffTag } from './index.js';
5
+ import { Tag } from './index.js';
6
6
  import { DataViewOffset, hasBytes } from './read/data.view.offset.js';
7
7
  import { CogTifGhostOptions } from './read/tiff.gdal.js';
8
8
  import { TagTiffBigConfig, TagTiffConfig, TiffIfdConfig } from './read/tiff.ifd.config.js';
@@ -141,7 +141,7 @@ export class CogTiff {
141
141
  const viewOffset = offset - view.sourceOffset;
142
142
  const tagCount = getUint(view, viewOffset, this.ifdConfig.offset, this.isLittleEndian);
143
143
 
144
- const tags: Map<TagId, TiffTag> = new Map();
144
+ const tags: Map<TiffTag, Tag> = new Map();
145
145
 
146
146
  // We now know how many bytes we need so ensure the ifd bytes are all read
147
147
  const ifdBytes = tagCount * this.ifdConfig.ifd;
@@ -1,5 +1,5 @@
1
1
  export { TiffEndian } from './tiff.endian.js';
2
2
  export { TiffCompression, TiffMimeType } from './tiff.mime.js';
3
- export { TagId as TiffTag, TagGeoId as TiffTagGeo } from './tiff.tag.id.js';
3
+ export { TiffTag as TiffTag, TiffTagGeo as TiffTagGeo } from './tiff.tag.id.js';
4
4
  export { TiffTagValueType } from './tiff.tag.value.js';
5
5
  export { TiffVersion } from './tiff.version.js';
@@ -1,5 +1,5 @@
1
1
  // Stolen from geotiff.js
2
- export enum TagId {
2
+ export enum TiffTag {
3
3
  // TIFF Baseline
4
4
  Artist = 0x013b,
5
5
  BitsPerSample = 0x0102,
@@ -120,7 +120,7 @@ export enum TagId {
120
120
  GeoAsciiParams = 0x87b1,
121
121
  }
122
122
 
123
- export enum TagGeoId {
123
+ export enum TiffTagGeo {
124
124
  GTModelTypeGeoKey = 1024,
125
125
  GTRasterTypeGeoKey = 1025,
126
126
  GTCitationGeoKey = 1026,
package/src/index.ts CHANGED
@@ -1,10 +1,10 @@
1
1
  export { CogTiff } from './cog.tiff.js';
2
2
  export { TiffEndian } from './const/tiff.endian.js';
3
3
  export { TiffCompression, TiffMimeType } from './const/tiff.mime.js';
4
- export { TagGeoId as TiffTagGeo, TagId as TiffTagId } from './const/tiff.tag.id.js';
4
+ export { TiffTagGeo, TiffTag } from './const/tiff.tag.id.js';
5
5
  export { TiffTagValueType } from './const/tiff.tag.value.js';
6
6
  export { TiffVersion } from './const/tiff.version.js';
7
- export { TagInline, TagLazy, TagOffset, Tag as TiffTag } from './read/tiff.tag.js';
7
+ export { TagInline, TagLazy, TagOffset, Tag } from './read/tiff.tag.js';
8
8
  export { getTiffTagSize } from './read/tiff.value.reader.js';
9
9
  export { Source } from './source.js';
10
10
  export { toHex } from './util/util.hex.js';
@@ -1,5 +1,5 @@
1
1
  import { CogTiff } from '../cog.tiff.js';
2
- import { TagId } from '../const/tiff.tag.id.js';
2
+ import { TiffTag } from '../const/tiff.tag.id.js';
3
3
  import { TiffTagValueType } from '../const/tiff.tag.value.js';
4
4
  import { getUint, getUint64 } from '../util/bytes.js';
5
5
  import { DataViewOffset, hasBytes } from './data.view.offset.js';
@@ -100,10 +100,10 @@ export function createTag(tiff: CogTiff, view: DataViewOffset, offset: number):
100
100
 
101
101
  const dataOffset = getUint(view, offset + 4 + tiff.ifdConfig.pointer, tiff.ifdConfig.pointer, tiff.isLittleEndian);
102
102
  switch (tagId) {
103
- case TagId.TileOffsets:
104
- case TagId.TileByteCounts:
105
- case TagId.StripByteCounts:
106
- case TagId.StripOffsets:
103
+ case TiffTag.TileOffsets:
104
+ case TiffTag.TileByteCounts:
105
+ case TiffTag.StripByteCounts:
106
+ case TiffTag.StripOffsets:
107
107
  const tag: TagOffset = {
108
108
  type: 'offset',
109
109
  id: tagId,
@@ -114,7 +114,7 @@ export function createTag(tiff: CogTiff, view: DataViewOffset, offset: number):
114
114
  tagOffset: offset,
115
115
  };
116
116
  // Some offsets are quite long and don't need to read them often, so only read the tags we are interested in when we need to
117
- if (tagId === TagId.TileOffsets && hasBytes(view, dataOffset, dataLength)) setBytes(tag, view);
117
+ if (tagId === TiffTag.TileOffsets && hasBytes(view, dataOffset, dataLength)) setBytes(tag, view);
118
118
  return tag;
119
119
  }
120
120
 
@@ -1,12 +1,13 @@
1
- import { TagId } from '../const/tiff.tag.id.js';
1
+ import { TiffTag } from '../const/tiff.tag.id.js';
2
2
  import { TiffTagValueType } from '../const/tiff.tag.value.js';
3
3
  import { DataViewOffset } from './data.view.offset.js';
4
4
 
5
+ /** Tiff tag interfaces */
5
6
  export type Tag<T = unknown> = TagLazy<T> | TagInline<T> | TagOffset;
6
7
 
7
8
  export interface TagBase {
8
9
  /** Id of the Tag */
9
- id: TagId;
10
+ id: TiffTag;
10
11
  /** Offset in bytes to where this tag was read from */
11
12
  tagOffset: number;
12
13
  /** Number of values */
@@ -15,6 +16,7 @@ export interface TagBase {
15
16
  dataType: TiffTagValueType;
16
17
  }
17
18
 
19
+ /** Tiff tag value is not inline and will be loaded later when requested */
18
20
  export interface TagLazy<T> extends TagBase {
19
21
  type: 'lazy';
20
22
  /** Value if loaded undefined otherwise */
@@ -29,6 +31,7 @@ export interface TagInline<T> extends TagBase {
29
31
  value: T;
30
32
  }
31
33
 
34
+ /** Tiff tag that is a list of offsets this can be partially read */
32
35
  export interface TagOffset extends TagBase {
33
36
  type: 'offset';
34
37
  /** Values of the offest's this is a sparse array unless @see {isLoaded} is true */