์ด๋ฏธ์ง€ ์—๋””ํ„ฐ ๋งŒ๋“ค๊ธฐ-1

 
์•„์ฃผ ๊ฐ„๋‹จํ•œ ์ด๋ฏธ์ง€ ์—๋””ํ„ฐ 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;

ํ•ญ์ƒ ์‚ฌ์ด๋“œ ํ”„๋กœ์ ํŠธ๋ฅผ ํ•ด๋„ ์œ ์ €๊ฐ€ ์—†๋‹ค ๋ณด๋‹ˆ ์ค‘๊ฐ„์— ํ์ง€๋ถ€์ง€ ๋๋‚˜๊ฑฐ๋‚˜, ์ƒˆ๋กœ์šด ๊ธฐ์ˆ ์„ ์ตํžˆ๊ธฐ ์œ„ํ•ด ์•ฑ์„ ๋งŒ๋“œ๋Š” ์ •๋„๋กœ ๋งˆ๋ฌด๋ฆฌํ•˜๊ณค ํ–ˆ์—ˆ๋Š”๋ฐ, ์ด๋ฒˆ์—๋Š” ์‹ค์ œ ์œ ์ €๊ฐ€ ์žˆ๊ณ , ํ•„์š”์„ฑ๋„ ๋ช…ํ™•ํ•ด ์ง„ํ–‰ ๊ณผ์ •์ด ํ›จ์”ฌ ์žฌ๋ฏธ์žˆ๊ฒŒ ๋А๊ปด์ง€๋Š” ๊ฒƒ ๊ฐ™๋‹ค. ๐Ÿ™‚