javascriptnode.jsjsonazure-functionsjimp

how to embed an image in a JSON response


I'm using Jimp to read in a JSON string that looks like this:

enter image description here

As you can see the image node is a base64-encoded JPEG.

I'm able to succesfully convert it to a TIFF and save it:

  Jimp.read(Buffer.from(inputImage, "base64"), function(err, image) {
    image.getBuffer(Jimp.MIME_TIFF, function(error, tiff) {
    context.bindings.outputBlob = tiff
    ...}

However, when I attempted to embed the tiff inside of a JSON object, the TIFF gets all garbled up:

  const response = {
    image: tiff.toString('base64'),
    correlation: correlation
  };

  context.bindings.outputBlob = response;

enter image description here

Here's the full code:

const Jimp = require("jimp");

module.exports = function(context, myBlob) {
  const correlation = context.bindings.inputBlob.correlation;
  const inputImage = context.bindings.inputBlob.image;
  const imageName = context.bindings.inputBlob.imageName;

  context.log(
    correlation + "Attempting to convert this image to a tiff: " + imageName
  );
  Jimp.read(Buffer.from(inputImage, "base64"), function(err, image) {
    image.getBuffer(Jimp.MIME_TIFF, function(error, tiff) {
      const response = {
        image: tiff.toString('base64'),
        correlation: correlation
      };

      context.bindings.outputBlob = response;
      context.log(
        correlation + "Succesfully converted " + imageName + " to tiff."
      );
      context.done();
    });
  });
};

How do we embed the tiff inside of a JSON payload?

If this output is non-negotiable, how would I render the tiff from the saved payload?


Solution

  • Well since you confirmed you are looking for output with context.res here is my working sample.. note that there is a maximum response size, so you can't return every image/file the way I am returning the image here

    const Jimp = require('jimp')
    
    module.exports = async function (context, req)
    {
        let response = {}
    
        try
        {
            let url = 'https://noahwriting.com/wp-content/uploads/2018/06/APPLE-300x286.jpg'
    
            //call function to download and resize image
            response = await resizeImage(url)
    
        }
        catch (err)
        {
            response.type = 'application/json'
            if (err.response == undefined)
            {
                context.log(err)
                response.status = 500
                response.data = err
            }
            else
            {
                response.data = err.response.data
                response.status = err.response.status
                context.log(response)
            }
        }
    
        //response
        context.res =
        {
            headers: { 'Content-Type': `${response.type}` },
            body: response.buf
        }
    }
    
    async function resizeImage(url)
    {
        //read image to buffer
        let image = await Jimp.read(url)
    
        //resize image
        image.resize(300, Jimp.AUTO)
    
        //save to buffer
        let image_buf = await image.getBufferAsync(image.getMIME())
    
        //image.getMIME() returns something like `image/jpeg` which is a valid Content-Type for responses.
        return { 'buf': image_buf, 'type': image.getMIME() }
    }
    

    (Offtopic but I saw that you are using blob storage so..) if you plan on storing photos/files/anything in Azure Blob Storage and you want to retrieve them in some systematic way you will find out very fast that you can't query the storage and you have to deal with ugly XML. My work around to avoid this way to create a function that stores photos/files in Blob Storage but then saves the url path to the file along with the file name and any other attributes to a mongo storage. So then I can make super fast queries to retrieve an array of links, which point to the respective files.