├── .gitignore
├── docs
├── original-img.jpg
├── original-img2.jpg
├── original-img-com.jpg
├── original-img1-com.jpg
└── docs.html
├── package.json
├── index.html
├── README.md
└── index.js
/.gitignore:
--------------------------------------------------------------------------------
1 | public
2 | node_modules
3 |
--------------------------------------------------------------------------------
/docs/original-img.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hicodersofficial/image_processing_api/HEAD/docs/original-img.jpg
--------------------------------------------------------------------------------
/docs/original-img2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hicodersofficial/image_processing_api/HEAD/docs/original-img2.jpg
--------------------------------------------------------------------------------
/docs/original-img-com.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hicodersofficial/image_processing_api/HEAD/docs/original-img-com.jpg
--------------------------------------------------------------------------------
/docs/original-img1-com.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hicodersofficial/image_processing_api/HEAD/docs/original-img1-com.jpg
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "image_compression",
3 | "version": "0.0.0",
4 | "author": {
5 | "email": "hicodersoffical@gmail.com",
6 | "name": "Hi Coders"
7 | },
8 | "dependencies": {
9 | "express": "^4.17.2",
10 | "multer": "^1.4.4",
11 | "sharp": "^0.30.1",
12 | "uuid": "^8.3.2"
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Upload form
8 |
9 |
10 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Image processing API
2 |
3 | Resize & compress image from URL.
4 | You can use this API to create different sizes of images.
5 |
6 | ```
7 | $ npm install
8 | ```
9 |
10 | ## Starting App
11 |
12 | ```
13 | $ node index.js
14 | ```
15 |
16 | After starting navigate to http://localhost:5000
17 |
18 | ## **Query Parameter**
19 |
20 | ```
21 | ?q={quality <=100 (Default: 60)}
22 | ?s={image size}
23 | ?w={width}
24 | ?h={height}
25 | ?fit={contain, cover, fill, outside, inside}
26 | ?bg={Background color for cropped area}
27 | ```
28 |
29 | ```
30 | http://localhost:5000/public/{filename}?q=90&s=200&fit=inside
31 | ```
32 |
33 | ## **Screenshots**
34 |
35 | **Original** (1.5 MB) | **Compressed** (75 KB)
36 |
37 |
38 |


39 |
40 |
41 | **Original** (3 MB) | **Compressed** (12 KB)
42 |
43 |
44 |


45 |
46 |
47 |
48 |
49 | ## [Follow Instagram](https://www.instagram.com/hi.coders/)
50 |
51 | ## **Thank You! ❣️**
52 |
--------------------------------------------------------------------------------
/docs/docs.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Docs
8 |
9 |
29 |
30 |
31 | All routes
32 |
35 |
36 |
37 |
POST /upload Upload image. requires FormData with
38 | option "file".
39 |
40 |
41 |
GET /public/{filename.png} Get Single
42 | image. all image.
43 |
Query Parameter
44 |
45 | ?q={quality <=100 (Default: 60)}
46 | ?s={image size}
47 | ?w={width}
48 | ?h={height}
49 | ?fit={contain, cover, fill, outside, inside}
50 | ?bg={Background color for cropped area}
51 |
52 |
53 |
54 |
55 |
56 |

60 | Original (1.5 MB)
61 |
62 |
63 |

67 | Compressed(75 KB)
68 |
69 |
70 |
71 |
72 |
73 |

76 | Original (3 MB)
77 |
78 |
79 |

82 | Compressed(12 KB)
83 |
84 |
85 |
86 |
87 |
88 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | const express = require("express");
2 | const fs = require("fs");
3 | const multer = require("multer");
4 | const path = require("path");
5 | const sharp = require("sharp");
6 | const app = express();
7 | const { v4 } = require("uuid");
8 |
9 | // custom logger (Alt: morgan)
10 | app.use((req, res, next) => {
11 | console.log(req.ip, req.method, req.path, req.headers["user-agent"]);
12 | next();
13 | });
14 |
15 | app.use(express.json());
16 |
17 | app.use("/public/:filename", async (req, res, next) => {
18 | try {
19 | const { filename } = req.params;
20 | let { w, h, q, fit, bg, s } = req.query;
21 |
22 | if (s) {
23 | s = parseInt(s);
24 | if (s > 10000) {
25 | return res.status(400).json({
26 | message: "Invalid size parameter. size must be <=10000",
27 | });
28 | }
29 | }
30 |
31 | if (w) {
32 | w = parseInt(w);
33 | if (w > 10000) {
34 | return res.status(400).json({
35 | message: "Invalid width parameter. width must be <=10000",
36 | });
37 | }
38 | }
39 |
40 | if (h) {
41 | h = parseInt(h);
42 | if (h > 10000) {
43 | return res.status(400).json({
44 | message: "Invalid height parameter. height must be <=10000",
45 | });
46 | }
47 | }
48 |
49 | if (q) {
50 | q = parseInt(q);
51 | if (q > 100) {
52 | return res.status(400).json({
53 | message: "Invalid quality parameter. quality must be <=10000",
54 | });
55 | }
56 | }
57 |
58 | res.setHeader("content-type", "image/jpg");
59 | const image = sharp(`./public/${filename}`).toFormat("jpeg", {
60 | quality: q ? parseInt(q) : 60,
61 | });
62 |
63 | res.send(
64 | await image
65 | .resize(
66 | s
67 | ? s
68 | : h && !w
69 | ? (
70 | await image.metadata()
71 | ).width
72 | : w
73 | ? parseInt(w)
74 | : null,
75 | s
76 | ? s
77 | : w && !h
78 | ? (
79 | await image.metadata()
80 | ).height
81 | : h
82 | ? parseInt(h)
83 | : null,
84 | { fit, background: bg ? "#" + bg : null }
85 | )
86 | .withMetadata()
87 | .toBuffer()
88 | );
89 | } catch (error) {
90 | console.log(error);
91 | res.setHeader("content-type", "application/json");
92 | res
93 | .status(500)
94 | .json({ message: "Internal server error", status: 500, success: false });
95 | }
96 | });
97 |
98 | app.get("/all-images", async (req, res, next) => {
99 | const files = fs
100 | .readdirSync("./public")
101 | .map((file) => ({ url: `http://localhost:5000/public/${file}` }));
102 | const response =
103 | files.length > 0
104 | ? files
105 | : {
106 | message:
107 | "No images found in public directory. Navigate to /upload to upload images images.",
108 | url: "http://localhost:5000/upload",
109 | };
110 | res.json(response);
111 | });
112 |
113 | const uploadMiddleware = multer({
114 | limits: 10_000_000,
115 | storage: multer.diskStorage({
116 | destination: "./public",
117 | filename: function (req, file, cb) {
118 | cb(null, v4() + path.extname(file.originalname));
119 | },
120 | }),
121 | }).single("file");
122 |
123 | app.post("/upload", uploadMiddleware, (req, res, next) => {
124 | console.log(req.files);
125 | res.json({
126 | url: `http://localhost:5000/public/${req.file.filename}`,
127 | message: "success",
128 | });
129 | });
130 |
131 | app.get("/upload", uploadMiddleware, (req, res, next) => {
132 | res.sendFile(path.join(__dirname, "index.html"));
133 | });
134 |
135 | app.get("/", async (req, res, next) => {
136 | res.sendFile(path.join(__dirname, "./docs/docs.html"));
137 | });
138 |
139 | const port = 5000;
140 | app.listen(port, () => {
141 | console.log(`Server running on port ${port}`);
142 | console.log(`http://localhost:${port}`);
143 | });
144 |
--------------------------------------------------------------------------------