forked from discord/lilliput
-
Notifications
You must be signed in to change notification settings - Fork 1
/
main.go
138 lines (114 loc) · 3.6 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
package main
import (
"flag"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"strings"
"time"
"github.com/discordapp/lilliput"
)
var EncodeOptions = map[string]map[int]int{
".jpeg": map[int]int{lilliput.JpegQuality: 85},
".png": map[int]int{lilliput.PngCompression: 7},
".webp": map[int]int{lilliput.WebpQuality: 85},
}
func main() {
var inputFilename string
var outputWidth int
var outputHeight int
var outputFilename string
var stretch bool
flag.StringVar(&inputFilename, "input", "", "name of input file to resize/transcode")
flag.StringVar(&outputFilename, "output", "", "name of output file, also determines output type")
flag.IntVar(&outputWidth, "width", 0, "width of output file")
flag.IntVar(&outputHeight, "height", 0, "height of output file")
flag.BoolVar(&stretch, "stretch", false, "perform stretching resize instead of cropping")
flag.Parse()
if inputFilename == "" {
fmt.Printf("No input filename provided, quitting.\n")
flag.Usage()
os.Exit(1)
}
// decoder wants []byte, so read the whole file into a buffer
inputBuf, err := ioutil.ReadFile(inputFilename)
if err != nil {
fmt.Printf("failed to read input file, %s\n", err)
os.Exit(1)
}
decoder, err := lilliput.NewDecoder(inputBuf)
// this error reflects very basic checks,
// mostly just for the magic bytes of the file to match known image formats
if err != nil {
fmt.Printf("error decoding image, %s\n", err)
os.Exit(1)
}
defer decoder.Close()
header, err := decoder.Header()
// this error is much more comprehensive and reflects
// format errors
if err != nil {
fmt.Printf("error reading image header, %s\n", err)
os.Exit(1)
}
// print some basic info about the image
fmt.Printf("file type: %s\n", decoder.Description())
fmt.Printf("%dpx x %dpx\n", header.Width(), header.Height())
if decoder.Duration() != 0 {
fmt.Printf("duration: %.2f s\n", float64(decoder.Duration())/float64(time.Second))
}
// get ready to resize image,
// using 8192x8192 maximum resize buffer size
ops := lilliput.NewImageOps(8192)
defer ops.Close()
// create a buffer to store the output image, 50MB in this case
outputImg := make([]byte, 50*1024*1024)
// use user supplied filename to guess output type if provided
// otherwise don't transcode (use existing type)
outputType := "." + strings.ToLower(decoder.Description())
if outputFilename != "" {
outputType = filepath.Ext(outputFilename)
}
if outputWidth == 0 {
outputWidth = header.Width()
}
if outputHeight == 0 {
outputHeight = header.Height()
}
resizeMethod := lilliput.ImageOpsFit
if stretch {
resizeMethod = lilliput.ImageOpsResize
}
if outputWidth == header.Width() && outputHeight == header.Height() {
resizeMethod = lilliput.ImageOpsNoResize
}
opts := &lilliput.ImageOptions{
FileType: outputType,
Width: outputWidth,
Height: outputHeight,
ResizeMethod: resizeMethod,
NormalizeOrientation: true,
EncodeOptions: EncodeOptions[outputType],
}
// resize and transcode image
outputImg, err = ops.Transform(decoder, opts, outputImg)
if err != nil {
fmt.Printf("error transforming image, %s\n", err)
os.Exit(1)
}
// image has been resized, now write file out
if outputFilename == "" {
outputFilename = "resized" + filepath.Ext(inputFilename)
}
if _, err := os.Stat(outputFilename); !os.IsNotExist(err) {
fmt.Printf("output filename %s exists, quitting\n", outputFilename)
os.Exit(1)
}
err = ioutil.WriteFile(outputFilename, outputImg, 0400)
if err != nil {
fmt.Printf("error writing out resized image, %s\n", err)
os.Exit(1)
}
fmt.Printf("image written to %s\n", outputFilename)
}