dongren1353 2019-07-17 13:29
浏览 46
已采纳

从存储桶将多个文件传递给exec.Command调用

I'm attempting to build a cloud function written in Go, that will use the available ImageMagick library in Google's Cloud Functions infrastructure to composite & manipulate several images into a resulting output image.

The root of the problem, is that the ImageMagick function that I want to use is available, but it takes multiple distinct inputs in order to work. My inputs are objects in a Storage Bucket.

The os/exec Cmd struct allows you to do this, by using an "ExtraFiles" array, and I know how to provide these extra files to my ImageMagick command.

However, the "ExtraFiles" array only wants to store instances of os.File, whereas the GCP Storage Client gives you a "Reader" instance when you open a file.

        backgroundBlob := storageClient.Bucket(inputBucket).Object(background)
        backgroundImg, err := backgroundBlob.NewReader(ctx)
        if err != nil {
                return "", fmt.Errorf("backgroundImg: %v", err)
        }

        foregroundBlob := storageClient.Bucket(inputBucket).Object(foreground)
        foregroundImg, err := foregroundBlob.NewReader(ctx)
        if err != nil {
                return "", fmt.Errorf("foregroundImg: %v", err)
        }

        outputBlob := storageClient.Bucket(outputBucket).Object(output)
        outputImg := outputBlob.NewWriter(ctx)
        defer outputImg.Close()

        // Set up some additional file handles since we're dealing with more inputs than STDIN Can cope with
        cmd := exec.Command("convert", "fd:3", "fd:4", "-composite", "fd:5")
        cmd.ExtraFiles = append(cmd.ExtraFiles,backgroundImg)
        cmd.ExtraFiles = append(cmd.ExtraFiles,foregroundImg)
        cmd.ExtraFiles = append(cmd.ExtraFiles,outputImg)

        if err := cmd.Run(); err != nil {
                return "", fmt.Errorf("cmd.Run: %v", err)
        }

        log.Printf("Blurred image has been uploaded to %s", outputBlob.ObjectName())

        return outputBlob.ObjectName(), nil
}```

So, from where I am at the moment, I need to do one of the following two things:
1. Figure out how to get Google's storage API to treat/use objects in their storage buckets as "os.File"s
OR
2. Figure out how to execute my "convert" command using multiple Readers as input, rather than leveraging the ExtraFiles array.

If anybody out there has any ideas on how to achieve either of the above, or has alternate ways of solving this problem, I would be very grateful to hear them!
  • 写回答

1条回答 默认 最新

  • dongyanzhui0524 2019-07-17 14:38
    关注

    To anybody who happens across this question in the future - I found a workaround. I'm not thrilled with it, but it is functional.

    Essentially, I was able to slurp the contents of the storage Readers & then create my own os.File objects within the Cloud Functions context. Then, passing that os.File to the exec.Cmd invocation. It's definitely not ideal, but here's the code:

    func Overlay(ctx context.Context, inputBucket, outputBucket, background string, foreground string, output string) (string, error) {
            // Retrieve the Background Image from the storage API
            backgroundBlob := storageClient.Bucket(inputBucket).Object(background)
            backgroundImg, err := backgroundBlob.NewReader(ctx)
            if err != nil {
                    return "", fmt.Errorf("backgroundImg: %v", err)
            }        
            // Read the contents of the file into a variable
            backgroundSlurp, err := ioutil.ReadAll(backgroundImg)
            if err != nil {
                    return "", fmt.Errorf("readFile: unable to read data from bucket %q, file %q: %v", inputBucket, background, err)
            }
            // Write the contents of Background Image to an os.File instance
            err = ioutil.WriteFile(fmt.Sprintf("/tmp/%s",background), backgroundSlurp, 0644)
            if err != nil {
                    return "", fmt.Errorf("backgroundImg: %v", err)
            }
            // Open the os.File instance to pass it on to os.exec later
            backgroundFile, err := os.Open(fmt.Sprintf("/tmp/%s",background))
            if err != nil {
                    return "", fmt.Errorf("backgroundFile: %v", err)
            }
    
            foregroundBlob := storageClient.Bucket(inputBucket).Object(foreground)
            foregroundImg, err := foregroundBlob.NewReader(ctx)
            if err != nil {
                    return "", fmt.Errorf("foregroundImg: %v", err)
            }
            // Read the contents of the file into a variable
            foreroundSlurp, err := ioutil.ReadAll(foregroundImg)
            if err != nil {
                    return "", fmt.Errorf("readFile: unable to read data from bucket %q, file %q: %v", inputBucket, foreground, err)
            }
            // Write the contents of Foreground Image to an os.File instance
            err = ioutil.WriteFile(fmt.Sprintf("/tmp/%s",foreground), foreroundSlurp, 0644)
            if err != nil {
                    return "", fmt.Errorf("foregroundImg: %v", err)
            }
            // Open the os.File instance to pass it on to os.exec later
            foregroundFile, err := os.Open(fmt.Sprintf("/tmp/%s",foreground))
            if err != nil {
                    return "", fmt.Errorf("foregroundFile: %v", err)
            }
    
            outputBlob := storageClient.Bucket(outputBucket).Object(output)
            outputImg := outputBlob.NewWriter(ctx)
            defer outputImg.Close()
    
            // Set up some additional file handles since we're delaqing with more inputs than STDIN Can cope with
            cmd := exec.Command("convert", "fd:3", "fd:4", "-composite", "-")
            cmd.Stdout = outputImg
            cmd.ExtraFiles = append(cmd.ExtraFiles,backgroundFile)
            cmd.ExtraFiles = append(cmd.ExtraFiles,foregroundFile)
    
            if err := cmd.Run(); err != nil {
                    return "", fmt.Errorf("cmd.Run: %v", err)
            }
    
            log.Printf("Blurred image has been uploaded to %s", outputBlob.ObjectName())
    
            return outputBlob.ObjectName(), nil
    }
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 关于#python#的问题:求帮写python代码
  • ¥20 MATLAB画图图形出现上下震荡的线条
  • ¥15 LiBeAs的带隙等于0.997eV,计算阴离子的N和P
  • ¥15 关于#windows#的问题:怎么用WIN 11系统的电脑 克隆WIN NT3.51-4.0系统的硬盘
  • ¥15 来真人,不要ai!matlab有关常微分方程的问题求解决,
  • ¥15 perl MISA分析p3_in脚本出错
  • ¥15 k8s部署jupyterlab,jupyterlab保存不了文件
  • ¥15 ubuntu虚拟机打包apk错误
  • ¥199 rust编程架构设计的方案 有偿
  • ¥15 回答4f系统的像差计算