s3 に保存してあるファイルをダウンロードしてくるのは,aws/aws-cli を使えば簡単にできる. が,本記事ではそうではなく,s3 から画像を取得,保存 (書き出し) はせずに,golang の image.Image 型に 押し込める方法をまとめる.
こうすることで,s3 の画像に自身のマシンで任意の処理・変換をしてから保存 (or api server なら serve) する事ができる.

まず,aws adk を利用可能にしておく.

import (
	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/s3"
	"github.com/aws/aws-sdk-go/service/s3/s3manager"
)

これを使って,s3 とのセッションを作成する.

sess, _ := session.NewSession(&aws.Config{
	Region: aws.String("my region")},
)

実際には,これをする前に,2 つの環境変数,AWS_ACCESS_KEY_IDAWS_SECRET_ACCESS_KEY を設定しておく必要がある.

これから実際に画像を取得していく.
まず,とってきた画像を入れておくバッファを用意する.これは aws-sdk から良い感じのが提供されているのでそれを使う.

buff := &aws.WriteAtBuffer{}

で,場所を指定してダウンロードしたファイルをそのバッファに書き込む.

s3dl := s3manager.NewDownloader(sess)
_, err := s3dl.Download(buff, &s3.GetObjectInput{
	Bucket: aws.String(bucket),
	Key:    aws.String(path),
})

データを突っ込んだ buff には Bytes() -> []byte が定義されているので, bytes.NewReader を使えば Read() が実装された構造体に変換できる. そうなってしまえば,image/jpegfunc Decode(r io.Reader) が使えるので 元々欲しかった image.Image にたどり着く.
実際にはこれら 2 つの処理を 1 行でかける.

image, err = jpeg.Decode(bytes.NewReader(buff.Bytes()))

これでできた imageimage.Image なので,以前の記事で紹介した Goで画像にテキストを合成する方法 を s3 & server で画像の保存なしで行う事ができる.


コード全体像を下に貼っておく.

package main

import (
	"bytes"
	"image"
	"image/jpeg"
	"log"
	"os"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/s3"
	"github.com/aws/aws-sdk-go/service/s3/s3manager"
)

const bucket = "mybucket"

func getImg(imgName string) image.Image {
	path := imgName

	sess, _ := session.NewSession(&aws.Config{
		Region: aws.String("my region")},
	)

	buff := &aws.WriteAtBuffer{}

	s3dl := s3manager.NewDownloader(sess)
	_, err := s3dl.Download(buff, &s3.GetObjectInput{
		Bucket: aws.String(bucket),
		Key:    aws.String(path),
	})

	var img image.Image
	img, err = jpeg.Decode(bytes.NewReader(buff.Bytes()))
	if err != nil {
		log.Fatal(err)
	}

    // ここで適当な画像処理できる.

    // 書き出したければこんな感じ
	w, _ := os.Create("hoge.jpeg")
	jpeg.Encode(w, img, &jpeg.Options{Quality: 100})

	return img
}