-
Notifications
You must be signed in to change notification settings - Fork 0
/
images.go
269 lines (226 loc) · 7 KB
/
images.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
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
package imageupsizer
import (
"bytes"
"crypto/tls"
"errors"
"fmt"
"html"
"image"
_ "image/jpeg"
_ "image/png"
"io/ioutil"
"mime/multipart"
"net/http"
"net/url"
"os"
"regexp"
"sort"
"strconv"
"strings"
_ "golang.org/x/image/webp"
)
type ImageData struct {
URL string
Bytes []byte
Extension string
image.Config
Area int
FileSize int64
LocalPath string
}
func uploadImage(filename string) ([]byte, error) {
var file, err = os.Open(filename)
if err != nil {
return nil, fmt.Errorf("error opening file; file: %s, error: %w", filename, err)
}
defer file.Close()
fileContents, err := ioutil.ReadAll(file)
if err != nil {
return nil, fmt.Errorf("error reading image contents; file: %s, error: %w", filename, err)
}
var buf = new(bytes.Buffer)
var writer = multipart.NewWriter(buf)
part, err := writer.CreateFormFile("encoded_image", filename)
if err != nil {
return nil, fmt.Errorf("error creating html form; file: %s, error: %w", filename, err)
}
_, err = part.Write(fileContents)
if err != nil {
return nil, fmt.Errorf("error adding file to form; file: %s, error: %w", filename, err)
}
if err := writer.WriteField("image_url", ""); err != nil {
return nil, fmt.Errorf("error adding form field image_url; file: %s, error: %w", filename, err)
}
if err := writer.WriteField("filename", ""); err != nil {
return nil, fmt.Errorf("error adding form field filename; file: %s, error: %w", filename, err)
}
if err := writer.WriteField("hl", "en"); err != nil {
return nil, fmt.Errorf("error adding form field hl; file: %s, error: %w", filename, err)
}
if err := writer.Close(); err != nil {
return nil, fmt.Errorf("error closing html form writer; file: %s, error: %w", filename, err)
}
req, err := http.NewRequest(http.MethodPost, "https://images.google.com/searchbyimage/upload", buf)
if err != nil {
return nil, fmt.Errorf("error creating http request; file: %s, error: %w", filename, err)
}
req.Header.Add("Content-Type", writer.FormDataContentType())
req.Header.Add("origin", "https://images.google.com/")
req.Header.Add("referer", "https://images.google.com/")
req.Header.Add("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.54 Safari/537.36")
var client = &http.Client{}
resp, err := client.Do(req)
if err != nil {
return nil, fmt.Errorf("error sending http request; file: %s, error: %w", filename, err)
}
defer resp.Body.Close()
contents, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("error reading resp.Body; file: %s, error: %w", filename, err)
}
return contents, nil
}
func getImage(url string) (*ImageData, error) {
var data = &ImageData{}
var httpCient = &http.Client{
Transport: &http.Transport{
TLSClientConfig: &tls.Config{
InsecureSkipVerify: true,
},
},
}
var req, err = http.NewRequest(http.MethodGet, url, nil)
if err != nil {
return nil, fmt.Errorf("error creating http req, url: %s, error: %w", url, err)
}
req.Header.Add("User-Agent", "Mozilla/5.0 (X11; Linux x86_64; rv:101.0) Gecko/20100101 Firefox/101.0")
resp, err := httpCient.Do(req)
if err != nil {
return nil, fmt.Errorf("error making http req, url: %s, error: %w", url, err)
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("error reading resp.Body, url: %s, error: %w", url, err)
}
if resp.StatusCode < 200 || resp.StatusCode > 299 {
return nil, fmt.Errorf("non 2xx resp code: %d, url: %s", resp.StatusCode, url)
}
if strings.HasPrefix(resp.Header.Get("content-type"), "text/html") {
return nil, errors.New("resp was html: " + url)
}
var cp = bytes.NewReader(body)
imageDecode, ext, err := image.DecodeConfig(cp)
if err != nil {
return nil, fmt.Errorf("error decoding image config, length: %d, url: %s, error: %w", len(body), url, err)
}
data.URL = url
data.Bytes = body
data.Extension = ext
data.Config = imageDecode
data.Area = data.Config.Height * data.Config.Width
data.FileSize = int64(len(body))
return data, nil
}
func getImageList(contents []byte) (*ImageData, error) {
var largeImgURL string
var r, err = regexp.Compile(`(/search\?.*?simg:.*?)">`)
if err != nil {
return nil, fmt.Errorf("error compiling regex, error: %w", err)
}
for _, i := range r.FindAllStringSubmatch(string(contents), -1) {
if len(i) < 2 {
continue
}
if strings.Contains(i[1], ",isz:l") {
largeImgURL = "https://google.com" + html.UnescapeString(i[1])
break
}
}
if len(largeImgURL) == 0 && bytes.Contains(contents, []byte("captcha")) {
return nil, ErrCaptcha
} else if len(largeImgURL) == 0 {
return nil, ErrNoLargerAvailable
}
req, err := http.NewRequest(http.MethodGet, largeImgURL, nil)
if err != nil {
return nil, fmt.Errorf("error creating http req, error: %w", err)
}
req.Header.Add("origin", "https://images.google.com/")
req.Header.Add("referer", "https://images.google.com/")
req.Header.Add("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.54 Safari/537.36")
var client = &http.Client{}
resp, err := client.Do(req)
if err != nil {
return nil, fmt.Errorf("error making http req, error: %w", err)
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("error reading resp.Body, error: %w", err)
}
imgInfo, err := regexp.Compile(`\["(https://.*?.)",(\d+),(\d+)\]`)
if err != nil {
return nil, fmt.Errorf("error compiling regex, error: %w", err)
}
var data []*ImageData
for _, i := range imgInfo.FindAllStringSubmatch(string(body), -1) {
if len(i) < 4 {
continue
}
urlUnquote, err := strconv.Unquote("\"" + i[1] + "\"")
if err != nil {
continue
}
imgURL, err := url.Parse(urlUnquote)
if err != nil {
continue
}
imgHeight, err := strconv.Atoi(i[2])
if err != nil {
continue
}
imgWidth, err := strconv.Atoi(i[3])
if err != nil {
continue
}
data = append(data, &ImageData{
URL: imgURL.String(),
Area: imgHeight * imgWidth,
})
}
if len(data) == 0 {
return nil, ErrNoResults
}
sort.Slice(data, func(i, j int) bool {
return data[i].Area > data[j].Area
})
return data[0], nil
}
func GetImageConfigFromFile(filename string) (*ImageData, error) {
var data = new(ImageData)
data.LocalPath = filename
var file, err = os.Open(filename)
if err != nil {
return nil, fmt.Errorf("error opening file: %s, error: %w", filename, err)
}
defer file.Close()
config, ext, err := image.DecodeConfig(file)
if err != nil {
return nil, fmt.Errorf("error decoding image: %s, error: %w", filename, err)
}
imageBody, err := ioutil.ReadAll(file)
if err != nil {
return nil, fmt.Errorf("error reading image contents: %s, error: %w", filename, err)
}
data.Config = config
data.Bytes = imageBody
data.Extension = ext
data.Area = config.Width * config.Height
if stat, err := file.Stat(); err != nil {
return nil, fmt.Errorf("error stat'ing file: %s, error: %w", filename, err)
} else {
data.FileSize = stat.Size()
}
return data, nil
}