Skip to content
This repository has been archived by the owner on Mar 14, 2019. It is now read-only.

Image Manipulation

Brylie Christopher Oxley edited this page Mar 3, 2015 · 1 revision

A common use for transformWrite is to manipulate images before saving them. To get this set up:

  1. Install GraphicsMagick or ImageMagick on your development machine and on any server that will host your app. (The free Meteor deployment servers do not have either of these, so you can't deploy to there.) These are normal operating system applications, so you have to install them using the correct method for your OS. For example, on Mac OSX you can use brew install graphicsmagick assuming you have Homebrew installed.
  2. Add the cfs:graphicsmagick Meteor package to your app: meteor add cfs:graphicsmagick

The following are some examples.

Basic Example

Images = new FS.Collection("images", {
    stores: [
      new FS.Store.FileSystem("images"),
      new FS.Store.FileSystem("thumbs", {
        transformWrite: function(fileObj, readStream, writeStream) {
          // Transform the image into a 10x10px thumbnail
          gm(readStream, fileObj.name()).resize('10', '10').stream().pipe(writeStream);
        }
      })
    ],
    filter: {
      allow: {
        contentTypes: ['image/*'] //allow only images in this FS.Collection
      }
    }
});

Note that this example requires the cfs:filesystem package.

Converting to a Different Image Format

To convert every file to a specific image format, you can pass a GraphicsMagick format string to the stream method, but you will also need to alter the FS.File instance as necessary in a beforeWrite function.

Images = new FS.Collection("images", {
    stores: [
      new FS.Store.FileSystem("images"),
      new FS.Store.FileSystem("thumbs", {
        beforeWrite: function(fileObj) {
          // We return an object, which will change the
          // filename extension and type for this store only.
          return {
            extension: 'png',
            type: 'image/png'
          };
        },
        transformWrite: function(fileObj, readStream, writeStream) {
          // Transform the image into a 10x10px PNG thumbnail
          gm(readStream).resize(60).stream('PNG').pipe(writeStream);
          // The new file size will be automatically detected and set for this store
        }
      })
    ],
    filter: {
      allow: {
        contentTypes: ['image/*'] //allow only images in this FS.Collection
      }
    }
});

Note that this example requires the cfs-filesystem package.

Converting a File Already Stored

You may want to adjust a bunch of images that you've already stored. This can be done easily by streaming out of the store and then back into it. The following example is for illustration purposes, but you should not use it on production data unless you have a throttled queue in a separate process or only a very small number of images.

Images.find().forEach(function (fileObj) {
  var readStream = fileObj.createReadStream('images');
  var writeStream = fileObj.createWriteStream('images');
  gm(readStream).swirl(180).stream().pipe(writeStream);
});

Note that you could also pipe the readStream from one store to the writeStream from another store to move files between stores, for example if you decide to use a different storage adapter and need to quickly and easily migrate the data. (We have not tested this, but it should be possible.)