javascriptnode.jsmeteorgridfs-streamgm

Manipulate GridFS file with GraphicsMagick and store it as new file


I'm trying to read a GridFS file via gridfs-stream (https://github.com/aheckmann/gridfs-stream), rotate it 90° with gm and store it as a new GridFS file.

My result looks very 'unstylish'... So I'm asking for help to optimize this little code snippet...

And the second thing for this code: I need a kind of 'switch'. This code do a rotation manipulation of the image. But I need to pass a parameter to do rotation, resize or something else. How do I integrate this?

import Grid from 'gridfs-stream'
import { MongoInternals } from 'meteor/mongo'

const id = '12345'
const gfs = Grid(
  MongoInternals.defaultRemoteCollectionDriver().mongo.db,
  MongoInternals.NpmModule
)

const readStream = gfs.createReadStream({ _id: id })
readStream.on('error', function (err) {
  console.error('Could not read stream', err)
  throw Meteor.Error(err)
})

gm(readStream)
  .rotate('#ffffff', 90)
  .stream(function (err, stdout, stderr) {
    if (err) {
      console.error('Could not write stream')
      throw Meteor.Error(err)
    }
    const writeStream = gfs.createWriteStream()
    const newFileId = writeStream.id
    writeStream.on('finish',
      function () {
        console.log('New file created with ID ' + newFileId)
      }
    )
    stdout.pipe(writeStream)
  })

Solution

  • I don't have a project set up to test this on but it looks right.

    Complex streaming tends to get pretty ugly looking. Not a whole lot you can do about it, besides trying not let it get out of hand. But let's see what we can do to beautify along the way while adding the additional functionality.

    import Grid from 'gridfs-stream'
    import gm from 'gm'
    import { MongoInternals } from 'meteor/mongo'
    
    const id = '12345'
    const gfs = Grid(
      MongoInternals.defaultRemoteCollectionDriver().mongo.db,
      MongoInternals.NpmModule
    )
    
    const gfsStreams = {
      read: _id => 
        gfs.createReadStream({ _id })
          .on('error', err => {
            console.error('Could not read stream', err)
            throw Meteor.Error(err)
          }),
      write: () => {
        const ws = gfs.createWriteStream()
        const newFileId = ws.id
        ws.on('finish', () =>
            console.log('New file created with ID ' + newFileId)
          )
          .on('error' => {
            console.error('Could not write stream')
            throw Meteor.Error(err)
          })
        return ws
      }
    }
    
    const transformedStream = gmTransform({
      filestream: gfsStreams.read(id),
      gmOptions: {
        magnify: [],
        rotate: ['ffffff', 90],
        blur: [7, 3]
        crop: [300, 300, 150, 130]
      },
      output: stdout  
    })
    
    stdout.pipe(transformedStream)
    
    function gmTrasform ({filestream, gmOptions}){
      let gmStream = gm(filestream)  
        .on('error', {
          console.error('Could not transform image')
          throw Meteor.Error(err)
        })
      Object.keys(gmOptions)
        .forEach(opt => {
          gmStream = gmStream[opt](...gmOptions[i])
        })
    
      return gmStream.stream()
        .pipe(gfsStreams.write())
    }