mirror of
https://github.com/lovell/sharp.git
synced 2025-07-09 10:30:15 +02:00
Expose runtime format availability
Aids addition of new format/method combos Dogfood this in the test code
This commit is contained in:
parent
1565522ecc
commit
c7ccf6801d
36
README.md
36
README.md
@ -218,8 +218,42 @@ sharp(inputBuffer)
|
|||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// Runtime discovery of available formats
|
||||||
|
console.dir(sharp.format);
|
||||||
|
```
|
||||||
|
|
||||||
## API
|
## API
|
||||||
|
|
||||||
|
### Attributes
|
||||||
|
|
||||||
|
#### format
|
||||||
|
|
||||||
|
An Object containing nested boolean values
|
||||||
|
representing the available input and output formats/methods,
|
||||||
|
for example:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{ jpeg: { id: 'jpeg',
|
||||||
|
input: { file: true, buffer: true, stream: true },
|
||||||
|
output: { file: true, buffer: true, stream: true } },
|
||||||
|
png: { id: 'png',
|
||||||
|
input: { file: true, buffer: true, stream: true },
|
||||||
|
output: { file: true, buffer: true, stream: true } },
|
||||||
|
webp: { id: 'webp',
|
||||||
|
input: { file: true, buffer: true, stream: true },
|
||||||
|
output: { file: true, buffer: true, stream: true } },
|
||||||
|
tiff: { id: 'tiff',
|
||||||
|
input: { file: true, buffer: true, stream: true },
|
||||||
|
output: { file: true, buffer: false, stream: false } },
|
||||||
|
magick: { id: 'magick',
|
||||||
|
input: { file: true, buffer: true, stream: true },
|
||||||
|
output: { file: false, buffer: false, stream: false } },
|
||||||
|
raw: { id: 'raw',
|
||||||
|
input: { file: false, buffer: false, stream: false },
|
||||||
|
output: { file: false, buffer: true, stream: true } } }
|
||||||
|
```
|
||||||
|
|
||||||
### Input methods
|
### Input methods
|
||||||
|
|
||||||
#### sharp([input])
|
#### sharp([input])
|
||||||
@ -235,7 +269,7 @@ JPEG, PNG, WebP, GIF* or TIFF format image data can be streamed into the object
|
|||||||
|
|
||||||
JPEG, PNG or WebP format image data can be streamed out from this object.
|
JPEG, PNG or WebP format image data can be streamed out from this object.
|
||||||
|
|
||||||
\* GIF support requires libvips 8.0.0+.
|
\* libvips 8.0.0+ is required for Buffer/Stream input of GIF and other `magick` formats.
|
||||||
|
|
||||||
#### metadata([callback])
|
#### metadata([callback])
|
||||||
|
|
||||||
|
22
index.js
22
index.js
@ -100,6 +100,11 @@ var Sharp = function(input) {
|
|||||||
module.exports = Sharp;
|
module.exports = Sharp;
|
||||||
util.inherits(Sharp, stream.Duplex);
|
util.inherits(Sharp, stream.Duplex);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Supported image formats
|
||||||
|
*/
|
||||||
|
module.exports.format = sharp.format();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Handle incoming chunk on Writable Stream
|
Handle incoming chunk on Writable Stream
|
||||||
*/
|
*/
|
||||||
@ -481,7 +486,8 @@ Sharp.prototype.webp = function() {
|
|||||||
Force raw, uint8 output
|
Force raw, uint8 output
|
||||||
*/
|
*/
|
||||||
Sharp.prototype.raw = function() {
|
Sharp.prototype.raw = function() {
|
||||||
if (semver.gte(libvipsVersion, '7.42.0')) {
|
var supportsRawOutput = module.exports.format.raw.output;
|
||||||
|
if (supportsRawOutput.file || supportsRawOutput.buffer || supportsRawOutput.stream) {
|
||||||
this.options.output = '__raw';
|
this.options.output = '__raw';
|
||||||
} else {
|
} else {
|
||||||
console.error('Raw output requires libvips 7.42.0+');
|
console.error('Raw output requires libvips 7.42.0+');
|
||||||
@ -491,15 +497,15 @@ Sharp.prototype.raw = function() {
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
Force output to a given format
|
Force output to a given format
|
||||||
|
@param format is either the id as a String or an Object with an 'id' attribute
|
||||||
*/
|
*/
|
||||||
module.exports.format = {'jpeg': 'jpeg', 'png': 'png', 'webp': 'webp', 'raw': 'raw'};
|
|
||||||
Sharp.prototype.toFormat = function(format) {
|
Sharp.prototype.toFormat = function(format) {
|
||||||
if (
|
var id = format;
|
||||||
typeof format === 'string' &&
|
if (typeof format === 'object') {
|
||||||
typeof module.exports.format[format] === 'string' &&
|
id = format.id;
|
||||||
typeof this[format] === 'function'
|
}
|
||||||
) {
|
if (typeof id === 'string' && typeof module.exports.format[id] === 'object' && typeof this[id] === 'function') {
|
||||||
this[format]();
|
this[id]();
|
||||||
} else {
|
} else {
|
||||||
throw new Error('Unsupported format ' + format);
|
throw new Error('Unsupported format ' + format);
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,7 @@ extern "C" void init(v8::Handle<v8::Object> target) {
|
|||||||
NODE_SET_METHOD(target, "concurrency", concurrency);
|
NODE_SET_METHOD(target, "concurrency", concurrency);
|
||||||
NODE_SET_METHOD(target, "counters", counters);
|
NODE_SET_METHOD(target, "counters", counters);
|
||||||
NODE_SET_METHOD(target, "libvipsVersion", libvipsVersion);
|
NODE_SET_METHOD(target, "libvipsVersion", libvipsVersion);
|
||||||
|
NODE_SET_METHOD(target, "format", format);
|
||||||
}
|
}
|
||||||
|
|
||||||
NODE_MODULE(sharp, init)
|
NODE_MODULE(sharp, init)
|
||||||
|
@ -10,6 +10,7 @@ using v8::Local;
|
|||||||
using v8::Object;
|
using v8::Object;
|
||||||
using v8::Number;
|
using v8::Number;
|
||||||
using v8::String;
|
using v8::String;
|
||||||
|
using v8::Boolean;
|
||||||
|
|
||||||
using sharp::counterQueue;
|
using sharp::counterQueue;
|
||||||
using sharp::counterProcess;
|
using sharp::counterProcess;
|
||||||
@ -78,3 +79,66 @@ NAN_METHOD(libvipsVersion) {
|
|||||||
snprintf(version, sizeof(version), "%d.%d.%d", vips_version(0), vips_version(1), vips_version(2));
|
snprintf(version, sizeof(version), "%d.%d.%d", vips_version(0), vips_version(1), vips_version(2));
|
||||||
NanReturnValue(NanNew<String>(version));
|
NanReturnValue(NanNew<String>(version));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Get available input/output file/buffer/stream formats
|
||||||
|
*/
|
||||||
|
NAN_METHOD(format) {
|
||||||
|
NanScope();
|
||||||
|
|
||||||
|
// Attribute names
|
||||||
|
Local<String> attrId = NanNew<String>("id");
|
||||||
|
Local<String> attrInput = NanNew<String>("input");
|
||||||
|
Local<String> attrOutput = NanNew<String>("output");
|
||||||
|
Local<String> attrFile = NanNew<String>("file");
|
||||||
|
Local<String> attrBuffer = NanNew<String>("buffer");
|
||||||
|
Local<String> attrStream = NanNew<String>("stream");
|
||||||
|
|
||||||
|
// Which load/save operations are available for each compressed format?
|
||||||
|
Local<Object> format = NanNew<Object>();
|
||||||
|
for (std::string f : {"jpeg", "png", "webp", "tiff", "magick", "openslide", "dz"}) {
|
||||||
|
// Input
|
||||||
|
Local<Object> input = NanNew<Object>();
|
||||||
|
input->Set(attrFile, NanNew<Boolean>(
|
||||||
|
vips_type_find("VipsOperation", (f + "load").c_str())));
|
||||||
|
input->Set(attrBuffer, NanNew<Boolean>(
|
||||||
|
vips_type_find("VipsOperation", (f + "load_buffer").c_str())));
|
||||||
|
input->Set(attrStream, input->Get(attrBuffer));
|
||||||
|
// Output
|
||||||
|
Local<Object> output = NanNew<Object>();
|
||||||
|
output->Set(attrFile, NanNew<Boolean>(
|
||||||
|
vips_type_find("VipsOperation", (f + "save").c_str())));
|
||||||
|
output->Set(attrBuffer, NanNew<Boolean>(
|
||||||
|
vips_type_find("VipsOperation", (f + "save_buffer").c_str())));
|
||||||
|
output->Set(attrStream, output->Get(attrBuffer));
|
||||||
|
// Other attributes
|
||||||
|
Local<Object> container = NanNew<Object>();
|
||||||
|
Local<String> formatId = NanNew<String>(f);
|
||||||
|
container->Set(attrId, formatId);
|
||||||
|
container->Set(attrInput, input);
|
||||||
|
container->Set(attrOutput, output);
|
||||||
|
// Add to set of formats
|
||||||
|
format->Set(formatId, container);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Raw, uncompressed data
|
||||||
|
Local<Object> raw = NanNew<Object>();
|
||||||
|
raw->Set(attrId, NanNew<String>("raw"));
|
||||||
|
format->Set(NanNew<String>("raw"), raw);
|
||||||
|
// No support for raw input yet, so always false
|
||||||
|
Local<Boolean> unsupported = NanNew<Boolean>(false);
|
||||||
|
Local<Object> rawInput = NanNew<Object>();
|
||||||
|
rawInput->Set(attrFile, unsupported);
|
||||||
|
rawInput->Set(attrBuffer, unsupported);
|
||||||
|
rawInput->Set(attrStream, unsupported);
|
||||||
|
raw->Set(attrInput, rawInput);
|
||||||
|
// Raw output via Buffer/Stream is available in libvips >= 7.42.0
|
||||||
|
Local<Boolean> supportsRawOutput = NanNew<Boolean>(vips_version(0) >= 8 || (vips_version(0) == 7 && vips_version(1) >= 42));
|
||||||
|
Local<Object> rawOutput = NanNew<Object>();
|
||||||
|
rawOutput->Set(attrFile, unsupported);
|
||||||
|
rawOutput->Set(attrBuffer, supportsRawOutput);
|
||||||
|
rawOutput->Set(attrStream, supportsRawOutput);
|
||||||
|
raw->Set(attrOutput, rawOutput);
|
||||||
|
|
||||||
|
NanReturnValue(format);
|
||||||
|
}
|
||||||
|
@ -7,5 +7,6 @@ NAN_METHOD(cache);
|
|||||||
NAN_METHOD(concurrency);
|
NAN_METHOD(concurrency);
|
||||||
NAN_METHOD(counters);
|
NAN_METHOD(counters);
|
||||||
NAN_METHOD(libvipsVersion);
|
NAN_METHOD(libvipsVersion);
|
||||||
|
NAN_METHOD(format);
|
||||||
|
|
||||||
#endif // SRC_UTILITIES_H_
|
#endif // SRC_UTILITIES_H_
|
||||||
|
@ -488,6 +488,7 @@ describe('Input/output', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (sharp.format.magick.input.file) {
|
||||||
it('Convert SVG, if supported, to PNG', function(done) {
|
it('Convert SVG, if supported, to PNG', function(done) {
|
||||||
sharp(fixtures.inputSvg)
|
sharp(fixtures.inputSvg)
|
||||||
.resize(100, 100)
|
.resize(100, 100)
|
||||||
@ -504,7 +505,9 @@ describe('Input/output', function() {
|
|||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sharp.format.magick.input.file) {
|
||||||
it('Convert PSD to PNG', function(done) {
|
it('Convert PSD to PNG', function(done) {
|
||||||
sharp(fixtures.inputPsd)
|
sharp(fixtures.inputPsd)
|
||||||
.resize(320, 240)
|
.resize(320, 240)
|
||||||
@ -518,9 +521,10 @@ describe('Input/output', function() {
|
|||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (semver.gte(sharp.libvipsVersion(), '7.40.0')) {
|
if (sharp.format.tiff.input.buffer) {
|
||||||
it('Load TIFF from Buffer [libvips ' + sharp.libvipsVersion() + '>=7.40.0]', function(done) {
|
it('Load TIFF from Buffer', function(done) {
|
||||||
var inputTiffBuffer = fs.readFileSync(fixtures.inputTiff);
|
var inputTiffBuffer = fs.readFileSync(fixtures.inputTiff);
|
||||||
sharp(inputTiffBuffer)
|
sharp(inputTiffBuffer)
|
||||||
.resize(320, 240)
|
.resize(320, 240)
|
||||||
@ -537,8 +541,8 @@ describe('Input/output', function() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (semver.gte(sharp.libvipsVersion(), '8.0.0')) {
|
if (sharp.format.magick.input.buffer) {
|
||||||
it('Load GIF from Buffer [libvips ' + sharp.libvipsVersion() + '>=8.0.0]', function(done) {
|
it('Load GIF from Buffer', function(done) {
|
||||||
var inputGifBuffer = fs.readFileSync(fixtures.inputGif);
|
var inputGifBuffer = fs.readFileSync(fixtures.inputGif);
|
||||||
sharp(inputGifBuffer)
|
sharp(inputGifBuffer)
|
||||||
.resize(320, 240)
|
.resize(320, 240)
|
||||||
@ -555,8 +559,8 @@ describe('Input/output', function() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (semver.gte(sharp.libvipsVersion(), '7.42.0')) {
|
if (sharp.format.raw.output.buffer) {
|
||||||
describe('Ouput raw, uncompressed image data [libvips ' + sharp.libvipsVersion() + '>=7.42.0]', function() {
|
describe('Ouput raw, uncompressed image data', function() {
|
||||||
it('1 channel greyscale image', function(done) {
|
it('1 channel greyscale image', function(done) {
|
||||||
sharp(fixtures.inputJpg)
|
sharp(fixtures.inputJpg)
|
||||||
.greyscale()
|
.greyscale()
|
||||||
|
@ -50,4 +50,25 @@ describe('Utilities', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('Format', function() {
|
||||||
|
it('Contains expected attributes', function() {
|
||||||
|
assert.strictEqual('object', typeof sharp.format);
|
||||||
|
Object.keys(sharp.format).forEach(function(format) {
|
||||||
|
assert.strictEqual(true, 'id' in sharp.format[format]);
|
||||||
|
assert.strictEqual(format, sharp.format[format].id);
|
||||||
|
['input', 'output'].forEach(function(direction) {
|
||||||
|
assert.strictEqual(true, direction in sharp.format[format]);
|
||||||
|
assert.strictEqual('object', typeof sharp.format[format][direction]);
|
||||||
|
assert.strictEqual(3, Object.keys(sharp.format[format][direction]).length);
|
||||||
|
assert.strictEqual(true, 'file' in sharp.format[format][direction]);
|
||||||
|
assert.strictEqual(true, 'buffer' in sharp.format[format][direction]);
|
||||||
|
assert.strictEqual(true, 'stream' in sharp.format[format][direction]);
|
||||||
|
assert.strictEqual('boolean', typeof sharp.format[format][direction].file);
|
||||||
|
assert.strictEqual('boolean', typeof sharp.format[format][direction].buffer);
|
||||||
|
assert.strictEqual('boolean', typeof sharp.format[format][direction].stream);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user