/
thumbnail.go
144 lines (121 loc) · 2.97 KB
/
thumbnail.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
139
140
141
142
143
144
package annote
import (
"errors"
"io"
"io/ioutil"
"log"
"os"
"os/exec"
"path/filepath"
)
// Code to create thumbnail images for files.
//
type Thumbnail struct {
Source *Store
item string
imagefile string
thumbdir string
}
var (
ErrNoContent = errors.New("No content")
)
// Scale down srcImage to fit the 800x600px bounding box.
//dstImageFit := imaging.Fit(srcImage, 800, 600, imaging.Lanczos)
// DoPDF will read the given content file from the store, create a
// thumbnail, and then copy it back into the store under the key
// "$item-thumbnail"
func (t *Thumbnail) DoPDF(item string) error {
t.item = item
itempath := t.Source.Find(item)
if itempath == "" {
return ErrNoContent
}
tmpfile, err := t.pdf2png(itempath)
if tmpfile != "" {
defer os.Remove(tmpfile)
}
if err != nil {
return err
}
return t.image2thumb(tmpfile)
}
func (t *Thumbnail) DoImage(item string) error {
t.item = item
itempath := t.Source.Find(item)
if itempath == "" {
return ErrNoContent
}
return t.image2thumb(itempath)
}
func (t *Thumbnail) pdf2png(sourceFilename string) (string, error) {
tmpfile, err := ioutil.TempFile("", "annote-pdf.*.png")
if err != nil {
return "", err
}
tmpfile.Close()
cmd := exec.Command("gs",
"-sDEVICE=png16m",
"-sPageList=1",
"-dUseCropBox",
"-r300",
"-o", tmpfile.Name(),
sourceFilename,
)
// run and wait for command to finish
output, err := cmd.CombinedOutput()
if err != nil {
log.Println("PDF to PNG", err)
log.Println(string(output))
os.Remove(tmpfile.Name())
return "", err
}
return tmpfile.Name(), nil
}
// image2thumb creates a thumbnail for the given file and then saves it into the store t has under the key "$item-thumbnail".
func (t *Thumbnail) image2thumb(sourceFilename string) error {
tmpdir, err := ioutil.TempDir("", "annote-thumb")
if err != nil {
return err
}
defer os.RemoveAll(tmpdir)
// this command is lifted from
// https://www.smashingmagazine.com/2015/06/efficient-image-resizing-with-imagemagick/
cmd := exec.Command("mogrify",
"-path", tmpdir,
"-filter", "Triangle",
"-define", "filter:support=2",
"-thumbnail", "338", // width curate uses
"-unsharp", "0.25x0.08+8.3+0.045",
"-dither", "None",
"-posterize", "136",
"-quality", "82",
"-define", "jpeg:fancy-upsampling=off",
"-define", "png:compression-filter=5",
"-define", "png:compression-level=9",
"-define", "png:compression-strategy=1",
"-define", "png:exclude-chunk=all",
"-interlace", "none",
"-colorspace", "sRGB",
sourceFilename,
)
// run and wait for command to finish
output, err := cmd.CombinedOutput()
if err != nil {
log.Println("PNG to Thumbnail", err)
log.Println(string(output))
return err
}
// now copy the file into the store
w, err := t.Source.Create(t.item + "-thumbnail")
if err != nil {
return err
}
defer w.Close()
r, err := os.Open(filepath.Join(tmpdir, filepath.Base(sourceFilename)))
if err != nil {
return err
}
defer r.Close()
_, err = io.Copy(w, r)
return err
}