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

@eris/exif

Package Overview
Dependencies
Maintainers
1
Versions
109
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@eris/exif - npm Package Compare versions

Comparing version 0.3.1-alpha.2 to 0.3.1-alpha.3

9

dist/decoder/ifd-entry.js

@@ -23,8 +23,11 @@ "use strict";

switch (this.dataType) {
// TODO: verify signed versions
case types_1.IFDDataType.Byte:
case types_1.IFDDataType.Short:
case types_1.IFDDataType.Long:
case types_1.IFDDataType.SignedByte:
case types_1.IFDDataType.SignedShort:
case types_1.IFDDataType.SignedLong:
return entryReader.read(this.lengthInBytes);
case types_1.IFDDataType.Rational:
// TODO: fix signed rational repr
case types_1.IFDDataType.SignedRational:

@@ -42,5 +45,5 @@ return entryReader.read(4) / entryReader.read(4);

return chars.join('');
case types_1.IFDDataType.SingleFloat:
case types_1.IFDDataType.Float:
return new DataView(entryReader.readAsBuffer(4).buffer).getFloat32(0);
case types_1.IFDDataType.DoubleFloat:
case types_1.IFDDataType.Double:
return new DataView(entryReader.readAsBuffer(8).buffer).getFloat64(0);

@@ -47,0 +50,0 @@ case types_1.IFDDataType.Undefined:

@@ -91,5 +91,15 @@ "use strict";

const length = stripBytesEntry.getValue(this._reader);
// TODO: throw if there's more than one strip
if (!maxResolutionJPEG || length > maxResolutionJPEG.length) {
maxResolutionJPEG = { offset, length, ifd };
const jpegBuffer = this._reader.use(() => {
this._reader.seek(offset);
return this._reader.readAsBuffer(length);
});
if (!jpeg_decoder_1.JPEGDecoder.isJPEG(jpegBuffer))
return;
const jpeg = new jpeg_decoder_1.JPEGDecoder(jpegBuffer);
const metadata = jpeg.extractMetadata();
if (!metadata.ImageLength || !metadata.ImageWidth)
return;
if (!maxResolutionJPEG || metadata.ImageWidth > maxResolutionJPEG.metadata.ImageWidth) {
// TODO: throw if there's more than one strip
maxResolutionJPEG = { metadata, buffer: jpegBuffer };
}

@@ -100,11 +110,21 @@ });

}
this._reader.seek(maxResolutionJPEG.offset);
return this._reader.readAsBuffer(maxResolutionJPEG.length);
return maxResolutionJPEG.buffer;
}
_readLargestJPEG() {
const maxResolutionJPEG = this._readLargestJPEGThumbnail() || this._readStripOffsetsAsJPEG();
if (!maxResolutionJPEG) {
throw new Error('Could not find thumbnail or read StripOffsets IFDs');
}
return maxResolutionJPEG;
// Try to read the JPEG thumbnail first
const maxThumbnailJPEG = this._readLargestJPEGThumbnail();
const thumbnailSize = (maxThumbnailJPEG && maxThumbnailJPEG.length) || 0;
// Only return it immediately if it seems large enough (>500KB)
if (maxThumbnailJPEG && thumbnailSize > 500 * 1000)
return maxThumbnailJPEG;
// Otherwise we'll fallback to the JPEG strip offsets
const maxStripOffsetJPEG = this._readStripOffsetsAsJPEG();
// Only return it if it's larger than the thumbnail
if (maxStripOffsetJPEG && maxStripOffsetJPEG.length > thumbnailSize)
return maxStripOffsetJPEG;
// Fallback to the small thumbnail if that's all we found
if (maxThumbnailJPEG)
return maxThumbnailJPEG;
// Fail loudly if all else fails
throw new Error('Could not find thumbnail or read StripOffsets IFDs');
}

@@ -120,2 +140,6 @@ extractJPEG(options = {}) {

const metadata = this.extractMetadata();
delete metadata.ImageWidth;
delete metadata.ImageLength;
delete metadata.EXIFImageWidth;
delete metadata.EXIFImageHeight;
const metadataBuffer = tiff_encoder_1.TIFFEncoder.encode(metadata);

@@ -122,0 +146,0 @@ this._cachedJPEG = jpeg_decoder_1.JPEGDecoder.injectEXIFMetadata(jpeg, metadataBuffer);

@@ -8,2 +8,11 @@ "use strict";

const log = log_1.createLogger('encoder');
const BLACKLISTED_TAGS = new Set([
types_1.IFDTag.SubIFD,
types_1.IFDTag.EXIFOffset,
types_1.IFDTag.StripOffsets,
types_1.IFDTag.StripByteCounts,
types_1.IFDTag.ThumbnailOffset,
types_1.IFDTag.ThumbnailLength,
types_1.IFDTag.RowsPerStrip,
]);
class TIFFEncoder {

@@ -15,2 +24,4 @@ static isSupportedEntry(tag, value) {

return false;
if (BLACKLISTED_TAGS.has(tag.code))
return false;
if (tag.dataType === types_1.IFDDataType.Short)

@@ -17,0 +28,0 @@ return value < Math.pow(2, 16);

@@ -10,4 +10,4 @@ "use strict";

model: ['Model'],
width: ['ImageWidth'],
height: ['ImageLength'],
width: ['EXIFImageWidth', 'ImageWidth'],
height: ['EXIFImageHeight', 'ImageLength'],
xResolution: ['XResolution'],

@@ -14,0 +14,0 @@ yResolution: ['YResolution'],

@@ -85,7 +85,9 @@ /// <reference types="node" />

Rational = 5,
SignedByte = 6,
Undefined = 7,
SignedShort = 8,
SignedLong = 9,
SignedRational = 10,
SingleFloat = 11,
DoubleFloat = 12
Float = 11,
Double = 12
}

@@ -92,0 +94,0 @@ export interface IJPEGOptions {

@@ -38,8 +38,10 @@ "use strict";

IFDDataType[IFDDataType["Rational"] = 5] = "Rational";
IFDDataType[IFDDataType["SignedByte"] = 6] = "SignedByte";
IFDDataType[IFDDataType["Undefined"] = 7] = "Undefined";
IFDDataType[IFDDataType["SignedShort"] = 8] = "SignedShort";
IFDDataType[IFDDataType["SignedLong"] = 9] = "SignedLong";
IFDDataType[IFDDataType["SignedRational"] = 10] = "SignedRational";
// From https://www.media.mit.edu/pia/Research/deepview/exif.html
IFDDataType[IFDDataType["SingleFloat"] = 11] = "SingleFloat";
IFDDataType[IFDDataType["DoubleFloat"] = 12] = "DoubleFloat";
IFDDataType[IFDDataType["Float"] = 11] = "Float";
IFDDataType[IFDDataType["Double"] = 12] = "Double";
})(IFDDataType = exports.IFDDataType || (exports.IFDDataType = {}));

@@ -51,7 +53,10 @@ function getDataTypeSize(dataType, name) {

case IFDDataType.String: // ASCII-string
case IFDDataType.SignedByte:
return 1;
case IFDDataType.Short: // word
case IFDDataType.SignedShort:
return 2;
case IFDDataType.Long: // double word
case IFDDataType.SingleFloat:
case IFDDataType.SignedLong:
case IFDDataType.Float:
case IFDDataType.Undefined:

@@ -61,3 +66,3 @@ return 4;

case IFDDataType.SignedRational:
case IFDDataType.DoubleFloat:
case IFDDataType.Double:
return 8;

@@ -64,0 +69,0 @@ default: {

@@ -26,8 +26,11 @@ import {getFriendlyName} from '../utils/tags'

switch (this.dataType) {
// TODO: verify signed versions
case IFDDataType.Byte:
case IFDDataType.Short:
case IFDDataType.Long:
case IFDDataType.SignedByte:
case IFDDataType.SignedShort:
case IFDDataType.SignedLong:
return entryReader.read(this.lengthInBytes)
case IFDDataType.Rational:
// TODO: fix signed rational repr
case IFDDataType.SignedRational:

@@ -47,5 +50,5 @@ return entryReader.read(4) / entryReader.read(4)

return chars.join('')
case IFDDataType.SingleFloat:
case IFDDataType.Float:
return new DataView(entryReader.readAsBuffer(4).buffer).getFloat32(0)
case IFDDataType.DoubleFloat:
case IFDDataType.Double:
return new DataView(entryReader.readAsBuffer(8).buffer).getFloat64(0)

@@ -52,0 +55,0 @@ case IFDDataType.Undefined:

@@ -110,3 +110,3 @@ import {IFD} from '../decoder/ifd'

private _readStripOffsetsAsJPEG(): IBufferLike | undefined {
let maxResolutionJPEG: IThumbnailLocation | undefined
let maxResolutionJPEG: {buffer: IBufferLike; metadata: IGenericMetadata} | undefined
this._ifds.forEach(ifd => {

@@ -125,6 +125,16 @@ const compressionEntry = ifd.entries.find(entry => entry.tag === IFDTag.Compression)

const length = stripBytesEntry.getValue(this._reader) as number
const jpegBuffer = this._reader.use(() => {
this._reader.seek(offset)
return this._reader.readAsBuffer(length)
})
// TODO: throw if there's more than one strip
if (!maxResolutionJPEG || length > maxResolutionJPEG.length) {
maxResolutionJPEG = {offset, length, ifd}
if (!JPEGDecoder.isJPEG(jpegBuffer)) return
const jpeg = new JPEGDecoder(jpegBuffer)
const metadata = jpeg.extractMetadata()
if (!metadata.ImageLength || !metadata.ImageWidth) return
if (!maxResolutionJPEG || metadata.ImageWidth > maxResolutionJPEG.metadata.ImageWidth!) {
// TODO: throw if there's more than one strip
maxResolutionJPEG = {metadata, buffer: jpegBuffer}
}

@@ -137,12 +147,20 @@ })

this._reader.seek(maxResolutionJPEG.offset)
return this._reader.readAsBuffer(maxResolutionJPEG.length)
return maxResolutionJPEG.buffer
}
private _readLargestJPEG(): IBufferLike {
const maxResolutionJPEG = this._readLargestJPEGThumbnail() || this._readStripOffsetsAsJPEG()
if (!maxResolutionJPEG) {
throw new Error('Could not find thumbnail or read StripOffsets IFDs')
}
return maxResolutionJPEG
// Try to read the JPEG thumbnail first
const maxThumbnailJPEG = this._readLargestJPEGThumbnail()
const thumbnailSize = (maxThumbnailJPEG && maxThumbnailJPEG.length) || 0
// Only return it immediately if it seems large enough (>500KB)
if (maxThumbnailJPEG && thumbnailSize > 500 * 1000) return maxThumbnailJPEG
// Otherwise we'll fallback to the JPEG strip offsets
const maxStripOffsetJPEG = this._readStripOffsetsAsJPEG()
// Only return it if it's larger than the thumbnail
if (maxStripOffsetJPEG && maxStripOffsetJPEG.length > thumbnailSize) return maxStripOffsetJPEG
// Fallback to the small thumbnail if that's all we found
if (maxThumbnailJPEG) return maxThumbnailJPEG
// Fail loudly if all else fails
throw new Error('Could not find thumbnail or read StripOffsets IFDs')
}

@@ -160,2 +178,6 @@

const metadata = this.extractMetadata()
delete metadata.ImageWidth
delete metadata.ImageLength
delete metadata.EXIFImageWidth
delete metadata.EXIFImageHeight
const metadataBuffer = TIFFEncoder.encode(metadata)

@@ -162,0 +184,0 @@

@@ -10,2 +10,3 @@ import {

IIFDTagDefinition,
IFDTag,
} from '../utils/types'

@@ -18,2 +19,12 @@ import {Writer} from '../utils/writer'

const BLACKLISTED_TAGS = new Set([
IFDTag.SubIFD,
IFDTag.EXIFOffset,
IFDTag.StripOffsets,
IFDTag.StripByteCounts,
IFDTag.ThumbnailOffset,
IFDTag.ThumbnailLength,
IFDTag.RowsPerStrip,
])
export class TIFFEncoder {

@@ -23,2 +34,3 @@ public static isSupportedEntry(tag: IIFDTagDefinition | undefined, value: any): boolean {

if (tag.group !== IFDGroup.EXIF) return false
if (BLACKLISTED_TAGS.has(tag.code)) return false
if (tag.dataType === IFDDataType.Short) return value < Math.pow(2, 16)

@@ -25,0 +37,0 @@ if (tag.dataType === IFDDataType.Long) return value < Math.pow(2, 32)

@@ -21,4 +21,4 @@ import {parseDate} from './date-parser'

width: ['ImageWidth'],
height: ['ImageLength'],
width: ['EXIFImageWidth', 'ImageWidth'],
height: ['EXIFImageHeight', 'ImageLength'],
xResolution: ['XResolution'],

@@ -25,0 +25,0 @@ yResolution: ['YResolution'],

@@ -98,8 +98,10 @@ export interface ILogger {

Rational = 5,
SignedByte = 6,
Undefined = 7,
SignedShort = 8,
SignedLong = 9,
SignedRational = 10,
// From https://www.media.mit.edu/pia/Research/deepview/exif.html
SingleFloat = 11,
DoubleFloat = 12,
Float = 11,
Double = 12,
}

@@ -155,7 +157,10 @@

case IFDDataType.String: // ASCII-string
case IFDDataType.SignedByte:
return 1
case IFDDataType.Short: // word
case IFDDataType.SignedShort:
return 2
case IFDDataType.Long: // double word
case IFDDataType.SingleFloat:
case IFDDataType.SignedLong:
case IFDDataType.Float:
case IFDDataType.Undefined:

@@ -165,3 +170,3 @@ return 4

case IFDDataType.SignedRational:
case IFDDataType.DoubleFloat:
case IFDDataType.Double:
return 8

@@ -168,0 +173,0 @@ default: {

{
"name": "@eris/exif",
"version": "0.3.1-alpha.2",
"version": "0.3.1-alpha.3",
"description": "Parses EXIF data.",

@@ -49,3 +49,3 @@ "main": "./dist/index.js",

},
"gitHead": "1be49b5ba3508e530c16a5b221c44d8e4886b3ae"
"gitHead": "736edbccdec6ff9888f6103916578dea219901fa"
}

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

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