Artikel Teknis

Memuat PDF Referensi Hibrida Dari Word dan Excel di Delphi

Buka PDF yang dihasilkan Microsoft Word atau Excel, buka halamannya, dan tidak ada yang terlihat aneh. Muat ke dalam program Delphi, baca ulang jumlah halamannya, dan jumlahnya tepat. Kemudian simpan ulang dengan enkripsi diaktifkan dan pekerjaan gagal dengan EListError, atau keluaran dibuka untuk peringatan referensi silang yang rusak. File tersebut tidak pernah rusak. Ini adalah file referensi hibrida, dan struktur yang memungkinkan penampil berusia lima belas tahun membukanya adalah struktur yang mengalahkan pemuat yang berhenti membaca terlalu dini

Ini adalah salah satu cara paling umum alur PDF yang lulus setiap pengujian internal menemui file yang tidak dapat diselesaikannya. Masukannya semuanya dihasilkan secara internal, sehingga tidak pernah berupa hibrida. File hibrida pertama tiba pada hari saat pelanggan meneruskan faktur yang diekspor dari spreadsheet

Apa yang sebenarnya ditulis Word dan Excel

ISO 32000-1 menjelaskan tata letak referensi hibrida dalam §7.5.8.4. Aplikasi yang menginginkan fitur PDF 1.5 seperti aliran objek, namun tetap membiarkan pembaca PDF 1.4 membuka file, menulis informasi referensi silang dua kali. Ada tabel referensi silang klasik, baris ASCII dengan lebar tetap yang mengakhiri setiap PDF hingga versi 1.4, dan ada aliran referensi silang yang mengindeks sisanya. Cuplikan bagian klasik membawa entri /XRefStm yang nilainya adalah offset byte dari aliran tersebut

Pembagian kerja disengaja. Objek yang harus dicapai pembaca lama, katalog dan pohon halaman di antaranya, dapat ditangani dari tabel klasik. Objek yang dilipat menjadi aliran objek terkompresi ditandai bebas di tabel klasik, dengan entri tipe f, jadi pembaca 1.4 melompat lurus melewatinya dan tidak pernah tersandung struktur yang tidak dapat diurainya. Lokasi asli mereka hanya ada di aliran referensi silang. Tanda tangan dari file semacam itu adalah ekornya: bagian klasik yang pendek, sering kali tidak lebih dari xref diikuti oleh judul sub-bagian 0 0, yang cuplikannya mengarah pada /XRefStm tempat data pemulihan yang sebenarnya berada

Mengapa jumlah halaman yang benar tidak membuktikan apa-apa

Karena katalog dan pohon halaman sengaja dapat dijangkau dari tabel klasik, pemuat yang hanya membaca tabel tersebut akan menemukan /Root, menelusuri pohon halaman, dan melaporkan jumlah halaman yang tepat. Segala hal yang dibutuhkan pembaca lama tersedia, sehingga filenya tampak sehat. Objek-objek yang raib merupakan objek yang dikemas ke dalam aliran objek: kamus bidang AcroForm, elemen struktur PDF yang diberi tag, rangkaian panjang kamus kecil yang tidak pernah harus terlihat oleh penampil lawas

Anda tidak menyadari celah tersebut sampai ada sesuatu yang menyentuh objek tersebut, dan penyimpanan ulang penuh menyentuh semuanya. Menelusuri dokumen untuk mengenkripsi ulang atau menulis ulangnya merupakan operasi persis yang meminta setiap nomor objek pada gilirannya, yang menjadi alasan gejalanya muncul pada waktu penyimpanan alih-alih waktu pemuatan, jauh dari penyebabnya

Jebakannya adalah detektor yang melihat xref lalu berhenti

Cara murah untuk memutuskan bagaimana file diindeks adalah dengan mengikuti startxref dan memeriksa byte pertama yang ditunjuknya. Kata kunci xref berarti tabel klasik; objek aliran berarti aliran referensi silang. Pengujian tersebut tepat untuk setiap file yang berkomitmen pada satu skema. Itu salah untuk file hibrida, di mana startxref miliknya mengarah ke bagian klasik untuk tujuan tunggal memuaskan pembaca lama, sementara /XRefStm di trailer bagian tersebut adalah tempat sebagian besar dokumen benar-benar diindeks. Detektor yang mengembalikan "klasik" pada xref pertama yang ditemuinya tidak pernah membaca /XRefStm, dan setiap objek yang hidup hanya dalam aliran tersebut menjadi tidak terlihat

var
  Pdf: THotPDF;
  PageCount: Integer;
begin
  Pdf := THotPDF.Create(nil);
  try
    PageCount := Pdf.LoadFromFile('Invoice_XLS.pdf');  // count is correct
    // inspect or edit the loaded document here
    Pdf.SaveLoadedDocument('Invoice_secured.pdf');     // walks every object
  finally
    Pdf.Free;
  end;
end;

Dengan adanya pendeteksi jalan keluar lebih awal, muatannya tampak baik dan penyimpanan ulangnya merupakan momen ketika objek yang tak ada mengumumkan dirinya. Perbaikannya tidak dengan membaca lebih banyak byte di awal; melainkan dengan mengenali trailer hibrida dan menyusul /XRefStm sebelum memutuskan bahwa file telah selesai

Urutan penggabungan tidak dapat dinegosiasikan

Setelah kedua indeks dibaca, keduanya hanya dapat digabungkan dalam satu arah. Aliran referensi silang harus digabungkan lebih dulu, dengan entri-entri klasik diisikan di sekelilingnya. Alasannya adalah tipu daya kecil pada inti formatnya. File hibrida menandai objek yang dikompresinya sebagai luang di dalam tabel klasik sehingga pembaca versi lama mengabaikannya. Pemuat yang menghormati kebijakan masuk-pertama-menang dan membaca tabel klasik lebih dulu akan merekam nomor-nomor objek itu sebagai luang, lantas membuang entri aliran yang aslinya menemukan mereka, dikarenakan slot-slotnya telah diambil. Balik urutannya dan masukkan tipe 2 dari aliran itu, dengan setiap masukkannya satu nomor aliran-objek beserta indeksnya, memenangkan slot-slot yang harus mereka miliki, dan penyertaan klasiknya diatur di sekitar mereka

Kedisiplinan yang sama mencegah adanya revisi usang yang menghidupkan kembali objek yang terhapus. Pembaruan secara berangsur menghubungkan rantai kemunduran lewat /Prev, dan entri bebas bertipe 0 merupakan penjaga di mana seksi yang lebih mutakhir telah memensiunkan sebuah nomor objek. Suatu seksi yang lebih lama nan lampau dalam rantai tersebut tidak akan diizinkan menimpa penjaga tersebut lewat satu lokasi usang. Hadapi pertama dilihat sebagai yang berwenang atas penanda yang bebas dan objek terhapus akan kekal terhapus; apabila dihadapi secara ceroboh, maka sejarah dari fail tersebut kembali bernyawa lewat pembaruan yang menyingkirkan sebuah konten

Apa maksud hal ini pada HotPDF

Mesin ini mengatasi berkas-berkas rujukan campuran bagi Anda, dan mengerjakannya dalam seluruh rangkaian di mana data rujukan disilang perlu ditata bahasanya. Unggah sebuah dokumen dengan LoadFromFile atau LoadFromStream, lakukan ubahan, dan panggil SaveLoadedDocument; atau langsung operasikan sebuah tindakan sekali tembak seperti halnya EncryptFile yang membaca isian dan menulis luaran. Namun apa pun itu cara penarikan bacanya /XRefStm, ia akan padukan porsi alur di bagian depan akan isian lazimnya, dan menangani objek-objek di mana dihidupkan dalam suatu alur sebelum ditoreh lewat tulisan pendaftaran ke mereka. Deret enkripsi AES-256 ini adalah tempat masalah paling utama memunculkan diri, sebab dokumen yang dikodekan menulis ulang setiap buah benda serta memaksakan tiap suatu benda sudah ditetapkan tempatnya

// One-shot: read the hybrid input, write an AES-256 encrypted copy
Pdf.EncryptFile('Letter_DOC.pdf', 'Letter_secured.pdf',
  'owner-secret', '', aes256, [prPrint, prFillAnnotations]);

Perincian yang bisa ditarik ini melingkupi hulu menuju API. Deret fail-fail dari Word, Excel, PowerPoint, dan senarai panjang lajur bentangan "Save as PDF" sewajarnya adalah percampuran wujud, jadi peramu-saji unggah di mana semata memfungsikan buatan jangkauan pembuat karya sendiri saja barangkali belum pernah sama sekali menemui keujudan seperti di dalam sesi coba-uji. Bibitilah keajegan muatan berserta ragam saripati data dari hasil tarikan ragam aplikasi karya buatan Office sungguhan, tak semata cuma dari tumpukan berkas yang dicetak ragam kodemu sendiri

Memeriksa suatu fail yang mencurigakan

Adanya dua periksa uji membereskan pertanyaan-pertanyaan tadi dengan lekas. Bukalah fail berpandangan hex (per-enam belas) dan lantas simak untaian bita per bita sesudah bagian akhir kode startxref; suatu bentuk fail berpandangan heksimal itu akan senantiasa menyibakkan wujud cuplikan isian pendek rujukan /XRefStm di perpustakaan fail akhir. Atau, sandangkan bandingan senarai benda perhitungan pendaftaran ke atas hasil pelaporan urai ke tingkatan setinggi-tingginya nilai pendaftaran /Size diletakkan di dalam deklarasi ekor bentangannya. Suatu ruang kosong berjeda lebar memaknai terdapat suatu tumpukan tak termaktub ke unggahan rujukan tersembunyi yang tiada dirajut, di mana keanehan tersebut adalah jua bentuk ketunaan di saat mencetuskannya di masa kegagalan luaran penyimpanan nantinya

Deret lajur unggahan akhir khas buatan Excel mencetuskan periksa uji pertama ke wujud lebih padu. Keseluruhan nilai sehabis barisan kode sandi rujukan utama xref berujud wajar ASCII saja, sebab adanya cap yang tertera dapat tersimak runut merujuk ke pandangan bukaan hex-nya, (keujudan tergeser-posisinya di sini dipaparkan secara ilustratif saja, adanya imbuhan keterangan tersertakan)

xref
0 0                          % empty classic subsection: no rows at all
trailer
<< /Size 216                 % one past the highest object number in use
   /Root 1 0 R
   /Info 15 0 R
   /ID [<5C9A...> <5C9A...>]
   /XRefStm 87325            % byte offset of the cross-reference stream
>>
startxref
88710                        % points at the classic section above
%%EOF

Porsi subseksi dari 0 0 adalah tempat penyingkapan cerita-nya: sebuah porsi lajur klasik nirisian data wujud semata bagi menggotong ujung cuplikannya saja, sementara cuplikan ekorannya berwujud semata guna bertutur akan deretan isian kosong semata /XRefStm 87325. Semacam instrumen pelacak terheningkan berhenti menyimak deret kata kunci xref maka dari saat perjumpaan setakat titik henti inilah, tersimak suatu ke-tiada-wujudan indeks apa-apa. Kala saja anda bersedia menjadikan ujicoba semacam itu sebuah perintah lajur-tulis naskah dari pada ditatap kosong lewat kacamata semata, sandi marka bakal lazim terposisikan bertempat ke ruang seputaran di dalam kisaran luasan kilobita pada suatu ujung akhir deretan fail terkait, sehingga cukup berbekal pembacaan sungsang seperlunya yang terbingkai

// Returns the /XRefStm offset from the file's tail, or -1 if the
// marker is absent (the file is not hybrid, or not a PDF at all)
function FindXRefStm(const FileName: string): Int64;
var
  FS: TFileStream;
  Tail: AnsiString;
  Len, P: Integer;
begin
  Result := -1;
  FS := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite);
  try
    Len := 2048;                        // the trailer lives in the tail
    if FS.Size < Len then
      Len := Integer(FS.Size);
    FS.Position := FS.Size - Len;       // bounded backward read: 2 KB max
    SetLength(Tail, Len);
    FS.ReadBuffer(Tail[1], Len);
  finally
    FS.Free;
  end;
  P := Pos(AnsiString('/XRefStm'), Tail);
  if P = 0 then
    Exit;                               // no hybrid marker in the tail
  Inc(P, Length('/XRefStm'));
  while (P <= Len) and (Tail[P] in [' ', #9, #13, #10]) do
    Inc(P);                             // skip whitespace after the key
  Result := 0;
  while (P <= Len) and (Tail[P] in ['0'..'9']) do
  begin
    Result := Result * 10 + Ord(Tail[P]) - Ord('0');
    Inc(P);
  end;
end;

// Usage: a non-negative result names the byte where the stream starts
if FindXRefStm('Invoice_XLS.pdf') >= 0 then
  Writeln('hybrid-reference file: resave will need the /XRefStm section');

Sikapilah proses merunut-periksa tadi dengan nilai ibarat menilik derajat memilah kegawatan atau kondisi luka berbatas periksanya (triase), namun semata tak ibarat selaku pisau pembedah pemerinci bahasa: hal sebegitunya memandu memberitakan pada engkau seputar bagian deret kelompok lajur porsi mananya di suatu tumpukan data yang kiranya amat menuntut perlunya kewaspadaan memadai sesaat mendahului kala berlangsung tahapan memanai operasi unggah luaran salin, cukuplah tiada sebarang selain daripadanya itu. Ihwal apanya sebuah pemuat perlu garap seterusnya bagi deret bilangan kegeseran yang disuainya, merunut rangkaian pertalian seksi porsi rantaiannya, melebur seksi jalur bentangan dengan memosisikannya mendahului rantaian wujud lazim yang ada, maupun kepatuhan menghening perlintasan ke-tanpa-isiannya, diantarkan menapak setahap berurutan semacam pengerjaan yang ada sedari artikel sanding yang memaparkan tata laksana seluk menangani PDF rujukan berhibrida asal beraneka keluaran aplikasi gubahan buatan Office

Cerita dari sudut si penoreh cetak tulis ini, bahwasanya urusan tentang tata rupa di awal muasal cetaknya berdasar aneka bentangan rujukan saling berseberang termampatkan digarap tuntas dalam artikel mengenai aneka ragam rentang subjek juga pembaruan seberkala kami. Kala saja berkas fail percampuran terkait dirasa kelewat membengkak luasan jangkau wujud besarnya, ragam jurus angkat unggah ke dalaman Pemandu Api Kembara Langsung buat pengerjaan bentangan wujud seksi luasan PDF bakal memperkenankan menilik dalam jeroannya tiada perlu musti mencerap melahap menyemai baca semua-muanya ke ruang isi kenangan (memori). Rangkaian itu serasi memadupadankan memuluskan hal menyelaraskan pengutuhan yang terbabarkan di mari, selayaknya bagian set yang dilepas sertakan teruntuk HotPDF Component di lingkungan gubahan C++Builder bersama Delphi sedari perihal menyimak memecah membaca, rekam tanda sandi enkripsi, berikut API-API rekam tanda membubuhi segenap tapak yang dituturkan senarai lain-lain bagian situs webtulis memblok-catat ini