Articolo tecnico

Maschere morbide e appiattimento della trasparenza in Delphi

PDF Library for Delphi crea entrambi i tipi di maschera morbida PDF da Delphi. SetImageSoftMaskEx collega un'immagine maschera a un'immagine target e può scrivere la voce /Matte di cui la grafica premoltiplicata ha bisogno. NewSoftMaskGraphicsState costruisce una maschera alpha o di luminosità da contenuto catturato e restituisce uno stato grafico che applicate al disegno successivo. E quando un consumatore non può gestire affatto la trasparenza, FlattenTransparency renderizza il risultato visivo e sostituisce ogni pagina con esso

Le maschere morbide sono il modo in cui il PDF esprime una dissolvenza a gradiente, una vignettatura, una foto fusa in uno sfondo, e ogni altro effetto in cui l'opacità varia attraverso una regione. La trasparenza costante è un singolo numero nello stato grafico; una maschera morbida è un'intera funzione della posizione, e finché non riuscite a crearne una, un'intera categoria di design non può essere riprodotta

I due tipi di maschera, e cosa legge ciascuna

Una maschera alpha prende i suoi valori dal canale alpha del contenuto mascherante. Una maschera di luminosità li prende dalla luminosità del contenuto mascherante, così un'area bianca è completamente opaca e un'area nera completamente trasparente. La luminosità è quella a cui i designer ricorrono, perché dipingere un gradiente in scala di grigi è un modo naturale per descrivere una dissolvenza

Le maschere morbide di tipo form sono costruite da contenuto catturato, e diversi dettagli sono fissi anziché opzionali. Il contenuto catturato diventa un gruppo di trasparenza isolato in DeviceRGB, così la maschera si valuta in uno spazio colore noto. Il colore di sfondo deve quindi avere tre componenti, corrispondenti a quel gruppo. La funzione di trasferimento accetta /Identity o un oggetto funzione valido, permettendovi di rimodellare la curva della maschera senza ridipingere la grafica

Diagramma che confronta le maschere morbide di luminosità e alpha che alimentano NewSoftMaskGraphicsState, con un promemoria che lo stato grafico persiste finché non viene cancellato
Le maschere di luminosità leggono la luminosità mentre le maschere alpha leggono la copertura, e NewSoftMaskGraphicsState racchiude entrambe in uno stato grafico persistente
uses
  PDFlibrary;

var
  Lib: TPDFlib;
  MaskCapture, MaskGS, PhotoID: Integer;
begin
  Lib := TPDFlib.Create;
  try
    Lib.LoadFromFile('brochure.pdf', '');

    // La pagina 4 contiene un gradiente in scala di grigi dipinto per l'uso come maschera
    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);        // sfuma sotto la maschera

    // Le impostazioni ExtGState persistono: termina lo scope esplicitamente
    Lib.SetGraphicsState(Lib.NewSoftMaskGraphicsState(0,
      PDF_SOFT_MASK_NONE, '', ''));

    Lib.SaveToFile('brochure-masked.pdf');
  finally
    Lib.Free;
  end;
end;

Quest'ultimo passaggio non è decorazione. I parametri dello stato grafico persistono finché non vengono cambiati, e applicare in seguito uno stato grafico ordinario non cancella una maschera morbida attiva. Senza un esplicito /SMask /None, tutto ciò che viene disegnato dopo la grafica mascherata eredita la maschera, il che è uno dei bug più sconcertanti da diagnosticare visivamente

Maschere immagine e la voce Matte

Per il mascheramento a livello di immagine, l'immagine maschera viene prima normalizzata a DeviceGray, così una maschera fornita in qualsiasi spazio colore si comporta in modo prevedibile. La voce opzionale /Matte, da uno a quattro componenti a seconda dello spazio colore dell'immagine, dice a un consumatore che i dati dell'immagine sono premoltiplicati rispetto a quel colore, il che previene l'alone scuro che compare quando una grafica premoltiplicata viene composta come se fosse alpha diretto

Diagramma che mostra una voce Matte mancante che produce aloni scuri mentre una Matte dichiarata compone in modo pulito, accanto alle protezioni PDF 1.4, PDF/A e PDF/X
Una /Matte dichiarata previene l'alone scuro della grafica premoltiplicata, mentre i file PDF/A-1 e PDF/X-1 vengono rifiutati prima di qualsiasi modifica agli oggetti

Qui contano due protezioni. PDF/A-1 e PDF/X-1 vietano la trasparenza, e la chiamata si rifiuta prima di modificare qualsiasi oggetto invece di produrre un file che fallisce la validazione in seguito. E una maschera morbida riuscita richiede PDF 1.4, che la libreria imposta automaticamente — la trasparenza non esisteva prima di quella versione, e un'intestazione 1.3 su un file contenente maschere morbide è semplicemente falsa

Gli stati ripetuti vengono riutilizzati: lo stesso form catturato, tipo di maschera, sfondo e firma della funzione di trasferimento producono lo stesso oggetto stato grafico invece di uno nuovo per ogni chiamata. Su un documento che maschera cento immagini in modo identico, sono novantanove oggetti che non vengono mai scritti

Perché appiattire, e cosa fa realmente l'appiattimento

La trasparenza è ancora la fonte più comune di "sembra corretto a schermo e sbagliato in stampa". I RIP più vecchi, alcuni sistemi di invio normativo e PDF/X-1a richiedono tutti un file senza alcuna trasparenza attiva

L'appiattimento qui è deliberatamente letterale: ogni pagina nell'intervallo richiesto viene renderizzata a un DPI scelto su uno sfondo opaco, e il contenuto e le risorse della pagina vengono sostituiti da quella singola immagine. Poiché il renderer produce il risultato composito finale, questo copre tutto in una volta — gruppi di trasparenza, modalità di fusione, maschere morbide, pattern e form annidati — senza alcuna logica di approssimazione per costrutto che possa sbagliare. La memoria di raster di picco resta limitata a una pagina

Diagramma di pipeline di FlattenTransparency che renderizza ogni pagina richiesta a 300 DPI su uno sfondo opaco e salva un file PDF 1.3 piatto pronto per la stampa
Ogni pagina richiesta viene renderizzata una sola volta al DPI scelto e restituita come una singola immagine opaca salvata in un file PDF 1.3 veritiero
// Appiattisce le pagine 1-8 a 300 DPI su bianco, poi salva come PDF 1.3
Lib.FlattenTransparency('1-8', 300, $FFFFFF, 0);
Lib.SaveToFile('press-ready.pdf');

Il compromesso è altrettanto letterale: l'output è un'immagine, quindi il testo non è più selezionabile o ricercabile e i bordi vettoriali vengono ricampionati al DPI scelto. L'appiattimento è un passaggio di consegna, non un passaggio di editing. Conservate l'originale trasparente e appiattite una copia

Pagine ruotate, unità utente e i box di pagina

Una pagina ruotata richiede attenzione che un'implementazione ingenua salta. Dopo il rendering, la larghezza e l'altezza visive vengono riscritte nel MediaBox, l'unità utente viene incorporata nel DPI effettivo e nella nuova dimensione di pagina, e la voce /Rotate, l'unità utente e i box di pagina ausiliari vengono rimossi

Saltare questo produce un file in cui l'immagine appiattita è corretta ma un visualizzatore la ruota di nuovo, o la scala per un'unità utente che non si applica più. Rimuovere i box invece di ricalcolarli è la scelta giusta, perché un TrimBox che descrive la geometria precedente all'appiattimento è peggio di nessun TrimBox affatto

Le annotazioni e i campi form vengono renderizzati nell'immagine statica per impostazione predefinita e gli oggetti interattivi rimossi, il che è ciò che un deliverable pronto per la stampa vuole. Se invece mantenete gli oggetti interattivi, il passaggio di annotazione del renderer viene disattivato così nulla viene disegnato due volte

Il controllo di versione che scansiona tutto

Salvare come PDF 1.3 richiede che non rimanga trasparenza da nessuna parte, e il controllo pre-salvataggio esamina ogni oggetto indiretto, non solo quelli raggiungibili dalle pagine. Questo è più rigoroso di quanto sembri a prima vista ed è corretto: una maschera morbida orfana lasciata da una modifica precedente è ancora nel file, e un consumatore che percorre gli oggetti anziché le pagine la troverà

Per rendere possibile il downgrade, un passaggio mark-and-sweep viene eseguito per impostazione predefinita una volta che ogni pagina target è stata sostituita con successo, rilasciando gli oggetti irraggiungibili. La conseguenza da prevedere è che gli identificatori di immagine, pagina catturata e stato grafico ottenuti prima di quel passaggio potrebbero non essere più validi dopo. Riacquisite gli identificatori di risorsa di cui avete bisogno prima di continuare a modificare, oppure disabilitate il passaggio e accettate che la versione non possa quindi essere abbassata

Due complementi completano il quadro. La grafica vettoriale che usa shading e gradienti anziché maschere è trattata in grafica vettoriale, shader e gradienti, ed è spesso la strada migliore quando l'effetto può essere espresso come uno shading. E se il motivo per cui state appiattendo è un requisito di colore anziché di trasparenza, il percorso di conversione in ricolorare un documento in un altro spazio colore preserva il testo attivo dove l'appiattimento non lo farebbe

La creazione di maschere morbide, l'appiattimento e il motore di rendering dietro di essi sono forniti in un'unica libreria per Delphi, C++Builder e Free Pascal; l'elenco completo delle funzionalità è disponibile sulla pagina di PDF Library for Delphi