โ ์ฌ๋ฐ๋ก ๋์ํ์ง ์๋๋ผ๋ ๊ฑฑ์ ๋ง์๋ผ. ๋ชจ๋ ๊ฒ์ด ๊ทธ๋ฌ๋ค๋ฉด, ๋ ์ง์ ์ ์์์ํ ๋๊น. โ
- ๋ชจ์ ์ ๋ฒ์น(Mosherโs Law)
์ํํธ์จ์ด ๊ณตํ ๋ด์ฉ

Sharp ๋ชจ๋
๋ ธ๋ ์ง์์๋ ๋ง์ ์ด๋ฏธ์ง ๋ฆฌ์ฌ์ด์ง ํจํค์ง๋ค์ด ์์์ง๋ง, ๋๊น์ง ์ด์๋จ์ ๋ชจ๋์ด shap ์ด๋ค.
์ด๋ฏธ์ง ๋ฆฌ์ฌ์ด์ง ๋์ ์์ฒด๊ฐ cpu์ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ์ก์๋จน๋ ์ฃผ๋ฒ์ด๋ผ, ๊ฐ๋ out of memory๋ก node๊ฐ ์ฃฝ๋ ๊ฒฝ์ฐ๊ฐ ์๊ธฐ ๋๋ฌธ์ด๋ค.
๊ทธ๋ฐ ๊ด์ ์์ sharp ๋ชจ๋์ ๋ฆฌ์ฌ์ด์ง ์๋๋ ๋น ๋ฅด๋ฉฐ ๋ฉ๋ชจ๋ฆฌ๋ ๋ค๋ฅธ ๋์ข
๋ชจ๋ ๋๋น ๋ง์ด ์ก์ ๋จน์ง ์๋๋ค.
Sharp ์ฌ์ฉ๋ฒ
์๋ ๊ณต์ ๋ฌธ์ ํํ์ด์ง์ ๋ค์ด๊ฐ๋ณด๋ฉด ์ต์ ์ ๋ํด ์์ฃผ ์ ์ ๋ฆฌ๋์ด์๋ค.
sharp - High performance Node.js image processing
sharp.pixelplumbing.com
> npm install sharp
sharp ๋ชจ๋ ์ค์น์ ์ฃผ์์ฌํญ โ ๏ธ
sharp๋ OS์ ๋ฐ์ด๋๋ฆฌ๋ฅผ ์ด์ฉํ๊ธฐ ๋๋ฌธ์ ์๋์ฐ, ๋งฅ, ๋ฆฌ๋ ์ค OS์ ๋ฐ๋ผ ์ค์น๋๋ ๋ชจ๋์ด ๋ค๋ฅด๊ฒ ๋๋ค.
๋จ์ํ npm install sharp ๋ช ๋ น์ด๋ฅผ ์คํํ ๊ฒฝ์ฐ ํ์ฌ ๋ด ์ปดํจํฐ์ OS์ CPU ์ํคํ ์ณ ์ฌ์์ ๋ง๊ฒ ์ ์ฉ ๋ฐ์ด๋๋ฆฌ๊ฐ ๋ค์ด๋๊ฒ ๋๋ค.
ํ OS์์ ์ญ ์ฌ์ฉํ ๊ฒ์ด๋ฉด ๋ฌธ์ ๋ ์์ง๋ง ๋ง์ผ node_modules๋ฅผ ๊ทธ๋๋ก ๋ฆฌ๋ ์ค ์๋ฒ๋ก ๋ค๊ณ ๊ฐ์ ์ฌ๋ ค ์ฌ์ฉํ ๋ ๋ฌธ์ ๊ฐ ์๊ธฐ๊ฒ ๋๋ค. ์๋ํ๋ฉด ์๋์ฐ ๋ฐ์ด๋๋ฆฌ๋ก ๋์๊ฐ๋ shap ํจํค์ง๋ฅผ ๋ฆฌ๋ ์์ ๋๋ฆฌ๋ ค๊ณ ํ๋ ๋์๊ฐ๋ฆฌ๊ฐ ์๊ธฐ ๋๋ฌธ์ด๋ค.
์ด๋ฌํ ๋ฌธ์ ๋ ์๋์ฐ OS์์ ๊ฐ๋ฐํ๊ณ AWS Lambda ํจ์๋ก ์ ๋ก๋ ํ ๋(๋๋ค๋ ์๋ง์กด ๋ฆฌ๋ ์ค๋ก ๋์๊ฐ๋ค) ๊ฐ์ฅ ๋น๋ฒํ ๋ฐ์ํ๋ ๋ฌธ์ ์ด๋ค.
๋ฐ๋ผ์ ๋ง์ผ ๋ฆฌ๋ ์ค ํ๊ฒฝ์์ ์ฌ์ฉํ ์์ ์ด๋ผ๋ฉด ๋ค์๊ณผ ๊ฐ์ด ๋ฏธ๋ฆฌ ์ต์ ์ผ๋ก ํ๋ซํผ์ ์ง์ ํด์ ์ฌ์ฉํด์ผ ํ๋ค.
> npm install --platform=linux sharp
[์ต์ ]
--platform: ์ค linuxํ๋ darwin๋๋ win32.
--arch: x64, ia32, arm๋๋ arm64.
--arm-version: 6, 7๋๋ 8( arm๊ธฐ๋ณธ๊ฐ์ 6, arm64๊ธฐ๋ณธ๊ฐ์ 8) ์ค ํ๋์ ๋๋ค.
--libc: glibc๋๋ musl. ์ด ์ต์ ์ ํ๋ซํผ์์๋ง ์๋ํ๋ฉฐ linux๊ธฐ๋ณธ๊ฐ์glibc
--sharp-install-force: ๋ฒ์ ํธํ์ฑ ๋ฐ ํ์ ๋ฆฌ์์ค ๋ฌด๊ฒฐ์ฑ ๊ฒ์ฌ๋ฅผ ๊ฑด๋๋๋๋ค.
๊ธฐ๋ณธ ์ด๋ฏธ์ง ๋ฆฌ์ฌ์ด์ง
๊ธฐ๋ณธ์ ์ธ ์ด๋ฏธ์ง ๋ฆฌ์ฌ์ด์ง ์ฌ์ฉ๋ฒ์ ๋ค์๊ณ ๊ฐ๋ค.
๊ฐ ๋ฉ์๋๋ค์ด ์ฒด์ด๋ ํํ๋ก ์ด๋ฃจ์ด์ ธ ์์ผ๋ฉฐ, ์ฒ์ ๋ก์ปฌ ์ด๋ฏธ์ง ํ์ผ์ ๋ถ๋ฌ์ฌ๋๋ ์๋๋ผ๋ฉด fs ๋ชจ๋๋ก ํ์ผ์ ๋ถ๋ฌ์์ผ ๋์ง๋ง, ๋ค์๊ณผ ๊ฐ์ด ๋ฐ๋ก ํธ๋ฆฌํ๊ฒ ๋ถ๋ฌ์ฌ์๋ ์๋ค.
.resize ๋ฉ์๋์ ์ธ์์ธ width, height ์ค ํ ๊ฐ๋ง ์ฃผ์ด์ง ๊ฒฝ์ฐ ๋๋จธ์ง ๊ฐ์ ์ ์ ํ๊ฒ ์กฐ์ ๋๋ค.
const sharp = require('sharp');
(async () => {
const image = await sharp('./my-image.jpg')
.resize(500, 500, { fit: 'contain' }) // fit : contain ๊ฐ๋ก ์ธ๋ก ๋น์จ์ ๊ฐ์ ์ ์ง
.withMetadata() // ์๋ณธ ์ด๋ฏธ์ง์ ๋ฉํ๋ฐ์ดํฐ ํฌํจ
.toFormat('jpeg', { quality : 100 }) // ํฌ๋งท, ํ๋ฆฌํฐ ์ง์
.toFile('resizeIMG.jpeg', (err, info) => { // ๋ฆฌ์ฌ์ด์ง๋ ์ด๋ฏธ์ง๋ฅผ ๋ก์ปฌ์ ์ ์ฅ
console.log(`๋ฆฌ์ฌ์ด์ง ์ด๋ฏธ์ง info : ${JSON.stringify(info, null, 2)}`);
})
.toBuffer(); // ๋ฆฌ์ฌ์ด์ง๋ ์ด๋ฏธ์ง๋ฅผ ๋
ธ๋์์ ์ฝ์์ ์๊ฒ buffer๋ก ๋ณํ
})();
Node.js์์ ํ์ผ์ด๋ ์ด๋ฏธ์ง(blob)์ ๊ฐ์ ์ด์ง ๋ฐ์ดํฐ๋ฅผ ์ฝ๊ณ ๋ค๋ฃจ๊ธฐ ์ํด์๋ ๋ง์ง๋ง์ toBuffer()์ ํตํด buffer๋ก ๋ณํํด์ผ ํ๋ค.
์ด๋ฏธ์ง ํฌ๊ธฐ ์ ํ
๋ง์ผ ๋ฆฌ์ฌ์ด์ง ๊ฐ๋ก ๊ธธ์ด(500ํฝ์ )๋ณด๋ค ์์ ์ด๋ฏธ์ง๋ฅผ ์ ๋ก๋ํ๋ฉด ์ด๋ป๊ฒ ํ ๊น?
์๋ณธ๋ณด๋ค ํฐ 500ํฝ์ ์ ๋ง์ถ๋ฉด ์ด๋ฏธ์ง๊ฐ ๊นจ์ง ๊ฒ์ด๊ณ , ๋ฆฌ์ฌ์ด์ง ์๋ฏธ๊ฐ ์๋ค.
๋ฐ๋ผ์ ์ด๋ฏธ์ง์ ํฌ๊ธฐ๋ฅผ ๋ฏธ๋ฆฌ ์ ์ ์๋ค๋ฉด ์ด๋ฐ ์ํฉ์ ๋ฏธ์ฐ์ ๋ฐฉ์งํ ์ ์๋ค.
(async() => {
const maxWidth = 500;
const image = await sharp('./my-image.jpg');
const { width } = await image.metadata(); // ์๋ณธ์ด๋ฏธ์ง ํฌ๊ธฐ ์ป๊ธฐ
if (width > maxWidth) {
const resized = await image.resize({ width: maxWidth });
}
})();
ajax ์ด๋ฏธ์ง ๋ค๋ฃจ๊ธฐ
๋ก์ปฌ ์ด๋ฏธ์ง๊ฐ ์๋, ajax๋ก ์ด๋ฏธ์ง๋ฅผ ๋ถ๋ฌ์ฌ๋๋ ๋ฐ์ด๋๋ฆฌ ์์ ์ ํด์ฃผ์ด์ผ ํ๋ค.
์ด๋ฏธ์ง๋ฅผ ๋ถ๋ฌ์ค๊ณ ๋ ธ๋์์ ์ด์ง ๋ฐ์ดํฐ๋ฅผ ๋ค๋ฃฐ ์ ์๊ฒ ๋ฒํผ๋ก ๋ณํํด์ฃผ์ด์ผ ํ๋ค.
/* fetch๋ก ์ด๋ฏธ์ง ๋ถ๋ฌ์ค๊ธฐ */
const fetch = require('node-fetch'); // > npm i node-fetch
(async() => {
const img = await fetch('์ด๋ฏธ์งURL') // ์ด๋ฏธ์ง url์ fetch
.then((res) => res.buffer()) // ๋ฐํ ์ด๋ฏธ์ง๋ฅผ blob์ผ๋ก ๋ณํ
const resized = await sharp(img).resize(200, 200);
})();
/* axios๋ก ์ด๋ฏธ์ง ๋ถ๋ฌ์ค๊ธฐ */
const axios = require('axios'); // > npm i axios
(async() => {
const img = await axios
.get('์ด๋ฏธ์งURL', { responseType: 'arraybuffer' })
.then((response) => Buffer.from(response.data)); // ์ด๋ฏธ์ง๋ฅผ ์๋ฒ๋จ์ผ๋ก ajax๋ก ๊ฐ์ ธ์ค๊ธฐ
const resized = await sharp(img).resize(200, 200);
})();
multer์ ํจ๊ป ์ฌ์ฉ
multer๋ก ์ด๋ฏธ์ง ์
๋ก๋๋ฅผ ํ๋ฉด ๋ฏธ๋ค์จ์ด๋ฅผ ํตํด req.file ๊ฐ์ฒด๊ฐ ๋ค์ด์ฌ ๊ฒ์ด๊ณ , ์ด๋ฅผ ๋ฐํ์ผ๋ก sharp๋ก ๋ฆฌ์ฌ์ด์ง ํด์ฃผ๋ ์ฝ๋์ด๋ค.
const sharp = require('sharp');
const fs = require('fs');
const multer = require('multer');
const storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, 'uploads/');
},
filename: (req, file, cb) => {
let newFileName = new Date().valueOf() + path.extname(file.originalname);
cb(null, newFileName);
},
});
router.post('/upload', upload.single('img'), (req, res, next) => {
try {
sharp(req.file.path) // ๋ฆฌ์ฌ์ด์งํ ํ์ผ์ ๊ฒฝ๋ก
.resize({ width: 640 }) // ์๋ณธ ๋น์จ ์ ์งํ๋ฉด์ width ํฌ๊ธฐ๋ง ์ค์
.withMetadata()
.toFile(`${req.file.path}/resize.png`, (err, info) => {
if (err) throw err;
console.log(`info : ${info}`);
fs.unlink(`${req.file.path}/resize.png`, (err) => {
// ์๋ณธํ์ผ์ ์ญ์ ํด์ค๋๋ค
// ์๋ณธํ์ผ์ ์ญ์ ํ์ง ์์๊ฑฐ๋ฉด ์๋ตํด์ค๋๋ค
if (err) throw err;
});
});
} catch (err) {
console.log(err);
}
});
์ํฐ๋งํฌ ๋ฃ๊ธฐ
sharp๋ ์ด๋ฏธ์ง ๋ฆฌ์ฌ์ด์ง ๋ฟ๋ง ์๋๋ผ ์ํฐ๋งํฌ ๋ฃ๋ ๊ธฐ๋ฅ๋ ์ง์ํด์ค๋ค.
์ํฐ๋งํฌ ๋ผ๊ณ ๋ดฃ์ ์ด๋ฏธ์ง ์์ ์ด๋ฏธ์ง๋ฅผ ์ฌ๋ ค๋๋ ํ์์ด๋ผ ๋ณต์กํ ์์ ์ด ์๋๋ค.
์ด๋ฏธ์ง๋ฅผ ๋ค๋ฅธ ์ด๋ฏธ์ง์ ์ถ๊ฐํ๊ธฐ ์ํด์๋ ์ถ๊ฐํ ์ด๋ฏธ์ง๋ฅผ Buffer ๊ฐ์ฒด๋ก ๋ฐ๊พธ์ด ์ฃผ์ด์ผ ํ๋ค.
(async() => {
const image = await sharp('./my-image.png');
const watermark = await sharp('./watermark.png').toBuffer();
const watermarked = await image
.composite([{
input: watermark,
gravity: 'southeast',
}])
.toFile(`watermarkIMG.${requiredFormat}`, (err, info) => {
// ๋ฆฌ์ฌ์ด์ง๋ ์ด๋ฏธ์ง๋ฅผ ๋ก์ปฌ์ ์ ์ฅ
console.log(`์ํฐ๋งํฌ๋ ์ด๋ฏธ์ง info : ${JSON.stringify(info, null, 2)}`);
})
})();
์ด๋ฏธ์ง๋ฅผ ํฌํจํ ์ปจํ
์ธ ์ฝ์
์์๋ composite ์ด๋ผ๋ ๋ฉ์๋๋ฅผ ์ฌ์ฉํ๋ค.
์ ๋ ฅ์ผ๋ก๋ ๋ฐฐ์ด ๊ฐ์ฒด๋ฅผ ๋ฐ์ผ๋ฉฐ, ๋ฐฐ์ด ๋ค์ ์ฝ์ ํ ์ปจํ ์ธ ์ผ์๋ก ์์ชฝ(ppt์ ๋งจ ์์ ๋๊ธฐ์ ๊ฐ์ ๊ธฐ๋ฅ)์ ๋ํ๋๋ค.
์ปจํ ์ธ ๋ ํน์ ์์น๋ฅผ ์ง์ ํ์ฌ ์ฝ์ ํ ์๋ ์์ง๋ง, gravity ์ต์ ์ผ๋ก ์ ์ค์, ์ค๋ฅธ์ชฝ ๋ฑ ์ ์ ํ ์์น์ ์์์ ๋ฐฐ์น๋๊ฒ ๋ง๋ค ์๋ ์๋ค. (https://sharp.pixelplumbing.com/api-composite)
์ด๋ฏธ์ง ๋ฆฌ์ฌ์ด์ง api ์๋น์ค ๋ง๋ค๊ธฐ
ํฐ์คํ ๋ฆฌ(๋ค์) ๋ธ๋ก๊ทธ์์๋ ์ด๋ฏธ์ง๋ฅผ ๋ฆฌ์ฌ์ด์ง ํด์ฃผ๋ api ์๋น์ค๋ฅผ ๊ณต์ง๋ก ์ ๊ณตํ๋ค.
์๋์ ๋งํฌ๋ฅผ ๋ธ๋ผ์ฐ์ ์ ๋์ฐ๋ฉด ์ค์ ๋ก ๋ฆฌ์ฌ์ด์ฆ ๋ ์ด๋ฏธ์ง๊ฐ ํ๋ฉด์ ์ถ๋ ฅ๋๋ค.
//i1.daumcdn.net/thumb/C100x100/?fname=[์ด๋ฏธ์งurl]

์ด ์ด๋ฏธ์ง ๋ฆฌ์ฌ์ด์ง api ์๋น์ค๋ฅผ ์ง์ Node(express)๋ก ๊ตฌํํด๋ณด์ (์ ๋ง ๊ฐ๋จํ๋ค!!)
์ฐ์ ๋ค์ ํจํค์ง๋ค์ ์ค์นํด์ค๋ค.
> npm i express sharp axios
const express = require('express');
const sharp = require('sharp');
const axios = require('axios');
const app = express();
// ... ๋ผ์ฐํ
์ฝ๋
app.listen(8081, () => {
console.log('8081๋ฒ ํฌํธ์์ ๋๊ธฐ์ค');
});
์ด๋ฏธ์ง ๋ฆฌ์ฌ์ด์ง ๋ผ์ฐํ
http://localhost:8081/thumb/500x700?fname=[์ด๋ฏธ์งurl]
ํํ๋ก api ์์ฒญ์ ํ๊ฒ๋๋ฉด ์ด๋ฏธ์ง๊ฐ 500x700 ์ฌ์ด์ฆ๋ก ๊ฐ์ ์กฐ์ ๋๋ ์๋น์ค๋ฅผ ๊ตฌํํด๋ณด์.
//? http://localhost:8081/thumb/500x700?fname=[์ด๋ฏธ์งurl]
app.get('/thumb/:size', async (req, res) => {
//* ๋ฆฌ์ฌ์ด์ง ์ค์
const quality = 100; // ์ด๋ฏธ์ง ํ๋ฆฌํฐ (๊ธฐ๋ณธ 80)
const [size1, size2] = req.params.size.split('x'); // [500, 700]
const ext = req.query.fname.split('.')[req.query.fname.split('.').length - 1]; // ํ์ผ ํฌ๋งท
const requiredFormat = ext === 'jpg' ? 'jpeg' : ext; // sharp ์์๋ jpg ๋ง๊ณ jpeg๋ฅผ ์ฌ์ฉํ๊ธฐ์ ์กฐ์น
console.log('๋ฆฌ์ฌ์ด์ง ํฌ๊ธฐ : ', req.params.size);
console.log('์๋ณธ ์ด๋ฏธ์ง ํฌ๋งท : ', requiredFormat);
//* ์ด๋ฏธ์ง ๊ฐ์ ธ์ค๊ธฐ
const img = await axios
.get(req.query.fname, { responseType: 'arraybuffer' })
.then((response) => Buffer.from(response.data));
//* ์ด๋ฏธ์ง ๋ฆฌ์ฌ์ด์ง
const imgCompress = await sharp(img)
.resize(parseInt(size1), parseInt(size2), { fit: 'contain' }) // fit : contain ๊ฐ๋ก ์ธ๋ก ๋น์จ์ ๊ฐ์ ์ ์ง
.withMetadata() // ์๋ณธ ์ด๋ฏธ์ง์ ๋ฉํ๋ฐ์ดํฐ ํฌํจ
.toFormat(requiredFormat, { quality }) // ํฌ๋งท / ํ๋ฆฌํฐ ์ง์
.toFile(`resizeIMG.${requiredFormat}`, (err, info) => {
// ๋ฆฌ์ฌ์ด์ง๋ ์ด๋ฏธ์ง๋ฅผ ๋ก์ปฌ์ ์ ์ฅ
console.log(`๋ฆฌ์ฌ์ด์ง ์ด๋ฏธ์ง info : ${JSON.stringify(info, null, 2)}`);
})
.toBuffer(); // ๋ฆฌ์ฌ์ด์ง๋ ์ด๋ฏธ์ง๋ฅผ ๋
ธ๋์์ ์ฝ์์ ์๊ฒ buffer๋ก ๋ณํ
res.status(200).end(imgCompress); // ๋ฆฌ์ฌ์ด์ง๋ ์ด๋ฏธ์ง๋ฅผ ๋ธ๋ผ์ฐ์ ์ ๋จ๊ฒ ์๋ต
});
resize({ fit ์ต์ })
- cover: (๊ธฐ๋ณธ๊ฐ) ๊ฐ๋ก ์ธ๋ก ๋น์จ์ ์ ์งํ๊ณ ์ด๋ฏธ์ง๊ฐ ๋ง๊ฒ ์๋ฅด๊ธฐ/์๋ ค ์ ๊ณต๋ ๋ ์น์๋ฅผ ๋ชจ๋ ํฌํจํ๋์ง ํ์ธ
- contain: ๊ฐ๋ก ์ธ๋ก ๋น์จ์ ์ ์งํ๊ณ ํ์ํ ๊ฒฝ์ฐ "๋ ํฐ๋ฐ์ค"๋ฅผ ์ฌ์ฉํ์ฌ ์ ๊ณต๋ ๋ ์น์ ๋ชจ๋์ ํฌํจ
- fill: ์ ๋ ฅ์ ์ข ํก๋น๋ฅผ ๋ฌด์ํ๊ณ ์ ๊ณต๋ ๋ ์น์๋ก ๋์ธ๋ค
- inside: ๊ฐ๋ก ์ธ๋ก ๋น์จ์ ์ ์งํ๋ฉด์ ์ด๋ฏธ์ง์ ํฌ๊ธฐ๋ฅผ ์ง์ ๋ ํฌ๊ธฐ๋ณด๋ค ์๊ฑฐ๋ ๊ฐ๊ฒ ์ ์งํ๋ฉด์ ๊ฐ๋ฅํ ํ ํฌ๊ฒ ์ด๋ฏธ์ง ํฌ๊ธฐ๋ฅผ ์กฐ์
- outside: ์ข ํก๋น๋ฅผ ์ ์งํ๋ฉด์ ์ด๋ฏธ์ง์ ํฌ๊ธฐ๊ฐ ์ง์ ๋ ๋ ๊ฐ์ง๋ณด๋ค ํฌ๊ฑฐ๋ ๊ฐ๋๋ก ์ต๋ํ ์๊ฒ ์ด๋ฏธ์ง ํฌ๊ธฐ๋ฅผ ์กฐ์
๋ค์ ์ด๋ฏธ์ง url์ ๋ฆฌ์ฌ์ด์ง ์๋น์ค๋ฅผ ์ด์ฉํด ์กฐ์ ํด ํด๋ณด์.
http://localhost:8081/thumb/500x700?fname=https://helpx.adobe.com/content/dam/help/en/photoshop/using/convert-color-image-black-white/jcr_content/main-pars/before_and_after/image-before/Landscape-Color.jpg



์ด๋ฏธ์ง ์ํฐ๋งํฌ ๋ผ์ฐํธ
๋ค์ ์ํฐ๋งํฌ ์ด๋ฏธ์ง ํ์ผ์ ์๋ฒ ํด๋์ ์ ์ฅํด๋๋ค.

//? http://localhost:8081/watermark?filename=[์ด๋ฏธ์งurl]
app.get('/watermark', async (req, res) => {
//* ์ํฐ ๋งํฌ ์์ฑํ๊ธฐ
const ext = req.query.fname.split('.')[req.query.fname.split('.').length - 1]; // ํ์ผ ํฌ๋งท
const requiredFormat = ext === 'jpg' ? 'jpeg' : ext; // sharp ์์๋ jpg ๋ง๊ณ jpeg๋ฅผ ์ฌ์ฉํ๊ธฐ์ ์กฐ์น
console.log('์๋ณธ ์ด๋ฏธ์ง ํฌ๋งท : ', requiredFormat);
// ์ด๋ฏธ์ง๋ฅผ ์๋ฒ๋จ์ผ๋ก ajax๋ก ๊ฐ์ ธ์ค๊ธฐ
const img = await axios
.get(req.query.fname, { responseType: 'arraybuffer' })
.then((response) => Buffer.from(response.data));
const original_img = await sharp(img);
const watermark = await sharp('./watermark.png').toBuffer(); // ๋ก์ปฌ์์ ์ํฐ๋งํฌ ์ด๋ฏธ์ง ๋ถ๋ฌ์ค๊ธฐ
const watermarked = await original_img
.composite([
{
input: watermark,
gravity: 'southeast', // ์ํฐ๋งํฌ ์์น
},
])
.toFile(`watermarkIMG.${requiredFormat}`, (err, info) => {
// ๋ฆฌ์ฌ์ด์ง๋ ์ด๋ฏธ์ง๋ฅผ ๋ก์ปฌ์ ์ ์ฅ
console.log(`์ํฐ๋งํฌ๋ ์ด๋ฏธ์ง info : ${JSON.stringify(info, null, 2)}`);
})
.toBuffer(); // ๋ฆฌ์ฌ์ด์ง๋ ์ด๋ฏธ์ง๋ฅผ ๋
ธ๋์์ ์ฝ์์ ์๊ฒ buffer๋ก ๋ณํ
res.status(200).end(watermarked); // ๋ฆฌ์ฌ์ด์ง๋ ์ด๋ฏธ์ง๋ฅผ ๋ธ๋ผ์ฐ์ ์ ๋จ๊ฒ ์๋ต
});
๋ค์๊ณผ ๊ฐ์ด ๋ผ์ฐํฐ๋ก ์์ฒญํด๋ณด๋ฉด, ์๋ณธ ์ด๋ฏธ์ง์ ๋ฐ๋์บ ์ํฐ๋งํฌ๊ฐ ์ ์ฝ์ ๋จ์ ํ์ธํ ์ ์๋ค.
http://localhost:8081/watermark?fname=https://helpx.adobe.com/content/dam/help/en/photoshop/using/convert-color-image-black-white/jcr_content/main-pars/before_and_after/image-before/Landscape-Color.jpg


์ด๋ ๊ฒ ๊ฐ๋จํ ์ด๋ฏธ์ง ๋ฆฌ์ฌ์ด์ง api ์๋ฒ๋ฅผ ๊ตฌํํด ๋ณด์๋ค.
ํ์ง๋ง ์ด์ฉ์๋ค์ด 24์๊ฐ ๋ด๋ด ์ด๋ฏธ์ง ๋ฆฌ์ฌ์ด์ง ๊ธฐ๋ฅ์ ์ฌ์ฉํ๋ ๊ฒ๋ ์๋๋, ์๋น์ค ์๋ฒ๋ฅผ 24์๊ฐ ๋ด๋ด ๊ธฐ๋์ํค๋ ๊ฒ์ ์์ ๋ญ๋น์ด๋ค.
๋ฐ๋ผ์ ๋ณดํต ์ด๋ฌํ ์๋น์ค๋ค์ ์๋ฒ๋ฆฌ์ค๋ก ๊ตฌํํ๋ค.
๋ง์ผ ์๋ฒ๋ฆฌ์ค์ ๋ํด ์์ง ์ ๋ชจ๋ฅด์ ๋ ์๋ถ๋ค์ ์ด๋ฒ ๊ธฐํ์ ํ๋ฒ ๊ณต๋ถํด๋ณด์!
[WEB] ๐ ์๋ฒ๋ฆฌ์ค(ServerLess) ๊ฐ๋ ๐ฏ ์ ๋ฆฌ (BaaS / FaaS)
์๋ฒ๋ฆฌ์ค ์ํคํ ์ณ(Serverless) ๋? ์๋ฒ๋ฆฌ์ค(Serverless)๋ ์ง์ญํ๋ฉด "์๋ฒ๊ฐ ์๋ค"๋ผ๋ ๋ป์ด ๋๋ค. ํ์ง๋ง ์ ๋ง๋ก ์๋ฒ๊ฐ ์๋ ๊ฒ์ ๋ปํ๋๊ฒ ์๋๋ค. ์๋น์ค๋ฅผ ํ๋๋ฐ ์์ด ์ด์ฐ๋์๋ ์ ์ฅ์๋ ํ
inpa.tistory.com
'Amazon Cloud/Lambda' ์นดํ ๊ณ ๋ฆฌ์ ๊ธ ๋ชฉ๋ก
์๋ ํ์ธ์. ์ ๋ ๋ฐฑ์ค๋ ๊ฐ๋ฐ์ ์ง๋ง์์ผ๋ก์, ์น ๊ฐ๋ฐ ๊ธฐ์ ๋ธ๋ก๊ทธ๋ฅผ ์ด์ํ๊ณ ์์ด์. ์ ๋ถํ๋๋ ค์~
inpa.tistory.com
์ด ๊ธ์ด ์ข์ผ์ จ๋ค๋ฉด ๊ตฌ๋ & ์ข์์
์ฌ๋ฌ๋ถ์ ๊ตฌ๋
๊ณผ ์ข์์๋
์ ์์๊ฒ ํฐ ํ์ด ๋ฉ๋๋ค.