Component Lab
DocumentJun 10, 2026

PDF 어노테이션 → AcroForm 변환기

스캔된 PDF엔 입력란이 없다. 그 위에 칸을 직접 그려 위치만 넘기면, 채울 수 있는 양식으로 구워진다. 좌표가 오가는 과정을 그대로 옮겨 봤다.

pointer events정규화 좌표계LLM 변환(시뮬)
Text
Checkbox
박스를 드래그·리사이즈해 보세요

POST payload · bbox_norm

{
  "fields": [
    {
      "field_name": "text_0",
      "field_type": "text",
      "bbox_norm": {
        "x0": 0.12,
        "y0": 0.16,
        "x1": 0.62,
        "y1": 0.24
      }
    },
    {
      "field_name": "checkbox_1",
      "field_type": "checkbox",
      "bbox_norm": {
        "x0": 0.12,
        "y0": 0.42,
        "x1": 0.18,
        "y1": 0.48
      }
    }
  ]
}

병원 사전승인 양식은 대부분 그냥 스캔한 PDF였다. 입력란이 없으니 출력해서 손으로 적는 수밖에 없다. 자동으로 채우려면 “여기에 이런 칸이 있다”는 걸 먼저 알려줘야 한다. 그래서 사람이나 AI가 그 자리를 오버레이로 찍어 주면, 백엔드가 실제로 입력 가능한 양식으로 바꿔 준다.

처음엔 화면 픽셀 좌표를 그대로 보냈다. 그런데 화면 크기나 DPI가 달라지면 칸이 어긋났다. 그래서 모든 박스를 페이지 대비 0~1 비율(bbox_norm)로 저장하기로 했다. 오른쪽 payload가 드래그할 때마다 바뀌는데, 이 값이면 어떤 해상도에서도 같은 자리에 다시 그릴 수 있다. 화면 좌표와 정규화 좌표 사이에 경계를 둔 게 이 데모의 핵심이다.

렌더링, 필드 파싱, 드래그 오버레이, 변환을 각각 따로 떼어 놨다. UI는 화면 좌표로 움직이고 API는 정규화 좌표로만 말하게 해서, 한쪽을 손봐도 다른 쪽이 휘청이지 않는다. 이 층들을 눈으로 펼쳐 본 게 옆에 있는 “레이어드 아키텍처 익스플로러” 포스트다.

여기선 진짜 pdfjspdf-lib, 백엔드 호출을 쓰지 않는다. 데이터가 흐르는 모양만 똑같이 따라 했다. 가짜 페이지에 칸을 놓고 → 정규화 payload를 만들고 → 변환 단계를 흉내 낸 뒤, 박스가 입력 위젯으로 바뀐 결과까지 보여 준다.