8

I have been struggling to succeed in downloading an image without piping it to fs. Here's what I have accomplished:

var Promise = require('bluebird'),
    fs = Promise.promisifyAll(require('fs')),
    requestAsync = Promise.promisify(require('request'));

function downloadImage(uri, filename){
    return requestAsync(uri)
        .spread(function (response, body) {
            if (response.statusCode != 200) return Promise.resolve();
            return fs.writeFileAsync(filename, body);
        })
       .then(function () { ... })

       // ...
}

A valid input might be:

downloadImage('http://goo.gl/5FiLfb', 'c:\\thanks.jpg');

I do believe the problem is with the handling of body. I have tried casting it to a Buffer (new Buffer(body, 'binary') etc.) in several encodings, but all failed.

Thanks from ahead for any help!

Selfish
  • 6,023
  • 4
  • 44
  • 63

1 Answers1

21

You have to tell request that the data is binary:

requestAsync(uri, { encoding : null })

Documented here:

encoding - Encoding to be used on setEncoding of response data. If null, the body is returned as a Buffer. Anything else (including the default value of undefined) will be passed as the encoding parameter to toString() (meaning this is effectively utf8 by default).

So without that option, the body data is interpreted as UTF-8 encoded, which it isn't (and yields an invalid JPEG file).

robertklep
  • 198,204
  • 35
  • 394
  • 381
  • Thanks! I don't know how I missed that. :) – Selfish Jul 08 '15 at 10:37
  • This answer helped me finally save valid PDFs I was fetching with [request-promise](https://www.npmjs.com/package/request-promise). I tried [every encoding supported by Node.js](http://stackoverflow.com/a/14551669/3212415), but the resulting file was always corrupt (and larger than it should have been). Turns out the problem was how it was coming back to begin with. Adding `encoding: null` fixed it, and then it saved fine no matter which encoding I used during `fs.writeFile()`. Thanks! – Troy Gizzi Oct 07 '16 at 00:00