1 0 0 rg, 순수한 빨강으로 채운 제목은 그레이 변환을 거치면 0.299 g로 돌아옵니다. 순수한 파랑은 0.114 g에 착지하는데, 검정과 충분히 가까워서 남색 로고와 본문 텍스트를 구분하기 어려워집니다. 이 숫자들은 반올림 사고가 아닙니다. BT.601 휘도 가중치로, 뷰어가 회색 장치에 RGB 페이지를 보여 줄 때 적용하는 것과 같은 값이고, 컬러 브로슈어가 그레이가 되어야 할 때 얼마나 많은 대비가 살아남는지를 결정합니다
RecolorDocument가 색마다 계산하는 것
PDF Library for Delphi는 이 변환을 TPDFlib의 RecolorDocument(TargetSpace)로 노출합니다. 그레이는 1, RGB는 2, CMYK는 3입니다. 변환된 것들의 개수를 반환하며, 지오메트리와 텍스트 위치, 이미지 배치는 원래 자리에 있습니다. 바뀌는 것은 색 값과 그 주변의 색 공간 이름뿐입니다
모든 색은 목표에 가는 길에 RGB를 거칩니다. 그레이는 휘도 합 0.299 R + 0.587 G + 0.114 B입니다. CMYK는 ISO 32000-1 §10.3의 단순 디바이스 규칙으로 RGB에 도달하는데, 각 채널은 자기 잉크와 검정의 합을 1에서 뺀 값을 0으로 잘라낸 것입니다. RGB는 가장 큰 성분을 검정으로 빼내어 CMYK에 도달합니다. K = 1 - max(R, G, B)이고 남은 잉크들은 남은 만큼 스케일됩니다. 프린터에 무엇을 보내기 전에 알아 두면 좋은 결과 몇 가지:
0.4 g그레이를 CMYK로 변환하면0 0 0 0.6 k, 검정 잉크 하나가 됩니다. 텍스트와 선에는 이것이 인쇄소가 원하는 것입니다- RGB
1 0.5 0(주황)은0 0.5 1 0 k가 되고, 검정은 전혀 없습니다 0.6 0.4 0.4 1 k같은 리치 블랙은 그레이로 가는 길에0 g가 되어, 잉크 여럿이 그저 사라집니다- 순수한 시안,
1 0 0 0 k는0.701 g로 변합니다. 포화 잉크에서 기대하는 것보다 밝습니다
변환된 연산자는 최대 소수 셋째 자리, 그리고 항상 마침표를 소수 구분자로 써서 기록됩니다. 작업을 돌리는 머신의 로캘이 무엇이든요. ISO 32000-1 §7.3.3은 콘텐츠 스트림에서 다른 것을 허용하지 않고, 시스템 로캘로 숫자를 포맷하는 변환기는 독일 워크스테이션에서 0,5 g를 기록하는데, 리더는 그것을 숫자 0 뒤에 미지의 연산자가 붙은 것으로 파싱합니다
var
Lib: TPDFlib;
Converted: Integer;
begin
Lib := TPDFlib.Create;
try
if Lib.LoadFromFile('brochure.pdf', '') <> 1 then
raise Exception.Create('Could not open brochure.pdf');
Converted := Lib.RecolorDocument(1); // 1 그레이, 2 RGB, 3 CMYK
WriteLn(Format('%d colors, images and gradients converted', [Converted]));
Lib.SaveToFile('brochure-gray.pdf');
finally
Lib.Free;
end;
end;
색이 이미 목표 공간에 있는 페이지는 원래 콘텐츠 바이트를 유지합니다. RecolorDocument는 실제로 한 공간에서 다른 공간으로 건너는 변환만 세므로, 이미 그레이인 문서는 0을 보고하고 안의 어떤 것도 다시 쓰이지 않습니다. 큰 파일에서는 이것이 중요합니다. 입력과 출력의 diff가 바뀐 페이지를 정확히 보여 줍니다
RecolorPage는 표지 사진을 왜 컬러로 남겨 둘까?
RecolorPage는 선택된 페이지의 색 연산자를 변환하고 거기서 멈춥니다. 이미지와 그라데이션은 문서 수준 객체이고 여러 페이지가 공유하는 경우가 많아, RecolorDocument만 그것들을 변환합니다. 그래서 표지만 변환하는 뻔한 방법, 즉 1페이지를 선택하고 RecolorPage(3)를 호출하는 방법은 RGB 사진 위에 CMYK 제목과 선을 얹어 줍니다
이 분리는 의도적입니다. 표지에 그려진 이미지 XObject는 12페이지에도 그려질 수 있고, 한 페이지를 위해 변환하면 양쪽 모두가 변합니다. 공유 리소스 안으로 조용히 손을 뻗는 페이지 범위 호출은 호출자가 선택하지 않은 페이지를 바꿔 버립니다. 둘 중 더 나쁜 놀라움은 이쪽이므로, 페이지 단위 호출은 페이지에 속한 것만 만집니다
// 표지의 연산자만. 이미지와 그라데이션은 여기서 변환되지 않는다
Lib.SelectPage(1);
Changed := Lib.RecolorPage(3);
if Changed = 0 then
WriteLn('Cover already uses CMYK operators (or the target was out of range)');
Lib.SaveToFile('cover-cmyk-operators.pdf');
// 문서 전체가 하나의 공간이어야 한다면 전체를 변환한다
Lib.RecolorDocument(3);
Lib.SaveToFile('all-cmyk.pdf');
위 스니펫에서 반환값을 주목하세요. 두 호출 모두 1에서 3 밖의 목표에 대해 0을 반환하고, 바꿔야 할 것이 없던 페이지도 0을 답하므로, 목표의 오타는 이미 올바른 문서와 똑같이 보입니다. 호출 전에 인수를 직접 검증하세요. RecolorDocument는 실행 전에 선택돼 있던 페이지를 복원하므로, 페이지별 작업 중간에 호출해도 이후 재선택이 필요 없습니다
범위 관련 세부 사항이 하나 더 있습니다. 연산자 패스는 각 페이지 자신의 콘텐츠 스트림, 즉 페이지 자신에 나열된 그리기 지시를 읽고, g, rg, k, 그들의 획(stroking) 형태, 그리고 현재 공간이 디바이스 공간일 때의 sc/scn을 변환합니다. 변환되는 sc 앞에 /DeviceRGB cs가 있으면 공간 이름도 목표로 다시 쓰입니다. 손으로 쓴 변환기가 이 이름 바꾸기를 건너뛰면 리더는 이제 회색 값 하나가 있는 자리에서 RGB 성분 셋을 찾습니다
이미지와 팔레트: 무엇이 바뀌고 무엇이 바이트를 지키나
이미지는 연산자만큼 중요합니다. 연산자만 처리해 그레이로 바뀐 브로슈어는 그레이 페이지 위에 컬러 사진을 여전히 보여 주는데, 이는 원본이나 완전 변환 어느 쪽보다 읽기 나쁩니다. RecolorDocument는 성분당 8비트, 디바이스 색 공간, 압축 없음 또는 decode 파라미터 없는 단순 Flate인 이미지를 변환합니다
인덱스 이미지는 다른 길을 갑니다. 샘플이 색 테이블로의 인덱스이므로, 테이블을 변환하고 모든 샘플은 이미 갖고 있던 인덱스를 유지합니다. 256색 팔레트 이미지로 저장된 스크린샷이나 차트는 샘플이 어떻게 패킹되고 압축됐든 이 방식으로 변환됩니다. 샘플은 결코 디코딩되지 않기 때문입니다. 팔레트의 밑바탕은 디바이스 공간이어야 하고, ICC 프로필 위의 팔레트는 자기 테이블을 유지합니다
JPEG나 fax 인코딩 이미지는 자기 바이트를 지킵니다. 색을 바꾸려면 디코딩하고 변환하고 다시 압축해야 하는데, 그러면 JPEG 아티팩트가 한 세대 더 끼어들고 아무도 요청하지 않은 방식으로 파일 크기가 바뀝니다. 작업이 정말 모든 사진의 그레이화를 요구한다면 재인코딩은 자체 품질 설정을 가진 별개의 결정이고, 컬러 변환이 대신 결정해 주는 것보다 호출자가 명시적으로 내리는 것이 낫습니다
소프트 마스크와 스텐실 마스크는 다른 이유로 그대로 남습니다. 소프트 마스크는 보통 DeviceGray 이미지지만 그 값들은 커버리지를 뜻합니다. 이를 3성분 RGB로 변환하면 뷰어는 그것을 투명도로 다루는 것을 멈추고, 본디 모양을 내야 할 콘텐츠 위에 회색 아트워크로 그려져 버립니다. RecolorDocument는 이미지를 변환하기 전에 /SMask나 /Mask로 참조되는 모든 객체를 수집하고, /ImageMask true인 이미지는 애초에 변환할 색이 없습니다
연산자 수준에서 ICCBased, Separation, Indexed, Pattern 공간으로 설정된 색도 쓰인 그대로 남습니다. 프로필을 읽지 않고 스팟 컬러나 프로필이 붙은 값을 디바이스 그레이로 바꾸면 페이지의 모습이 달라지고, 외관을 지키는 것이 본업인 패스가 프로필의 의미를 추측하기 시작해서는 안 됩니다
그라데이션: 색 공간과 스톱은 함께 움직인다
셰이딩은 자기 색 공간을 한 번 선언하고 모든 스톱을 함수에 넘깁니다. 함수가 여전히 숫자 셋을 반환하는 동안 /ColorSpace를 DeviceRGB에서 DeviceGray로 이름을 바꾸면, 리더는 첫 번째 숫자, 그러니까 빨강 채널을 회색 레벨로 삼습니다. 파랑에서 흰색으로 가는 그라데이션은 검정에서 시작하는 띠로 렌더링됩니다. RecolorDocument는 먼저 함수 트리 전체를 읽기 전용으로 훑고, 모든 노드가 변환 가능할 때만 아무것도 변환합니다. 그 뒤에야 스톱을 다시 쓰고 공간 이름을 바꿉니다
다시 쓰이는 함수는 두 끝 색 /C0과 /C1이 단순 배열인 지수형과, 그것으로 만들어진 스티칭 함수입니다. /Background 색도 나머지와 함께 변환됩니다. 샘플링된 테이블이나 PostScript 프로그램으로 정의된 셰이딩은 자기 정의를 유지하고, 색을 함수 대신 스트림 안에 저장하는 메시 타입 4~7도 마찬가지입니다. 어느 쪽이든 다시 쓰는 것은 재생성이지 색 변환이 아닙니다
그라데이션을 찾는 것 자체가 함정입니다. 디자인 도구는 셰이딩에 자기 객체를 주는 일이 드물고, 보통 그것을 칠하는 패턴 사전 안이나 페이지의 /Shading 리소스 안에 인라인으로 놓입니다. 저희가 그라데이션 패스를 만들 당시 최상위 객체 스캔은 거의 아무것도 찾지 못했습니다. 검색은 이제 객체 그래프를 따라가고, 12단계 깊이로 한정되며 각 객체 번호를 한 번만 방문합니다. 모든 페이지가 공유하는 리소스는 한 번 변환되고, 객체가 자기 자신을 가리키는 파일도 루프에 빠지지 않습니다
인쇄 제출 전 재채색이 들어맞는 곳
RecolorDocument를 정규화로 다루세요. 디바이스 공간 사이의 값을 변환할 뿐이고, ICC 프로필을 적용하거나 렌더링 인텐트를 존중하거나 인쇄 조건을 시뮬레이션하지 않습니다. 계약 교정쇄를 맞춰야 하는 작업에는 프로필 기반 워크플로가 맞는 도구이고, 재채색 패스는 기껏해야 그 워크플로가 돌기 전에 모든 것을 하나의 공간으로 옮기는 단계입니다
이 호출이 값을 하는 곳은 일상적인 생산 사례입니다. 그레이여야 하는 제출물이 RGB 로고와 함께 도착하거나, 색으로 인쇄되면 안 되는 내부 보고서나, 프리플라이트 단계가 모든 파일이 하나의 공간을 쓸 때까지 거부할 배치가 그것입니다. 외부로 나가는 것은 무엇이든 RecolorDocument를 거쳐야 하고 RecolorPage만으로 끝내면 안 됩니다. 절반만 변환된 파일은 빠른 육안 검사는 통과했다가 프린터에서 실패하기 때문입니다. 판정은 같은 작업 안에서 실행하세요. PDF/A와 PDF/UA preflight와 컴플라이언스·서명 워크벤치 노트가 방법을 보여 줍니다
// IsValidRecolorTarget은 여러분이 직접 추가하는 헬퍼. 라이브러리에는 이런 호출이 없다
function IsValidRecolorTarget(Space: Integer): Boolean;
begin
Result := (Space >= 1) and (Space <= 3);
end;
procedure NormalizeFile(const Src, Dst: string; Space: Integer);
var
Lib: TPDFlib;
begin
if not IsValidRecolorTarget(Space) then
raise EArgumentException.CreateFmt('Bad recolor target %d', [Space]);
Lib := TPDFlib.Create;
try
if Lib.LoadFromFile(Src, '') <> 1 then
raise Exception.CreateFmt('Could not open %s', [Src]);
if Lib.RecolorDocument(Space) = 0 then
WriteLn(Src, ': already in the target space, copied unchanged');
Lib.SaveToFile(Dst);
finally
Lib.Free;
end;
end;
출력에서 돌릴 수 있는 빠른 검사가 하나 있습니다. 그레이 변환 뒤에 변환된 페이지의 콘텐츠를 아무 PDF 인스펙터로나 여는 것입니다. 페이지 자신의 콘텐츠에는 더 이상 rg, RG, k, K 연산자가 없어야 합니다. 패스를 살아남은 색은 위의 사례들에서 옵니다. JPEG, 프로필이 붙거나 스팟인 색, sampled나 mesh 그라데이션, 그리고 폼 XObject 안에서 그려진 아트워크로, 그 지시들은 페이지 콘텐츠가 아니라 자기 스트림에 삽니다
변환만이 아니라 벡터 아트워크까지 직접 만든다면, 벡터 그래픽, 셰이더, 그라데이션 산책문이 셰이딩과 패턴이 애초에 어떻게 만들어지는지 보여 주며, 위의 그라데이션 규칙이 예측하기 쉬워집니다
색 패스는 인프로세스에서 돕니다. PDF Library for Delphi는 Delphi, C++Builder, Lazarus를 위한 네이티브 Pascal이므로, 들어오는 파일 배치를 정규화하는 데 서버에 외부 변환기나 커맨드라인 도구가 필요 없습니다. PDF Library for Delphi 제품 페이지에 문서 처리 API의 나머지가 나열돼 있습니다