2015-11-20 38 views
5

我正在使用CollectionFS來管理圖像。此外,我使用graphicsmagick gm()來處理圖像。使用graphicsmagick的collectionFS中意外的空writestream

現在我想裁剪已保存的圖像。因此,在點擊事件中調用服務器方法,它執行crop()。但在完成此操作之後,在收集中,我找到一個空的圖像,並在正確的日期更新size=0

我不明白,我做錯了什麼。

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); 
    } 
}); 

更新

正如Christian所推薦的,我爲writeStream使用了一個tmp文件,因爲writeStream不能像readStream一樣 - 這導致了空的結果。

但寫入tmp文件後,其內容必須被複制回公用存儲。我怎麼做?

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 
    } 
}); 

更新2 我這個嘗試之一:

// 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); 
     }); 

    } 
}); 

回答

2

您不能讀取和寫入同一個文件。這相當於類似

cat test | grep 1 > test 

上的外殼。你可以嘗試一下,看看test之後會是空的。

您需要在crop方法中創建一箇中間臨時文件。


假設確實是問題,那麼這是這樣的一種方式(未測試):

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

那麼有什麼區別這樣做呢? https://github.com/CollectionFS/Meteor-CollectionFS/wiki/How-to:-Convert-a-file-already-stored – user3142695

+0

你有沒有試過,它的工作?我不是流的專家,但我理解他們的方式可能是運氣,如果它確實如此 - 它可能適用於在從緩衝區開始寫入之前整體緩衝的小文件,但不適用於較大文件。但是誰知道,也許collectionfs在內部做了一些聰明的事情來允許這樣做。無論如何,我不認爲我會依賴這一點。讓我知道當你測試這個時你發現了什麼。 –

+0

嗯..你能舉個例子說明你將如何使用臨時流? – user3142695