Bir tarama toplu işi sayfa başına tek JPEG'ten ibaret olabilir; font yok, açıklama yok, yer imi yok — ve yine de PDF/raster olarak başarısız olabilir. ISO 23504-1, yalnızca raster sayfalardan fazlasını ister: dosya, trailer alanındaki bir %PDF-raster-1.0 yorumuyla kendini tanımlamalı, XMP meta verisi ve trailer /ID taşımalı ve katalog ile Info sözlüğünü kısa, izinli listelerde tutmalı. Bir yakalama toplu işini denetlemek bu yüzden iki farklı okuma gerektirir: biri ham baytlar üzerinden, biri her sayfanın gerçekte çizdiği şey üzerinden
Aynı dosyanın iki okuması
PDF/R doğrulaması ile SaveAsPdfR, PDFium Component'in Small Business ve Enterprise sürümleriyle gelir ve doğrulamayı o hat boyunca böler. FPdfPdfr birimindeki ValidatePdfRCompliance bir akış okur ve bayt düzeyi kuralları denetler: başlık sürümü, raster işaretçisi, object stream'ler, katalog ve Info girdileri, XMP, trailer /ID, MediaBox kaynakları, font kaynakları, yasak filtre adları ve görüntü nesnesi sayısının sayfa sayısıyla eşleşip eşleşmediği. ValidatePdfRPageFacts ise bir TPdfRPageFacts kaydından birer sayfa denetler: sayfanın kaç metin, yol, form ve shading nesnesi çizdiği, tek şerit görüntünün nerede durduğu, piksel boyutu, bit derinliği, renk alanı ve filtre zinciri
İki okuma da tek bir numaralandırma olan TPdfRValidationIssue üzerinden rapor verir ve birleşik giriş noktaları bunları tek bir TPdfRValidationResult içinde birleştirir. Conformance alanı yalnızca raster işaretçisi bulunduğunda prc1 olur ve IsCompliant, düzey prc1 iken ve sorun kümesi boşken True döndürür. Her başka yönden kusursuz ama işaretçisi olmayan bir dosya prcNone raporlar; insanlar temiz bir taramayı ilk kez içinden geçirdiklerinde buna şaşırır
Soru, sayfa bilgilerinin nereden geldiğidir. TPdf.ValidatePdfR bunları yüklenmiş belgeden toplar ama önce o belgeyi geçici bir depoya serileştirir ve bayt denetimlerini yeniden kaydedilen kopya üzerinde çalıştırır; dolayısıyla işaretçi ve katalog kararları taze bir kaydı anlatır ve diskteki dosyadan farklı olabilir. FPdfBusinessWorkflows içindeki ValidatePdfRasterSource, giriş akışının tek bir anlık görüntüsünü alır ve iki okumayı da ona karşı çalıştırır. Arşive girmek üzere olan bir dosya için kullanılacak çağrı budur: karar, o zaman arşivlenen baytları anlatır
uses
System.Classes, System.SysUtils, System.TypInfo,
FPdfPdfr, FPdfReport, FPdfBusinessWorkflows;
procedure CheckDeliveredScan(const FileName: string; Log: TStrings);
var
Src: TFileStream;
Options: TPdfRasterSourceValidationOptions;
Report: TPdfRasterSourceValidationReport;
Issue: TPdfRValidationIssue;
I: Integer;
begin
Options := TPdfRasterSourceValidationOptions.Default;
Options.MaxInputBytes := 512 * 1024 * 1024; // varsayılan bütçe 64 MiB
Options.Validation.MinimumResolutionDpi := 200; // yakalama sözleşmemiz
Src := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite);
try
if not ValidatePdfRasterSource(Src, Options, Report) then
begin
Log.Add(Format('Check stopped (%s): %s',
[GetEnumName(TypeInfo(TPdfRasterSourceStatus), Ord(Report.Status)),
Report.ErrorMessage]));
Exit;
end;
finally
Src.Free;
end;
if Report.IsCompliant then
Log.Add('PDF/R-1 conformant')
else
begin
// Validation.Issues, bayt düzeyi sorunları ve her sayfa sorununu tutar
for Issue := Low(TPdfRValidationIssue) to High(TPdfRValidationIssue) do
if Issue in Report.Validation.Issues then
Log.Add('File: ' + GetEnumName(TypeInfo(TPdfRValidationIssue), Ord(Issue)));
// PageIssues hangi sayfaların yeniden taranacağını söyler
for I := 0 to Report.ProcessedPageCount - 1 do
for Issue := Low(TPdfRValidationIssue) to High(TPdfRValidationIssue) do
if Issue in Report.PageIssues[I] then
Log.Add(Format('Page %d: %s', [Report.Pages[I].PageNumber,
GetEnumName(TypeInfo(TPdfRValidationIssue), Ord(Issue))]));
end;
// Makine tarafından okunabilir kararı arşivlenen dosyanın yanına koyun
Log.Add(Report.ToJson(TPdfReportLimits.Default));
end;
TPdfRasterSourceValidationOptions'un tarama toplu işleri için önemli iki varsayılanı vardır. MaxInputBytes 64 MiB ve MaxPages 1000'dir; uzun bir renkli tarama toplu işi bayt bütçesini aşabilir ve denetim o zaman prssBudgetExceeded durumuyla, Complete False olarak biter. MemoryLimitBytes 8 MiB'dir; onun ötesinde anlık görüntü TemporaryDirectory'ye taşar ve rapor SnapshotSpilled ayarlar. Report.IsCompliant ayrıca Complete ister; yarıda kalmış bir denetim asla geçmiş gibi okunmaz
Bir OCR metin katmanı PDF/R'yi neden düşürür?
Çünkü bir raster sayfa taranan görüntüyü çizer ve başka hiçbir şey. Görünmez bir OCR katmanı, PDF/A akışında sıradan bir ektir ve PDF/R'nin dışladığı iki şeyi dosyaya sokar: bayt okumasının pvriFontForbidden olarak raporladığı bir font kaynağı ve sayfa okumasının pvriNonRasterPageContent olarak raporladığı sayfa üzerindeki metin nesneleri. Aynı sayfa sorunu vektör yolları, shading'leri ve form XObject'leri için de ateşlenir; damgalı bir sayfa numarası ya da çizilmiş bir kenarlık kuralı da gizli metin gibi aynı biçimde başarısız olur
Sayfa-görüntü ilişkisi de katıdır. Her sayfa tam olarak bir şerit görüntü taşımalıdır; pvriPageImageMismatch, görüntüsü olmayan bir sayfada da taraması iki görüntü olarak yan yana yazılmış bir sayfada da ateşlenir. Bayt tarafında sayım, /Subtype'ı /Image olan her nesnenin üzerinden alınır; dolayısıyla fazladan her görüntü nesnesi — örneğin şeride eklenmiş bir soft mask — toplamı sayfa sayısının ötesine iter
Geometri iki denetim alır. pvriBadMediaBox, [0 0 ...] ile başlamayan bir MediaBox raporlar; bayt okuması satır içi sayısal dizilere bakar. Sayfa okuması sonra şeridin çizilmiş sınırlarını MediaBox ile karşılaştırır ve herhangi bir kenar GeometryTolerancePoints'ten — varsayılanı 0.5 punto — fazlasıyla kaymışsa pvriStripGeometryInvalid raporlar. Görüntüyü sayfanın yüzde 98'ine ölçekleyerek beyaz bir kenar bırakan bir tarayıcı sürücüsü burada başarısız olur; sayfa ekranda düzgün görünse bile. Kenar kabul edilebilir iç dosyalar için RequireFullPageStrip'i False yapmak kapsam testini kapatır
Hangi görüntü kodlamaları geçer
Doğrulayıcı dört şerit filtresi kabul eder: /CCITTFaxDecode, /DCTDecode, /JPXDecode ve /FlateDecode. Bayt okuması öteki standart filtreleri adlarıyla pvriForbiddenImageFilter olarak işaretler: /LZWDecode, /RunLengthDecode, /ASCII85Decode, /ASCIIHexDecode, /JBIG2Decode ve /Crypt
JBIG2, yakalama ekiplerinin ilk çarptığı reddediliştir. PDF/A'da izinlidir ve iki düzeyli sayfaları çok iyi sıkıştırır; dolayısıyla PDF/A için kurulmuş bir yakalama profili onu çoktan üretiyor olabilir. Kayıplı örüntü eşleştirme kipinin taranmış bir glifi benzer görünümlü biriyle değiştirdiği bilinir — taranan formlardaki rakamlar için belgelenmiş bir sorun — ve bir raster arşivi tam olarak kâğıtta olanın dosyada olması için vardır. O sayfaları CCITT Group 4 ile yeniden kodlamak hem iki düzeyli hem kayıpsız tutar
Sayfa okuması bir adım öteye gider ve filtre zincirini görüntünün bit derinliği ve renk alanıyla birlikte inceler; uyuşmazlıkları pvriImageCompressionParametersInvalid olarak raporlar:
- Birden fazla filtreden oluşan bir zincir reddedilir; dolayısıyla ASCII85'e sarılmış bir Flate görüntüsü iki kez düşer, bir kez bayt tarafında bir kez burada
/CCITTFaxDecode1 bitlik bir DeviceGray şeridinde durmalıdır/DCTDecode, DeviceGray ya da DeviceRGB'de 8 bitlik ya da 24 bitlik bir şeritte durmalıdır/FlateDecode1 bitlik şeritlerde kabul edilir; 24 bitlik bir Flate sayfa bu denetimi düşürür/JPXDecodepiksel başına 1, 8 ya da 24 bittede kabul edilir
Filtreden bağımsız olarak, renk alanı DeviceGray de DeviceRGB de olmayan bir şerit pvriImageColorInvalid alır. ICC tabanlı ya da CMYK bir tarama bu yüzden sarılmadan önce dönüştürülmelidir ve bunun en ucuz yeri, hiçbir PDF yazılmadan önce tarayıcı profilidir
Şerit çözünürlüğü nasıl hesaplanır
Görüntü kendi çözünürlüğünü taşıyorsa sayfa okuması onu kullanır. Taşımıyorsa etkin çözünürlük piksellerden ve sayfa boyutundan türetilir: piksel genişliği çapı 72 bölü punto cinsinden MediaBox genişliği, yükseklik için aynı. Bir tarayıcının 612 ile 792 punto arası bir US Letter sayfasına 2550 ile 3300 piksel şerit yazdığını düşünün. Bu her iki yönde tam olarak 300 dpi eder. Aynı sayfa 600 ile 776 pikselde yatayda kabaca 70.6 dpi eder; bu varsayılan en düşüğün 72'nin altındadır ve sayfa pvriImageResolutionInvalid alır
TPdfRValidationOptions içindeki varsayılan aralık 72 ile 2400 dpi'dir. O sınırlar yalnızca bariz biçimde bozuk sayfaları yakalar. Bir yakalama sözleşmesi genellikle belirli bir en düşük değer vaat eder — çoğunlukla 200 ya da 300 dpi — ve o değer MinimumResolutionDpi'ye aittir: 150 dpi'lik bir sayfa varsayılan aralığı geçer ve tam olarak sözleşmenin dışlamak için yazıldığı sayfadır. Sınırlardan birini 0 yapmak o tarafın denetimini kapatır
ValidatePdfRPageFacts herkese açıktır; dolayısıyla aynı kurallar, hiçbir PDF var olmadan, doğrudan tarayıcının her görüntü hakkında raporladıkları üzerinden çalışabilir:
uses
FPdfPdfr;
// Sayfa bilgilerini tarayıcı çıktısından kurar; bu yardımcı sizindir, kitaplığın parçası değildir
function ScannerStripFacts(PixelW, PixelH: Integer;
PageWidthPt, PageHeightPt: Single; const Filter: string;
BitsPerPixel: LongWord; ColorSpace: Integer): TPdfRPageFacts;
begin
Result := Default(TPdfRPageFacts);
Result.PageNumber := 1;
Result.MediaWidth := PageWidthPt;
Result.MediaHeight := PageHeightPt;
Result.ImageCount := 1;
Result.ImageRight := PageWidthPt; // şerit bütün sayfayı kapsar
Result.ImageTop := PageHeightPt;
Result.PixelWidth := PixelW; // HorizontalDpi 0'da bırakıldı: türetilir
Result.PixelHeight := PixelH;
Result.BitsPerPixel := BitsPerPixel;
Result.ColorSpace := ColorSpace; // 1 = DeviceGray, 2 = DeviceRGB
SetLength(Result.Filters, 1);
Result.Filters[0] := Filter;
end;
var
Opts: TPdfRValidationOptions;
Issues: TPdfRValidationIssues;
begin
Opts := TPdfRValidationOptions.Default;
Opts.MinimumResolutionDpi := 300;
// Letter üzerinde 300 dpi renkli JPEG: boş küme
Issues := ValidatePdfRPageFacts(
ScannerStripFacts(2550, 3300, 612, 792, 'DCTDecode', 24, 2), Opts);
// Aynı sayfa 24 bitle Flate ile sıkıştırılmış:
// [pvriImageCompressionParametersInvalid]
Issues := ValidatePdfRPageFacts(
ScannerStripFacts(2550, 3300, 612, 792, 'FlateDecode', 24, 2), Opts);
end;
Katalog, Info sözlüğü ve XMP
Zorunlu /Type ile /Pages'in yanında ISO 23504-1, katalogda yalnızca Version, ViewerPreferences, PageLayout, PageMode, AcroForm ve Metadata'ya izin verir. Doğrulayıcı katalogu, o kümenin dışındaki 21 standart anahtara karşı denetler ve herhangi biri göründüğünde pvriProhibitedCatalogEntry yükseltir; aralarında Outlines, Names, PageLabels, OpenAction, StructTreeRoot, MarkInfo, Lang, OCProperties ve OutputIntents var. Sonuncusu pratikte önemlidir: bir PDF/A dosyası her zaman bir çıktı amacı taşır, dolayısıyla tek bir dosya iki profili de karşılayamaz
Info sözlüğü Creator, Producer, CreationDate ve ModDate tutabilir; Title, Author, Subject, Keywords ve Trapped pvriProhibitedInfoEntry yükseltir. /Metadata akışı olmayan bir katalog pvriMissingXmpMetadata alır. Akış yerindeyken XMP'inde xmp:CreateDate, xmp:ModifyDate ve xmp:MetadataDate'den herhangi biri eksikse bulgu bu kez pvriMetadataInvalid olur. pvriInfoXmpMismatch, Producer'ı pdf:Producer ile ve Creator'ı xmp:CreatorTool ile karşılaştırır. Tarihler o karşılaştırmanın dışında bırakılır, çünkü iki kodlama meşru biçimde farklıdır; hex dizgeleri olarak saklanan Info değerleri atlanır. Tipik tetikleyici, XMP'ye dokunmadan Info Producer'ını yeniden yazan sonradan bir araçtır
Kalan kapsayıcı kuralları kısadır. Başlık %PDF-1.4 ile %PDF-1.7 arası ya da %PDF-2.0 olmalıdır (pvriBadHeader); herhangi bir /Type /ObjStm akışı pvriObjStmPresent yükseltir ve şifreli bir dosya %PDF-2.0 başlığı kullanmalıdır (pvriEncryptVersionMismatch). RequireEncryptedPdf20Profile açık bırakıldıysa şifreleme sözlüğü ayrıca /V 5 ya da 6 ile /R 5 ve üzeri bildirmelidir; aksi hâlde dosya pvriEncryptedPdf20ProfileInvalid alır
İşaretçileri yazmak
TPdfRSaveOptions Creator, Producer, CreationDate, ModDate, DocumentId ve InstanceId taşır ve Title, Author, Subject ya da Keywords için alanı yoktur; çünkü profil onları yasaklar. StripInfoOptionalEntries ile StripCatalogOptionalEntries varsayılanda True'dur ve dışlanan girdileri kaynaktan siler; ya birini False yapın, girdiler kalır — uyumluluk pahasına. TPdf.SaveAsPdfR, boş seçenek alanlarını yüklenmiş belgenin kendi meta verisi ve dosya kimliklerinden doldurur, güvenliği kaldırır, sonra işaretçiyi, kırpılmış sözlükleri, XMP paketini ve trailer /ID'yi yazar
uses
System.Classes, System.SysUtils, PDFium, FPdfPdfr;
procedure WrapScanAsPdfR(const InFile, OutFile: string; Log: TStrings);
var
Pdf: TPdf;
Opts: TPdfRSaveOptions;
Written: TFileStream;
Res: TPdfRValidationResult;
begin
Pdf := TPdf.Create(nil);
try
Pdf.FileName := InFile;
Pdf.Active := True;
Opts := TPdfRSaveOptions.Default;
Opts.Creator := 'Capture Station 4'; // Producer, tarihler ve kimlikler kaynaktan gelir
if not Pdf.SaveAsPdfR(OutFile, Opts) then
raise Exception.Create('PDF/R save failed: ' + InFile);
finally
Pdf.Free;
end;
// Bellek içi belgeyi değil, yazılan baytları denetleyin
Written := TFileStream.Create(OutFile, fmOpenRead or fmShareDenyWrite);
try
Res := ValidatePdfRCompliance(Written);
if pvriPageImageMismatch in Res.Issues then
Log.Add('A source page still has no single strip image');
if pvriFontForbidden in Res.Issues then
Log.Add('The source carries fonts; rescan or drop the text layer');
finally
Written.Free;
end;
end;
Sarma yalnızca meta veriyi ve tanımlamayı değiştirir. Vektör metin çizen ya da şerit görüntüsü olmayan bir kaynak sayfa, SaveAsPdfR'den aynı sayfa içeriğiyle çıkar ve aynı sayfa denetimlerinde düşer. Sayfa içeriği bilerek dokunulmadan bırakılır; çünkü bir taramayı sessizce yeniden render etmek, arşivin korumak üzere kurulduğu piksellerin ta kendisini değiştirirdi. İlk listedeki CheckDeliveredScan'i OutFile üzerinde çalıştırmak, sayfa okumaları dahil tam kararı verir
PDF/R bir yakalama hattında nereye oturur
PDF/R, taramanın kendisinin kayıt olduğu ve doğruluğun bütün sözleşme olduğu çıktılar için uygundur: kanıt niteliğinde görüntüleme, çek ve havale yakalama, geniş formatlı bir tarayıcıdan çizim arşivleri. Bir belge aranabilir metin, etiketleme, ekler ya da yer imleri gerektirdiği an PDF/A'ya aittir; çünkü o özelliklerin her biri yukarıdaki dışlanan listelerine düşer
Pek çok ekip ikisini de tutar. Bir PDF/R özgünü bir kez yazılır ve hiç değişmez; OCR katmanlı bir PDF/A türevi erişimi karşılar. Doğrulayıcılar birbirinden bağımsızdır; dolayısıyla tek bir toplu iş her dosyayı iddia ettiği profile karşı denetleyebilir. Arşiv tarafı PDF/A arşiv uyumluluğu ile PDF/A preflight doğrulamasında, baskı çıktısı ise baskıya hazır PDF/X belgelerini doğrulamada işlenir
Burada gösterilen PDF/R denetimleri, Delphi, C++Builder ve Lazarus için PDFium Component'in Small Business ve Enterprise sürümlerinin parçasıdır; PDF/A, PDF/X, PDF/E ve PDF/UA doğrulayıcılarının yanında dururlar. Sürümler ve desteklenen IDE sürümleri PDFium Component ürün sayfasında