Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit311df38

Browse files
committed
initial commit
0 parents  commit311df38

File tree

9 files changed

+364
-0
lines changed

9 files changed

+364
-0
lines changed

‎.gitignore‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
main

‎Makefile‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
run:
2+
go run*.go -o ./tmp
3+
build:
4+
go build -o image-compressor

‎README.md‎

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
#Image Compressor API
2+
3+
##Overview
4+
5+
Image Compressor API is a simple HTTP service written in Go that allows you to compress and resize images from a given URL. It supports popular image formats such as JPEG, PNG, and WebP.
6+
7+
##Features
8+
9+
- Image compression and resizing based on provided parameters.
10+
- Automatic determination of the image format based on the URL's content type.
11+
- Support for JPEG, PNG, and WebP output formats.
12+
- Option to specify output quality and resolution.
13+
- Efficient caching: If the compressed image already exists, it is served without re-compression.
14+
15+
##Getting Started
16+
17+
###Prerequisites
18+
19+
- Go (Golang) installed on your machine.
20+
-[mux](https://github.com/gorilla/mux),[nfnt/resize](https://github.com/nfnt/resize), and[chai2010/webp](https://github.com/chai2010/webp) Go packages.
21+
22+
###Installation
23+
24+
1. Clone the repository:
25+
26+
```bash
27+
git clone https://github.com/yourusername/your-repo.git
28+
cd your-repo
29+
```
30+
31+
2. Install dependencies:
32+
33+
```bash
34+
go get -u github.com/gorilla/mux
35+
go get -u github.com/nfnt/resize
36+
go get -u github.com/chai2010/webp
37+
```
38+
39+
3. Build and run the project:
40+
41+
```bash
42+
go run*.go -o ./tmp
43+
```
44+
45+
Alternatively, for a production build:
46+
47+
```bash
48+
go build -o image-compressor
49+
./image-compressor -o ./tmp
50+
```
51+
52+
###Usage
53+
54+
To compress an image, make a GET request to the`/compressor` endpoint with the following parameters:
55+
56+
-`url`: URL of the image to be compressed.
57+
-`output`: Desired output format (e.g., "jpeg", "png", "webp").
58+
-`quality`: Output quality (0-100, applicable for JPEG).
59+
-`resolution`: Output resolution in the format "widthxheight" (e.g., "1024x720").
60+
61+
Example:
62+
63+
```bash
64+
curl"http://localhost:8080/compressor?url=https://example.com/image.jpg&output=webp&quality=80&resolution=1024x720"
65+
```
66+
67+
##API Endpoints
68+
69+
###`/compressor`
70+
71+
-**Method:** GET
72+
-**Parameters:**
73+
-`url` (required): URL of the image to be compressed.
74+
-`output` (optional): Desired output format (e.g., "jpeg", "png", "webp").
75+
-`quality` (optional): Output quality (0-100, applicable for JPEG).
76+
-`resolution` (optional): Output resolution in the format "widthxheight" (e.g., "1024x720").
77+
78+
Example:
79+
80+
```bash
81+
curl"http://localhost:8080/compressor?url=https://example.com/image.jpg&output=webp&quality=80&resolution=1024x720"
82+
```
83+
84+
##License
85+
86+
This project is licensed under the[MIT License](LICENSE).

‎go.mod‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
modulegithub.com/daniwebdev/image-compressor-api
2+
3+
go1.20
4+
5+
require (
6+
github.com/chai2010/webpv1.1.1// indirect
7+
github.com/gorilla/muxv1.8.1// indirect
8+
github.com/nfnt/resizev0.0.0-20180221191011-83c6a9932646// indirect
9+
)

‎go.sum‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
github.com/chai2010/webpv1.1.1 h1:jTRmEccAJ4MGrhFOrPMpNGIJ/eybIgwKpcACsrTEapk=
2+
github.com/chai2010/webpv1.1.1/go.mod h1:0XVwvZWdjjdxpUEIf7b9g9VkHFnInUSYujwqTLEuldU=
3+
github.com/gorilla/muxv1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
4+
github.com/gorilla/muxv1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
5+
github.com/nfnt/resizev0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ=
6+
github.com/nfnt/resizev0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8=

‎image-compressor‎

8.75 MB
Binary file not shown.

‎main.go‎

Lines changed: 255 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,255 @@
1+
package main
2+
3+
import (
4+
"crypto/md5"
5+
"encoding/hex"
6+
"flag"
7+
"fmt"
8+
"image"
9+
"image/jpeg"
10+
"image/png"
11+
"io"
12+
"net/http"
13+
"os"
14+
"path/filepath"
15+
"strings"
16+
17+
"github.com/chai2010/webp"
18+
"github.com/gorilla/mux"
19+
"github.com/nfnt/resize"
20+
)
21+
22+
varoutputDirectorystring
23+
24+
funcinit() {
25+
flag.StringVar(&outputDirectory,"o",".","Output directory for compressed images")
26+
flag.Parse()
27+
}
28+
29+
funcdownloadImage(urlstring) (image.Image,string,error) {
30+
resp,err:=http.Get(url)
31+
iferr!=nil {
32+
returnnil,"",err
33+
}
34+
deferresp.Body.Close()
35+
36+
varimg image.Image
37+
varformatstring
38+
39+
// Determine the image format based on content type
40+
contentType:=resp.Header.Get("Content-Type")
41+
switch {
42+
casestrings.Contains(contentType,"jpeg"):
43+
img,_,err=image.Decode(resp.Body)
44+
format="jpeg"
45+
casestrings.Contains(contentType,"png"):
46+
img,_,err=image.Decode(resp.Body)
47+
format="png"
48+
casestrings.Contains(contentType,"webp"):
49+
img,err=webp.Decode(resp.Body)
50+
format="webp"
51+
default:
52+
returnnil,"",fmt.Errorf("unsupported image format")
53+
}
54+
55+
iferr!=nil {
56+
returnnil,"",err
57+
}
58+
59+
returnimg,format,nil
60+
}
61+
62+
funccompressImage(img image.Image,format,outputstring,qualityint,resolutionstring)error {
63+
// Resize the image if resolution is provided
64+
ifresolution!="" {
65+
size:=strings.Split(resolution,"x")
66+
width,height:=parseResolution(size[0],size[1],img.Bounds().Dx(),img.Bounds().Dy())
67+
img=resize.Resize(width,height,img,resize.Lanczos3)
68+
}
69+
70+
// Create the output file in the specified directory
71+
out,err:=os.Create(filepath.Join(outputDirectory,output))
72+
iferr!=nil {
73+
returnerr
74+
}
75+
deferout.Close()
76+
77+
// Compress and save the image in the specified format
78+
switchformat {
79+
case"jpeg":
80+
options:= jpeg.Options{Quality:quality}
81+
err=jpeg.Encode(out,img,&options)
82+
case"png":
83+
encoder:= png.Encoder{CompressionLevel:png.BestCompression}
84+
err=encoder.Encode(out,img)
85+
case"webp":
86+
options:=&webp.Options{Lossless:true}
87+
err=webp.Encode(out,img,options)
88+
default:
89+
returnfmt.Errorf("unsupported output format")
90+
}
91+
92+
iferr!=nil {
93+
returnerr
94+
}
95+
96+
returnnil
97+
}
98+
99+
funcgenerateMD5Hash(inputstring)string {
100+
hasher:=md5.New()
101+
hasher.Write([]byte(input))
102+
returnhex.EncodeToString(hasher.Sum(nil))
103+
}
104+
105+
funcatoi(sstring)int {
106+
result:=0
107+
for_,c:=ranges {
108+
result=result*10+int(c-'0')
109+
}
110+
returnresult
111+
}
112+
113+
funcparseResolution(width,heightstring,originalWidth,originalHeightint) (uint,uint) {
114+
varnewWidth,newHeightuint
115+
116+
ifwidth=="auto"&&height=="auto" {
117+
// If both dimensions are "auto," maintain the original size
118+
newWidth=uint(originalWidth)
119+
newHeight=uint(originalHeight)
120+
}elseifwidth=="auto" {
121+
// If width is "auto," calculate height maintaining the aspect ratio
122+
ratio:=float64(originalWidth)/float64(originalHeight)
123+
newHeight=uint(atoi(height))
124+
newWidth=uint(float64(newHeight)*ratio)
125+
}elseifheight=="auto" {
126+
// If height is "auto," calculate width maintaining the aspect ratio
127+
ratio:=float64(originalHeight)/float64(originalWidth)
128+
newWidth=uint(atoi(width))
129+
newHeight=uint(float64(newWidth)*ratio)
130+
}else {
131+
// Use the provided width and height
132+
newWidth=uint(atoi(width))
133+
newHeight=uint(atoi(height))
134+
}
135+
136+
returnnewWidth,newHeight
137+
}
138+
139+
funccompressHandler(w http.ResponseWriter,r*http.Request) {
140+
url:=r.URL.Query().Get("url")
141+
format:=r.URL.Query().Get("output")
142+
quality:=r.URL.Query().Get("quality")
143+
resolution:=r.URL.Query().Get("resolution")
144+
145+
// Concatenate parameters into a single string
146+
paramsString:=fmt.Sprintf("%s-%s-%s-%s",url,format,quality,resolution)
147+
148+
// Generate MD5 hash from the concatenated parameters
149+
hash:=generateMD5Hash(paramsString)
150+
151+
// Generate the output filename using the hash and format
152+
output:=fmt.Sprintf("%s.%s",hash,format)
153+
154+
// Check if the compressed file already exists in the output directory
155+
filePath:=filepath.Join(outputDirectory,output)
156+
if_,err:=os.Stat(filePath);err==nil {
157+
// File exists, no need to download and compress again
158+
159+
// Open and send the existing compressed image file
160+
compressedFile,err:=os.Open(filePath)
161+
iferr!=nil {
162+
http.Error(w,fmt.Sprintf("Error opening compressed image file: %s",err),http.StatusInternalServerError)
163+
return
164+
}
165+
defercompressedFile.Close()
166+
167+
// Set the appropriate Content-Type based on the output format
168+
varcontentTypestring
169+
switchformat {
170+
case"jpeg":
171+
contentType="image/jpeg"
172+
case"png":
173+
contentType="image/png"
174+
case"webp":
175+
contentType="image/webp"
176+
default:
177+
http.Error(w,"Unsupported output format",http.StatusInternalServerError)
178+
return
179+
}
180+
181+
// Set the Content-Type header
182+
w.Header().Set("Content-Type",contentType)
183+
184+
// Copy the existing compressed image file to the response writer
185+
_,err=io.Copy(w,compressedFile)
186+
iferr!=nil {
187+
http.Error(w,fmt.Sprintf("Error sending compressed image: %s",err),http.StatusInternalServerError)
188+
return
189+
}
190+
191+
return
192+
}
193+
194+
img,imgFormat,err:=downloadImage(url)
195+
iferr!=nil {
196+
http.Error(w,fmt.Sprintf("Error downloading image: %s",err),http.StatusInternalServerError)
197+
return
198+
}
199+
200+
ifformat=="" {
201+
format=imgFormat
202+
}
203+
204+
err=compressImage(img,format,output,atoi(quality),resolution)
205+
iferr!=nil {
206+
http.Error(w,fmt.Sprintf("Error compressing image: %s",err),http.StatusInternalServerError)
207+
return
208+
}
209+
210+
// Set the appropriate Content-Type based on the output format
211+
varcontentTypestring
212+
switchformat {
213+
case"jpeg":
214+
contentType="image/jpeg"
215+
case"png":
216+
contentType="image/png"
217+
case"webp":
218+
contentType="image/webp"
219+
default:
220+
http.Error(w,"Unsupported output format",http.StatusInternalServerError)
221+
return
222+
}
223+
224+
// Set the Content-Type header
225+
w.Header().Set("Content-Type",contentType)
226+
227+
// Open and send the compressed image file
228+
compressedFile,err:=os.Open(filePath)
229+
iferr!=nil {
230+
http.Error(w,fmt.Sprintf("Error opening compressed image file: %s",err),http.StatusInternalServerError)
231+
return
232+
}
233+
defercompressedFile.Close()
234+
235+
// Copy the compressed image file to the response writer
236+
_,err=io.Copy(w,compressedFile)
237+
iferr!=nil {
238+
http.Error(w,fmt.Sprintf("Error sending compressed image: %s",err),http.StatusInternalServerError)
239+
return
240+
}
241+
fmt.Fprintf(w,"Image compressed and saved to %s\n",filePath)
242+
}
243+
244+
245+
246+
funcmain() {
247+
r:=mux.NewRouter()
248+
r.HandleFunc("/compressor",compressHandler).Methods("GET")
249+
r.HandleFunc("/compressor/{filename}",compressHandler).Methods("GET")
250+
251+
http.Handle("/",r)
252+
253+
fmt.Printf("Server is listening on :8080. Output directory: %s\n",outputDirectory)
254+
http.ListenAndServe(":8080",nil)
255+
}

‎tmp/.gitignore‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
*
2+
!README.md
3+
!.gitignore

‎tmp/README.md‎

Whitespace-only changes.

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp