PDF Library for Delphi tworzy z Delphi oba rodzaje maski miękkiej PDF. SetImageSoftMaskEx dołącza obraz maski do obrazu docelowego i potrafi zapisać wpis /Matte, którego potrzebuje grafika z przemnożonym kanałem alfa (pre-multiplied). NewSoftMaskGraphicsState buduje maskę alfa albo luminancji z przechwyconej treści i zwraca stan graficzny, który stosujesz do kolejnego rysowania. A gdy odbiorca w ogóle nie potrafi obsłużyć przezroczystości, FlattenTransparency renderuje wynik wizualny i zastępuje nim każdą stronę
Maski miękkie to sposób, w jaki PDF wyraża gradientowe zanikanie, winietę, zdjęcie wtopione w tło i każdy inny efekt, w którym nieprzezroczystość zmienia się w obrębie regionu. Stała przezroczystość to pojedyncza liczba w stanie graficznym; maska miękka to cała funkcja pozycji, i dopóki nie potrafisz jej stworzyć, cała kategoria projektów pozostaje niemożliwa do odtworzenia
Dwa typy masek i co każdy z nich odczytuje
Maska alfa pobiera swoje wartości z kanału alfa treści maskującej. Maska luminancji pobiera je z jasności treści maskującej, więc biały obszar jest w pełni nieprzezroczysty, a czarny w pełni przezroczysty. Luminancja jest tym, po co sięgają projektanci, ponieważ namalowanie gradientu w skali szarości to naturalny sposób opisania zanikania
Maski miękkie formularza są budowane z przechwyconej treści, a kilka szczegółów jest ustalonych, a nie opcjonalnych. Przechwycona treść staje się izolowaną grupą przezroczystości w DeviceRGB, więc maska jest obliczana w znanej przestrzeni kolorów. Kolor tła musi więc mieć trzy składowe, pasujące do tej grupy. Funkcja transferu przyjmuje /Identity albo prawidłowy obiekt funkcji, pozwalając przekształcić krzywą maski bez ponownego malowania grafiki
uses
PDFlibrary;
var
Lib: TPDFlib;
MaskCapture, MaskGS, PhotoID: Integer;
begin
Lib := TPDFlib.Create;
try
Lib.LoadFromFile('brochure.pdf', '');
// Strona 4 zawiera gradient w skali szarości namalowany do użycia jako maska
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); // zanika pod maską
// Ustawienia ExtGState utrzymują się: jawnie zakończ zakres
Lib.SetGraphicsState(Lib.NewSoftMaskGraphicsState(0,
PDF_SOFT_MASK_NONE, '', ''));
Lib.SaveToFile('brochure-masked.pdf');
finally
Lib.Free;
end;
end;
Ten ostatni krok to nie ozdobnik. Parametry stanu graficznego utrzymują się, dopóki nie zostaną zmienione, a zastosowanie potem zwykłego stanu graficznego nie czyści aktywnej maski miękkiej. Bez jawnego /SMask /None wszystko narysowane po zamaskowanej grafice dziedziczy maskę, co jest jednym z bardziej zagadkowych błędów do zdiagnozowania wizualnie
Maski obrazów i wpis Matte
Dla maskowania na poziomie obrazu obraz maski jest najpierw normalizowany do DeviceGray, więc maska dostarczona w dowolnej przestrzeni kolorów zachowuje się przewidywalnie. Opcjonalny wpis /Matte, od jednej do czterech składowych w zależności od przestrzeni kolorów obrazu, informuje odbiorcę, że dane obrazu są przemnożone przez ten kolor, co zapobiega ciemnej aureoli pojawiającej się, gdy grafika z przemnożonym kanałem jest kompozytowana tak, jakby miała zwykłą alfę
Liczą się tu dwie bariery. PDF/A-1 i PDF/X-1 zabraniają przezroczystości, a wywołanie odmawia, zanim zmodyfikuje jakikolwiek obiekt, zamiast produkować plik, który później nie przejdzie walidacji. A udana maska miękka wymaga PDF 1.4, co biblioteka ustawia automatycznie — przezroczystość nie istniała przed tą wersją, a nagłówek 1.3 w pliku zawierającym maski miękkie jest po prostu fałszywy
Powtarzające się stany są używane ponownie: ten sam przechwycony formularz, typ maski, tło i sygnatura funkcji transferu dają ten sam obiekt stanu graficznego zamiast nowego przy każdym wywołaniu. W dokumencie maskującym identycznie sto obrazów to dziewięćdziesiąt dziewięć obiektów, które nigdy nie zostają zapisane
Dlaczego spłaszczać i co spłaszczanie faktycznie robi
Przezroczystość wciąż jest najczęstszym źródłem sytuacji „na ekranie wygląda dobrze, a na maszynie drukarskiej źle”. Starsze RIP-y, niektóre systemy zgłoszeń regulacyjnych i PDF/X-1a wymagają pliku w ogóle bez żywej przezroczystości
Spłaszczanie jest tu celowo dosłowne: każda strona w żądanym zakresie jest renderowana przy wybranym DPI na nieprzezroczystym tle, a treść i zasoby strony są zastępowane tym pojedynczym obrazem. Ponieważ renderer produkuje ostateczny skompozytowany wynik, obejmuje to wszystko naraz — grupy przezroczystości, tryby mieszania, maski miękkie, wzory i zagnieżdżone formularze — bez żadnej logiki przybliżania dla poszczególnych konstrukcji, która mogłaby zawieść. Szczytowe zużycie pamięci rastrowej pozostaje ograniczone do jednej strony
// Spłaszcz strony 1-8 przy 300 DPI na białym tle, następnie zapisz jako PDF 1.3
Lib.FlattenTransparency('1-8', 300, $FFFFFF, 0);
Lib.SaveToFile('press-ready.pdf');
Kompromis jest równie dosłowny: wyjściem jest obraz, więc tekst nie jest już zaznaczalny ani przeszukiwalny, a krawędzie wektorowe są ponownie próbkowane przy wybranym DPI. Spłaszczanie to krok dostarczenia, nie krok edycji. Zachowaj przezroczysty oryginał i spłaszcz kopię
Obrócone strony, jednostki użytkownika i pola stron
Obrócona strona wymaga staranności, którą naiwna implementacja pomija. Po renderowaniu wizualna szerokość i wysokość są zapisywane z powrotem do MediaBox, jednostka użytkownika jest wliczana w efektywne DPI i nowy rozmiar strony, a wpis /Rotate, jednostka użytkownika i pomocnicze pola stron są usuwane
Pominięcie tego daje plik, w którym spłaszczony obraz jest poprawny, ale przeglądarka obraca go ponownie albo skaluje przez jednostkę użytkownika, która już nie ma zastosowania. Usunięcie pól zamiast ich ponownego obliczenia jest właściwą decyzją, ponieważ TrimBox opisujący geometrię sprzed spłaszczenia jest gorszy niż brak TrimBox w ogóle
Adnotacje i pola formularza są domyślnie renderowane do statycznego obrazu, a interaktywne obiekty usuwane, czego potrzebuje dostarczana wersja gotowa do druku. Jeśli zamiast tego zachowasz obiekty interaktywne, przebieg adnotacji renderera jest wyłączany, aby nic nie zostało narysowane dwukrotnie
Kontrola wersji, która skanuje wszystko
Zapis jako PDF 1.3 wymaga, by nigdzie nie została żadna przezroczystość, a kontrola przed zapisem sprawdza każdy obiekt pośredni, nie tylko te osiągalne ze stron. To surowsze, niż wygląda na pierwszy rzut oka, i jest poprawne: osierocona maska miękka pozostawiona przez wcześniejszą edycję wciąż jest w pliku, a odbiorca przechodzący po obiektach, a nie po stronach, ją znajdzie
Aby to obniżenie wersji było osiągalne, przebieg oznaczania i zamiatania (mark-and-sweep) domyślnie uruchamia się, gdy tylko każda docelowa strona zostanie pomyślnie zastąpiona, zwalniając nieosiągalne obiekty. Konsekwencją, z którą trzeba się liczyć, jest to, że identyfikatory obrazu, przechwyconej strony i stanu graficznego uzyskane przed tym zamiataniem mogą potem już nie być ważne. Uzyskaj ponownie identyfikatory zasobów, których potrzebujesz, zanim będziesz kontynuować edycję, albo wyłącz zamiatanie i zaakceptuj, że wersji nie da się wtedy obniżyć
Obraz uzupełniają dwaj towarzysze. Grafika wektorowa wykorzystująca cieniowania i gradienty zamiast masek jest opisana w grafice wektorowej, shaderach i gradientach, i często jest lepszą drogą, gdy efekt da się wyrazić jako cieniowanie. A jeśli powodem spłaszczania jest wymóg kolorystyczny, a nie przezroczystości, ścieżka konwersji w przekolorowywaniu dokumentu do innej przestrzeni kolorów zachowuje żywy tekst tam, gdzie spłaszczanie by go nie zachowało
Tworzenie masek miękkich, spłaszczanie i stojący za nimi silnik renderujący są dostarczane w jednej bibliotece dla Delphi, C++Builder i Free Pascal; pełną listę funkcji znajdziesz na stronie PDF Library for Delphi