dayuloli
dayuloli

Reputation: 17051

Displaying images from private subdirectory in Meteor

I have a set of images I am storing in my /private sub-directory, I am trying to retrieve the data inside a server method and sending the data back to the client to be displayed.

How can I do that?


I have an image named test.png inside /private/photos. Here's what I've tried.

/client/test.js

Template.test.onRendered(function () {
    Meteor.call('returnPhoto', 'photos/test.png', function (e, data) {
        console.log(data);
        console.log(window.btoa(data));
        $('#imgContainerImg').attr('src', 'data:image/png;base64,' + window.btoa(data));
    });
})

/server/methods.js

returnPhoto: function (assetPath) {
  return Assets.getText(assetPath);
  return Assets.getBinary(assetPath);
}

I tried both Assets.getText and Assets.getBinary, the first gives me some binary gibberish, and the second gives me an array of numbers. Using the btoa function doesn't work regardless.


I have looked at the CollectionFS package, but I do not need to upload the pictures and store them all in a collection. I'd like the images to be available as soon as I put them in that directory, without having to call myFSCollection.insert.

Upvotes: 3

Views: 585

Answers (2)

Daniel Budick
Daniel Budick

Reputation: 1850

This is the solution I work with:

client/main.js

const imagesLookup = new ReactiveDict();
Template.registerHelper('img', function(src) {
  Meteor.call('image', src, (err, img)=> {
    imagesLookup.set(src, img);
  });
  return imagesLookup.get(src);
});

client/main.html

<template="stuffWithImage">
  <!-- src is the path of the image in private -->
  <img src="{{img src}}"/>
</template>

imports/methods.js

Meteor.methods({
  image(src){
    //validate input and check if use is allowed to see this asset
    if(Meteor.isClient){
      //return some loading animation
    }
    const buffer = new Buffer(Assets.getBinary(src), 'binary');
    const magicNumber = buffer.toString('hex',0,4)
    const base64String = buffer.toString('base64');
    return `data:image/${getImageType(magicNumber)};base64,${base64String}`;
  }
});

function getImageType(magicNumber){
  if (magicNumber === 'ffd8ffe0') {
    return 'jpeg';
  }
  //check for other formats... here is a table: https://asecuritysite.com/forensics/magic
}

Upvotes: 1

dayuloli
dayuloli

Reputation: 17051

Using the following, I was able to get images from the private directory, send it over to the client as a byte array, which then gets converted into a base64 string and displayed as data URL.

client/test.js

Template.test.onRendered(function () {
    Meteor.call('returnPhoto', 'photos/test.png', function (e, data) {
        var base64String = btoa(String.fromCharCode.apply(null, new Uint8Array(data)));
        $('#imgContainerImg').attr('src', 'data:image/png;base64,' + base64String);
    });
})

server/methods.js

returnPhoto: function (assetPath) {
    return Assets.getBinary(assetPath);
}

Upvotes: 1

Related Questions