ImageMagick 可以在 Windows PowerShell 上运行,但无法在 go 上运行

发布于 2025-01-18 18:42:22 字数 2898 浏览 3 评论 0原文

我需要使用 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中)上,它返回一个错误,实际上没有指定的错误消息,它只是失败了 输入图片这里的描述

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

I need to add watermark with ImageMagick, for some reason, I need to run it with golang.

Here is my code snippet

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!")
    }
}

Because I've use os.Getwd() in the code, so we cannot run it directly through go run main.go, instead, we should build an executable

# 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

On macOS, the executable works fine, the watermark was successfully added
enter image description here

On Windows(in PowerShell), it returns an error, actually no specified error message, it just failed
enter image description here

Anyone who knows how to solve this error?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

萌梦深 2025-01-25 18:42:22

不是使用 powershell 从您的Go Inserion 中调用您的可执行文件,您正在使用cmd.exe,具有不同的语法规则(它不识别`(backtick)作为逃生字符,是一种元时间,不支持逃脱的”因此

​代码> cmd.exe ,由于语法差异而失败的旧式Windows Shell。

因此,替换:

    command = "cmd"
    secondParam = "/c"

与:

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

另外,请考虑在-c之前放置以下参数,以增加鲁棒性:

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

请参阅 powershell.exe 的文档。


退后一步:

您的可执行电话不使用任何 shell功能 (例如重定向到文件,通过管道连接多个命令,...),所以您可以简单地调用magick 直接,并且其所有参数通过 exec.command (),可以加快操作并避免逃脱的需求。

You're not using PowerShell to invoke your executable from inside your Go application, you're using cmd.exe, which has different syntax rules (it doesn't recognize ` (the backtick) as the escape character, % is a metacharacter, no support for escaping " as \", ...)

Therefore, because you're mistakenly passing a command line designed for powershell.exe (the Windows PowerShell CLI) to cmd.exe, the legacy Windows shell, which fails, due to the syntax differences.

Therefore, replace:

    command = "cmd"
    secondParam = "/c"

with:

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

Additionally, consider placing the following arguments before -c, for added robustness:

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

See the documentation for powershell.exe.


Taking a step back:

Your executable call doesn't use any shell features (such as redirecting to a file, connecting multiple commands via a pipeline, ...), so you could simply invoke magick directly, with it and all its arguments passed individually to exec.Command(), which speeds up the operation and avoids the need for escaping.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文