gpdf 에서 투명 PNG 를 임베드하는 방법
PNG 바이트를 그대로 c.Image 에 넘긴다. gpdf 가 알파 채널을 PDF SMask 로 변환해 투명 배경이 그대로 렌더된다.
질문을 다시 표현하면
로고나 도장을 배경 투명 PNG — Photoshop 이나 Figma 가 내보내는 RGBA PNG — 로 가지고 있다. 이걸 gpdf 의 PDF 에 임베드하면 투명 영역이 그대로 투명으로 남는가? 아니면 로고 주변에 흰색 박스가 생기는가?
빠른 답
PNG 바이트를 c.Image 에 넘기면 끝이다. 추가 옵션은 필요 없다. gpdf 가 알파 채널을 디코드해 PDF SMask (소프트 마스크) 객체를 이미지와 함께 작성한다. 투명 픽셀은 그대로 투명으로 렌더된다.
logo, _ := os.ReadFile("logo.png")
c.Image(logo, template.FitWidth(document.Mm(40)))
레시피는 이게 전부. 흰 배경에 알파를 평탄화할 필요도, RGBA 를 RGB 로 변환할 필요도, "투명도 활성화" 같은 옵션을 넘길 필요도 없다. PNG 는 PDF 까지 PNG 로 간다.
그대로 돌릴 수 있는 완성 예제
투명도를 실제로 보려면 PNG 아래에 비쳐 보일 무언가가 있어야 한다. 본문 위에 워터마크를 올리는 패턴이 가장 흔하고, page.Absolute 는 로고를 고정 좌표에 배치하면서 일반 흐름의 콘텐츠가 그 아래에 페이지를 채우게 해준다.
package main
import (
"log"
"os"
"github.com/gpdf-dev/gpdf"
"github.com/gpdf-dev/gpdf/document"
"github.com/gpdf-dev/gpdf/template"
)
func main() {
stamp, err := os.ReadFile("draft-stamp.png")
if err != nil {
log.Fatal(err)
}
doc := gpdf.NewDocument(
gpdf.WithPageSize(gpdf.A4),
gpdf.WithMargins(document.UniformEdges(document.Mm(20))),
)
page := doc.AddPage()
page.AutoRow(func(r *template.RowBuilder) {
r.Col(12, func(c *template.ColBuilder) {
c.Text("분기 보고서 — 2026 Q1", template.FontSize(20), template.Bold())
c.Text("1 분기 매출은 전년 동기 대비 38% 증가했다. 엔터프라이즈 갱신과 금융 서비스 신규 고객 3 곳이 견인했다. 인프라 비용이 정체되며 영업이익률은 24% 까지 확대됐다.")
c.Text("분기말 직원은 142 명. 4 분기말 128 명에서 14 명 순증, 그중 9 명이 엔지니어링 채용이다.")
})
})
page.Absolute(document.Mm(60), document.Mm(120), func(c *template.ColBuilder) {
c.Image(stamp, template.FitWidth(document.Mm(80)))
})
data, err := doc.Generate()
if err != nil {
log.Fatal(err)
}
if err := os.WriteFile("report-draft.pdf", data, 0o644); err != nil {
log.Fatal(err)
}
}
draft-stamp.png 은 빨간 굵은 "DRAFT" 글씨에 배경이 완전히 투명한 RGBA PNG 라고 가정한다. 본문 위에 올려지면 모든 투명 픽셀이 아래 단락을 비치게 한다. draft-stamp.png 을 어떤 로고, 인장, 서명 이미지로 바꿔도 된다 — 같은 코드 경로, 같은 SMask 처리가 돈다.
gpdf 가 PNG 에 실제로 하는 일
흥미로운 건 writer 쪽이다. PDF 에는 "RGBA 이미지" 라는 단일 객체가 없다. RGB 이미지 객체와 그에 대응하는 그레이스케일 SMask (소프트 마스크) 이미지 가 짝을 이루고, 마스크의 각 픽셀 값이 메인 이미지의 알파로 사용된다. 합성은 PDF 리더가 렌더 시점에 한다.
PNG 를 gpdf 에 넘기면 렌더러 (document/render/pdftarget.go) 가 픽셀 격자를 한 번 훑는다:
- 24 비트 RGB 가 메인 이미지 스트림에 들어가고 FlateDecode 로 압축된다
- 8 비트 알파가 별도의 SMask 스트림에 들어가고 역시 FlateDecode 된다
- 이미지 사전에
/SMask <ref>가 추가되어 알파 스트림을 참조한다
모든 알파 샘플이 0xFF (완전 불투명) 으로 끝나면 gpdf 는 알파 버퍼를 버리고 SMask 작성을 건너뛴다. JPEG 같은 불투명 PNG 는 결과물에서 추가 비용이 0 이라는 뜻. 비용은 알파가 실제로 일을 할 때만 든다.
이 경로 전체가 pure Go 다 — 표준 라이브러리의 image/png 가 디코드를, compress/flate 가 압축을 맡는다. CGO 도, libpng 의존성도 없다. macOS 에서 linux/arm64 (Lambda 등) 으로 크로스컴파일해도 결과는 여전히 정적 바이너리 한 개다.
JPEG 함정
"투명한" 로고가 어떤 도구에서 JPEG 로 내보내졌다면, 투명도는 gpdf 가 그 파일을 보기 전에 이미 사라졌다. JPEG 는 알파 채널을 가질 수 없으므로, 내보낸 도구가 적당한 배경색 (보통 흰색) 으로 알파를 평탄화한 상태다.
c.Image(jpegBytes) 자체는 잘 동작하지만, 임베드된 이미지는 원래 투명이던 자리에 불투명한 흰색 (혹은 검정, 분홍) 사각형을 남긴다. 수정은 상류에서 — PNG 로 다시 내보내야 한다. gpdf 에는 JPEG 에서 사라진 투명도를 복원하는 옵션이 없다.
"PNG-8" 의 팔레트 투명도는 별개 이슈다. gpdf 는 표준 image/png 를 쓰므로 팔레트 PNG 도 정상적으로 처리한다. 문제는 자산 파이프라인 어딘가에서 실수로 JPEG 를 거치는 경우 — 한 번 잃어버린 데이터는 돌아오지 않는다.
크기 조정과 워터마크
실용적인 확장은 두 가지로 충분하다.
로고 스케일링: template.FitWidth(document.Mm(40)) 또는 template.FitHeight(document.Mm(20)) 을 넘긴다. PNG 는 풀 해상도로 디코드된 뒤, 렌더링 시점에 PDF 좌표 변환으로 축소된다 — 알파에는 리샘플링 단계가 없다. 가장자리는 변함없이 또렷하다.
대각선 "DRAFT" 워터마크: 워터마크를 알파가 옅은 (25–40% 정도) PNG 로 만들고, 위 예제처럼 page.Absolute 로 배치한다. 알파가 픽셀 단위이므로 워터마크 안에서 불투명도를 변화시키는 것도 가능하다 — 그라디언트 페이드, 로고 실선 주변만 반투명, 같은 식. PDF 리더가 아래 텍스트와 알아서 합성한다.
픽셀 정확도로 30% 불투명도 오버레이가 필요하면 그건 이미지 편집기에서 알파를 굽는 결정이다. gpdf 는 받은 알파 값을 그대로 재현할 뿐이고, Builder API 에 이미지 단위 불투명도 곱셈 옵션은 없다.
파일 크기 감각
알파 있는 PNG → RGB 스트림 + 그레이스케일 SMask 스트림이므로 알파 없는 같은 이미지 대비 대략 33% 더 크다. 100 KB 의 불투명 PNG 임베드는 알파를 붙이면 약 133 KB 가 된다. 로고 한 장이라면 체감되지 않는다. 50 페이지 보고서에 페이지마다 워터마크를 깔아도 마찬가지 — SMask 는 한 번 등록되어 각 페이지에서 참조될 뿐 복제되지 않는다.
이미지 한 장이 갑자기 메가바이트 단위가 된다면 원인은 gpdf 의 인코딩이 아니라 원본 PNG 다. 임베드 전에 pngquant 나 oxipng 에 한 번 통과시키자. 알파 채널은 두 도구 모두에서 살아남는다.
관련 레시피
- gpdf 에서 일본어 폰트 임베드하기 — 같은 "바이트만 넘기면 된다" 패턴, TrueType 버전
- Go 로 50 줄 이내에 인보이스 PDF 만들기 — 투명 회사 로고가 실제 문서에서 보통 어디에 배치되는지
- gpdf 가 다른 Go PDF 라이브러리보다 10–30× 빠른 이유 — pure Go 디코드 경로가 마이크로초 단위로 무엇을 쓰고 무엇을 절약하는지
gpdf 사용해 보기
gpdf 는 Go 의 PDF 생성 라이브러리다. MIT, 의존성 0, PNG 와 TrueType 모두 pure Go 처리.
go get github.com/gpdf-dev/gpdf