Ghostscript peut être utilisé avec un exécutable binaire ou via une librairie partagée. C'est à cette deuxième hypothèse que nous nous intéressons. Nous allons piloter Ghostscript avec du code Python en utilisant la librairie libgs.
Les sources de version librairie partagée de Ghostscript sont disponibles de deux manières :
- avec une archive TAR compressée disponible sur le site ;
- avec un dépôt distant à clôner localement.
Le code source se télécharge à partir du site de Ghostscript. Il est commun pour toutes les plateformes (Windows, MacOs, Linux). Nous récupérons une archive TAR avec une compression GZIP. Le numéro de version est précisé dans le nom du fichier (ghostscript-10.02.1.tar.gz
pour la version 10.02.1)
% wget https://github.com/ArtifexSoftware/ghostpdl-downloads/releases/download/gs10021/ghostscript-10.02.1.tar.gz
% tar xvf ghostscript-10.02.1.tar.gz
% cd ghostscript-10.02.1
Dans Linux, nous mettons à jour le système, puis nous installons le compilateur GCC.
% sudo apt update && sudo apt upgrade
% sudo apt install build-essential
Dans MacOs, si nous n'utilisons pas Xcode, nous devons installer les utilisateurs de développement en ligne de commandes. Nous ouvrons le terminal et nous exécutons cette commande.
gilles@MBP-de-Gilles ~ % xcode-select --install
Une fenêtre apparaît et nous cliquons sur le bouton Installer
. Nous validons le contrat de licence. L'installation de Command Line Developer Tools se fait automatiquement. Nous pouvons suivre la progression. A la fin, gcc est installé.
Pour vérifier la bonne installation de GCC, nous taperons la commande suivante :
$ gcc -v
gcc version 11.4.0 (Ubuntu 11.4.0-1ubuntu1~22.04)
gilles@MBP-de-Gilles ~ % gcc -v
Apple clang version 13.1.6 (clang-1316.0.21.2.5)
Target: arm64-apple-darwin21.4.0
Thread model: posix
InstalledDir: /Library/Developer/CommandLineTools/usr/bin
Ensuite nous allons exécuter la configuration pour préparer les fichiers makefile.
% ./configure
Pour afficher l'aide du script de configuration nous exécuterons la commande ./configure --help
dans le terminal.
Pour lancer la compilation de la librairie partagée Ghostscript, nous exécuterons la commande make so
ou make debugso
dans le terminal.
% make so
Pour supprimer tous les fichiers de compilation nous avons à notre disposition make soclean
. A la suite nous allons pouvoir relancer tout le processus de compilation avec une génération de tous les fichiers intermédiaires.
Pour exécuter l'exécutable sur le système, nous lancerons la commande sudo make install-so
ou sudo make install-sodebug
à la suite de la compilation. La librairie est installée dans le dossier /usr/local/lib
(MacOS et Linux).
gilles@linux-mint:~/Téléchargements/ghostscript-10.02.1$ sudo make install-so
Les librairies compilées sont disponibles dans le dossier sobin
. Sous Linux, nous trouverons des fichiers avec extension so
. Par exemple pour la version 10.02, nous aurons la librairie libgs.so.10.02
, et deux liens symboliques vers la librairie (libgs.so
et libgs.so.10
). Sous MacOs, les librairies auront une extension dylib
. Pour la version 10.02 nous aurons la librairie libgs.dylib.10.02
et deux liens symboliques (libgs.dylib.10.02
ou libgs.dylib.10
).
La librairie partagée peut être utilisée avec deux exécutables : gsc
et gsx
. Le premier est identique à gs
. Le deuxième, gsx
, utilise en sortie un périphérique d'affichage s'appuyant sur un widget GTK+.
% gsc -v
GPL Ghostscript 10.02.1 (2023-11-01)
Copyright (C) 2023 Artifex Software, Inc. All rights reserved.
Nous pouvons aussi compiler Ghostscript à partir d'un dépôt distant (Git). Bien entendu il faut au préalable avoir installé Git.
gilles@MBP-de-Gilles % git clone git://git.ghostscript.com/ghostpdl.git
Cloning into 'ghostpdl'...
remote: Enumerating objects: 231573, done.
remote: Counting objects: 100% (8266/8266), done.
remote: Compressing objects: 100% (5125/5125), done.
remote: Total 231573 (delta 4424), reused 4834 (delta 3122), pack-reused 223307
Receiving objects: 100% (231573/231573), 243.30 MiB | 10.57 MiB/s, done.
Resolving deltas: 100% (182471/182471), done.
Nous devons exécuter autogen.sh pour préparer localement le dépôt. Sous MacOs, nous devons au préalable installer via brew deux outils supplémentaires.
gilles@MBP-de-Gilles % brew install autoconf automake
Il nous reste à nous placer à la racine du dépôt local, et d'exécuter successivement
gilles@MBP-de-Gilles gs % git clone git://git.ghostscript.com/ghostpdl.git
gilles@MBP-de-Gilles gs % cd ghostpdl
gilles@MBP-de-Gilles ghostpdl % ./autogen.sh
gilles@MBP-de-Gilles ghostpdl % ./configure
gilles@MBP-de-Gilles ghostpdl % make debugso
Pour synchroniser localement avec le dépôt distant nous exécuterons à la racine du dépôt local la commande git pull dans le terminal.
gilles@MBP-de-Gilles ghostpdl % git pull
Pour les utilisateurs de Visual Studio Code, pour référencer la librairie libgs, nous pouvons ajouter à une variable d'environnement
GSAPI_LIB
au fichier de configuration. Cette variable pointera sur le fichier.{ // Utilisez IntelliSense pour en savoir plus sur les attributs possibles. // Pointez pour afficher la description des attributs existants. // Pour plus d'informations, visitez : https://go.microsoft.com/fwlink/?linkid=830387 "version": "0.2.0", "configurations": [ { "name": "Débogueur Python : Fichier actuel", "type": "debugpy", "request": "launch", "program": "${file}", "console": "integratedTerminal", "env": { "GSAPI_LIB":"/Users/gilles/Downloads/ghostscript-10.02.1/sobin/libgs.dylib.10.02" } } ] }
Dans le dossier Windows
de l'archive Ghostscript nous pouvons ouvrir dans Microsoft Visual Studio 2022 le fichier solution GhostPDL.sln
. Pour obtenir la librairie nous devons générer la solution complète (Menu Générer -> Générer la solution) ou Ctrl+Maj+B
. Par défaut, la version debug sera générée. Les fichiers résultants se trouveront dans le dossier debugbin
.
Avant d'exécuter le script Python, nous devons définir une variable d'environnement GSAPI_LIB
. Dans Powershell nous procéderons comme cela :
PS > $env:GSAPI_LIB="C:\Users\gilles\Downloads\ghostscript-10.02.1\debugbin\gsdll64.dll"
Pour obtenir la liste des variables d'environnement dans Powershell nous utiliseront la ligne qui suit :
PS > dir env:
Dans l'Invite de commandes (cmd) nous utiliserons l'instruction set
:
> set GSAPI_LIBDIR=C:\Users\gilles\Downloads\ghostscript-10.02.1\debugbin\gsdll64.dll
Pour vérifier la présence de la variable nous utilisons sans argument l'instruction set
.
Pour exécuter cette application, il est fortement conseillé de créer un environnement virtuel.
PS C:\Users\gilles\Documents\Python Scripts\pdf> python -m venv .venv
Pour activer l'environnement dans Powershell nous écrirons les commandes suivantes :
PS C:\Users\gilles\Documents\Python Scripts\pdf> .\.venv\Scripts\Activate.ps1
(.venv) PS C:\Users\gilles\Documents\Python Scripts\pdf> pip list
Package Version
----------------- -------
pip 23.3.2
python-utils 3.8.1
setuptools 65.5.0
Pour fonctionner ce script a besoin de bibliothèques auxiliaires. Nous pouvons les installer directement par une commande pip
.
(.venv) PS C:\Users\gilles\Documents\Python Scripts\pdf> python install tzlocal tqdm
Nous pouvons aussi utiliser un fichier texte que nous appelerons requirements.txt
auquel nous ajouterons la ligne suivante :
tqdm==4.66.2
tzlocal==5.2
Pour installer les bibliothèques, nous utiliserons le fichier requirements.txt
avec la commande pip
.
(.venv) PS C:\Users\gilles\Documents\Python Scripts\pdf> pip install -r requirements.txt
Dans le système d'Apple nous allons utiliser l'environnement Python Conda. Nous pouvons utiliser les distributions Anaconda ou Miniconda pour utiliser Conda. Elles sont compatibles avec tous les systèmes d'exploitation (Windows, Mac Os ou Linux). Cela permet une meilleure intégration d'un environnement de travail Python.
Une fois installée, nous allons travailler dans des environnements virtuels. Pour obtenir la liste des environnements présents sur le système, nous utiliserons dans le Terminal les instructions qui suivent :
% conda env list
ou
% conda info --envs
Nous pouvons également obtenir des informations sur l'environnement. Ici, nous sommes en présence d'un environnement sous Mac OS Silicon (arm).
% conda info
active environment : base
active env location : /Users/gilles/opt/anaconda3
shell level : 1
user config file : /Users/gilles/.condarc
populated config files : /Users/gilles/.condarc
conda version : 4.13.0
conda-build version : 3.21.8
python version : 3.9.12.final.0
virtual packages : __osx=13.3.1=0
__unix=0=0
__archspec=1=arm64
base environment : /Users/gilles/opt/anaconda3 (writable)
conda av data dir : /Users/gilles/opt/anaconda3/etc/conda
conda av metadata url : None
channel URLs : https://repo.anaconda.com/pkgs/main/osx-arm64
https://repo.anaconda.com/pkgs/main/noarch
https://repo.anaconda.com/pkgs/r/osx-arm64
https://repo.anaconda.com/pkgs/r/noarch
package cache : /Users/gilles/opt/anaconda3/pkgs
/Users/gilles/.conda/pkgs
envs directories : /Users/gilles/opt/anaconda3/envs
/Users/gilles/.conda/envs
platform : osx-arm64
user-agent : conda/4.13.0 requests/2.27.1 CPython/3.9.12 Darwin/22.4.0 OSX/13.3.1
UID:GID : 501:20
netrc file : None
offline mode : False
L'environnement de développement Python peut être mis à jour.
% conda update conda
Si nous utilisons la distribution Anaconda, nous pouvons également utiliser la commande suivante :
% conda update anaconda
Pour développer, nous devons créer un environnement virtuel. Pour cela, nous utilisons la commande create, suivi de l'argument -n
pour donner un nom à l'environnement. Optionnellement, nous pouvons définir la version de Python à installer.
% conda create -n gscli python=3.11
ou
% conda create --name gscli python=3.11
Nous pouvons également intégrer des bibliothèques à la création de l'environnement. -c conda-forge
est utilisé pour définir le dépôt de bibliothèque à utiliser.
% conda create -n gscli -c conda-forge python=3.11 tqdm
Une bibliothèque peut être installée par la suite lorsque l'environnement est en cours d'utilisation.
% conda install -c conda-forge tqdm
Si nous souhaitons mettre à jour un package spécifique nous utiliserons la commande update
suivi du ou des noms de packages.
% conda update tdqm
Les dépendances (packages) sont également mises à jour. Tout est automatique, il n'est pas nécessaire de s'en inquiéter. update
propose quelques options supplémentaires :
--no-deps
pour ne pas mettre à jour les dépendances--force-reinstall
pour forcer la mise à jour même si le package est à jour--dry-run
pour simuler la mise à jour--yes
pour répondre automatiquement oui à toute question
La mise à jour de tous les packages d'un environnement se fait de cette manière.
% conda update -all
L'utilisation d'un environnement nécessite son activation. Pour faire cela, nous avons la commande :
% conda activate gscli
Pour quitter l'environnement nous procéderons comme suit :
% conda deactivate
Pour supprimer un environnement de développement :
% conda env remove --name gscli
Pour supprimer tous les environnements à un emplacement spécifique, nous utiliserons l'argument --prefix
.
% conda env remove --prefix /Users/gilles/envs
Dans le dossier comportant le script Python nous copions la librairie libgs (avec un lien symbolique).
ghostscript/libgs/libgs.dylib
ghostscript/libgs/libgs.dylib.10.02
Nous devons également copier le fichier gsapi.py
du dossier demos/python
des sources de Ghostscript.
Le dossier contenant le script gs.py
doit comporter a minima les fichiers suivants.
libgs
├── README.md
├── gs.py
├── gsapi.py
├── libgs.dylib -> libgs.dylib.10.02
├── libgs.dylib.10.02
└── requirements.txt
Pour afficher l'aide de la commande nous ajoutons le paramètre -h
.
python3 ./ghostscript/libgs/gs.py -h
usage: gscli.py [-h] [-v] [-o DESTINATION] [--replace | --no-replace] [--recursive | --no-recursive] [-p PASSWORD] [--lockpwd LOCKPWD] [--admpwd ADMPWD] [--permissions [{print,change,extract,fill,copy,annotation,quality,none} ...]] [-d DPI] [-r RELEASE] [--strategy {Gray,RGB,CMYK}]
[--gray [STRATEGY]] [--rgb [STRATEGY]] [--cmyk [STRATEGY]] [--compression {LZW,Flate,jpeg,RLE}] [--lzw [COMPRESSION]] [--flate [COMPRESSION]] [--jpeg [COMPRESSION]] [--rle [COMPRESSION]] [--downsample {Subsample,Average,Bicubic}] [--subsample [DOWNSAMPLE]]
[--average [DOWNSAMPLE]] [--bicubic [DOWNSAMPLE]]
[--papersize {a0,a1,a2,a3,a4,a4small,a5,a6,a7,a8,a9,a10,isob0,isob1,isob2,isob3,isob4,isob5,isob6,c0,c1,c2,c3,c4,c5,c6,11x17,ledger,legal,letter,lettersmall,arche,archd,archc,archb,archa,jisb0,jisb1,jisb2,jisb3,jisb4,jisb5,jisb6,flsa,flse,halfletter,hagaki}]
[--profile {printer,default,prepress,screen,PSL2Printer,ebook}] [-i] [--title TITLE] [--author AUTHOR] [--subject SUBJECT] [--keywords KEYWORDS] [--creator CREATOR] [--producer PRODUCER] [--csv CSV] [--delimiter DELIMITER]
[source ...]
Conversion de fichier au format PDF
positional arguments:
source Fichier source
options:
-h, --help show this help message and exit
-v, --version show program's version number and exit
-o DESTINATION, --destination DESTINATION
Fichier ou Dossier de destination
--replace, --no-replace
Remplacement des fichiers existants
--recursive, --no-recursive
Recherche dans les dossiers et sous-dossiers
-p PASSWORD, --password PASSWORD
Mot de passe pour les documents vérouillés
--lockpwd LOCKPWD Mot de passe pour vérouiller l'ouverture du document
--admpwd ADMPWD Mot de passe du propriétaire du document
--permissions [{print,change,extract,fill,copy,annotation,quality,none} ...]
Permissions accordés
-d DPI, --dpi DPI Points par pouce
-r RELEASE, --release RELEASE
Version du document PDF (défaut=1.4)
--strategy {Gray,RGB,CMYK}
Stratégie de conversion des couleurs
--gray [STRATEGY] Conversion en niveaux de gris (8 bits)
--rgb [STRATEGY] Conversion en couleurs (24 bits)
--cmyk [STRATEGY] Conversion en CMYK (32 bits)
--compression {LZW,Flate,jpeg,RLE}
Méthode de compression des images
--lzw [COMPRESSION] Compression sans perte
--flate [COMPRESSION]
Compression sans perte basée sur GZIP/ZIP
--jpeg [COMPRESSION] Compression avec perte
--rle [COMPRESSION] Compression simple sans perte basée sur la répétition des données (run-length encoding ou RLE)
--downsample {Subsample,Average,Bicubic}
Algorithme de rééchantillonage des images
--subsample [DOWNSAMPLE]
Algorithme de rééchantillonage plus rapide
--average [DOWNSAMPLE]
Algorithme de rééchantillonage intermédiaire
--bicubic [DOWNSAMPLE]
Algorithme de rééchantillonage qualitatif (plus lent)
--papersize {a0,a1,a2,a3,a4,a4small,a5,a6,a7,a8,a9,a10,isob0,isob1,isob2,isob3,isob4,isob5,isob6,c0,c1,c2,c3,c4,c5,c6,11x17,ledger,legal,letter,lettersmall,arche,archd,archc,archb,archa,jisb0,jisb1,jisb2,jisb3,jisb4,jisb5,jisb6,flsa,flse,halfletter,hagaki}
Appliquer à tout le document un format de page
--profile {printer,default,prepress,screen,PSL2Printer,ebook}
Profile Distiller
-i, --info Informations sur le fichier
--title TITLE Titre du document
--author AUTHOR Auteur du document
--subject SUBJECT Sujet ou objet du document
--keywords KEYWORDS Mots clefs séparés par une virgule et un espace
--creator CREATOR Créateur
--producer PRODUCER Outil de création du document
--csv CSV Enregistre les informations dans un fichier csv
--delimiter DELIMITER
Délimiteur CSV
Utilisation de libgs (https://ghostscript.com)
Pour afficher des informations sur un document PDF nous lancerons le script gs.py
avec le nom du fichier en argument.
% python3 ./gs.py "/Users/gilles/Downloads/dossier.pdf"
Fichier: /Users/gilles/Downloads/dossier.pdf
pages: 239
width: 583.200012
height: 834.47998
size: 20.57 cm x 29.44 cm
Author: gilles
Title: dossier
Subject: n/a
Keywords: n/a
Creator: OmniPage CSDK 20.2
Producer: GPL Ghostscript 10.02.1
ModDate: 21/02/2024 17:20:51 UTC+01:00
CreationDate: 14/02/2024 15:30:58
Il est possible d'obtenir les informations pour tous les fichiers d'un dossier. Par exemple, pour le dossier pdf
.
% python3 ./gs.py --info "/Users/gilles/Downloads/pdf"
Pour une exploitation des informations obtenues, il est possible de créer un fichier CSV pour une utilisation d'un outil tiers comme un tableur.
% python3 ./gs.py --info --csv "/Users/gilles/Downloads/infos.csv" "/Users/gilles/Downloads/pdf"
Par défaut, les colonnes du fichier CSV sont séparées par une tabulation \t
. Avec l'option --delimiter
nous définissons un délimiteur personnalisé.
Pour faire une conversion simple, nous précisions un fichier de destination. Dans cet exemple, il n'y a aucune modification dans le fichier hormis la date de modification (ModDate
).
-
1 fichier source -> 1 fichier destination : le fichier source est converti vers un fichier destination.
% python3 ./gs.py --replace --gray --destination "/Users/gilles/Downloads/dossier-gray.pdf" "/Users/gilles/Downloads/dossier.pdf"
-
dossier(s) sources(s) -> dossier destination : tous les fichiers du dossier source sont copiés dans le dossier destination. Les fichiers destination ne sont pas renommés. Par exemple nous faisons une convertion de tous les fichiers PDF du dossier
pdfs
vers le dossierpdfs
. Si plusieurs dossiers sources sont indiqués, les fichiers PDF de chaque dossier sera converti dans le dossier de destination.% python3 ./gs.py --replace --gray --destination "/Users/gilles/Downloads/pdfs-gray" "/Users/gilles/Downloads/pdfs" % python3 ./gs.py --replace --gray --destination "/Users/gilles/Downloads/pdfs-gray" "/Users/gilles/Downloads/pdf1" "/Users/gilles/Downloads/pdf2"
-
Fichier(s) source(s) -> dossier destination : si le dossier destination n'existe pas il sera automatiquement créé. Par exemple, les fichiers sources sont précisés les uns après les autres comme paramètre source (ici
dossier.pdf
etannexes.pdf
). Le dossierpdfs-gray
accueillera les fichiers convertis.% python3 ./gs.py --replace --gray --destination "/Users/gilles/Downloads/pdfs-gray" "/Users/gilles/Downloads/dossier.pdf" "/Users/gilles/Downloads/annexes.pdf"
Si la destination n'est pas définie, les fichiers seront copiés à la racine du dossier de l'utilisateur actif.
Nous pouvons modifier les métadatas dans un nouveau fichier. Dans cet exemple nous allons donner un titre, un auteur ainsi que deux mots clefs. Chaque valeur de métadatas doit être passée en argument avec en début et fin des doubles guillemets. Chaque mot-clef doit être séparé par une virgule et un espace.
% python3 ./gs.py --title "Dossier" --author "Gilles" --keywords "dossier, projet" --destination "/Users/gilles/Downloads/pdf1/dossier-convertion.pdf" "/Users/gilles/Downloads/pdf1/dossier.pdf"
Les profils Adobe Distiller sont utilisables en invoquant l'option --profile
suivi de l'identifiant d'un des profils acceptés par Ghostscript (pour obtenir la liste, il faut afficher l'aide en ligne).
% python3 ./gs.py --profile ebook --destination "/Users/gilles/Downloads/dossier-convertion.pdf" "/Users/gilles/Downloads/dossier.pdf"
Le document peut être converti en niveau de gris et les images adaptées à 100 DPI.
% python3 ./gs.py --strategy Gray --dpi 100 --destination "/Users/gilles/Downloads/dossier-convertion.pdf" "/Users/gilles/Downloads/dossier.pdf"
Par défaut le script Python ne supprime pas les fichiers de destination qui existent. Il faut donc ajouter --replace
pour forcer le remplacement.
Pour définir un mot de passe à l'ouverture d'un fichier, nous devons à la fois définir le mot de passe du propriétaire (owner) et le mot de passe de l'utilisateur.
% python3 ./gs.py --profile ebook --lockpwd pwduser --admpwd pwdadmin --destination "/Users/gilles/Downloads/dossier-convertion.pdf" "/Users/gilles/Downloads/dossier.pdf"
Nous pouvons aussi modifier les autorisations d'usage. Par exemple, le document peut être limité en lecture et impression.
% python3 ./gs.py --profile ebook --lockpwd pwduser --admpwd pwdadmin --permissions print --destination "/Users/gilles/Downloads/dossier-convertion.pdf" "/Users/gilles/Downloads/dossier.pdf"
Les mots de passe utilisateur et propriétaire doivent être différent.
Le tableau qui suit récapitule les différentes autorisations.
Autorisations | print |
change |
extract |
fill |
copy |
annotation |
---|---|---|---|---|---|---|
impression | ✓ | |||||
Copie du texte ou des graphisme | ✓ | |||||
Modification des attributs du document | ✓ | ✓ | ✓ | |||
Insertion, rotation ou suppression de pages | ✓ | |||||
Ajout d'annotations ou de signatures | ✓ | |||||
Extraction du texte à des fins d'accessibilité | ✓ | |||||
Remplissage des champs de formulaire existants | ✓ | ✓ |