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

从存储桶将多个文件传递给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
    }
    
    已采纳该答案
    评论
    解决 无用
    打赏 举报

相关推荐 更多相似问题