【问题标题】:Unexpected empty writestream in collectionFS using graphicsmagick使用 graphicsmagick 的 collectionFS 中出现意外的空 writestream
【发布时间】:2015-11-20 16:35:17
【问题描述】:

我正在使用 CollectionFS 来管理图像。此外,我正在使用 graphicsmagick gm() 来处理图像。

现在我想裁剪已保存的图像。因此,在点击事件上,会调用一个服务器方法,该方法会执行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);
        });

    }
});

【问题讨论】:

    标签: javascript meteor graphicsmagick collectionfs


    【解决方案1】:

    您不能读取和写入同一个文件。这相当于

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

    【讨论】:

    • 你试过了吗,它有效吗?我不是流方面的专家,但我理解它们的方式可能是幸运的——它可能适用于在从缓冲区开始写出之前作为一个整体缓冲的小文件,但不适用于较大的文件。但是谁知道呢,也许 collectionfs 在内部做了一些聪明的事情来允许这样做。无论如何,我不认为我会依赖它。让我知道您在测试时发现了什么。
    • 嗯..你能举个例子,你将如何使用临时流吗?
    • 完成后如何将tmp复制到write并清空tmp
    • 真的吗?你要求所有这些额外的工作,你甚至没有投票或接受答案?我相信你会在某个地方找到最后一个问题的答案。它只是将文件复制到您已经拥有的流中;-)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-28
    • 2017-09-19
    相关资源
    最近更新 更多