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
    }
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥100 set_link_state
  • ¥15 虚幻5 UE美术毛发渲染
  • ¥15 CVRP 图论 物流运输优化
  • ¥15 Tableau online 嵌入ppt失败
  • ¥100 支付宝网页转账系统不识别账号
  • ¥15 基于单片机的靶位控制系统
  • ¥15 真我手机蓝牙传输进度消息被关闭了,怎么打开?(关键词-消息通知)
  • ¥15 装 pytorch 的时候出了好多问题,遇到这种情况怎么处理?
  • ¥20 IOS游览器某宝手机网页版自动立即购买JavaScript脚本
  • ¥15 手机接入宽带网线,如何释放宽带全部速度