An open API service indexing awesome lists of open source software.

https://github.com/lee-seokmin/PhotoFrame

๐Ÿ“ธ A website that frames the metadata of a photo.
https://github.com/lee-seokmin/PhotoFrame

fastapi nextjs photography photoshop-crack python react

Last synced: 9 months ago
JSON representation

๐Ÿ“ธ A website that frames the metadata of a photo.

Awesome Lists containing this project

README

          

์ด ์›น์‚ฌ์ดํŠธ๋Š” [Next.js](https://nextjs.org/)๋ฅผ ์‚ฌ์šฉํ•ด ๋งŒ๋“ค์–ด์กŒ์Šต๋‹ˆ๋‹ค.


[![Netlify Status](https://api.netlify.com/api/v1/badges/7913246e-2b44-4772-9f57-2f4119fa43a4/deploy-status)](https://app.netlify.com/sites/photoframeo/deploys)

## ์ด ์‚ฌ์ดํŠธ๋ฅผ ๋งŒ๋“  ๋ชฉ์ 

์ธ์Šคํƒ€๊ทธ๋žจ์— ์ž์‹ ์ด ์ฐ์€ ์‚ฌ์ง„์„ ์˜ฌ๋ฆด ๋•Œ, ์›๋ณธ ๊ทธ๋Œ€๋กœ ์˜ฌ๋ฆฌ๋Š” ๊ฒƒ ๋ณด๋‹ค ๊ทธ ์‚ฌ์ง„์˜ [EXIF](https://namu.wiki/w/EXIF)(์…”ํ„ฐ ์Šคํ”ผ๋“œ, ์กฐ๋ฆฌ๊ฐœ ๊ฐ’, ISO๋“ฑ)๋ฅผ ์ž…๋ ฅํ•ด ๋†“์Œ์œผ๋กœ์จ ์‚ฌ๋žŒ๋“ค์ด ์ •๋ณด๋ฅผ ์•Œ ์ˆ˜ ์žˆ๊ฒŒ ๋˜๋Š” ํ”„๋ ˆ์ž„์„ ๋งŒ๋“œ๋Š” ๊ฒƒ์ด ์œ ํ–‰์ด๋‹ค.
๊ทธ๋Ÿฌ๋‚˜, ์ด ์ž‘์—…์€ ํฌํ† ์ƒต์œผ๋กœ ์ผ์ผ์ด ์ž…๋ ฅํ•ด์•ผ ํ•˜๋‹ค๋Š” ๊ฒƒ์ด ๋‹จ์ ์ด์—ˆ๋‹ค. ๊ทธ๋ž˜์„œ ์ด ์ž‘์—…์„ Python ์ฝ”๋“œ๋กœ ์ž๋™ํ™”ํ•˜์—ฌ ์‚ฌ์šฉ์ž์—๊ฒŒ ์ œ๊ณตํ•˜๋ฉด ๋”์šฑ ํŽธ๋ฆฌํ•˜๊ฒ ๋‹ค๋Š” ์ƒ๊ฐ์„ ํ•˜์—ฌ ๋งŒ๋“ค์—ˆ๋‹ค.

## Getting Started

๋จผ์ €, ๋กœ์ปฌ ์„œ๋ฒ„์—์„œ ๋‹ค์Œ์˜ ์ปค๋งจ๋“œ๋ฅผ ์‹คํ–‰ํ•œ๋‹ค:

```bash
npm run dev
# or
yarn dev
# or
pnpm dev
# or
bun dev
```

๋กœ์ปฌ ์ฃผ์†Œ [http://localhost:3000](http://localhost:3000)์— ์ ‘์†ํ•˜์—ฌ ๊ฒฐ๊ณผ๋ฌผ์„ ํ™•์ธํ•œ๋‹ค.

## ์ฃผ์š” ์ฝ”๋“œ

```typescript
function setupCanvas(imgWidth: number, imgHeight: number, padding: number, metadataHeight: number): {
canvas: HTMLCanvasElement;
ctx: CanvasRenderingContext2D;
canvasWidth: number;
canvasHeight: number;
scaledImgWidth: number;
scaledImgHeight: number;
imgX: number;
imgY: number;
} {
// ๊ณ ์ • ์บ”๋ฒ„์Šค ํฌ๊ธฐ
const canvasWidth = 1080 * 2;
const canvasHeight = 1350 * 2;

const canvas = document.createElement('canvas');
canvas.width = canvasWidth;
canvas.height = canvasHeight;

const ctx = canvas.getContext('2d');
if (!ctx) throw new Error('Could not get canvas context');

// ๋ฐฐ๊ฒฝ ์„ค์ •
ctx.fillStyle = 'white';
ctx.fillRect(0, 0, canvasWidth, canvasHeight);

// ์ด๋ฏธ์ง€ ํฌ๊ธฐ ๊ณ„์‚ฐ (์บ”๋ฒ„์Šค์— ๋งž๊ฒŒ ์Šค์ผ€์ผ๋ง)
const imageArea = canvasHeight - (padding * 5) - metadataHeight;
const scale = Math.min(
(canvasWidth - padding * 2) / imgWidth,
imageArea / imgHeight
);

const scaledImgWidth = imgWidth * scale;
const scaledImgHeight = imgHeight * scale;

// ์ด๋ฏธ์ง€ ์œ„์น˜ ๊ณ„์‚ฐ (๊ฐ€๋กœ ๋ฐ ์„ธ๋กœ ์ค‘์•™ ์ •๋ ฌ)
const imgX = (canvasWidth - scaledImgWidth) / 2;

// ๊ฐ€๋กœ ์ด๋ฏธ์ง€(landscape)์ธ ๊ฒฝ์šฐ ์ˆ˜์ง ์ค‘์•™ ์ •๋ ฌ
let imgY = padding * 2;
if (imgWidth > imgHeight) {
// ๊ฐ€๋กœ ์ด๋ฏธ์ง€๋ฉด ์ˆ˜์ง์œผ๋กœ๋„ ์ค‘์•™์— ๋ฐฐ์น˜
imgY = (canvasHeight - metadataHeight - scaledImgHeight) / 2;
}

return {
canvas,
ctx,
canvasWidth,
canvasHeight,
scaledImgWidth,
scaledImgHeight,
imgX,
imgY
};
}
```

## ๋กœ์ง

```mermaid
flowchart LR
A(ํ”„๋ก ํŠธ์—”๋“œ)
B[์‚ฌ์ง„์˜ ๋ฉ”ํƒ€ ๋ฐ์ดํ„ฐ ๊ฐ€์ ธ์˜ค๊ธฐ]
C[canvas๋ฅผ ์ด์šฉํ•˜์—ฌ
ํฐ ๋ฐฐ๊ฒฝ ๋งŒ๋“ค๊ธฐ]
D[์›๋ณธ ์‚ฌ์ง„์„ ์ผ์ •ํ•œ
๋น„์œจ์— ๋งž์ถฐ resizeํ•˜๊ธฐ]
E[ํฐ ๋ฐฐ๊ฒฝ์— resize๋œ ์‚ฌ์ง„๊ณผ
๋ฉ”ํƒ€ ๋ฐ์ดํ„ฐ ์ž…๋ ฅํ•˜๊ธฐ]

A ---> |์‚ฌ์ง„ ์ „์†ก| B
subgraph ๋ฐฑ์—”๋“œ
B --- C --- D --- E
end
E ---> |์ƒ์„ฑ๋œ ์ด๋ฏธ์ง€๋ฅผ base64๋กœ
์ธ์ฝ”๋”ฉํ•˜์—ฌ returnํ•˜๊ธฐ| A
```