CUPS 라벨 인쇄 (CUPS 옵션, Bixolon 회전, QPDF 변환)
프린터 옵션 하나만 바꾸면 끝날 줄 알았습니다. 라벨 방향 하나 바꾸는 게 그렇게 간단한 일 아니었냐고요? 저도 처음엔 그렇게 생각했습니다. 그런데 막상 CUPS(Common UNIX Printing System, 리눅스 계열 서버에서 프린터를 관리하는 인쇄 시스템)에서 Bixolon 라벨 프린터 옵션을 하나하나 뒤지다 보니, 이게 생각보다 훨씬 복잡한 문제라는 걸 깨달았습니다. 결국 프린터 옵션이 아니라 PDF 파일 자체를 회전시키는 방향으로 문제를 해결했고, 그 과정에서 꽤 많은 걸 배웠습니다.
CUPS 옵션으로 라벨 방향 바꾸기, 왜 안 되나
회사에서 Bixolon 라벨 프린터로 라벨을 찍어내고 있었는데, 자동 라벨 부착기 교체로 인해 라벨 규격이 바뀌었습니다. 기존에 쓰던 가로가 긴 라벨에서 세로가 긴 라벨로 바꿔야 하는 상황이었습니다. 웹서버에서 CUPS를 통해 인쇄 명령을 보내고 있었으니, 가장 먼저 떠오른 방법은 당연히 CUPS 인쇄 옵션을 수정하는 것이었습니다.
CUPS에서는 lp 명령어에 -o 옵션을 붙여서 인쇄 방향을 지정할 수 있습니다. 예를 들어 lp -o landscape filename 처럼 쓰거나, 좀 더 세밀하게 -o orientation-requested=4 같은 방식으로 90도 회전을 지정할 수 있습니다. orientation-requested란 인쇄 출력물의 페이지 방향을 숫자 값으로 지정하는 CUPS 표준 옵션으로, 3은 세로(portrait), 4는 가로(landscape), 5는 270도 회전, 6은 180도 회전을 의미합니다.
그런데 제가 직접 써봤는데, 이 옵션이 Bixolon에서는 제대로 먹히질 않았습니다. 출력물이 회전되지 않고 그냥 원래 방향 그대로 나오거나, 아예 이상한 형태로 잘려 나오기도 했습니다. 그래서 프린터에서 직접 지원하는 옵션이 뭔지 확인하기 위해 lpoptions 명령어를 사용했습니다.
lpoptions란 CUPS에서 특정 프린터에 등록된 옵션 목록을 조회하거나 기본값을 설정하는 명령어입니다. lpoptions -p Bixolon -l을 실행하면 해당 프린터 드라이버가 지원하는 모든 옵션이 나열됩니다. 실행해 보니 Rotation 항목에 0NoRotation, 1Rotate90, 2Rotate180, 3Rotate270이 있었습니다. 보자마자 “아, 이거면 되겠다” 싶었습니다. 하지만 실제로 적용해 보니 결과는 마찬가지였습니다. 회전이 적용되지 않거나, 프린터가 그 명령 자체를 무시하는 것처럼 보였습니다.
솔직히 이건 예상 밖이었습니다. 드라이버에 옵션이 있으면 당연히 동작해야 한다고 생각했는데, 현실은 달랐습니다. PPD 파일(PostScript Printer Description, 프린터의 기능과 옵션을 기술한 설정 파일)에 옵션이 등록되어 있더라도 해당 모델의 펌웨어나 드라이버가 실제로 그 명령을 처리하지 않으면 아무 소용이 없습니다. 특히 라벨 전용 프린터는 일반 레이저 프린터와 달리 회전 처리를 하드웨어 수준에서 지원하지 않는 경우가 많다는 점을 이번에 몸소 확인했습니다.
더 곤란한 점은 제가 원격으로 프린터를 테스트해야 했다는 겁니다. 매번 명령을 바꿔서 인쇄해보고, 현장 담당자에게 결과를 확인받아야 하는 구조였으니 한 번 테스트에 꽤 많은 시간이 소요됐습니다. 이런 상황에서 옵션 하나하나를 무한정 시도하는 방식은 현실적으로 한계가 있었습니다.
Bixolon 회전 문제, QPDF로 발상 전환
프린터 옵션 쪽에서 막히자 방향을 바꿔야 했습니다. 프린터에게 회전시켜 달라고 부탁하는 게 아니라, 프린터에 넘기기 전에 PDF 파일 자체를 먼저 돌려놓는 방식입니다. 이때 사용한 것이 QPDF입니다.
QPDF란 PDF 파일의 구조를 변환하는 C++ 기반의 커맨드라인 도구 및 라이브러리로, PDF 내용의 의미는 건드리지 않으면서 파일의 구조적 속성을 바꿀 수 있습니다(출처: QPDF 공식 문서). 페이지 회전, 분리, 병합, 암호화 같은 작업이 가능하고, 무엇보다 외부 의존성이 거의 없어 서버 환경에서 가볍게 쓸 수 있다는 점이 마음에 들었습니다.
저는 mPDF(PHP에서 PDF를 생성하는 라이브러리)로 라벨 PDF를 만든 다음, 그 결과물을 QPDF로 넘겨서 90도 회전시키는 방식을 택했습니다. 처음에 이 방법을 생각했을 때는 “과연 될까?” 반신반의했습니다만, 실제로 해보니 깔끔하게 작동했습니다. 회전된 PDF가 CUPS를 통해 Bixolon으로 전달되고, 프린터는 그냥 “방향이 이미 맞춰진 PDF”를 받아 그대로 출력하기만 하면 되는 구조입니다.
이 방식이 유용한 이유를 정리하면 다음과 같습니다.
- 프린터 드라이버나 펌웨어의 회전 지원 여부와 무관하게 동작합니다. PDF 자체가 이미 원하는 방향으로 저장되어 있기 때문입니다.
- 원격 환경에서 테스트 횟수를 크게 줄일 수 있습니다. 로컬에서 PDF 파일 회전 결과를 미리 확인하고 전송할 수 있기 때문입니다.
- CUPS 옵션 변경 없이 인쇄 파이프라인의 앞단에서 처리하므로, 기존 인쇄 설정에 영향을 주지 않습니다.
- mPDF처럼 PDF를 생성하는 단계와 분리되어 있어, 생성 로직을 건드리지 않고 후처리만 추가하는 형태로 작업할 수 있습니다.
일반적으로 PDF 회전은 뷰어나 편집기에서 저장할 때 처리하는 것이라고 알려져 있지만, 서버 자동화 환경에서는 QPDF처럼 커맨드라인에서 처리할 수 있는 도구가 훨씬 현실적입니다. 제 경험상 이건 좀 다릅니다. GUI 없이 돌아가는 웹서버에서 PDF 편집기를 띄울 수는 없으니까요.
QPDF 변환, 실제 인쇄 파이프라인에서 어떻게 동작하나
실제 흐름을 보면 이렇습니다. 웹 애플리케이션이 mPDF를 호출해 라벨 PDF를 생성하고, 그 임시 파일을 QPDF로 넘겨 회전 처리한 뒤, lp 명령어로 CUPS에 인쇄 요청을 보냅니다. 이 파이프라인(pipeline, 여러 처리 단계를 직렬로 연결한 자동화 흐름)이 안정적으로 돌아가려면 각 단계의 출력이 다음 단계의 입력으로 정확히 전달되어야 합니다.
CUPS에서 lp 명령어는 표준 입력(standard input)도 지원합니다. 즉 program | lp -d printer 형식으로 프로그램 출력을 바로 인쇄 큐에 넣을 수 있습니다. 인쇄 큐(print queue)란 인쇄 요청들이 순서대로 대기하는 목록을 뜻하며, CUPS가 프린터 상태에 맞게 하나씩 꺼내 처리합니다. 저는 이 구조를 활용해 QPDF의 출력을 바로 파이프로 lp에 연결하는 방식도 테스트해 봤습니다.
인쇄 작업을 확인할 때는 lpstat 명령어를 씁니다. lpstat란 현재 인쇄 큐 상태와 등록된 프린터 목록을 보여주는 CUPS 명령어입니다. lpstat -p -d를 실행하면 사용 가능한 프린터 목록과 기본 프린터가 어떤 것인지 한 번에 확인할 수 있습니다. 원격 환경에서 작업할 때 프린터가 연결 상태인지 먼저 확인하는 데 꽤 요긴하게 썼습니다.
한 가지 더 짚자면, CUPS의 공식 문서(출처: CUPS 공식 문서)를 보면 -o landscape 같은 표준 옵션들이 모든 프린터에서 보장되는 것처럼 설명되어 있습니다. 하지만 이건 CUPS 레벨에서의 이야기고, 실제 프린터 드라이버가 그 옵션을 구현하고 있는지는 별개의 문제입니다. 라벨 프린터처럼 특수 목적 장비는 표준 옵션 지원이 불완전한 경우가 충분히 있습니다. 제가 경험한 Bixolon이 딱 그런 케이스였습니다.
결국 이번 작업에서 핵심은 “어디서 회전을 처리할 것인가”를 다시 생각하는 것이었습니다. 프린터에 맡기지 않고 PDF 생성 직후 단계에서 처리하는 방식이 이 상황에서는 훨씬 현실적이고 안정적이었습니다.
자주 묻는 질문
Q. CUPS lp 명령어의 -o landscape 옵션이 Bixolon 라벨 프린터에서 안 먹힐 때 어떻게 해야 하나요?
A. lpoptions -p 프린터명 -l 명령어로 해당 프린터가 실제로 지원하는 옵션 목록을 먼저 확인하는 것이 우선입니다. Rotation 옵션이 목록에 있더라도 드라이버나 펌웨어 수준에서 실제 동작하지 않는 경우가 있습니다. 이럴 때는 QPDF처럼 PDF 파일 자체를 회전시킨 뒤 인쇄하는 방법이 더 확실한 대안입니다.
Q. QPDF로 PDF를 회전시키면 텍스트나 이미지 품질이 손상되지 않나요?
A. QPDF는 PDF의 내용(content stream)을 직접 수정하지 않고 구조적인 변환만 수행합니다. 페이지 회전은 페이지 객체에 회전 속성값을 추가하는 방식으로 처리되기 때문에, 텍스트나 이미지 데이터 자체는 그대로 보존됩니다. 실제로 제가 mPDF로 생성한 라벨을 QPDF로 회전시켰을 때도 품질 저하는 전혀 없었습니다.
Q. mPDF에서 처음부터 세로 방향으로 라벨을 만들면 되는 거 아닌가요?
A. 가능하다면 그게 가장 간단한 방법입니다. 다만 기존에 이미 가로 방향으로 생성하도록 만들어진 로직이 있고, 그 로직을 건드리면 다른 출력물에 영향이 갈 수 있는 상황이라면 후처리 방식이 더 안전합니다. 생성 로직은 유지한 채 QPDF로 회전만 추가하면 변경 범위를 최소화할 수 있습니다.
Q. 원격 서버에서 인쇄 테스트할 때 인쇄 작업이 정상적으로 접수됐는지 어떻게 확인하나요?
A. lpstat 명령어를 사용하면 됩니다. lpstat 또는 lpq를 실행하면 현재 인쇄 큐에 어떤 작업이 대기 중인지, 인쇄 중인 작업이 무엇인지 확인할 수 있습니다. 작업이 큐에 쌓였는데 출력이 안 된다면 프린터 연결 상태나 드라이버 문제일 가능성이 높습니다.
Q. QPDF는 서버에 어떻게 설치하나요?
A. Ubuntu나 Debian 기반 서버라면 apt install qpdf 명령어로 간단히 설치됩니다. CentOS나 RHEL 계열은 yum 또는 dnf로 설치 가능하며, 패키지 저장소에 없는 경우 QPDF 공식 GitHub 저장소에서 소스를 받아 빌드할 수 있습니다. 외부 의존성이 매우 적어 설치 자체는 어렵지 않습니다.
프린터 옵션이 문서에 존재한다고 해서 반드시 동작한다는 보장은 없습니다. 이번 작업을 통해 그 사실을 다시 한번 확인했습니다. 특정 옵션에 계속 매달리기보다 파이프라인의 어느 단계에서 문제를 해결할 수 있는지를 먼저 따져보는 것이 더 빠를 때가 있습니다. Bixolon과 CUPS 조합으로 라벨 방향 문제를 겪고 있다면, QPDF로 PDF 자체를 회전시켜 넘기는 방식을 한번 시도해 보시기 바랍니다. 생각보다 훨씬 간단하게 풀립니다.
—
참고: https://www.cups.org/doc/options.html, https://qpdf.readthedocs.io/en/stable/overview.html