├── .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 |
11 | 12 | 13 |
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 |
33 | GET /all-images Get list of all image. 34 |
35 |
GET /upload Upload image UI.
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 | --------------------------------------------------------------------------------