probe-image-size
Advanced tools
Comparing version 5.0.0 to 6.0.0
@@ -9,2 +9,16 @@ # Changelog | ||
## [6.0.0] - 2020-11-04 | ||
### Added | ||
- Add support for `.ico` files. | ||
### Changed | ||
- node.js v10+ required. | ||
- Drop callbacks support. | ||
- Drop legacy call support (URL in `options`). | ||
- Input stream will now be closed by default. | ||
- Use `needle` instead of outdated `request` (options names are different). | ||
- Rewrite tests to async/await. | ||
- Deps bump & cleanup. | ||
## [5.0.0] - 2019-09-14 | ||
@@ -164,2 +178,3 @@ ### Changed | ||
[6.0.0]: https://github.com/nodeca/probe-image-size/compare/5.0.0...6.0.0 | ||
[5.0.0]: https://github.com/nodeca/probe-image-size/compare/4.1.1...5.0.0 | ||
@@ -166,0 +181,0 @@ [4.1.1]: https://github.com/nodeca/probe-image-size/compare/4.1.0...4.1.1 |
82
http.js
@@ -5,6 +5,7 @@ 'use strict'; | ||
var ProbeError = require('./lib/common').ProbeError; | ||
var request = require('request'); | ||
var needle = require('needle'); | ||
var merge = require('deepmerge'); | ||
var pkg = require('./package.json'); | ||
var probeStream = require('./stream'); | ||
var URL = require('url').URL; | ||
@@ -14,19 +15,11 @@ var defaultAgent = pkg.name + '/' + pkg.version + '(+https://github.com/nodeca/probe-image-size)'; | ||
var defaults = { | ||
timeout: 60000, | ||
// retries: 1, // needed for `got` only, not supported by `request` | ||
open_timeout: 10000, | ||
response_timeout: 60000, | ||
read_timeout: 60000, | ||
follow_max: 10, | ||
// Use to ignore bad certificates. | ||
//rejectUnauthorized: false, | ||
headers: { | ||
'User-Agent': defaultAgent, | ||
// Override default "gzip, deflate" header that is auto-inserted when | ||
// request has gzip option turned on. | ||
// | ||
// It's done so because gzip may have large block size, and we only need | ||
// to know a first few bytes to extract image size. | ||
// | ||
'Accept-Encoding': 'identity' | ||
}, | ||
// turn gzip decompression on in case there are misconfigured servers | ||
// that always return gzip encoded content even if not requested | ||
gzip: true | ||
'User-Agent': defaultAgent | ||
} | ||
}; | ||
@@ -37,6 +30,6 @@ | ||
return new Promise(function (resolve, reject) { | ||
var stream, length, finalUrl; | ||
var stream, len, finalUrl = src; | ||
try { | ||
stream = request(merge.all([ { url: src }, defaults, options ])); | ||
stream = needle.get(src, merge.all([ defaults, options ])); | ||
} catch (err) { | ||
@@ -47,37 +40,34 @@ reject(err); | ||
stream.on('response', function (res) { | ||
if (res.statusCode !== 200) { | ||
var err = new ProbeError('bad status code: ' + res.statusCode, null, res.statusCode); | ||
stream.on('redirect', function (location) { | ||
finalUrl = new URL(location, finalUrl).href; | ||
}); | ||
stream.abort(); | ||
reject(err); | ||
stream.on('header', function (statusCode, headers) { | ||
if (statusCode !== 200) { | ||
reject(new ProbeError('bad status code: ' + statusCode, null, statusCode)); | ||
stream.request.abort(); | ||
return; | ||
} | ||
var len = res.headers['content-length']; | ||
len = headers['content-length']; | ||
}); | ||
if (len && len.match(/^\d+$/)) length = +len; | ||
finalUrl = res.request.uri.href; | ||
stream.on('err', function (err) { | ||
reject(err); | ||
stream.request.abort(); | ||
}); | ||
probeStream(stream) | ||
.then(function (result) { | ||
if (length) result.length = length; | ||
probeStream(stream, true) | ||
.then(function (result) { | ||
if (len && len.match(/^\d+$/)) result.length = +len; | ||
result.url = finalUrl; | ||
result.url = finalUrl; | ||
resolve(result); | ||
}) | ||
.catch(reject) | ||
.then(function () { stream.abort(); }); | ||
}); | ||
stream.on('error', function (err) { | ||
/* This check needed for `got` only, because it returns 404 as error. | ||
if (err.statusCode) { | ||
reject(new ProbeError('bad status code: ' + err.statusCode, null, err.statusCode)); | ||
return; | ||
}*/ | ||
reject(err); | ||
}); | ||
resolve(result); | ||
stream.request.abort(); | ||
}) | ||
.catch(function (err) { | ||
reject(err); | ||
stream.request.abort(); | ||
}); | ||
}); | ||
@@ -84,0 +74,0 @@ }; |
35
index.js
@@ -6,43 +6,14 @@ 'use strict'; | ||
var probeHttp = require('./http'); | ||
var nextTick = require('next-tick'); | ||
var merge = require('deepmerge'); | ||
/* eslint-disable consistent-return */ | ||
module.exports = function get_image_size(src, options, callback) { | ||
module.exports = function get_image_size(src, options) { | ||
if (typeof src.on === 'function' && typeof src.emit === 'function') { | ||
// looks like an EventEmitter, treating it as a stream | ||
callback = options; | ||
if (!callback) return probeStream(src); | ||
probeStream(src) | ||
.then(function (size) { nextTick(callback.bind(null, null, size)); }) | ||
.catch(function (err) { nextTick(callback.bind(null, err)); }); | ||
return; | ||
return probeStream(src, options); | ||
} | ||
// HTTP (not stream) | ||
if (typeof src === 'string') { | ||
// `probe(string [, options, callback])` | ||
if (typeof options === 'function') { | ||
callback = options; | ||
options = {}; | ||
} | ||
options = options || {}; | ||
} else { | ||
// Legacy style, `probe(object [, callback])` | ||
callback = options; | ||
options = merge({}, src); | ||
src = options.url; | ||
delete options.url; | ||
} | ||
if (!callback) return probeHttp(src, options); | ||
probeHttp(src, options) | ||
.then(function (size) { nextTick(callback.bind(null, null, size)); }) | ||
.catch(function (err) { nextTick(callback.bind(null, err)); }); | ||
return probeHttp(src, options || {}); | ||
}; | ||
@@ -49,0 +20,0 @@ |
@@ -6,3 +6,2 @@ 'use strict'; | ||
var streamParser = require('stream-parser'); | ||
var inherits = require('util').inherits; | ||
@@ -14,3 +13,6 @@ | ||
inherits(ParserStream, Transform); | ||
// Inherit from Transform | ||
ParserStream.prototype = Object.create(Transform.prototype); | ||
ParserStream.prototype.constructor = ParserStream; | ||
streamParser(ParserStream.prototype); | ||
@@ -82,5 +84,6 @@ | ||
// Inherit from Error | ||
require('inherits')(ProbeError, Error); | ||
ProbeError.prototype = Object.create(Error.prototype); | ||
ProbeError.prototype.constructor = ProbeError; | ||
exports.ProbeError = ProbeError; |
'use strict'; | ||
module.exports = { | ||
bmp: require('./parse_stream/bmp'), | ||
gif: require('./parse_stream/gif'), | ||
ico: require('./parse_stream/ico'), | ||
jpeg: require('./parse_stream/jpeg'), | ||
@@ -8,0 +8,0 @@ png: require('./parse_stream/png'), |
@@ -8,2 +8,3 @@ 'use strict'; | ||
jpeg: require('./parse_sync/jpeg'), | ||
ico: require('./parse_sync/ico'), | ||
png: require('./parse_sync/png'), | ||
@@ -10,0 +11,0 @@ psd: require('./parse_sync/psd'), |
{ | ||
"name": "probe-image-size", | ||
"version": "5.0.0", | ||
"version": "6.0.0", | ||
"description": "Get image size without full download (JPG, GIF, PNG, WebP, BMP, TIFF, PSD)", | ||
@@ -10,2 +10,3 @@ "keywords": [ | ||
"jpeg", | ||
"ico", | ||
"gif", | ||
@@ -29,12 +30,13 @@ "png", | ||
"scripts": { | ||
"lint": "./node_modules/.bin/eslint .", | ||
"test": "npm run lint && ./node_modules/.bin/mocha", | ||
"coverage": "rm -rf coverage && ./node_modules/.bin/istanbul cover node_modules/.bin/_mocha", | ||
"report-coveralls": "./node_modules/.bin/istanbul cover ./node_modules/mocha/bin/_mocha --report lcovonly -- -R spec && cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js && rm -rf ./coverage" | ||
"lint": "eslint .", | ||
"test": "npm run lint && nyc mocha", | ||
"coverage": "npm run test && nyc report --reporter html", | ||
"report-coveralls": "nyc report --reporter=text-lcov | coveralls" | ||
}, | ||
"mocha": { | ||
"timeout": 5000 | ||
}, | ||
"dependencies": { | ||
"deepmerge": "^4.0.0", | ||
"inherits": "^2.0.3", | ||
"next-tick": "^1.0.0", | ||
"request": "^2.83.0", | ||
"needle": "^2.5.2", | ||
"stream-parser": "~0.3.1" | ||
@@ -44,7 +46,6 @@ }, | ||
"coveralls": "^3.0.0", | ||
"eslint": "^6.0.1", | ||
"from2": "^2.1", | ||
"istanbul": "^0.4.1", | ||
"mocha": "^6.1.4" | ||
"eslint": "^7.12.1", | ||
"mocha": "^8.2.0", | ||
"nyc": "^15.1.0" | ||
} | ||
} |
102
README.md
@@ -9,3 +9,3 @@ probe-image-size | ||
> Get image size without full download. Supported image types: | ||
> JPG, GIF, PNG, WebP, BMP, TIFF, SVG, PSD. | ||
> JPG, GIF, PNG, WebP, BMP, TIFF, SVG, PSD, ICO. | ||
@@ -24,3 +24,3 @@ Key features: | ||
```bash | ||
npm install probe-image-size --save | ||
npm install probe-image-size | ||
``` | ||
@@ -32,49 +32,32 @@ | ||
```js | ||
var probe = require('probe-image-size'); | ||
const probe = require('probe-image-size'); | ||
// Get by URL | ||
// | ||
probe('http://example.com/image.jpg').then(result => { | ||
console.log(result); // => | ||
/* | ||
{ | ||
width: xx, | ||
height: yy, | ||
type: 'jpg', | ||
mime: 'image/jpeg', | ||
wUnits: 'px', | ||
hUnits: 'px', | ||
url: 'http://example.com/image.jpg' | ||
} | ||
*/ | ||
}); | ||
let result = await probe('http://example.com/image.jpg'); | ||
console.log(result); // => | ||
/* | ||
{ | ||
width: xx, | ||
height: yy, | ||
type: 'jpg', | ||
mime: 'image/jpeg', | ||
wUnits: 'px', | ||
hUnits: 'px', | ||
url: 'http://example.com/image.jpg' | ||
} | ||
*/ | ||
// By URL with options | ||
// | ||
probe('http://example.com/image.jpg', { timeout: 5000 }).then(function (result) { | ||
console.log(result); | ||
}); | ||
let result = await probe('http://example.com/image.jpg', { rejectUnauthorized: false }); | ||
console.log(result); | ||
// With callback | ||
// | ||
probe('http://example.com/image.jpg', function (err, result) { | ||
console.log(result); | ||
}); | ||
// From the stream | ||
// | ||
var input = require('fs').createReadStream('image.jpg'); | ||
let result = await probe(require('fs').createReadStream('image.jpg')); | ||
console.log(result); | ||
probe(input).then(result => { | ||
console.log(result); | ||
// terminate input, depends on stream type, | ||
// this example is for fs streams only. | ||
input.destroy(); | ||
}); | ||
// From a Buffer | ||
// | ||
var data = require('fs').readFileSync('image.jpg'); | ||
// From a Buffer (sync) | ||
let data = require('fs').readFileSync('image.jpg'); | ||
console.log(probe.sync(data)); | ||
@@ -87,11 +70,16 @@ ``` | ||
### probe(src [, options, callback]) -> Promise | ||
Note: | ||
`src` can be of this types: | ||
- You can access/browserify `stream.js` / `http.js` / `sync.js` directly. | ||
- If you don't like `http.js` dependencies, you can create your own wrapper | ||
for `stream.js`. | ||
- __String__ - URL to fetch | ||
- __Stream__ - readable stream | ||
### probe(src [, options|keepOpen]) -> Promise | ||
`options` - HTTP only. See [`got` documentation](https://github.com/sindresorhus/got). | ||
Defaults changed to `{ retries: 1, timeout: 30000 }` | ||
- `src` can be of this types: | ||
- _String_ - URL to fetch | ||
- _Stream_ - readable stream | ||
- `options` - HTTP only. See [`needle` documentation](https://github.com/tomas/needle#request-options), and customized [defaults](https://github.com/nodeca/probe-image-size/blob/master/http.js#L13). | ||
- `keepOpen` (Boolean) - stream only. Keep stream open after parser finishes | ||
(input stream will be closed by default) | ||
@@ -104,8 +92,10 @@ `result` (Promise) contains: | ||
height: YY, | ||
length: ZZ, // byte length of the file (if available, HTTP only) | ||
type: ..., // image 'type' (usual file name extention) | ||
mime: ..., // mime type | ||
length: ZZ, // byte length of the file (if available, HTTP only) | ||
type: ..., // image 'type' (usual file name extention) | ||
mime: ..., // mime type | ||
wUnits: 'px', // width units type ('px' by default, can be different for SVG) | ||
hUnits: 'px', // height units type ('px' by default, can be different for SVG) | ||
url: ..., // last url for the image in chain of redirects (if no redirects, same as src) (HTTP only) | ||
url: ..., // HTTP only, last url for the image in chain of redirects | ||
// (if no redirects, same as src) | ||
variants: [ { width, height }, ... ] | undefined // full list of sizes for ICO | ||
} | ||
@@ -119,14 +109,3 @@ ``` | ||
If callback (legacy node style) provided, `Promise` will not be returned. | ||
__Note 1.__ If you use `Stream` as source, it's your responsibility to close that | ||
stream in callback. In other case you can get memory leak, because stream will | ||
be left in paused state. With http requests that's not a problem - everything | ||
is released automatically, as soon as possible. | ||
__Note 2.__ We still support legacy v2.x signature for http probe (`src` is | ||
Object as described in [request](https://github.com/request/request)). But it | ||
will be deprecated in next versions. | ||
### sync.probe(src) -> result|null | ||
@@ -147,3 +126,2 @@ | ||
- [image-size](https://github.com/netroy/image-size) | ||
- [imagesize](https://github.com/arnaud-lb/imagesize.js) | ||
@@ -150,0 +128,0 @@ |
@@ -7,20 +7,32 @@ 'use strict'; | ||
var PassThrough = require('stream').PassThrough; | ||
var pipeline = require('stream').pipeline; | ||
module.exports = function probeStream(stream) { | ||
module.exports = function probeStream(src, keepOpen) { | ||
var proxy = new PassThrough(); | ||
var cnt = 0; // count of working parsers | ||
var result = new Promise(function (resolve, reject) { | ||
stream.on('error', reject); | ||
src.on('error', reject); | ||
proxy.on('error', reject); | ||
function nope() {} | ||
var alive_parsers = []; | ||
var last_error; | ||
function parserEnd() { | ||
function parserEnd(err) { | ||
var idx = alive_parsers.indexOf[this]; | ||
/* istanbul ignore if */ | ||
if (idx < 0) return; | ||
/* istanbul ignore if */ | ||
if (err) last_error = err; | ||
proxy.unpipe(this); | ||
this.removeAllListeners(); | ||
cnt--; | ||
alive_parsers.splice(idx, 1); | ||
if (alive_parsers.length) return; | ||
// if all parsers finished without success -> fail. | ||
if (!cnt) reject(new ProbeError('unrecognized file format', 'ECONTENT')); | ||
reject(last_error || new ProbeError('unrecognized file format', 'ECONTENT')); | ||
} | ||
@@ -31,9 +43,9 @@ | ||
cnt++; | ||
alive_parsers.push(pStream); | ||
pStream.once('data', resolve); | ||
pStream.once('end', parserEnd); | ||
// silently ignore errors because user does not need to know | ||
// that something wrong is happening here | ||
pStream.on('error', nope); | ||
// User does not need to know that something wrong in parser | ||
// Process error the same was unrecognized format (end without data) | ||
pStream.on('error', parserEnd); | ||
@@ -46,4 +58,4 @@ proxy.pipe(pStream); | ||
// request stream doesn't have unpipe, https://github.com/request/request/issues/874 | ||
if (typeof stream.unpipe === 'function') stream.unpipe(proxy); | ||
proxy.end(); | ||
if (keepOpen && typeof src.unpipe === 'function') src.unpipe(proxy); | ||
proxy.destroy(); | ||
} | ||
@@ -53,3 +65,4 @@ | ||
stream.pipe(proxy); | ||
if (keepOpen) src.pipe(proxy); | ||
else pipeline(src, proxy, function () {}); | ||
@@ -56,0 +69,0 @@ return result; |
47030
3
4
29
1163
126
+ Addedneedle@^2.5.2
+ Addeddebug@3.2.7(transitive)
+ Addediconv-lite@0.4.24(transitive)
+ Addedms@2.1.3(transitive)
+ Addedneedle@2.9.1(transitive)
+ Addedsax@1.4.1(transitive)
- Removedinherits@^2.0.3
- Removednext-tick@^1.0.0
- Removedrequest@^2.83.0
- Removedajv@6.12.6(transitive)
- Removedasn1@0.2.6(transitive)
- Removedassert-plus@1.0.0(transitive)
- Removedasynckit@0.4.0(transitive)
- Removedaws-sign2@0.7.0(transitive)
- Removedaws4@1.13.2(transitive)
- Removedbcrypt-pbkdf@1.0.2(transitive)
- Removedcaseless@0.12.0(transitive)
- Removedcombined-stream@1.0.8(transitive)
- Removedcore-util-is@1.0.2(transitive)
- Removeddashdash@1.14.1(transitive)
- Removeddelayed-stream@1.0.0(transitive)
- Removedecc-jsbn@0.1.2(transitive)
- Removedextend@3.0.2(transitive)
- Removedextsprintf@1.3.0(transitive)
- Removedfast-deep-equal@3.1.3(transitive)
- Removedfast-json-stable-stringify@2.1.0(transitive)
- Removedforever-agent@0.6.1(transitive)
- Removedform-data@2.3.3(transitive)
- Removedgetpass@0.1.7(transitive)
- Removedhar-schema@2.0.0(transitive)
- Removedhar-validator@5.1.5(transitive)
- Removedhttp-signature@1.2.0(transitive)
- Removedinherits@2.0.4(transitive)
- Removedis-typedarray@1.0.0(transitive)
- Removedisstream@0.1.2(transitive)
- Removedjsbn@0.1.1(transitive)
- Removedjson-schema@0.4.0(transitive)
- Removedjson-schema-traverse@0.4.1(transitive)
- Removedjson-stringify-safe@5.0.1(transitive)
- Removedjsprim@1.4.2(transitive)
- Removedmime-db@1.52.0(transitive)
- Removedmime-types@2.1.35(transitive)
- Removednext-tick@1.1.0(transitive)
- Removedoauth-sign@0.9.0(transitive)
- Removedperformance-now@2.1.0(transitive)
- Removedpsl@1.15.0(transitive)
- Removedpunycode@2.3.1(transitive)
- Removedqs@6.5.3(transitive)
- Removedrequest@2.88.2(transitive)
- Removedsafe-buffer@5.2.1(transitive)
- Removedsshpk@1.18.0(transitive)
- Removedtough-cookie@2.5.0(transitive)
- Removedtunnel-agent@0.6.0(transitive)
- Removedtweetnacl@0.14.5(transitive)
- Removeduri-js@4.4.1(transitive)
- Removeduuid@3.4.0(transitive)
- Removedverror@1.10.0(transitive)