@mapcatch/util 1.0.15 → 2.0.1

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.
Files changed (81) hide show
  1. package/dist/catchUtil.min.esm.js +67927 -14001
  2. package/dist/catchUtil.min.js +2695 -55
  3. package/package.json +22 -3
  4. package/src/constants/annotation_color.js +7 -0
  5. package/src/constants/annotation_draw_style.js +228 -0
  6. package/src/constants/annotation_label_style.js +76 -0
  7. package/src/constants/annotation_style.js +118 -0
  8. package/src/constants/cameras.js +1 -1
  9. package/src/constants/crs.js +31473 -31473
  10. package/src/constants/error_codes.js +44 -0
  11. package/src/constants/height_colors.js +1 -0
  12. package/src/constants/index.js +9 -2
  13. package/src/constants/map_style.js +11 -0
  14. package/src/constants/measurement_fields.js +3 -3
  15. package/src/{event.js → event/event.js} +1 -14
  16. package/src/event/event_bus.js +5 -0
  17. package/src/event/index.js +2 -0
  18. package/src/gl-operations/constants.js +9 -11
  19. package/src/gl-operations/default_options.js +5 -5
  20. package/src/gl-operations/index.js +166 -239
  21. package/src/gl-operations/reglCommands/contours.js +20 -20
  22. package/src/gl-operations/reglCommands/default.js +34 -34
  23. package/src/gl-operations/reglCommands/hillshading.js +116 -116
  24. package/src/gl-operations/reglCommands/index.js +6 -6
  25. package/src/gl-operations/reglCommands/multiLayers.js +55 -55
  26. package/src/gl-operations/reglCommands/transitions.js +24 -24
  27. package/src/gl-operations/reglCommands/util.js +54 -54
  28. package/src/gl-operations/renderer.js +69 -69
  29. package/src/gl-operations/shaders/transform.js +2 -2
  30. package/src/gl-operations/shaders/util/rgbaToFloat.glsl +11 -11
  31. package/src/gl-operations/texture_manager.js +58 -58
  32. package/src/gl-operations/util.js +154 -154
  33. package/src/index.js +14 -2
  34. package/src/measure/index.js +198 -0
  35. package/src/measure/tile_cache.js +88 -0
  36. package/src/mvs/index.js +26 -0
  37. package/src/mvs/protos/index.js +12 -0
  38. package/src/mvs/protos/proto_10.js +155 -0
  39. package/src/observation_pretict.js +168 -0
  40. package/src/photo-parser/exif/gps_tags.js +33 -0
  41. package/src/photo-parser/exif/ifd1_tags.js +22 -0
  42. package/src/photo-parser/exif/index.js +130 -0
  43. package/src/photo-parser/exif/parse_image.js +290 -0
  44. package/src/photo-parser/exif/string_values.js +137 -0
  45. package/src/photo-parser/exif/tags.js +75 -0
  46. package/src/photo-parser/exif/tiff_tags.js +35 -0
  47. package/src/photo-parser/exif/util.js +103 -0
  48. package/src/photo-parser/image-size/detector.js +24 -0
  49. package/src/photo-parser/image-size/fromFile.js +55 -0
  50. package/src/photo-parser/image-size/index.js +2 -0
  51. package/src/photo-parser/image-size/lookup.js +37 -0
  52. package/src/photo-parser/image-size/types/bmp.js +10 -0
  53. package/src/photo-parser/image-size/types/cur.js +16 -0
  54. package/src/photo-parser/image-size/types/dds.js +10 -0
  55. package/src/photo-parser/image-size/types/gif.js +11 -0
  56. package/src/photo-parser/image-size/types/heif.js +35 -0
  57. package/src/photo-parser/image-size/types/icns.js +112 -0
  58. package/src/photo-parser/image-size/types/ico.js +74 -0
  59. package/src/photo-parser/image-size/types/index.js +43 -0
  60. package/src/photo-parser/image-size/types/j2c.js +11 -0
  61. package/src/photo-parser/image-size/types/jp2.js +22 -0
  62. package/src/photo-parser/image-size/types/jpg.js +157 -0
  63. package/src/photo-parser/image-size/types/ktx.js +18 -0
  64. package/src/photo-parser/image-size/types/png.js +36 -0
  65. package/src/photo-parser/image-size/types/pnm.js +74 -0
  66. package/src/photo-parser/image-size/types/psd.js +10 -0
  67. package/src/photo-parser/image-size/types/svg.js +100 -0
  68. package/src/photo-parser/image-size/types/tga.js +14 -0
  69. package/src/photo-parser/image-size/types/tiff.js +92 -0
  70. package/src/photo-parser/image-size/types/utils.js +83 -0
  71. package/src/photo-parser/image-size/types/webp.js +67 -0
  72. package/src/photo-parser/index.js +181 -0
  73. package/src/report/annotations_report.js +446 -0
  74. package/src/report/index.js +2 -0
  75. package/src/report/map_util.js +81 -0
  76. package/src/report/pdf_creator.js +247 -0
  77. package/src/report/report.js +583 -0
  78. package/src/transform.js +204 -0
  79. package/src/util.js +371 -75
  80. package/CHANGELOG.md +0 -60
  81. /package/src/constants/{colors.js → dsm_colors.js} +0 -0
@@ -0,0 +1,103 @@
1
+ export default {
2
+ imageHasData (img) {
3
+ return !!(img.exifdata)
4
+ },
5
+ getStringFromDB (buffer, start, length) {
6
+ var outstr = ''
7
+ for (var n = start; n < start + length; n++) {
8
+ outstr += String.fromCharCode(buffer.getUint8(n))
9
+ }
10
+ return outstr
11
+ },
12
+ xml2Object (xml) {
13
+ var obj = {}
14
+ if (xml.childNodes.length > 0) {
15
+ for (var i = 0; i < xml.childNodes.length; i++) {
16
+ var item = xml.childNodes[i]
17
+ var attributes = item.attributes
18
+ for (var idx in attributes) {
19
+ var itemAtt = attributes[idx]
20
+ var dataKey = itemAtt.nodeName
21
+ var dataValue = itemAtt.nodeValue
22
+
23
+ if (dataKey !== undefined) {
24
+ obj[dataKey] = dataValue
25
+ }
26
+ }
27
+ var nodeName = item.nodeName
28
+
29
+ if (obj[nodeName] == null || typeof (obj[nodeName]) == 'undefined') {
30
+ obj[nodeName] = this.xml2json(item)
31
+ } else {
32
+ if (typeof (obj[nodeName].push) == 'undefined') {
33
+ var old = obj[nodeName]
34
+
35
+ obj[nodeName] = []
36
+ obj[nodeName].push(old)
37
+ }
38
+ obj[nodeName].push(this.xml2json(item))
39
+ }
40
+ }
41
+ } else {
42
+ obj = xml.textContent
43
+ }
44
+ return obj
45
+ },
46
+ xml2json (xml) {
47
+ var json = {}
48
+
49
+ if (xml.nodeType == 1) { // element node
50
+ if (xml.attributes.length > 0) {
51
+ json['@attributes'] = {}
52
+ for (var j = 0; j < xml.attributes.length; j++) {
53
+ var attribute = xml.attributes.item(j)
54
+ json['@attributes'][attribute.nodeName] = attribute.nodeValue
55
+ }
56
+ }
57
+ } else if (xml.nodeType == 3) { // text node
58
+ return xml.nodeValue
59
+ }
60
+
61
+ // deal with children
62
+ if (xml.hasChildNodes()) {
63
+ for (var i = 0; i < xml.childNodes.length; i++) {
64
+ var child = xml.childNodes.item(i)
65
+ var nodeName = child.nodeName
66
+ if (json[nodeName] == null) {
67
+ json[nodeName] = this.xml2json(child)
68
+ } else {
69
+ if (json[nodeName].push == null) {
70
+ var old = json[nodeName]
71
+ json[nodeName] = []
72
+ json[nodeName].push(old)
73
+ }
74
+ json[nodeName].push(this.xml2json(child))
75
+ }
76
+ }
77
+ }
78
+
79
+ return json
80
+ },
81
+ objectURLToBlob (url, callback) {
82
+ var http = new XMLHttpRequest()
83
+ http.open('GET', url, true)
84
+ http.responseType = 'blob'
85
+ http.onload = function () {
86
+ if (this.status == 200 || this.status === 0) {
87
+ callback(this.response)
88
+ }
89
+ }
90
+ http.send()
91
+ },
92
+ base64ToArrayBuffer (base64) {
93
+ base64 = base64.replace(/^data:([^;]+);base64,/gmi, '')
94
+ var binary = atob(base64)
95
+ var len = binary.length
96
+ var buffer = new ArrayBuffer(len)
97
+ var view = new Uint8Array(buffer)
98
+ for (var i = 0; i < len; i++) {
99
+ view[i] = binary.charCodeAt(i)
100
+ }
101
+ return buffer
102
+ }
103
+ }
@@ -0,0 +1,24 @@
1
+ import { typeHandlers, types } from './types/index'
2
+
3
+ // This map helps avoid validating for every single image type
4
+ const firstBytes = new Map([
5
+ [0x38, 'psd'],
6
+ [0x42, 'bmp'],
7
+ [0x44, 'dds'],
8
+ [0x47, 'gif'],
9
+ [0x49, 'tiff'],
10
+ [0x4d, 'tiff'],
11
+ [0x52, 'webp'],
12
+ [0x69, 'icns'],
13
+ [0x89, 'png'],
14
+ [0xff, 'jpg']
15
+ ])
16
+
17
+ export function detector (input) {
18
+ const byte = input[0]
19
+ const type = firstBytes.get(byte)
20
+ if (type && typeHandlers.get(type).validate(input)) {
21
+ return type
22
+ }
23
+ return types.find((type) => typeHandlers.get(type).validate(input))
24
+ }
@@ -0,0 +1,55 @@
1
+ import * as fs from 'node:fs'
2
+ import * as path from 'node:path'
3
+
4
+ import { lookup } from './lookup'
5
+
6
+ // Maximum input size, with a default of 512 kilobytes.
7
+ // TO-DO: make this adaptive based on the initial signature of the image
8
+ const MaxInputSize = 512 * 1024
9
+
10
+ // This queue is for async `fs` operations, to avoid reaching file-descriptor limits
11
+ const queue = []
12
+
13
+ let concurrency = 100
14
+ export const setConcurrency = (c) => {
15
+ concurrency = c
16
+ }
17
+
18
+ const processQueue = async () => {
19
+ const jobs = queue.splice(0, concurrency)
20
+ const promises = jobs.map(async ({ filePath, resolve, reject }) => {
21
+ let handle
22
+ try {
23
+ handle = await fs.promises.open(path.resolve(filePath), 'r')
24
+ } catch (err) {
25
+ return reject(err)
26
+ }
27
+ try {
28
+ const { size } = await handle.stat()
29
+ if (size <= 0) {
30
+ throw new Error('Empty file')
31
+ }
32
+ const inputSize = Math.min(size, MaxInputSize)
33
+ const input = new Uint8Array(inputSize)
34
+ await handle.read(input, 0, inputSize, 0)
35
+ resolve(lookup(input))
36
+ } catch (err) {
37
+ reject(err)
38
+ } finally {
39
+ await handle.close()
40
+ }
41
+ })
42
+
43
+ await Promise.allSettled(promises)
44
+
45
+ if (queue.length) setTimeout(processQueue, 100)
46
+ }
47
+
48
+ /**
49
+ * @param {string} filePath - relative/absolute path of the image file
50
+ */
51
+ export const imageSize = async (filePath) =>
52
+ new Promise < ISizeCalculationResult > ((resolve, reject) => {
53
+ queue.push({ filePath, resolve, reject })
54
+ processQueue()
55
+ })
@@ -0,0 +1,2 @@
1
+ export { types } from './types'
2
+ export { lookup as imageSize, disableTypes } from './lookup'
@@ -0,0 +1,37 @@
1
+ import { typeHandlers } from './types/index'
2
+ import { detector } from './detector'
3
+
4
+ const globalOptions = {
5
+ disabledTypes: []
6
+ }
7
+
8
+ /**
9
+ * Return size information based on an Uint8Array
10
+ *
11
+ * @param {Uint8Array} input
12
+ * @returns {ISizeCalculationResult}
13
+ */
14
+ export function lookup (input) {
15
+ // detect the file type... don't rely on the extension
16
+ const type = detector(input)
17
+
18
+ if (typeof type !== 'undefined') {
19
+ if (globalOptions.disabledTypes.indexOf(type) > -1) {
20
+ throw new TypeError('disabled file type: ' + type)
21
+ }
22
+
23
+ // find an appropriate handler for this file type
24
+ const size = typeHandlers.get(type).calculate(input)
25
+ if (size !== undefined) {
26
+ size.type = size.type ?? type
27
+ return size
28
+ }
29
+ }
30
+
31
+ // throw up, if we don't understand the file
32
+ throw new TypeError('unsupported file type: ' + type)
33
+ }
34
+
35
+ export const disableTypes = (types) => {
36
+ globalOptions.disabledTypes = types
37
+ }
@@ -0,0 +1,10 @@
1
+ import { toUTF8String, readInt32LE, readUInt32LE } from './utils'
2
+
3
+ export const BMP = {
4
+ validate: (input) => toUTF8String(input, 0, 2) === 'BM',
5
+
6
+ calculate: (input) => ({
7
+ height: Math.abs(readInt32LE(input, 22)),
8
+ width: readUInt32LE(input, 18)
9
+ })
10
+ }
@@ -0,0 +1,16 @@
1
+ import { ICO } from './ico'
2
+ import { readUInt16LE } from './utils'
3
+
4
+ const TYPE_CURSOR = 2
5
+ export const CUR = {
6
+ validate (input) {
7
+ const reserved = readUInt16LE(input, 0)
8
+ const imageCount = readUInt16LE(input, 4)
9
+ if (reserved !== 0 || imageCount === 0) return false
10
+
11
+ const imageType = readUInt16LE(input, 2)
12
+ return imageType === TYPE_CURSOR
13
+ },
14
+
15
+ calculate: (input) => ICO.calculate(input)
16
+ }
@@ -0,0 +1,10 @@
1
+ import { readUInt32LE } from './utils'
2
+
3
+ export const DDS = {
4
+ validate: (input) => readUInt32LE(input, 0) === 0x20534444,
5
+
6
+ calculate: (input) => ({
7
+ height: readUInt32LE(input, 12),
8
+ width: readUInt32LE(input, 16)
9
+ })
10
+ }
@@ -0,0 +1,11 @@
1
+ import { toUTF8String, readUInt16LE } from './utils'
2
+
3
+ const gifRegexp = /^GIF8[79]a/
4
+ export const GIF = {
5
+ validate: (input) => gifRegexp.test(toUTF8String(input, 0, 6)),
6
+
7
+ calculate: (input) => ({
8
+ height: readUInt16LE(input, 8),
9
+ width: readUInt16LE(input, 6)
10
+ })
11
+ }
@@ -0,0 +1,35 @@
1
+ import { findBox, readUInt32BE, toUTF8String } from './utils'
2
+
3
+ const brandMap = {
4
+ avif: 'avif',
5
+ mif1: 'heif',
6
+ msf1: 'heif', // hief-sequence
7
+ heic: 'heic',
8
+ heix: 'heic',
9
+ hevc: 'heic', // heic-sequence
10
+ hevx: 'heic' // heic-sequence
11
+ }
12
+
13
+ export const HEIF = {
14
+ validate (buffer) {
15
+ const ftype = toUTF8String(buffer, 4, 8)
16
+ const brand = toUTF8String(buffer, 8, 12)
17
+ return 'ftyp' === ftype && brand in brandMap
18
+ },
19
+
20
+ calculate (buffer) {
21
+ // Based on https://nokiatech.github.io/heif/technical.html
22
+ const metaBox = findBox(buffer, 'meta', 0)
23
+ const iprpBox = metaBox && findBox(buffer, 'iprp', metaBox.offset + 12)
24
+ const ipcoBox = iprpBox && findBox(buffer, 'ipco', iprpBox.offset + 8)
25
+ const ispeBox = ipcoBox && findBox(buffer, 'ispe', ipcoBox.offset + 8)
26
+ if (ispeBox) {
27
+ return {
28
+ height: readUInt32BE(buffer, ispeBox.offset + 16),
29
+ width: readUInt32BE(buffer, ispeBox.offset + 12),
30
+ type: toUTF8String(buffer, 8, 12)
31
+ }
32
+ }
33
+ throw new TypeError('Invalid HEIF, no size found')
34
+ }
35
+ }
@@ -0,0 +1,112 @@
1
+ import { toUTF8String, readUInt32BE } from './utils'
2
+
3
+ /**
4
+ * ICNS Header
5
+ *
6
+ * | Offset | Size | Purpose |
7
+ * | 0 | 4 | Magic literal, must be "icns" (0x69, 0x63, 0x6e, 0x73) |
8
+ * | 4 | 4 | Length of file, in bytes, msb first. |
9
+ *
10
+ */
11
+ const SIZE_HEADER = 4 + 4 // 8
12
+ const FILE_LENGTH_OFFSET = 4 // MSB => BIG ENDIAN
13
+
14
+ /**
15
+ * Image Entry
16
+ *
17
+ * | Offset | Size | Purpose |
18
+ * | 0 | 4 | Icon type, see OSType below. |
19
+ * | 4 | 4 | Length of data, in bytes (including type and length), msb first. |
20
+ * | 8 | n | Icon data |
21
+ */
22
+ const ENTRY_LENGTH_OFFSET = 4 // MSB => BIG ENDIAN
23
+
24
+ const ICON_TYPE_SIZE = {
25
+ ICON: 32,
26
+ 'ICN#': 32,
27
+ // m => 16 x 16
28
+ 'icm#': 16,
29
+ icm4: 16,
30
+ icm8: 16,
31
+ // s => 16 x 16
32
+ 'ics#': 16,
33
+ ics4: 16,
34
+ ics8: 16,
35
+ is32: 16,
36
+ s8mk: 16,
37
+ icp4: 16,
38
+ // l => 32 x 32
39
+ icl4: 32,
40
+ icl8: 32,
41
+ il32: 32,
42
+ l8mk: 32,
43
+ icp5: 32,
44
+ ic11: 32,
45
+ // h => 48 x 48
46
+ ich4: 48,
47
+ ich8: 48,
48
+ ih32: 48,
49
+ h8mk: 48,
50
+ // . => 64 x 64
51
+ icp6: 64,
52
+ ic12: 32,
53
+ // t => 128 x 128
54
+ it32: 128,
55
+ t8mk: 128,
56
+ ic07: 128,
57
+ // . => 256 x 256
58
+ ic08: 256,
59
+ ic13: 256,
60
+ // . => 512 x 512
61
+ ic09: 512,
62
+ ic14: 512,
63
+ // . => 1024 x 1024
64
+ ic10: 1024
65
+ }
66
+
67
+ function readImageHeader (
68
+ input,
69
+ imageOffset
70
+ ) {
71
+ const imageLengthOffset = imageOffset + ENTRY_LENGTH_OFFSET
72
+ return [
73
+ toUTF8String(input, imageOffset, imageLengthOffset),
74
+ readUInt32BE(input, imageLengthOffset)
75
+ ]
76
+ }
77
+
78
+ function getImageSize (type) {
79
+ const size = ICON_TYPE_SIZE[type]
80
+ return { width: size, height: size, type }
81
+ }
82
+
83
+ export const ICNS = {
84
+ validate: (input) => toUTF8String(input, 0, 4) === 'icns',
85
+
86
+ calculate (input) {
87
+ const inputLength = input.length
88
+ const fileLength = readUInt32BE(input, FILE_LENGTH_OFFSET)
89
+ let imageOffset = SIZE_HEADER
90
+
91
+ let imageHeader = readImageHeader(input, imageOffset)
92
+ let imageSize = getImageSize(imageHeader[0])
93
+ imageOffset += imageHeader[1]
94
+
95
+ if (imageOffset === fileLength) return imageSize
96
+
97
+ const result = {
98
+ height: imageSize.height,
99
+ images: [imageSize],
100
+ width: imageSize.width
101
+ }
102
+
103
+ while (imageOffset < fileLength && imageOffset < inputLength) {
104
+ imageHeader = readImageHeader(input, imageOffset)
105
+ imageSize = getImageSize(imageHeader[0])
106
+ imageOffset += imageHeader[1]
107
+ result.images.push(imageSize)
108
+ }
109
+
110
+ return result
111
+ }
112
+ }
@@ -0,0 +1,74 @@
1
+ import { readUInt16LE } from './utils'
2
+
3
+ const TYPE_ICON = 1
4
+
5
+ /**
6
+ * ICON Header
7
+ *
8
+ * | Offset | Size | Purpose |
9
+ * | 0 | 2 | Reserved. Must always be 0. |
10
+ * | 2 | 2 | Image type: 1 for icon (.ICO) image, 2 for cursor (.CUR) image. Other values are invalid. |
11
+ * | 4 | 2 | Number of images in the file. |
12
+ *
13
+ */
14
+ const SIZE_HEADER = 2 + 2 + 2 // 6
15
+
16
+ /**
17
+ * Image Entry
18
+ *
19
+ * | Offset | Size | Purpose |
20
+ * | 0 | 1 | Image width in pixels. Can be any number between 0 and 255. Value 0 means width is 256 pixels. |
21
+ * | 1 | 1 | Image height in pixels. Can be any number between 0 and 255. Value 0 means height is 256 pixels. |
22
+ * | 2 | 1 | Number of colors in the color palette. Should be 0 if the image does not use a color palette. |
23
+ * | 3 | 1 | Reserved. Should be 0. |
24
+ * | 4 | 2 | ICO format: Color planes. Should be 0 or 1. |
25
+ * | | | CUR format: The horizontal coordinates of the hotspot in number of pixels from the left. |
26
+ * | 6 | 2 | ICO format: Bits per pixel. |
27
+ * | | | CUR format: The vertical coordinates of the hotspot in number of pixels from the top. |
28
+ * | 8 | 4 | The size of the image's data in bytes |
29
+ * | 12 | 4 | The offset of BMP or PNG data from the beginning of the ICO/CUR file |
30
+ *
31
+ */
32
+ const SIZE_IMAGE_ENTRY = 1 + 1 + 1 + 1 + 2 + 2 + 4 + 4 // 16
33
+
34
+ function getSizeFromOffset (input, offset) {
35
+ const value = input[offset]
36
+ return value === 0 ? 256 : value
37
+ }
38
+
39
+ function getImageSize (input, imageIndex) {
40
+ const offset = SIZE_HEADER + imageIndex * SIZE_IMAGE_ENTRY
41
+ return {
42
+ height: getSizeFromOffset(input, offset + 1),
43
+ width: getSizeFromOffset(input, offset)
44
+ }
45
+ }
46
+
47
+ export const ICO = {
48
+ validate (input) {
49
+ const reserved = readUInt16LE(input, 0)
50
+ const imageCount = readUInt16LE(input, 4)
51
+ if (reserved !== 0 || imageCount === 0) return false
52
+
53
+ const imageType = readUInt16LE(input, 2)
54
+ return imageType === TYPE_ICON
55
+ },
56
+
57
+ calculate (input) {
58
+ const nbImages = readUInt16LE(input, 4)
59
+ const imageSize = getImageSize(input, 0)
60
+
61
+ if (nbImages === 1) return imageSize
62
+
63
+ const imgs = [imageSize]
64
+ for (let imageIndex = 1; imageIndex < nbImages; imageIndex += 1) {
65
+ imgs.push(getImageSize(input, imageIndex))
66
+ }
67
+
68
+ return {
69
+ height: imageSize.height,
70
+ images: imgs,
71
+ width: imageSize.width
72
+ }
73
+ }
74
+ }
@@ -0,0 +1,43 @@
1
+ // load all available handlers explicitely for browserify support
2
+ import { BMP } from './bmp'
3
+ import { CUR } from './cur'
4
+ import { DDS } from './dds'
5
+ import { GIF } from './gif'
6
+ import { HEIF } from './heif'
7
+ import { ICNS } from './icns'
8
+ import { ICO } from './ico'
9
+ import { J2C } from './j2c'
10
+ import { JP2 } from './jp2'
11
+ import { JPG } from './jpg'
12
+ import { KTX } from './ktx'
13
+ import { PNG } from './png'
14
+ import { PNM } from './pnm'
15
+ import { PSD } from './psd'
16
+ import { SVG } from './svg'
17
+ import { TGA } from './tga'
18
+ import { TIFF } from './tiff'
19
+ import { WEBP } from './webp'
20
+
21
+ export const typeHandlers = new Map([
22
+ ['bmp', BMP],
23
+ ['cur', CUR],
24
+ ['dds', DDS],
25
+ ['gif', GIF],
26
+ ['heif', HEIF],
27
+ ['icns', ICNS],
28
+ ['ico', ICO],
29
+ ['j2c', J2C],
30
+ ['jp2', JP2],
31
+ ['jpg', JPG],
32
+ ['ktx', KTX],
33
+ ['png', PNG],
34
+ ['pnm', PNM],
35
+ ['psd', PSD],
36
+ ['svg', SVG],
37
+ ['tga', TGA],
38
+ ['tiff', TIFF],
39
+ ['webp', WEBP]
40
+ ])
41
+
42
+
43
+ export const types = Array.from(typeHandlers.keys())
@@ -0,0 +1,11 @@
1
+ import { toHexString, readUInt32BE } from './utils'
2
+
3
+ export const J2C = {
4
+ // TODO: this doesn't seem right. SIZ marker doesn't have to be right after the SOC
5
+ validate: (input) => toHexString(input, 0, 4) === 'ff4fff51',
6
+
7
+ calculate: (input) => ({
8
+ height: readUInt32BE(input, 12),
9
+ width: readUInt32BE(input, 8)
10
+ })
11
+ }
@@ -0,0 +1,22 @@
1
+ import { readUInt32BE, findBox } from './utils'
2
+
3
+ export const JP2 = {
4
+ validate (input) {
5
+ if (readUInt32BE(input, 4) !== 0x6a502020 || readUInt32BE(input, 0) < 1) return false
6
+ const ftypBox = findBox(input, 'ftyp', 0)
7
+ if (!ftypBox) return false
8
+ return readUInt32BE(input, ftypBox.offset + 4) === 0x66747970
9
+ },
10
+
11
+ calculate (input) {
12
+ const jp2hBox = findBox(input, 'jp2h', 0)
13
+ const ihdrBox = jp2hBox && findBox(input, 'ihdr', jp2hBox.offset + 8)
14
+ if (ihdrBox) {
15
+ return {
16
+ height: readUInt32BE(input, ihdrBox.offset + 8),
17
+ width: readUInt32BE(input, ihdrBox.offset + 12)
18
+ }
19
+ }
20
+ throw new TypeError('Unsupported JPEG 2000 format')
21
+ }
22
+ }