Technical Article

Delphi를 사용한 PDF 내 바코드 생성: QR, PDF417, DataMatrix

배송 라벨이나 청구서에 인쇄되는 바코드의 단 한 가지 임무는 첫 번째 스캔 시점에 스캐너에 의해 제대로 해독되는 것입니다. 첫 번째 스캔을 무사히 통과할 수 있을지는 소포가 하역장에 도착하기 훨씬 전에 결정됩니다. 바로 그 기호가 페이지에 어떻게 배치되었는지에 달려 있습니다. Delphi 보고 시스템 파이프라인에서 가장 널리 행해지는 실수는 바코드를 외부 프로그램에서 비트맵으로 렌더링한 후 그 이미지를 PDF에 박는 것입니다. 화면의 특정 배율에서는 깨끗하게 보여도 다른 곳에서는 화질이 쉽게 깨집니다.

가장 좋은 대안은 페이지 안에 직접 기호를 벡터(vector) 콘텐츠로 묘사해 넣는 것입니다. PDFlibPas는 이를 위한 전용 드로잉 함수군을 제공하며, 2D 매트릭스 기호인 QR, PDF417, DataMatrix부터 시작해 선형 계열인 Code128, GS1-128, 우편 자동화용 USPS Intelligent Mail까지 광범위하게 다룹니다. 벡터를 도입하는 기술적 타당성은 단순한 미적 향상에 머물지 않습니다. 스캐너 장비가 예측하는 규격 위치에 바코드 막대들이 정확하게 도달할 수 있는지의 여부에 관한 것입니다.

벡터 구현 방식이 비트맵 삽입 방식보다 우수한 이유

바코드는 막대(bar)와 공백(space)의 조합 무늬이거나, 2D 규격에서는 명암이 엇갈리는 격자형 모듈들로 구성됩니다. 디코더 장치는 이 모듈 너비들의 정밀 비율을 계측해 정보를 해독해 냅니다. 이 배분율을 변형시키는 모든 요소는 바코드 기호가 가진 오류 복구 마진을 저해하는 노이즈로 작용합니다. 래스터화(rasterize)된 비트맵 바코드 이미지는 해상도 픽셀 수가 고정되어 있습니다. 이 PDF 데이터를 인쇄기로 보낼 때 인쇄 핀 도트 눈금이 이미지 그리드 선과 완벽히 1대 1 매핑되지 못하면, 래스터화 엔진은 강제로 리샘플링을 거치게 되며, 이로 인해 경계선이 뭉개져 인접 픽셀로 퍼져 버립니다. 얇은 선이 굵어지거나 인접 공백이 좁아져, 디코더가 참조하는 고유 너비 비율 정보가 왜곡되는 원인입니다.

벡터 그래픽 콘텐츠로 바코드를 그리면, 동일한 기호는 PDF 사용자 공간 좌표를 기반으로 선언된 여러 개의 채워진 직사각형 집합 형태로 묘사됩니다. 고정된 픽셀 그리드와 싸울 필요가 없습니다. 인쇄 출력 시 실제 출력 장비가 가진 물리 해상도로 각 사각형 경계를 직접 채우므로, 확대율이나 크기에 영향받지 않고 인쇄 하드웨어가 제공하는 극한의 경계면 선명도를 확보할 수 있습니다. 화물 팔레트 라벨용으로 크게 확대하거나 일반 우편물용으로 아주 작게 줄여도 기하학적 정밀함이 유지됩니다. 이 정확성이 첫 번째 스캔 시의 해독 성공률을 극대화하며, 이는 페이지에 바코드를 올리는 궁극적인 이유입니다.

QR 코드와 네 가지 오류 수정 레벨

QR은 두 축을 동시에 스캔해 내는 2차원 매트릭스 형태이며, 덕분에 좁은 공간 내에 다량의 정보를 집약시킵니다. 데이터 훼손에 대처하는 복구 복원력은 4개 등급의 리드-솔로몬(Reed-Solomon) 오류 수정 알고리즘에 기초합니다. L 등급은 약 7%의 코드워드를 복구하고, M은 약 15%, Q는 약 25%, H는 약 30%를 자체 정정해 냅니다. 고성능 정정 단계는 거저 얻어지지 않습니다. 복구용 보정 데이터가 격자 면적 용량을 일정 부분 잠식하기 때문에, 동일 데이터 보정 기준 시 고성능 오류 수정 단계를 적용할수록 인쇄 기호 밀도가 조밀해지거나 바코드 전체 실면적이 비대해집니다.

어느 수준을 택할지는 인쇄물이 노출될 유통 환경적 특성에 맞게 상충 관계를 저울질해야 합니다. 화면 액정 preview 상태로만 리딩될 깨끗한 디지털 PDF 명세서라면 L 등급으로 설정해 작고 얇게 만드는 것이 유리합니다. 반면 실물로 인쇄되어 물류 창고에서 긁히고 구겨지거나 상자 테이프 등에 일부 가려질 소포 라벨이라면 Q 또는 H 등급이 필수적입니다. 추가된 백업 코드워드 덕분에 기호가 오염되거나 훼손되어도 디코더가 원본 데이터를 완벽히 복원해 낼 수 있기 때문입니다. DrawQRCode는 드로잉을 고정할 출력 너비와 높이를 지정하는 SymbolSize 및 좌표 값과, 인코딩 방식을 지정하는 EncodeOptions(자동 처리를 뜻하는 0 값 외에 숫자, 알파뉴메릭, ISO-8859-1, UTF-8 변형 등 지정 가능), 회전 각도 방향을 제어할 DrawOptions 등을 인수로 받습니다.

var
  Pdf: TPDFlib;
begin
  Pdf := TPDFlib.Create(nil);
  try
    Pdf.NewDocument;
    Pdf.SetPageSize('A4');
    Pdf.SetMeasurementUnits(1);   // 1 = millimetres
    Pdf.NewPage;

    // 30 mm square QR, automatic encoding, normal orientation
    Pdf.DrawQRCode(20, 20, 30, 'https://www.loslab.com/', 0, 0);

    Pdf.SaveToFile('Label_QR.pdf');
  finally
    Pdf.Free;
  end;
end;

오류 정정 비율 단계 자체는 인코더 엔진이 사용자가 설정한 바코드 최종 크기 면적에 맞춰 데이터를 적절히 배분하여 자동 결정합니다. 거친 물류 현장에 대응하기 위해 높은 수준의 오류 수정을 강제하고자 한다면, 인코더가 압축 정정용 백업 데이터 용량을 확보할 수 있도록 바코드 초기 스케일 면적 크기를 여유롭게 지정해 주십시오.

신분증 및 배송 라벨용 PDF417

PDF417은 적층형 선형(stacked linear) 바코드 기호입니다. 각 행은 아주 짧은 1차원 바코드 형태이며, 이 행들이 여러 개 적층되어 사각형 블록 구조를 형성합니다. 주민등록증, 항공 탑승권, 그리고 대량의 물류 배송 라벨 등 넓은 사각 레이아웃 내에 많은 양의 텍스트 데이터를 우겨넣어야 할 때 활용됩니다. 오류 수정 레벨은 0부터 8까지 선택 가능합니다. 레벨이 높아질 때마다 보정 코드 데이터 크기가 2배씩 늘어나므로, 레벨 5는 레벨 1에 비해 월등한 복구 능력을 제공하는 반면 문서 내 인쇄 공간을 더 많이 차지합니다.

라벨 인쇄 영역은 언제나 한정되어 있으므로, PDF417 블록의 기하학적 윤곽 형태를 자유롭게 조절할 수 있어야 합니다. DrawPDF417SymbolEx는 기본형 드로잉 메서드가 지원하지 않는 고급 제어 인수를 제공합니다. FixedColumnsFixedRows는 가로 열 및 세로 행의 한계 개수를 강제 설정하며, 0 값을 넘겨주면 인코더 엔진이 최적 규격으로 자동 배치합니다. ErrorLevel은 자동 매핑을 의미하는 -1 외에 0~8의 명시적 레벨 값을 전달받습니다. ModuleSize는 설정된 현재 치수 단위 기준의 최소 소선(module) 너비 치수이며, HeightWidthRatio는 가로 폭 폭 대비 개별 모듈의 세로 비율을 지정해 사각형 인쇄 배치 공간에 꼭 들어맞도록 바코드 세로 길이를 높이거나 낮출 때 씁니다.

// Fixed 10 data columns, automatic rows, error level 5,
// module 0.30 mm wide, rows three times the module width tall
Pdf.DrawPDF417SymbolEx(20, 60, 'PDF417 PAYLOAD 0123456789',
  0,        // Options: 0 = normal orientation
  10,       // FixedColumns
  0,        // FixedRows: 0 = automatic
  5,        // ErrorLevel: 0 to 8
  0.30,     // ModuleSize, in the current measurement unit
  3.0);     // HeightWidthRatio

라벨 템플릿 영역 설계 시 열 개수(column count)를 고정하는 방식이 주로 쓰입니다. 열 수가 고정되면 데이터가 변경되더라도 가로 인쇄 폭이 일정하게 유지되므로 주변 명세서 서식이 틀어지지 않으며, 인코더가 데이터 증가량에 맞춰 세로 행 높이만 아래로 유연하게 늘려 대응합니다.

초소형 마킹 전용 DataMatrix

DataMatrix는 아주 협소한 인쇄 영역 내에 바코드를 새겨야 할 때 활용하는 최적의 기호입니다. 현대적 정정 규격인 ECC 200 리드-솔로몬 기반 2차원 밀집 격자 형식을 쓰며, 동일 데이터 규격 기준 QR을 새기기 곤란한 미세 공정 크기 영역에서도 스캐너 해독율을 안정적으로 확보해 줍니다. 반도체 부품 표면 직접 각인(DPM), 소형 전자 장비 부품 스티커, 그리고 오밀조밀한 물류 분류 바코드 등에 널리 도입되어 있습니다.

DrawDataMatrixSymbol은 기본 모듈의 간격(pitch)을 정할 ModuleSize, ASCII를 뜻하는 1 값 형식의 Encoding, 그리고 자동 매핑을 뜻하는 0 또는 10x10부터 132x132 규격 사각 격자 크기 규격을 제어할 SymbolSize를 전달받습니다. Options 매개변수는 회전 각도값과 여백 영역(quiet-zone) 너비를 복합적으로 수용하며, 여기에 100~400을 더해 1~4단위 모듈 두께의 외곽 흰색 테두리 여백을 설정할 수 있습니다. 외곽 여백은 단순한 디자인적 장식이 아닙니다. 디코더 장비가 데이터 수집 전에 고유 외곽 패턴(finder pattern)의 위치를 감지하기 위해 필요한 완충 지대이며, 주변 텍스트 잉크와 지나치게 밀착되어 붙어 있으면 기호 획득 실패 오류를 겪게 됩니다.

// Auto-sized ASCII DataMatrix, 0.5 mm module, normal orientation
// with a one-module quiet zone (Options 0 + 100)
Pdf.DrawDataMatrixSymbol(20, 110, 0.5, 'DMX-SN-4408812',
  1,        // Encoding: 1 = ASCII
  0,        // SymbolSize: 0 = automatic
  100);     // Options: normal + one-module quiet zone

1차원 선형 바코드가 여전히 널리 쓰이는 이유

2차원 복합 기호들이 눈길을 끌지만, 전통적인 1차원 선형 바코드는 소매 유통 및 도소매 물류 도크의 주류 장비인 단일 광선 레이저 스캐너 인프라 덕분에 여전히 업계의 큰 비중을 차지합니다. Code128은 알파뉴메릭(문자+숫자) 데이터를 다루는 표준 규격이며, 세 가지 캐릭터 셋(Character Set)을 유연하게 교체해 성능을 최적화합니다. 캐릭터 셋 A는 특수 제어 코드와 영문 대문자 위주, B는 전체 출력 가능 ASCII 코드 범위, C는 순수 숫자 데이터를 처리할 때 씁니다. 셋 C는 두 자리 숫자를 단 한 자의 바코드 단위 기호로 압축해 묘사하므로, 숫자 데이터를 연속으로 표현할 때 A나 B 방식을 쓸 때보다 바코드 가로 길이를 정확히 절반으로 축소시킵니다. 긴 숫자를 표현할 때 공간 효율성이 가장 우수하며, PDFlibPas Code128 컴포넌트는 최적의 규격 길이 도출을 위해 B와 C 캐릭터 셋 변환을 내부적으로 자동 수행합니다.

EAN-128로 알려졌던 GS1-128 표준은 Code128 규격에 물류용 식별자 정보(Application Identifier, 특정 정보 종류를 의미하는 괄호 접두사)를 수반할 수 있도록 개량한 것입니다. 이 식별자 정보를 통해 인식하는 시스템은 뒤따르는 문자열이 소포 시리얼인지, 제품 로트 일련번호인지, 유통기한 날짜 정보인지 등을 정확하게 가려 판별합니다. 이 구조적 신호는 특수 제어 문자인 FNC1 부호 코드로 개시됩니다. PDFlibPas 라이브러리 내에서는 DrawBarcode 함수 호출 시 Code128 타입을 명시하고 식별자 기호가 새로 개시되는 지점 위치에 리터럴로 [FNC1] 문자열 값을 직접 기입하여 GS1-128 코드를 손쉽게 구현합니다.

var
  W: Double;
begin
  // Code128, with FNC1 markers this becomes a GS1-128 symbol.
  // AI 21 (serial) = ABC123, AI 20 (variant) = 13
  Pdf.DrawBarcode(20, 150, 60, 18, '[FNC1]21ABC123[FNC1]2013',
    3,        // Barcode: 3 = Code128
    0);       // Options: 0 = default drawing

  // Measure the rendered width for a 0.30 mm narrow bar before laying out
  W := Pdf.GetBarcodeWidth(0.30, '[FNC1]21ABC123[FNC1]2013', 3);
end;

우편 정보용 표준인 USPS Intelligent Mail(일명 OneCode)은 데이터 값에 따라 막대의 세로 높낮이를 가변적으로 변경하는(height-modulated) 선형 바코드의 특수한 형태입니다. DrawIntelligentMailBarcode는 개별 막대 폭, 전체 세로 한계 높이, 기준 트래커 라인 세로 치수, 간격 너비 등의 기하 구조 치수들을 입력받고, 20/25/29/31자리의 숫자로 구성된 데이터 문자열을 받아 바코드를 그립니다. 막대와 트래커 라인의 물리 세로 크기 규정이 엄격한 이유는, 장비가 해독 시 개별 막대가 전체 막대(full bar)인지, 상단 확장(ascender)인지, 하단 확장(descender)인지 등의 상태를 높이를 통해 판별하며, 우체국 스캐너 시스템이 이 높낮이 설계 규격 정보의 오차율을 기준으로 데이터를 해석하기 때문입니다.

페이지 내 기호 묘사 및 레이아웃 사전 산출

본 문서에 소개된 모든 드로잉 호출 함수는 현재 페이지 정보 캔버스 영역 내에 내용을 즉시 기록하므로, 바코드를 별도 파일 등의 외부 파일 이미지 형태로 불러오는 대신 순수 PDF 문서 생성 주기 내에서 원천적으로 그려냅니다. 바코드 기호가 온전히 벡터 수치 좌표 데이터로 묘사되기 때문에, 데이터 크기와 차지할 면적이 생성되는 시점에서 좌표값 계산식으로 미리 결정될 수 있어 일관된 좌표 배치가 가능해집니다.

선형 1차원 바코드 계열은 그리기 작업 개시 전에 총 가로 크기를 먼저 산출해 보면 유용합니다. GetBarcodeWidth는 기본 모듈 소선 두께값과 바코드 유형 정보를 전달받아 최종적으로 묘사될 가로 전체 치수를 리턴하므로, 바코드를 그린 후에 서식 글씨가 겹치는 실수를 방지하고 그릴 공간을 레이아웃에 정확히 예약할 수 있습니다. 2차원 바코드들은 SymbolSizeModuleSize를 통해 가로세로 점유 면적 치수가 고정형으로 지정되므로 서식 배치가 훨씬 쉽습니다. 어떠한 방식을 활용하든 원칙은 일관됩니다. 리딩 기기가 요구하는 물리 기준 면적 크기를 확보하고, 기호가 서식 배치 프레임 내에 무사히 들어맞는지 검증한 뒤, 실물 출력기에서도 극한의 외곽선 선명도를 지키도록 벡터 수치 계산 좌표 형태로 생성해 보십시오.

바코드를 얹어 완성된 PDF 페이지를 관리하는 더 넓은 흐름의 기술들은, PDF 텍스트 이미지 추출 안내 문서에서 내용을 확인해 볼 수 있으며, 대용량 파일을 제어하는 방식은 대규모 PDF의 고속 병합 분할 안내 가이드를 참고하십시오. 두 문서 모두 본 문서에서 설명한 드로잉 메커니즘을 핵심으로 응용하며, 이는 Delphi 및 C++Builder용 Delphi PDF Library에 포함되어 종합적으로 제공됩니다.