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.
|
* 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.
|
* Allow use of GPS (IFD3) EXIF metadata.
|
||||||
[#2767](https://github.com/lovell/sharp/issues/2767)
|
[#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.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 {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.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.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.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.
|
* @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;
|
sequentialRead?: boolean | undefined;
|
||||||
/** Number representing the DPI for vector images in the range 1 to 100000. (optional, default 72) */
|
/** Number representing the DPI for vector images in the range 1 to 100000. (optional, default 72) */
|
||||||
density?: number | undefined;
|
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 */
|
/** Number of pages to extract for multi-page input (GIF, TIFF, PDF), use -1 for all pages */
|
||||||
pages?: number | undefined;
|
pages?: number | undefined;
|
||||||
/** Page number to start extracting from for multi-page input (GIF, TIFF, PDF), zero based. (optional, default 0) */
|
/** 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
|
* @private
|
||||||
*/
|
*/
|
||||||
function _inputOptionsFromObject (obj) {
|
function _inputOptionsFromObject (obj) {
|
||||||
const { raw, density, limitInputPixels, unlimited, sequentialRead, failOn, failOnError, animated, page, pages, subifd } = obj;
|
const { raw, density, limitInputPixels, ignoreIcc, unlimited, sequentialRead, failOn, failOnError, animated, page, pages, subifd } = obj;
|
||||||
return [raw, density, limitInputPixels, unlimited, sequentialRead, failOn, failOnError, animated, page, pages, subifd].some(is.defined)
|
return [raw, density, limitInputPixels, ignoreIcc, unlimited, sequentialRead, failOn, failOnError, animated, page, pages, subifd].some(is.defined)
|
||||||
? { raw, density, limitInputPixels, unlimited, sequentialRead, failOn, failOnError, animated, page, pages, subifd }
|
? { raw, density, limitInputPixels, ignoreIcc, unlimited, sequentialRead, failOn, failOnError, animated, page, pages, subifd }
|
||||||
: undefined;
|
: undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -35,6 +35,7 @@ function _createInputDescriptor (input, inputOptions, containerOptions) {
|
|||||||
const inputDescriptor = {
|
const inputDescriptor = {
|
||||||
failOn: 'warning',
|
failOn: 'warning',
|
||||||
limitInputPixels: Math.pow(0x3FFF, 2),
|
limitInputPixels: Math.pow(0x3FFF, 2),
|
||||||
|
ignoreIcc: false,
|
||||||
unlimited: false,
|
unlimited: false,
|
||||||
sequentialRead: true
|
sequentialRead: true
|
||||||
};
|
};
|
||||||
@ -97,6 +98,14 @@ function _createInputDescriptor (input, inputOptions, containerOptions) {
|
|||||||
throw is.invalidParameterError('density', 'number between 1 and 100000', inputOptions.density);
|
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
|
// limitInputPixels
|
||||||
if (is.defined(inputOptions.limitInputPixels)) {
|
if (is.defined(inputOptions.limitInputPixels)) {
|
||||||
if (is.bool(inputOptions.limitInputPixels)) {
|
if (is.bool(inputOptions.limitInputPixels)) {
|
||||||
|
@ -103,6 +103,10 @@ namespace sharp {
|
|||||||
if (HasAttr(input, "density")) {
|
if (HasAttr(input, "density")) {
|
||||||
descriptor->density = AttrAsDouble(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
|
// Raw pixel input
|
||||||
if (HasAttr(input, "rawChannels")) {
|
if (HasAttr(input, "rawChannels")) {
|
||||||
descriptor->rawDepth = AttrAsEnum<VipsBandFormat>(input, "rawDepth", VIPS_TYPE_BAND_FORMAT);
|
descriptor->rawDepth = AttrAsEnum<VipsBandFormat>(input, "rawDepth", VIPS_TYPE_BAND_FORMAT);
|
||||||
|
@ -55,6 +55,7 @@ namespace sharp {
|
|||||||
size_t bufferLength;
|
size_t bufferLength;
|
||||||
bool isBuffer;
|
bool isBuffer;
|
||||||
double density;
|
double density;
|
||||||
|
bool ignoreIcc;
|
||||||
VipsBandFormat rawDepth;
|
VipsBandFormat rawDepth;
|
||||||
int rawChannels;
|
int rawChannels;
|
||||||
int rawWidth;
|
int rawWidth;
|
||||||
@ -93,6 +94,7 @@ namespace sharp {
|
|||||||
bufferLength(0),
|
bufferLength(0),
|
||||||
isBuffer(FALSE),
|
isBuffer(FALSE),
|
||||||
density(72.0),
|
density(72.0),
|
||||||
|
ignoreIcc(FALSE),
|
||||||
rawDepth(VIPS_FORMAT_UCHAR),
|
rawDepth(VIPS_FORMAT_UCHAR),
|
||||||
rawChannels(0),
|
rawChannels(0),
|
||||||
rawWidth(0),
|
rawWidth(0),
|
||||||
|
@ -320,7 +320,8 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|||||||
if (
|
if (
|
||||||
sharp::HasProfile(image) &&
|
sharp::HasProfile(image) &&
|
||||||
image.interpretation() != VIPS_INTERPRETATION_LABS &&
|
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
|
// Convert to sRGB/P3 using embedded profile
|
||||||
try {
|
try {
|
||||||
@ -329,7 +330,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|||||||
->set("depth", image.interpretation() == VIPS_INTERPRETATION_RGB16 ? 16 : 8)
|
->set("depth", image.interpretation() == VIPS_INTERPRETATION_RGB16 ? 16 : 8)
|
||||||
->set("intent", VIPS_INTENT_PERCEPTUAL));
|
->set("intent", VIPS_INTENT_PERCEPTUAL));
|
||||||
} catch(...) {
|
} catch(...) {
|
||||||
// Ignore failure of embedded profile
|
sharp::VipsWarningCallback(nullptr, G_LOG_LEVEL_WARNING, "Invalid embedded profile", nullptr);
|
||||||
}
|
}
|
||||||
} else if (image.interpretation() == VIPS_INTERPRETATION_CMYK) {
|
} else if (image.interpretation() == VIPS_INTERPRETATION_CMYK) {
|
||||||
image = image.icc_transform(processingProfile, VImage::option()
|
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) {
|
it('toFormat=JPEG takes precedence over WebP extension', function (done) {
|
||||||
const outputWebP = fixtures.path('output.webp');
|
const outputWebP = fixtures.path('output.webp');
|
||||||
sharp(fixtures.inputPng)
|
sharp(fixtures.inputPng)
|
||||||
|
.resize(8)
|
||||||
.jpeg()
|
.jpeg()
|
||||||
.toFile(outputWebP, function (err, info) {
|
.toFile(outputWebP, function (err, info) {
|
||||||
if (err) throw err;
|
if (err) throw err;
|
||||||
@ -662,6 +663,7 @@ describe('Input/output', function () {
|
|||||||
|
|
||||||
it('toFormat=WebP takes precedence over JPEG extension', function (done) {
|
it('toFormat=WebP takes precedence over JPEG extension', function (done) {
|
||||||
sharp(fixtures.inputPng)
|
sharp(fixtures.inputPng)
|
||||||
|
.resize(8)
|
||||||
.webp()
|
.webp()
|
||||||
.toFile(outputJpg, function (err, info) {
|
.toFile(outputJpg, function (err, info) {
|
||||||
if (err) throw err;
|
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', () => {
|
describe('Switch off safety limits for certain formats', () => {
|
||||||
it('Valid', () => {
|
it('Valid', () => {
|
||||||
assert.doesNotThrow(() => {
|
assert.doesNotThrow(() => {
|
||||||
@ -816,6 +839,11 @@ describe('Input/output', function () {
|
|||||||
sharp({ density: 'zoinks' });
|
sharp({ density: 'zoinks' });
|
||||||
}, /Expected number between 1 and 100000 for density but received zoinks of type string/);
|
}, /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 () {
|
it('Setting animated property updates pages property', function () {
|
||||||
assert.strictEqual(sharp({ animated: false }).options.input.pages, 1);
|
assert.strictEqual(sharp({ animated: false }).options.input.pages, 1);
|
||||||
assert.strictEqual(sharp({ animated: true }).options.input.pages, -1);
|
assert.strictEqual(sharp({ animated: true }).options.input.pages, -1);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user