Socket
Socket
Sign inDemoInstall

image-size

Package Overview
Dependencies
Maintainers
1
Versions
65
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

image-size - npm Package Compare versions

Comparing version 1.0.2 to 1.1.0

dist/types/heif.d.ts

5

dist/detector.d.ts

@@ -1,3 +0,2 @@

/// <reference types="node" />
import { imageType } from './types';
export declare function detector(buffer: Buffer): imageType | undefined;
import type { imageType } from './types/index';
export declare function detector(input: Uint8Array): imageType | undefined;

14

dist/detector.js
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.detector = void 0;
const types_1 = require("./types");
const keys = Object.keys(types_1.typeHandlers);
const index_1 = require("./types/index");
const keys = Object.keys(index_1.typeHandlers);
// This map helps avoid validating for every single image type

@@ -17,15 +17,15 @@ const firstBytes = {

0x89: 'png',
0xff: 'jpg'
0xff: 'jpg',
};
function detector(buffer) {
const byte = buffer[0];
function detector(input) {
const byte = input[0];
if (byte in firstBytes) {
const type = firstBytes[byte];
if (type && types_1.typeHandlers[type].validate(buffer)) {
if (type && index_1.typeHandlers[type].validate(input)) {
return type;
}
}
const finder = (key) => types_1.typeHandlers[key].validate(buffer);
const finder = (key) => index_1.typeHandlers[key].validate(input);
return keys.find(finder);
}
exports.detector = detector;

@@ -1,7 +0,6 @@

/// <reference types="node" />
import { imageType } from './types';
import { ISizeCalculationResult } from './types/interface';
declare type CallbackFn = (e: Error | null, r?: ISizeCalculationResult) => void;
import type { imageType } from './types/index';
import type { ISizeCalculationResult } from './types/interface';
type CallbackFn = (e: Error | null, r?: ISizeCalculationResult) => void;
export default imageSize;
export declare function imageSize(input: Buffer | string): ISizeCalculationResult;
export declare function imageSize(input: Uint8Array | string): ISizeCalculationResult;
export declare function imageSize(input: string, callback: CallbackFn): void;

@@ -8,0 +7,0 @@ export declare const disableFS: (v: boolean) => void;

@@ -7,7 +7,7 @@ "use strict";

const queue_1 = require("queue");
const types_1 = require("./types");
const index_1 = require("./types/index");
const detector_1 = require("./detector");
// Maximum buffer size, with a default of 512 kilobytes.
// Maximum input size, with a default of 512 kilobytes.
// TO-DO: make this adaptive based on the initial signature of the image
const MaxBufferSize = 512 * 1024;
const MaxInputSize = 512 * 1024;
// This queue is for async `fs` operations, to avoid reaching file-descriptor limits

@@ -17,14 +17,14 @@ const queue = new queue_1.default({ concurrency: 100, autostart: true });

disabledFS: false,
disabledTypes: []
disabledTypes: [],
};
/**
* Return size information based on a buffer
* Return size information based on an Uint8Array
*
* @param {Buffer} buffer
* @param {Uint8Array} input
* @param {String} filepath
* @returns {Object}
*/
function lookup(buffer, filepath) {
function lookup(input, filepath) {
// detect the file type.. don't rely on the extension
const type = (0, detector_1.detector)(buffer);
const type = (0, detector_1.detector)(input);
if (typeof type !== 'undefined') {

@@ -35,6 +35,6 @@ if (globalOptions.disabledTypes.indexOf(type) > -1) {

// find an appropriate handler for this file type
if (type in types_1.typeHandlers) {
const size = types_1.typeHandlers[type].calculate(buffer, filepath);
if (type in index_1.typeHandlers) {
const size = index_1.typeHandlers[type].calculate(input, filepath);
if (size !== undefined) {
size.type = type;
size.type = size.type ?? type;
return size;

@@ -48,7 +48,7 @@ }

/**
* Reads a file into a buffer.
* Reads a file into an Uint8Array.
* @param {String} filepath
* @returns {Promise<Buffer>}
* @returns {Promise<Uint8Array>}
*/
async function asyncFileToBuffer(filepath) {
async function readFileAsync(filepath) {
const handle = await fs.promises.open(filepath, 'r');

@@ -60,6 +60,6 @@ try {

}
const bufferSize = Math.min(size, MaxBufferSize);
const buffer = Buffer.alloc(bufferSize);
await handle.read(buffer, 0, bufferSize, 0);
return buffer;
const inputSize = Math.min(size, MaxInputSize);
const input = new Uint8Array(inputSize);
await handle.read(input, 0, inputSize, 0);
return input;
}

@@ -71,8 +71,8 @@ finally {

/**
* Synchronously reads a file into a buffer, blocking the nodejs process.
* Synchronously reads a file into an Uint8Array, blocking the nodejs process.
*
* @param {String} filepath
* @returns {Buffer}
* @returns {Uint8Array}
*/
function syncFileToBuffer(filepath) {
function readFileSync(filepath) {
// read from the file, synchronously

@@ -85,6 +85,6 @@ const descriptor = fs.openSync(filepath, 'r');

}
const bufferSize = Math.min(size, MaxBufferSize);
const buffer = Buffer.alloc(bufferSize);
fs.readSync(descriptor, buffer, 0, bufferSize, 0);
return buffer;
const inputSize = Math.min(size, MaxInputSize);
const input = new Uint8Array(inputSize);
fs.readSync(descriptor, input, 0, inputSize, 0);
return input;
}

@@ -99,8 +99,8 @@ finally {

/**
* @param {Buffer|string} input - buffer or relative/absolute path of the image file
* @param {Uint8Array|string} input - Uint8Array or relative/absolute path of the image file
* @param {Function=} [callback] - optional function for async detection
*/
function imageSize(input, callback) {
// Handle buffer input
if (Buffer.isBuffer(input)) {
// Handle Uint8Array input
if (input instanceof Uint8Array) {
return lookup(input);

@@ -110,3 +110,3 @@ }

if (typeof input !== 'string' || globalOptions.disabledFS) {
throw new TypeError('invalid invocation. input should be a Buffer');
throw new TypeError('invalid invocation. input should be a Uint8Array');
}

@@ -116,18 +116,24 @@ // resolve the file path

if (typeof callback === 'function') {
queue.push(() => asyncFileToBuffer(filepath)
.then((buffer) => process.nextTick(callback, null, lookup(buffer, filepath)))
queue.push(() => readFileAsync(filepath)
.then((input) => process.nextTick(callback, null, lookup(input, filepath)))
.catch(callback));
}
else {
const buffer = syncFileToBuffer(filepath);
return lookup(buffer, filepath);
const input = readFileSync(filepath);
return lookup(input, filepath);
}
}
exports.imageSize = imageSize;
const disableFS = (v) => { globalOptions.disabledFS = v; };
const disableFS = (v) => {
globalOptions.disabledFS = v;
};
exports.disableFS = disableFS;
const disableTypes = (types) => { globalOptions.disabledTypes = types; };
const disableTypes = (types) => {
globalOptions.disabledTypes = types;
};
exports.disableTypes = disableTypes;
const setConcurrency = (c) => { queue.concurrency = c; };
const setConcurrency = (c) => {
queue.concurrency = c;
};
exports.setConcurrency = setConcurrency;
exports.types = Object.keys(types_1.typeHandlers);
exports.types = Object.keys(index_1.typeHandlers);

@@ -1,2 +0,2 @@

import { IImage } from './interface';
import type { IImage } from './interface';
export declare const BMP: IImage;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.BMP = void 0;
const utils_1 = require("./utils");
exports.BMP = {
validate(buffer) {
return ('BM' === buffer.toString('ascii', 0, 2));
},
calculate(buffer) {
return {
height: Math.abs(buffer.readInt32LE(22)),
width: buffer.readUInt32LE(18)
};
}
validate: (input) => (0, utils_1.toUTF8String)(input, 0, 2) === 'BM',
calculate: (input) => ({
height: Math.abs((0, utils_1.readInt32LE)(input, 22)),
width: (0, utils_1.readUInt32LE)(input, 18),
}),
};

@@ -1,2 +0,2 @@

import { IImage } from './interface';
import type { IImage } from './interface';
export declare const CUR: IImage;

@@ -5,16 +5,14 @@ "use strict";

const ico_1 = require("./ico");
const utils_1 = require("./utils");
const TYPE_CURSOR = 2;
exports.CUR = {
validate(buffer) {
const reserved = buffer.readUInt16LE(0);
const imageCount = buffer.readUInt16LE(4);
if (reserved !== 0 || imageCount === 0) {
validate(input) {
const reserved = (0, utils_1.readUInt16LE)(input, 0);
const imageCount = (0, utils_1.readUInt16LE)(input, 4);
if (reserved !== 0 || imageCount === 0)
return false;
}
const imageType = buffer.readUInt16LE(2);
const imageType = (0, utils_1.readUInt16LE)(input, 2);
return imageType === TYPE_CURSOR;
},
calculate(buffer) {
return ico_1.ICO.calculate(buffer);
}
calculate: (input) => ico_1.ICO.calculate(input),
};

@@ -1,2 +0,2 @@

import { IImage } from './interface';
import type { IImage } from './interface';
export declare const DDS: IImage;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.DDS = void 0;
const utils_1 = require("./utils");
exports.DDS = {
validate(buffer) {
return buffer.readUInt32LE(0) === 0x20534444;
},
calculate(buffer) {
return {
height: buffer.readUInt32LE(12),
width: buffer.readUInt32LE(16)
};
}
validate: (input) => (0, utils_1.readUInt32LE)(input, 0) === 0x20534444,
calculate: (input) => ({
height: (0, utils_1.readUInt32LE)(input, 12),
width: (0, utils_1.readUInt32LE)(input, 16),
}),
};

@@ -1,2 +0,2 @@

import { IImage } from './interface';
import type { IImage } from './interface';
export declare const GIF: IImage;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.GIF = void 0;
const utils_1 = require("./utils");
const gifRegexp = /^GIF8[79]a/;
exports.GIF = {
validate(buffer) {
const signature = buffer.toString('ascii', 0, 6);
return (gifRegexp.test(signature));
},
calculate(buffer) {
return {
height: buffer.readUInt16LE(8),
width: buffer.readUInt16LE(6)
};
}
validate: (input) => gifRegexp.test((0, utils_1.toUTF8String)(input, 0, 6)),
calculate: (input) => ({
height: (0, utils_1.readUInt16LE)(input, 8),
width: (0, utils_1.readUInt16LE)(input, 6),
}),
};

@@ -1,2 +0,2 @@

import { IImage } from './interface';
import type { IImage } from './interface';
export declare const ICNS: IImage;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ICNS = void 0;
const utils_1 = require("./utils");
/**

@@ -65,7 +66,7 @@ * ICNS Header

};
function readImageHeader(buffer, imageOffset) {
function readImageHeader(input, imageOffset) {
const imageLengthOffset = imageOffset + ENTRY_LENGTH_OFFSET;
return [
buffer.toString('ascii', imageOffset, imageLengthOffset),
buffer.readUInt32BE(imageLengthOffset)
(0, utils_1.toUTF8String)(input, imageOffset, imageLengthOffset),
(0, utils_1.readUInt32BE)(input, imageLengthOffset),
];

@@ -78,22 +79,19 @@ }

exports.ICNS = {
validate(buffer) {
return ('icns' === buffer.toString('ascii', 0, 4));
},
calculate(buffer) {
const bufferLength = buffer.length;
const fileLength = buffer.readUInt32BE(FILE_LENGTH_OFFSET);
validate: (input) => (0, utils_1.toUTF8String)(input, 0, 4) === 'icns',
calculate(input) {
const inputLength = input.length;
const fileLength = (0, utils_1.readUInt32BE)(input, FILE_LENGTH_OFFSET);
let imageOffset = SIZE_HEADER;
let imageHeader = readImageHeader(buffer, imageOffset);
let imageHeader = readImageHeader(input, imageOffset);
let imageSize = getImageSize(imageHeader[0]);
imageOffset += imageHeader[1];
if (imageOffset === fileLength) {
if (imageOffset === fileLength)
return imageSize;
}
const result = {
height: imageSize.height,
images: [imageSize],
width: imageSize.width
width: imageSize.width,
};
while (imageOffset < fileLength && imageOffset < bufferLength) {
imageHeader = readImageHeader(buffer, imageOffset);
while (imageOffset < fileLength && imageOffset < inputLength) {
imageHeader = readImageHeader(input, imageOffset);
imageSize = getImageSize(imageHeader[0]);

@@ -104,3 +102,3 @@ imageOffset += imageHeader[1];

return result;
}
},
};

@@ -1,2 +0,2 @@

import { IImage } from './interface';
import type { IImage } from './interface';
export declare const ICO: IImage;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ICO = void 0;
const utils_1 = require("./utils");
const TYPE_ICON = 1;

@@ -32,40 +33,37 @@ /**

const SIZE_IMAGE_ENTRY = 1 + 1 + 1 + 1 + 2 + 2 + 4 + 4; // 16
function getSizeFromOffset(buffer, offset) {
const value = buffer.readUInt8(offset);
function getSizeFromOffset(input, offset) {
const value = input[offset];
return value === 0 ? 256 : value;
}
function getImageSize(buffer, imageIndex) {
const offset = SIZE_HEADER + (imageIndex * SIZE_IMAGE_ENTRY);
function getImageSize(input, imageIndex) {
const offset = SIZE_HEADER + imageIndex * SIZE_IMAGE_ENTRY;
return {
height: getSizeFromOffset(buffer, offset + 1),
width: getSizeFromOffset(buffer, offset)
height: getSizeFromOffset(input, offset + 1),
width: getSizeFromOffset(input, offset),
};
}
exports.ICO = {
validate(buffer) {
const reserved = buffer.readUInt16LE(0);
const imageCount = buffer.readUInt16LE(4);
if (reserved !== 0 || imageCount === 0) {
validate(input) {
const reserved = (0, utils_1.readUInt16LE)(input, 0);
const imageCount = (0, utils_1.readUInt16LE)(input, 4);
if (reserved !== 0 || imageCount === 0)
return false;
}
const imageType = buffer.readUInt16LE(2);
const imageType = (0, utils_1.readUInt16LE)(input, 2);
return imageType === TYPE_ICON;
},
calculate(buffer) {
const nbImages = buffer.readUInt16LE(4);
const imageSize = getImageSize(buffer, 0);
if (nbImages === 1) {
calculate(input) {
const nbImages = (0, utils_1.readUInt16LE)(input, 4);
const imageSize = getImageSize(input, 0);
if (nbImages === 1)
return imageSize;
}
const imgs = [imageSize];
for (let imageIndex = 1; imageIndex < nbImages; imageIndex += 1) {
imgs.push(getImageSize(buffer, imageIndex));
imgs.push(getImageSize(input, imageIndex));
}
const result = {
return {
height: imageSize.height,
images: imgs,
width: imageSize.width
width: imageSize.width,
};
return result;
}
},
};

@@ -1,3 +0,2 @@

/// <reference types="node" />
export interface ISize {
export type ISize = {
width: number | undefined;

@@ -7,9 +6,9 @@ height: number | undefined;

type?: string;
}
export interface ISizeCalculationResult extends ISize {
};
export type ISizeCalculationResult = {
images?: ISize[];
}
export interface IImage {
validate: (buffer: Buffer) => boolean;
calculate: (buffer: Buffer, filepath?: string) => ISizeCalculationResult;
}
} & ISize;
export type IImage = {
validate: (input: Uint8Array) => boolean;
calculate: (input: Uint8Array, filepath?: string) => ISizeCalculationResult;
};

@@ -1,2 +0,2 @@

import { IImage } from './interface';
import type { IImage } from './interface';
export declare const J2C: IImage;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.J2C = void 0;
const utils_1 = require("./utils");
exports.J2C = {
validate(buffer) {
// TODO: this doesn't seem right. SIZ marker doesn't have to be right after the SOC
return buffer.toString('hex', 0, 4) === 'ff4fff51';
},
calculate(buffer) {
return {
height: buffer.readUInt32BE(12),
width: buffer.readUInt32BE(8),
};
}
// TODO: this doesn't seem right. SIZ marker doesn't have to be right after the SOC
validate: (input) => (0, utils_1.toHexString)(input, 0, 4) === 'ff4fff51',
calculate: (input) => ({
height: (0, utils_1.readUInt32BE)(input, 12),
width: (0, utils_1.readUInt32BE)(input, 8),
}),
};

@@ -1,2 +0,2 @@

import { IImage } from './interface';
import type { IImage } from './interface';
export declare const JP2: IImage;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.JP2 = void 0;
const BoxTypes = {
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 parseIHDR = (box) => {
return {
height: box.readUInt32BE(4),
width: box.readUInt32BE(8),
};
};
const utils_1 = require("./utils");
exports.JP2 = {
validate(buffer) {
const signature = buffer.toString('hex', 4, 8);
const signatureLength = buffer.readUInt32BE(0);
if (signature !== BoxTypes.jp__ || signatureLength < 1) {
validate(input) {
if ((0, utils_1.readUInt32BE)(input, 4) !== 0x6a502020 || (0, utils_1.readUInt32BE)(input, 0) < 1)
return false;
const ftypBox = (0, utils_1.findBox)(input, 'ftyp', 0);
if (!ftypBox)
return false;
return (0, utils_1.readUInt32BE)(input, ftypBox.offset + 4) === 0x66747970;
},
calculate(input) {
const jp2hBox = (0, utils_1.findBox)(input, 'jp2h', 0);
const ihdrBox = jp2hBox && (0, utils_1.findBox)(input, 'ihdr', jp2hBox.offset + 8);
if (ihdrBox) {
return {
height: (0, utils_1.readUInt32BE)(input, ihdrBox.offset + 8),
width: (0, utils_1.readUInt32BE)(input, ihdrBox.offset + 12),
};
}
const ftypeBoxStart = signatureLength + 4;
const ftypBoxLength = buffer.readUInt32BE(signatureLength);
const ftypBox = buffer.slice(ftypeBoxStart, ftypeBoxStart + ftypBoxLength);
return ftypBox.toString('hex', 0, 4) === BoxTypes.ftyp;
throw new TypeError('Unsupported JPEG 2000 format');
},
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:
// WHAT ARE THESE 4 BYTES?????
// eslint-disable-next-line no-case-declarations
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));
default:
throw new TypeError('Unsupported header found: ' + buffer.toString('ascii', offset, offset + 4));
}
}
};

@@ -1,2 +0,2 @@

import { IImage } from './interface';
import type { IImage } from './interface';
export declare const JPG: IImage;

@@ -8,3 +8,3 @@ "use strict";

exports.JPG = void 0;
const readUInt_1 = require("../readUInt");
const utils_1 = require("./utils");
const EXIF_MARKER = '45786966';

@@ -19,9 +19,9 @@ const APP1_DATA_SIZE_BYTES = 2;

const NUM_DIRECTORY_ENTRIES_BYTES = 2;
function isEXIF(buffer) {
return (buffer.toString('hex', 2, 6) === EXIF_MARKER);
function isEXIF(input) {
return (0, utils_1.toHexString)(input, 2, 6) === EXIF_MARKER;
}
function extractSize(buffer, index) {
function extractSize(input, index) {
return {
height: buffer.readUInt16BE(index),
width: buffer.readUInt16BE(index + 2)
height: (0, utils_1.readUInt16BE)(input, index),
width: (0, utils_1.readUInt16BE)(input, index + 2),
};

@@ -38,5 +38,7 @@ }

const offset = EXIF_HEADER_BYTES + idfOffset;
const idfDirectoryEntries = (0, readUInt_1.readUInt)(exifBlock, 16, offset, isBigEndian);
const idfDirectoryEntries = (0, utils_1.readUInt)(exifBlock, 16, offset, isBigEndian);
for (let directoryEntryNumber = 0; directoryEntryNumber < idfDirectoryEntries; directoryEntryNumber++) {
const start = offset + NUM_DIRECTORY_ENTRIES_BYTES + (directoryEntryNumber * IDF_ENTRY_BYTES);
const start = offset +
NUM_DIRECTORY_ENTRIES_BYTES +
directoryEntryNumber * IDF_ENTRY_BYTES;
const end = start + IDF_ENTRY_BYTES;

@@ -48,6 +50,6 @@ // Skip on corrupt EXIF blocks

const block = exifBlock.slice(start, end);
const tagNumber = (0, readUInt_1.readUInt)(block, 16, 0, isBigEndian);
const tagNumber = (0, utils_1.readUInt)(block, 16, 0, isBigEndian);
// 0x0112 (decimal: 274) is the `orientation` tag ID
if (tagNumber === 274) {
const dataFormat = (0, readUInt_1.readUInt)(block, 16, 2, isBigEndian);
const dataFormat = (0, utils_1.readUInt)(block, 16, 2, isBigEndian);
if (dataFormat !== 3) {

@@ -58,15 +60,15 @@ return;

// if there would more than 4 bytes in total it's a pointer
const numberOfComponents = (0, readUInt_1.readUInt)(block, 32, 4, isBigEndian);
const numberOfComponents = (0, utils_1.readUInt)(block, 32, 4, isBigEndian);
if (numberOfComponents !== 1) {
return;
}
return (0, readUInt_1.readUInt)(block, 16, 8, isBigEndian);
return (0, utils_1.readUInt)(block, 16, 8, isBigEndian);
}
}
}
function validateExifBlock(buffer, index) {
function validateExifBlock(input, index) {
// Skip APP1 Data Size
const exifBlock = buffer.slice(APP1_DATA_SIZE_BYTES, index);
const exifBlock = input.slice(APP1_DATA_SIZE_BYTES, index);
// Consider byte alignment
const byteAlign = exifBlock.toString('hex', EXIF_HEADER_BYTES, EXIF_HEADER_BYTES + TIFF_BYTE_ALIGN_BYTES);
const byteAlign = (0, utils_1.toHexString)(exifBlock, EXIF_HEADER_BYTES, EXIF_HEADER_BYTES + TIFF_BYTE_ALIGN_BYTES);
// Ignore Empty EXIF. Validate byte alignment

@@ -79,36 +81,34 @@ const isBigEndian = byteAlign === BIG_ENDIAN_BYTE_ALIGN;

}
function validateBuffer(buffer, index) {
function validateInput(input, index) {
// index should be within buffer limits
if (index > buffer.length) {
if (index > input.length) {
throw new TypeError('Corrupt JPG, exceeded buffer limits');
}
// Every JPEG block must begin with a 0xFF
if (buffer[index] !== 0xFF) {
throw new TypeError('Invalid JPG, marker table corrupted');
}
}
exports.JPG = {
validate(buffer) {
const SOIMarker = buffer.toString('hex', 0, 2);
return ('ffd8' === SOIMarker);
},
calculate(buffer) {
validate: (input) => (0, utils_1.toHexString)(input, 0, 2) === 'ffd8',
calculate(input) {
// Skip 4 chars, they are for signature
buffer = buffer.slice(4);
input = input.slice(4);
let orientation;
let next;
while (buffer.length) {
while (input.length) {
// read length of the next block
const i = buffer.readUInt16BE(0);
if (isEXIF(buffer)) {
orientation = validateExifBlock(buffer, i);
const i = (0, utils_1.readUInt16BE)(input, 0);
// Every JPEG block must begin with a 0xFF
if (input[i] !== 0xff) {
input = input.slice(1);
continue;
}
if (isEXIF(input)) {
orientation = validateExifBlock(input, i);
}
// ensure correct format
validateBuffer(buffer, i);
validateInput(input, i);
// 0xFFC0 is baseline standard(SOF)
// 0xFFC1 is baseline optimized(SOF)
// 0xFFC2 is progressive(SOF2)
next = buffer[i + 1];
if (next === 0xC0 || next === 0xC1 || next === 0xC2) {
const size = extractSize(buffer, i + 5);
next = input[i + 1];
if (next === 0xc0 || next === 0xc1 || next === 0xc2) {
const size = extractSize(input, i + 5);
// TODO: is orientation=0 a valid answer here?

@@ -121,10 +121,10 @@ if (!orientation) {

orientation,
width: size.width
width: size.width,
};
}
// move to the next block
buffer = buffer.slice(i + 2);
input = input.slice(i + 2);
}
throw new TypeError('Invalid JPG, no size found');
}
},
};

@@ -1,2 +0,2 @@

import { IImage } from './interface';
import type { IImage } from './interface';
export declare const KTX: IImage;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.KTX = void 0;
const SIGNATURE = 'KTX 11';
const utils_1 = require("./utils");
exports.KTX = {
validate(buffer) {
return SIGNATURE === buffer.toString('ascii', 1, 7);
validate: (input) => {
const signature = (0, utils_1.toUTF8String)(input, 1, 7);
return ['KTX 11', 'KTX 20'].includes(signature);
},
calculate(buffer) {
return {
height: buffer.readUInt32LE(40),
width: buffer.readUInt32LE(36),
};
}
calculate: (input) => {
const type = input[5] === 0x31 ? 'ktx' : 'ktx2';
const offset = type === 'ktx' ? 36 : 20;
return ({
height: (0, utils_1.readUInt32LE)(input, offset + 4),
width: (0, utils_1.readUInt32LE)(input, offset),
type,
});
},
};

@@ -1,2 +0,2 @@

import { IImage } from './interface';
import type { IImage } from './interface';
export declare const PNG: IImage;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.PNG = void 0;
const utils_1 = require("./utils");
const pngSignature = 'PNG\r\n\x1a\n';

@@ -9,7 +10,7 @@ const pngImageHeaderChunkName = 'IHDR';

exports.PNG = {
validate(buffer) {
if (pngSignature === buffer.toString('ascii', 1, 8)) {
let chunkName = buffer.toString('ascii', 12, 16);
validate(input) {
if (pngSignature === (0, utils_1.toUTF8String)(input, 1, 8)) {
let chunkName = (0, utils_1.toUTF8String)(input, 12, 16);
if (chunkName === pngFriedChunkName) {
chunkName = buffer.toString('ascii', 28, 32);
chunkName = (0, utils_1.toUTF8String)(input, 28, 32);
}

@@ -23,14 +24,14 @@ if (chunkName !== pngImageHeaderChunkName) {

},
calculate(buffer) {
if (buffer.toString('ascii', 12, 16) === pngFriedChunkName) {
calculate(input) {
if ((0, utils_1.toUTF8String)(input, 12, 16) === pngFriedChunkName) {
return {
height: buffer.readUInt32BE(36),
width: buffer.readUInt32BE(32)
height: (0, utils_1.readUInt32BE)(input, 36),
width: (0, utils_1.readUInt32BE)(input, 32),
};
}
return {
height: buffer.readUInt32BE(20),
width: buffer.readUInt32BE(16)
height: (0, utils_1.readUInt32BE)(input, 20),
width: (0, utils_1.readUInt32BE)(input, 16),
};
}
},
};

@@ -1,2 +0,2 @@

import { IImage } from './interface';
import type { IImage } from './interface';
export declare const PNM: IImage;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.PNM = void 0;
const utils_1 = require("./utils");
const PNMTypes = {

@@ -12,5 +13,4 @@ P1: 'pbm/ascii',

P7: 'pam',
PF: 'pfm'
PF: 'pfm',
};
const Signatures = Object.keys(PNMTypes);
const handlers = {

@@ -55,3 +55,3 @@ default: (lines) => {

height: size.height,
width: size.width
width: size.width,
};

@@ -62,17 +62,14 @@ }

}
}
},
};
exports.PNM = {
validate(buffer) {
const signature = buffer.toString('ascii', 0, 2);
return Signatures.includes(signature);
},
calculate(buffer) {
const signature = buffer.toString('ascii', 0, 2);
validate: (input) => (0, utils_1.toUTF8String)(input, 0, 2) in PNMTypes,
calculate(input) {
const signature = (0, utils_1.toUTF8String)(input, 0, 2);
const type = PNMTypes[signature];
// TODO: this probably generates garbage. move to a stream based parser
const lines = buffer.toString('ascii', 3).split(/[\r\n]+/);
const lines = (0, utils_1.toUTF8String)(input, 3).split(/[\r\n]+/);
const handler = handlers[type] || handlers.default;
return handler(lines);
}
},
};

@@ -1,2 +0,2 @@

import { IImage } from './interface';
import type { IImage } from './interface';
export declare const PSD: IImage;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.PSD = void 0;
const utils_1 = require("./utils");
exports.PSD = {
validate(buffer) {
return ('8BPS' === buffer.toString('ascii', 0, 4));
},
calculate(buffer) {
return {
height: buffer.readUInt32BE(14),
width: buffer.readUInt32BE(18)
};
}
validate: (input) => (0, utils_1.toUTF8String)(input, 0, 4) === '8BPS',
calculate: (input) => ({
height: (0, utils_1.readUInt32BE)(input, 14),
width: (0, utils_1.readUInt32BE)(input, 18),
}),
};

@@ -1,2 +0,2 @@

import { IImage } from './interface';
import type { IImage } from './interface';
export declare const SVG: IImage;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.SVG = void 0;
const utils_1 = require("./utils");
const svgReg = /<svg\s([^>"']|"[^"]*"|'[^']*')*>/;

@@ -17,7 +18,7 @@ const extractorRegExps = {

ex: 8,
m: 96 / INCH_CM * 100,
m: (96 / INCH_CM) * 100,
mm: 96 / INCH_CM / 10,
pc: 96 / 72 / 12,
pt: 96 / 72,
px: 1
px: 1,
};

@@ -36,3 +37,3 @@ const unitsReg = new RegExp(`^([0-9.]+(?:e\\d+)?)(${Object.keys(units).join('|')})?$`);

height: parseLength(bounds[3]),
width: parseLength(bounds[2])
width: parseLength(bounds[2]),
};

@@ -76,8 +77,6 @@ }

exports.SVG = {
validate(buffer) {
const str = String(buffer);
return svgReg.test(str);
},
calculate(buffer) {
const root = buffer.toString('utf8').match(extractorRegExps.root);
// Scan only the first kilo-byte to speed up the check on larger files
validate: (input) => svgReg.test((0, utils_1.toUTF8String)(input, 0, 1000)),
calculate(input) {
const root = (0, utils_1.toUTF8String)(input).match(extractorRegExps.root);
if (root) {

@@ -93,3 +92,3 @@ const attrs = parseAttributes(root[0]);

throw new TypeError('Invalid SVG');
}
},
};

@@ -1,2 +0,2 @@

import { IImage } from './interface';
import type { IImage } from './interface';
export declare const TGA: IImage;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.TGA = void 0;
const utils_1 = require("./utils");
exports.TGA = {
validate(buffer) {
return buffer.readUInt16LE(0) === 0 && buffer.readUInt16LE(4) === 0;
validate(input) {
return (0, utils_1.readUInt16LE)(input, 0) === 0 && (0, utils_1.readUInt16LE)(input, 4) === 0;
},
calculate(buffer) {
calculate(input) {
return {
height: buffer.readUInt16LE(14),
width: buffer.readUInt16LE(12),
height: (0, utils_1.readUInt16LE)(input, 14),
width: (0, utils_1.readUInt16LE)(input, 12),
};
}
},
};

@@ -1,2 +0,2 @@

import { IImage } from './interface';
import type { IImage } from './interface';
export declare const TIFF: IImage;

@@ -7,6 +7,6 @@ "use strict";

const fs = require("fs");
const readUInt_1 = require("../readUInt");
const utils_1 = require("./utils");
// Read IFD (image-file-directory) into a buffer
function readIFD(buffer, filepath, isBigEndian) {
const ifdOffset = (0, readUInt_1.readUInt)(buffer, 32, 4, isBigEndian);
function readIFD(input, filepath, isBigEndian) {
const ifdOffset = (0, utils_1.readUInt)(input, 32, 4, isBigEndian);
// read only till the end of the file

@@ -19,3 +19,3 @@ let bufferSize = 1024;

// populate the buffer
const endBuffer = Buffer.alloc(bufferSize);
const endBuffer = new Uint8Array(bufferSize);
const descriptor = fs.openSync(filepath, 'r');

@@ -27,21 +27,21 @@ fs.readSync(descriptor, endBuffer, 0, bufferSize, ifdOffset);

// TIFF values seem to be messed up on Big-Endian, this helps
function readValue(buffer, isBigEndian) {
const low = (0, readUInt_1.readUInt)(buffer, 16, 8, isBigEndian);
const high = (0, readUInt_1.readUInt)(buffer, 16, 10, isBigEndian);
function readValue(input, isBigEndian) {
const low = (0, utils_1.readUInt)(input, 16, 8, isBigEndian);
const high = (0, utils_1.readUInt)(input, 16, 10, isBigEndian);
return (high << 16) + low;
}
// move to the next tag
function nextTag(buffer) {
if (buffer.length > 24) {
return buffer.slice(12);
function nextTag(input) {
if (input.length > 24) {
return input.slice(12);
}
}
// Extract IFD tags from TIFF metadata
function extractTags(buffer, isBigEndian) {
function extractTags(input, isBigEndian) {
const tags = {};
let temp = buffer;
let temp = input;
while (temp && temp.length) {
const code = (0, readUInt_1.readUInt)(temp, 16, 0, isBigEndian);
const type = (0, readUInt_1.readUInt)(temp, 16, 2, isBigEndian);
const length = (0, readUInt_1.readUInt)(temp, 32, 4, isBigEndian);
const code = (0, utils_1.readUInt)(temp, 16, 0, isBigEndian);
const type = (0, utils_1.readUInt)(temp, 16, 2, isBigEndian);
const length = (0, utils_1.readUInt)(temp, 32, 4, isBigEndian);
// 0 means end of IFD

@@ -64,4 +64,4 @@ if (code === 0) {

// Test if the TIFF is Big Endian or Little Endian
function determineEndianness(buffer) {
const signature = buffer.toString('ascii', 0, 2);
function determineEndianness(input) {
const signature = (0, utils_1.toUTF8String)(input, 0, 2);
if ('II' === signature) {

@@ -81,6 +81,4 @@ return 'LE';

exports.TIFF = {
validate(buffer) {
return signatures.includes(buffer.toString('hex', 0, 4));
},
calculate(buffer, filepath) {
validate: (input) => signatures.includes((0, utils_1.toHexString)(input, 0, 4)),
calculate(input, filepath) {
if (!filepath) {

@@ -90,5 +88,5 @@ throw new TypeError('Tiff doesn\'t support buffer');

// Determine BE/LE
const isBigEndian = determineEndianness(buffer) === 'BE';
const isBigEndian = determineEndianness(input) === 'BE';
// read the IFD
const ifdBuffer = readIFD(buffer, filepath, isBigEndian);
const ifdBuffer = readIFD(input, filepath, isBigEndian);
// extract the tags from the IFD

@@ -102,3 +100,3 @@ const tags = extractTags(ifdBuffer, isBigEndian);

return { height, width };
}
},
};

@@ -1,2 +0,2 @@

import { IImage } from './interface';
import type { IImage } from './interface';
export declare const WEBP: IImage;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.WEBP = void 0;
function calculateExtended(buffer) {
const utils_1 = require("./utils");
function calculateExtended(input) {
return {
height: 1 + buffer.readUIntLE(7, 3),
width: 1 + buffer.readUIntLE(4, 3)
height: 1 + (0, utils_1.readUInt24LE)(input, 7),
width: 1 + (0, utils_1.readUInt24LE)(input, 4),
};
}
function calculateLossless(buffer) {
function calculateLossless(input) {
return {
height: 1 + (((buffer[4] & 0xF) << 10) | (buffer[3] << 2) | ((buffer[2] & 0xC0) >> 6)),
width: 1 + (((buffer[2] & 0x3F) << 8) | buffer[1])
height: 1 +
(((input[4] & 0xf) << 10) | (input[3] << 2) | ((input[2] & 0xc0) >> 6)),
width: 1 + (((input[2] & 0x3f) << 8) | input[1]),
};
}
function calculateLossy(buffer) {
function calculateLossy(input) {
// `& 0x3fff` returns the last 14 bits
// TO-DO: include webp scaling in the calculations
return {
height: buffer.readInt16LE(8) & 0x3fff,
width: buffer.readInt16LE(6) & 0x3fff
height: (0, utils_1.readInt16LE)(input, 8) & 0x3fff,
width: (0, utils_1.readInt16LE)(input, 6) & 0x3fff,
};
}
exports.WEBP = {
validate(buffer) {
const riffHeader = 'RIFF' === buffer.toString('ascii', 0, 4);
const webpHeader = 'WEBP' === buffer.toString('ascii', 8, 12);
const vp8Header = 'VP8' === buffer.toString('ascii', 12, 15);
return (riffHeader && webpHeader && vp8Header);
validate(input) {
const riffHeader = 'RIFF' === (0, utils_1.toUTF8String)(input, 0, 4);
const webpHeader = 'WEBP' === (0, utils_1.toUTF8String)(input, 8, 12);
const vp8Header = 'VP8' === (0, utils_1.toUTF8String)(input, 12, 15);
return riffHeader && webpHeader && vp8Header;
},
calculate(buffer) {
const chunkHeader = buffer.toString('ascii', 12, 16);
buffer = buffer.slice(20, 30);
calculate(input) {
const chunkHeader = (0, utils_1.toUTF8String)(input, 12, 16);
input = input.slice(20, 30);
// Extended webp stream signature
if (chunkHeader === 'VP8X') {
const extendedHeader = buffer[0];
const extendedHeader = input[0];
const validStart = (extendedHeader & 0xc0) === 0;
const validEnd = (extendedHeader & 0x01) === 0;
if (validStart && validEnd) {
return calculateExtended(buffer);
return calculateExtended(input);
}

@@ -48,12 +50,12 @@ else {

// Lossless webp stream signature
if (chunkHeader === 'VP8 ' && buffer[0] !== 0x2f) {
return calculateLossy(buffer);
if (chunkHeader === 'VP8 ' && input[0] !== 0x2f) {
return calculateLossy(input);
}
// Lossy webp stream signature
const signature = buffer.toString('hex', 3, 6);
const signature = (0, utils_1.toHexString)(input, 3, 6);
if (chunkHeader === 'VP8L' && signature !== '9d012a') {
return calculateLossless(buffer);
return calculateLossless(input);
}
throw new TypeError('Invalid WebP');
}
},
};
{
"name": "image-size",
"version": "1.0.2",
"version": "1.1.0",
"description": "get dimensions of any image file",

@@ -12,7 +12,9 @@ "main": "dist/index.js",

"engines": {
"node": ">=14.0.0"
"node": ">=18.0.0"
},
"packageManager": "yarn@3.5.1",
"bin": "bin/image-size.js",
"scripts": {
"pretest": "eslint --ext .ts,.js bin lib specs",
"lint": "eslint --ext .ts,.js bin lib specs",
"format": "prettier --write lib specs",
"test": "nyc mocha",

@@ -31,14 +33,17 @@ "clean": "rm -rf dist docs",

"height",
"png",
"jpeg",
"avif",
"bmp",
"cur",
"gif",
"heic",
"heif",
"icns",
"ico",
"jpeg",
"png",
"psd",
"svg",
"tga",
"tiff",
"webp",
"svg",
"icns",
"ico",
"cur"
"webp"
],

@@ -49,23 +54,29 @@ "repository": "git://github.com/image-size/image-size.git",

"devDependencies": {
"@types/chai": "4.3.1",
"@types/glob": "7.2.0",
"@types/mocha": "9.1.1",
"@types/node": "18.0.3",
"@types/sinon": "10.0.12",
"@typescript-eslint/eslint-plugin": "5.30.6",
"@typescript-eslint/parser": "5.30.6",
"chai": "4.3.6",
"eslint": "8.19.0",
"glob": "8.0.3",
"mocha": "10.0.0",
"@types/chai": "4.3.5",
"@types/glob": "8.1.0",
"@types/mocha": "10.0.1",
"@types/node": "18.16.16",
"@types/sinon": "10.0.15",
"@typescript-eslint/eslint-plugin": "5.59.8",
"@typescript-eslint/parser": "5.59.8",
"chai": "4.3.7",
"eslint": "8.41.0",
"eslint-config-prettier": "8.8.0",
"eslint-plugin-prettier": "4.2.1",
"glob": "10.2.6",
"mocha": "10.2.0",
"nyc": "15.1.0",
"sinon": "14.0.0",
"ts-node": "10.8.2",
"typedoc": "0.23.7",
"typescript": "4.7.4"
"prettier": "2.8.8",
"sinon": "15.1.0",
"ts-node": "10.9.1",
"typedoc": "0.24.7",
"typescript": "5.0.4"
},
"nyc": {
"include": "lib",
"exclude": "specs/*.spec.ts"
},
"dependencies": {
"queue": "6.0.2"
},
"packageManager": "yarn@3.2.0"
}
}

@@ -11,19 +11,20 @@ # image-size

* BMP
* CUR
* DDS
* GIF
* ICNS
* ICO
* J2C
* JP2
* JPEG
* KTX
* PNG
* PNM (PAM, PBM, PFM, PGM, PPM)
* PSD
* SVG
* TGA
* TIFF
* WebP
- BMP
- CUR
- DDS
- GIF
- HEIC (HEIF, AVCI, AVIF)
- ICNS
- ICO
- J2C
- JP2
- JPEG
- KTX (1 and 2)
- PNG
- PNM (PAM, PBM, PFM, PGM, PPM)
- PSD
- SVG
- TGA
- TIFF
- WebP

@@ -45,4 +46,4 @@ ## Programmatic Usage

```javascript
const sizeOf = require('image-size')
const dimensions = sizeOf('images/funny-cats.png')
const sizeOf = require("image-size")
const dimensions = sizeOf("images/funny-cats.png")
console.log(dimensions.width, dimensions.height)

@@ -54,4 +55,4 @@ ```

```javascript
const sizeOf = require('image-size')
sizeOf('images/funny-cats.png', function (err, dimensions) {
const sizeOf = require("image-size")
sizeOf("images/funny-cats.png", function (err, dimensions) {
console.log(dimensions.width, dimensions.height)

@@ -67,3 +68,3 @@ })

```javascript
const sizeOf = require('image-size')
const sizeOf = require("image-size")
sizeOf.setConcurrency(123456)

@@ -75,7 +76,9 @@ ```

```javascript
const { promisify } = require('util')
const sizeOf = promisify(require('image-size'))
sizeOf('images/funny-cats.png')
.then(dimensions => { console.log(dimensions.width, dimensions.height) })
.catch(err => console.error(err))
const { promisify } = require("util")
const sizeOf = promisify(require("image-size"))
sizeOf("images/funny-cats.png")
.then((dimensions) => {
console.log(dimensions.width, dimensions.height)
})
.catch((err) => console.error(err))
```

@@ -86,7 +89,6 @@

```javascript
const { promisify } = require('util')
const sizeOf = promisify(require('image-size'))
(async () => {
const { promisify } = require("util")
const sizeOf = promisify(require("image-size"))(async () => {
try {
const dimensions = await sizeOf('images/funny-cats.png')
const dimensions = await sizeOf("images/funny-cats.png")
console.log(dimensions.width, dimensions.height)

@@ -96,3 +98,3 @@ } catch (err) {

}
})().then(c => console.log(c))
})().then((c) => console.log(c))
```

@@ -107,4 +109,4 @@

```javascript
const sizeOf = require('image-size')
const images = sizeOf('images/multi-size.ico').images
const sizeOf = require("image-size")
const images = sizeOf("images/multi-size.ico").images
for (const dimensions of images) {

@@ -118,8 +120,8 @@ console.log(dimensions.width, dimensions.height)

```javascript
const url = require('url')
const http = require('http')
const url = require("url")
const http = require("http")
const sizeOf = require('image-size')
const sizeOf = require("image-size")
const imgUrl = 'http://my-amazing-website.com/image.jpeg'
const imgUrl = "http://my-amazing-website.com/image.jpeg"
const options = url.parse(imgUrl)

@@ -129,8 +131,10 @@

const chunks = []
response.on('data', function (chunk) {
chunks.push(chunk)
}).on('end', function() {
const buffer = Buffer.concat(chunks)
console.log(sizeOf(buffer))
})
response
.on("data", function (chunk) {
chunks.push(chunk)
})
.on("end", function () {
const buffer = Buffer.concat(chunks)
console.log(sizeOf(buffer))
})
})

@@ -143,10 +147,12 @@ ```

### Disabling certain image types
```javascript
const imageSize = require('image-size')
imageSize.disableTypes(['tiff', 'ico'])
const imageSize = require("image-size")
imageSize.disableTypes(["tiff", "ico"])
```
### Disabling all file-system reads
```javascript
const imageSize = require('image-size')
const imageSize = require("image-size")
imageSize.disableFS(true)

@@ -160,4 +166,4 @@ ```

```javascript
const sizeOf = require('image-size')
const dimensions = sizeOf('images/photo.jpeg')
const sizeOf = require("image-size")
const dimensions = sizeOf("images/photo.jpeg")
console.log(dimensions.orientation)

@@ -184,10 +190,2 @@ ```

## Hosted API
We also provide a hosted API for image-size which may simplify your use case.
<a href="https://image-size.saasify.sh">
<img src="https://badges.saasify.sh?text=View%20Hosted%20API" height="40"/>
</a>
## Credits

@@ -194,0 +192,0 @@

Sorry, the diff of this file is not supported yet

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