Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Is it possible to support icc of type Buffer in the withMetadata method? #3704

Open
rambo-panda opened this issue Jun 21, 2023 · 2 comments
Open

Comments

@rambo-panda
Copy link

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

@lovell
Copy link
Owner

lovell commented Jun 21, 2023

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.

@rambo-panda
Copy link
Author

rambo-panda commented Jul 26, 2023

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);
};

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants