How can I get a buffer for a file (image) from CollectionFS
Asked Answered
K

1

13

I'm trying to insert an image into a pdf I'm creating server-side with PDFkit. I'm using cfs:dropbox to store my files. Before when I was using cvs:filesystem, it was easy to add the images to my pdf's cause they were right there. Now that they're stored remotely, I'm not sure how to add them, since PDFkit does not support adding images with just the url. It will, however, accept a buffer. How can I get a buffer from my CollectionFS files?

So far I have something like this:

var portrait = Portraits.findOne('vS2yFy4gxXdjTtz5d');
readStream = portrait.createReadStream('portraits');

I tried getting the buffer two ways so far:

First using dataMan, but the last command never comes back:

var dataMan = new DataMan.ReadStream(readStream, portrait.type());
var buffer = Meteor.wrapAsync(Function.prototype.bind(dataMan.getBuffer, dataMan))();

Second buffering the stream manually:

var buffer = new Buffer(0);
readStream.on('readable', function() {
    buffer = Buffer.concat([buffer, readStream.read()]);
});
readStream.on('end', function() {
    console.log(buffer.toString('base64'));
});

That never seems to come back either. I double-checked my doc to make sure it was there and it has a valid url and the image appears when I put the url in my browser. Am I missing something?

Kare answered 23/6, 2015 at 0:3 Comment(6)
what do you mean by "never comes back"? How/where in your code are you using these solutions. The second one should work.Matson
also, are you calling readStream.read() anywhere?Matson
By "never comes back" I mean the callback for the 'end' event is never executed (I don't see the log message in the console).Kare
In my second attempt, I called readStream.read() at the end of the third line.Kare
github.com/CollectionFS/Meteor-CollectionFS/issues/457 Check the example Icellan posts toward the bottom of the thread. Note: make sure to replace readable with data in the event handler.Showily
Brian, your answer appears to be correct. Unfortunately, I won't have a chance to try it out before the bounty ends. Why don't you add it as an answer so you get some of the bounty? Be sure to copy the answer here, and not just link to it. Otherwise the mods will complain. Later when I test it, I'll mark it as correct.Kare
S
5

I had to do something similar and since there's no answer to this question, here is how I do it:

// take a cfs file and return a base64 string
var getBase64Data = function(file, callback) {
  // callback has the form function (err, res) {}
  var readStream = file.createReadStream();
  var buffer = [];
  readStream.on('data', function(chunk) {
    buffer.push(chunk);
  });
  readStream.on('error', function(err) {
    callback(err, null);
  });
  readStream.on('end', function() {
    callback(null, buffer.concat()[0].toString('base64'));
  });
};

// wrap it to make it sync    
var getBase64DataSync = Meteor.wrapAsync(getBase64Data);

// get a cfs file
var file = Files.findOne();

// get the base64 string
var base64str = getBase64DataSync(file);

// get the buffer from the string
var buffer = new Buffer(base64str, 'base64')

Hope it'll help!

Stander answered 28/9, 2015 at 14:45 Comment(1)
I haven't tested it, but it looks like exactly what I was trying to figure out. Back in July I just saved the base 64 string straight on the collection, but that uses more space. Thanks for your help.Kare

© 2022 - 2024 — McMap. All rights reserved.