Expose libjpeg optimize_coding flag (#1265)

This commit is contained in:
Tom Lokhorst 2018-06-21 19:12:10 +02:00 committed by Lovell Fuller
parent 873aa6700f
commit 76c41eaf05
5 changed files with 43 additions and 3 deletions

View File

@ -192,6 +192,7 @@ const Sharp = function (input, options) {
jpegTrellisQuantisation: false, jpegTrellisQuantisation: false,
jpegOvershootDeringing: false, jpegOvershootDeringing: false,
jpegOptimiseScans: false, jpegOptimiseScans: false,
jpegOptimiseCoding: true,
pngProgressive: false, pngProgressive: false,
pngCompressionLevel: 9, pngCompressionLevel: 9,
pngAdaptiveFiltering: false, pngAdaptiveFiltering: false,

View File

@ -148,6 +148,8 @@ function withMetadata (withMetadata) {
* @param {Boolean} [options.overshootDeringing=false] - apply overshoot deringing, requires mozjpeg * @param {Boolean} [options.overshootDeringing=false] - apply overshoot deringing, requires mozjpeg
* @param {Boolean} [options.optimiseScans=false] - optimise progressive scans, forces progressive, requires mozjpeg * @param {Boolean} [options.optimiseScans=false] - optimise progressive scans, forces progressive, requires mozjpeg
* @param {Boolean} [options.optimizeScans=false] - alternative spelling of optimiseScans * @param {Boolean} [options.optimizeScans=false] - alternative spelling of optimiseScans
* @param {Boolean} [options.optimiseCoding=true] - optimise Huffman coding tables
* @param {Boolean} [options.optimizeCoding=true] - alternative spelling of optimiseCoding
* @param {Boolean} [options.force=true] - force JPEG output, otherwise attempt to use input format * @param {Boolean} [options.force=true] - force JPEG output, otherwise attempt to use input format
* @returns {Sharp} * @returns {Sharp}
* @throws {Error} Invalid options * @throws {Error} Invalid options
@ -185,6 +187,10 @@ function jpeg (options) {
this.options.jpegProgressive = true; this.options.jpegProgressive = true;
} }
} }
options.optimiseCoding = is.bool(options.optimizeCoding) ? options.optimizeCoding : options.optimiseCoding;
if (is.defined(options.optimiseCoding)) {
this._setBooleanOption('jpegOptimiseCoding', options.optimiseCoding);
}
} }
return this._updateFormatOut('jpeg', options); return this._updateFormatOut('jpeg', options);
} }

View File

@ -735,7 +735,7 @@ class PipelineWorker : public Nan::AsyncWorker {
->set("trellis_quant", baton->jpegTrellisQuantisation) ->set("trellis_quant", baton->jpegTrellisQuantisation)
->set("overshoot_deringing", baton->jpegOvershootDeringing) ->set("overshoot_deringing", baton->jpegOvershootDeringing)
->set("optimize_scans", baton->jpegOptimiseScans) ->set("optimize_scans", baton->jpegOptimiseScans)
->set("optimize_coding", TRUE))); ->set("optimize_coding", baton->jpegOptimiseCoding)));
baton->bufferOut = static_cast<char*>(area->data); baton->bufferOut = static_cast<char*>(area->data);
baton->bufferOutLength = area->length; baton->bufferOutLength = area->length;
area->free_fn = nullptr; area->free_fn = nullptr;
@ -850,7 +850,7 @@ class PipelineWorker : public Nan::AsyncWorker {
->set("trellis_quant", baton->jpegTrellisQuantisation) ->set("trellis_quant", baton->jpegTrellisQuantisation)
->set("overshoot_deringing", baton->jpegOvershootDeringing) ->set("overshoot_deringing", baton->jpegOvershootDeringing)
->set("optimize_scans", baton->jpegOptimiseScans) ->set("optimize_scans", baton->jpegOptimiseScans)
->set("optimize_coding", TRUE)); ->set("optimize_coding", baton->jpegOptimiseCoding));
baton->formatOut = "jpeg"; baton->formatOut = "jpeg";
baton->channels = std::min(baton->channels, 3); baton->channels = std::min(baton->channels, 3);
} else if (baton->formatOut == "png" || (mightMatchInput && isPng) || (willMatchInput && } else if (baton->formatOut == "png" || (mightMatchInput && isPng) || (willMatchInput &&
@ -929,7 +929,7 @@ class PipelineWorker : public Nan::AsyncWorker {
{"trellis_quant", baton->jpegTrellisQuantisation ? "TRUE" : "FALSE"}, {"trellis_quant", baton->jpegTrellisQuantisation ? "TRUE" : "FALSE"},
{"overshoot_deringing", baton->jpegOvershootDeringing ? "TRUE": "FALSE"}, {"overshoot_deringing", baton->jpegOvershootDeringing ? "TRUE": "FALSE"},
{"optimize_scans", baton->jpegOptimiseScans ? "TRUE": "FALSE"}, {"optimize_scans", baton->jpegOptimiseScans ? "TRUE": "FALSE"},
{"optimize_coding", "TRUE"} {"optimize_coding", baton->jpegOptimiseCoding ? "TRUE": "FALSE"}
}; };
suffix = AssembleSuffixString(extname, options); suffix = AssembleSuffixString(extname, options);
} }
@ -1268,6 +1268,7 @@ NAN_METHOD(pipeline) {
baton->jpegTrellisQuantisation = AttrTo<bool>(options, "jpegTrellisQuantisation"); baton->jpegTrellisQuantisation = AttrTo<bool>(options, "jpegTrellisQuantisation");
baton->jpegOvershootDeringing = AttrTo<bool>(options, "jpegOvershootDeringing"); baton->jpegOvershootDeringing = AttrTo<bool>(options, "jpegOvershootDeringing");
baton->jpegOptimiseScans = AttrTo<bool>(options, "jpegOptimiseScans"); baton->jpegOptimiseScans = AttrTo<bool>(options, "jpegOptimiseScans");
baton->jpegOptimiseCoding = AttrTo<bool>(options, "jpegOptimiseCoding");
baton->pngProgressive = AttrTo<bool>(options, "pngProgressive"); baton->pngProgressive = AttrTo<bool>(options, "pngProgressive");
baton->pngCompressionLevel = AttrTo<uint32_t>(options, "pngCompressionLevel"); baton->pngCompressionLevel = AttrTo<uint32_t>(options, "pngCompressionLevel");
baton->pngAdaptiveFiltering = AttrTo<bool>(options, "pngAdaptiveFiltering"); baton->pngAdaptiveFiltering = AttrTo<bool>(options, "pngAdaptiveFiltering");

View File

@ -104,6 +104,7 @@ struct PipelineBaton {
bool jpegTrellisQuantisation; bool jpegTrellisQuantisation;
bool jpegOvershootDeringing; bool jpegOvershootDeringing;
bool jpegOptimiseScans; bool jpegOptimiseScans;
bool jpegOptimiseCoding;
bool pngProgressive; bool pngProgressive;
int pngCompressionLevel; int pngCompressionLevel;
bool pngAdaptiveFiltering; bool pngAdaptiveFiltering;
@ -189,6 +190,7 @@ struct PipelineBaton {
jpegTrellisQuantisation(false), jpegTrellisQuantisation(false),
jpegOvershootDeringing(false), jpegOvershootDeringing(false),
jpegOptimiseScans(false), jpegOptimiseScans(false),
jpegOptimiseCoding(true),
pngProgressive(false), pngProgressive(false),
pngCompressionLevel(9), pngCompressionLevel(9),
pngAdaptiveFiltering(false), pngAdaptiveFiltering(false),

View File

@ -826,6 +826,36 @@ describe('Input/output', function () {
}); });
}); });
it('Optimise coding generates smaller output length', function (done) {
// First generate with optimize coding enabled (default)
sharp(fixtures.inputJpg)
.resize(320, 240)
.jpeg()
.toBuffer(function (err, withOptimiseCoding, withInfo) {
if (err) throw err;
assert.strictEqual(true, withOptimiseCoding.length > 0);
assert.strictEqual(withOptimiseCoding.length, withInfo.size);
assert.strictEqual('jpeg', withInfo.format);
assert.strictEqual(320, withInfo.width);
assert.strictEqual(240, withInfo.height);
// Then generate with coding disabled
sharp(fixtures.inputJpg)
.resize(320, 240)
.jpeg({ optimizeCoding: false })
.toBuffer(function (err, withoutOptimiseCoding, withoutInfo) {
if (err) throw err;
assert.strictEqual(true, withoutOptimiseCoding.length > 0);
assert.strictEqual(withoutOptimiseCoding.length, withoutInfo.size);
assert.strictEqual('jpeg', withoutInfo.format);
assert.strictEqual(320, withoutInfo.width);
assert.strictEqual(240, withoutInfo.height);
// Verify optimised image is of a smaller size
assert.strictEqual(true, withOptimiseCoding.length < withoutOptimiseCoding.length);
done();
});
});
});
it('Convert SVG to PNG at default 72DPI', function (done) { it('Convert SVG to PNG at default 72DPI', function (done) {
sharp(fixtures.inputSvg) sharp(fixtures.inputSvg)
.resize(1024) .resize(1024)