운송장
택배 운송장을 만들고, 뽑은 파일에 나중에 글자를 얹습니다. JPEG 로 받는 법과 이미 있는 PDF 에 워터마크·글자를 얹는 법을 배웁니다.
여기서 배우는 것
편집기로 만들기
- 보내는 곳과 받는 곳을 사각형 두 개로 나눕니다. 모서리를 둥글리면 인쇄물에서 두 묶음이 눈에 잘 갈립니다.
- 추적 QR 을 넣고 값에 추적 주소를 적습니다. 스마트폰으로 찍는 용도라 QR 이 맞습니다.
- 운송장은 접히고 젖습니다. 글자를 작게 쓰지 말고, 중요한 것은 굵게 두십시오.
스키마 · API 로 만들기
- format 을 "jpeg" 로 두면 JPEG 로 받습니다. quality 를 1~100 으로 줄 수 있습니다.
- quality 는 JPEG 에만 적용됩니다. PNG 와 함께 보내면 무시하지 않고 거절합니다 — 조용히 무시된 옵션은 저희 쪽 결함처럼 보입니다.
- 이미 뽑은 PDF 에 글자를 얹으려면 POST /v1/files 로 올리고 POST /v1/pdf/stamp 를 부릅니다. text 는 필수이고, pages · x · y · size · opacity · rotate · color 를 줄 수 있습니다.
- 워터마크와 글자 추가는 같은 엔진이고 옵션만 다릅니다. 쪽 번호는 1부터이고, 좌표는 쪽 좌하단 기준 pt 입니다.
- ⚠ 얹는 글자는 Latin-1 만 됩니다. 한글·한자·이모지는 거절합니다 — 표준 글꼴로 그릴 수 없고, 깨진 글자를 조용히 찍는 것보다 거절이 낫기 때문입니다.
만든 뒤에
뽑은 파일에 글자 얹기
POST /v1/pdf/stamp
{
"file": "file_01J…",
"text": "REPRINT",
"pages": [
1
],
"size": 48,
"opacity": 0.15,
"rotate": 30,
"color": "#d92d20"
}완성 문서
아래 JSON 이 위 두 순서가 만드는 바로 그 문서입니다. 저희 테스트가 이 문서를 검증하고 경고 없이 렌더되는지 확인하므로, 그대로 붙여 넣어 쓰셔도 됩니다.
{
"v": 1,
"unit": "px",
"page": {
"size": "a5",
"orientation": "portrait",
"margin": {
"t": 14,
"r": 14,
"b": 14,
"l": 14
},
"header": "",
"footer": ""
},
"fonts": [],
"styles": [
{
"id": "s_h",
"fontFamily": "Liberation Sans",
"fontSize": 11,
"fontWeight": 400,
"italic": false,
"color": "#666666",
"bg": "transparent",
"align": "left",
"valign": "top",
"lineHeight": 1.5,
"border": "none",
"radius": 0,
"opacity": 1
},
{
"id": "s_b",
"fontFamily": "Liberation Sans",
"fontSize": 16,
"fontWeight": 700,
"italic": false,
"color": "#111111",
"bg": "transparent",
"align": "left",
"valign": "top",
"lineHeight": 1.5,
"border": "none",
"radius": 0,
"opacity": 1
},
{
"id": "s_l",
"fontFamily": "Liberation Sans",
"fontSize": 12,
"fontWeight": 400,
"italic": false,
"color": "#222222",
"bg": "transparent",
"align": "left",
"valign": "top",
"lineHeight": 1.5,
"border": "none",
"radius": 0,
"opacity": 1
},
{
"id": "s_box",
"fontFamily": "Liberation Sans",
"fontSize": 12,
"fontWeight": 400,
"italic": false,
"color": "#111111",
"bg": "transparent",
"align": "left",
"valign": "top",
"lineHeight": 1.5,
"border": "none",
"radius": 10,
"opacity": 1
}
],
"nodes": [
{
"id": "n_from",
"parent": "",
"order": 0,
"type": "rect",
"x": 0,
"y": 0,
"w": 391,
"h": 96,
"show": "",
"styleId": "s_box",
"props": {
"text": "",
"src": "",
"fit": "",
"thickness": 1,
"stroke": "#dfe3e8",
"fill": "#fafbfc",
"repeat": "",
"as": "",
"break": "",
"keep": "",
"padding": 0,
"padY": 0,
"padX": 0,
"align": "",
"valign": "",
"wrap": "",
"bind": "",
"headerHeight": 0,
"rowHeight": 0,
"max": 0,
"columns": [],
"rows": 0,
"cells": [],
"chartKind": "",
"codeKind": "",
"ecc": "",
"fieldKind": "",
"fieldName": "",
"options": [],
"required": false,
"readonly": false,
"html": ""
},
"name": "Sender block"
},
{
"id": "n_from_h",
"parent": "n_from",
"order": 1,
"type": "label",
"x": 12,
"y": 10,
"w": 360,
"h": 14,
"show": "",
"styleId": "s_h",
"props": {
"text": "From",
"src": "",
"fit": "",
"thickness": 0,
"stroke": "",
"fill": "",
"repeat": "",
"as": "",
"break": "",
"keep": "",
"padding": 0,
"padY": 0,
"padX": 0,
"align": "",
"valign": "",
"wrap": "",
"bind": "",
"headerHeight": 0,
"rowHeight": 0,
"max": 0,
"columns": [],
"rows": 0,
"cells": [],
"chartKind": "",
"codeKind": "",
"ecc": "",
"fieldKind": "",
"fieldName": "",
"options": [],
"required": false,
"readonly": false,
"html": ""
},
"name": "From caption"
},
{
"id": "n_from_n",
"parent": "n_from",
"order": 2,
"type": "label",
"x": 12,
"y": 28,
"w": 360,
"h": 20,
"show": "",
"styleId": "s_b",
"props": {
"text": "{{ data.from.name }}",
"src": "",
"fit": "",
"thickness": 0,
"stroke": "",
"fill": "",
"repeat": "",
"as": "",
"break": "",
"keep": "",
"padding": 0,
"padY": 0,
"padX": 0,
"align": "",
"valign": "",
"wrap": "",
"bind": "",
"headerHeight": 0,
"rowHeight": 0,
"max": 0,
"columns": [],
"rows": 0,
"cells": [],
"chartKind": "",
"codeKind": "",
"ecc": "",
"fieldKind": "",
"fieldName": "",
"options": [],
"required": false,
"readonly": false,
"html": ""
},
"name": "Sender"
},
{
"id": "n_from_a",
"parent": "n_from",
"order": 3,
"type": "label",
"x": 12,
"y": 50,
"w": 360,
"h": 0,
"show": "",
"styleId": "s_l",
"props": {
"text": "{{ data.from.address }}",
"src": "",
"fit": "",
"thickness": 0,
"stroke": "",
"fill": "",
"repeat": "",
"as": "",
"break": "",
"keep": "",
"padding": 0,
"padY": 0,
"padX": 0,
"align": "",
"valign": "",
"wrap": "",
"bind": "",
"headerHeight": 0,
"rowHeight": 0,
"max": 0,
"columns": [],
"rows": 0,
"cells": [],
"chartKind": "",
"codeKind": "",
"ecc": "",
"fieldKind": "",
"fieldName": "",
"options": [],
"required": false,
"readonly": false,
"html": ""
},
"name": "Sender address"
},
{
"id": "n_to",
"parent": "",
"order": 4,
"type": "rect",
"x": 0,
"y": 112,
"w": 391,
"h": 120,
"show": "",
"styleId": "s_box",
"props": {
"text": "",
"src": "",
"fit": "",
"thickness": 2,
"stroke": "#111111",
"fill": "",
"repeat": "",
"as": "",
"break": "",
"keep": "",
"padding": 0,
"padY": 0,
"padX": 0,
"align": "",
"valign": "",
"wrap": "",
"bind": "",
"headerHeight": 0,
"rowHeight": 0,
"max": 0,
"columns": [],
"rows": 0,
"cells": [],
"chartKind": "",
"codeKind": "",
"ecc": "",
"fieldKind": "",
"fieldName": "",
"options": [],
"required": false,
"readonly": false,
"html": ""
},
"name": "Recipient block"
},
{
"id": "n_to_h",
"parent": "n_to",
"order": 5,
"type": "label",
"x": 12,
"y": 10,
"w": 360,
"h": 14,
"show": "",
"styleId": "s_h",
"props": {
"text": "To",
"src": "",
"fit": "",
"thickness": 0,
"stroke": "",
"fill": "",
"repeat": "",
"as": "",
"break": "",
"keep": "",
"padding": 0,
"padY": 0,
"padX": 0,
"align": "",
"valign": "",
"wrap": "",
"bind": "",
"headerHeight": 0,
"rowHeight": 0,
"max": 0,
"columns": [],
"rows": 0,
"cells": [],
"chartKind": "",
"codeKind": "",
"ecc": "",
"fieldKind": "",
"fieldName": "",
"options": [],
"required": false,
"readonly": false,
"html": ""
},
"name": "To caption"
},
{
"id": "n_to_n",
"parent": "n_to",
"order": 6,
"type": "label",
"x": 12,
"y": 28,
"w": 360,
"h": 26,
"show": "",
"styleId": "s_b",
"props": {
"text": "{{ data.to.name }}",
"src": "",
"fit": "",
"thickness": 0,
"stroke": "",
"fill": "",
"repeat": "",
"as": "",
"break": "",
"keep": "",
"padding": 0,
"padY": 0,
"padX": 0,
"align": "",
"valign": "",
"wrap": "",
"bind": "",
"headerHeight": 0,
"rowHeight": 0,
"max": 0,
"columns": [],
"rows": 0,
"cells": [],
"chartKind": "",
"codeKind": "",
"ecc": "",
"fieldKind": "",
"fieldName": "",
"options": [],
"required": false,
"readonly": false,
"html": ""
},
"name": "Recipient"
},
{
"id": "n_to_a",
"parent": "n_to",
"order": 7,
"type": "label",
"x": 12,
"y": 56,
"w": 360,
"h": 0,
"show": "",
"styleId": "s_l",
"props": {
"text": "{{ data.to.address }}",
"src": "",
"fit": "",
"thickness": 0,
"stroke": "",
"fill": "",
"repeat": "",
"as": "",
"break": "",
"keep": "",
"padding": 0,
"padY": 0,
"padX": 0,
"align": "",
"valign": "",
"wrap": "",
"bind": "",
"headerHeight": 0,
"rowHeight": 0,
"max": 0,
"columns": [],
"rows": 0,
"cells": [],
"chartKind": "",
"codeKind": "",
"ecc": "",
"fieldKind": "",
"fieldName": "",
"options": [],
"required": false,
"readonly": false,
"html": ""
},
"name": "Recipient address"
},
{
"id": "n_qr",
"parent": "",
"order": 8,
"type": "code",
"x": 0,
"y": 248,
"w": 120,
"h": 120,
"show": "",
"styleId": "s_l",
"props": {
"text": "https://track.example.com/{{ data.tracking }}",
"src": "",
"fit": "",
"thickness": 0,
"stroke": "",
"fill": "",
"repeat": "",
"as": "",
"break": "",
"keep": "",
"padding": 0,
"padY": 0,
"padX": 0,
"align": "",
"valign": "",
"wrap": "",
"bind": "",
"headerHeight": 0,
"rowHeight": 0,
"max": 0,
"columns": [],
"rows": 0,
"cells": [],
"chartKind": "",
"codeKind": "qr",
"ecc": "M",
"fieldKind": "",
"fieldName": "",
"options": [],
"required": false,
"readonly": false,
"html": ""
},
"name": "Tracking QR"
},
{
"id": "n_track",
"parent": "",
"order": 9,
"type": "label",
"x": 136,
"y": 268,
"w": 255,
"h": 24,
"show": "",
"styleId": "s_b",
"props": {
"text": "{{ data.tracking }}",
"src": "",
"fit": "",
"thickness": 0,
"stroke": "",
"fill": "",
"repeat": "",
"as": "",
"break": "",
"keep": "",
"padding": 0,
"padY": 0,
"padX": 0,
"align": "",
"valign": "",
"wrap": "",
"bind": "",
"headerHeight": 0,
"rowHeight": 0,
"max": 0,
"columns": [],
"rows": 0,
"cells": [],
"chartKind": "",
"codeKind": "",
"ecc": "",
"fieldKind": "",
"fieldName": "",
"options": [],
"required": false,
"readonly": false,
"html": ""
},
"name": "Tracking number"
}
]
}요청 본문입니다. template 자리에 위 문서를, data 자리에 아래 데이터를 넣습니다.
{
"template": "(the document above)",
"data": {
"from": {
"name": "brewmypdf",
"address": "118 Seongsui-ro, Seongdong-gu, Seoul"
},
"to": {
"name": "Do-hyun Kim",
"address": "145 Gwanggyo-ro, Yeongtong-gu, Suwon — Apt 302-1201"
},
"tracking": "BM1234567890"
},
"format": "jpeg",
"quality": 92
}