Habrahabr, chers collègues!
Le problème de l'impression de données dans un document PDF n'est pas nouveau, je ne suis pas le premier et je ne suis pas le dernier à le rencontrer, j'ai donc décidé de partager mon expérience de résolution et en même temps de présenter à votre attention un petit site web application sur ce sujet.
1. Le format PDF est bon car il n'est pas modifiable. Dans tous les cas, il est peu probable qu'un utilisateur ordinaire soit impliqué dans la modification d'un document PDF. Cela signifie que le format PDF est bien adapté pour l'échange de documents juridiquement significatifs.
2. Le format PDF est mauvais car il n'est pas modifiable). la création de modèles, le remplissage d'un ensemble de données d'un formulaire de document PDF en mode automatique est difficile, et le mode manuel nécessite l'installation d'applications lourdes et payantes.
En tant que programmeur, je suis principalement préoccupé par le 2ème point. Comment imprimer l'ensemble de données requis dans un document PDF dans une application logicielle?
Un autre googler sur ce sujet n'a apporté aucun résultat.
Je ne réussi à Google que tout est mauvais avec frappe ( Pourquoi est - il si difficile d'extraire le texte du PDF? , PDF à partir du point de vue d'un programmeur ) et il y a une option à le modèle le fichier docx d' abord, ce n'est pas difficile à faire ( Remplir des documents dans Microsoft Word ... ), puis convertir en fichier docx console libreoffice (librewrite) en PDF. Tout cela peut être fait automatiquement à partir de l'application.
Mais d'abord, une telle décision signifie que le projet aura une forte dépendance sur libreoffice.
Et deuxièmement, lors de la conversion de docx en PDF dans libreoffice, le document est un peu différent de ce à quoi il ressemble dans Word et / ou PDF généré en Word à partir d'un fichier docx.
Enfin, passons à l'essentiel de la solution envisagée. Bien sûr, "templating" dans ce cas est un mot fort, mais la solution proposée est tout à fait appropriée et utile.
En python (et php), il existe plusieurs bibliothèques (pas difficile à google) qui vous permettent d'imprimer des chaînes et des images dans des fichiers PDF, nous utilisons pdfrw + reportlab.Canvas. Autrement dit, en principe, il n'y a pas de problème pour taper les données, le problème avec ces bibliothèques est que pour chaque champ, vous devez définir ses coordonnées exactes dans le document, ce qui signifie que
1.Nous avons besoin d'une sorte de fonctionnalité unifiée qui stockerait les coordonnées des champs non pas à l'intérieur du code source, mais dans un fichier séparé. Je clarifierai tout de suite que par expérience, je recommande de stocker ces coordonnées dans des fichiers et sous contrôle de version, c'est-à -dire validez les coordonnées avec les formulaires PDF correspondants et les méthodes qui génèrent un ensemble particulier de documents. Et ne mettez pas ces coordonnées dans la base de données, car cela rendra difficile le retour aux versions précédentes (coordonnées) des documents, si le besoin s'en fait sentir. Tout semble clair ici.
2. Ces coordonnées doivent être calculées d'une manière ou d'une autre, et c'est une tâche triste si vous le faites manuellement.
L'idée principale ici est de créer des éléments div mobiles dans le navigateur, d'utiliser la souris pour ajuster leur position à l'endroit souhaité dans le document et d'enregistrer les coordonnées des éléments obtenus dans le navigateur dans un fichier sur le backend. En fait, ces deux points sont implémentés dans l' application.
Mode d'application
Cela ressemble Ă une petite application Web avec un front-end et un back-end, c.-Ă -d. le publier en tant que package python ne fonctionnera peut-ĂŞtre pas.
1. Téléchargez les sources depuis le gita
2. Installez les dépendances
3. Lisez README.md (installez et configurez nginx pour les fichiers statiques)
4. Dans le dossier documents, créez un sous-dossier avec le nom du document à générer et à l'intérieur ce sous-dossier crée deux fichiers et (si nécessaire) un répertoire avec des images:
- form.pdf # document formulaire dans lequel vous devez
imprimer des données - fields.json # paramètres des champs à imprimer
- images # est facultatif, un ensemble d'images qui doivent ĂŞtre saisies Je vous
recommande de sauvegarder également le fichier docx d'origine (le cas échéant), qui n'est pas impliqué dans la génération du document, mais cela sera utile si vous devez apporter des modifications et régénérer le formulaire du document PDF
- form.docx # n'est pas nécessaire, aucun nom
Le fichier fields.json a la structure suivante, par exemple:
{ "0": [ [32.25, 710.25, "fio", "DejaVuSans", 12, 420], [425.25, 681.75, "gender", "DejaVuSans", 12, 18], [206.25, 681.75, "birth_date", "DejaVuSans", 12, 173], [462.75, 681.53, "foto.jpg", "DejaVuSans", 12, 92], [146.25, 665.25, "birth_place", "DejaVuSans", 12, 418], [228.0, 634.5, "registration", "DejaVuSans", 12, 340] ], "1": [ [132.0, 720.76, "1_work", "DejaVuSans", 10, 260], [132.0, 697.51, "2_work", "DejaVuSans", 10, 260], [132.0, 673.51, "3_work", "DejaVuSans", 10, 141] ] }
L'ajout / la suppression de lignes dans ce fichier ajoute / supprime les champs qui sont imprimés dans le formulaire
5. Ouvrez la page de configuration des champs (http://127.0.0.1/tpdf/positioning?pdf_name=ZayavlenieNaZagranpasport&page_num=1)
6. Ajustez la position de les champs avec la souris dans le navigateur et enregistrer cette position
7. La souris n'est pas toujours en mesure de définir avec précision la position souhaitée des champs, afin d'ajuster la position des champs, vous pouvez ouvrir le fichier fieldd.json et corriger le coordonnées manuellement. Les données du fichier sont classées par la coordonnée Y et chaque champ est stocké sur sa propre ligne dans le fichier. Ceux. le fichier avec les coordonnées des champs est soigneusement formaté, ce qui vous permet d'effectuer manuellement, facilement les ajustements nécessaires.
huit.Nous créons une autre méthode pour imprimer ce type de document (si vous devez d'une manière ou d'une autre préparer les données initiales et / ou les prendre non pas de l'avant, mais du backend).
9. Si tout est en ordre, validez le jeu de données fields.json et les fichiers résultants (mais pas dans mon git, mais dans votre git local, bien que si le document peut être utile à quelqu'un d'autre, vous pouvez collecter une banque de documents publique , c'est une idée).
Le fichier résultant avec les coordonnées peut être utilisé dans un autre projet, dans un autre langage de programmation, par exemple php, car les coordonnées du fichier sont écrites en unités de mesure (points) utilisées dans les fichiers PDF.
Si vous avez un projet python, le code source de cette application peut être simplement intégré dans le projet et, grâce à l'utilisation de la classe Tpdf principale, générer un PDF à n'importe quel endroit pratique dans le code.
Il est souvent nécessaire de générer non seulement un document à partir de plusieurs pages, mais d’assembler plusieurs documents en un seul fichier PDF, chacun devant être imprimé dans le bon ordre et certains d’entre eux plus d’une fois. La classe principale de cette application a une méthode spéciale pour ces besoins qui génère un ensemble de documents, voir la méthode de traitement / tpdf / exemple /.
Les données doivent être transmises à la classe principale lors de son instanciation. La classe principale peut être étendue avec des propriétés (@property), qui seront calculées en fonction des données d'entrée et insérées dans le PDF par nom de propriété = nom de champ. Ainsi, dans l'exemple, le champ fio est affiché et les données sont transmises nom, prénom, deuxième nom.Vous
pouvez déployer cette petite application en tant que service indépendant, et toutes les autres applications de l'environnement y accèderont pour le document nécessaire sur le réseau , mais alors il y aura des coûts de transmission sur le réseau, les fichiers PDF ne sont pas trop "légers", la génération de documents elle-même est rapide.
Au lieu de centaines de mots, il est parfois préférable de regarder une instruction vidéo (je n'ai pas enregistré de son).
Expérience de mise en œuvre (rake).
- PyPDF2, 28 3 , - . , , , , , , , - . , — . , pdfrw , , . .. 28 0.3 . : , , , .
- ajax, , .
- PDF. , , 3/4, PDF. , , .
(TODO)
- .
, / / / () fields.json - , , .
- , PDF-.
- Une méthode générique qui prend un ensemble de données en entrée et renvoie une collection de documents.