mirror of
https://github.com/lovell/sharp.git
synced 2025-07-09 18:40:16 +02:00
Expose mozjpeg quant_table flag (#1285)
This commit is contained in:
parent
5cb35485f1
commit
7bbc5176a1
@ -116,6 +116,8 @@ Use these JPEG options for output image.
|
|||||||
- `options.progressive` **[Boolean][6]** use progressive (interlace) scan (optional, default `false`)
|
- `options.progressive` **[Boolean][6]** use progressive (interlace) scan (optional, default `false`)
|
||||||
- `options.chromaSubsampling` **[String][1]** set to '4:4:4' to prevent chroma subsampling when quality <= 90 (optional, default `'4:2:0'`)
|
- `options.chromaSubsampling` **[String][1]** set to '4:4:4' to prevent chroma subsampling when quality <= 90 (optional, default `'4:2:0'`)
|
||||||
- `options.trellisQuantisation` **[Boolean][6]** apply trellis quantisation, requires mozjpeg (optional, default `false`)
|
- `options.trellisQuantisation` **[Boolean][6]** apply trellis quantisation, requires mozjpeg (optional, default `false`)
|
||||||
|
- `options.quantisationTable` **[Number][8]** [quantisation table][9] to use, integer 0-8 (optional, default `0`)
|
||||||
|
- `options.quantizationTable` **[Number][8]** alternative spelling of quantisationTable (optional, default `0`)
|
||||||
- `options.overshootDeringing` **[Boolean][6]** apply overshoot deringing, requires mozjpeg (optional, default `false`)
|
- `options.overshootDeringing` **[Boolean][6]** apply overshoot deringing, requires mozjpeg (optional, default `false`)
|
||||||
- `options.optimiseScans` **[Boolean][6]** optimise progressive scans, forces progressive, requires mozjpeg (optional, default `false`)
|
- `options.optimiseScans` **[Boolean][6]** optimise progressive scans, forces progressive, requires mozjpeg (optional, default `false`)
|
||||||
- `options.optimizeScans` **[Boolean][6]** alternative spelling of optimiseScans (optional, default `false`)
|
- `options.optimizeScans` **[Boolean][6]** alternative spelling of optimiseScans (optional, default `false`)
|
||||||
@ -312,3 +314,5 @@ Returns **Sharp**
|
|||||||
[7]: https://nodejs.org/api/buffer.html
|
[7]: https://nodejs.org/api/buffer.html
|
||||||
|
|
||||||
[8]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number
|
[8]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number
|
||||||
|
|
||||||
|
[9]: https://jcupitt.github.io/libvips/API/current/VipsForeignSave.html#vips-jpegsave
|
||||||
|
@ -193,6 +193,7 @@ const Sharp = function (input, options) {
|
|||||||
jpegOvershootDeringing: false,
|
jpegOvershootDeringing: false,
|
||||||
jpegOptimiseScans: false,
|
jpegOptimiseScans: false,
|
||||||
jpegOptimiseCoding: true,
|
jpegOptimiseCoding: true,
|
||||||
|
jpegQuantisationTable: 0,
|
||||||
pngProgressive: false,
|
pngProgressive: false,
|
||||||
pngCompressionLevel: 9,
|
pngCompressionLevel: 9,
|
||||||
pngAdaptiveFiltering: false,
|
pngAdaptiveFiltering: false,
|
||||||
|
@ -150,6 +150,8 @@ function withMetadata (withMetadata) {
|
|||||||
* @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.optimiseCoding=true] - optimise Huffman coding tables
|
||||||
* @param {Boolean} [options.optimizeCoding=true] - alternative spelling of optimiseCoding
|
* @param {Boolean} [options.optimizeCoding=true] - alternative spelling of optimiseCoding
|
||||||
|
* @param {Number} [options.quantisationTable=0] - quantization table to use, integer 0-8, requires mozjpeg
|
||||||
|
* @param {Number} [options.quantizationTable=0] - alternative spelling of quantisationTable
|
||||||
* @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
|
||||||
@ -191,6 +193,14 @@ function jpeg (options) {
|
|||||||
if (is.defined(options.optimiseCoding)) {
|
if (is.defined(options.optimiseCoding)) {
|
||||||
this._setBooleanOption('jpegOptimiseCoding', options.optimiseCoding);
|
this._setBooleanOption('jpegOptimiseCoding', options.optimiseCoding);
|
||||||
}
|
}
|
||||||
|
options.quantisationTable = is.number(options.quantizationTable) ? options.quantizationTable : options.quantisationTable;
|
||||||
|
if (is.defined(options.quantisationTable)) {
|
||||||
|
if (is.integer(options.quantisationTable) && is.inRange(options.quantisationTable, 0, 8)) {
|
||||||
|
this.options.jpegQuantisationTable = options.quantisationTable;
|
||||||
|
} else {
|
||||||
|
throw new Error('Invalid quantisation table (integer, 0-8) ' + options.quantisationTable);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return this._updateFormatOut('jpeg', options);
|
return this._updateFormatOut('jpeg', options);
|
||||||
}
|
}
|
||||||
|
@ -733,6 +733,7 @@ class PipelineWorker : public Nan::AsyncWorker {
|
|||||||
->set("interlace", baton->jpegProgressive)
|
->set("interlace", baton->jpegProgressive)
|
||||||
->set("no_subsample", baton->jpegChromaSubsampling == "4:4:4")
|
->set("no_subsample", baton->jpegChromaSubsampling == "4:4:4")
|
||||||
->set("trellis_quant", baton->jpegTrellisQuantisation)
|
->set("trellis_quant", baton->jpegTrellisQuantisation)
|
||||||
|
->set("quant_table", baton->jpegQuantisationTable)
|
||||||
->set("overshoot_deringing", baton->jpegOvershootDeringing)
|
->set("overshoot_deringing", baton->jpegOvershootDeringing)
|
||||||
->set("optimize_scans", baton->jpegOptimiseScans)
|
->set("optimize_scans", baton->jpegOptimiseScans)
|
||||||
->set("optimize_coding", baton->jpegOptimiseCoding)));
|
->set("optimize_coding", baton->jpegOptimiseCoding)));
|
||||||
@ -848,6 +849,7 @@ class PipelineWorker : public Nan::AsyncWorker {
|
|||||||
->set("interlace", baton->jpegProgressive)
|
->set("interlace", baton->jpegProgressive)
|
||||||
->set("no_subsample", baton->jpegChromaSubsampling == "4:4:4")
|
->set("no_subsample", baton->jpegChromaSubsampling == "4:4:4")
|
||||||
->set("trellis_quant", baton->jpegTrellisQuantisation)
|
->set("trellis_quant", baton->jpegTrellisQuantisation)
|
||||||
|
->set("quant_table", baton->jpegQuantisationTable)
|
||||||
->set("overshoot_deringing", baton->jpegOvershootDeringing)
|
->set("overshoot_deringing", baton->jpegOvershootDeringing)
|
||||||
->set("optimize_scans", baton->jpegOptimiseScans)
|
->set("optimize_scans", baton->jpegOptimiseScans)
|
||||||
->set("optimize_coding", baton->jpegOptimiseCoding));
|
->set("optimize_coding", baton->jpegOptimiseCoding));
|
||||||
@ -927,6 +929,7 @@ class PipelineWorker : public Nan::AsyncWorker {
|
|||||||
{"interlace", baton->jpegProgressive ? "TRUE" : "FALSE"},
|
{"interlace", baton->jpegProgressive ? "TRUE" : "FALSE"},
|
||||||
{"no_subsample", baton->jpegChromaSubsampling == "4:4:4" ? "TRUE": "FALSE"},
|
{"no_subsample", baton->jpegChromaSubsampling == "4:4:4" ? "TRUE": "FALSE"},
|
||||||
{"trellis_quant", baton->jpegTrellisQuantisation ? "TRUE" : "FALSE"},
|
{"trellis_quant", baton->jpegTrellisQuantisation ? "TRUE" : "FALSE"},
|
||||||
|
{"quant_table", std::to_string(baton->jpegQuantisationTable)},
|
||||||
{"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", baton->jpegOptimiseCoding ? "TRUE": "FALSE"}
|
{"optimize_coding", baton->jpegOptimiseCoding ? "TRUE": "FALSE"}
|
||||||
@ -1266,6 +1269,7 @@ NAN_METHOD(pipeline) {
|
|||||||
baton->jpegProgressive = AttrTo<bool>(options, "jpegProgressive");
|
baton->jpegProgressive = AttrTo<bool>(options, "jpegProgressive");
|
||||||
baton->jpegChromaSubsampling = AttrAsStr(options, "jpegChromaSubsampling");
|
baton->jpegChromaSubsampling = AttrAsStr(options, "jpegChromaSubsampling");
|
||||||
baton->jpegTrellisQuantisation = AttrTo<bool>(options, "jpegTrellisQuantisation");
|
baton->jpegTrellisQuantisation = AttrTo<bool>(options, "jpegTrellisQuantisation");
|
||||||
|
baton->jpegQuantisationTable = AttrTo<uint32_t>(options, "jpegQuantisationTable");
|
||||||
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->jpegOptimiseCoding = AttrTo<bool>(options, "jpegOptimiseCoding");
|
||||||
|
@ -102,6 +102,7 @@ struct PipelineBaton {
|
|||||||
bool jpegProgressive;
|
bool jpegProgressive;
|
||||||
std::string jpegChromaSubsampling;
|
std::string jpegChromaSubsampling;
|
||||||
bool jpegTrellisQuantisation;
|
bool jpegTrellisQuantisation;
|
||||||
|
int jpegQuantisationTable;
|
||||||
bool jpegOvershootDeringing;
|
bool jpegOvershootDeringing;
|
||||||
bool jpegOptimiseScans;
|
bool jpegOptimiseScans;
|
||||||
bool jpegOptimiseCoding;
|
bool jpegOptimiseCoding;
|
||||||
@ -188,6 +189,7 @@ struct PipelineBaton {
|
|||||||
jpegProgressive(false),
|
jpegProgressive(false),
|
||||||
jpegChromaSubsampling("4:2:0"),
|
jpegChromaSubsampling("4:2:0"),
|
||||||
jpegTrellisQuantisation(false),
|
jpegTrellisQuantisation(false),
|
||||||
|
jpegQuantisationTable(0),
|
||||||
jpegOvershootDeringing(false),
|
jpegOvershootDeringing(false),
|
||||||
jpegOptimiseScans(false),
|
jpegOptimiseScans(false),
|
||||||
jpegOptimiseCoding(true),
|
jpegOptimiseCoding(true),
|
||||||
|
@ -389,6 +389,16 @@ describe('Input/output', function () {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('Invalid JPEG quantisation table', function () {
|
||||||
|
[-1, 88.2, 'test'].forEach(function (table) {
|
||||||
|
it(table.toString(), function () {
|
||||||
|
assert.throws(function () {
|
||||||
|
sharp().jpeg({ quantisationTable: table });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('Progressive JPEG image', function (done) {
|
it('Progressive JPEG image', function (done) {
|
||||||
sharp(fixtures.inputJpg)
|
sharp(fixtures.inputJpg)
|
||||||
.resize(320, 240)
|
.resize(320, 240)
|
||||||
@ -856,6 +866,37 @@ describe('Input/output', function () {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('Specifying quantisation table provides different JPEG', function (done) {
|
||||||
|
// First generate with default quantisation table
|
||||||
|
sharp(fixtures.inputJpg)
|
||||||
|
.resize(320, 240)
|
||||||
|
.jpeg({ optimiseCoding: false })
|
||||||
|
.toBuffer(function (err, withDefaultQuantisationTable, withInfo) {
|
||||||
|
if (err) throw err;
|
||||||
|
assert.strictEqual(true, withDefaultQuantisationTable.length > 0);
|
||||||
|
assert.strictEqual(withDefaultQuantisationTable.length, withInfo.size);
|
||||||
|
assert.strictEqual('jpeg', withInfo.format);
|
||||||
|
assert.strictEqual(320, withInfo.width);
|
||||||
|
assert.strictEqual(240, withInfo.height);
|
||||||
|
// Then generate with different quantisation table
|
||||||
|
sharp(fixtures.inputJpg)
|
||||||
|
.resize(320, 240)
|
||||||
|
.jpeg({ optimiseCoding: false, quantisationTable: 3 })
|
||||||
|
.toBuffer(function (err, withQuantTable3, withoutInfo) {
|
||||||
|
if (err) throw err;
|
||||||
|
assert.strictEqual(true, withQuantTable3.length > 0);
|
||||||
|
assert.strictEqual(withQuantTable3.length, withoutInfo.size);
|
||||||
|
assert.strictEqual('jpeg', withoutInfo.format);
|
||||||
|
assert.strictEqual(320, withoutInfo.width);
|
||||||
|
assert.strictEqual(240, withoutInfo.height);
|
||||||
|
|
||||||
|
// Verify image is same (as mozjpeg may not be present) size or less
|
||||||
|
assert.strictEqual(true, withQuantTable3.length <= withDefaultQuantisationTable.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)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user