4

I am currently in the situation of migrating an "old" ASP MVC project to new Core MVC (1.1), hurdling from one breaking change to the next. I am now stuck at topic "image processing", as System.Web.Helpers.WebImage was removed. I looked at several possible solutions and liked the proposed way via Microsoft.AspNetCore.NodeServices described in this comment!.

It all works well when using the sample script and passing in file names. I have spent some hours now to try and get this same thing to work passing a byte stream as I read image data from DB and wanted to directly pipe it through to the JS.

The JS using JIMP library:

var jimp = require("jimp");

module.exports = function (result, source, mimeType, maxWidth, maxHeight) {
// Invoke the 'jimp' NPM module, and have it pipe the resulting image data back to .NET
jimp.read(source.buffer).then(function (file) {
    var width = maxWidth || jimp.AUTO;
    var height = maxHeight || jimp.AUTO;
    file.resize(maxWidth, height)
         .getBuffer(mimeType, function (err, buffer) {
             var stream = result.stream;
             stream.write(buffer);
             stream.end();
         });
    }).catch(function (err) {
    console.error(err);
   });
};

The action on my image controller

var imageStream = await _nodeServices.InvokeAsync<Stream>(
                "Node/resizeImageBuffer",
                bild.BildDaten.Daten, // byte[]
                bild.Mimetype, // "image/jpeg"
                targetsize, // e.g. 400
                targetsize);

When I call it like this, my byte[] gets serialized to string and does not work as a buffer in node.

When I try to wrap in a stream, JS is not even executed as it breaks on serializing the parameter. So like this:

var imageStream = await _nodeServices.InvokeAsync<Stream>(
            "Node/resizeImageBuffer",
            new MemoryStream(bild.BildDaten.Daten), // MemoryStream
            bild.Mimetype, // "image/jpeg"
            targetsize, // e.g. 400
            targetsize);

it throws

JsonSerializationException: Error getting value from 'ReadTimeout' on 'System.IO.FileStream'.

What I do net get, the result stream from Node to C# works and is a valid System.IO.Stream object, but the same does not work as an output parameter... Perhaps somebody has an idea?

AndreasF
  • 41
  • 1

1 Answers1

2

What I ended up doing was using System.BitConverter.ToString() to convert the image byte[] to its hex string representation and passing that to the node script.

var byteString = System.BitConverter.ToString(image.Bytes);
var img = await _nodeServices.InvokeAsync<Stream>(
    "./NodeServices/thumbnail",
     "image/jpeg",
     byteString,
     width,
     height
);

Then inside the node script, I parsed the hex string back into a byte array, created a buffer with that, and was able to then pass the buffer off to jimp.

const jimp = require('jimp')

module.exports = function (result, mimeType, bytes, maxWidth, maxHeight) {
   const parsedBytes = bytes.split('-').map(e => parseInt(`0x${e}`))
   const buffer = Buffer.from(parsedBytes)

   jimp.read(buffer)
       .then((img) => {
           var width = maxWidth || jimp.AUTO
           var height = maxHeight || jimp.AUTO
           img.resize(width, height)
              .getBuffer(mimeType, function (err, buffer) {
                  const stream = result.stream
                  stream.write(buffer)
                  stream.end()
              })
    })
    .catch(err => {
        console.error(err)
    })
}

I'm hoping to discover a way to just pass the byte[] array itself to the node script, but for now I'm just happy this works.

Caleb Bergman
  • 858
  • 1
  • 8
  • 18