ImageMagick 可以 运行 on Windows PowerShell 但不能 运行 with go

ImageMagick can run on Windows PowerShell but can't run with go

我需要用 ImageMagick 添加水印,出于某种原因,我需要 运行 用 golang 添加水印。

这是我的代码片段

package main

import (
    "fmt"
    "os"
    "os/exec"
    "path/filepath"
    "runtime"
    "strings"
)

func main() {
    currentDir, _ := os.Getwd()

    sourceImg := os.Args[1]

    sourceName := filepath.Base(sourceImg)
    sourceExt := filepath.Ext(sourceImg)
    imgNameWithoutExt := strings.Replace(sourceName, sourceExt, "", 1)
    targetImgName := imgNameWithoutExt + "_wm" + sourceExt
    targetImg := filepath.Join(filepath.Dir(sourceImg), targetImgName)

    command := "bash"
    secondParam := "-c"
    // In macOS or Linux, use backslash to escape parenthesis
    cmdStr := `magick "` + sourceImg + `" -set option:watermarkWidth "%[fx:int(w*0.25)]" -alpha set -background none \( -fill "#FFFFFF80" -stroke "#FF000080" -strokeWidth 3 -undercolor "#FF000080" -font "arial.ttf" -size "%[watermarkWidth]x" label:"This is watermark" -gravity center -geometry +10+10 -rotate -30 \) -composite -quality 40 "` + targetImg + `"`

    if runtime.GOOS == "windows" {
        sourceImg = strings.ReplaceAll(sourceImg, "\", "\\")
        targetImg = strings.ReplaceAll(targetImg, "\", "\\")
        // In PowerShell, use babckstick (`) to escape parenthesis
        command = "cmd"
        secondParam = "/c"
        cmdStr = `magick "` + sourceImg + `" -set option:watermarkWidth "%[fx:int(w*0.25)]" -alpha set -background none ` + "`(" + ` -fill "#FFFFFF80" -stroke "#FF000080" -strokeWidth 3 -undercolor "#FF000080" -font "arial.ttf" -size "%[watermarkWidth]x" label:"This is watermark" -gravity center -geometry +10+10 -rotate -30 ` + "`)" + ` -composite -quality 40 "` + targetImg + `"`
    }

    fmt.Println(cmdStr)

    cmd := exec.Command(command, secondParam, cmdStr)
    cmd.Dir = currentDir
    ouput, err := cmd.Output()
    if err != nil {
        fmt.Println("Error:", ouput, err.Error())
    } else {
        fmt.Println("Watermark was successfully added!")
    }
}

因为我在代码中使用了os.Getwd(),所以我们不能运行直接通过go run main.go,而是应该构建一个可执行文件

# build Windows executable
GOOS=windows GOARCH=amd64 go build -ldflags "-w -s" -o "test-magick.exe" main.go

# build macOS executable
GOOS=darwin GOARCH=amd64 go build -ldflags "-w -s" -o "test-magick" main.go

# build Linux executable(I didn't test)
GOOS=linux GOARCH=amd64 go build -ldflags "-w -s" -o "test-magick" main.go

在 macOS 上,可执行文件运行正常,水印已成功添加

在Windows(在PowerShell中),它returns一个错误,实际上没有指定的错误信息,它只是失败了

有人知道如何解决这个错误吗?

没有使用PowerShell从您的 Go 应用程序中调用您的可执行文件 ,您正在使用 cmd.exe,它具有不同的语法规则(它不将 `(反引号)识别为转义字符,% 是元字符,不支持转义 " 作为 \", ...)

因此,由于您错误地将专为 powershell.exe(Windows PowerShell CLI)设计的命令行传递给了 cmd.exe,遗留的 Windows shell,由于语法差异,失败了。

因此,替换:

    command = "cmd"
    secondParam = "/c"

与:

    command = "powershell.exe"
    secondParam = "-c"

此外,考虑在 -c 之前放置以下参数以增加稳健性:

   "-ExecutionPolicy", "Bypass", "-NoProfile"

参见documentation for powershell.exe


退一步:

您的可执行调用没有使用任何 shell 功能(例如重定向到文件、连接多个命令通过管道,...),所以你可以简单地调用magick直接,用它和它的所有参数单独传递exec.Command(),这样可以加快运算速度,避免转义