exiftool-vendored
Advanced tools
Comparing version 2.0.1 to 2.1.0
@@ -9,3 +9,3 @@ "use strict"; | ||
const s = i.toString(10); | ||
return (s.length >= 2) ? s : '0' + s; | ||
return (s.length >= 2) ? s : "0" + s; | ||
}); | ||
@@ -18,3 +18,3 @@ } | ||
const s = Math.abs(i).toString(10); | ||
return '-' + ((s.length >= 2) ? s : '0' + s); | ||
return "-" + ((s.length >= 2) ? s : "0" + s); | ||
} | ||
@@ -30,9 +30,9 @@ else { | ||
if (tzoffsetMinutes === undefined) { | ||
return ''; | ||
return ""; | ||
} | ||
else if (tzoffsetMinutes === 0) { | ||
return 'Z'; | ||
return "Z"; | ||
} | ||
else { | ||
const sign = (tzoffsetMinutes >= 0) ? '+' : '-'; | ||
const sign = (tzoffsetMinutes >= 0) ? "+" : "-"; | ||
const tzoff = Math.abs(tzoffsetMinutes); | ||
@@ -62,3 +62,3 @@ const hours = Math.floor(tzoff / 60); | ||
toString() { | ||
return pad2(this.hour, this.minute, this.second).join(':'); | ||
return pad2(this.hour, this.minute, this.second).join(":"); | ||
} | ||
@@ -165,5 +165,5 @@ } | ||
} | ||
else if (tagName.includes('UTC') || tagName.includes('GPS') || input.toString().endsWith('Z')) { | ||
else if (tagName.includes("UTC") || tagName.includes("GPS") || input.toString().endsWith("Z")) { | ||
this.tzOffsetMinutes = 0; | ||
this.inputWithoutTimezone = input.endsWith('Z') ? input.slice(0, -1) : input; | ||
this.inputWithoutTimezone = input.endsWith("Z") ? input.slice(0, -1) : input; | ||
} | ||
@@ -174,3 +174,3 @@ else { | ||
const [wholeMatch, offsetSignS, hourOffsetS, minuteOffsetS] = match; | ||
const offsetSign = offsetSignS === '-' ? -1 : 1; | ||
const offsetSign = offsetSignS === "-" ? -1 : 1; | ||
const hourOffset = parseInt(hourOffsetS, 10); | ||
@@ -177,0 +177,0 @@ const minuteOffset = parseInt(minuteOffsetS, 10); |
@@ -1,2 +0,2 @@ | ||
import { Task } from './task'; | ||
import { Task } from "./task"; | ||
export interface TaskProvider { | ||
@@ -3,0 +3,0 @@ (): Task<any> | undefined; |
@@ -5,7 +5,7 @@ "use strict"; | ||
const _process = require("process"); | ||
const debug = require("debug"); | ||
const deferred_1 = require("./deferred"); | ||
const debug = require("debug"); | ||
const dbg = debug("exiftool-vendored:process"); | ||
const isWin32 = _process.platform === 'win32'; | ||
const exiftoolPath = require(`exiftool-vendored.${isWin32 ? 'exe' : 'pl'}`); | ||
const isWin32 = _process.platform === "win32"; | ||
const exiftoolPath = require(`exiftool-vendored.${isWin32 ? "exe" : "pl"}`); | ||
if (!_fs.existsSync(exiftoolPath)) { | ||
@@ -15,4 +15,4 @@ throw new Error(`Vendored ExifTool does not exist at ${exiftoolPath}`); | ||
function ellipsize(str, max) { | ||
str = '' + str; | ||
return (str.length < max) ? str : str.substring(0, max - 1) + '…'; | ||
str = "" + str; | ||
return (str.length < max) ? str : str.substring(0, max - 1) + "…"; | ||
} | ||
@@ -28,12 +28,12 @@ exports.ellipsize = ellipsize; | ||
this._closedDeferred = new deferred_1.Deferred(); | ||
this.buff = ''; | ||
this.proc = _child_process.spawn(exiftoolPath, ['-stay_open', 'True', '-@', '-']); | ||
this.buff = ""; | ||
this.proc = _child_process.spawn(exiftoolPath, ["-stay_open", "True", "-@", "-"]); | ||
this.proc.unref(); // don't let node count ExifTool as a reason to stay alive | ||
this.proc.stdout.on('data', d => this.onData(d)); | ||
this.proc.stderr.on('data', d => this.onError(d)); | ||
this.proc.on('close', () => { | ||
this.proc.stdout.on("data", d => this.onData(d)); | ||
this.proc.stderr.on("data", d => this.onError(d)); | ||
this.proc.on("close", () => { | ||
this._ended = true; | ||
this._closedDeferred.resolve(); | ||
}); | ||
_process.on('beforeExit', () => this.end()); | ||
_process.on("beforeExit", () => this.end()); | ||
this.workIfIdle(); | ||
@@ -44,3 +44,3 @@ } | ||
this._ended = true; | ||
this.proc.stdin.write('\n-stay_open\nFalse\n'); | ||
this.proc.stdin.write("\n-stay_open\nFalse\n"); | ||
this.proc.stdin.end(); | ||
@@ -74,6 +74,6 @@ } | ||
...this.currentTask.args, | ||
'-ignoreMinorErrors', | ||
'-execute', | ||
'' // Need to end -execute with a newline | ||
].join('\n'); | ||
"-ignoreMinorErrors", | ||
"-execute", | ||
"" // Need to end -execute with a newline | ||
].join("\n"); | ||
this.proc.stdin.write(cmd); | ||
@@ -100,7 +100,7 @@ } | ||
const task = this.currentTask; | ||
this.buff = ''; | ||
this.buff = ""; | ||
this.currentTask = undefined; | ||
if (task === undefined) { | ||
if (buff.length > 0) { | ||
dbg('Internal error: stdin got data, with no current task'); | ||
dbg("Internal error: stdin got data, with no current task"); | ||
dbg(`Ignoring output >>>${buff}<<<`); | ||
@@ -116,3 +116,3 @@ } | ||
} | ||
ExifToolProcess.ready = '{ready}'; | ||
ExifToolProcess.ready = "{ready}"; | ||
exports.ExifToolProcess = ExifToolProcess; |
@@ -1,28 +0,11 @@ | ||
import { Tags } from './tags'; | ||
import { Task } from './task'; | ||
export { Tags } from './tags'; | ||
export { ExifDate, ExifTime, ExifDateTime, ExifTimeZoneOffset } from './datetime'; | ||
export interface ExifToolAPI { | ||
/** | ||
* @return a promise holding the version number of the vendored ExifTool | ||
*/ | ||
version(): Promise<string>; | ||
/** | ||
* @return a Promise holding the metadata tags found in `file`. | ||
*/ | ||
read(file: string): Promise<Tags>; | ||
/** | ||
* Request graceful shut down of any running ExifTool child processes. | ||
* | ||
* This may need to be called in `after` or `finally` clauses in tests | ||
* or scripts for them to exit cleanly. | ||
*/ | ||
end(): void; | ||
} | ||
import { Tags } from "./tags"; | ||
import { Task } from "./task"; | ||
export { Tags } from "./tags"; | ||
export { ExifDate, ExifTime, ExifDateTime, ExifTimeZoneOffset } from "./datetime"; | ||
/** | ||
* Manages delegating calls to a vendored running instance of ExifTool. | ||
* | ||
* Instantiation is expensive: use the exported singleton instance of this class, `exiftool`. | ||
* Instances should be shared: consider using the exported singleton instance of this class, `exiftool`. | ||
*/ | ||
export declare class ExifTool implements ExifToolAPI { | ||
export declare class ExifTool { | ||
readonly maxProcs: number; | ||
@@ -36,3 +19,3 @@ private _procs; | ||
/** | ||
* @return a Promise to the vendored ExifTool's version | ||
* @return a promise holding the version number of the vendored ExifTool | ||
*/ | ||
@@ -45,2 +28,18 @@ version(): Promise<string>; | ||
/** | ||
* Extract the low-resolution thumbnail in `path/to/image.jpg` | ||
* and write it to `path/to/thumbnail.jpg`. | ||
* | ||
* Note that these images are less than .1 megapixels in size. | ||
* @return a `Promise<void>`. An `Error` is raised if | ||
* the file could not be read or the output not written. | ||
*/ | ||
extractThumbnail(imageFile: string, thumbnailFile: string): Promise<void>; | ||
/** | ||
* Extract the "preview" image in `path/to/image.jpg` | ||
* and write it to `path/to/thumbnail.jpg`. | ||
* @return a `Promise<void>`. An `Error` is raised if | ||
* the file could not be read or the output not written. | ||
*/ | ||
extractPreview(imageFile: string, previewFile: string): Promise<void>; | ||
/** | ||
* Request graceful shut down of any running ExifTool child processes. | ||
@@ -52,2 +51,6 @@ * | ||
end(): Promise<any>; | ||
/** | ||
* `enqueueTask` is not for normal consumption. External code | ||
* can extend `Task` to add functionality. | ||
*/ | ||
enqueueTask<T>(task: Task<T>): Task<T>; | ||
@@ -61,3 +64,5 @@ private dequeueTask(); | ||
* in order to leverage a single running ExifTool process. | ||
* | ||
* Note that this instance will only use 1 CPU. | ||
*/ | ||
export declare const exiftool: ExifToolAPI; | ||
export declare const exiftool: ExifTool; |
"use strict"; | ||
const exiftool_process_1 = require("./exiftool_process"); | ||
const image_extraction_task_1 = require("./image_extraction_task"); | ||
const tags_task_1 = require("./tags_task"); | ||
const version_task_1 = require("./version_task"); | ||
const exiftool_process_1 = require("./exiftool_process"); | ||
const _process = require("process"); | ||
var datetime_1 = require("./datetime"); | ||
@@ -10,7 +12,6 @@ exports.ExifDate = datetime_1.ExifDate; | ||
exports.ExifTimeZoneOffset = datetime_1.ExifTimeZoneOffset; | ||
const _process = require("process"); | ||
/** | ||
* Manages delegating calls to a vendored running instance of ExifTool. | ||
* | ||
* Instantiation is expensive: use the exported singleton instance of this class, `exiftool`. | ||
* Instances should be shared: consider using the exported singleton instance of this class, `exiftool`. | ||
*/ | ||
@@ -25,6 +26,6 @@ class ExifTool { | ||
this._tasks = []; | ||
_process.on('exit', () => this.end()); | ||
_process.on("exit", () => this.end()); | ||
} | ||
/** | ||
* @return a Promise to the vendored ExifTool's version | ||
* @return a promise holding the version number of the vendored ExifTool | ||
*/ | ||
@@ -41,2 +42,22 @@ version() { | ||
/** | ||
* Extract the low-resolution thumbnail in `path/to/image.jpg` | ||
* and write it to `path/to/thumbnail.jpg`. | ||
* | ||
* Note that these images are less than .1 megapixels in size. | ||
* @return a `Promise<void>`. An `Error` is raised if | ||
* the file could not be read or the output not written. | ||
*/ | ||
extractThumbnail(imageFile, thumbnailFile) { | ||
return this.enqueueTask(image_extraction_task_1.ImageExtractionTask.for("ThumbnailImage", imageFile, thumbnailFile)).promise; | ||
} | ||
/** | ||
* Extract the "preview" image in `path/to/image.jpg` | ||
* and write it to `path/to/thumbnail.jpg`. | ||
* @return a `Promise<void>`. An `Error` is raised if | ||
* the file could not be read or the output not written. | ||
*/ | ||
extractPreview(imageFile, previewFile) { | ||
return this.enqueueTask(image_extraction_task_1.ImageExtractionTask.for("PreviewImage", imageFile, previewFile)).promise; | ||
} | ||
/** | ||
* Request graceful shut down of any running ExifTool child processes. | ||
@@ -51,2 +72,6 @@ * | ||
} | ||
/** | ||
* `enqueueTask` is not for normal consumption. External code | ||
* can extend `Task` to add functionality. | ||
*/ | ||
enqueueTask(task) { | ||
@@ -77,3 +102,5 @@ this._tasks.push(task); | ||
* in order to leverage a single running ExifTool process. | ||
* | ||
* Note that this instance will only use 1 CPU. | ||
*/ | ||
exports.exiftool = new ExifTool(); |
@@ -1,3 +0,3 @@ | ||
import { Tags } from './tags'; | ||
import { Task } from './task'; | ||
import { Tags } from "./tags"; | ||
import { Task } from "./task"; | ||
export declare class TagsTask extends Task<Tags> { | ||
@@ -4,0 +4,0 @@ readonly SourceFile: string; |
"use strict"; | ||
const _dt = require("./datetime"); | ||
const _path = require("path"); | ||
const task_1 = require("./task"); | ||
const _path = require("path"); | ||
class TagsTask extends task_1.Task { | ||
@@ -15,5 +15,5 @@ constructor(SourceFile, args) { | ||
const args = [ | ||
'-json', | ||
'-coordFormat', '%.8f', | ||
'-fast', | ||
"-json", | ||
"-coordFormat", "%.8f", | ||
"-fast", | ||
...optionalArgs, | ||
@@ -40,3 +40,3 @@ sourceFile | ||
// TimeZone just wins if we're just handed it, then use it: | ||
const tze = new _dt.ExifTimeZoneOffset('TimeZone', this.rawTags.TimeZone); | ||
const tze = new _dt.ExifTimeZoneOffset("TimeZone", this.rawTags.TimeZone); | ||
if (tze.tzOffsetMinutes !== undefined) { | ||
@@ -46,4 +46,4 @@ this.tzoffset = tze.tzOffsetMinutes; | ||
else { | ||
const gps = _dt.parse('GPSDateTime', this.rawTags.GPSDateTime, 0); | ||
const local = _dt.parse('DateTimeOriginal', this.rawTags.DateTimeOriginal, 0); | ||
const gps = _dt.parse("GPSDateTime", this.rawTags.GPSDateTime, 0); | ||
const local = _dt.parse("DateTimeOriginal", this.rawTags.DateTimeOriginal, 0); | ||
if (gps && local) { | ||
@@ -66,18 +66,18 @@ // timezone offsets are never less than 30 minutes. | ||
try { | ||
if (tagName.endsWith('DateStampMode') || tagName.endsWith('Sharpness') | ||
|| tagName.endsWith('Firmware') || tagName.endsWith('DateDisplayFormat')) { | ||
if (tagName.endsWith("DateStampMode") || tagName.endsWith("Sharpness") | ||
|| tagName.endsWith("Firmware") || tagName.endsWith("DateDisplayFormat")) { | ||
return value.toString(); // force to string | ||
} | ||
else if (tagName.endsWith('BitsPerSample')) { | ||
return value.toString().split(' ').map((i) => parseInt(i, 10)); | ||
else if (tagName.endsWith("BitsPerSample")) { | ||
return value.toString().split(" ").map((i) => parseInt(i, 10)); | ||
} | ||
else if (tagName.endsWith('FlashFired')) { | ||
else if (tagName.endsWith("FlashFired")) { | ||
const s = value.toString().toLowerCase(); | ||
return (s === 'yes' || s === '1' || s === 'true'); | ||
return (s === "yes" || s === "1" || s === "true"); | ||
} | ||
else if (typeof value === 'string' && tagName.includes('Date') || tagName.includes('Time')) { | ||
else if (typeof value === "string" && tagName.includes("Date") || tagName.includes("Time")) { | ||
return _dt.parse(tagName, value, this.tzoffset); | ||
} | ||
else if (tagName.endsWith('GPSLatitude') || tagName.endsWith('GPSLongitude')) { | ||
const ref = (this.rawTags[tagName + 'Ref'] || value.toString().split(' ')[1]); | ||
else if (tagName.endsWith("GPSLatitude") || tagName.endsWith("GPSLongitude")) { | ||
const ref = (this.rawTags[tagName + "Ref"] || value.toString().split(" ")[1]); | ||
if (ref === undefined) { | ||
@@ -88,3 +88,3 @@ return value; // give up | ||
const direction = ref.trim().toLowerCase(); | ||
const sorw = direction.startsWith('w') || direction.startsWith('s'); | ||
const sorw = direction.startsWith("w") || direction.startsWith("s"); | ||
return parseFloat(value) * (sorw ? -1 : 1); | ||
@@ -91,0 +91,0 @@ } |
@@ -1,2 +0,2 @@ | ||
import { Deferred } from './deferred'; | ||
import { Deferred } from "./deferred"; | ||
/** | ||
@@ -3,0 +3,0 @@ * Emodies both a command (`args`), and a handler for the resulting output |
@@ -1,2 +0,2 @@ | ||
import { Task } from './task'; | ||
import { Task } from "./task"; | ||
export declare class VersionTask extends Task<string> { | ||
@@ -3,0 +3,0 @@ private static readonly versionRegex; |
@@ -5,3 +5,3 @@ "use strict"; | ||
constructor() { | ||
super(['-ver']); | ||
super(["-ver"]); | ||
} | ||
@@ -8,0 +8,0 @@ parse(input) { |
{ | ||
"name": "exiftool-vendored", | ||
"version": "2.0.1", | ||
"version": "2.1.0", | ||
"description": "Efficient, cross-platform access to ExifTool", | ||
@@ -9,3 +9,3 @@ "main": "./dist/exiftool.js", | ||
"clean": "rimraf lib dist", | ||
"lint": "tslint src/**/*.ts", | ||
"lint": "tslint --fix src/**/*.ts", | ||
"fmt": "bash -c 'tsfmt -r src/**/*.ts'", | ||
@@ -90,5 +90,7 @@ "compile": "tsc", | ||
"@types/jsdom": "^2.0.29", | ||
"@types/mocha": "^2.2.34", | ||
"@types/node": "^6.0.53", | ||
"@types/mocha": "^2.2.37", | ||
"@types/node": "^7.0.0", | ||
"@types/pify": "0.0.28", | ||
"@types/rimraf": "^0.0.28", | ||
"@types/tmp": "0.0.32", | ||
"@types/xmldom": "^0.1.28", | ||
@@ -101,9 +103,11 @@ "chai": "^3.5.0", | ||
"np": "^2.12.0", | ||
"npm-run-all": "^3.1.2", | ||
"npm-run-all": "^4.0.0", | ||
"pify": "^2.3.0", | ||
"rimraf": "^2.5.4", | ||
"tar-fs": "^1.15.0", | ||
"tslint": "^4.2.0", | ||
"tmp": "0.0.31", | ||
"tslint": "^4.3.1", | ||
"tslint-config-standard": "^2.0.0", | ||
"tslint-eslint-rules": "^3.2.3", | ||
"typescript": "^2.1.4", | ||
"typescript": "^2.1.5", | ||
"typescript-formatter": "^4.0.1", | ||
@@ -110,0 +114,0 @@ "xmldom": "^0.1.27", |
@@ -39,5 +39,19 @@ # exiftool-vendored | ||
import { exiftool, Tags } from "exiftool-vendored" | ||
exiftool.read("path/to/file.jpg").then((tags /*: Tags */) => { | ||
console.log(`Make: ${metadata.Make}, Model: ${metadata.Model}`) | ||
}) | ||
// Read all metadata tags in `path/to/image.jpg`. | ||
// Returns a `Promise<Tags>`. | ||
exiftool | ||
.read("path/to/image.jpg") | ||
.then((tags /*: Tags */) => { | ||
console.log(`Make: ${tags.Make}, Model: ${tags.Model}`) | ||
}) | ||
// Extract the low-resolution thumbnail in `path/to/image.jpg` | ||
// and write it to `path/to/thumbnail.jpg`. | ||
// Returns a `Promise<void>` | ||
// which contains an error or success status. | ||
exiftool.extractThumbnail("path/to/image.jpg", "path/to/thumbnail.jpg") | ||
// Extract the "Preview" image (found in RAW images): | ||
exiftool.extractPreview("path/to/image.jpg", "path/to/preview.jpg") | ||
``` | ||
@@ -132,2 +146,6 @@ | ||
### v2.1.0 | ||
* ✨ `extractThumbnail` and `extractPreview` implemented to pull out EXIF-embedded images | ||
### v2.0.1 | ||
@@ -134,0 +152,0 @@ |
Sorry, the diff of this file is too big to display
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
123323
3343
211
28