Technisch artikel

PDF's verkleinen door bijna-identieke afbeeldingen samen te voegen in Delphi

PDF Library for Delphi kan afbeeldingen in een PDF samenvoegen die er hetzelfde uitzien maar niet byte-identiek zijn, via DeduplicateSimilarImages. Exacte deduplicatie voegt alleen afbeeldingen samen waarvan de dictionaries en gecodeerde payloads overeenkomen; deze functie vergelijkt hoe de afbeeldingen er daadwerkelijk uitzien, met een perceptual hash plus twee pixelfoutdrempels, en leidt elke verwijzing om naar één canoniek object

De bestanden waar dit loont, zijn de bestanden die per ongeluk zijn gegroeid. Een gescande batch waarbij elke pagina hetzelfde logo draagt, opnieuw gecodeerd door een andere scanner. Een rapport samengesteld uit bronnen die elk dezelfde grafiek insloten op een iets andere JPEG-kwaliteit. Een catalogus waarvan de thumbnails door twee tools opnieuw zijn gegenereerd. In elk geval bevat het bestand veel kopieën van één afbeelding, en exacte deduplicatie kan geen van alle aanraken

Wat "voldoende gelijk" moet betekenen

Er moeten drie drempels allemaal worden gehaald voordat twee afbeeldingen worden samengevoegd, en elk vangt een ander soort verschil. De perceptual-hashafstand begrenst structureel verschil: een 64-bit difference hash wordt berekend uit een sample van 64 bij 64 van de gedecodeerde afbeelding, en de toegestane Hamming-afstand loopt van 0 tot 7. De gemiddelde kanaalfout begrenst algehele drift, wat herbecodering oplevert. De maximale enkelkanaalsfout begrenst lokaal verschil, wat een kleine bewerking oplevert

Dat alle drie vereist zijn, is wat de samenvoeging verdedigbaar maakt. Een afbeelding die verschilt door een watermerk in één hoek heeft een lage gemiddelde fout en een hoge maximale fout, dus wijst de maximale-foutpoort haar af. Een afbeelding die opnieuw is gecomprimeerd, heeft overal een kleine fout, dus komt ze erdoor. Dat is precies het onderscheid dat een grootte-optimalisator moet maken

Drie drempels bewaken de samenvoeging van bijna-identieke afbeeldingen: hashafstand, gemiddelde kanaalfout en maximale enkelkanaalsfout
Alle drie de poorten gebruiken gedecodeerde pixels — een watermerkpaar sneuvelt bij de maximale-foutpoort, terwijl een opnieuw gecodeerde tweeling er moeiteloos doorheen glipt
uses
  PDFlibrary;

var
  Lib: TPDFlib;
  Stats: TPDFlibImageSimilarityDedupStats;
  Merged: Integer;
begin
  Lib := TPDFlib.Create;
  try
    Lib.LoadFromFile('scanned-batch.pdf', '');

    // Hashafstand 2, gemiddelde fout 2, enkelkanaalsfout 4.
    // Opties kunnen een dry run aanvragen zodat er niets wordt gewijzigd
    Merged := Lib.DeduplicateSimilarImages(2, 2, 4, 0, Stats);
    if Merged < 0 then
      raise Exception.Create('deduplication failed');

    Log(Format('%d scanned, %d merged, %d refs repointed, %d bytes duplicated',
      [Stats.ImagesScanned, Stats.ImagesDeduplicated,
       Stats.ReferencesRepointed, Stats.DuplicatePayloadBytes]));
    Log(Format('worst accepted: hash %d, mean %.2f, channel %d',
      [Stats.MaxAcceptedHashDistance, Stats.MaxAcceptedMeanError,
       Stats.MaxAcceptedChannelError]));
    Lib.SaveToFile('scanned-batch-optimised.pdf');
  finally
    Lib.Free;
  end;
end;

Semantische identiteit komt vóór visuele gelijkenis

Voordat er ook maar één pixel wordt vergeleken, moeten kandidaat-afbeeldingen semantisch overeenkomen. De library bouwt een stabiele signature op basis van de volledige afbeeldingsdictionary, met uitzondering van /Length, /Filter en /DecodeParms, zodat afmetingen, kleurruimte, bitdiepte, maskers, de /Decode-array, interpolatie, optional-content-lidmaatschap en metadata allemaal moeten overeenkomen

Deze volgorde voorkomt een hele klasse van foutieve samenvoegingen. Twee afbeeldingen kunnen er identiek uitzien in een sample van 64 bij 64 en zich toch anders gedragen op de pagina: één met /Interpolate true en één zonder worden bij het schalen anders gladgestreken, en één die tot een optional-content-groep behoort, verdwijnt wanneer die laag wordt verborgen. Samenvoegen over die grenzen heen levert een document op dat kleiner is en fout

Alleen indirecte Image XObjects worden gescand. Inline afbeeldingen zijn een andere constructie met andere economie, en afbeeldingen die niet kunnen worden gedecodeerd, worden conservatief overgeslagen en geteld in plaats van op goed vertrouwen samengevoegd — geen pixelbewijs, geen samenvoeging

Hoe de zoekactie goedkoop blijft

Elke afbeelding tegen elke andere afbeelding vergelijken is kwadratisch, wat onaanvaardbaar is bij een document met duizenden afbeeldingen. De hash wordt daarom gesplitst in acht 8-bit banden, elk met een geordende index

Het ladenkastprincipe doet de rest: als twee hashes op ten hoogste 7 bits verschillen, moeten ze op minstens één van de acht banden exact overeenkomen. Kandidaten band voor band opzoeken vindt daarom elke toegestane match zonder een uitputtende paarsgewijze scan, en de gepubliceerde limiet van 7 bestaat precies omdat de garantie alleen tot die afstand geldt

De 64-bit difference hash splitst in acht 8-bit banden, en het ladenkastprincipe garandeert dat na zeven bitomkeringen nog steeds minstens één band overeenkomt
Zeven omgekeerde bits over acht banden moeten minstens één band intact laten, wat een kwadratische scan omzet in acht geordende opzoekingen

Kandidaten en bandtreffers worden deterministisch geordend op objectnummer en generatie, en het laagste objectnummer wordt canoniek. Dat maakt de output reproduceerbaar: de optimalisator twee keer op dezelfde invoer draaien levert dezelfde canonieke keuzes op, wat van belang is wanneer het resultaat wordt vergeleken of ondertekend

Dry runs en eerlijke rapportage

Omdat dit een lossy optimalisatie is in die zin dat de samengevoegde afbeeldingen niet identiek waren, is de verstandige workflow eerst kijken en dan pas springen. De dry-run-optie rapporteert wat er zou worden samengevoegd en hoeveel payload zou worden teruggewonnen zonder de objectgraaf te wijzigen, zodat een batchtaak het effect kan loggen en een mens de drempels één keer kan goedkeuren in plaats van per bestand

Twee eerlijkheidsopmerkingen in de rapportage verdienen vermelding. Het terugwinbare cijfer schat alleen de gecodeerde payload van dubbele streams; het telt geen dictionary-, indirect-object- en cross-reference-overhead mee, dus is de werkelijke verkleining van het bestand iets groter dan gerapporteerd in plaats van kleiner. En het rapport toont de maximaal geaccepteerde fout en de vergelijkingsbelasting, zodat u kunt zien hoe dicht de samenvoegingen bij uw drempels kwamen

Het vaste samplingraster van 64 bij 64 is een bewuste benadering, en het heeft een gevolg dat het waard is duidelijk te benoemen: een verschil dat kleiner is dan één samplecel kan onopgemerkt blijven, zelfs bij een drempel van nul. Eén enkel gewijzigd woord op een gescande pagina overleeft die sampling mogelijk niet. Wanneer bewijs op byteniveau vereist is, gebruik dan in plaats daarvan het exacte-deduplicatietraject — dat voegt alleen werkelijk identieke resources samen en maakt helemaal geen visueel oordeel

Waar het thuishoort in een grootteverkleiningspijplijn

Orden de passes op risico. Voer eerst exacte resourcededuplicatie uit, want die is lossless en gratis. Dan lettertypesubsetting, wat ook lossless is en meestal de grootste enkele winst oplevert bij tekstzware documenten, zoals behandeld in PDF-bestandsgrootte-optimalisatie en lettertypesubsetting. Dan hercompressie of downsampling van afbeeldingen als het doelmedium dat toelaat. Perceptuele deduplicatie hoort daarna, want het is de enige stap waarvan het resultaat afhangt van een oordeel

Aanbevolen pijplijnvolgorde van lossless exacte deduplicatie en lettertypesubsetting naar voorwaardelijke afbeeldingshercompressie, perceptuele deduplicatie en verificatie
Elke stap voegt risico toe, dus komen lossless winsten eerst en draait de op-oordeel-gebaseerde samenvoeging als laatste, gevolgd door een render-en-vergelijk-controle

Kies drempels per documentklasse in plaats van globaal. Voor gescande batches waarbij elke pagina hetzelfde briefhoofd draagt, voegt een hashafstand van 2 tot 3 met een gemiddelde fout rond 2 het briefhoofd betrouwbaar samen. Voor documenten waarbij afbeeldingen data dragen — grafieken, kaarten, medische beeldvorming — gebruikt u nul of bijna-nul drempels, of slaat u de pass helemaal over, want twee grafieken die op één geplot punt verschillen, zijn twee verschillende grafieken, hoe gelijkend ze er ook uitzien op 64 bij 64

Verifieer na het optimaliseren. Render een steekproef van pagina's van vóór en na en vergelijk ze, en controleer of het aantal pagina's en het aantal afbeeldingen is veranderd zoals u verwachtte. Het inspectietraject voor wat een document daadwerkelijk bevat, wordt beschreven in PDF-bestandsgrootte auditen per categorie, wat ook de snelste manier is om erachter te komen of afbeeldingen om te beginnen uw probleem zijn

Perceptuele deduplicatie, exacte resourcededuplicatie en de grootte-audit draaien op dezelfde objectgraaf voor Delphi, C++Builder en Free Pascal; de volledige functielijst staat op de PDF Library for Delphi-pagina