PDF Library for Delphi는 Delphi에서 두 종류의 PDF 소프트 마스크를 모두 작성합니다. SetImageSoftMaskEx는 대상 이미지에 마스크 이미지를 붙이며, 미리 곱해진 아트워크가 필요로 하는 /Matte 항목을 기록할 수 있습니다. NewSoftMaskGraphicsState는 캡처된 콘텐츠로부터 알파 또는 루미노시티 마스크를 만들고, 이후의 그리기에 적용할 그래픽 상태를 반환합니다. 그리고 소비자가 투명도를 전혀 처리할 수 없을 때는 FlattenTransparency가 시각적 결과를 렌더링해 각 페이지를 그것으로 대체합니다
소프트 마스크는 PDF가 그라디언트 페이드, 비네트, 배경에 블렌딩된 사진, 그리고 불투명도가 영역에 따라 달라지는 그 밖의 모든 효과를 표현하는 방법입니다. 상수 투명도는 그래픽 상태 안의 숫자 하나일 뿐이지만, 소프트 마스크는 위치에 대한 하나의 함수 전체이며, 이를 작성할 수 있기 전까지는 디자인의 한 범주 전체를 재현할 수 없습니다
두 가지 마스크 유형과 각각이 읽는 것
알파 마스크는 마스킹 콘텐츠의 알파 채널에서 값을 가져옵니다. 루미노시티 마스크는 마스킹 콘텐츠의 밝기에서 값을 가져오므로, 흰 영역은 완전 불투명이고 검은 영역은 완전 투명입니다. 루미노시티는 디자이너들이 즐겨 쓰는 쪽인데, 그레이스케일 그라디언트를 칠하는 것이 페이드를 표현하는 자연스러운 방법이기 때문입니다
폼 소프트 마스크는 캡처된 콘텐츠로부터 만들어지며, 여러 세부사항은 선택이 아니라 고정되어 있습니다. 캡처된 콘텐츠는 DeviceRGB 안의 고립된 투명도 그룹이 되므로, 마스크는 알려진 색공간 안에서 평가됩니다. 그러므로 배경색은 그 그룹과 일치하는 세 개의 구성 요소를 가져야 합니다. 전달 함수는 /Identity나 유효한 함수 객체를 받아들이며, 이를 통해 아트워크를 다시 칠하지 않고도 마스크 커브를 재구성할 수 있습니다
uses
PDFlibrary;
var
Lib: TPDFlib;
MaskCapture, MaskGS, PhotoID: Integer;
begin
Lib := TPDFlib.Create;
try
Lib.LoadFromFile('brochure.pdf', '');
// 4페이지에는 마스크로 쓰기 위해 칠해진 그레이스케일 그라디언트가 있음
MaskCapture := Lib.CapturePage(4);
MaskGS := Lib.NewSoftMaskGraphicsState(MaskCapture,
PDF_SOFT_MASK_LUMINOSITY, '0 0 0', '/Identity');
Lib.SelectPage(1);
Lib.SetGraphicsState(MaskGS);
PhotoID := Lib.AddImageFromFile('hero.jpg', 0);
Lib.SelectImage(PhotoID);
Lib.DrawImage(40, 700, 515, 260); // 마스크 아래에서 서서히 사라짐
// ExtGState 설정은 유지됨: 범위를 명시적으로 끝낼 것
Lib.SetGraphicsState(Lib.NewSoftMaskGraphicsState(0,
PDF_SOFT_MASK_NONE, '', ''));
Lib.SaveToFile('brochure-masked.pdf');
finally
Lib.Free;
end;
end;
그 마지막 단계는 장식이 아닙니다. 그래픽 상태 매개변수는 바뀌기 전까지 유지되며, 이후에 평범한 그래픽 상태를 적용해도 활성 상태인 소프트 마스크는 지워지지 않습니다. 명시적인 /SMask /None이 없으면, 마스크가 적용된 아트워크 이후에 그려지는 모든 것이 그 마스크를 물려받는데, 이는 시각적으로 진단하기에 가장 당혹스러운 버그 중 하나입니다
이미지 마스크와 Matte 항목
이미지 수준 마스킹에서는 마스크 이미지가 먼저 DeviceGray로 정규화되므로, 어떤 색공간으로 제공된 마스크도 예측 가능하게 동작합니다. 선택적인 /Matte 항목은 이미지의 색공간에 따라 하나에서 네 개의 구성 요소를 가지며, 이미지 데이터가 그 색상에 대해 미리 곱해져 있다는 것을 소비자에게 알려줍니다. 이는 미리 곱해진 아트워크가 마치 순수 알파인 것처럼 합성될 때 나타나는 어두운 헤일로를 막아 줍니다
여기서는 두 가지 가드레일이 중요합니다. PDF/A-1과 PDF/X-1은 투명도를 금지하므로, 이 호출은 나중에 검증에 실패하는 파일을 만드는 대신 어떤 객체도 수정하기 전에 거부합니다. 그리고 성공적인 소프트 마스크에는 PDF 1.4가 필요하며, 라이브러리는 이를 자동으로 설정합니다 — 투명도는 그 버전 이전에는 존재하지 않았으므로, 소프트 마스크를 담은 파일에 1.3 헤더를 붙이는 것은 그냥 거짓입니다
반복되는 상태는 재사용됩니다: 같은 캡처된 폼, 마스크 유형, 배경색, 전달 함수 시그니처는 호출마다 새 객체가 아니라 같은 그래픽 상태 객체를 만들어냅니다. 백 개의 이미지를 동일하게 마스킹하는 문서에서는, 이것이 곧 아흔아홉 개의 객체가 전혀 기록되지 않는다는 뜻입니다
왜 평탄화하는가, 그리고 평탄화가 실제로 하는 일
투명도는 여전히 '화면에서는 맞는데 인쇄소에서는 틀리다'는 가장 흔한 원인입니다. 오래된 RIP, 일부 규제 제출 시스템, PDF/X-1a는 모두 살아 있는 투명도가 전혀 없는 파일을 요구합니다
여기서 평탄화는 의도적으로 말 그대로의 의미입니다: 요청된 범위의 각 페이지는 선택한 DPI로 불투명한 배경 위에 렌더링되며, 페이지 콘텐츠와 리소스는 그 단일 이미지로 대체됩니다. 렌더러가 최종 합성 결과를 만들어내므로, 이는 투명도 그룹, 블렌드 모드, 소프트 마스크, 패턴, 중첩된 폼까지 모든 것을 한 번에 처리하며, 구성체별로 근사 로직을 따로 틀릴 여지가 없습니다. 최대 래스터 메모리는 페이지 하나 분량으로 제한됩니다
// 1~8페이지를 흰 배경 위 300 DPI로 평탄화한 다음 PDF 1.3으로 저장
Lib.FlattenTransparency('1-8', 300, $FFFFFF, 0);
Lib.SaveToFile('press-ready.pdf');
대가 역시 똑같이 말 그대로입니다: 출력은 이미지이므로 텍스트는 더 이상 선택하거나 검색할 수 없고, 벡터 가장자리는 선택한 DPI로 다시 샘플링됩니다. 평탄화는 편집 단계가 아니라 전달 단계입니다. 투명한 원본은 그대로 보관하고 사본을 평탄화하세요
회전된 페이지, 사용자 단위, 페이지 박스
회전된 페이지는 순진한 구현이 놓치기 쉬운 주의가 필요합니다. 렌더링 후에는 시각적인 너비와 높이가 MediaBox에 다시 기록되고, 사용자 단위는 유효 DPI와 새 페이지 크기 안으로 접혀 들어가며, /Rotate 항목, 사용자 단위, 보조 페이지 박스는 제거됩니다
이를 건너뛰면 평탄화된 이미지는 올바른데도 뷰어가 이를 다시 회전시키거나, 더 이상 적용되지 않는 사용자 단위로 스케일을 조정하는 파일이 만들어집니다. 박스를 다시 계산하는 대신 제거하는 것이 올바른 선택인데, 평탄화 이전의 지오메트리를 설명하는 TrimBox는 TrimBox가 아예 없는 것보다 더 나쁘기 때문입니다
주석과 폼 필드는 기본적으로 정적 이미지 안에 렌더링되고 상호작용 객체는 제거되는데, 이는 인쇄 준비용 산출물이 원하는 바입니다. 대신 상호작용 객체를 유지한다면, 렌더러의 주석 패스는 꺼지므로 아무것도 두 번 그려지지 않습니다
모든 것을 훑는 버전 검사
PDF 1.3으로 저장하려면 어디에도 투명도가 남아 있지 않아야 하며, 저장 전 검사는 페이지에서 도달 가능한 객체뿐 아니라 모든 간접 객체를 검사합니다. 이는 처음 보기보다 더 엄격하며, 그것이 올바릅니다: 이전 편집이 남긴 고아 소프트 마스크는 여전히 파일 안에 있으며, 페이지가 아니라 객체를 순회하는 소비자는 이를 찾아낼 것입니다
이 다운그레이드를 가능하게 하기 위해, 대상 페이지가 모두 성공적으로 교체된 뒤에는 기본적으로 mark-and-sweep 패스가 실행되어 도달할 수 없는 객체를 해제합니다. 대비해 둘 결과는, 그 스윕 이전에 얻은 이미지, 캡처된 페이지, 그래픽 상태 식별자가 이후에는 더 이상 유효하지 않을 수 있다는 것입니다. 편집을 계속하기 전에 필요한 리소스 식별자를 다시 얻거나, 스윕을 비활성화하고 그러면 버전을 낮출 수 없다는 점을 받아들이세요
두 가지 관련 자료가 이 그림을 완성합니다. 마스크 대신 셰이딩과 그라디언트를 사용하는 벡터 아트워크는 벡터 그래픽, 셰이더와 그라디언트에서 다루며, 효과를 셰이딩으로 표현할 수 있다면 보통 더 나은 경로입니다. 그리고 평탄화하려는 이유가 투명도가 아니라 색상 요구사항이라면, 문서를 다른 색공간으로 재색상화하기의 변환 경로는 평탄화가 없애 버릴 살아 있는 텍스트를 보존합니다
소프트 마스크 작성, 평탄화, 그리고 그 기반의 렌더링 엔진은 Delphi, C++Builder, Free Pascal을 위한 하나의 라이브러리로 제공됩니다. 전체 기능 목록은 Delphi용 PDF Library 페이지에서 확인할 수 있습니다