
Baru-baru ini, dalam satu startup, saya memecahkan masalah menghasilkan tiket dalam format PDF. Pada saat itu, sebuah situs web dengan setumpuk teknologi sudah siap, jadi saya mencari pendekatan yang tidak memerlukan penggunaan alat tambahan. Pada akhirnya, saya mengusulkan untuk membuat tiket dalam format HTML terlebih dahulu, dan kemudian mengonversi ke PDF menggunakan browser Chrome. Ternyata, metode ini dapat menghasilkan tidak hanya tiket kaya dihiasi dengan CSS, tetapi juga berbagai laporan dengan grafik di JavaScript. Dalam artikel ini, saya akan berbicara tentang cara meluncurkan Chrome untuk tujuan ini, memberikan beberapa kiat untuk menyesuaikan CSS, dan juga membahas kerugian dari solusi ini.
Opsi-opsi alternatif tidak akan dibahas di sini, karena sudah cukup dituliskan pada mereka, mereka mudah ditemukan, dan mereka adalah alat yang siap pakai, informasi yang lebih baik untuk dilihat di sumber utama - dalam dokumentasi di situs web resmi. Metode yang diusulkan bukan alat independen dan lebih seperti produk sampingan dari pengembangan beberapa teknologi. Di segmen Internet berbahasa Rusia, ada sedikit informasi yang terkumpul di dalamnya, jadi saya memutuskan untuk mengisi kekosongan.
Mengapa opsi ini dipilih?
Keuntungan terbesar adalah bahwa Chrome tidak perlu memperluas tumpukan teknologi untuk menghasilkan PDF. Pengembang frontend membuat HTML dengan alat pengembangan yang sudah dikenal dan segera melihat hasil kerja antara di browser. Pada saat yang sama, Chrome mungkin berputar dalam tes dan mentransfernya ke backend tidak sulit. Juga harus dicatat bahwa pembuat kode dapat mengakses seluruh gudang properti css termasuk Flexbox dan Grid.
Saya akan berbicara tentang kekurangan dan cara untuk mengatasinya selama artikel.
Kami memecahkan masalah dalam satu baris
Di baris perintah, kami memanggil Chrome dalam mode tanpa kepala dengan menyimpan halaman dalam pdf:
chrome --headless --disable-gpu --print-to-pdf https://google.com
Pengguna Linux mungkin perlu menjalankan chromium-browser
alih chromium-browser
alih chrome
.
Pengguna MAC mungkin merasa terbantu untuk melakukan pra-buat alias:
alias chrome="/Applications/Google\\ \\Chrome.app/Contents/MacOS/Google\\ \\Chrome"
UPDATE: Komentar menjelaskan bahwa pengguna Windows harus secara eksplisit mengatur nama file PDF --print-to-pdf=output.pdf
Jika Anda sudah memiliki pembuat dokumen HTML, alih-alih https://google.com
tentukan URL untuk menerima dokumen ini.
Buka file output.pdf
di direktori lokal dan lihat hasilnya.
Hal pertama yang menarik perhatian Anda adalah keberadaan Header dengan tanggal cetak dan Footer dengan URL dan pagination. Untuk menghapusnya, Anda perlu menambahkan beberapa aturan CSS. Aturan-aturan ini tidak mungkin ditambahkan ke google.com
, jadi untuk pekerjaan lebih lanjut lebih baik membuat dokumen HTML Anda sendiri.
Tambahkan CSS
CSS memiliki @page
kueri media khusus, yang digunakan untuk mencetak; kami akan mengatur lekukan di dalamnya sehingga Header dan Footer tidak cocok:
@page { size: A4; margin: 0mm; }
Metode ini hanya akan berfungsi untuk dokumen satu halaman, saat mencetak dua halaman atau lebih, Footer dengan URL dan penomoran halaman akan tetap berada di bagian bawah. Anda dapat secara eksplisit meminta Chrome untuk mematikan tampilan Header dan Footer dengan mengatur parameter cetak displayHeaderFooter = False
, tetapi saat ini tidak dipindahkan ke antarmuka baris perintah. Untuk mencapainya, Anda perlu alat untuk mengotomatiskan pekerjaan dengan browser: Selenium atau dalang. Selanjutnya, saya akan mempertimbangkan opsi pertama, karena proyek saya menggunakan Python.
Luncurkan Chrome melalui Selenium
Jadi, instal Selenium dengan perintah pip install selenium
, unduh driver chrome yang sesuai dengan versi Chrome Anda dari http://chromedriver.chromium.org/ dan gunakan fungsi get_pdf_from_html
dari contoh di bawah ini:
import sys from selenium import webdriver from selenium.webdriver.chrome.options import Options import json, base64 def get_pdf_from_html(path, chromedriver='./chromedriver', print_options = {}):
Untuk mendapatkan file PDF, Anda dapat menjalankan contoh ini dari baris perintah dengan menentukan url dan nama file untuk menyimpan PDF, atau memanggil fungsi get_pdf_from_html
dan menyampaikan tiga argumen padanya:
- path - url dari dokumen html;
- chromedriver - jalur di mesin lokal ke driver chrome (secara default, itu harus di direktori lokal);
- print_options - atribut cetak tambahan.
Perlu dicatat bahwa Selenium tidak memiliki antarmuka standar untuk mencetak halaman dalam PDF, dan hanya Chrome yang dapat melakukan ini, jadi Anda harus langsung menghubungi driver.command_executor._request
.
Sekarang mari kita lihat alat apa yang tersedia untuk mengontrol penempatan konten pada dokumen multi-halaman.
Tipografi CSS
Saat mencetak dupleks, Anda dapat mengatur margin berbeda dari tepi untuk halaman kanan dan kiri satu per satu jika Anda berencana untuk menjahitnya di masa mendatang:
@page :left { margin-left: 4cm; margin-right: 2cm; } @page :right { margin-left: 4cm; margin-right: 2cm; }
Untuk halaman pertama, Anda dapat menentukan desain Anda sendiri, misalnya, peningkatan indentasi dari tepi atas:
@page :first { margin-top: 10cm }
Dimungkinkan untuk mengatur istirahat halaman sebelum tajuk tingkat pertama sehingga dimulai pada halaman ganjil:
h1 { page-break-before : right }
Menggunakan properti page-break-after
, Anda dapat mencegah page break segera setelah beberapa elemen, misalnya, header tingkat kedua:
h2 { page-break-after : avoid }
Properti page-break-inside
membantu untuk menghindari page break di tempat yang tidak diinginkan untuk melakukan ini, misalnya di tengah-tengah tabel
table { page-break-inside : avoid }
Properti orphans
dan orphans
akan membantu mencegah page break pada awal dan akhir paragraf:
@page { orphans:4; widows:2; }
Bagaimana dengan kinerja?
Pada Core i5-8600K 3600MHz menjadi satu aliran, satu konversi dokumen sederhana membutuhkan 0,6 detik. Pada mesin ketik portabel akhir saya 2013, 2,4 GHz - 1,5 detik.
Jelas, sumber daya utama dihabiskan untuk meluncurkan browser. Anda dapat mengurangi waktu konversi untuk sejumlah besar file jika Anda menjalankan Chrome satu kali sebagai layanan mikro dan mengirimkannya URL untuk konversi. Implementasi metode ini berada di luar cakupan artikel ini.
Apa lagi yang salah?
Saya melihat dua masalah utama:
- Ketidakmungkinan hanya menentukan posisi elemen dalam dokumen. Ini membuatnya sulit untuk membuat daftar isi dengan indikasi otomatis nomor halaman, terutama jika ukuran konten tidak diketahui sebelumnya.
- Konversi Chrome adalah produk Google, yang mengumpulkan berbagai informasi tentang pengguna. Jika kebocoran data dari dokumen tidak dapat diterima, Anda harus berhati-hati tentang solusi yang diusulkan - tutup browser dengan akses ke sumber daya eksternal, atau bahkan cari solusi lain. Menggunakan open source Chromium tidak menyelesaikan masalah - bug dari Google telah ditemukan di dalamnya.
Kesimpulan
Saya mengusulkan untuk menarik kesimpulan tentang diterimanya menggunakan pendekatan ini sendiri. Setiap proyek unik dengan caranya sendiri. Apakah metode ini cocok untuk proyek Anda, itu terserah Anda.