Add raw, uncompressed image data output #136

This commit is contained in:
Lovell Fuller 2014-12-16 15:46:47 +00:00
parent 464fb1726d
commit a190ae6b08
4 changed files with 100 additions and 5 deletions

View File

@ -392,6 +392,18 @@ Use PNG format for the output image.
Use WebP format for the output image.
#### raw()
_Requires libvips 7.42.0+_
Provide raw, uncompressed uint8 (unsigned char) image data for Buffer and Stream based output.
The number of channels depends on the input image and selected options.
* 1 channel for images converted to `greyscale()`, with each byte representing one pixel.
* 3 channels for colour images without alpha transparency, with bytes ordered \[red, green, blue, red, green, blue, etc.\]).
* 4 channels for colour images with alpha transparency, with bytes ordered \[red, green, blue, alpha, red, green, blue, alpha, etc.\].
#### quality(quality)
The output quality to use for lossy JPEG, WebP and TIFF output formats. The default quality is `80`.

View File

@ -341,10 +341,10 @@ Sharp.prototype.compressionLevel = function(compressionLevel) {
};
/*
Disable the use of adaptive row filtering for PNG output - requires libvips 7.41.0+
Disable the use of adaptive row filtering for PNG output - requires libvips 7.42.0+
*/
Sharp.prototype.withoutAdaptiveFiltering = function(withoutAdaptiveFiltering) {
if (semver.gte(libvipsVersion, '7.41.0')) {
if (semver.gte(libvipsVersion, '7.42.0')) {
this.options.withoutAdaptiveFiltering = (typeof withoutAdaptiveFiltering === 'boolean') ? withoutAdaptiveFiltering : true;
} else {
console.error('withoutAdaptiveFiltering requires libvips 7.41.0+');
@ -425,6 +425,15 @@ Sharp.prototype.webp = function() {
return this;
};
Sharp.prototype.raw = function() {
if (semver.gte(libvipsVersion, '7.42.0')) {
this.options.output = '__raw';
} else {
console.error('Raw output requires libvips 7.42.0+');
}
return this;
};
/*
Used by a Writable Stream to notify that it is ready for data
*/

View File

@ -635,6 +635,35 @@ class ResizeWorker : public NanAsyncWorker {
return Error(baton, hook);
}
baton->outputFormat = "webp";
#if (VIPS_MAJOR_VERSION >= 7 && VIPS_MINOR_VERSION >= 42)
} else if (baton->output == "__raw") {
// Write raw, uncompressed image data to buffer
if (baton->greyscale) {
// Extract first band for greyscale image
VipsImage *grey;
if (vips_extract_band(image, &grey, 1, NULL)) {
return Error(baton, hook);
}
vips_object_local(hook, grey);
image = grey;
}
if (image->BandFmt != VIPS_FORMAT_UCHAR) {
// Cast pixels to uint8 (unsigned char)
VipsImage *uchar;
if (vips_cast(image, &uchar, VIPS_FORMAT_UCHAR, NULL)) {
return Error(baton, hook);
}
vips_object_local(hook, uchar);
image = uchar;
}
// Get raw image data
baton->bufferOut = vips_image_write_to_memory(image, &baton->bufferOutLength);
if (baton->bufferOut == NULL) {
(baton->err).append("Could not allocate enough memory for raw output");
return Error(baton, hook);
}
baton->outputFormat = "raw";
#endif
} else {
bool outputJpeg = IsJpeg(baton->output);
bool outputPng = IsPng(baton->output);
@ -649,7 +678,7 @@ class ResizeWorker : public NanAsyncWorker {
}
baton->outputFormat = "jpeg";
} else if (outputPng || (matchInput && inputImageType == ImageType::PNG)) {
#if (VIPS_MAJOR_VERSION >= 7 && VIPS_MINOR_VERSION >= 41)
#if (VIPS_MAJOR_VERSION >= 7 && VIPS_MINOR_VERSION >= 42)
// Select PNG row filter
int filter = baton->withoutAdaptiveFiltering ? VIPS_FOREIGN_PNG_FILTER_NONE : VIPS_FOREIGN_PNG_FILTER_ALL;
// Write PNG to file

View File

@ -384,8 +384,8 @@ describe('Input/output', function() {
done();
});
if (semver.gte(sharp.libvipsVersion(), '7.41.0')) {
it('withoutAdaptiveFiltering generates smaller file [libvips ' + sharp.libvipsVersion() + '>=7.41.0]', function(done) {
if (semver.gte(sharp.libvipsVersion(), '7.42.0')) {
it('withoutAdaptiveFiltering generates smaller file [libvips ' + sharp.libvipsVersion() + '>=7.42.0]', function(done) {
// First generate with adaptive filtering
sharp(fixtures.inputPng)
.resize(320, 240)
@ -463,4 +463,49 @@ describe('Input/output', function() {
});
}
if (semver.gte(sharp.libvipsVersion(), '7.42.0')) {
describe('Ouput raw, uncompressed image data [libvips ' + sharp.libvipsVersion() + '>=7.42.0]', function() {
it('1 channel greyscale image', function(done) {
sharp(fixtures.inputJpg)
.greyscale()
.resize(32, 24)
.raw()
.toBuffer(function(err, data, info) {
assert.strictEqual(32 * 24 * 1, info.size);
assert.strictEqual(data.length, info.size);
assert.strictEqual('raw', info.format);
assert.strictEqual(32, info.width);
assert.strictEqual(24, info.height);
done();
});
});
it('3 channel colour image without transparency', function(done) {
sharp(fixtures.inputJpg)
.resize(32, 24)
.raw()
.toBuffer(function(err, data, info) {
assert.strictEqual(32 * 24 * 3, info.size);
assert.strictEqual(data.length, info.size);
assert.strictEqual('raw', info.format);
assert.strictEqual(32, info.width);
assert.strictEqual(24, info.height);
done();
});
});
it('4 channel colour image with transparency', function(done) {
sharp(fixtures.inputPngWithTransparency)
.resize(32, 24)
.raw()
.toBuffer(function(err, data, info) {
assert.strictEqual(32 * 24 * 4, info.size);
assert.strictEqual(data.length, info.size);
assert.strictEqual('raw', info.format);
assert.strictEqual(32, info.width);
assert.strictEqual(24, info.height);
done();
});
});
});
}
});