watson-developer-cloud / node-sdk

:comet: Node.js library to access IBM Watson services.
https://www.npmjs.com/package/ibm-watson
Apache License 2.0
1.48k stars 669 forks source link

[visual-recognition] should accept Buffer objects when uploading images #333

Closed ammilanov closed 8 years ago

ammilanov commented 8 years ago

Feature request

The Visual Recognition library should be able to support Buffer objects for the 'classify' operation. So far only file ReadStreams are supported.

One should be able to something like that:

var buffer = getBufferWithImageDataSomehow();

visual_recognition.classify({
  images_file: buffer
}, function(err, res) {
    ....
});

My use case

Consider a file uploaded to a Node web application. Suppose you have the image data and you construct or get somehow a Buffer object containing the data. While storing the file onto the disk and creating a ReadStream is an option, it is somewhat complicated and a lot slower in term of performance.

Proposed solution

Remove the isStream limitation from the following file: https://github.com/watson-developer-cloud/node-sdk/blob/76998c9a340259aead2c0c4ef2807ddaa91fbf67/visual-recognition/v3.js#L55

Since the request library supports Buffers it should not be that hard. The only complication here is, that currently (version '2016-05-20') the Watson Visual Recognition API counts on the file extension submitted through the HTTP request and not on the MIME type to detect the image format.

So a sample call using request should look something like that:

let buffer = getBufferWithImageDataSomehow();
let fileExtension = detectFileExtension(buffer);

request({
  method: 'POST',
  url:  '.../v3/classify',
  gzip: true,
  qs: {
    api_key: apiKey,
    version: '2016-05-20'
  },
  formData: {
    images_file: {
      value: buffer,  // Here we pass the Buffer
      options: {
        filename: `image.${fileExtension}` // Passing file name with a proper
                                           //file extension is very imporant here!!
      }
    } 
   },
}, ...);

// Detect only ZIP, PNG and JPEG files because these are the only image
// formats supported by the Waston Visual Recogntion API
function detectFileExtension(buffer) {
  if (!Buffer.isBuffer(buffer)) {
    throw new Error('This is not a buffer!');
  }

  let signature = buffer.readUInt32BE();
  switch(signature) {
    case 0x504B0304:
    case 0x504B0506:
    case 0x504B0708:
      return 'zip';
    case 0x89504E47:
      return 'png';
    case 0xFFD8FFE0:
    case 0xFFD8FFE1:
    case 0xFFD8FFE8:
      return 'jpg';
    default:
      throw new Error('Unsupported file format');
  }
}
nfriedly commented 8 years ago

This should be fixed in v2.9.0, which will be published once the CI loop completes. I used a slight variation of your suggestion to handle buffers, and also made it accept Objects so that you can just specify the filename and/or content type yourself using request's format.

Please try it out and let me know if it works for you.