将两个标准输入参数传递给ImageMagick子进程

4

我有一些限制,不便具体说明,需要我使用ImageMagick作为子进程。

我有多个jpg文件的base64字符串,希望ImageMagick进行处理。 具体来说,我想让ImageMagick将这些jpg文件合并在一起。如果我有2个普通的jpg文件,那么我会使用以下格式从命令行执行:

node convert in_1.jpg in_2.jpg +append out.jpg

在JS文件中,我会使用以下代码:

var spawn, magicCommands, imagic;
spawn = require('child_process').spawn;
magicCommands = ["in_1.jpg",
                 "in_2.jpg",
                 "+append",
                 "out.jpg"];
imagic = spawn("convert", magicCommands);

现在,如果我想使用1个标准输入缓冲区,则以下内容将起作用。

    var arrow1JpgBase64, arrow2JpgBase64, arrowBuffer1, arrowBuffer2, magicCommands, imagic;

    spawn = require('child_process').spawn;
    exec = require('child_process').exec;

    arrow1JpgBase64 = "/9j/4AAQSkZJRgABAQEAYABgAAD/2wBDAAUDBAQEAwUEBAQFBQUGBwwIBwcHBw8LCwkMEQ8SEhEPERETFhwXExQaFRERGCEYGh0dHx8fExciJCIeJBweHx7/2wBDAQUFBQcGBw4ICA4eFBEUHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh7/wAARCAAFAAkDASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD1/wCFngjxJba78QbWT4reLTLH4pZ2mjt9PLTCSxs5VL+bbSYZUkWPCFUxGu1EHFdz/wAIb4j/AOiseM//AAF0n/5BoooA/9k=";
    arrow2JpgBase64 = "/9j/4AAQSkZJRgABAQEAYABgAAD/2wBDAAUDBAQEAwUEBAQFBQUGBwwIBwcHBw8LCwkMEQ8SEhEPERETFhwXExQaFRERGCEYGh0dHx8fExciJCIeJBweHx7/2wBDAQUFBQcGBw4ICA4eFBEUHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh7/wAARCAAFAAkDASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD1/wCOvgjxJc/Dt7NPit4tMt1q+k20Ty2+nqsLyajbIkoMFtFJuRmDjbIpyo5xmu5/4Q3xH/0Vjxn/AOAuk/8AyDRRQB//2Q==";
    arrowBuffer1 = new Buffer(arrow1JpgBase64, 'base64');
    arrowBuffer2 = new Buffer(arrow2JpgBase64, 'base64');
    magicCommands = ["jpg:",
                     "in_2.jpg",
                     "+append",
                     "out.jpg"];

    imagic = spawn("convert", magicCommands);
    imagic.stdin.write(arrowBuffer1);
    imagic.stdin.end();

    imagic.on('exit', function (code) {
        if (code === 0) {
            exec("open out.jpg");
        } else {
            console.log("error code: " + code);
        }
    }); // end of on exit

到目前为止一切都很好,但我想要使用两个缓冲区而不仅仅是其中的1个。因此,如果我用"jpg:"替换"in_2.jpg",这行,那么我需要如何更改其余的脚本才能使其正常工作呢?
谢谢

1
走之前,也许你可以在ImageMagick中使用 fd: 处理器,并将一个缓冲区放在 fd:3 上,另一个放在 fd:4 上... http://www.imagemagick.org/Usage/files/#fd - Mark Setchell
如果您已经有一个base64字符串(且字符数小于5000),为什么不直接将其作为参数传递,例如inline:data:image/jpeg;base64,... - emcconville
@emcconville 我也曾尝试过同样的事情,但似乎不再起作用了。我在这里尝试了Kurt的示例... https://dev59.com/qWfWa4cB1Zd3GeqPh4v_#12067952 和这里ASIDE下面的示例... http://www.imagemagick.org/Usage/files/#inline 在IM v6.9.2-5中似乎都无法正常工作。 - Mark Setchell
感谢回复。@Mark Setchell,您的回复看起来非常有前途,但您能否编写一些代码,展示如何将fd分配给缓冲区?很抱歉我表现出了我的无知! - Trevor
另一个选项可能是创建一个fifo,使用mkfifo将您的base64字符串写入fifo,并使IM从stdin读取一个文件,从fifo读取另一个文件... convert jpg:fifo -append result.jpg - Mark Setchell
显示剩余2条评论
2个回答

4
正如Mark Setchell在评论中所指出的,使用ImageMagick的fd:协议将起作用。
var spawnOptions = {
      stdio: [
        0, // stdin,
        1, // stdout
        2, // stderr
        'pipe', // arrowBuffer1
        'pipe'  // arrowBuffer2
      ]
};
magic = spawn("convert", magicCommands, spawnOptions);

这段文字涉及编程相关内容,需要翻译为中文:

这会打开 fd:3fd:4 以进行管道传输。我不太熟悉 家族,但通常有一种方法可以传递资源以外的

针对您的代码

magickCommands 变量更新为从新的 fd 读取,并直接写入新的 pipes

magicCommands = ["fd:3",
                 "fd:4",
                 "+append",
                 "out.jpg"];

// ...
imagic.stdio[3].write(arrowBuffer1);
imagic.stdio[4].write(arrowBuffer2);
imagic.stdio[3].end();
imagic.stdio[4].end();

我收到了一条消息,说 imagic.stdio[3] 未定义,我无法向其写入。不过我认为这已经接近了。 - Trevor

1

我不太确定这些“限制”具体是什么,或者我们正试图避免或解决什么问题,但以下将多个文件流合并的技巧可能会对你有所帮助:

# Make a red block
convert -size 50x50 xc:red multi.miff

# Make a green block, but APPEND INTO A SINGLE STREAM
convert -size 50x50 xc:lime miff:- >> multi.miff

# Make a blue block, but APPEND INTO A SINGLE STREAM
convert -size 50x50 xc:blue miff:- >> multi.miff

# Tell IM to convert and append multiple images in single stream 
convert multi.miff +append result.png

enter image description here

此外,如果您将上面的最后一个命令更改为以下内容,IM将在完成对文件multi.miff的操作后立即删除它 - 也就是为您整理好!
convert ephemeral:multi.miff +append result.png

再次感谢,我所指的限制是我不能使用基于C++的本地节点模块,因此这排除了我使用lwip或其他可能的选项。我真正想要的是避免不必要地写入硬盘。缓冲区已经存在,因此如果我可以将它们作为参数传递,那么比保存它们为文件然后删除文件更好。如果有这样的事情,我将发布另一个线程,以获取缓冲区的fd! - Trevor
1
好的,我越来越接近理解了...你考虑过使用小型RAM磁盘作为临时文件吗? - Mark Setchell
不,这是为客户系统设计的,需要进行多次安装。我可能只能创建和删除文件来解决问题。但我会先尝试创建缓冲流,然后我认为它们可以通过其fd进行引用。我在这里发布了一个帖子http://www.imagemagick.org/discourse-server/viewtopic.php?t=13100,但我不理解答案。 - Trevor
我尝试了一下RAM磁盘,看起来它可能是一个简单而高效的解决方案。我将使用这种方法,并查看我的客户IT部门是否有任何问题。我会回报告告诉大家进展如何。 - Trevor

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接