From bbe387a1b69f599e0cac5fcbb85e19f8053423ee Mon Sep 17 00:00:00 2001 From: Ambrose Chua Date: Tue, 26 May 2020 17:48:26 +0800 Subject: [PATCH] Add sample thumbnail generation --- cmd/control/control.go | 6 +- cmd/thumbnail/thumbnail.go | 119 +++++++++++++++++++++++++++++++++++++ go.mod | 5 +- go.sum | 20 ++++++- 4 files changed, 146 insertions(+), 4 deletions(-) create mode 100644 cmd/thumbnail/thumbnail.go diff --git a/cmd/control/control.go b/cmd/control/control.go index 194409e..5d94f7b 100644 --- a/cmd/control/control.go +++ b/cmd/control/control.go @@ -19,9 +19,13 @@ func main() { accessKey = os.Getenv("MINIO_ACCESS_KEY") secretKey = os.Getenv("MINIO_SECRET_KEY") + server := &http.Server{ + ReadTimeout: 5 * time.Second, + WriteTimeout: 10 * time.Second, + } http.HandleFunc("/list", hello) http.HandleFunc("/write", hello2) - http.ListenAndServe(":8090", nil) + server.ListenAndServe() } func hello(w http.ResponseWriter, req *http.Request) { diff --git a/cmd/thumbnail/thumbnail.go b/cmd/thumbnail/thumbnail.go new file mode 100644 index 0000000..cbfc4cf --- /dev/null +++ b/cmd/thumbnail/thumbnail.go @@ -0,0 +1,119 @@ +package main + +import ( + "bytes" + "io/ioutil" + "log" + "net/http" + "os" + "time" + + "github.com/davidbyttow/govips/pkg/vips" + "github.com/minio/minio-go/v6" +) + +var client *http.Client +var minioClient *minio.Client + +const maxAspectRatio = 6 + +var accessKey string +var secretKey string +var endpoint string +var endpointSecure bool + +func main() { + // Read configuration + accessKey = os.Getenv("MINIO_ACCESS_KEY") + secretKey = os.Getenv("MINIO_SECRET_KEY") + endpoint = os.Getenv("MINIO_ENDPOINT") + endpointSecure = os.Getenv("MINIO_ENDPOINT_SECURE") == "true" + + // Setup HTTP client + transport := &http.Transport{ + MaxIdleConns: 4, + MaxIdleConnsPerHost: 4, + IdleConnTimeout: 30 * time.Second, + DisableCompression: true, + } + client = &http.Client{ + Transport: transport, + Timeout: 5 * time.Second, + } + // Setup minio client + var err error + minioClient, err = minio.New(endpoint, accessKey, secretKey, endpointSecure) + if err != nil { + panic(err) + } + // Setup vips + vips.Startup(nil) + defer vips.Shutdown() + + buf, err := fetch("https://huge.makerforce.io/pub/MVIMG_20200320_154434.jpg") + if err != nil { + panic(err) + } + + start := time.Now() + resizedBufWEBP, err := resize(buf, vips.ImageTypeWEBP, 320, 70) + end := time.Now() + if err != nil { + panic(err) + } + log.Println("passed", end.Sub(start)) + + start = time.Now() + resizedBufJPEG, err := resize(buf, vips.ImageTypeJPEG, 320, 75) + end = time.Now() + if err != nil { + panic(err) + } + log.Println("passed", end.Sub(start)) + + err = save(resizedBufWEBP, "pub", "out.webp", "image/webp") + if err != nil { + panic(err) + } + + err = save(resizedBufJPEG, "pub", "out.jpg", "image/jpeg") + if err != nil { + panic(err) + } +} + +func fetch(url string) ([]byte, error) { + resp, err := client.Get(url) + if err != nil { + return nil, err + } + defer resp.Body.Close() + return ioutil.ReadAll(resp.Body) +} + +func resize(buf []byte, format vips.ImageType, height, quality int) ([]byte, error) { + i, err := vips.NewImageFromBuffer(buf) + if err != nil { + return nil, err + } + defer i.Close() + + scale := float64(height) / float64(i.Height()) + err = i.Resize(scale) + if err != nil { + return nil, err + } + outBuf, _, err := i.Export(vips.ExportParams{ + Format: format, + Quality: quality, + }) + return outBuf, err +} + +func save(buf []byte, bucket, key, contentType string) error { + _, err := minioClient.PutObject(bucket, key, bytes.NewBuffer(buf), int64(len(buf)), minio.PutObjectOptions{ + ContentType: contentType, + StorageClass: "REDUCED_REDUNDANCY", + }) + return err +} diff --git a/go.mod b/go.mod index 91105f7..5b41fc0 100644 --- a/go.mod +++ b/go.mod @@ -2,4 +2,7 @@ module git.makerforce.io/photos/photos go 1.14 -require github.com/minio/minio-go/v6 v6.0.55 +require ( + github.com/davidbyttow/govips v0.0.0-20200412130214-cbefdd8c639a + github.com/minio/minio-go/v6 v6.0.55 +) diff --git a/go.sum b/go.sum index 83a7e18..d76310e 100644 --- a/go.sum +++ b/go.sum @@ -1,35 +1,51 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davidbyttow/govips v0.0.0-20200412130214-cbefdd8c639a h1:g1X1c43wACmPtvFo+szBy/0coLkRwVJ0+i2f6YJITto= +github.com/davidbyttow/govips v0.0.0-20200412130214-cbefdd8c639a/go.mod h1:a3qO525EPfJNYa0NXBcNtXzJvyQsJAxphEDa7OOHPBk= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/minio/minio-go v1.0.0 h1:ooSujki+Z1PRGZsYffJw5jnF5eMBvzMVV86TLAlM0UM= -github.com/minio/minio-go v3.0.2+incompatible h1:TgjYEriSwSpcawLVPw4LpkENIJdqqtVwkyMEnNapZ8w= github.com/minio/minio-go/v6 v6.0.55 h1:Hqm41952DdRNKXM+6hCnPXCsHCYSgLf03iuYoxJG2Wk= github.com/minio/minio-go/v6 v6.0.55/go.mod h1:KQMM+/44DSlSGSQWSfRrAZ12FVMmpWNuX37i2AX0jfI= github.com/minio/sha256-simd v0.1.1 h1:5QHSlgo3nt5yKOJrC7W8w7X+NFl8cMPZm96iu8kKUJU= github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/sirupsen/logrus v1.5.0/go.mod h1:+F7Ogzej0PZc/94MaYx/nvG9jOFMD2osvC3s+Squfpo= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a h1:pa8hGb/2YqsZKovtsgrwcDH1RZhVbTKCjLp47XpqCDs= github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190513172903-22d7a77e9e5f h1:R423Cnkcp5JABoeemiGEPlt9tHXFfw5kvc0yqlxRPWo= golang.org/x/crypto v0.0.0-20190513172903-22d7a77e9e5f/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190522155817-f3200d17e092 h1:4QSRKanuywn15aTZvI/mIDEgPQpswuFndXpOj3rKEco= golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894 h1:Cz4ceDQGXuKRnVBDTS23GTn/pU5OE2C0WrNTOYK1Uuc= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +gopkg.in/ini.v1 v1.42.0 h1:7N3gPTt50s8GuLortA00n8AqRTk75qOP98+mTPpgzRk= gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=