PDFium Component membuat anotasi markup teks, yang berarti sorotan (highlight), garis bawah (underline), coretan (strikeout), dan coretan bergelombang (squiggly), melalui TPdf.CreateAnnotation: Anda menetapkan HasAttachmentPoints := True pada rekaman TPdfAnnotation &dan mengisi quadrilateral AttachmentPoints-nya, dan komponen tersebut menulis entri QuadPoints yang didefinisikan dalam ISO 32000-1 §12.5.6.10. Itu adalah seluruh permukaan API. Alasan artikel ini ada adalah apa yang terjadi di bawahnya, karena rantai panggilan PDFium mentah memiliki mode kegagalan yang menghasilkan gejala yang paling tidak membantu dalam toolkit: FPDFAnnot_SetAttachmentPoints mengembalikan false pada anotasi yang baru dibuat, setiap saat, tanpa kode kesalahan dan tanpa petunjuk. Ini adalah pendamping sisi pembuatan untuk artikel kami tentang membaca dan meninjau anotasi yang ada, yang berjalan ke arah sebaliknya melalui struktur yang sama
Adegan debugging selalu sama. Anda membuat anotasi sorot (highlight), memanggil penyetel attachment-points dengan indeks 0, fungsi mengembalikan false, dan Anda mulai meragukan koordinat Anda sendiri. Anda mentransposisikan titik-titik tersebut, membalik sumbu Y, menukar ruang halaman dengan ruang perangkat. Tidak ada yang membantu, karena koordinatnya tidak pernah menjadi masalah. Masalahnya adalah semantik indeks dari C API, dan begitu Anda melihatnya, perbaikannya hanya dua baris
Arti QuadPoints dalam ISO 32000-1
QuadPoints adalah larik (array) dari angka 8×n yang mendeskripsikan n quadrilaterals, dan ISO 32000-1 §12.5.6.10 mensyaratkannya pada setiap anotasi markup teks: setiap quadrilateral menandai kata atau sekelompok kata berurutan yang diterapkan sorotan, garis bawah, atau coretan. Entri Rect anotasi masih ada, tetapi untuk subtipe markup itu hanya membatasi wilayah; quads adalah apa yang sebenarnya dilukis oleh renderer. Bentuknya berupa quadrilateral daripada persegi panjang karena teks dapat diputar atau dipotong, sehingga keempat sudut disimpan sebagai empat titik independen: x1 y1 x2 y2 x3 y3 x4 y4
Urutan dari keempat titik tersebut adalah di mana spesifikasi dan basis instalasi berbeda jalan. Teks spesifikasi menggambarkan titik-titik tersebut menelusuri quadrilateral berlawanan arah jarum jam, tetapi renderer milik Adobe sendiri selalu menafsirkannya dalam pola Z sebagai gantinya: pertama tepi atas dari kiri ke kanan, lalu tepi bawah dari kiri ke kanan. Karena setiap penulis mengujinya terhadap Acrobat, secara efektif setiap renderer, termasuk PDFium, mengikuti pola Z, dan file yang mengikuti kata-kata literal spesifikasi dirender sebagai sorotan yang kolaps atau terpuntir di beberapa penampil. Struktur FS_QUADPOINTSF milik PDFium mengodekan konvensi ini secara tepat: (x1,y1) adalah sudut kiri atas, (x2,y2) kanan atas, (x3,y3) kiri bawah, (x4,y4) kanan bawah, dalam koordinat halaman di mana Y tumbuh ke atas. Ikuti urutan itu dan selesai; renderer toleran terhadap banyak hal, tetapi quad yang acak-acakan bukanlah salah satunya
Mengapa FPDFAnnot_SetAttachmentPoints mengembalikan false?
FPDFAnnot_SetAttachmentPoints gagal pada anotasi baru karena kontraknya adalah untuk mengganti quadrilateral pada indeks yang diberikan, dan anotasi yang baru dibuat memiliki nol quadrilateral untuk diganti. Tanda tangannya membutuhkan handel anotasi, quad_index, dan titik-titik; indeks 0 tidak berarti "slot pertama, membuatnya jika diperlukan", itu berarti "quad nomor 0 yang ada", dan ketika FPDFAnnot_CountAttachmentPoints melaporkan 0, tidak ada quad seperti itu dan panggilan mengembalikan false. Fungsi yang membuat slot adalah FPDFAnnot_AppendAttachmentPoints. Setiap anotasi yang dibuat melalui FPDFPage_CreateAnnot dimulai dengan jumlah nol, sehingga jalur pembuatan harus memanggil Append terlebih dahulu, dan hanya pembaruan berikutnya yang boleh memanggil Set
// Di dalam penulis anotasi komponen (v1.79.1+):
// anotasi baru belum memiliki slot quad, jadi Append membuat
// yang pertama; Set hanya menggantikan slot yang sudah ada
if FPDFAnnot_CountAttachmentPoints(Annotation) = 0 then
Check(FPDFAnnot_AppendAttachmentPoints(Annotation, QuadPoints) <> 0,
'Cannot set attachment points')
else
Check(FPDFAnnot_SetAttachmentPoints(Annotation, 0, QuadPoints) <> 0,
'Cannot set attachment points');
Pola yang sama berlaku jika Anda memanggil fungsi C yang diekspor secara langsung, yang diizinkan oleh komponen karena semua titik masuk FPDFAnnot_* entry points dimunculkan di PDFium.pas. Kapan pun Anda memegang handel FPDF_ANNOTATION dan ingin menulis quads, tanyakan FPDFAnnot_CountAttachmentPoints terlebih dahulu dan rute yang sesuai. Jika Anda mencari "FPDFAnnot_SetAttachmentPoints returns false", cabang hitung-lalu-tambahkan ini hampir pasti adalah jawaban Anda
Membuat sorotan dengan TPdf.CreateAnnotation
var
Pdf: TPdf;
A: TPdfAnnotation;
begin
Pdf := TPdf.Create(nil);
try
Pdf.CreateDocument;
Pdf.AddPage(0, 595, 842);
FillChar(A, SizeOf(A), 0);
A.Subtype := anHighlight;
A.HasColor := True;
A.Color := clYellow;
A.ColorAlpha := $80; // 50% opasitas
A.HasAttachmentPoints := True;
A.AttachmentPoints[1].X := 50; A.AttachmentPoints[1].Y := 700; // kiri-atas
A.AttachmentPoints[2].X := 250; A.AttachmentPoints[2].Y := 700; // kanan-atas
A.AttachmentPoints[3].X := 50; A.AttachmentPoints[3].Y := 680; // kiri-bawah
A.AttachmentPoints[4].X := 250; A.AttachmentPoints[4].Y := 680; // kanan-bawah
A.Rectangle.Left := 50; A.Rectangle.Top := 700;
A.Rectangle.Right := 250; A.Rectangle.Bottom := 680;
A.ContentsText := 'Highlighted region';
Pdf.CreateAnnotation(A);
Pdf.SaveAs('highlighted.pdf');
finally
Pdf.Free;
end;
end;
Beralih subtipe hanya memakan satu baris. anUnderline, anStrikeout, dan anSquiggly mengambil bentuk rekaman yang identik, quads dan semuanya, karena ISO 32000-1 memperlakukan keempatnya sebagai keluarga anotasi yang sama yang dibedakan hanya berdasarkan bagaimana wilayah quad dihiasi. Subtipe yang bukan markup teks, seperti anSquare, anCircle, dan anText, memposisikan diri mereka dari Rectangle saja; biarkan HasAttachmentPoints bernilai False untuk jenis tersebut, dan mesin quad tidak akan pernah berjalan
Mengapa AttachmentPoints[0] dapat dikompilasi di Delphi tetapi gagal di FPC?
TQuadrilateralPoint dideklarasikan sebagai array [1..4] of TPdfPoint, larik berbasis 1, dan hal itu menjebak siapa saja yang jarinya terbiasa dengan pengindeksan berbasis nol. Tulis A.AttachmentPoints[0] dan dcc32 milik Delphi akan mengompilasinya tanpa keluhan, karena pemeriksaan jangkauan (range checking) dinonaktifkan secara bawaan; saat runtime, ekspresi tersebut secara senyap membaca atau menulis memori tepat sebelum larik, yang dalam rekaman TPdfAnnotation adalah bidang yang berdekatan. Sorotan Anda mendapatkan satu sudut sampah, atau bidang tetangga menjadi rusak, dan tidak ada yang dimunculkan. Free Pascal menangkap bug persis seperti ini di sumber demo kami sendiri selama porting Lazarus: fpc melakukan pemeriksaan jangkauan waktu kompilasi pada indeks konstan dan menolak AttachmentPoints[0..3] secara langsung, yang merupakan bagaimana kesalahan selisih satu (off-by-one) dan bug pustaka Set-versus-Append terungkap bersama
Dua kebiasaan mengikuti. Indeks quad 1 hingga 4, mencocokkan urutan sudut dalam kode di atas, dan bangun kode anotasi Anda setidaknya sekali dengan pemeriksaan jangkauan diaktifkan, baik {$R+} di Delphi atau build fpc apa pun, sebelum memercayainya. Build dcc32 bawaan yang lolos bukan merupakan bukti bahwa indeksnya benar; itu hanya bukti bahwa tidak ada yang crash pada memori yang kebetulan ada di sana
Mendapatkan koordinat quad dari teks asli
Persegi panjang yang dikodekan secara keras baik untuk demo, tetapi sorotan produksi melacak glyph yang sebenarnya, dan koordinatnya harus berasal dari geometri halaman teks PDFium alih-alih tebakan. Rutinitas yang dibahas dalam panduan kami untuk ekstraksi teks dengan PDFium Component memberi Anda kotak pembatas per karakter dalam ruang koordinat halaman yang sama dengan yang digunakan quads, sehingga hasil pencarian langsung dikonversi menjadi titik sudut: kiri karakter pertama, kanan karakter setelahnya, atas dan bawah dari cakupan garis. Jika Anda membuat teks sendiri dan perlu mengetahui di mana garis akan jatuh sebelum mereka ada, artikel pengukuran teks dan pembungkusan kata membahas penghitungan cakupan tersebut di awal
Satu batasan jujur: rekaman TPdfAnnotation membawa satu TQuadrilateralPoint, sehingga satu panggilan CreateAnnotation menulis satu quadrilateral. Pilihan yang mencakup tiga baris membutuhkan tiga quads, satu per baris, menurut §12.5.6.10, dan Anda memiliki dua cara untuk mencapainya. Cara sederhana adalah satu anotasi per baris, yang merender dengan benar di mana saja dan mempertahankan API tingkat komponen. Cara ringkas, satu anotasi yang membawa tiga quads, berarti membuat anotasi melalui komponen dan kemudian memanggil FPDFAnnot_AppendAttachmentPoints yang diekspor sendiri untuk quad kedua dan ketiga, yang berfungsi tepat karena Append membuat slot alih-alih menggantikannya. Jangan mencoba menjangkau multi-quad melalui panggilan SetAttachmentPoints berulang kali; setiap indeks yang melewati jumlah saat ini hanya akan mengembalikan false, karena alasan yang sama seperti indeks 0 pada anotasi baru
Setelah menulis, verifikasi di penampil nyata alih-alih memercayai kode pengembalian: buka file di Acrobat atau penampil berbasis PDFium mana pun dan konfirmasikan markup mendarat di teks, terbaca pada opasitas yang dimaksudkan, dan bertahan dalam proses bolak-balik simpan-dan-muat ulang. Jenis anotasi, penanganan quad, dan penulis yang peka terhadap jumlah (count-aware) yang ditunjukkan di sini semuanya merupakan bagian dari PDFium Component standar untuk Delphi, C++Builder, dan Lazarus; halaman produk membawa referensi API anotasi lengkap bersama dengan bagian pustaka lainnya