-
Notifications
You must be signed in to change notification settings - Fork 16
/
fastimage.go
104 lines (88 loc) · 2.88 KB
/
fastimage.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
package fastimage
import (
"bytes"
"io"
"net/http"
"time"
)
const defaultTimeout = uint(time.Duration(5000) * time.Millisecond)
// DetectImageType is the main function used to detect the type and size
// of a remote image represented by the url.
//
// Only check ImageType and ImageSize if error is not nil.
//
// If you want to set request timeout for uri, use DetectImageTypeWithTimeout() instead.
func DetectImageType(uri string) (ImageType, *ImageSize, error) {
return DetectImageTypeWithTimeout(uri, defaultTimeout)
}
// DetectImageTypeWithTimeout acts same as DetectImageType(),
// except this function takes additional parameter timeout (millisecond)
// for setting request timeout.
//
// If timeout < 1, default timeout 5000 is used.
func DetectImageTypeWithTimeout(uri string, timeout uint) (ImageType, *ImageSize, error) {
logger.Printf("Opening HTTP stream")
client := &http.Client{
Timeout: time.Duration(timeout) * time.Millisecond,
}
resp, err := client.Get(uri)
if err != nil {
return Unknown, nil, err
}
defer closeHTTPStream(resp)
return DetectImageTypeFromResponse(resp)
}
// DetectImageTypeFromResponse is a secondary function used to detect the type
// and size of a remote image represented by the resp.
// This way you can create your own request and then pass it here.
// Check examples from http://golang.org/pkg/net/http/
//
// Only check ImageType and ImageSize if error is not nil.
func DetectImageTypeFromResponse(resp *http.Response) (ImageType, *ImageSize, error) {
logger.Printf("Response content-length: %v bytes", resp.ContentLength)
return DetectImageTypeFromReader(resp.Body)
}
// DetectImageTypeFromReader detects the type and size from a stream of bytes.
//
// Only check ImageType and ImageSize if error is not nil.
func DetectImageTypeFromReader(r io.Reader) (ImageType, *ImageSize, error) {
buffer := bytes.Buffer{}
logger.Printf("Starting operation")
defer logger.Printf("Ended after reading %v bytes", buffer.Len())
for {
err := readToBuffer(r, &buffer)
if err != nil {
logger.Printf("Bailing out because of err %v", err)
return Unknown, nil, err
}
if buffer.Len() < 2 {
continue
}
if buffer.Len() > 20000 {
logger.Println("Type not found until buffer read exceeds 20000 bytes")
return Unknown, nil, err
}
for _, ImageTypeParser := range imageTypeParsers {
if ImageTypeParser.Detect(buffer.Bytes()) {
t := ImageTypeParser.Type()
size, err := ImageTypeParser.GetSize(buffer.Bytes())
if err == nil {
logger.Printf("Found image type %v with size %v", t, size)
return t, size, nil
}
break
}
}
}
}
func readToBuffer(body io.Reader, buffer *bytes.Buffer) error {
chunk := make([]byte, 8)
count, err := body.Read(chunk)
logger.Printf("Read %v bytes", count)
buffer.Write(chunk[:count])
return err
}
func closeHTTPStream(http *http.Response) {
logger.Printf("Closing HTTP Stream")
http.Body.Close()
}