Nothing
Nothing

Reputation: 78

Saved Media file has unsupported type using sharp in nodejs

I am trying to fetch the image from a remote url, resize it and save it to my computer locally. For this, i am using got library which returns a buffer. i take that buffer and resize the image and then store it in a file using sharp js. Here is my code:

module.exports =  async function resize() {
    const url = 'https://images.unsplash.com/photo-1636838123974-c94c6904b97a?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=687&q=80';

const readStream = await got(url).buffer();
const resizedBuffer = await sharp(readStream).resize(200, 200);
const storedValue = await resizedBuffer.toFile('output');
console.log("resized buffer", resizedBuffer);
console.log("-----------------------------------------------------------")
console.log(storedValue);
return "ok";

}

The console.log(storedValue) gives:

{
  format: 'jpeg',
  width: 200,
  height: 200,
  channels: 3,
  premultiplied: false,
  size: 5432
}

However, the output image is not shown as a jpeg by my windows machine. It shows like this: the file name output is the output

The filename output is the output from the code above. hacker is a random unused jpg image. specifying output.jpg to the file does give me a jpg image but the input can be any format jpg, png, gif so, i need to have the same extension as the media.

Upvotes: 1

Views: 1396

Answers (1)

Tanner Dolby
Tanner Dolby

Reputation: 4421

Sharp generates the image without an extension because you don't supply one. The first argument for toFile is fileOut, which represents the path to write the image data to. Since the string "output" doesn't have an extension specified, the image is generated without an extension as that is what we tell it to do.

If you utilize the format parameter of your user defined resize function, then you can supply a media extension in the function calls and the generated images will have the expected extension types.

const BASE_URL = "https://images.unsplash.com/";
const imgUrl = "photo-1636838123974-c94c6904b97a?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=687&q=80";
const fullUrl = `${BASE_URL}${imgUrl}`;

async function resize(url, format, width, height, filename) {
    const readStream = await got(url).buffer();
    const resizedBuffer = await sharp(readStream).resize(width, height);
    const storedValue = await resizedBuffer.toFile(`${filename}.${format}`);
    console.log("resized buffer", resizedBuffer);
    console.log("-----------------------------------------------------------")
    console.log(storedValue);
    return "ok";
}

resize(fullUrl, "png", 200, 200, "foo");
// generates foo.png (image of 3 croissants on a plate)

resize(fullUrl, "jpg", 200, 200, "bar");
// generates bar.jpeg

Or if you choose to not define a format parameter for the resize function, you can grab the image extension from the resizedBuffer. I looked through the output and found options contains a key tiffCompression which defines the media extension type that Sharp received from the readStream.

const BASE_URL = "https://images.unsplash.com/";
const imgUrl = "photo-1636838123974-c94c6904b97a?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=687&q=80";
const fullUrl = `${BASE_URL}${imgUrl}`;

async function resize(url, width, height, filename) {
    const readStream = await got(url).buffer();
    const resizedBuffer = await sharp(readStream).resize(width, height);
    const format = resizedBuffer["options"]["tiffCompression"];
    const storedValue = await resizedBuffer.toFile(`${filename}.${format}`);
    console.log("resized buffer", resizedBuffer);
    console.log("-----------------------------------------------------------")
    console.log(storedValue);
    return "ok";
}

resize(fullUrl, 200, 200, "foo");
// generates foo.jpeg (image of 3 croissants on a plate)

Upvotes: 1

Related Questions