mirror of
https://github.com/lovell/sharp.git
synced 2025-07-10 11:00:14 +02:00
Selected output format > unknown file extension #344
This commit is contained in:
parent
5c1067c63f
commit
677b2b9089
@ -396,7 +396,9 @@ sharp('input.png')
|
|||||||
|
|
||||||
#### toFile(path, [callback])
|
#### toFile(path, [callback])
|
||||||
|
|
||||||
`path` is a String containing the path to write the image data to. The format is inferred from the extension, with JPEG, PNG, WebP, TIFF and DZI supported.
|
`path` is a String containing the path to write the image data to.
|
||||||
|
|
||||||
|
If an explicit output format is not selected, it will be inferred from the extension, with JPEG, PNG, WebP, TIFF and DZI supported.
|
||||||
|
|
||||||
`callback`, if present, is called with two arguments `(err, info)` where:
|
`callback`, if present, is called with two arguments `(err, info)` where:
|
||||||
|
|
||||||
|
@ -25,6 +25,10 @@
|
|||||||
[#340](https://github.com/lovell/sharp/issues/340)
|
[#340](https://github.com/lovell/sharp/issues/340)
|
||||||
[@janaz](https://github.com/janaz)
|
[@janaz](https://github.com/janaz)
|
||||||
|
|
||||||
|
* Ensure selected format takes precedence over any unknown output filename extension.
|
||||||
|
[#344](https://github.com/lovell/sharp/issues/344)
|
||||||
|
[@ubaltaci](https://github.com/ubaltaci)
|
||||||
|
|
||||||
* Add support for libvips' PBM, PGM, PPM and FITS image format loaders.
|
* Add support for libvips' PBM, PGM, PPM and FITS image format loaders.
|
||||||
[#347](https://github.com/lovell/sharp/issues/347)
|
[#347](https://github.com/lovell/sharp/issues/347)
|
||||||
[@oaleynik](https://github.com/oaleynik)
|
[@oaleynik](https://github.com/oaleynik)
|
||||||
|
35
index.js
35
index.js
@ -86,7 +86,8 @@ var Sharp = function(input, options) {
|
|||||||
// overlay
|
// overlay
|
||||||
overlayPath: '',
|
overlayPath: '',
|
||||||
// output options
|
// output options
|
||||||
output: '__input',
|
formatOut: 'input',
|
||||||
|
fileOut: '',
|
||||||
progressive: false,
|
progressive: false,
|
||||||
quality: 80,
|
quality: 80,
|
||||||
compressionLevel: 6,
|
compressionLevel: 6,
|
||||||
@ -667,8 +668,8 @@ Sharp.prototype.limitInputPixels = function(limit) {
|
|||||||
/*
|
/*
|
||||||
Write output image data to a file
|
Write output image data to a file
|
||||||
*/
|
*/
|
||||||
Sharp.prototype.toFile = function(output, callback) {
|
Sharp.prototype.toFile = function(fileOut, callback) {
|
||||||
if (!output || output.length === 0) {
|
if (!fileOut || fileOut.length === 0) {
|
||||||
var errOutputInvalid = new Error('Invalid output');
|
var errOutputInvalid = new Error('Invalid output');
|
||||||
if (typeof callback === 'function') {
|
if (typeof callback === 'function') {
|
||||||
callback(errOutputInvalid);
|
callback(errOutputInvalid);
|
||||||
@ -676,7 +677,7 @@ Sharp.prototype.toFile = function(output, callback) {
|
|||||||
return BluebirdPromise.reject(errOutputInvalid);
|
return BluebirdPromise.reject(errOutputInvalid);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (this.options.fileIn === output) {
|
if (this.options.fileIn === fileOut) {
|
||||||
var errOutputIsInput = new Error('Cannot use same file for input and output');
|
var errOutputIsInput = new Error('Cannot use same file for input and output');
|
||||||
if (typeof callback === 'function') {
|
if (typeof callback === 'function') {
|
||||||
callback(errOutputIsInput);
|
callback(errOutputIsInput);
|
||||||
@ -684,7 +685,7 @@ Sharp.prototype.toFile = function(output, callback) {
|
|||||||
return BluebirdPromise.reject(errOutputIsInput);
|
return BluebirdPromise.reject(errOutputIsInput);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this.options.output = output;
|
this.options.fileOut = fileOut;
|
||||||
return this._pipeline(callback);
|
return this._pipeline(callback);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -702,7 +703,7 @@ Sharp.prototype.toBuffer = function(callback) {
|
|||||||
Force JPEG output
|
Force JPEG output
|
||||||
*/
|
*/
|
||||||
Sharp.prototype.jpeg = function() {
|
Sharp.prototype.jpeg = function() {
|
||||||
this.options.output = '__jpeg';
|
this.options.formatOut = 'jpeg';
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -710,7 +711,7 @@ Sharp.prototype.jpeg = function() {
|
|||||||
Force PNG output
|
Force PNG output
|
||||||
*/
|
*/
|
||||||
Sharp.prototype.png = function() {
|
Sharp.prototype.png = function() {
|
||||||
this.options.output = '__png';
|
this.options.formatOut = 'png';
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -718,7 +719,7 @@ Sharp.prototype.png = function() {
|
|||||||
Force WebP output
|
Force WebP output
|
||||||
*/
|
*/
|
||||||
Sharp.prototype.webp = function() {
|
Sharp.prototype.webp = function() {
|
||||||
this.options.output = '__webp';
|
this.options.formatOut = 'webp';
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -726,7 +727,7 @@ Sharp.prototype.webp = function() {
|
|||||||
Force raw, uint8 output
|
Force raw, uint8 output
|
||||||
*/
|
*/
|
||||||
Sharp.prototype.raw = function() {
|
Sharp.prototype.raw = function() {
|
||||||
this.options.output = '__raw';
|
this.options.formatOut = 'raw';
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -734,15 +735,17 @@ 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
|
@param format is either the id as a String or an Object with an 'id' attribute
|
||||||
*/
|
*/
|
||||||
Sharp.prototype.toFormat = function(format) {
|
Sharp.prototype.toFormat = function(formatOut) {
|
||||||
var id = format;
|
if (isObject(formatOut) && isDefined(formatOut.id)) {
|
||||||
if (typeof format === 'object') {
|
formatOut = formatOut.id;
|
||||||
id = format.id;
|
|
||||||
}
|
}
|
||||||
if (typeof id === 'string' && typeof module.exports.format[id] === 'object' && typeof this[id] === 'function') {
|
if (
|
||||||
this[id]();
|
isDefined(formatOut) &&
|
||||||
|
['jpeg', 'png', 'webp', 'raw', 'tiff', 'dz', 'input'].indexOf(formatOut) !== -1
|
||||||
|
) {
|
||||||
|
this.options.formatOut = formatOut;
|
||||||
} else {
|
} else {
|
||||||
throw new Error('Unsupported format ' + format);
|
throw new Error('Unsupported output format ' + formatOut);
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
@ -53,6 +53,26 @@ namespace sharp {
|
|||||||
return EndsWith(str, ".dzi") || EndsWith(str, ".DZI");
|
return EndsWith(str, ".dzi") || EndsWith(str, ".DZI");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Provide a string identifier for the given image type.
|
||||||
|
*/
|
||||||
|
std::string ImageTypeId(ImageType const imageType) {
|
||||||
|
std::string id;
|
||||||
|
switch (imageType) {
|
||||||
|
case ImageType::JPEG: id = "jpeg"; break;
|
||||||
|
case ImageType::PNG: id = "png"; break;
|
||||||
|
case ImageType::WEBP: id = "webp"; break;
|
||||||
|
case ImageType::TIFF: id = "tiff"; break;
|
||||||
|
case ImageType::MAGICK: id = "magick"; break;
|
||||||
|
case ImageType::OPENSLIDE: id = "openslide"; break;
|
||||||
|
case ImageType::PPM: id = "ppm"; break;
|
||||||
|
case ImageType::FITS: id = "fits"; break;
|
||||||
|
case ImageType::RAW: id = "raw"; break;
|
||||||
|
case ImageType::UNKNOWN: id = "unknown"; break;
|
||||||
|
}
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Determine image format of a buffer.
|
Determine image format of a buffer.
|
||||||
*/
|
*/
|
||||||
|
@ -34,6 +34,11 @@ namespace sharp {
|
|||||||
bool IsTiff(std::string const &str);
|
bool IsTiff(std::string const &str);
|
||||||
bool IsDz(std::string const &str);
|
bool IsDz(std::string const &str);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Provide a string identifier for the given image type.
|
||||||
|
*/
|
||||||
|
std::string ImageTypeId(ImageType const imageType);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Determine image format of a buffer.
|
Determine image format of a buffer.
|
||||||
*/
|
*/
|
||||||
|
@ -33,6 +33,7 @@ using vips::VImage;
|
|||||||
using vips::VError;
|
using vips::VError;
|
||||||
|
|
||||||
using sharp::ImageType;
|
using sharp::ImageType;
|
||||||
|
using sharp::ImageTypeId;
|
||||||
using sharp::DetermineImageType;
|
using sharp::DetermineImageType;
|
||||||
using sharp::HasProfile;
|
using sharp::HasProfile;
|
||||||
using sharp::HasAlpha;
|
using sharp::HasAlpha;
|
||||||
@ -113,18 +114,7 @@ class MetadataWorker : public AsyncWorker {
|
|||||||
}
|
}
|
||||||
if (imageType != ImageType::UNKNOWN) {
|
if (imageType != ImageType::UNKNOWN) {
|
||||||
// Image type
|
// Image type
|
||||||
switch (imageType) {
|
baton->format = ImageTypeId(imageType);
|
||||||
case ImageType::JPEG: baton->format = "jpeg"; break;
|
|
||||||
case ImageType::PNG: baton->format = "png"; break;
|
|
||||||
case ImageType::WEBP: baton->format = "webp"; break;
|
|
||||||
case ImageType::TIFF: baton->format = "tiff"; break;
|
|
||||||
case ImageType::MAGICK: baton->format = "magick"; break;
|
|
||||||
case ImageType::OPENSLIDE: baton->format = "openslide"; break;
|
|
||||||
case ImageType::PPM: baton->format = "ppm"; break;
|
|
||||||
case ImageType::FITS: baton->format = "fits"; break;
|
|
||||||
case ImageType::RAW: baton->format = "raw"; break;
|
|
||||||
case ImageType::UNKNOWN: break;
|
|
||||||
}
|
|
||||||
// VipsImage attributes
|
// VipsImage attributes
|
||||||
baton->width = image.width();
|
baton->width = image.width();
|
||||||
baton->height = image.height();
|
baton->height = image.height();
|
||||||
|
163
src/pipeline.cc
163
src/pipeline.cc
@ -49,6 +49,7 @@ using sharp::Blur;
|
|||||||
using sharp::Sharpen;
|
using sharp::Sharpen;
|
||||||
|
|
||||||
using sharp::ImageType;
|
using sharp::ImageType;
|
||||||
|
using sharp::ImageTypeId;
|
||||||
using sharp::DetermineImageType;
|
using sharp::DetermineImageType;
|
||||||
using sharp::HasProfile;
|
using sharp::HasProfile;
|
||||||
using sharp::HasAlpha;
|
using sharp::HasAlpha;
|
||||||
@ -82,8 +83,8 @@ struct PipelineBaton {
|
|||||||
int rawWidth;
|
int rawWidth;
|
||||||
int rawHeight;
|
int rawHeight;
|
||||||
int rawChannels;
|
int rawChannels;
|
||||||
std::string output;
|
std::string formatOut;
|
||||||
std::string outputFormat;
|
std::string fileOut;
|
||||||
void *bufferOut;
|
void *bufferOut;
|
||||||
size_t bufferOutLength;
|
size_t bufferOutLength;
|
||||||
int topOffsetPre;
|
int topOffsetPre;
|
||||||
@ -139,7 +140,8 @@ struct PipelineBaton {
|
|||||||
rawWidth(0),
|
rawWidth(0),
|
||||||
rawHeight(0),
|
rawHeight(0),
|
||||||
rawChannels(0),
|
rawChannels(0),
|
||||||
outputFormat(""),
|
formatOut(""),
|
||||||
|
fileOut(""),
|
||||||
bufferOutLength(0),
|
bufferOutLength(0),
|
||||||
topOffsetPre(-1),
|
topOffsetPre(-1),
|
||||||
topOffsetPost(-1),
|
topOffsetPost(-1),
|
||||||
@ -707,62 +709,75 @@ class PipelineWorker : public AsyncWorker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Output
|
// Output
|
||||||
if (baton->output == "__jpeg" || (baton->output == "__input" && inputImageType == ImageType::JPEG)) {
|
if (baton->fileOut == "") {
|
||||||
// Write JPEG to buffer
|
// Buffer output
|
||||||
baton->bufferOut = static_cast<char*>(const_cast<void*>(vips_blob_get(image.jpegsave_buffer(VImage::option()
|
if (baton->formatOut == "jpeg" || (baton->formatOut == "input" && inputImageType == ImageType::JPEG)) {
|
||||||
->set("strip", !baton->withMetadata)
|
// Write JPEG to buffer
|
||||||
->set("Q", baton->quality)
|
baton->bufferOut = static_cast<char*>(const_cast<void*>(vips_blob_get(image.jpegsave_buffer(VImage::option()
|
||||||
->set("optimize_coding", TRUE)
|
->set("strip", !baton->withMetadata)
|
||||||
->set("no_subsample", baton->withoutChromaSubsampling)
|
->set("Q", baton->quality)
|
||||||
->set("trellis_quant", baton->trellisQuantisation)
|
->set("optimize_coding", TRUE)
|
||||||
->set("overshoot_deringing", baton->overshootDeringing)
|
->set("no_subsample", baton->withoutChromaSubsampling)
|
||||||
->set("optimize_scans", baton->optimiseScans)
|
->set("trellis_quant", baton->trellisQuantisation)
|
||||||
->set("interlace", baton->progressive)
|
->set("overshoot_deringing", baton->overshootDeringing)
|
||||||
), &baton->bufferOutLength)));
|
->set("optimize_scans", baton->optimiseScans)
|
||||||
baton->outputFormat = "jpeg";
|
->set("interlace", baton->progressive)
|
||||||
} else if (baton->output == "__png" || (baton->output == "__input" && inputImageType == ImageType::PNG)) {
|
), &baton->bufferOutLength)));
|
||||||
// Write PNG to buffer
|
baton->formatOut = "jpeg";
|
||||||
baton->bufferOut = static_cast<char*>(const_cast<void*>(vips_blob_get(image.pngsave_buffer(VImage::option()
|
} else if (baton->formatOut == "png" || (baton->formatOut == "input" && inputImageType == ImageType::PNG)) {
|
||||||
->set("strip", !baton->withMetadata)
|
// Write PNG to buffer
|
||||||
->set("compression", baton->compressionLevel)
|
baton->bufferOut = static_cast<char*>(const_cast<void*>(vips_blob_get(image.pngsave_buffer(VImage::option()
|
||||||
->set("interlace", baton->progressive)
|
->set("strip", !baton->withMetadata)
|
||||||
->set("filter", baton->withoutAdaptiveFiltering ? VIPS_FOREIGN_PNG_FILTER_NONE : VIPS_FOREIGN_PNG_FILTER_ALL)
|
->set("compression", baton->compressionLevel)
|
||||||
), &baton->bufferOutLength)));
|
->set("interlace", baton->progressive)
|
||||||
baton->outputFormat = "png";
|
->set("filter", baton->withoutAdaptiveFiltering ? VIPS_FOREIGN_PNG_FILTER_NONE : VIPS_FOREIGN_PNG_FILTER_ALL)
|
||||||
} else if (baton->output == "__webp" || (baton->output == "__input" && inputImageType == ImageType::WEBP)) {
|
), &baton->bufferOutLength)));
|
||||||
// Write WEBP to buffer
|
baton->formatOut = "png";
|
||||||
baton->bufferOut = static_cast<char*>(const_cast<void*>(vips_blob_get(image.webpsave_buffer(VImage::option()
|
} else if (baton->formatOut == "webp" || (baton->formatOut == "input" && inputImageType == ImageType::WEBP)) {
|
||||||
->set("strip", !baton->withMetadata)
|
// Write WEBP to buffer
|
||||||
->set("Q", baton->quality)
|
baton->bufferOut = static_cast<char*>(const_cast<void*>(vips_blob_get(image.webpsave_buffer(VImage::option()
|
||||||
), &baton->bufferOutLength)));
|
->set("strip", !baton->withMetadata)
|
||||||
baton->outputFormat = "webp";
|
->set("Q", baton->quality)
|
||||||
} else if (baton->output == "__raw") {
|
), &baton->bufferOutLength)));
|
||||||
// Write raw, uncompressed image data to buffer
|
baton->formatOut = "webp";
|
||||||
if (baton->greyscale || image.interpretation() == VIPS_INTERPRETATION_B_W) {
|
} else if (baton->formatOut == "raw") {
|
||||||
// Extract first band for greyscale image
|
// Write raw, uncompressed image data to buffer
|
||||||
image = image[0];
|
if (baton->greyscale || image.interpretation() == VIPS_INTERPRETATION_B_W) {
|
||||||
}
|
// Extract first band for greyscale image
|
||||||
if (image.format() != VIPS_FORMAT_UCHAR) {
|
image = image[0];
|
||||||
// Cast pixels to uint8 (unsigned char)
|
}
|
||||||
image = image.cast(VIPS_FORMAT_UCHAR);
|
if (image.format() != VIPS_FORMAT_UCHAR) {
|
||||||
}
|
// Cast pixels to uint8 (unsigned char)
|
||||||
// Get raw image data
|
image = image.cast(VIPS_FORMAT_UCHAR);
|
||||||
baton->bufferOut = static_cast<char*>(image.write_to_memory(&baton->bufferOutLength));
|
}
|
||||||
if (baton->bufferOut == nullptr) {
|
// Get raw image data
|
||||||
(baton->err).append("Could not allocate enough memory for raw output");
|
baton->bufferOut = static_cast<char*>(image.write_to_memory(&baton->bufferOutLength));
|
||||||
|
if (baton->bufferOut == nullptr) {
|
||||||
|
(baton->err).append("Could not allocate enough memory for raw output");
|
||||||
|
return Error();
|
||||||
|
}
|
||||||
|
baton->formatOut = "raw";
|
||||||
|
} else {
|
||||||
|
// Unsupported output format
|
||||||
|
(baton->err).append("Unsupported output format ");
|
||||||
|
if (baton->formatOut == "input") {
|
||||||
|
(baton->err).append(ImageTypeId(inputImageType));
|
||||||
|
} else {
|
||||||
|
(baton->err).append(baton->formatOut);
|
||||||
|
}
|
||||||
return Error();
|
return Error();
|
||||||
}
|
}
|
||||||
baton->outputFormat = "raw";
|
|
||||||
} else {
|
} else {
|
||||||
bool outputJpeg = IsJpeg(baton->output);
|
// File output
|
||||||
bool outputPng = IsPng(baton->output);
|
bool isJpeg = IsJpeg(baton->fileOut);
|
||||||
bool outputWebp = IsWebp(baton->output);
|
bool isPng = IsPng(baton->fileOut);
|
||||||
bool outputTiff = IsTiff(baton->output);
|
bool isWebp = IsWebp(baton->fileOut);
|
||||||
bool outputDz = IsDz(baton->output);
|
bool isTiff = IsTiff(baton->fileOut);
|
||||||
bool matchInput = !(outputJpeg || outputPng || outputWebp || outputTiff || outputDz);
|
bool isDz = IsDz(baton->fileOut);
|
||||||
if (outputJpeg || (matchInput && inputImageType == ImageType::JPEG)) {
|
bool matchInput = baton->formatOut == "input" && !(isJpeg || isPng || isWebp || isTiff || isDz);
|
||||||
|
if (baton->formatOut == "jpeg" || isJpeg || (matchInput && inputImageType == ImageType::JPEG)) {
|
||||||
// Write JPEG to file
|
// Write JPEG to file
|
||||||
image.jpegsave(const_cast<char*>(baton->output.data()), VImage::option()
|
image.jpegsave(const_cast<char*>(baton->fileOut.data()), VImage::option()
|
||||||
->set("strip", !baton->withMetadata)
|
->set("strip", !baton->withMetadata)
|
||||||
->set("Q", baton->quality)
|
->set("Q", baton->quality)
|
||||||
->set("optimize_coding", TRUE)
|
->set("optimize_coding", TRUE)
|
||||||
@ -772,41 +787,42 @@ class PipelineWorker : public AsyncWorker {
|
|||||||
->set("optimize_scans", baton->optimiseScans)
|
->set("optimize_scans", baton->optimiseScans)
|
||||||
->set("interlace", baton->progressive)
|
->set("interlace", baton->progressive)
|
||||||
);
|
);
|
||||||
baton->outputFormat = "jpeg";
|
baton->formatOut = "jpeg";
|
||||||
} else if (outputPng || (matchInput && inputImageType == ImageType::PNG)) {
|
} else if (baton->formatOut == "png" || isPng || (matchInput && inputImageType == ImageType::PNG)) {
|
||||||
// Write PNG to file
|
// Write PNG to file
|
||||||
image.pngsave(const_cast<char*>(baton->output.data()), VImage::option()
|
image.pngsave(const_cast<char*>(baton->fileOut.data()), VImage::option()
|
||||||
->set("strip", !baton->withMetadata)
|
->set("strip", !baton->withMetadata)
|
||||||
->set("compression", baton->compressionLevel)
|
->set("compression", baton->compressionLevel)
|
||||||
->set("interlace", baton->progressive)
|
->set("interlace", baton->progressive)
|
||||||
->set("filter", baton->withoutAdaptiveFiltering ? VIPS_FOREIGN_PNG_FILTER_NONE : VIPS_FOREIGN_PNG_FILTER_ALL)
|
->set("filter", baton->withoutAdaptiveFiltering ? VIPS_FOREIGN_PNG_FILTER_NONE : VIPS_FOREIGN_PNG_FILTER_ALL)
|
||||||
);
|
);
|
||||||
baton->outputFormat = "png";
|
baton->formatOut = "png";
|
||||||
} else if (outputWebp || (matchInput && inputImageType == ImageType::WEBP)) {
|
} else if (baton->formatOut == "webp" || isWebp || (matchInput && inputImageType == ImageType::WEBP)) {
|
||||||
// Write WEBP to file
|
// Write WEBP to file
|
||||||
image.webpsave(const_cast<char*>(baton->output.data()), VImage::option()
|
image.webpsave(const_cast<char*>(baton->fileOut.data()), VImage::option()
|
||||||
->set("strip", !baton->withMetadata)
|
->set("strip", !baton->withMetadata)
|
||||||
->set("Q", baton->quality)
|
->set("Q", baton->quality)
|
||||||
);
|
);
|
||||||
baton->outputFormat = "webp";
|
baton->formatOut = "webp";
|
||||||
} else if (outputTiff || (matchInput && inputImageType == ImageType::TIFF)) {
|
} else if (baton->formatOut == "tiff" || isTiff || (matchInput && inputImageType == ImageType::TIFF)) {
|
||||||
// Write TIFF to file
|
// Write TIFF to file
|
||||||
image.tiffsave(const_cast<char*>(baton->output.data()), VImage::option()
|
image.tiffsave(const_cast<char*>(baton->fileOut.data()), VImage::option()
|
||||||
->set("strip", !baton->withMetadata)
|
->set("strip", !baton->withMetadata)
|
||||||
->set("Q", baton->quality)
|
->set("Q", baton->quality)
|
||||||
->set("compression", VIPS_FOREIGN_TIFF_COMPRESSION_JPEG)
|
->set("compression", VIPS_FOREIGN_TIFF_COMPRESSION_JPEG)
|
||||||
);
|
);
|
||||||
baton->outputFormat = "tiff";
|
baton->formatOut = "tiff";
|
||||||
} else if (outputDz) {
|
} else if (baton->formatOut == "dz" || IsDz(baton->fileOut)) {
|
||||||
// Write DZ to file
|
// Write DZ to file
|
||||||
image.dzsave(const_cast<char*>(baton->output.data()), VImage::option()
|
image.dzsave(const_cast<char*>(baton->fileOut.data()), VImage::option()
|
||||||
->set("strip", !baton->withMetadata)
|
->set("strip", !baton->withMetadata)
|
||||||
->set("tile_size", baton->tileSize)
|
->set("tile_size", baton->tileSize)
|
||||||
->set("overlap", baton->tileOverlap)
|
->set("overlap", baton->tileOverlap)
|
||||||
);
|
);
|
||||||
baton->outputFormat = "dz";
|
baton->formatOut = "dz";
|
||||||
} else {
|
} else {
|
||||||
(baton->err).append("Unsupported output " + baton->output);
|
// Unsupported output format
|
||||||
|
(baton->err).append("Unsupported output format " + baton->fileOut);
|
||||||
return Error();
|
return Error();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -840,7 +856,7 @@ class PipelineWorker : public AsyncWorker {
|
|||||||
}
|
}
|
||||||
// Info Object
|
// Info Object
|
||||||
Local<Object> info = New<Object>();
|
Local<Object> info = New<Object>();
|
||||||
Set(info, New("format").ToLocalChecked(), New<String>(baton->outputFormat).ToLocalChecked());
|
Set(info, New("format").ToLocalChecked(), New<String>(baton->formatOut).ToLocalChecked());
|
||||||
Set(info, New("width").ToLocalChecked(), New<Uint32>(static_cast<uint32_t>(width)));
|
Set(info, New("width").ToLocalChecked(), New<Uint32>(static_cast<uint32_t>(width)));
|
||||||
Set(info, New("height").ToLocalChecked(), New<Uint32>(static_cast<uint32_t>(height)));
|
Set(info, New("height").ToLocalChecked(), New<Uint32>(static_cast<uint32_t>(height)));
|
||||||
Set(info, New("channels").ToLocalChecked(), New<Uint32>(static_cast<uint32_t>(baton->channels)));
|
Set(info, New("channels").ToLocalChecked(), New<Uint32>(static_cast<uint32_t>(baton->channels)));
|
||||||
@ -856,7 +872,7 @@ class PipelineWorker : public AsyncWorker {
|
|||||||
} else {
|
} else {
|
||||||
// Add file size to info
|
// Add file size to info
|
||||||
GStatBuf st;
|
GStatBuf st;
|
||||||
g_stat(baton->output.data(), &st);
|
g_stat(baton->fileOut.data(), &st);
|
||||||
Set(info, New("size").ToLocalChecked(), New<Uint32>(static_cast<uint32_t>(st.st_size)));
|
Set(info, New("size").ToLocalChecked(), New<Uint32>(static_cast<uint32_t>(st.st_size)));
|
||||||
argv[1] = info;
|
argv[1] = info;
|
||||||
}
|
}
|
||||||
@ -1091,8 +1107,9 @@ NAN_METHOD(pipeline) {
|
|||||||
baton->optimiseScans = attrAs<bool>(options, "optimiseScans");
|
baton->optimiseScans = attrAs<bool>(options, "optimiseScans");
|
||||||
baton->withMetadata = attrAs<bool>(options, "withMetadata");
|
baton->withMetadata = attrAs<bool>(options, "withMetadata");
|
||||||
baton->withMetadataOrientation = attrAs<int32_t>(options, "withMetadataOrientation");
|
baton->withMetadataOrientation = attrAs<int32_t>(options, "withMetadataOrientation");
|
||||||
// Output filename or __format for Buffer
|
// Output
|
||||||
baton->output = attrAsStr(options, "output");
|
baton->formatOut = attrAsStr(options, "formatOut");
|
||||||
|
baton->fileOut = attrAsStr(options, "fileOut");
|
||||||
baton->tileSize = attrAs<int32_t>(options, "tileSize");
|
baton->tileSize = attrAs<int32_t>(options, "tileSize");
|
||||||
baton->tileOverlap = attrAs<int32_t>(options, "tileOverlap");
|
baton->tileOverlap = attrAs<int32_t>(options, "tileOverlap");
|
||||||
// Function to notify of queue length changes
|
// Function to notify of queue length changes
|
||||||
|
123
test/unit/io.js
123
test/unit/io.js
@ -392,76 +392,89 @@ describe('Input/output', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Output filename without extension uses input format', function() {
|
describe('Output filename with unknown extension', function() {
|
||||||
|
|
||||||
it('JPEG', function(done) {
|
it('Match JPEG input', function(done) {
|
||||||
sharp(fixtures.inputJpg).resize(320, 80).toFile(fixtures.outputZoinks, function(err, info) {
|
sharp(fixtures.inputJpg)
|
||||||
if (err) throw err;
|
.resize(320, 80)
|
||||||
assert.strictEqual(true, info.size > 0);
|
.toFile(fixtures.outputZoinks, function(err, info) {
|
||||||
assert.strictEqual('jpeg', info.format);
|
|
||||||
assert.strictEqual(320, info.width);
|
|
||||||
assert.strictEqual(80, info.height);
|
|
||||||
fs.unlinkSync(fixtures.outputZoinks);
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('PNG', function(done) {
|
|
||||||
sharp(fixtures.inputPng).resize(320, 80).toFile(fixtures.outputZoinks, function(err, info) {
|
|
||||||
if (err) throw err;
|
|
||||||
assert.strictEqual(true, info.size > 0);
|
|
||||||
assert.strictEqual('png', info.format);
|
|
||||||
assert.strictEqual(320, info.width);
|
|
||||||
assert.strictEqual(80, info.height);
|
|
||||||
fs.unlinkSync(fixtures.outputZoinks);
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Transparent PNG', function(done) {
|
|
||||||
sharp(fixtures.inputPngWithTransparency).resize(320, 80).toFile(fixtures.outputZoinks, function(err, info) {
|
|
||||||
if (err) throw err;
|
|
||||||
assert.strictEqual(true, info.size > 0);
|
|
||||||
assert.strictEqual('png', info.format);
|
|
||||||
assert.strictEqual(320, info.width);
|
|
||||||
assert.strictEqual(80, info.height);
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
if (sharp.format.webp.input.file) {
|
|
||||||
it('WebP', function(done) {
|
|
||||||
sharp(fixtures.inputWebP).resize(320, 80).toFile(fixtures.outputZoinks, function(err, info) {
|
|
||||||
if (err) throw err;
|
if (err) throw err;
|
||||||
assert.strictEqual(true, info.size > 0);
|
assert.strictEqual(true, info.size > 0);
|
||||||
assert.strictEqual('webp', info.format);
|
assert.strictEqual('jpeg', info.format);
|
||||||
assert.strictEqual(320, info.width);
|
assert.strictEqual(320, info.width);
|
||||||
assert.strictEqual(80, info.height);
|
assert.strictEqual(80, info.height);
|
||||||
fs.unlinkSync(fixtures.outputZoinks);
|
fs.unlinkSync(fixtures.outputZoinks);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Match PNG input', function(done) {
|
||||||
|
sharp(fixtures.inputPng)
|
||||||
|
.resize(320, 80)
|
||||||
|
.toFile(fixtures.outputZoinks, function(err, info) {
|
||||||
|
if (err) throw err;
|
||||||
|
assert.strictEqual(true, info.size > 0);
|
||||||
|
assert.strictEqual('png', info.format);
|
||||||
|
assert.strictEqual(320, info.width);
|
||||||
|
assert.strictEqual(80, info.height);
|
||||||
|
fs.unlinkSync(fixtures.outputZoinks);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
if (sharp.format.webp.input.file) {
|
||||||
|
it('Match WebP input', function(done) {
|
||||||
|
sharp(fixtures.inputWebP)
|
||||||
|
.resize(320, 80)
|
||||||
|
.toFile(fixtures.outputZoinks, function(err, info) {
|
||||||
|
if (err) throw err;
|
||||||
|
assert.strictEqual(true, info.size > 0);
|
||||||
|
assert.strictEqual('webp', info.format);
|
||||||
|
assert.strictEqual(320, info.width);
|
||||||
|
assert.strictEqual(80, info.height);
|
||||||
|
fs.unlinkSync(fixtures.outputZoinks);
|
||||||
|
done();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
it('TIFF', function(done) {
|
it('Match TIFF input', function(done) {
|
||||||
sharp(fixtures.inputTiff).resize(320, 80).toFile(fixtures.outputZoinks, function(err, info) {
|
sharp(fixtures.inputTiff)
|
||||||
if (err) throw err;
|
.resize(320, 80)
|
||||||
assert.strictEqual(true, info.size > 0);
|
.toFile(fixtures.outputZoinks, function(err, info) {
|
||||||
assert.strictEqual('tiff', info.format);
|
if (err) throw err;
|
||||||
assert.strictEqual(320, info.width);
|
assert.strictEqual(true, info.size > 0);
|
||||||
assert.strictEqual(80, info.height);
|
assert.strictEqual('tiff', info.format);
|
||||||
fs.unlinkSync(fixtures.outputZoinks);
|
assert.strictEqual(320, info.width);
|
||||||
done();
|
assert.strictEqual(80, info.height);
|
||||||
});
|
fs.unlinkSync(fixtures.outputZoinks);
|
||||||
|
done();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Fail with GIF', function(done) {
|
it('Match GIF input, therefore fail', function(done) {
|
||||||
sharp(fixtures.inputGif).resize(320, 80).toFile(fixtures.outputZoinks, function(err) {
|
sharp(fixtures.inputGif)
|
||||||
assert(!!err);
|
.resize(320, 80)
|
||||||
done();
|
.toFile(fixtures.outputZoinks, function(err) {
|
||||||
});
|
assert(!!err);
|
||||||
|
done();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('Force JPEG format for PNG input', function(done) {
|
||||||
|
sharp(fixtures.inputPng)
|
||||||
|
.resize(320, 80)
|
||||||
|
.jpeg()
|
||||||
|
.toFile(fixtures.outputZoinks, function(err, info) {
|
||||||
|
if (err) throw err;
|
||||||
|
assert.strictEqual(true, info.size > 0);
|
||||||
|
assert.strictEqual('jpeg', info.format);
|
||||||
|
assert.strictEqual(320, info.width);
|
||||||
|
assert.strictEqual(80, info.height);
|
||||||
|
fs.unlinkSync(fixtures.outputZoinks);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('PNG output', function() {
|
describe('PNG output', function() {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user