바코드는 문서를 장식하는 그림이 아닙니다. 바코드는 측정값이며, 스캐너는 이를 읽는 도구입니다. 이러한 재구성은 PDF에 바코드를 그리는 방법에 대한 거의 모든 것을 결정합니다. 막대는 검은색 자체로 정보를 전달하지 않습니다; 정보는 막대 너비 대 공백 너비의 비율에 존재하며, 리더기(reader)는 레이저나 센서가 스캔할 때의 전환을 타이밍하여 이를 복구합니다. 해당 기하학적 구조를 압축하거나, 흐리게 하거나, 여백을 좁히면 겉보기에는 바코드와 똑같아 보이지만 얼룩처럼 스캔되는 결과물이 생성됩니다. HotPDF는 페이지에 바코드를 배치하는 두 가지 방법을 제공하며, 그 둘의 차이는 기하학적 구조를 통제하는 것과 포기하는 것의 차이와 정확히 같습니다

HotPDF가 인코딩할 수 있는 것
HotPDF는 선형(1차원) 기호를 그리며, 그 세트는 대부분의 프로젝트에서 필요로 하는 것보다 광범위합니다. THPDFBarcodeType 열거형은 교차(interleaved), 산업용 및 매트릭스 형태의 Code 2 of 5 제품군; Code 39 및 그 확장 변형; 세 가지 Code 128 하위 집합 A, B, C; Code 93 기본 및 확장; MSI; PostNet; Codabar; 소매용 UPC 및 EAN 그룹, 즉 EAN-8, EAN-13, UPC-A, 압축된 UPC-E0 및 UPC-E1, 그리고 UPC 추가 2자리 및 5자리 부가 기호(add-on); 그리고 GS1-128 (EAN-128) 하위 집합을 다룹니다. 이는 공급망 라벨, 소매점 POS(Point of Sale) 및 창고에 여전히 남아 있는 오래된 산업용 코드를 처리하기에 충분합니다
이 컴포넌트가 그리지 않는 것은 2차원 제품군입니다. 여기에는 QR, Data Matrix 또는 PDF417이 없습니다. 이들은 자체 오류 수정 수학을 사용하여 그리드에 바이트를 인코딩하며, 요구 사항에서 이를 명시하는 경우 이 도구는 잘못된 도구이므로 이를 기반으로 구축한 후에 알게 되기보다는 미리 아는 것이 좋습니다. 1차원 코드의 경우 실용적인 질문은 더 좁습니다: 인코딩은 서로 교환할 수 없기 때문에 어떤 기호가 여러분이 실제로 가지고 있는 데이터를 허용하는가 하는 것입니다
데이터 제약은 현실적이며 생성 시점에 문제가 됩니다. Code 2 of 5 변형과 MSI는 숫자만 받습니다. Code 39는 대문자, 숫자 및 소수의 구두점을 전달합니다; 소문자나 전체 ASCII 범위가 필요한 경우 Code 39 Extended 또는 Code 128 하위 집합을 사용해야 합니다. Code 128C는 밀도를 위해 각 기호에 두 개의 숫자를 압축하므로 짝수 길이의 숫자 문자열만 필요로 합니다. EAN-13은 12자리를 예상하고 13번째를 체크 숫자로 계산합니다; EAN-8은 7자리를 예상하고 8번째를 계산합니다; UPC-A는 12자리를 받습니다. 기호가 표현할 수 없는 데이터를 기호에 전달하면 도움이 되는 예외가 발생하지 않고 가비지를 인코딩하는 바코드를 얻게 되며, 이는 누군가 계산대에서 스캔할 때까지는 멀쩡해 보이기 때문에 더 나쁩니다
두 가지 그리기 경로, 두 가지 수준의 제어
프로덕션 환경에서 사용해야 할 메서드는 페이지 객체의 DrawBarcode입니다. 이는 기호, 위치, 높이, 그리고 다른 모든 것보다 중요한 매개변수 하나, 즉 모듈 너비인 MUnit을 취합니다. 모듈은 가장 좁은 막대의 너비로, 코드의 다른 모든 측정값이 이에 대한 배수가 되는 원자 단위이며 여기서는 포인트 단위로 표현됩니다. 인쇄된 결과물이 스캔되는지 여부에 대한 모든 것은 이 단일 정수로 귀결됩니다
var
Pdf: THotPDF;
begin
Pdf := THotPDF.Create(nil);
try
Pdf.FileName := 'label.pdf';
Pdf.BeginDoc;
// BCType, X, Y, Height, MUnit (module width in points), angle,
// data, UseCheckSum, bar color, background color.
Pdf.CurrentPage.DrawBarcode(
bcCodeEAN13, // symbology
72, 680, // X, Y in points from the bottom-left
60, // bar height
1, // MUnit: 1pt narrowest bar
0, // no rotation
'123456789012', // 12 digits; the 13th is the check
True, // append the modulo-10 check digit
clBlack, clWhite); // bars black, background white
Pdf.EndDoc;
finally
Pdf.Free;
end;
end;
두 개의 인수는 자세히 살펴볼 가치가 있습니다. UseCheckSum은 기호가 예상하는 modulo-10 체크 숫자를 추가하며, 소매용 코드의 경우 거의 항상 True를 원할 것입니다; 데이터에 이미 사전 계산된 체크가 있는 경우에만 끄세요. 그렇지 않으면 체크 숫자가 두 번 추가됩니다. 막대 및 배경색은 마지막 두 매개변수이며, 여기서 창의성을 발휘하려는 유혹은 아래에서 논의할 함정입니다. 또한 좌표 원점에도 유의하세요: HotPDF의 다른 모든 그리기 호출과 마찬가지로 X 및 Y는 페이지의 왼쪽 하단 모서리에서 포인트 단위로 측정되며 Y는 위로 커집니다. 이는 Hello World 예제에서 설명하는 것과 동일한 규칙입니다
두 번째 경로는 DirectDrawBarcode로, 데이터와 경계 상자인 X, Y, Width, Height를 취하고 막대 패턴을 해당 너비에 맞게 크기를 조정합니다. 크기를 지정하면 메서드가 그 안에서 막대를 맞추기 때문에 그리드에 코드를 배치하는 데 편리합니다. 그 편리함은 곧 위험 요소이기도 합니다. 너비를 지정하면 더 이상 모듈 크기를 설정하지 않게 됩니다; 메서드는 데이터가 필요로 하는 막대 수에 따라 여러분이 허용한 공간을 나누고, 가장 좁은 막대는 그 나눗셈의 결과가 무엇이든 그것이 됩니다. 너무 좁은 상자 안에 조밀한 Code 128 문자열을 요구하면 스캐너가 분해할 수 없는 수준 이하로 모듈이 은밀하게 줄어듭니다. 안정적으로 스캔되어야 하는 모든 것에 대해 DrawBarcode를 선호하고 MUnit을 신중하게 설정하세요. DirectDrawBarcode는 미리 보기용으로, 또는 결과 막대가 여전히 읽을 수 있음을 측정한 레이아웃용으로 남겨 두세요
모듈 너비는 해상도 결정입니다
레이블이 작동하는지 여부를 결정하는 산술 연산은 다음과 같습니다. 레이저 스캐너와 카메라 모두 구별할 수 있는 가장 작은 특징이 있으며, 좁은 막대는 인쇄 후 그 크기보다 충분히 커야 합니다. 범용 선형 코드에 대해 널리 인용되는 하한선은 약 0.33mm인 13 mil의 좁은 막대이며, 많은 소매 및 산업 가이드에서는 이를 목표가 아닌 최소값으로 취급합니다. 이를 PDF 단위로 변환해 보세요: 1포인트는 1/72인치(약 0.353mm)이므로 1포인트의 모듈 너비는 바로 그 하한선에 위치합니다. 그렇기 때문에 실제 스캐너용 코드에서 신뢰할 수 있는 가장 작은 값은 MUnit := 1이며, 이를 2로 두 배 늘리는 것은 여유 공간이 있는 레이블에서 거의 비용이 들지 않는 여백을 확보하는 이유입니다
이제 이를 출력 해상도와 연결하세요. 모듈 또한 프린터에서 견뎌내야 하기 때문입니다. 300 DPI 레이저 프린터에서 하나의 장치 도트는 1/300인치이므로 1포인트 모듈은 약 4도트 너비입니다. 4도트는 깔끔한 가장자리를 렌더링하기에 겨우 충분합니다; 토너 번짐과 약간의 정렬 오류로 인해 너비가 줄어들고, PDF에서 1포인트로 측정한 막대는 사양이 허용하는 것보다 더 두껍거나 얇게 인쇄됩니다. 모듈을 2포인트로 늘리면 8도트를 사용할 수 있게 되어 그러한 노이즈를 흡수합니다. 내재화할 가치가 있는 규칙은 다음과 같습니다: 포인트 단위로 설정한 모듈 너비는 여러분이 원하는 해상도가 아니라 실제 인쇄 해상도에서 편안한 정수 개의 장치 도트에 매핑되어야 합니다. 화면에서는 완벽하게 스캔되지만 창고 프린터에서는 실패하는 코드는 거의 항상 이 확인에 실패한 것입니다
여백(Quiet Zone)은 기호의 일부입니다
올바르게 인코딩된 바코드가 스캔되지 않는 가장 흔한 단일 이유는 막대 양쪽의 공백인 여백(quiet zone) 때문입니다. 스캐너는 코드의 시작과 끝을 찾기 위해 이 여백을 사용합니다; 여백이 없으면 리더기는 첫 번째 막대와 페이지에서 그 옆에 있는 것을 구별할 수 없습니다. 표준은 구체적입니다. 대부분의 선형 기호는 양쪽에 모듈 너비의 최소 10배에 해당하는 여백을 필요로 하며, UPC 및 EAN 소매 코드는 왼쪽에 9개 모듈, 오른쪽에 7개 모듈을 요구합니다. 1포인트 모듈의 경우 막대 양쪽에 약 1/7인치인 약 10포인트의 보장된 공백이 있게 됩니다
HotPDF는 막대만 그리고 다른 것은 그리지 않습니다. 이 컴포넌트는 여백을 대신 확보해주지 않으므로 그 책임은 여러분에게 있으며 잊어버리기 쉽습니다. 실패 모드는 미묘합니다: 바코드를 표 셀 테두리에 바짝 붙여 배치하거나 페이지 레이아웃에서 바코드 옆에 로고가 바짝 붙도록 놔두면, 빈 페이지에서 모든 테스트를 통과했던 코드가 실제 문서 내부로 배송되는 순간 스캔이 중단됩니다. 여백을 명시적으로 예산에 넣으세요. DrawBarcode를 호출하기 전에 양쪽에 최소 10개 모듈 너비의 여백을 남기고 해당 영역을 침범하는 모든 그래픽, 선 또는 텍스트를 단순한 꾸밈 선택이 아닌 결함으로 간주하세요
색상, 대비 및 사람이 읽을 수 있는 선
브랜드 팔레트와 일치시킬 수 있도록 막대 및 배경색 설정이 존재하지만, 이는 작동하는 코드를 깨뜨리는 가장 빠른 방법입니다. 스캐너는 대조를 읽으며 고전적으로 빨간색 빛을 사용하여 밝은 바탕에 어두운 막대를 기대합니다. 흰색 바탕에 검은색은 테스트 없이 선택할 수 있는 유일한 조합입니다. 흰색 바탕에 진한 파란색이나 진한 녹색은 통과할 수 있습니다; 광도(luminance) 대비가 낮은 색상, 특히 빨간색 빛을 내는 스캐너가 배경으로 인식하는 빨간색 막대는 스캔되지 않습니다. 디자이너가 유색 바코드를 요구한다면 솔직한 답변은 막대는 검은색으로 유지하고 색상은 레이블의 다른 곳에 적용하라는 것입니다
DrawBarcode 경로는 스캔이 실패할 때 점원이 직접 키보드로 입력하는 숫자인 막대 아래의 사람이 읽을 수 있는 텍스트를 렌더링할 수도 있습니다. 해당 텍스트는 대체(fallback) 수단이지 장식이 아니므로 자체 캡션을 배치할 때 여백에 닿지 않게 하세요; 여백에 욱여넣은 기호 캡션은 스캐너가 의존하는 바로 그 공백을 무산시킵니다. 여백 레이블을 위한 TextOut을 포함하여 여기에 나온 예제의 필드들은 보고서 출력 가이드에서 다루는 것과 동일한 그리기 호출이며, 이 가이드는 바코드가 더 큰 구성된 페이지의 한 요소일 때 참고할 곳입니다
짧은 검증 습관
벡터 막대는 언급할 가치가 있는 장점입니다. DrawBarcode는 래스터화된 이미지가 아니라 PDF 그리기 연산자로 코드를 작성하기 때문에 막대는 어떤 줌에서도 선명하게 유지되며 파일 자체 해상도를 가지지 않습니다; 유일하게 중요한 해상도는 프린터의 해상도뿐입니다. 그렇다고 해서 테스트가 면제되는 것은 아니며, 단지 종이 위에서 테스트해야 함을 의미할 뿐입니다. 샘플을 생성하여 코드가 실제로 만날 수 있는 가장 낮은 해상도의 장치에서 인쇄하고, 책상 위의 고급 이미저가 아닌 사용자가 쥐고 있는 것과 동일한 등급의 리더기로 스캔해 보세요. 인쇄물에서 자로 여백을 확인하고, 모듈 너비가 포인트에서 도트로 잘 변환되었는지 확인하고, 디코딩된 값이 체크 숫자를 포함하여 인코딩한 것과 일치하는지 확인하세요. 실제 스캐너로 5분만 확인하면 위에서 설명한 모든 오류를 잡아낼 수 있으며, 잘못된 레이블이 붙은 재고 팔레트가 배송되기 전에 잡아냅니다
여기에 표시된 DrawBarcode 및 DirectDrawBarcode 메서드는 델파이 및 C++Builder용 HotPDF 컴포넌트의 일부입니다