2015-11-20 17 views
5

Uso CollectionFS per la gestione delle immagini. Inoltre sto usando graphicsmagick gm() per manipolare le immagini.writestream vuoto inatteso in collectionFS utilizzando graphicsmagick

Ora voglio ritagliare un'immagine già salvata. Pertanto, in un evento click viene chiamato un metodo server, che esegue il ritaglio(). Ma dopo averlo fatto, nella raccolta trovo un'immagine vuota con size=0 aggiornata alla data corretta.

Non vedo, quello che sto facendo male.

shared.js

Images = new FS.Collection("images", { 
    stores: [ 
     new FS.Store.FileSystem("thumbnail", { 
      transformWrite: function(fileObj, readStream, writeStream) { 
       gm(readStream, fileObj.name()).autoOrient().resize('96', '96' + '^').gravity('Center').extent('96', '96').stream().pipe(writeStream); 
      } 
     }), 
     new FS.Store.FileSystem("public"), 
    ] 
}); 

server.js

Meteor.methods({ 
    'crop': function (fileId, selection) { 
     var file = Images.findOne({ _id: fileId }), 
      read = file.createReadStream('public'), 
      write = file.createWriteStream('public'); 

     gm(read) 
      .crop(selection.width, selection.height, selection.left, selection.top) 
     .stream() 
     .pipe(write); 
    } 
}); 

Client.js

Template.editor.events({ 
    'click #crop': function() { 
     var fileId  = '123456789', 
      selection = { height: 100, width: 100, top: 10, left: 10 }; 

     Meteor.call('crop', fileId, selection); 
    } 
}); 

Aggiornamento

Come consigliato da Christian Sto usando un file tmp per writeStream, perché lo stream di scrittura non può essere lo stesso del readStream - che ha causato il risultato vuoto.

Ma dopo aver scritto nel file tmp, il contenuto deve essere copiato nell'archivio pubblico. Come lo faccio?

Meteor.methods({ 
    'crop': function (fileId, selection) { 

     var fs = Meteor.npmRequire('fs'), 
      file = Images.findOne({ _id: fileId }), 
      read = file.createReadStream('public'), 
      filename = '/tmp/gm_' + Date.now(), 
      tmp = fs.createWriteStream(filename); 

     gm(read) 
      .crop(selection.width, selection.height, selection.left, selection.top) 
     .stream() 
     .pipe(tmp); 

     // After writing to tmp -> copy back to stream and delete tmp-file 
    } 
}); 

Update 2 ho provato questo:

// Add temp store 
new FS.Store.FileSystem("temp") 

// Method 
Meteor.methods({ 
    'crop': function (fileId, selection) { 
     var file = Images.findOne({ _id: fileId }), 
      read = file.createReadStream('public'), 
      temp = file.createWriteStream('temp'); 

     gm(read) 
      .crop(selection.width, selection.height, selection.left, selection.top) 
     .stream() 
     .pipe(tmp) 
     .on('end', function() { 
      var tmpread = file.createReadStream('temp'), 
       write = file.createWriteStream('public'); 

      gm(tmpread).stream().pipe(write); 
     }); 

    } 
}); 

risposta

2

Non è possibile leggere e scrivere nello stesso file. Questo è equivalente a cose come

cat test | grep 1 > test 

sul guscio. Puoi provare e vedere che test sarà vuoto in seguito.

È necessario creare un file temporaneo intermedio nel metodo .


Supponendo che è effettivamente il problema, allora questo è un modo di fare questo (non testato):

var fs = Meteor.npmRequire('fs'); 
var file = Images.findOne({ _id: fileId }), 
var read = file.createReadStream('public'), 
var filename = '/tmp/gm_' + Date.now(); 
var tmp = fs.createWriteStream(filename); 

var gmread = gm(read) 
    .crop(selection.width, selection.height, selection.left, selection.top) 
    .stream(); 

gmread.on('end', function() { 
    // done streaming through GM, copy the result back: 
    var tmpread = fs.createReadStream(filename); 
    var write = file.createWriteStream('public'); 
    tmpread.pipe(write); 
}); 

gmread.pipe(tmp); 
+0

Allora, qual è la differenza a questo? https://github.com/CollectionFS/Meteor-CollectionFS/wiki/How-to:-Convert-a-file-stready-stored – user3142695

+0

hai provato e funziona? Non sono un esperto di streaming, ma il modo in cui li capisco potrebbe essere una fortuna se lo facesse, potrebbe funzionare per file di piccole dimensioni che vengono bufferizzati nel loro complesso prima che inizi la scrittura dal buffer, ma non per quelli più grandi. Ma chi lo sa, forse collectionfs fa qualcosa di intelligente internamente per permettere questo. In un modo o nell'altro, non penso che mi baserei su questo. Fammi sapere cosa scopri quando provi questo. –

+0

Hmm .. potresti per favore fare un esempio di come useresti un flusso temporaneo? – user3142695