
์์ฃผ ๊ฐ๋จํ ์ด๋ฏธ์ง ์๋ํฐ 1์ฐจ ๋ฒ์ ์ ์ฃผ๋ง ๋์ ๋น ๋ฅด๊ฒ ๊ตฌํํด ๋ณด์๋ค.
์์ํ๊ฒ ๋ ๊ณ๊ธฐ๋ ์๋ง๊ฐ ์์
ํ ํ์๋ค ์ํ ์ฌ์ง์ ์์
๊ธฐ๋ก์ฉ์ผ๋ก ํธ์งํ๋ ๊ณผ์ ์ ์ง์ผ๋ดค๋๋ฐ, ๋ฆฌ์ฌ์ด์ง๊ณผ ๋ผ๋ฒจ๋ง ๋ฑ์ ๊ฐ๊ฐ ๋ค๋ฅธ ํด์์ ์ฒ๋ฆฌํ๋๋ผ ์์
์ด ๋ฒ๊ฑฐ๋กญ๊ณ ๋นํจ์จ์ ์ด์๋ค. ๊ทธ๋์ ํ์ํ ๊ธฐ๋ฅ๋ค์ ์ญ ์ ๋ฆฌํ๊ณ , ๊ณ์ ๋ฏธ๋ฃจ๋ค ์ฃผ๋ง์ 1์ฐจ ๋ฒ์ ์ ์์ฑํ์๋ค.
์์ฑ ํ ์ค๋ ์ ์ ํ
์คํธ๋ฅผ ์งํํ๋ฉฐ ํผ๋๋ฐฑ์ ๋ฐ์๊ณ , ํ์ฌ๋ ์ด์ ์ฒ๋ฆฌ์ ํผ๋๋ฐฑ ๋ฐ์์ ํฌํจํ 2์ฐจ ์ถ๊ฐ ๊ธฐ๋ฅ ๊ตฌํ์ด ํ์ํ ์ํ๋ค.
1์ฐจ ์ฃผ์ ๊ธฐ๋ฅ
1. ์ด๋ฏธ์ง ๊ฐ์ ธ์ค๊ธฐ
- ํ์ผ ์ ํ or ๋๋๊ทธ ์ค ๋๋กญ์ผ๋ก ์
๋ก๋ ๊ฐ๋ฅ
- ์
๋ก๋ ์ ๋ฏธ๋ฆฌ ๋ณด๊ธฐ ์ ๊ณต
2. ๋ฆฌ์ฌ์ด์ฆ ์ต์
์ ์ ๊ฐ ๊ณ ์ ๋ ํฌ๊ธฐ๋ง ์ฌ์ฉํ๊ธฐ ๋๋ฌธ์ ํฌ๊ธฐ ๋ณ๊ฒฝ ๊ธฐ๋ฅ์ ์ ์ธํ๊ณ , ์ด๋ฏธ์ง ๋น์จ๋ง ์ ์งํ๋๋ก ๊ตฌํ
3. ๋ผ๋ฒจ๋ง ๊ธฐ๋ฅ
- ํ๋จ ์ข์ธก / ์ค์ / ์ฐ์ธก ์์น ์ ํ ๊ฐ๋ฅ
- ํฐํธ ํฌ๊ธฐ์ ์ฌ๋ฐฑ ์กฐ์ ๊ฐ๋ฅ
- ๋ฏธ๋ฆฌ ๋ณด๊ธฐ์ ๋
ธ์ถ ํ์
4. ๋ค์ด๋ก๋
- ๊ฐ๋ณ ์ ์ฅ ๋ฒํผ์ผ๋ก ๋จ์ผ ์ด๋ฏธ์ง ๋ค์ด๋ก๋
- ์ ์ฒด ์ด๋ฏธ์ง๋ฅผ ZIP ํ์ผ๋ก ๋ฌถ์ด ๋ค์ด๋ก๋
์ผ๋จ ๋ค์ด๋ก๋๋ ๊ฐ๋ณ ๋ค์ด๋ก๋์ ์ ์ฒด ๋ค์ด๋ก๋๊ฐ ๊ฐ๋ฅํ๋๋ก ํด์ผ ํด์ JSZip ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ํ์ฉํ์๋ค. ๋ค๋ง ํ
์คํธ ์ค์ ์๋ง๊ฐ ์ฌ์ฉํ๋ ๋ค๋ฅธ ์๋ํฐ์ ํธํ์ฑ ์ด์๊ฐ ์๋ ๊ฒ ๊ฐ์ ํด๊ฒฐ์ด ํ์ํ๋ฐ ์ง๊ธ ์๋์ฐ ๋
ธํธ๋ถ์ด ์์ด์ ๋ฌด์จ ์ด์์ธ์ง ์ ๋๋ก ํ์ธ์ด ์ด๋ ค์ด ์ํฉ์ด๋ค.
๊ตฌํ ๊ณผ์ ์์ ์๊ฒ ๋ ์ ๊ณผ ๊ฒช์ ์ด์
1. Object URL ๋ฉ๋ชจ๋ฆฌ ๋์ ๋ฐฉ์ง
์ด๋ฏธ์ง ๋ฏธ๋ฆฌ๋ณด๊ธฐ ๊ธฐ๋ฅ์ ๊ตฌํํ๊ธฐ ์ํด URL.createObjectURL์ ํ์ฉํ์๋ค. ํด๋น ๋ฉ์๋๋ ๋ผ์ฐ์ ๋ฉ๋ชจ๋ฆฌ์ ํ์ผ ๋ด์ฉ์ Blob ํํ๋ก ๋ณด๊ดํ๊ณ , ํด๋น Blob์ ์ ๊ทผํ ์ ์๋ ์์ URL์ ๋ง๋ค์ด์ฃผ๋ ์ญํ ์ ํ๋ค. ๋ค๋ง ํด๋น ๋ฉ์๋๋ฅผ ์ฌ์ฉํ ๋ ์ฃผ์ํ ์ ์ด ์๋๋ฐ URL.revokeObjectURL๋ก ํด์ ํ์ง ์์ผ๋ฉด ๋ธ๋ผ์ฐ์ ๊ฐ ํด๋น ๋ฉ๋ชจ๋ฆฌ๋ฅผ ๊ณ์ ๋ถ์ก๊ณ ์๊ฒ ๋์ด์ ์
๋ก๋์ ์ญ์ ๋ฅผ ๋ฐ๋ณตํ๋ฉด ๋ฉ๋ชจ๋ฆฌ ์ ์ ๊ฐ ์ ์ ์ปค์ ธ ์ฑ๋ฅ ์ ํ๋ ๋ธ๋ผ์ฐ์ ํญ ๋ค์ด์ผ๋ก ์ด์ด์ง ์ ์๋ค๊ณ ํ๋ค. ๊ทธ๋์ ์๋์ ๊ฐ์ด ZIP Blob์ ๋ง๋ค์ด ๋ค์ด๋ก๋ ๋งํฌ๋ก ์ฐ๊ฒฐํ ๋, ๋ค์ด๋ก๋๊ฐ ๋๋๋ฉด URL์ ํด์ ํ๋ ๋ก์ง์ ์ถ๊ฐํ์๋ค.
const handleDownloadSelected = async () => {
const zip = new JSZip();
for (const it of items) {
const blob = await renderBlob(it.file, it.label ? it.label : null);
if (!blob) continue;
const nameWithoutExt = it.name.replace(/\.[^.]+$/, '');
const suffix = it.label && it.label.trim() ? '_labeled' : '_resized';
zip.file(`${nameWithoutExt}${suffix}.jpg`, blob);
await new Promise((r) => setTimeout(r, 0));
}
....
setTimeout(() => {
URL.revokeObjectURL(a.href);
a.remove();
}, 100);
};
2. ํฐํธ ์ค์ผ์ผ๋ง ์ด์
์บ๋ฒ์ค ํฐํธ ํฌ๊ธฐ๋ฅผ ์ ๋๊ฐ์ผ๋ก ๊ฐ์ ๊ณ ์ ํด ๋๋ฉด, ๋ฆฌ์ฌ์ด์ฆ๋ ์ด๋ฏธ์ง์ ํฝ์
ํฌ๊ธฐ์ ๋ฐ๋ผ ์๋์ ์ธ ๋น์จ์ด ๊นจ์ง๋ ์ด์๊ฐ ๋ฐ์ํ์๋ค. ๊ทธ๋์ ๊ธฐ์ค width์ ํ๋ ์ ํด ๋๊ณ , ์ค์ ๋ ๋๋ง width์ ๋น๋กํด์ ํฐํธ,ํจ๋ฉ์ ์ค์ผ์ผ ํ๋๋ก ํ์๋๋ฐ, ์ต์๊ฐ, ์ต๋๊ฐ ํด๋จํ๋ฅผ ๊ฑธ์ด ๋๋ฌด ์๊ฑฐ๋ ํฌ์ง ์๊ฒ ์ ํํ์๊ณ , ๋ง์ฝ ํ
์คํธ๊ฐ ๋ฐ์ค๋ณด๋ค ๊ธธ๋ฉด ํญ์ ๋ง์ถฐ ์๋ ์ถ์ ๊ธฐ๋ฅ๋ ์ผ๋จ ์ถ๊ฐํ์๋ค. (++ ํฐํธ๊ฐ ๋๋ฌด ์์์ง๋ ๊ฒ์ ๋๋นํด์ ์ต์ 12px ๋ก ์ ํ)
const fs = Math.max(12, Math.floor((fontSize * W) / 800));
3. ํ
์คํธ ์ค๋ฒํ๋ก์ฐ ๋ฐฉ์ง
ํ
์คํธ๊ฐ ๋ฐ์ค๋ณด๋ค ๊ธธ์ด์ง ๊ฒฝ์ฐ๋ฅผ ๋๋นํด์ ์๋์ผ๋ก ํฌ๊ธฐ๋ฅผ ์กฐ์ ํ๋ ๊ธฐ๋ฅ์ด ํ์ํ๋๋ฐ,
๋จผ์ ํ
์คํธ์ ์ค์ ํฌ๊ธฐ๋ฅผ ์ธก์ ํ๊ณ
const metrics = ctx.measureText(text);
const textW = Math.ceil(metrics.width);
const textH = Math.ceil(fs * 1.3);
์ธก์ ๋ ํ
์คํธ ํฌ๊ธฐ๋ฅผ ๊ธฐ์ค์ผ๋ก ํจ๋ฉ์ ํฌํจํ ์ ์ฒด ๋ฐ์ค ํฌ๊ธฐ๋ฅผ ๊ณ์ฐํ๋๋ก ํ์๋ค.
const boxW = textW + paddingX * 2;
const boxH = textH + paddingY * 2;
ํญ์ ์ฌ์ด๋ ํ๋ก์ ํธ๋ฅผ ํด๋ ์ ์ ๊ฐ ์๋ค ๋ณด๋ ์ค๊ฐ์ ํ์ง๋ถ์ง ๋๋๊ฑฐ๋, ์๋ก์ด ๊ธฐ์ ์ ์ตํ๊ธฐ ์ํด ์ฑ์ ๋ง๋๋ ์ ๋๋ก ๋ง๋ฌด๋ฆฌํ๊ณค ํ์๋๋ฐ, ์ด๋ฒ์๋ ์ค์ ์ ์ ๊ฐ ์๊ณ , ํ์์ฑ๋ ๋ช
ํํด ์งํ ๊ณผ์ ์ด ํจ์ฌ ์ฌ๋ฏธ์๊ฒ ๋๊ปด์ง๋ ๊ฒ ๊ฐ๋ค. ๐
'๐ WIL' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
| Tailwind v4 ๋ง์ด๊ทธ๋ ์ด์ : Dynamic spacing utilities (0) | 2025.08.24 |
|---|---|
| ๋ฃจํธ ๋จ์ผ ์ค์น vs ์ํฌ์คํ์ด์ค ์ค์น (3) | 2025.08.17 |
| 8์ ์ฒซ์งธ ์ฃผ.. (6) | 2025.08.03 |
| CSR+SSR+RSC+ Hydration (2) | 2025.07.27 |
| ํด๋ฆฐ ์ฝ๋์ ์ฌ๋ฆฌํ: ์ ์ฐ๋ฆฌ๋ ์ง์ ๋ถํ ๋ฆฌ์กํธ ์ปดํฌ๋ํธ๋ฅผ ์์ฑํ๋๊ฐ (0) | 2025.07.20 |