mirror of
https://github.com/lovell/sharp.git
synced 2025-07-09 10:30:15 +02:00
Add ignoreIcc input option to ignore embedded ICC profile
This commit is contained in:
parent
a2988c9edc
commit
42d2f07e44
@ -18,6 +18,8 @@ Requires libvips v8.14.0
|
||||
|
||||
* Prefer integer (un)premultiply for faster resizing of RGBA images.
|
||||
|
||||
* Add `ignoreIcc` input option to ignore embedded ICC profile.
|
||||
|
||||
* Allow use of GPS (IFD3) EXIF metadata.
|
||||
[#2767](https://github.com/lovell/sharp/issues/2767)
|
||||
|
||||
|
@ -126,6 +126,7 @@ const debuglog = util.debuglog('sharp');
|
||||
* @param {boolean} [options.unlimited=false] - Set this to `true` to remove safety features that help prevent memory exhaustion (JPEG, PNG, SVG, HEIF).
|
||||
* @param {boolean} [options.sequentialRead=true] - Set this to `false` to use random access rather than sequential read. Some operations will do this automatically.
|
||||
* @param {number} [options.density=72] - number representing the DPI for vector images in the range 1 to 100000.
|
||||
* @param {number} [options.ignoreIcc=false] - should the embedded ICC profile, if any, be ignored.
|
||||
* @param {number} [options.pages=1] - number of pages to extract for multi-page input (GIF, WebP, AVIF, TIFF, PDF), use -1 for all pages.
|
||||
* @param {number} [options.page=0] - page number to start extracting from for multi-page input (GIF, WebP, AVIF, TIFF, PDF), zero based.
|
||||
* @param {number} [options.subifd=-1] - subIFD (Sub Image File Directory) to extract for OME-TIFF, defaults to main image.
|
||||
|
2
lib/index.d.ts
vendored
2
lib/index.d.ts
vendored
@ -814,6 +814,8 @@ declare namespace sharp {
|
||||
sequentialRead?: boolean | undefined;
|
||||
/** Number representing the DPI for vector images in the range 1 to 100000. (optional, default 72) */
|
||||
density?: number | undefined;
|
||||
/** Should the embedded ICC profile, if any, be ignored. */
|
||||
ignoreIcc?: boolean | undefined;
|
||||
/** Number of pages to extract for multi-page input (GIF, TIFF, PDF), use -1 for all pages */
|
||||
pages?: number | undefined;
|
||||
/** Page number to start extracting from for multi-page input (GIF, TIFF, PDF), zero based. (optional, default 0) */
|
||||
|
15
lib/input.js
15
lib/input.js
@ -21,9 +21,9 @@ const align = {
|
||||
* @private
|
||||
*/
|
||||
function _inputOptionsFromObject (obj) {
|
||||
const { raw, density, limitInputPixels, unlimited, sequentialRead, failOn, failOnError, animated, page, pages, subifd } = obj;
|
||||
return [raw, density, limitInputPixels, unlimited, sequentialRead, failOn, failOnError, animated, page, pages, subifd].some(is.defined)
|
||||
? { raw, density, limitInputPixels, unlimited, sequentialRead, failOn, failOnError, animated, page, pages, subifd }
|
||||
const { raw, density, limitInputPixels, ignoreIcc, unlimited, sequentialRead, failOn, failOnError, animated, page, pages, subifd } = obj;
|
||||
return [raw, density, limitInputPixels, ignoreIcc, unlimited, sequentialRead, failOn, failOnError, animated, page, pages, subifd].some(is.defined)
|
||||
? { raw, density, limitInputPixels, ignoreIcc, unlimited, sequentialRead, failOn, failOnError, animated, page, pages, subifd }
|
||||
: undefined;
|
||||
}
|
||||
|
||||
@ -35,6 +35,7 @@ function _createInputDescriptor (input, inputOptions, containerOptions) {
|
||||
const inputDescriptor = {
|
||||
failOn: 'warning',
|
||||
limitInputPixels: Math.pow(0x3FFF, 2),
|
||||
ignoreIcc: false,
|
||||
unlimited: false,
|
||||
sequentialRead: true
|
||||
};
|
||||
@ -97,6 +98,14 @@ function _createInputDescriptor (input, inputOptions, containerOptions) {
|
||||
throw is.invalidParameterError('density', 'number between 1 and 100000', inputOptions.density);
|
||||
}
|
||||
}
|
||||
// Ignore embeddded ICC profile
|
||||
if (is.defined(inputOptions.ignoreIcc)) {
|
||||
if (is.bool(inputOptions.ignoreIcc)) {
|
||||
inputDescriptor.ignoreIcc = inputOptions.ignoreIcc;
|
||||
} else {
|
||||
throw is.invalidParameterError('ignoreIcc', 'boolean', inputOptions.ignoreIcc);
|
||||
}
|
||||
}
|
||||
// limitInputPixels
|
||||
if (is.defined(inputOptions.limitInputPixels)) {
|
||||
if (is.bool(inputOptions.limitInputPixels)) {
|
||||
|
@ -103,6 +103,10 @@ namespace sharp {
|
||||
if (HasAttr(input, "density")) {
|
||||
descriptor->density = AttrAsDouble(input, "density");
|
||||
}
|
||||
// Should we ignore any embedded ICC profile
|
||||
if (HasAttr(input, "ignoreIcc")) {
|
||||
descriptor->ignoreIcc = AttrAsBool(input, "ignoreIcc");
|
||||
}
|
||||
// Raw pixel input
|
||||
if (HasAttr(input, "rawChannels")) {
|
||||
descriptor->rawDepth = AttrAsEnum<VipsBandFormat>(input, "rawDepth", VIPS_TYPE_BAND_FORMAT);
|
||||
|
@ -55,6 +55,7 @@ namespace sharp {
|
||||
size_t bufferLength;
|
||||
bool isBuffer;
|
||||
double density;
|
||||
bool ignoreIcc;
|
||||
VipsBandFormat rawDepth;
|
||||
int rawChannels;
|
||||
int rawWidth;
|
||||
@ -93,6 +94,7 @@ namespace sharp {
|
||||
bufferLength(0),
|
||||
isBuffer(FALSE),
|
||||
density(72.0),
|
||||
ignoreIcc(FALSE),
|
||||
rawDepth(VIPS_FORMAT_UCHAR),
|
||||
rawChannels(0),
|
||||
rawWidth(0),
|
||||
|
@ -320,7 +320,8 @@ class PipelineWorker : public Napi::AsyncWorker {
|
||||
if (
|
||||
sharp::HasProfile(image) &&
|
||||
image.interpretation() != VIPS_INTERPRETATION_LABS &&
|
||||
image.interpretation() != VIPS_INTERPRETATION_GREY16
|
||||
image.interpretation() != VIPS_INTERPRETATION_GREY16 &&
|
||||
!baton->input->ignoreIcc
|
||||
) {
|
||||
// Convert to sRGB/P3 using embedded profile
|
||||
try {
|
||||
@ -329,7 +330,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
||||
->set("depth", image.interpretation() == VIPS_INTERPRETATION_RGB16 ? 16 : 8)
|
||||
->set("intent", VIPS_INTENT_PERCEPTUAL));
|
||||
} catch(...) {
|
||||
// Ignore failure of embedded profile
|
||||
sharp::VipsWarningCallback(nullptr, G_LOG_LEVEL_WARNING, "Invalid embedded profile", nullptr);
|
||||
}
|
||||
} else if (image.interpretation() == VIPS_INTERPRETATION_CMYK) {
|
||||
image = image.icc_transform(processingProfile, VImage::option()
|
||||
|
@ -652,6 +652,7 @@ describe('Input/output', function () {
|
||||
it('toFormat=JPEG takes precedence over WebP extension', function (done) {
|
||||
const outputWebP = fixtures.path('output.webp');
|
||||
sharp(fixtures.inputPng)
|
||||
.resize(8)
|
||||
.jpeg()
|
||||
.toFile(outputWebP, function (err, info) {
|
||||
if (err) throw err;
|
||||
@ -662,6 +663,7 @@ describe('Input/output', function () {
|
||||
|
||||
it('toFormat=WebP takes precedence over JPEG extension', function (done) {
|
||||
sharp(fixtures.inputPng)
|
||||
.resize(8)
|
||||
.webp()
|
||||
.toFile(outputJpg, function (err, info) {
|
||||
if (err) throw err;
|
||||
@ -697,6 +699,27 @@ describe('Input/output', function () {
|
||||
});
|
||||
});
|
||||
|
||||
it('can ignore ICC profile', async () => {
|
||||
const [r1, g1, b1] = await sharp(fixtures.inputJpgWithPortraitExif5, { ignoreIcc: true })
|
||||
.extract({ width: 1, height: 1, top: 16, left: 16 })
|
||||
.raw()
|
||||
.toBuffer();
|
||||
|
||||
const [r2, g2, b2] = await sharp(fixtures.inputJpgWithPortraitExif5, { ignoreIcc: false })
|
||||
.extract({ width: 1, height: 1, top: 16, left: 16 })
|
||||
.raw()
|
||||
.toBuffer();
|
||||
|
||||
assert.deepStrictEqual({ r1, g1, b1, r2, g2, b2 }, {
|
||||
r1: 60,
|
||||
r2: 77,
|
||||
g1: 54,
|
||||
g2: 69,
|
||||
b1: 20,
|
||||
b2: 25
|
||||
});
|
||||
});
|
||||
|
||||
describe('Switch off safety limits for certain formats', () => {
|
||||
it('Valid', () => {
|
||||
assert.doesNotThrow(() => {
|
||||
@ -816,6 +839,11 @@ describe('Input/output', function () {
|
||||
sharp({ density: 'zoinks' });
|
||||
}, /Expected number between 1 and 100000 for density but received zoinks of type string/);
|
||||
});
|
||||
it('Invalid ignoreIcc: string', function () {
|
||||
assert.throws(function () {
|
||||
sharp({ ignoreIcc: 'zoinks' });
|
||||
}, /Expected boolean for ignoreIcc but received zoinks of type string/);
|
||||
});
|
||||
it('Setting animated property updates pages property', function () {
|
||||
assert.strictEqual(sharp({ animated: false }).options.input.pages, 1);
|
||||
assert.strictEqual(sharp({ animated: true }).options.input.pages, -1);
|
||||
|
Loading…
x
Reference in New Issue
Block a user