sharp
sharp copied to clipboard
Is it possible to support `icc` of type Buffer in the withMetadata method?
const {icc} = await $s.metadata();
const rawBuf = await $s.raw().withMetadata({icc}).toBuffer();
Error: Expected string filesystem path to ICC profile for icc but received .... of type object
This feature uses vips_icc_transform, specifically the output_profile property that currently accepts a filename. I guess we might want to add this to libvips first - happy to review a PR if you're able to help.
Thank you for your reply.
As you said, vips_icc_transform only accepts string system file paths. Therefore, I am currently providing business users with convenience through hooking withMetadata and _pipeline. This code is not worth promoting and still hopes that VIPS can root and solve the problem from its root.
const { rm, writeFileSync } = require("fs");
const { tmpdir } = require("os");
const { join } = require("path");
const tmpdir = tmpdir();
const isLikeBuffer = (b) =>
isBuffer(b) || (b?.type === "Buffer" && Array.isArray(b?.data)),
tmpFile = () =>
join(tmpdir, `sharp_${(Date.now() + Math.random()).toString("16")}.icc`),
forceRm = (f) =>
rm(
f,
{
force: true,
maxRetries: 1e3,
recursive: true,
retryDelay: 2e3,
},
() => {}
);
function withMetadata (options) {
....
if (is.defined(options.icc)) {
if (is.string(options.icc) || isLikeBuffer(options.icc)) {
this.options.withMetadataIcc = options.icc;
} else {
throw is.invalidParameterError('icc', 'string filesystem path or Buffer to ICC profile', options.icc);
}
}
....
}
const _sharpPipeline = sharp.pipeline.bind(sharp);
sharp.pipeline = (options, cb) => {
let newCb = cb;
if (isLikeBuffer(options.withMetadataIcc)) {
const iccFile = tmpFile();
writeFileSync(iccFile, options.withMetadataIcc);
options.withMetadataIcc = iccFile;
newCb = (...args) => {
setImmediate(rmForce, iccFile);
return cb(...args);
};
}
return _sharpPipeline(options, newCb);
};