Skip to content
This repository was archived by the owner on May 25, 2023. It is now read-only.

Commit 17308de

Browse files
committed
Make use of the image service to serve thumbnails.
1 parent e8693c1 commit 17308de

File tree

3 files changed

+29
-358
lines changed

3 files changed

+29
-358
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
.DS_Store
2+
*.pyc
23
node_modules

server/gae-go/app/main.go

Lines changed: 28 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* jQuery File Upload Plugin GAE Go Example 2.0
2+
* jQuery File Upload Plugin GAE Go Example 2.1
33
* https://github.com/blueimp/jQuery-File-Upload
44
*
55
* Copyright 2011, Sebastian Tschan
@@ -14,37 +14,29 @@ package app
1414
import (
1515
"appengine"
1616
"appengine/blobstore"
17-
"appengine/memcache"
17+
"appengine/image"
1818
"appengine/taskqueue"
1919
"bytes"
20-
"encoding/base64"
2120
"encoding/json"
2221
"fmt"
23-
"image"
24-
"image/png"
2522
"io"
2623
"log"
2724
"mime/multipart"
2825
"net/http"
2926
"net/url"
3027
"regexp"
31-
"resize"
3228
"strings"
3329
"time"
3430
)
3531

36-
import _ "image/gif"
37-
import _ "image/jpeg"
38-
3932
const (
40-
WEBSITE = "http://blueimp.github.com/jQuery-File-Upload/"
41-
MIN_FILE_SIZE = 1 // bytes
42-
MAX_FILE_SIZE = 5000000 // bytes
43-
IMAGE_TYPES = "image/(gif|p?jpeg|(x-)?png)"
44-
ACCEPT_FILE_TYPES = IMAGE_TYPES
45-
EXPIRATION_TIME = 300 // seconds
46-
THUMBNAIL_MAX_WIDTH = 80
47-
THUMBNAIL_MAX_HEIGHT = THUMBNAIL_MAX_WIDTH
33+
WEBSITE = "http://blueimp.github.com/jQuery-File-Upload/"
34+
MIN_FILE_SIZE = 1 // bytes
35+
MAX_FILE_SIZE = 5000000 // bytes
36+
IMAGE_TYPES = "image/(gif|p?jpeg|(x-)?png)"
37+
ACCEPT_FILE_TYPES = IMAGE_TYPES
38+
EXPIRATION_TIME = 300 // seconds
39+
THUMBNAIL_PARAM = "=s80"
4840
)
4941

5042
var (
@@ -94,49 +86,19 @@ func (fi *FileInfo) CreateUrls(r *http.Request, c appengine.Context) {
9486
escape(string(fi.Name))
9587
fi.DeleteUrl = fi.Url
9688
fi.DeleteType = "DELETE"
97-
if fi.ThumbnailUrl != "" && -1 == strings.Index(
98-
r.Header.Get("Accept"),
99-
"application/json",
100-
) {
101-
fi.ThumbnailUrl = uString + "thumbnails/" +
102-
escape(string(fi.Key))
103-
}
104-
}
105-
106-
func (fi *FileInfo) CreateThumbnail(r io.Reader, c appengine.Context) (data []byte, err error) {
107-
defer func() {
108-
if rec := recover(); rec != nil {
109-
log.Println(rec)
110-
// 1x1 pixel transparent GIf, bas64 encoded:
111-
s := "R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="
112-
data, _ = base64.StdEncoding.DecodeString(s)
113-
fi.ThumbnailUrl = "data:image/gif;base64," + s
114-
}
115-
memcache.Add(c, &memcache.Item{
116-
Key: string(fi.Key),
117-
Value: data,
118-
Expiration: EXPIRATION_TIME,
119-
})
120-
}()
121-
img, _, err := image.Decode(r)
122-
check(err)
123-
if bounds := img.Bounds(); bounds.Dx() > THUMBNAIL_MAX_WIDTH ||
124-
bounds.Dy() > THUMBNAIL_MAX_HEIGHT {
125-
w, h := THUMBNAIL_MAX_WIDTH, THUMBNAIL_MAX_HEIGHT
126-
if bounds.Dx() > bounds.Dy() {
127-
h = bounds.Dy() * h / bounds.Dx()
128-
} else {
129-
w = bounds.Dx() * w / bounds.Dy()
130-
}
131-
img = resize.Resize(img, img.Bounds(), w, h)
89+
if imageTypes.MatchString(fi.Type) {
90+
servingUrl, err := image.ServingURL(
91+
c,
92+
fi.Key,
93+
&image.ServingURLOptions{
94+
Secure: strings.HasSuffix(u.Scheme, "s"),
95+
Size: 0,
96+
Crop: false,
97+
},
98+
)
99+
check(err)
100+
fi.ThumbnailUrl = servingUrl.String() + THUMBNAIL_PARAM
132101
}
133-
var b bytes.Buffer
134-
err = png.Encode(&b, img)
135-
check(err)
136-
data = b.Bytes()
137-
fi.ThumbnailUrl = "data:image/png;base64," +
138-
base64.StdEncoding.EncodeToString(data)
139-
return
140102
}
141103

142104
func check(err error) {
@@ -174,7 +136,6 @@ func handleUpload(r *http.Request, p *multipart.Part) (fi *FileInfo) {
174136
fi.Error = rec.(error).Error()
175137
}
176138
}()
177-
var b bytes.Buffer
178139
lr := &io.LimitedReader{R: p, N: MAX_FILE_SIZE + 1}
179140
context := appengine.NewContext(r)
180141
w, err := blobstore.Create(context, fi.Type)
@@ -189,17 +150,10 @@ func handleUpload(r *http.Request, p *multipart.Part) (fi *FileInfo) {
189150
return
190151
}
191152
delayedDelete(context, fi)
192-
if b.Len() > 0 {
193-
fi.CreateThumbnail(&b, context)
194-
}
195153
fi.CreateUrls(r, context)
196154
}()
197155
check(err)
198-
var wr io.Writer = w
199-
if imageTypes.MatchString(fi.Type) {
200-
wr = io.MultiWriter(&b, w)
201-
}
202-
_, err = io.Copy(wr, lr)
156+
_, err = io.Copy(w, lr)
203157
return
204158
}
205159

@@ -253,7 +207,7 @@ func get(w http.ResponseWriter, r *http.Request) {
253207
fmt.Sprintf("attachment; filename=%s;", parts[2]),
254208
)
255209
}
256-
blobstore.Send(w, appengine.BlobKey(key))
210+
blobstore.Send(w, blobKey)
257211
return
258212
}
259213
}
@@ -285,48 +239,12 @@ func delete(w http.ResponseWriter, r *http.Request) {
285239
}
286240
if key := parts[1]; key != "" {
287241
c := appengine.NewContext(r)
288-
blobstore.Delete(c, appengine.BlobKey(key))
289-
memcache.Delete(c, key)
290-
}
291-
}
292-
293-
func serveThumbnail(w http.ResponseWriter, r *http.Request) {
294-
parts := strings.Split(r.URL.Path, "/")
295-
if len(parts) == 3 {
296-
if key := parts[2]; key != "" {
297-
var data []byte
298-
c := appengine.NewContext(r)
299-
item, err := memcache.Get(c, key)
300-
if err == nil {
301-
data = item.Value
302-
} else {
303-
blobKey := appengine.BlobKey(key)
304-
if _, err = blobstore.Stat(c, blobKey); err == nil {
305-
fi := FileInfo{Key: blobKey}
306-
data, _ = fi.CreateThumbnail(
307-
blobstore.NewReader(c, blobKey),
308-
c,
309-
)
310-
}
311-
}
312-
if err == nil && len(data) > 3 {
313-
w.Header().Add(
314-
"Cache-Control",
315-
fmt.Sprintf("public,max-age=%d", EXPIRATION_TIME),
316-
)
317-
contentType := "image/png"
318-
if string(data[:3]) == "GIF" {
319-
contentType = "image/gif"
320-
} else if string(data[1:4]) != "PNG" {
321-
contentType = "image/jpeg"
322-
}
323-
w.Header().Set("Content-Type", contentType)
324-
fmt.Fprintln(w, string(data))
325-
return
326-
}
327-
}
242+
blobKey := appengine.BlobKey(key)
243+
err := blobstore.Delete(c, blobKey)
244+
check(err)
245+
err = image.DeleteServingURL(c, blobKey)
246+
check(err)
328247
}
329-
http.Error(w, "404 Not Found", http.StatusNotFound)
330248
}
331249

332250
func handle(w http.ResponseWriter, r *http.Request) {
@@ -357,5 +275,4 @@ func handle(w http.ResponseWriter, r *http.Request) {
357275

358276
func init() {
359277
http.HandleFunc("/", handle)
360-
http.HandleFunc("/thumbnails/", serveThumbnail)
361278
}

0 commit comments

Comments
 (0)