gif-frames
Advanced tools
Comparing version 0.1.0 to 0.2.0
var path = require('path'); | ||
var MultiRange = require('multi-integer-range').MultiRange; | ||
var getPixels = require('get-pixels'); | ||
var savePixels = require('save-pixels'); | ||
var fs = require('fs'); | ||
// https://stackoverflow.com/a/28203456 | ||
function numDigits (x) { | ||
return (Math.log10((x ^ (x >> 31)) - (x >> 31)) | 0) + 1; | ||
function nopromises () { | ||
throw new Error( | ||
'Promises not supported in your environment. ' + | ||
'Use the callback argument or a Promise polyfill.' | ||
); | ||
} | ||
// https://stackoverflow.com/a/2998822 | ||
function padNumber (num, size) { | ||
var s = num + ''; | ||
while (s.length < size) { | ||
s = '0' + s; | ||
} | ||
return s; | ||
} | ||
var brokenPromise = { | ||
then: nopromises, | ||
catch: nopromises | ||
}; | ||
@@ -23,41 +21,71 @@ function gifFrames (options, callback) { | ||
callback = callback || function () {}; | ||
var input = options.input; | ||
if (!input) { | ||
callback(new Error('"input" option is required.')); | ||
var promise; | ||
var resolve; | ||
var reject; | ||
if (typeof Promise === 'function') { | ||
promise = new Promise(function (_resolve, _reject) { | ||
resolve = function (res) { | ||
callback(null, res); | ||
_resolve(res); | ||
}; | ||
reject = function (err) { | ||
callback(err); | ||
_reject(err); | ||
}; | ||
}); | ||
} else { | ||
promise = brokenPromise; | ||
resolve = function (res) { | ||
callback(null, res); | ||
}; | ||
reject = callback; | ||
} | ||
var url = options.url; | ||
if (!url) { | ||
reject(new Error('"url" option is required.')); | ||
return; | ||
} | ||
var filename = options.filename | ||
|| (typeof input === 'string' ? path.basename(input) : ''); | ||
if (typeof input !== 'string' && !filename) { | ||
callback(new Error('"filename" option is required for non-string inputs.')); | ||
var frames = options.frames; | ||
if (!frames && frames !== 0) { | ||
reject(new Error('"frames" option is required.')); | ||
return; | ||
} | ||
var filenameType = path.extname(filename).slice(1); | ||
var outputType = options.outputType || filenameType || 'jpg'; | ||
var outputPathBase = filename | ||
&& filenameType.toLowerCase() === outputType.toLowerCase() | ||
&& filename.slice(0, -(outputType.length + 1)) | ||
|| filename; | ||
var outputType = options.outputType || 'jpg'; | ||
var quality = options.quality; | ||
getPixels(input, 'image/gif', function (err, pixels) { | ||
var acceptedFrames = new MultiRange(frames); | ||
getPixels(url, 'image/gif', function (err, pixels) { | ||
if (err) { | ||
callback(err); | ||
reject(err); | ||
return; | ||
} | ||
if (pixels.shape.length < 4) { | ||
callback(new Error('Input should be multi-frame GIF.')); | ||
reject(new Error('"url" input should be multi-frame GIF.')); | ||
return; | ||
} | ||
var frameCount = pixels.shape[0]; | ||
var frameCountDigits = numDigits(frameCount); | ||
for (var i = 0; i < frameCount; i++) { | ||
savePixels(pixels.pick(i), outputType, { | ||
quality: options.quality | ||
}).pipe(fs.createWriteStream( | ||
outputPathBase + '-' + padNumber(i, frameCountDigits) + '.' + outputType | ||
)); | ||
var frameData = []; | ||
for (var i = 0; i < pixels.shape[0]; i++) { | ||
if (!acceptedFrames.has(i)) { | ||
continue; | ||
} | ||
(function (frameIndex) { | ||
frameData.push({ | ||
getImageStream: function () { | ||
return savePixels(pixels.pick(frameIndex), outputType, { | ||
quality: quality | ||
}); | ||
}, | ||
frameIndex: frameIndex | ||
}); | ||
})(i); | ||
} | ||
resolve(frameData); | ||
}); | ||
return promise; | ||
} | ||
module.exports = gifFrames; |
{ | ||
"name": "gif-frames", | ||
"version": "0.1.0", | ||
"version": "0.2.0", | ||
"description": "Pure JavaScript tool for extracting GIF frames and saving to file", | ||
@@ -30,4 +30,5 @@ "main": "gif-frames.js", | ||
"get-pixels": "^3.3.0", | ||
"multi-integer-range": "^3.0.0", | ||
"save-pixels": "^2.3.4" | ||
} | ||
} |
@@ -13,13 +13,62 @@ # gif-frames | ||
Options: | ||
* `input` (**required**): The pathname to the file, or an [in-memory Buffer](http://nodejs.org/api/buffer.html) | ||
* ***TODO:*** `frames` (**required**): The set of frames to extract (currently extracts all) | ||
* `filename` (*optional* if `input` is a pathname, **required** if `input` is a `Buffer`): The input file's name | ||
* `outputType` (*optional*, default "jpg"): Type to use for output (see [`type`](https://github.com/scijs/save-pixels#requiresave-pixelsarray-type-options) for `save-pixels`) | ||
### Options: | ||
* `url` (**required**): The pathname to the file, or an [in-memory Buffer](http://nodejs.org/api/buffer.html) | ||
* `frames` (**required**): The set of frames to extract. Can be one of: | ||
- `'all'` (gets every frame) | ||
- Any valid [`Initializer`](https://github.com/smikitky/node-multi-integer-range#initializers) accepted by the [multi-integer-range library](https://github.com/smikitky/node-multi-integer-range) | ||
* `outputType` (*optional*, default `'jpg'`): Type to use for output (see [`type`](https://github.com/scijs/save-pixels#requiresave-pixelsarray-type-options) for `save-pixels`) | ||
* `quality` (*optional*): Jpeg quality (see [`quality`](https://github.com/scijs/save-pixels#requiresave-pixelsarray-type-options) for `save-pixels`) | ||
The optional callback is called if an error occurs, with the error object | ||
as its only argument. | ||
The callback accepts the arguments `(error, frameData)`. | ||
Returns: | ||
***TODO:*** A stream of the extracted frames | ||
### Returns: | ||
A `Promise` resolving to the `frameData` array (if promises are supported in the running environment) | ||
## `frameData` | ||
An array of objects of the form: | ||
```javascript | ||
{ | ||
getImageStream, | ||
frameIndex | ||
} | ||
``` | ||
## Examples | ||
Writing selected frames to the file system in Node: | ||
```javascript | ||
var gifFrames = require('gif-frames'); | ||
var fs = require('fs'); | ||
gifFrames( | ||
{ url: 'image.gif', frames: '0-2,7', outputType: 'png' }, | ||
function (err, frameData) { | ||
if (err) { | ||
throw err; | ||
} | ||
frameData.forEach(function (frame) { | ||
frame.getImageStream().pipe(fs.createWriteStream( | ||
'image-' + frame.frameIndex + '.png' | ||
)); | ||
}); | ||
} | ||
); | ||
``` | ||
Drawing first frame to canvas in browser (and using a `Promise`): | ||
```javascript | ||
var gifFrames = require('gif-frames'); | ||
gifFrames({ url: 'image.gif', frames: 0, outputType: 'canvas' }) | ||
.then(function (frameData) { | ||
var canvas = document.createElement('canvas'); | ||
document.body.appendChild(canvas); | ||
frameData[0].getImageStream().pipe(canvas); | ||
}).catch(console.error.bind(console)); | ||
``` |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
6176
81
74
0
3
+ Addedmulti-integer-range@^3.0.0
+ Addedmulti-integer-range@3.0.0(transitive)