데이터 형식
완료하면 OpenResult 로 두 가지가 온다.
| 것 | 타입 | 용도 |
|---|---|---|
png | Blob (image/png) | 독자용 결과물. 문서·이미지 태그에 넣는다 |
data | Drawing | 재편집용 원본. 도형이 살아 있다. initial 로 넘기면 그대로 다시 열린다 |
PNG 만 남기면 도형이 그림에 박혀 다시 고칠 수 없다. data 를 PNG 옆에 곁파일로 함께 저장하는 것이 기본 흐름이다.
Drawing
ts
interface Drawing {
version: 1;
width: number;
height: number;
background: string | null;
shapes: Shape[];
}| 필드 | 타입 | 의미 |
|---|---|---|
version | 1 | 스키마 버전. @newtil/editor 가 곁파일로 저장하던 DrawingData v1 과 같은 모양이라 기존 곁파일이 그대로 열린다 |
width | number | 판 가로(px). 모든 좌표의 기준 |
height | number | 판 세로(px) |
background | string | null | 배경 캡처 — data URL. null 이면 흰 판 |
shapes | Shape[] | 도형. 배열 순서 = 그리는 순서(뒤가 위) |
- 빈 판 기본 크기는 800×450 (
emptyDrawing()). - 배경을 넣으면
width·height는 배경 이미지 크기가 된다. 긴 변이 1600px 을 넘으면 그 한도로 줄인다.
자기 완결성
background 는 파일이든 주소든 반드시 data URL 로 구워 넣는다. 그래서 Drawing JSON 하나만 있으면 어느 서버·어느 페이지에서도 다시 열리고, 나중에 canvas 로 다시 구울 수 있다(교차 출처 이미지는 canvas 를 오염시켜 못 굽는다). 대신 배경이 있으면 JSON 이 수백 KB~수 MB 가 된다.
Shape
모든 도형이 갖는 공통 필드:
| 필드 | 타입 | 의미 |
|---|---|---|
id | string | 도형 식별자. 판 안에서 유일 |
type | 아래 표 | 도형 종류 |
color | string | 선·채움·글자 색(CSS 색 문자열, 기본 8색은 #rrggbb) |
stroke | number | 선 굵기(1~12). 글자·배지는 size 계산의 근거 |
fill? | "translucent" | "solid" | null | 채우기. 사각형·타원에만 의미. 없거나 null 이면 채우지 않음. translucent 는 불투명도 0.25 |
dashed? | boolean | 점선. 무늬는 [stroke × 3, stroke × 2] |
opacity? | number | 전체 투명도 0~1. 없으면 1 |
종류별 필드:
type | 고유 필드 | 의미 |
|---|---|---|
"rect" | x1, y1, x2, y2: number, radius?: number | 두 모서리 점. 어느 쪽이 작아도 된다. radius 는 모서리 둥글기(px, 폭·높이 절반까지) — UI 로는 못 만들고 데이터로만 지정 |
"ellipse" | x1, y1, x2, y2: number | 바깥 상자의 두 모서리 |
"line" | x1, y1, x2, y2: number | 시작·끝점 |
"arrow" | x1, y1, x2, y2: number | 시작·끝점. (x2, y2) 에 화살촉 |
"arrow2" | x1, y1, x2, y2: number | 양 끝에 화살촉 |
"pen" | points: number[] | [x0, y0, x1, y1, …] 평탄 배열 |
"highlighter" | points: number[] | 위와 같음. 그릴 때 굵기 stroke × 4, 불투명도 0.35 |
"text" | x, y: number, text: string, size: number | 왼쪽 위 기준점, 글자(\n 줄바꿈), 글자 크기(px). 굵은 글꼴, 흰 테두리 |
"badge" | x, y: number, n: number, size: number | 원 중심, 번호, 반지름(px). 색 원 + 흰 숫자 |
TypeScript 로는 Shape 가 type 을 판별자로 하는 합집합 타입이다.
ts
type ToolName = "select" | "pen" | "highlighter" | "line" | "arrow" | "arrow2" | "rect" | "ellipse" | "text" | "badge";
type Fill = "translucent" | "solid";
// Shape 의 type 은 ToolName 에서 "select" 를 뺀 아홉 가지예시
json
{
"version": 1,
"width": 600,
"height": 400,
"background": "data:image/png;base64,iVBORw0KGgo…",
"shapes": [
{ "id": "s1abc0", "type": "rect", "color": "#ef4444", "stroke": 4, "fill": "translucent", "x1": 60, "y1": 80, "x2": 240, "y2": 200 },
{ "id": "s1abc1", "type": "arrow", "color": "#3b82f6", "stroke": 4, "dashed": true, "x1": 60, "y1": 360, "x2": 300, "y2": 240 },
{ "id": "s1abc2", "type": "text", "color": "#111111", "stroke": 4, "x": 300, "y": 20, "text": "여기를 보세요", "size": 30 },
{ "id": "s1abc3", "type": "badge", "color": "#ef4444", "stroke": 4, "x": 30, "y": 40, "n": 1, "size": 16 }
]
}PNG 와의 관계
png 는 renderToPng(data) 로 data 에서 구운 것이다. 순서는 흰 바탕 → 배경 이미지 → shapes 순서대로. 화면(SVG)과 같은 규칙으로 canvas 에 그리므로 팝업에서 본 것과 같은 그림이 나온다.
같은 함수를 직접 부를 수도 있다 — 저장해 둔 JSON 에서 PNG 를 다시 만들 때:
ts
import { renderToPng } from "@newtil/drawing";
const png = await renderToPng(drawing); // Blob("image/png"), 크기 width × height도우미
ts
import { emptyDrawing, bounds } from "@newtil/drawing";
emptyDrawing(); // { version: 1, width: 800, height: 450, background: null, shapes: [] }
emptyDrawing(1280, 720); // 크기 지정
bounds(shape); // { x, y, w, h } — 도형의 바깥 상자. 글자는 어림(글자 폭 0.6em 가정)