jlelse
/
hugo-micropub
Archived
1
Fork 0
This repository has been archived on 2020-09-14. You can view files and clone it, but cannot push or open issues or pull requests.
hugo-micropub/imagecompression.go

141 lines
3.0 KiB
Go

package main
import (
"bytes"
"encoding/json"
"errors"
"io"
"io/ioutil"
"net/http"
"os"
"sort"
"strings"
)
type ImageCompression interface {
Compress(url string) (location string, err error)
}
// Tinify
type Tinify struct {
// API Key
key string
}
func (t *Tinify) Compress(url string) (location string, err error) {
fileExtension := func() string {
spliced := strings.Split(url, ".")
return spliced[len(spliced)-1]
}()
supportedTypes := []string{"jpg", "jpeg", "png"}
sort.Strings(supportedTypes)
i := sort.SearchStrings(supportedTypes, strings.ToLower(fileExtension))
if !(i < len(supportedTypes) && supportedTypes[i] == strings.ToLower(fileExtension)) {
err = errors.New("file not supported")
return
}
// Shrink
shrinkedUrl, e := t.shrink(url)
if e != nil {
err = errors.New("failed to compress file")
return
}
// Create temp file
file, e := ioutil.TempFile("", "tiny-*."+fileExtension)
if e != nil {
err = errors.New("failed to create temporary file")
return
}
defer func() {
// Cleanup
_ = file.Close()
_ = os.Remove(file.Name())
}()
// Resize and download image
e = t.resize(shrinkedUrl, file)
if e != nil {
err = errors.New("failed to resize file or save compressed file")
return
}
hashFile, e := os.Open(file.Name())
defer func() { _ = hashFile.Close() }()
if e != nil {
err = errors.New("failed to open temporary file")
return
}
fileName, err := getSHA256(hashFile)
if err != nil {
return
}
location, err = SelectedMediaStorage.Upload(fileName+"."+fileExtension, file)
return
}
func (t *Tinify) shrink(source string) (string, error) {
type Source struct {
Url string `json:"url"`
}
data := struct {
Source Source `json:"source"`
}{
Source: Source{
Url: source,
},
}
body := new(bytes.Buffer)
err := json.NewEncoder(body).Encode(data)
if err != nil {
return "", err
}
req, err := http.NewRequest("POST", "https://api.tinify.com/shrink", body)
if err != nil {
return "", err
}
req.SetBasicAuth("api", t.key)
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
return "", err
}
if resp.StatusCode != 201 {
return "", errors.New("not 201 response code")
}
return resp.Header.Get("Location"), nil
}
func (t *Tinify) resize(output string, file *os.File) error {
type Resize struct {
Method string `json:"method"`
Width int `json:"width"`
}
data := struct {
Resize Resize `json:"resize"`
}{
Resize: Resize{
Method: "scale",
Width: 2000,
},
}
body := new(bytes.Buffer)
err := json.NewEncoder(body).Encode(data)
if err != nil {
return err
}
req, err := http.NewRequest("POST", output, body)
if err != nil {
return err
}
req.SetBasicAuth("api", t.key)
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
if resp.StatusCode != 200 {
return errors.New("not 201 response code")
}
defer resp.Body.Close()
_, err = io.Copy(file, resp.Body)
return err
}