HotPDF renderar en PDF-transparensgrupp ritad med ett icke-Normalt blend mode genom att låta gruppen beräkna sin egen blend: Cb(1 − α) + α·B(Cb, Cs), med grupp-alpha den spårar eller återställer från ett svart och ett vitt pass. Sedan v2.770.0 väljer egenskapen THotPDF.RenderColorimetricLuminosityMasks också huruvida luminosity-soft masks läser färg som viktad RGB, som vanliga visare, eller som CIE Y, som ISO 32000-1 beskriver
Båda ändringarna kom ur samma sorts fil: en sida exporterad från ett designverktyg, där ett produktfoto ligger på en mjuk skugga. Skuggan är en Form XObject ritad som en transparensgrupp med /BM /Multiply, och dess uttoning är en luminosity-soft mask. I andra visare är skuggan en lätt, neutral grå. I äldre HotPDF-byggen kom den ut nästan svart och tonad mot bakgrundsfärgen. Två separata buggar var staplade ovanpå varandra, och de är värda att ta isär eftersom vilken renderare som helst som växer ur en "opaka objekt först"-design träffar båda
Varför renderas en Multiply-skugga för mörk?
En Multiply-skugga renderas för mörk när renderaren blendar gruppens komponerade resultat i stället för gruppens egen färg och alpha. De delvis transparenta pixlarna i det resultatet innehåller redan bakgrunden, så att blenda dem med bakgrunden multiplicerar bakgrunden med sig själv. Normal blending med en opacitet är linjär och överlever det misstaget omärkt; Multiply, Screen, Darken och alla andra icke-linjära lägen gör inte det
HotPDF:s renderingspipeline hanterade ursprungligen blend modes per ritat objekt med en enkel och snabb modell. Innan ett objekt ritas tar renderaren en snapshot av de berörda pixlarna; efter ritningen jämför den "före"- och "efter"-bitmapparna och behandlar "efter"-färgen som en opak källa Cs, beräknar B(Cb, Cs) och komponerar den med aktuell opacitet. För en fylld kurva, en glyph eller en opak bild är det exakt rätt: källan är verkligen opak inuti sin form, och formen är där pixlarna ändrades
En transparensgrupp bryter det antagandet. ISO 32000-1 §11.4 definierar en grupp som något som först komponeras in i sitt eget resultat, med sin egen färg och sin egen alpha, och först därefter blendas med bakgrunden som ett enda objekt. Där en skugga är 30 procent opak håller "efter"-bitmappen ungefär 0,3 av skuggfärgen plus 0,7 av sidan under den. Mata det in i Multiply som en opak källa och formeln blir bakgrund gånger (ett värde som redan innehåller bakgrunden): skuggan mörknar och tar bakgrundens kulör. Ingenting kraschar, ingen diagnostik löser ut, och sidan ser bara fel ut, vilket är sämsta sättet för en renderare att fallera
Hur HotPDF låter en transparensgrupp göra sin egen blending
Sedan v2.769.3 flyttar HotPDF blenden för en grupp ritad under ett icke-Normalt blend mode ur den generiska per-objekt-vägen och in i grupprenderaren själv. Gruppen beräknar Cb(1 − α) + α·B(Cb, Cs) direkt ur sin egen färg, sin egen alpha och bakgrundssnapshoten som togs för Do-operatorn, och märker sedan resultatet som redan blendat så att den omslutande Do bara komponerar det med aktuell opacitet i stället för att blenda en andra gång. Vanliga objekt behåller den snabba före-och-efter-modellen, och grupper under Normal blending påverkas inte eftersom det linjära fallet aldrig var fel
Det svåra är alpha. En isolerad grupp (/I true) utgår från en helt transparent bakgrund, så renderaren spårar redan ett eget alpha-plan för den och kan läsa α direkt. En icke-isolerad grupp komponerar ovanpå vad som redan finns på sidan och har inget alpha-plan av sitt eget. HotPDF återställer det genom att rita gruppen två gånger, en gång på svart och en gång på vitt:
- På svart hamnar varje pixel som
α·Cs - På vitt hamnar samma pixel som
α·Cs + (1 − α) - Subtraktion ger
α = 1 − (white − black), och därefterCs = black / α
Det fungerar eftersom varje Normal-komposition renderaren utför, inklusive GDI AlphaBlend för bilder med soft masks och kantutjämningar, är linjär i bakgrunden. Tricket har dock ett villkor: gruppens innehåll måste i sig blenda normalt. Sätter gruppens egna ExtGState-resurser ett icke-Normalt /BM skiljer de två passen inte längre åt med en ren linjär term, så HotPDF delar inte gruppen och faller tillbaka på tidigare beteende. Kontrollen täcker bara gruppens egna resurser, inte nästlade formulär. Kostnaden är också verklig: sådana sidor renderas något långsammare eftersom gruppen ritas två gånger. Soft masks byggda inuti gruppen behålls till dess båda passen är klara, så det andra passet träffar maskcachen i stället för att bygga om dem
// Illustration av alpha-återställningen per kanal (värden 0..1).
// Black = gruppen ritad på en svart bakgrund, White = på en vit bakgrund.
procedure RecoverGroupPixel(Black, White: Double;
out Alpha, Source: Double);
begin
Alpha := 1.0 - (White - Black);
if Alpha < 0.0 then Alpha := 0.0;
if Alpha > 1.0 then Alpha := 1.0;
if Alpha > 0.0 then
Source := Black / Alpha // un-premultiply
else
Source := 0.0; // helt transparent: färgen är irrelevant
end;
// Multiply-blend, därefter gruppens komposition Cb(1 - a) + a * B(Cb, Cs)
function CompositeMultiply(Backdrop, Source, Alpha: Double): Double;
begin
Result := Backdrop * (1.0 - Alpha) + Alpha * (Backdrop * Source);
end;
Koden ovan är en illustration av matematiken, inte ett HotPDF-API; renderaren gör samma sak per kanal och per pixel inuti THotPDF.RenderLoadedPageToBitmap. I praktiken förlorar alpha som återställts ur två 8-bitars-pass precision när den närmar sig noll, så mycket svaga kanter bär en del kvantiseringsbrus, vilket är varför divisionen bara är meningsfull där alpha tydligt ligger över noll
Blend mode:en återställs till Normal inuti gruppen
Blend mode:en, liksom konstant alpha och soft masken, gäller transparensgruppen som helhet och inte varje objekt inuti den, så gruppinnehåll måste utgå från Normal blending (ISO 32000-1 §11.6.6). HotPDF återställde tidigare opacitet och soft mask vid gruppinträde men lämnade blend mode:en orörd. Resultatet inuti en isolerad grupp var dramatiskt: innehållet multiplicerade sig självt in i gruppens tomma ursprungsbakgrund, som är svart, och hela gruppen ritades svart
Samma återställning gäller när en soft mask byggs. Sätter ett ExtGState både /BM /Multiply och /SMask måste maskgruppen ritas med Normal blending; annars blir en vit maskgrupp svart och gömmer precis vad masken var tänkt att visa. Båda återställningarna ingår i v2.769.3, och båda är osynliga på enkla dokument, vilket är hur de levde så länge som de gjorde
Vilket värde ska en luminosity-soft mask ta för medelgrått?
Enligt ISO 32000-1 ska en luminosity-soft mask vars grupp använder ett CIE-baserat blandningsutrymme ta CIE 1931 Y, och Y för en sRGB-medelgrått på 0,5 är bara ungefär 0,21 eftersom Y är linjärt ljus. Vanliga PDF-visare löser i stället gruppfärgen till RGB och väger de kodade värdena ungefär 0,30 / 0,59 / 0,11, vilket ger ungefär 0,5 för samma grått. Sedan v2.770.0 är HotPDF:s standard visarkompatibel viktning och erbjuder THotPDF.RenderColorimetricLuminosityMasks för specifikationsläsningen
Gapet är inte akademiskt. En uttoning i en designverktygsexport är oftast en gradient i en ICCBased- eller kalibrerad grupp, och mellantoner är precis där linjärt Y och gamma-kodad grått skiljer sig mest. Med CIE Y släpper en medelgrå mask bara igenom ungefär en femtedel av skuggan i stället för hälften, så skuggor och vinjetter blir märkbart ljusare än i alla andra visare kunden öppnar filen i. Att ha rätt efter standardens bokstav och fel efter allas ögon är en dålig affär för ett standardvärde, så standarden följer visarna och det strikta läget ligger ett egenskapsanrop bort
var
Pdf: THotPDF;
Bmp: TBitmap;
begin
Pdf := THotPDF.Create(nil);
try
if Pdf.LoadFromFile('catalog-page.pdf') > 0 then
begin
// Standard (False): luminosity-masker väger den lösta färgen
// som DeviceRGB, i linje med vad vanliga visare visar.
// True: ta CIE Y när maskgruppen har ett CIE-baserat utrymme.
Pdf.RenderColorimetricLuminosityMasks := False;
Bmp := Pdf.RenderLoadedPageToBitmap(0, 150);
if Bmp <> nil then
try
Bmp.SaveToFile('catalog-page-viewer.bmp');
finally
Bmp.Free;
end;
end;
finally
Pdf.Free;
end;
end;
Egenskapen spelar bara roll när maskgruppens blandningsutrymme är CIE-baserat: CalGray, CalRGB, Lab eller ICCBased. Masker vars grupp använder DeviceGray, DeviceRGB eller DeviceCMYK renderas exakt som förut under endera inställningen, eftersom enhetsutrymmeskonverteringen till grått är densamma i båda lägena
Fallgropar: /BC, /CS och rendercachen
En luminosity-soft mask är bara så konsekvent som sin bakgrund: /BC-färgen som fyller maskytan utanför gruppen måste konverteras med samma regel som färgen inuti gruppen. HotPDF ändrade båda tillsammans i v2.770.0. Att konvertera färgen med viktad RGB men bakgrunden med CIE Y ger en synlig söm där gruppens begränsningsruta slutar, en bugg som är lätt att införa när bakgrunden går genom en annan hjälprutin än innehållet
Gruppattributen måste också vara giltiga innan något av detta händer. HotPDF läser blandningsutrymmet från gruppens /CS-post och kräver att /BC bär exakt ett tal per komponent i det utrymmet: tre för ett RGB-baserat utrymme, fyra för CMYK, ett för grått. En saknad /CS eller en /BC med fel antal värden får masken att fallera innan gruppen exekveras, och färgen ritas då omaskerad i stället för maskerad med en gissad bakgrund. Separation, DeviceN och NChannel är inte giltiga blandningsutrymmen, så spotfärgsmålning inuti en maskgrupp går genom sin tint-transform till det alternativa utrymmet innan luminositeten beräknas
Till slut ändrar inställningen pixlar, så den är en del av cache-nyckeln. Bitmappar renderade med RenderColorimetricLuminosityMasks på och av cachas separat i både minnes- och diskrenderingscachen, och att växla egenskapen mellan anrop till THotPDF.RenderLoadedPageToBitmapCached returnerar aldrig en bitmapp från det andra läget. En driftanteckning: v2.769.3 introducerade en regression som bara drabbade Win64, där sidor med en transparensgrupp som inte satte någon egen soft mask inte renderades; den är fixad i v2.770.1, så 64-bitars-applikationer bör använda den utgåvan eller senare
// Korrektur sida vid sida: rendera samma sida i båda lägena.
// Varje läge cachas under sin egen nyckel, så upprepade anrop är billiga.
Pdf.RenderColorimetricLuminosityMasks := False;
ViewerBmp := Pdf.RenderLoadedPageToBitmapCached(PageIndex, 96);
Pdf.RenderColorimetricLuminosityMasks := True;
StrictBmp := Pdf.RenderLoadedPageToBitmapCached(PageIndex, 96);
// ... visa båda, frisläpp dem sedan: cachade anrop returnerar anroparägda kopior
ViewerBmp.Free;
StrictBmp.Free;
För det bredare rendering-API:et, inklusive DPI-val, sidocachen och vad renderaren fortfarande approximerar, se att rendera en PDF-sida till en Delphi-TBitmap med HotPDF. Är problemet åt andra hållet, att ta bort transparens ur en fil för tryck eller arkivering i stället för att rita den, täcker soft masks och transparensflattening i PDFlibPas den sidan
FAQ
Renderar HotPDF PDF-blend modes inuti transparensgrupper korrekt?
Ja, sedan v2.769.3. En grupp ritad med Multiply eller ett annat icke-Normalt blend mode blendar sin egen färg och alpha mot bakgrunden, och dess innehåll utgår från Normal blending som ISO 32000-1 §11.6.6 kräver
Varför renderar HotPDF icke-isolerade grupper två gånger?
En icke-isolerad grupp har inget alpha-plan av sitt eget. HotPDF ritar den på svart och på vitt och återställer alpha som 1 − (white − black), vilket kostar lite fart men gör Multiply-skuggor korrekta
Ska jag sätta RenderColorimetricLuminosityMasks till True?
Låt den vara False för att matcha vad vanliga PDF-visare visar. Sätt den till True bara när du behöver CIE Y-läsningen i ISO 32000-1 för CIE-baserade maskgrupper, till exempel i en konformitetsjämförelse
Blend mode-transparensgrupper, luminosity-soft masks och sidrenderaren som ritar dem är en del av HotPDF Delphi Component, ett inbyggt VCL-bibliotek för Delphi och C++Builder som skapar, redigerar och renderar PDF-dokument utan externa DLL:er