Skip to content

데이터 형식

완료하면 OpenResult 로 두 가지가 온다.

타입용도
pngBlob (image/png)독자용 결과물. 문서·이미지 태그에 넣는다
dataDrawing재편집용 원본. 도형이 살아 있다. initial 로 넘기면 그대로 다시 열린다

PNG 만 남기면 도형이 그림에 박혀 다시 고칠 수 없다. data 를 PNG 옆에 곁파일로 함께 저장하는 것이 기본 흐름이다.

Drawing

ts
interface Drawing {
  version: 1;
  width: number;
  height: number;
  background: string | null;
  shapes: Shape[];
}
필드타입의미
version1스키마 버전. @newtil/editor 가 곁파일로 저장하던 DrawingData v1 과 같은 모양이라 기존 곁파일이 그대로 열린다
widthnumber판 가로(px). 모든 좌표의 기준
heightnumber판 세로(px)
backgroundstring | null배경 캡처 — data URL. null 이면 흰 판
shapesShape[]도형. 배열 순서 = 그리는 순서(뒤가 위)
  • 빈 판 기본 크기는 800×450 (emptyDrawing()).
  • 배경을 넣으면 width·height 는 배경 이미지 크기가 된다. 긴 변이 1600px 을 넘으면 그 한도로 줄인다.

자기 완결성

background 는 파일이든 주소든 반드시 data URL 로 구워 넣는다. 그래서 Drawing JSON 하나만 있으면 어느 서버·어느 페이지에서도 다시 열리고, 나중에 canvas 로 다시 구울 수 있다(교차 출처 이미지는 canvas 를 오염시켜 못 굽는다). 대신 배경이 있으면 JSON 이 수백 KB~수 MB 가 된다.

Shape

모든 도형이 갖는 공통 필드:

필드타입의미
idstring도형 식별자. 판 안에서 유일
type아래 표도형 종류
colorstring선·채움·글자 색(CSS 색 문자열, 기본 8색은 #rrggbb)
strokenumber선 굵기(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 로는 Shapetype 을 판별자로 하는 합집합 타입이다.

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 와의 관계

pngrenderToPng(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 가정)