使用Golang调用Imagemagick无临时文件拼接图片是否可行?
问题解答
这个需求完全可以实现,不需要生成任何临时文件。
问题原因
你遇到的无法传入多个stdin流的问题,是因为对Imagemagick的stdin读取规则不了解:当命令参数中出现多个-占位符时,Imagemagick会按顺序从同一个stdin流中依次读取对应数量的输入文件,每个文件的格式由占位符前的前缀指定(这里就是png:-)。
原代码问题
- 所有defer语句都错写为
f1.Close(),会导致f2、f3文件句柄没有正常关闭 - 只给stdin传入了第一张图片的字节流,没有传入后两张的内容
解决方案
用Go标准库的io.MultiReader把三个图片的buffer按顺序拼接为一个Reader,直接赋值给cmd.Stdin即可,Imagemagick会自动从流中拆分出3张PNG图片。
修改后完整代码
package main import ( "bytes" "fmt" "image" "image/png" "io" "os" "os/exec" ) func main() { var output bytes.Buffer // 读取第一张图 buff1 := new(bytes.Buffer) f1, err := os.Open("image/1.png") if err != nil { fmt.Printf("open 1.png failed: %v\n", err) return } defer f1.Close() img1, _, err := image.Decode(f1) if err != nil { fmt.Printf("decode 1.png failed: %v\n", err) return } if err = png.Encode(buff1, img1); err != nil { fmt.Printf("encode 1.png to buffer failed: %v\n", err) return } // 读取第二张图 buff2 := new(bytes.Buffer) f2, err := os.Open("image/2.png") if err != nil { fmt.Printf("open 2.png failed: %v\n", err) return } defer f2.Close() img2, _, err := image.Decode(f2) if err != nil { fmt.Printf("decode 2.png failed: %v\n", err) return } if err = png.Encode(buff2, img2); err != nil { fmt.Printf("encode 2.png to buffer failed: %v\n", err) return } // 读取第三张图 buff3 := new(bytes.Buffer) f3, err := os.Open("image/3.png") if err != nil { fmt.Printf("open 3.png failed: %v\n", err) return } defer f3.Close() img3, _, err := image.Decode(f3) if err != nil { fmt.Printf("decode 3.png failed: %v\n", err) return } if err = png.Encode(buff3, img3); err != nil { fmt.Printf("encode 3.png to buffer failed: %v\n", err) return } // 拼接命令,三个png:-对应三张输入图,+append是水平拼接,垂直拼接换成-append cmd := exec.Command("convert", "png:-", "png:-", "png:-", "+append", "png:-") // 把三个buffer按顺序拼接成一个Reader作为stdin cmd.Stdin = io.MultiReader(buff1, buff2, buff3) cmd.Stdout = &output if err := cmd.Run(); err != nil { fmt.Printf("convert run failed: %v\n", err) return } // 保存结果 imgPng, _, err := image.Decode(bytes.NewReader(output.Bytes())) if err != nil { fmt.Printf("decode result failed: %v\n", err) return } out, err := os.Create("result.png") if err != nil { fmt.Printf("create result.png failed: %v\n", err) return } defer out.Close() if err = png.Encode(out, imgPng); err != nil { fmt.Printf("save result.png failed: %v\n", err) return } fmt.Println("图片拼接完成,结果已保存为result.png") }
注意事项
- 如果你要拼接的图片尺寸很大,内存占用会对应升高,这种场景才建议考虑临时文件方案
- 上述代码补全了错误处理逻辑,正式环境使用建议保留,避免出现异常无提示的情况
内容的提问来源于stack exchange,提问作者JR Wink
相关产品推荐
相关产品推荐

