Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

probe-image-size

Package Overview
Dependencies
Maintainers
1
Versions
32
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

probe-image-size - npm Package Compare versions

Comparing version 6.0.0 to 7.0.0

lib/exif_utils.js

7

CHANGELOG.md

@@ -9,2 +9,8 @@ # Changelog

## [7.0.0] - 2021-03-11
### Added
- Add AVIF/HEIC/HEIF support.
- Add orientation info.
## [6.0.0] - 2020-11-04

@@ -178,2 +184,3 @@ ### Added

[7.0.0]: https://github.com/nodeca/probe-image-size/compare/6.0.0...7.0.0
[6.0.0]: https://github.com/nodeca/probe-image-size/compare/5.0.0...6.0.0

@@ -180,0 +187,0 @@ [5.0.0]: https://github.com/nodeca/probe-image-size/compare/4.1.1...5.0.0

36

lib/parse_stream/jpeg.js
'use strict';
/* eslint-disable consistent-return */
var ParserStream = require('../common').ParserStream;
var str2arr = require('../common').str2arr;
var sliceEq = require('../common').sliceEq;
var exif = require('../exif_utils');
var SIG_EXIF = str2arr('Exif\0\0');
// part of parseJpegMarker called after skipping initial FF

@@ -52,3 +60,4 @@ function parseJpegMarker_afterFF(parser, callback) {

function getJpegSize(parser) {
// sandbox is a storage for intermediate data retrieved from jpeg while parsing it
function getJpegSize(parser, sandbox) {
parseJpegMarker(parser, function (code, length) {

@@ -69,5 +78,17 @@ if (!code || length < 0) {

// try to get orientation from Exif segment
if (code === 0xE1 && length >= 10) {
parser._bytes(length, function (data) {
if (sliceEq(data, 0, SIG_EXIF)) {
sandbox.orientation = exif.get_orientation(data.slice(6, 6 + length));
}
getJpegSize(parser, sandbox);
});
return;
}
if (length <= 0) {
// e.g. empty comment
getJpegSize(parser);
getJpegSize(parser, sandbox);
return;

@@ -83,3 +104,3 @@ }

parser.push({
var result = {
width: data.readUInt16BE(3),

@@ -91,4 +112,7 @@ height: data.readUInt16BE(1),

hUnits: 'px'
});
};
if (sandbox.orientation > 0) result.orientation = sandbox.orientation;
parser.push(result);
parser.push(null);

@@ -100,3 +124,3 @@ });

parser._skipBytes(length, function () {
getJpegSize(parser);
getJpegSize(parser, sandbox);
});

@@ -118,3 +142,3 @@ });

getJpegSize(parser);
getJpegSize(parser, {});
});

@@ -121,0 +145,0 @@

176

lib/parse_stream/webp.js
'use strict';
/* eslint-disable no-bitwise */
/* eslint-disable no-use-before-define */

@@ -8,28 +9,37 @@ var ParserStream = require('../common').ParserStream;

var sliceEq = require('../common').sliceEq;
var exif = require('../exif_utils');
var SIG_RIFF = str2arr('RIFF');
var SIG_WEBPVP8 = str2arr('WEBPVP8');
var SIG_RIFF = str2arr('RIFF');
var SIG_WEBP = str2arr('WEBP');
function parseVP8(parser) {
parser._bytes(14, function (data) {
parser._skipBytes(Infinity);
function safeSkip(parser, count, callback) {
if (count === 0) { // parser._skipBytes throws error if count === 0
callback();
return;
}
if (data[7] !== 0x9D || data[8] !== 0x01 || data[9] !== 0x2A) {
// bad code block signature
parser.push(null);
return;
parser._skipBytes(count, callback);
}
function parseVP8(parser, length, sandbox) {
parser._bytes(10, function (data) {
// check code block signature
if (data[3] === 0x9D && data[4] === 0x01 && data[5] === 0x2A) {
sandbox.result = sandbox.result || {
width: data.readUInt16LE(6) & 0x3FFF,
height: data.readUInt16LE(8) & 0x3FFF,
type: 'webp',
mime: 'image/webp',
wUnits: 'px',
hUnits: 'px'
};
}
parser.push({
width: data.readUInt16LE(10) & 0x3FFF,
height: data.readUInt16LE(12) & 0x3FFF,
type: 'webp',
mime: 'image/webp',
wUnits: 'px',
hUnits: 'px'
safeSkip(parser, length - 10, function () {
sandbox.offset += length;
getWebpSize(parser, sandbox);
});
parser.push(null);
});

@@ -39,17 +49,33 @@ }

function parseVP8L(parser) {
parser._bytes(9, function (data) {
parser._skipBytes(Infinity);
function parseVP8L(parser, length, sandbox) {
parser._bytes(5, function (data) {
// check code block signature
if (data[0] === 0x2F) {
var bits = data.readUInt32LE(1);
if (data[4] !== 0x2F) {
// bad code block signature
parser.push(null);
return;
sandbox.result = sandbox.result || {
width: (bits & 0x3FFF) + 1,
height: ((bits >> 14) & 0x3FFF) + 1,
type: 'webp',
mime: 'image/webp',
wUnits: 'px',
hUnits: 'px'
};
}
var bits = data.readUInt32LE(5);
safeSkip(parser, length - 5, function () {
sandbox.offset += length;
getWebpSize(parser, sandbox);
});
});
}
parser.push({
width: (bits & 0x3FFF) + 1,
height: ((bits >> 14) & 0x3FFF) + 1,
function parseVP8X(parser, length, sandbox) {
parser._bytes(10, function (data) {
sandbox.result = sandbox.result || {
// TODO: replace with `data.readUIntLE(8, 3) + 1`
// when 0.10 support is dropped
width: ((data[6] << 16) | (data[5] << 8) | data[4]) + 1,
height: ((data[9] << 16) | (data[8] << 8) | data[7]) + 1,
type: 'webp',

@@ -59,5 +85,19 @@ mime: 'image/webp',

hUnits: 'px'
};
safeSkip(parser, length - 10, function () {
sandbox.offset += length;
getWebpSize(parser, sandbox);
});
});
}
parser.push(null);
function parseExif(parser, length, sandbox) {
parser._bytes(length, function (data) {
// exif is the last chunk we care about, stop after it
sandbox.offset = Infinity;
sandbox.exif_orientation = exif.get_orientation(data);
getWebpSize(parser, sandbox);
});

@@ -67,18 +107,54 @@ }

function parseVP8X(parser) {
parser._bytes(14, function (data) {
function getWebpSize(parser, sandbox) {
if (sandbox.fileLength - 8 <= sandbox.offset) {
parser._skipBytes(Infinity);
parser.push({
// TODO: replace with `data.readUIntLE(8, 3) + 1`
// when 0.10 support is dropped
width: ((data[10] << 16) | (data[9] << 8) | data[8]) + 1,
height: ((data[13] << 16) | (data[12] << 8) | data[11]) + 1,
type: 'webp',
mime: 'image/webp',
wUnits: 'px',
hUnits: 'px'
});
if (sandbox.result) {
var result = sandbox.result;
if (sandbox.exif_orientation > 0) {
result.orientation = sandbox.exif_orientation;
}
parser.push(result);
}
parser.push(null);
return;
}
parser._bytes(4 - sandbox.bufferedChunkHeader.length, function (data) {
sandbox.offset += 4 - sandbox.bufferedChunkHeader.length;
var header = sandbox.bufferedChunkHeader + String.fromCharCode.apply(null, data);
// after each chunk of odd size there should be 0 byte of padding, skip those
header = header.replace(/^\0+/, '');
if (header.length < 4) {
sandbox.bufferedChunkHeader = header;
getWebpSize(parser, sandbox);
return;
}
sandbox.bufferedChunkHeader = '';
parser._bytes(4, function (data) {
sandbox.offset += 4;
var length = data.readUInt32LE(0);
if (header === 'VP8 ' && length >= 10) {
parseVP8(parser, length, sandbox);
} else if (header === 'VP8L' && length >= 5) {
parseVP8L(parser, length, sandbox);
} else if (header === 'VP8X' && length >= 10) {
parseVP8X(parser, length, sandbox);
} else if (header === 'EXIF' && length >= 4) {
parseExif(parser, length, sandbox);
} else {
safeSkip(parser, length, function () {
sandbox.offset += length;
getWebpSize(parser, sandbox);
});
}
});
});

@@ -91,12 +167,12 @@ }

parser._bytes(16, function (data) {
parser._bytes(12, function (data) {
// check /^RIFF....WEBPVP8([ LX])$/ signature
if (sliceEq(data, 0, SIG_RIFF) && sliceEq(data, 8, SIG_WEBPVP8)) {
switch (data[15]) {
case 32/*' '*/: parseVP8(parser); return;
case 76/* L */: parseVP8L(parser); return;
case 88/* X */: parseVP8X(parser); return;
}
if (sliceEq(data, 0, SIG_RIFF) && sliceEq(data, 8, SIG_WEBP)) {
getWebpSize(parser, {
fileLength: data.readUInt32LE(4) + 8,
offset: 12,
exif_orientation: 0,
bufferedChunkHeader: '' // for dealing with padding
});
} else {

@@ -103,0 +179,0 @@ parser._skipBytes(Infinity);

@@ -6,4 +6,10 @@ 'use strict';

var readUInt16BE = require('../common').readUInt16BE;
var str2arr = require('../common').str2arr;
var sliceEq = require('../common').sliceEq;
var exif = require('../exif_utils');
var SIG_EXIF = str2arr('Exif\0\0');
module.exports = function (data) {

@@ -48,2 +54,9 @@ if (data.length < 2) return;

var orientation;
// try to get orientation from Exif segment
if (code === 0xE1 && length >= 10 && sliceEq(data, offset, SIG_EXIF)) {
orientation = exif.get_orientation(data.slice(offset + 6, offset + length));
}
if (length >= 5 &&

@@ -55,3 +68,3 @@ (0xC0 <= code && code <= 0xCF) &&

return {
var result = {
width: readUInt16BE(data, offset + 3),

@@ -64,2 +77,8 @@ height: readUInt16BE(data, offset + 1),

};
if (orientation > 0) {
result.orientation = orientation;
}
return result;
}

@@ -66,0 +85,0 @@

@@ -10,12 +10,11 @@ 'use strict';

var readUInt32LE = require('../common').readUInt32LE;
var exif = require('../exif_utils');
var SIG_RIFF = str2arr('RIFF');
var SIG_WEBPVP8 = str2arr('WEBPVP8');
var SIG_RIFF = str2arr('RIFF');
var SIG_WEBP = str2arr('WEBP');
function parseVP8(data) {
if (data.length < 16 + 14) return;
if (data[16 + 7] !== 0x9D || data[16 + 8] !== 0x01 || data[16 + 9] !== 0x2A) {
function parseVP8(data, offset) {
if (data[offset + 3] !== 0x9D || data[offset + 4] !== 0x01 || data[offset + 5] !== 0x2A) {
// bad code block signature

@@ -26,4 +25,4 @@ return;

return {
width: readUInt16LE(data, 16 + 10) & 0x3FFF,
height: readUInt16LE(data, 16 + 12) & 0x3FFF,
width: readUInt16LE(data, offset + 6) & 0x3FFF,
height: readUInt16LE(data, offset + 8) & 0x3FFF,
type: 'webp',

@@ -37,9 +36,7 @@ mime: 'image/webp',

function parseVP8L(data) {
if (data.length < 16 + 9) return;
function parseVP8L(data, offset) {
if (data[offset] !== 0x2F) return;
if (data[16 + 4] !== 0x2F) return;
var bits = readUInt32LE(data, offset + 1);
var bits = readUInt32LE(data, 16 + 5);
return {

@@ -56,10 +53,8 @@ width: (bits & 0x3FFF) + 1,

function parseVP8X(data) {
if (data.length < 16 + 14) return;
function parseVP8X(data, offset) {
return {
// TODO: replace with `data.readUIntLE(8, 3) + 1`
// when 0.10 support is dropped
width: ((data[16 + 10] << 16) | (data[16 + 9] << 8) | data[16 + 8]) + 1,
height: ((data[16 + 13] << 16) | (data[16 + 12] << 8) | data[16 + 11]) + 1,
width: ((data[offset + 6] << 16) | (data[offset + 5] << 8) | data[offset + 4]) + 1,
height: ((data[offset + 9] << offset) | (data[offset + 8] << 8) | data[offset + 7]) + 1,
type: 'webp',

@@ -77,9 +72,44 @@ mime: 'image/webp',

// check /^RIFF....WEBPVP8([ LX])$/ signature
if (sliceEq(data, 0, SIG_RIFF) && sliceEq(data, 8, SIG_WEBPVP8)) {
switch (data[15]) {
case 32/*' '*/: return parseVP8(data);
case 76/* L */: return parseVP8L(data);
case 88/* X */: return parseVP8X(data);
if (!sliceEq(data, 0, SIG_RIFF) && !sliceEq(data, 8, SIG_WEBP)) return;
var offset = 12;
var result = null;
var exif_orientation = 0;
var fileLength = readUInt32LE(data, 4) + 8;
if (fileLength > data.length) return;
while (offset + 8 < fileLength) {
if (data[offset] === 0) {
// after each chunk of odd size there should be 0 byte of padding, skip those
offset++;
continue;
}
var header = String.fromCharCode.apply(null, data.slice(offset, offset + 4));
var length = readUInt32LE(data, offset + 4);
if (header === 'VP8 ' && length >= 10) {
result = result || parseVP8(data, offset + 8);
} else if (header === 'VP8L' && length >= 9) {
result = result || parseVP8L(data, offset + 8);
} else if (header === 'VP8X' && length >= 10) {
result = result || parseVP8X(data, offset + 8);
} else if (header === 'EXIF') {
exif_orientation = exif.get_orientation(data.slice(offset + 8, offset + 8 + length));
// exif is the last chunk we care about, stop after it
offset = Infinity;
}
offset += 8 + length;
}
if (!result) return;
if (exif_orientation > 0) {
result.orientation = exif_orientation;
}
return result;
};
'use strict';
module.exports = {
avif: require('./parse_stream/avif'),
bmp: require('./parse_stream/bmp'),

@@ -5,0 +6,0 @@ gif: require('./parse_stream/gif'),

@@ -5,6 +5,7 @@ 'use strict';

module.exports = {
avif: require('./parse_sync/avif'),
bmp: require('./parse_sync/bmp'),
gif: require('./parse_sync/gif'),
ico: require('./parse_sync/ico'),
jpeg: require('./parse_sync/jpeg'),
ico: require('./parse_sync/ico'),
png: require('./parse_sync/png'),

@@ -11,0 +12,0 @@ psd: require('./parse_sync/psd'),

{
"name": "probe-image-size",
"version": "6.0.0",
"version": "7.0.0",
"description": "Get image size without full download (JPG, GIF, PNG, WebP, BMP, TIFF, PSD)",

@@ -32,3 +32,3 @@ "keywords": [

"coverage": "npm run test && nyc report --reporter html",
"report-coveralls": "nyc report --reporter=text-lcov | coveralls"
"report-coveralls": "nyc --reporter=lcov mocha"
},

@@ -44,3 +44,2 @@ "mocha": {

"devDependencies": {
"coveralls": "^3.0.0",
"eslint": "^7.12.1",

@@ -47,0 +46,0 @@ "mocha": "^8.2.0",

probe-image-size
================
[![Build Status](https://img.shields.io/travis/nodeca/probe-image-size/master.svg?style=flat)](https://travis-ci.org/nodeca/probe-image-size)
[![CI](https://github.com/nodeca/probe-image-size/workflows/CI/badge.svg?branch=master)](https://github.com/nodeca/probe-image-size/actions)
[![NPM version](https://img.shields.io/npm/v/probe-image-size.svg?style=flat)](https://www.npmjs.org/package/probe-image-size)

@@ -9,3 +9,3 @@ [![Coverage Status](https://coveralls.io/repos/github/nodeca/probe-image-size/badge.svg?branch=master)](https://coveralls.io/github/nodeca/probe-image-size?branch=master)

> Get image size without full download. Supported image types:
> JPG, GIF, PNG, WebP, BMP, TIFF, SVG, PSD, ICO.
> JPG, GIF, PNG, WebP, BMP, TIFF, SVG, PSD, ICO, AVIF, HEIC, HEIF.

@@ -96,6 +96,18 @@ Key features:

// (if no redirects, same as src)
variants: [ { width, height }, ... ] | undefined // full list of sizes for ICO
// optional, image orientation (from Exif), number from 1 to 8;
// you may wish to swap width and height if orientation is >= 5
orientation: X,
// optional, full list of sizes for ICO (always) and AVIF (if multiple images)
variants: [ { width, height }, ... ] | undefined
}
```
Width and height in the output object represent image size *before* any transformations
(orientation, cropping) are applied. Orientation is returned separately, which you may
wish to apply afterwards depending on browser support (browsers
[only support JPEG](https://zpl.fi/exif-orientation-in-different-formats/) orientation for now).
See [known issues](known_issues.md) for details.
Returned errors can be extended with 2 fields:

@@ -102,0 +114,0 @@

@@ -13,2 +13,5 @@ 'use strict';

// increase max number of listeners to stop memory leak warning
proxy.setMaxListeners(Object.keys(parsers).length + 10);
var result = new Promise(function (resolve, reject) {

@@ -15,0 +18,0 @@ src.on('error', reject);

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc