3

I am seeing the following error when trying to extract an image's metadata information with the Sharp module: "Input file contains unsupported image format".

This is only happening for certain signed image urls, particularly ones that contain xmp information in the metadata.

I am hoping someone can help me spot where the issue might be occurring in this code snippet.

Here is the exact code snippet I am using (insert the signed image URL where specified in the doStuff function to test):

const sharp = require("sharp");
const fs = require('fs');
const fetch = require('node-fetch');

async function storeUrlToLocal(sourceUrl) {
    const destPath = './';

    const request = {
        method: 'GET',
        encoding: null,
    };
    response = await fetch(sourceUrl, request);

    if (response.status >= 400)
        throw new Error(`Failed to fetch data from ${sourceUrl}, status returned = ${response.status}`);

    const localPath = `${destPath}test.png`;
    const fileStream = fs.createWriteStream(localPath);

    return new Promise((resolve, reject) => {
        response.body.pipe(fileStream);
        response.body.on("error", reject);
        response.body.on("end", async () => {
            const fileExists = fs.existsSync(localPath);
            console.log(`All the data in the file has been read ${localPath} = ${fileExists}`);
            resolve(localPath);
        });
        response.body.on("finish",() => {
            console.log('All writes are now complete.');
        });
    }).catch(error => {
        console.log(error);
    });
}

async function doStuff() {
    const localFilePath = await storeUrlToLocal('<INSERT_IMAGE_URL_HERE>');

    // Read image file and extract metadata
    let manipulator;
    let imageMetadata;
    try {
        manipulator = sharp(localFilePath, { limitInputPixels: 5000000000 });
        console.log('Manipulator = ', manipulator);
        imageMetadata = await manipulator.metadata();
        console.log("ImageMetadata = ", imageMetadata);
    } catch (error) {
        console.log(`Image Metadata Extraction Error: ${error.message}`);
        throw error;
    }
}

doStuff();

This code snippet above fails with the "Input file contains unsupported image format" on the line that extracts metadata (imageMetadata = await manipulator.metadata();)

So the strange thing is, I am able to properly extract the metadata (with no errors) with this same code if I add a short Sleep after this line: const fileStream = fs.createWriteStream(localPath);

So this code snippet (all I'm doing here is adding a short sleep after fs.createWriteSteam) allows the image metadata to be extracted without issue:

const sharp = require("sharp");
const fs = require('fs');
const fetch = require('node-fetch');

async function storeUrlToLocal(sourceUrl) {
    const destPath = './';

    const request = {
        method: 'GET',
        encoding: null,
    };
    response = await fetch(sourceUrl, request);

    if (response.status >= 400)
        throw new Error(`Failed to fetch data from ${sourceUrl}, status returned = ${response.status}`);

    const localPath = `${destPath}test.png`;
    const fileStream = fs.createWriteStream(localPath);

    function sleep(ms) {
        return new Promise(resolve => setTimeout(resolve, ms));
    }
    await sleep(1000);

    return new Promise((resolve, reject) => {
        response.body.pipe(fileStream);
        response.body.on("error", reject);
        response.body.on("end", async () => {
            const fileExists = fs.existsSync(localPath);
            console.log(`All the data in the file has been read ${localPath} = ${fileExists}`);
            resolve(localPath);
        });
        response.body.on("finish",() => {
            console.log('All writes are now complete.');
        });
    }).catch(error => {
        console.log(error);
    });
}

async function doStuff() {
    const localFilePath = await storeUrlToLocal('<INSERT_IMAGE_URL_HERE>');

    // Read image file and extract metadata
    let manipulator;
    let imageMetadata;
    try {
        manipulator = sharp(localFilePath, { limitInputPixels: 5000000000 });
        console.log('Manipulator = ', manipulator);
        imageMetadata = await manipulator.metadata();
        console.log("ImageMetadata = ", imageMetadata);
    } catch (error) {
        console.log(`Image Metadata Extraction Error: ${error.message}`);
        throw error;
    }
}

doStuff();

Why would this Sleep resolve my issues? I don't see any asynchronous calls being run that I would need to be waiting for to complete. Perhaps fs.createWriteStream didn't have enough time to complete its operation? But I do not have the option to await the call to fs.createWriteStream, as it is not async.

AntonioGarcía
  • 1,140
  • 2
  • 15
  • 25

0 Answers0