Comparing version 0.0.0 to 0.0.1
@@ -17,5 +17,6 @@ /// <reference types="node" /> | ||
*/ | ||
declare function imageSize(input: Buffer): ISizeCalculationResult | void; | ||
declare const types: string[] | ||
declare function imageMeta(input: Buffer): ISizeCalculationResult | void; | ||
declare const types: string[]; | ||
export { imageSize, types } | ||
export default imageMeta; | ||
export { types }; |
@@ -1,47 +0,47 @@ | ||
'use strict' | ||
'use strict'; | ||
Object.defineProperty(exports, '__esModule', { value: true }) | ||
Object.defineProperty(exports, '__esModule', { value: true }); | ||
const BMP = { | ||
validate (buffer) { | ||
return buffer.toString('ascii', 0, 2) === 'BM' | ||
validate(buffer) { | ||
return buffer.toString("ascii", 0, 2) === "BM"; | ||
}, | ||
calculate (buffer) { | ||
calculate(buffer) { | ||
return { | ||
height: Math.abs(buffer.readInt32LE(22)), | ||
width: buffer.readUInt32LE(18) | ||
} | ||
}; | ||
} | ||
} | ||
}; | ||
const TYPE_ICON = 1 | ||
const SIZE_HEADER = 2 + 2 + 2 | ||
const SIZE_IMAGE_ENTRY = 1 + 1 + 1 + 1 + 2 + 2 + 4 + 4 | ||
function getSizeFromOffset (buffer, offset) { | ||
const value = buffer.readUInt8(offset) | ||
return value === 0 ? 256 : value | ||
const TYPE_ICON = 1; | ||
const SIZE_HEADER = 2 + 2 + 2; | ||
const SIZE_IMAGE_ENTRY = 1 + 1 + 1 + 1 + 2 + 2 + 4 + 4; | ||
function getSizeFromOffset(buffer, offset) { | ||
const value = buffer.readUInt8(offset); | ||
return value === 0 ? 256 : value; | ||
} | ||
function getImageSize (buffer, imageIndex) { | ||
const offset = SIZE_HEADER + imageIndex * SIZE_IMAGE_ENTRY | ||
function getImageSize(buffer, imageIndex) { | ||
const offset = SIZE_HEADER + imageIndex * SIZE_IMAGE_ENTRY; | ||
return { | ||
height: getSizeFromOffset(buffer, offset + 1), | ||
width: getSizeFromOffset(buffer, offset) | ||
} | ||
}; | ||
} | ||
const ICO = { | ||
validate (buffer) { | ||
validate(buffer) { | ||
if (buffer.readUInt16LE(0) !== 0) { | ||
return false | ||
return false; | ||
} | ||
return buffer.readUInt16LE(2) === TYPE_ICON | ||
return buffer.readUInt16LE(2) === TYPE_ICON; | ||
}, | ||
calculate (buffer) { | ||
const nbImages = buffer.readUInt16LE(4) | ||
const imageSize = getImageSize(buffer, 0) | ||
calculate(buffer) { | ||
const nbImages = buffer.readUInt16LE(4); | ||
const imageSize = getImageSize(buffer, 0); | ||
if (nbImages === 1) { | ||
return imageSize | ||
return imageSize; | ||
} | ||
const imgs = [imageSize] | ||
const imgs = [imageSize]; | ||
for (let imageIndex = 1; imageIndex < nbImages; imageIndex += 1) { | ||
imgs.push(getImageSize(buffer, imageIndex)) | ||
imgs.push(getImageSize(buffer, imageIndex)); | ||
} | ||
@@ -52,56 +52,56 @@ const result = { | ||
width: imageSize.width | ||
} | ||
return result | ||
}; | ||
return result; | ||
} | ||
} | ||
}; | ||
const TYPE_CURSOR = 2 | ||
const TYPE_CURSOR = 2; | ||
const CUR = { | ||
validate (buffer) { | ||
validate(buffer) { | ||
if (buffer.readUInt16LE(0) !== 0) { | ||
return false | ||
return false; | ||
} | ||
return buffer.readUInt16LE(2) === TYPE_CURSOR | ||
return buffer.readUInt16LE(2) === TYPE_CURSOR; | ||
}, | ||
calculate (buffer) { | ||
return ICO.calculate(buffer) | ||
calculate(buffer) { | ||
return ICO.calculate(buffer); | ||
} | ||
} | ||
}; | ||
const DDS = { | ||
validate (buffer) { | ||
return buffer.readUInt32LE(0) === 542327876 | ||
validate(buffer) { | ||
return buffer.readUInt32LE(0) === 542327876; | ||
}, | ||
calculate (buffer) { | ||
calculate(buffer) { | ||
return { | ||
height: buffer.readUInt32LE(12), | ||
width: buffer.readUInt32LE(16) | ||
} | ||
}; | ||
} | ||
} | ||
}; | ||
const gifRegexp = /^GIF8[79]a/ | ||
const gifRegexp = /^GIF8[79]a/; | ||
const GIF = { | ||
validate (buffer) { | ||
const signature = buffer.toString('ascii', 0, 6) | ||
return gifRegexp.test(signature) | ||
validate(buffer) { | ||
const signature = buffer.toString("ascii", 0, 6); | ||
return gifRegexp.test(signature); | ||
}, | ||
calculate (buffer) { | ||
calculate(buffer) { | ||
return { | ||
height: buffer.readUInt16LE(8), | ||
width: buffer.readUInt16LE(6) | ||
} | ||
}; | ||
} | ||
} | ||
}; | ||
const SIZE_HEADER$1 = 4 + 4 | ||
const FILE_LENGTH_OFFSET = 4 | ||
const ENTRY_LENGTH_OFFSET = 4 | ||
const SIZE_HEADER$1 = 4 + 4; | ||
const FILE_LENGTH_OFFSET = 4; | ||
const ENTRY_LENGTH_OFFSET = 4; | ||
const ICON_TYPE_SIZE = { | ||
ICON: 32, | ||
'ICN#': 32, | ||
'icm#': 16, | ||
"ICN#": 32, | ||
"icm#": 16, | ||
icm4: 16, | ||
icm8: 16, | ||
'ics#': 16, | ||
"ics#": 16, | ||
ics4: 16, | ||
@@ -132,27 +132,27 @@ ics8: 16, | ||
ic10: 1024 | ||
} | ||
function readImageHeader (buffer, imageOffset) { | ||
const imageLengthOffset = imageOffset + ENTRY_LENGTH_OFFSET | ||
}; | ||
function readImageHeader(buffer, imageOffset) { | ||
const imageLengthOffset = imageOffset + ENTRY_LENGTH_OFFSET; | ||
return [ | ||
buffer.toString('ascii', imageOffset, imageLengthOffset), | ||
buffer.toString("ascii", imageOffset, imageLengthOffset), | ||
buffer.readUInt32BE(imageLengthOffset) | ||
] | ||
]; | ||
} | ||
function getImageSize$1 (type) { | ||
const size = ICON_TYPE_SIZE[type] | ||
return { width: size, height: size, type } | ||
function getImageSize$1(type) { | ||
const size = ICON_TYPE_SIZE[type]; | ||
return {width: size, height: size, type}; | ||
} | ||
const ICNS = { | ||
validate (buffer) { | ||
return buffer.toString('ascii', 0, 4) === 'icns' | ||
validate(buffer) { | ||
return buffer.toString("ascii", 0, 4) === "icns"; | ||
}, | ||
calculate (buffer) { | ||
const bufferLength = buffer.length | ||
const fileLength = buffer.readUInt32BE(FILE_LENGTH_OFFSET) | ||
let imageOffset = SIZE_HEADER$1 | ||
let imageHeader = readImageHeader(buffer, imageOffset) | ||
let imageSize = getImageSize$1(imageHeader[0]) | ||
imageOffset += imageHeader[1] | ||
calculate(buffer) { | ||
const bufferLength = buffer.length; | ||
const fileLength = buffer.readUInt32BE(FILE_LENGTH_OFFSET); | ||
let imageOffset = SIZE_HEADER$1; | ||
let imageHeader = readImageHeader(buffer, imageOffset); | ||
let imageSize = getImageSize$1(imageHeader[0]); | ||
imageOffset += imageHeader[1]; | ||
if (imageOffset === fileLength) { | ||
return imageSize | ||
return imageSize; | ||
} | ||
@@ -163,43 +163,43 @@ const result = { | ||
width: imageSize.width | ||
} | ||
}; | ||
while (imageOffset < fileLength && imageOffset < bufferLength) { | ||
imageHeader = readImageHeader(buffer, imageOffset) | ||
imageSize = getImageSize$1(imageHeader[0]) | ||
imageOffset += imageHeader[1] | ||
result.images.push(imageSize) | ||
imageHeader = readImageHeader(buffer, imageOffset); | ||
imageSize = getImageSize$1(imageHeader[0]); | ||
imageOffset += imageHeader[1]; | ||
result.images.push(imageSize); | ||
} | ||
return result | ||
return result; | ||
} | ||
} | ||
}; | ||
const J2C = { | ||
validate (buffer) { | ||
return buffer.toString('hex', 0, 4) === 'ff4fff51' | ||
validate(buffer) { | ||
return buffer.toString("hex", 0, 4) === "ff4fff51"; | ||
}, | ||
calculate (buffer) { | ||
calculate(buffer) { | ||
return { | ||
height: buffer.readUInt32BE(12), | ||
width: buffer.readUInt32BE(8) | ||
} | ||
}; | ||
} | ||
} | ||
}; | ||
const BoxTypes = { | ||
ftyp: '66747970', | ||
ihdr: '69686472', | ||
jp2h: '6a703268', | ||
jp__: '6a502020', | ||
rreq: '72726571', | ||
xml_: '786d6c20' | ||
} | ||
ftyp: "66747970", | ||
ihdr: "69686472", | ||
jp2h: "6a703268", | ||
jp__: "6a502020", | ||
rreq: "72726571", | ||
xml_: "786d6c20" | ||
}; | ||
const calculateRREQLength = (box) => { | ||
const unit = box.readUInt8(0) | ||
let offset = 1 + 2 * unit | ||
const numStdFlags = box.readUInt16BE(offset) | ||
const flagsLength = numStdFlags * (2 + unit) | ||
offset = offset + 2 + flagsLength | ||
const numVendorFeatures = box.readUInt16BE(offset) | ||
const featuresLength = numVendorFeatures * (16 + unit) | ||
return offset + 2 + featuresLength | ||
} | ||
const unit = box.readUInt8(0); | ||
let offset = 1 + 2 * unit; | ||
const numStdFlags = box.readUInt16BE(offset); | ||
const flagsLength = numStdFlags * (2 + unit); | ||
offset = offset + 2 + flagsLength; | ||
const numVendorFeatures = box.readUInt16BE(offset); | ||
const featuresLength = numVendorFeatures * (16 + unit); | ||
return offset + 2 + featuresLength; | ||
}; | ||
const parseIHDR = (box) => { | ||
@@ -209,120 +209,120 @@ return { | ||
width: box.readUInt32BE(8) | ||
} | ||
} | ||
}; | ||
}; | ||
const JP2 = { | ||
validate (buffer) { | ||
const signature = buffer.toString('hex', 4, 8) | ||
const signatureLength = buffer.readUInt32BE(0) | ||
validate(buffer) { | ||
const signature = buffer.toString("hex", 4, 8); | ||
const signatureLength = buffer.readUInt32BE(0); | ||
if (signature !== BoxTypes.jp__ || signatureLength < 1) { | ||
return false | ||
return false; | ||
} | ||
const ftypeBoxStart = signatureLength + 4 | ||
const ftypBoxLength = buffer.readUInt32BE(signatureLength) | ||
const ftypBox = buffer.slice(ftypeBoxStart, ftypeBoxStart + ftypBoxLength) | ||
return ftypBox.toString('hex', 0, 4) === BoxTypes.ftyp | ||
const ftypeBoxStart = signatureLength + 4; | ||
const ftypBoxLength = buffer.readUInt32BE(signatureLength); | ||
const ftypBox = buffer.slice(ftypeBoxStart, ftypeBoxStart + ftypBoxLength); | ||
return ftypBox.toString("hex", 0, 4) === BoxTypes.ftyp; | ||
}, | ||
calculate (buffer) { | ||
const signatureLength = buffer.readUInt32BE(0) | ||
const ftypBoxLength = buffer.readUInt16BE(signatureLength + 2) | ||
let offset = signatureLength + 4 + ftypBoxLength | ||
const nextBoxType = buffer.toString('hex', offset, offset + 4) | ||
calculate(buffer) { | ||
const signatureLength = buffer.readUInt32BE(0); | ||
const ftypBoxLength = buffer.readUInt16BE(signatureLength + 2); | ||
let offset = signatureLength + 4 + ftypBoxLength; | ||
const nextBoxType = buffer.toString("hex", offset, offset + 4); | ||
switch (nextBoxType) { | ||
case BoxTypes.rreq: | ||
const MAGIC = 4 | ||
offset = offset + 4 + MAGIC + calculateRREQLength(buffer.slice(offset + 4)) | ||
return parseIHDR(buffer.slice(offset + 8, offset + 24)) | ||
const MAGIC = 4; | ||
offset = offset + 4 + MAGIC + calculateRREQLength(buffer.slice(offset + 4)); | ||
return parseIHDR(buffer.slice(offset + 8, offset + 24)); | ||
case BoxTypes.jp2h: | ||
return parseIHDR(buffer.slice(offset + 8, offset + 24)) | ||
return parseIHDR(buffer.slice(offset + 8, offset + 24)); | ||
default: | ||
throw new TypeError('Unsupported header found: ' + buffer.toString('ascii', offset, offset + 4)) | ||
throw new TypeError("Unsupported header found: " + buffer.toString("ascii", offset, offset + 4)); | ||
} | ||
} | ||
} | ||
}; | ||
function readUInt (buffer, bits, offset, isBigEndian) { | ||
offset = offset || 0 | ||
const endian = isBigEndian ? 'BE' : 'LE' | ||
const methodName = 'readUInt' + bits + endian | ||
return buffer[methodName].call(buffer, offset) | ||
function readUInt(buffer, bits, offset, isBigEndian) { | ||
offset = offset || 0; | ||
const endian = isBigEndian ? "BE" : "LE"; | ||
const methodName = "readUInt" + bits + endian; | ||
return buffer[methodName].call(buffer, offset); | ||
} | ||
const EXIF_MARKER = '45786966' | ||
const APP1_DATA_SIZE_BYTES = 2 | ||
const EXIF_HEADER_BYTES = 6 | ||
const TIFF_BYTE_ALIGN_BYTES = 2 | ||
const BIG_ENDIAN_BYTE_ALIGN = '4d4d' | ||
const LITTLE_ENDIAN_BYTE_ALIGN = '4949' | ||
const IDF_ENTRY_BYTES = 12 | ||
const NUM_DIRECTORY_ENTRIES_BYTES = 2 | ||
function isEXIF (buffer) { | ||
return buffer.toString('hex', 2, 6) === EXIF_MARKER | ||
const EXIF_MARKER = "45786966"; | ||
const APP1_DATA_SIZE_BYTES = 2; | ||
const EXIF_HEADER_BYTES = 6; | ||
const TIFF_BYTE_ALIGN_BYTES = 2; | ||
const BIG_ENDIAN_BYTE_ALIGN = "4d4d"; | ||
const LITTLE_ENDIAN_BYTE_ALIGN = "4949"; | ||
const IDF_ENTRY_BYTES = 12; | ||
const NUM_DIRECTORY_ENTRIES_BYTES = 2; | ||
function isEXIF(buffer) { | ||
return buffer.toString("hex", 2, 6) === EXIF_MARKER; | ||
} | ||
function extractSize (buffer, index) { | ||
function extractSize(buffer, index) { | ||
return { | ||
height: buffer.readUInt16BE(index), | ||
width: buffer.readUInt16BE(index + 2) | ||
} | ||
}; | ||
} | ||
function extractOrientation (exifBlock, isBigEndian) { | ||
const idfOffset = 8 | ||
const offset = EXIF_HEADER_BYTES + idfOffset | ||
const idfDirectoryEntries = readUInt(exifBlock, 16, offset, isBigEndian) | ||
function extractOrientation(exifBlock, isBigEndian) { | ||
const idfOffset = 8; | ||
const offset = EXIF_HEADER_BYTES + idfOffset; | ||
const idfDirectoryEntries = readUInt(exifBlock, 16, offset, isBigEndian); | ||
for (let directoryEntryNumber = 0; directoryEntryNumber < idfDirectoryEntries; directoryEntryNumber++) { | ||
const start = offset + NUM_DIRECTORY_ENTRIES_BYTES + directoryEntryNumber * IDF_ENTRY_BYTES | ||
const end = start + IDF_ENTRY_BYTES | ||
const start = offset + NUM_DIRECTORY_ENTRIES_BYTES + directoryEntryNumber * IDF_ENTRY_BYTES; | ||
const end = start + IDF_ENTRY_BYTES; | ||
if (start > exifBlock.length) { | ||
return | ||
return; | ||
} | ||
const block = exifBlock.slice(start, end) | ||
const tagNumber = readUInt(block, 16, 0, isBigEndian) | ||
const block = exifBlock.slice(start, end); | ||
const tagNumber = readUInt(block, 16, 0, isBigEndian); | ||
if (tagNumber === 274) { | ||
const dataFormat = readUInt(block, 16, 2, isBigEndian) | ||
const dataFormat = readUInt(block, 16, 2, isBigEndian); | ||
if (dataFormat !== 3) { | ||
return | ||
return; | ||
} | ||
const numberOfComponents = readUInt(block, 32, 4, isBigEndian) | ||
const numberOfComponents = readUInt(block, 32, 4, isBigEndian); | ||
if (numberOfComponents !== 1) { | ||
return | ||
return; | ||
} | ||
return readUInt(block, 16, 8, isBigEndian) | ||
return readUInt(block, 16, 8, isBigEndian); | ||
} | ||
} | ||
} | ||
function validateExifBlock (buffer, index) { | ||
const exifBlock = buffer.slice(APP1_DATA_SIZE_BYTES, index) | ||
const byteAlign = exifBlock.toString('hex', EXIF_HEADER_BYTES, EXIF_HEADER_BYTES + TIFF_BYTE_ALIGN_BYTES) | ||
const isBigEndian = byteAlign === BIG_ENDIAN_BYTE_ALIGN | ||
const isLittleEndian = byteAlign === LITTLE_ENDIAN_BYTE_ALIGN | ||
function validateExifBlock(buffer, index) { | ||
const exifBlock = buffer.slice(APP1_DATA_SIZE_BYTES, index); | ||
const byteAlign = exifBlock.toString("hex", EXIF_HEADER_BYTES, EXIF_HEADER_BYTES + TIFF_BYTE_ALIGN_BYTES); | ||
const isBigEndian = byteAlign === BIG_ENDIAN_BYTE_ALIGN; | ||
const isLittleEndian = byteAlign === LITTLE_ENDIAN_BYTE_ALIGN; | ||
if (isBigEndian || isLittleEndian) { | ||
return extractOrientation(exifBlock, isBigEndian) | ||
return extractOrientation(exifBlock, isBigEndian); | ||
} | ||
} | ||
function validateBuffer (buffer, index) { | ||
function validateBuffer(buffer, index) { | ||
if (index > buffer.length) { | ||
throw new TypeError('Corrupt JPG, exceeded buffer limits') | ||
throw new TypeError("Corrupt JPG, exceeded buffer limits"); | ||
} | ||
if (buffer[index] !== 255) { | ||
throw new TypeError('Invalid JPG, marker table corrupted') | ||
throw new TypeError("Invalid JPG, marker table corrupted"); | ||
} | ||
} | ||
const JPG = { | ||
validate (buffer) { | ||
const SOIMarker = buffer.toString('hex', 0, 2) | ||
return SOIMarker === 'ffd8' | ||
validate(buffer) { | ||
const SOIMarker = buffer.toString("hex", 0, 2); | ||
return SOIMarker === "ffd8"; | ||
}, | ||
calculate (buffer) { | ||
buffer = buffer.slice(4) | ||
let orientation | ||
let next | ||
calculate(buffer) { | ||
buffer = buffer.slice(4); | ||
let orientation; | ||
let next; | ||
while (buffer.length) { | ||
const i = buffer.readUInt16BE(0) | ||
const i = buffer.readUInt16BE(0); | ||
if (isEXIF(buffer)) { | ||
orientation = validateExifBlock(buffer, i) | ||
orientation = validateExifBlock(buffer, i); | ||
} | ||
validateBuffer(buffer, i) | ||
next = buffer[i + 1] | ||
validateBuffer(buffer, i); | ||
next = buffer[i + 1]; | ||
if (next === 192 || next === 193 || next === 194) { | ||
const size = extractSize(buffer, i + 5) | ||
const size = extractSize(buffer, i + 5); | ||
if (!orientation) { | ||
return size | ||
return size; | ||
} | ||
@@ -333,46 +333,46 @@ return { | ||
width: size.width | ||
} | ||
}; | ||
} | ||
buffer = buffer.slice(i + 2) | ||
buffer = buffer.slice(i + 2); | ||
} | ||
throw new TypeError('Invalid JPG, no size found') | ||
throw new TypeError("Invalid JPG, no size found"); | ||
} | ||
} | ||
}; | ||
const SIGNATURE = 'KTX 11' | ||
const SIGNATURE = "KTX 11"; | ||
const KTX = { | ||
validate (buffer) { | ||
return SIGNATURE === buffer.toString('ascii', 1, 7) | ||
validate(buffer) { | ||
return SIGNATURE === buffer.toString("ascii", 1, 7); | ||
}, | ||
calculate (buffer) { | ||
calculate(buffer) { | ||
return { | ||
height: buffer.readUInt32LE(40), | ||
width: buffer.readUInt32LE(36) | ||
} | ||
}; | ||
} | ||
} | ||
}; | ||
const pngSignature = 'PNG\r\n\n' | ||
const pngImageHeaderChunkName = 'IHDR' | ||
const pngFriedChunkName = 'CgBI' | ||
const pngSignature = "PNG\r\n\n"; | ||
const pngImageHeaderChunkName = "IHDR"; | ||
const pngFriedChunkName = "CgBI"; | ||
const PNG = { | ||
validate (buffer) { | ||
if (pngSignature === buffer.toString('ascii', 1, 8)) { | ||
let chunkName = buffer.toString('ascii', 12, 16) | ||
validate(buffer) { | ||
if (pngSignature === buffer.toString("ascii", 1, 8)) { | ||
let chunkName = buffer.toString("ascii", 12, 16); | ||
if (chunkName === pngFriedChunkName) { | ||
chunkName = buffer.toString('ascii', 28, 32) | ||
chunkName = buffer.toString("ascii", 28, 32); | ||
} | ||
if (chunkName !== pngImageHeaderChunkName) { | ||
throw new TypeError('Invalid PNG') | ||
throw new TypeError("Invalid PNG"); | ||
} | ||
return true | ||
return true; | ||
} | ||
return false | ||
return false; | ||
}, | ||
calculate (buffer) { | ||
if (buffer.toString('ascii', 12, 16) === pngFriedChunkName) { | ||
calculate(buffer) { | ||
if (buffer.toString("ascii", 12, 16) === pngFriedChunkName) { | ||
return { | ||
height: buffer.readUInt32BE(36), | ||
width: buffer.readUInt32BE(32) | ||
} | ||
}; | ||
} | ||
@@ -382,27 +382,27 @@ return { | ||
width: buffer.readUInt32BE(16) | ||
} | ||
}; | ||
} | ||
} | ||
}; | ||
const PNMTypes = { | ||
P1: 'pbm/ascii', | ||
P2: 'pgm/ascii', | ||
P3: 'ppm/ascii', | ||
P4: 'pbm', | ||
P5: 'pgm', | ||
P6: 'ppm', | ||
P7: 'pam', | ||
PF: 'pfm' | ||
} | ||
const Signatures = Object.keys(PNMTypes) | ||
P1: "pbm/ascii", | ||
P2: "pgm/ascii", | ||
P3: "ppm/ascii", | ||
P4: "pbm", | ||
P5: "pgm", | ||
P6: "ppm", | ||
P7: "pam", | ||
PF: "pfm" | ||
}; | ||
const Signatures = Object.keys(PNMTypes); | ||
const handlers = { | ||
default: (lines) => { | ||
let dimensions = [] | ||
let dimensions = []; | ||
while (lines.length > 0) { | ||
const line = lines.shift() | ||
if (line[0] === '#') { | ||
continue | ||
const line = lines.shift(); | ||
if (line[0] === "#") { | ||
continue; | ||
} | ||
dimensions = line.split(' ') | ||
break | ||
dimensions = line.split(" "); | ||
break; | ||
} | ||
@@ -413,20 +413,20 @@ if (dimensions.length === 2) { | ||
width: parseInt(dimensions[0], 10) | ||
} | ||
}; | ||
} else { | ||
throw new TypeError('Invalid PNM') | ||
throw new TypeError("Invalid PNM"); | ||
} | ||
}, | ||
pam: (lines) => { | ||
const size = {} | ||
const size = {}; | ||
while (lines.length > 0) { | ||
const line = lines.shift() | ||
const line = lines.shift(); | ||
if (line.length > 16 || line.charCodeAt(0) > 128) { | ||
continue | ||
continue; | ||
} | ||
const [key, value] = line.split(' ') | ||
const [key, value] = line.split(" "); | ||
if (key && value) { | ||
size[key.toLowerCase()] = parseInt(value, 10) | ||
size[key.toLowerCase()] = parseInt(value, 10); | ||
} | ||
if (size.height && size.width) { | ||
break | ||
break; | ||
} | ||
@@ -438,35 +438,35 @@ } | ||
width: size.width | ||
} | ||
}; | ||
} else { | ||
throw new TypeError('Invalid PAM') | ||
throw new TypeError("Invalid PAM"); | ||
} | ||
} | ||
} | ||
}; | ||
const PNM = { | ||
validate (buffer) { | ||
const signature = buffer.toString('ascii', 0, 2) | ||
return Signatures.includes(signature) | ||
validate(buffer) { | ||
const signature = buffer.toString("ascii", 0, 2); | ||
return Signatures.includes(signature); | ||
}, | ||
calculate (buffer) { | ||
const signature = buffer.toString('ascii', 0, 2) | ||
const type = PNMTypes[signature] | ||
const lines = buffer.toString('ascii', 3).split(/[\r\n]+/) | ||
const handler = handlers[type] || handlers.default | ||
return handler(lines) | ||
calculate(buffer) { | ||
const signature = buffer.toString("ascii", 0, 2); | ||
const type = PNMTypes[signature]; | ||
const lines = buffer.toString("ascii", 3).split(/[\r\n]+/); | ||
const handler = handlers[type] || handlers.default; | ||
return handler(lines); | ||
} | ||
} | ||
}; | ||
const PSD = { | ||
validate (buffer) { | ||
return buffer.toString('ascii', 0, 4) === '8BPS' | ||
validate(buffer) { | ||
return buffer.toString("ascii", 0, 4) === "8BPS"; | ||
}, | ||
calculate (buffer) { | ||
calculate(buffer) { | ||
return { | ||
height: buffer.readUInt32BE(14), | ||
width: buffer.readUInt32BE(18) | ||
} | ||
}; | ||
} | ||
} | ||
}; | ||
const svgReg = /<svg\s([^>"']|"[^"]*"|'[^']*')*>/ | ||
const svgReg = /<svg\s([^>"']|"[^"]*"|'[^']*')*>/; | ||
const extractorRegExps = { | ||
@@ -477,4 +477,4 @@ height: /\sheight=(['"])([^%]+?)\1/, | ||
width: /\swidth=(['"])([^%]+?)\1/ | ||
} | ||
const INCH_CM = 2.54 | ||
}; | ||
const INCH_CM = 2.54; | ||
const units = { | ||
@@ -488,21 +488,21 @@ cm: 96 / INCH_CM, | ||
pt: 96 / 72 | ||
} | ||
function parseLength (len) { | ||
const m = /([0-9.]+)([a-z]*)/.exec(len) | ||
}; | ||
function parseLength(len) { | ||
const m = /([0-9.]+)([a-z]*)/.exec(len); | ||
if (!m) { | ||
return void 0 | ||
return void 0; | ||
} | ||
return Math.round(parseFloat(m[1]) * (units[m[2]] || 1)) | ||
return Math.round(parseFloat(m[1]) * (units[m[2]] || 1)); | ||
} | ||
function parseViewbox (viewbox) { | ||
const bounds = viewbox.split(' ') | ||
function parseViewbox(viewbox) { | ||
const bounds = viewbox.split(" "); | ||
return { | ||
height: parseLength(bounds[3]), | ||
width: parseLength(bounds[2]) | ||
} | ||
}; | ||
} | ||
function parseAttributes (root) { | ||
const width = root.match(extractorRegExps.width) | ||
const height = root.match(extractorRegExps.height) | ||
const viewbox = root.match(extractorRegExps.viewbox) | ||
function parseAttributes(root) { | ||
const width = root.match(extractorRegExps.width); | ||
const height = root.match(extractorRegExps.height); | ||
const viewbox = root.match(extractorRegExps.viewbox); | ||
return { | ||
@@ -512,12 +512,12 @@ height: height && parseLength(height[2]), | ||
width: width && parseLength(width[2]) | ||
} | ||
}; | ||
} | ||
function calculateByDimensions (attrs) { | ||
function calculateByDimensions(attrs) { | ||
return { | ||
height: attrs.height, | ||
width: attrs.width | ||
} | ||
}; | ||
} | ||
function calculateByViewbox (attrs, viewbox) { | ||
const ratio = viewbox.width / viewbox.height | ||
function calculateByViewbox(attrs, viewbox) { | ||
const ratio = viewbox.width / viewbox.height; | ||
if (attrs.width) { | ||
@@ -527,3 +527,3 @@ return { | ||
width: attrs.width | ||
} | ||
}; | ||
} | ||
@@ -534,3 +534,3 @@ if (attrs.height) { | ||
width: Math.floor(attrs.height * ratio) | ||
} | ||
}; | ||
} | ||
@@ -540,72 +540,72 @@ return { | ||
width: viewbox.width | ||
} | ||
}; | ||
} | ||
const SVG = { | ||
validate (buffer) { | ||
const str = String(buffer) | ||
return svgReg.test(str) | ||
validate(buffer) { | ||
const str = String(buffer); | ||
return svgReg.test(str); | ||
}, | ||
calculate (buffer) { | ||
const root = buffer.toString('utf8').match(extractorRegExps.root) | ||
calculate(buffer) { | ||
const root = buffer.toString("utf8").match(extractorRegExps.root); | ||
if (root) { | ||
const attrs = parseAttributes(root[0]) | ||
const attrs = parseAttributes(root[0]); | ||
if (attrs.width && attrs.height) { | ||
return calculateByDimensions(attrs) | ||
return calculateByDimensions(attrs); | ||
} | ||
if (attrs.viewbox) { | ||
return calculateByViewbox(attrs, attrs.viewbox) | ||
return calculateByViewbox(attrs, attrs.viewbox); | ||
} | ||
} | ||
throw new TypeError('Invalid SVG') | ||
throw new TypeError("Invalid SVG"); | ||
} | ||
} | ||
}; | ||
function calculateExtended (buffer) { | ||
function calculateExtended(buffer) { | ||
return { | ||
height: 1 + buffer.readUIntLE(7, 3), | ||
width: 1 + buffer.readUIntLE(4, 3) | ||
} | ||
}; | ||
} | ||
function calculateLossless (buffer) { | ||
function calculateLossless(buffer) { | ||
return { | ||
height: 1 + ((buffer[4] & 15) << 10 | buffer[3] << 2 | (buffer[2] & 192) >> 6), | ||
width: 1 + ((buffer[2] & 63) << 8 | buffer[1]) | ||
} | ||
}; | ||
} | ||
function calculateLossy (buffer) { | ||
function calculateLossy(buffer) { | ||
return { | ||
height: buffer.readInt16LE(8) & 16383, | ||
width: buffer.readInt16LE(6) & 16383 | ||
} | ||
}; | ||
} | ||
const WEBP = { | ||
validate (buffer) { | ||
const riffHeader = buffer.toString('ascii', 0, 4) === 'RIFF' | ||
const webpHeader = buffer.toString('ascii', 8, 12) === 'WEBP' | ||
const vp8Header = buffer.toString('ascii', 12, 15) === 'VP8' | ||
return riffHeader && webpHeader && vp8Header | ||
validate(buffer) { | ||
const riffHeader = buffer.toString("ascii", 0, 4) === "RIFF"; | ||
const webpHeader = buffer.toString("ascii", 8, 12) === "WEBP"; | ||
const vp8Header = buffer.toString("ascii", 12, 15) === "VP8"; | ||
return riffHeader && webpHeader && vp8Header; | ||
}, | ||
calculate (buffer) { | ||
const chunkHeader = buffer.toString('ascii', 12, 16) | ||
buffer = buffer.slice(20, 30) | ||
if (chunkHeader === 'VP8X') { | ||
const extendedHeader = buffer[0] | ||
const validStart = (extendedHeader & 192) === 0 | ||
const validEnd = (extendedHeader & 1) === 0 | ||
calculate(buffer) { | ||
const chunkHeader = buffer.toString("ascii", 12, 16); | ||
buffer = buffer.slice(20, 30); | ||
if (chunkHeader === "VP8X") { | ||
const extendedHeader = buffer[0]; | ||
const validStart = (extendedHeader & 192) === 0; | ||
const validEnd = (extendedHeader & 1) === 0; | ||
if (validStart && validEnd) { | ||
return calculateExtended(buffer) | ||
return calculateExtended(buffer); | ||
} else { | ||
throw new TypeError('Invalid WebP') | ||
throw new TypeError("Invalid WebP"); | ||
} | ||
} | ||
if (chunkHeader === 'VP8 ' && buffer[0] !== 47) { | ||
return calculateLossy(buffer) | ||
if (chunkHeader === "VP8 " && buffer[0] !== 47) { | ||
return calculateLossy(buffer); | ||
} | ||
const signature = buffer.toString('hex', 3, 6) | ||
if (chunkHeader === 'VP8L' && signature !== '9d012a') { | ||
return calculateLossless(buffer) | ||
const signature = buffer.toString("hex", 3, 6); | ||
if (chunkHeader === "VP8L" && signature !== "9d012a") { | ||
return calculateLossless(buffer); | ||
} | ||
throw new TypeError('Invalid WebP') | ||
throw new TypeError("Invalid WebP"); | ||
} | ||
} | ||
}; | ||
@@ -628,56 +628,56 @@ const typeHandlers = { | ||
webp: WEBP | ||
} | ||
}; | ||
const getMimeType = (type) => { | ||
if (type === 'svg') { | ||
return 'image/svg+xml' | ||
if (type === "svg") { | ||
return "image/svg+xml"; | ||
} | ||
return `image/${type}` | ||
} | ||
return `image/${type}`; | ||
}; | ||
const keys = Object.keys(typeHandlers) | ||
const keys = Object.keys(typeHandlers); | ||
const firstBytes = { | ||
56: 'psd', | ||
66: 'bmp', | ||
68: 'dds', | ||
71: 'gif', | ||
73: 'tiff', | ||
77: 'tiff', | ||
82: 'webp', | ||
105: 'icns', | ||
137: 'png', | ||
255: 'jpg' | ||
} | ||
function detector (buffer) { | ||
const byte = buffer[0] | ||
56: "psd", | ||
66: "bmp", | ||
68: "dds", | ||
71: "gif", | ||
73: "tiff", | ||
77: "tiff", | ||
82: "webp", | ||
105: "icns", | ||
137: "png", | ||
255: "jpg" | ||
}; | ||
function detector(buffer) { | ||
const byte = buffer[0]; | ||
if (byte in firstBytes) { | ||
const type = firstBytes[byte] | ||
const type = firstBytes[byte]; | ||
if (typeHandlers[type].validate(buffer)) { | ||
return type | ||
return type; | ||
} | ||
} | ||
const finder = key => typeHandlers[key].validate(buffer) | ||
return keys.find(finder) | ||
const finder = (key) => typeHandlers[key].validate(buffer); | ||
return keys.find(finder); | ||
} | ||
function lookup (buffer, filepath) { | ||
const type = detector(buffer) | ||
function lookup(buffer, filepath) { | ||
const type = detector(buffer); | ||
if (type && type in typeHandlers) { | ||
const size = typeHandlers[type].calculate(buffer, filepath) | ||
const size = typeHandlers[type].calculate(buffer, filepath); | ||
if (size !== void 0) { | ||
size.type = type | ||
size.mimeType = getMimeType(type) | ||
return size | ||
size.type = type; | ||
size.mimeType = getMimeType(type); | ||
return size; | ||
} | ||
} | ||
throw new TypeError('unsupported file type: ' + type + ' (file: ' + filepath + ')') | ||
throw new TypeError("unsupported file type: " + type + " (file: " + filepath + ")"); | ||
} | ||
function imageSize (input) { | ||
function imageMeta(input) { | ||
if (Buffer.isBuffer(input)) { | ||
return lookup(input) | ||
return lookup(input); | ||
} | ||
throw new Error('Input should be buffer!') | ||
throw new Error("Input should be buffer!"); | ||
} | ||
const types = Object.keys(typeHandlers) | ||
const types = Object.keys(typeHandlers); | ||
exports.imageSize = imageSize | ||
exports.types = types | ||
exports.default = imageMeta; | ||
exports.types = types; |
{ | ||
"name": "image-meta", | ||
"version": "0.0.0", | ||
"version": "0.0.1", | ||
"description": "", | ||
@@ -16,2 +16,3 @@ "repository": "nuxt-contrib/image-meta", | ||
"lint": "eslint --ext .ts,.js .", | ||
"release": "yarn test && yarn build && standard-version && git push --follow-tags && npm publish", | ||
"test": "yarn lint" | ||
@@ -23,2 +24,3 @@ }, | ||
"siroc": "^0.4.0", | ||
"standard-version": "^9.0.0", | ||
"typescript": "^4.0.5" | ||
@@ -25,0 +27,0 @@ }, |
# image-meta | ||
... | ||
[![npm version][npm-v-src]][npm-v-href] | ||
[![npm downloads][npm-d-src]][npm-d-href] | ||
[![bundle phobia][bundlephobia-src]][bundlephobia-href] | ||
Using yarn: | ||
``` | ||
yarn add image-meta | ||
``` | ||
Using npm: | ||
``` | ||
npm install image-meta | ||
``` | ||
Usage: | ||
```ts | ||
import imageMeta from 'image-meta' | ||
import fetch from 'node-fetch' | ||
const data = await fetch(url).then(res => res.buffer()) | ||
const { width, height, mimeType } = await imageMeta(data) | ||
``` | ||
**Note:** This package only works with Node.js because of `Buffer` dependency! | ||
## License | ||
[MIT](./LICENSE) - Based on [image-size](https://github.com/image-size/image-size) | ||
<!-- Refs --> | ||
[npm-v-src]: https://img.shields.io/npm/v/image-meta?style=flat-square | ||
[npm-v-href]: https://npmjs.com/package/image-meta | ||
[npm-d-src]: https://img.shields.io/npm/dm/image-meta?style=flat-square | ||
[npm-d-href]: https://npmjs.com/package/image-meta | ||
[github-actions-src]: https://img.shields.io/github/workflow/status/nuxt-contrib/image-meta/ci/master?style=flat-square | ||
[github-actions-href]: https://github.com/nuxt-contrib/image-meta/actions?query=workflow%3Aci | ||
[bundlephobia-src]: https://img.shields.io/bundlephobia/min/image-meta?style=flat-square | ||
[bundlephobia-href]: https://bundlephobia.com/result?p=image-meta |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
20735
6
665
48
5
1