probe-image-size
Version:
Get image size without full download (JPG, GIF, PNG, WebP, BMP, TIFF, PSD)
167 lines (130 loc) • 4.01 kB
JavaScript
// Utils used to parse miaf-based files (avif/heic/heif)
//
// - image collections are not supported (only last size is reported)
// - images with metadata encoded after image data are not supported
// - images without any `ispe` box are not supported
//
var ParserStream = require('../common').ParserStream
var str2arr = require('../common').str2arr
var sliceEq = require('../common').sliceEq
var readUInt32BE = require('../common').readUInt32BE
var miaf = require('../miaf_utils')
var exif = require('../exif_utils')
var SIG_FTYP = str2arr('ftyp')
function safeSkip (parser, count, callback) {
if (count === 0) { // parser._skipBytes throws error if count === 0
callback()
return
}
parser._skipBytes(count, callback)
}
function readExifOrientation (parser, sandbox, on_orientation) {
if (!sandbox.exif_location || sandbox.exif_location.offset <= sandbox.offset) {
on_orientation(0)
return
}
parser._skipBytes(sandbox.exif_location.offset - sandbox.offset, function () {
sandbox.offset = sandbox.exif_location.offset
parser._bytes(4, function (data) {
sandbox.offset += 4
var sig_offset = readUInt32BE(data, 0)
safeSkip(parser, sig_offset, function () {
sandbox.offset += sig_offset
var byteCount = sandbox.exif_location.length - sig_offset - 4
if (byteCount <= 0) {
on_orientation(0)
return
}
parser._bytes(byteCount, function (exif_data) {
sandbox.offset += byteCount
on_orientation(exif.get_orientation(exif_data))
})
})
})
})
}
// sandbox is a storage for intermediate data retrieved from jpeg while parsing it
function readAvifSize (parser, sandbox) {
parser._bytes(8, function (data) {
sandbox.offset += 8
var size = readUInt32BE(data, 0) - 8
var type = String.fromCharCode.apply(null, data.slice(4, 8))
if (type === 'mdat') {
parser._skipBytes(Infinity)
parser.push(null)
return
}
if (size < 0) {
parser._skipBytes(Infinity)
parser.push(null)
return
}
if (type === 'meta' && size > 0) {
parser._bytes(size, function (data) {
sandbox.offset += size
var imgSize = miaf.readSizeFromMeta(data)
if (!imgSize) {
parser._skipBytes(Infinity)
parser.push(null)
return
}
var result = {
width: imgSize.width,
height: imgSize.height,
type: sandbox.fileType.type,
mime: sandbox.fileType.mime,
wUnits: 'px',
hUnits: 'px'
}
if (imgSize.variants.length > 1) {
result.variants = imgSize.variants
}
if (imgSize.orientation) {
result.orientation = imgSize.orientation
}
sandbox.exif_location = imgSize.exif_location
readExifOrientation(parser, sandbox, function (orientation) {
if (orientation > 0) result.orientation = orientation
parser._skipBytes(Infinity)
parser.push(result)
parser.push(null)
})
})
} else {
safeSkip(parser, size, function () {
sandbox.offset += size
readAvifSize(parser, sandbox)
})
}
})
}
module.exports = function () {
var parser = new ParserStream()
var sandbox = { offset: 0, fileType: null }
parser._bytes(8, function (data) {
sandbox.offset += 8
if (!sliceEq(data, 4, SIG_FTYP)) {
parser._skipBytes(Infinity)
parser.push(null)
return
}
var size = readUInt32BE(data, 0) - 8
if (size <= 0) {
parser._skipBytes(Infinity)
parser.push(null)
return
}
parser._bytes(size, function (data) {
sandbox.offset += size
sandbox.fileType = miaf.getMimeType(data)
if (!sandbox.fileType) {
parser._skipBytes(Infinity)
parser.push(null)
return
}
readAvifSize(parser, sandbox)
})
})
return parser
}