Compresser un ePub: ma méthode pour réduire la taille d’un ePub

Lorsque j’ai terminé mon ebook, je l’ai tout naturellement exporté et j’ai obtenu un fichier ePub de… 160Mo. C’est beaucoup trop. Il est nécessaire de compresser un ePub avant de le publier car les distributeurs (Amazon en premier), facturent le coût de la distribution en fonction de la taille du fichier. Avec ma méthode, j’ai obtenu un ePub de 29Mo: 80% de compression. Pas mal non?

Réduire la taille d’un ePub: quels éléments?

Fichier ePub trop lourd? Pour alléger un ePub, on va parler compression. La 1ère source d’éléments à compresser dans un ePub, ce sont les images! Dans mon cas, elles représentent 90% de la taille de mon eBook.

On peut trouver aussi d’autres sources d’optimisations comme le nombre de police intégrés.

Structure d’un fichier ePub

Comprenons déjà la structure d’un fichier ePub. Un fichier ePub est une archive Zip d’une structure bien définie:

  • le 1er fichier de l’archive est mimetype. Il ne doit pas être compressé.
  • un dossier « META-INF » contenant quelques informations de base sur la structure.
  • un autre dossier, « OPS » ou « oebps » contenant les données du ePub.

Le fichier mimetype permet aux applications qui vont lire ce fichier de le considérer comme un fichier spécial de type application/epub+zip, et pas comme une simple archive zip.

Le contenu du fichier mimetype fait exactement 20 caractères, sans saut de ligne à la fin:

application/epub+zip

Ce que ça veut dire, c’est que nous allons pouvoir dézipper le ePub pour comprendre ce qui prend de la place afin de pouvoir compresser un ePub en conséquence.

Commencez donc par dézipper le fichier ePub. Vous pouvez ajouter l’extension .zip pour vous aider. Sur macOs, via le terminal, la commande est:

flogg@MacBook:~/ePub$ unzip MonEBook.epub

On obtient la structure:

flogg@MacBook:~/ePub$ ls
META-INF/   OPS/        MonEBook.epub  mimetype

Réduire la taille d’un ePub: les images

Aller donc voir la taille du dossier OPS/images/. Il est énorme? Parfait, on va pouvoir compresser.

L’analyse dépend de chaque cas. Je vous raconte le mien mais le votre pourrait être différent.

Premier constat, je n’ai que des fichiers PNG. Clairement, ce n’est pas le format le plus efficace pour mon type de contenu. On préférera le format JPEG. Ce changement n’est valable que pour les images que n’ont pas besoin de fond transparent. Pour ces dernières, il n’y a pas d’autres choix que de conserver le format PNG.

Deuxième constat, ces fichiers ne sont pas optimisés du tout. Une simple optimisation des fichiers en suivant les recommandations de Google m’a permis de gagner 50Mo.

Convertir les images d’un ePub en JPEG

Les fichiers ePub supportent 4 types de fichiers images:

  • PNG
  • JPEG
  • GIF
  • SVG

Pour convertir de JPEG en PNG, j’utilise ImageMagick en ligne de commande sur macOs. Rappel: la transformation va remplacer les images au fond transparent par un fond blanc (-background white).

flogg@MacBook:~/ePub$ convert ./OPS/images/image.png -background white -alpha remove ./OPS/images/image.jpg
flogg@MacBook:~/ePub$ rm ./OPS/images/image.png

Il faut maintenant changer toutes les références de ce fichier dans tout votre ePub:

  • OPS/epb.opf: Ce fichier contient un inventaire des fichiers de l’ePub. Il faut remplacer une ligne comme:
<item id="dataItem5" href="images/image-1.png" media-type="image/png"/>

par

<item id="dataItem5" href="images/image-1.jpg" media-type="image/jpg"/>
  • OPS/page-xxx.xhtml: Ce fichier contient une page de votre ePub. Il suffit de remplacer toutes les occurrences de images/image-1.png par images/image-1.jpg

Répétez l’opération pour toutes les images. Vous pouvez automatiser l’opération de renommage des occurrences avec sed, par exemple:

flogg@MacBook:~/ePub$ sed -i'' -e "s/images\/image-1.png/images\/image-1.jpg/g" ./OPS/page-*.xhtml
flogg@MacBook:~/ePub$ sed -i'' -e "s/href=\"images\/image-1.png\"\ media-type=\"image\/png\"/href=\"images\/image-1.jpg\"\ media-type=\"image\/jpeg\"/g" ./OPS/epb.opf
flogg@MacBook:~/ePub$ rm ./OPS/*-e

La simple conversion de mes fichiers PNG en JPG m’a permis de compresser un ePub de 60% (157Mo > 63,1Mo).

Compresser les images d’un ePub

Que les images soient au format JPG ou PNG, c’est pareil et c’est très simple. Compresser toutes les images avec un programme comme ImageOptim, en suivant les recommandations de Google pour l’optimisation des images. Oui, on va dégrader la qualité de certaines images mais ce sera difficilement visible à l’oeil.

J’ai obtenu une compression d’environ:

  • 30% pour les fichiers PNG
  • 50% pour les fichiers JPG

Supprimer les images en doublon

Dans mon cas, j’utilise à plusieurs reprises une même image (un rond rouge). L’image de ce rond rouge est présente plus de 50 fois, avec un nom différent.

On peut compresser un peu plus l’ePub en ne conservant qu’une occurence de cette image et en remplaçant toutes les occurrences dans les fichiers page-xxx.html et epb.opf.

Je n’ai pas fait cette optimisation car le gain était assez minimes dans mon cas (moins de 1Mo).

Réduire la taille d’un ePub: les polices

Si vous incorporez les polices dans votre ePub, elles sont enregistrés dans le dossier OBS/fonts/.

Vérifiez les polices incorporées, et si elles sont toutes justifiées.

Dans mon cas, j’ai découvert 2 polices inutiles incorporées:

  • « Wingdings »: pour 2 malheureuses puces rondes.
  • « FontAwesome5Pro-Solid-900.otf »: pour 2 petites icônes grasses alors que les autres ne le sont pas

Remplacer ces polices dans votre éditeur d’eBook afin qu’elles ne soient pas présentes à l’exportation.

Réduire la taille d’un ePub: reconstruire le fichier

Pour reconstruire le fichier, il faut suivre correctement et à la lettre le format ePub. Suivez le guide ici: Reconstruire un fichier ePub

Compresser un ePub: comparatif des améliorations

Voici un récapitulatif des gains possibles avec mon fichier de base:

ÉtapePoids du fichiers
Origine160Mo
Optimisation PNG-57Mo
Conversion JPG-100Mo
Conversion JPG
+ Optimisation
-130Mo
Suppression des polices inutiles-3Mo
Suppression des images en doublons-1Mo

Pour mon eBook, j’ai choisi de convertir en JPG, optimiser les images et supprimer les polices inutiles et j’ai finalement obtenu un ePub de 29Mo! YEAH!

Sauvegarde automatique de base de données MySQL: mon script

Une sauvegarde automatique de la base de données MySQL peut sauver! Un piratage de site peut toujours arriver et sans sauvegarde, vous êtes bon pour tout recommencer depuis zéro.

Faire une sauvegarde (un backup) sur le même serveur, c’est un début mais ça ne suffit pas. Si un pirate a accès à votre serveur, il peut facilement tout supprimer, y compris vos sauvegarder. C’est pourquoi il faut conserver vos backups sur un autre support. Tout d’abord sur un autre serveur, puis également sur un support déconnecté d’Internet.

Quelles solutions possibles?

Sauvegarde automatique avec WordPress

Il existe plusieurs plugins WordPress qui fonctionnent très bien. Le plus connu est certainement UpDraftPlus.

Mais les plugins WordPress… faut pas non plus en abuser. Il y a déjà assez de plugins dans tous les sens, lorsque je peux éviter d’en ajouter, j’évite!

Sauvegarde WordPress sans plugin

Pour sauvegarder les articles de WordPress sans plugin et de manière automatique, il faut passer par un script de sauvegarde. Ce script fera appel à MysqlDump pour créer des sauvegardes et Crontab pour le planifier chaque jour.

Sauvegarde automatique avec MysqlDump et Crontab

J’ai mis en place un script qui effectue une sauvegarde automatique de la base de données tous les jours sur un NAS situé chez moi. Tous les 3 mois, je fais une sauvegarde froide, je fais une copie des dernières sauvegarde sur un disque externe. Avec ce process, j’ai une réponse à plusieurs risques:

  • Piratage du site: récupération depuis la sauvegarde de la veille
  • Piratage du site + du serveur de sauvegarde: récupération depuis la sauvegarde d’il y a max 3 mois.

Dans mon cas, le « serveur de sauvegarde » est un Raspberry Pi. C’est lui qui va créer les backups et les enregistrer sur le NAS.

Sécurité de la sauvegarde automatique de base de données

L’idée générale, c’est une tâche ordonnancé par cron qui se connecte automatiquement au serveur, sauvegarde les bases de données et les transfert sur le NAS. Pour limiter les accès du programme de sauvegarde, on va créer un utilisateur spécial pour se connecter en SSH, et un autre pour accéder à la base de donnée.

Créer un utilisateur sans permissions dans Linux

La configuration par défaut suffit. La commande est simple:

ubuntu@serveur: sudo adduser backupuser

Saisissez un mot de passe compliqué, issu d’un générateur de mot de passe. De toutes façons, on ne va jamais l’utiliser puisque la connexion SSH par mot de passe est désactivé sur le serveur web.

Pour permettre la connexion par clef SSH, il faut ajouter notre clef . Copier la clef SSH du serveur de sauvegarde:

ubuntu@pi:~$ cat ~/.ssh/id_rsa.pub

Sur le serveur web, ajouter votre clef pour le nouvel utilisateur:

ubuntu@serveur:~$ sudo -u backupuser bash
backupuser@serveur:~$ mkdir -p ~/.ssh
backupuser@serveur:~$ echo "MACLEFSSH" >> ~/.ssh/authorized_keys

Désormais, le serveur de sauvegarde sait se connecter au serveur web, avec un utilisateur sans permissions. Sans risque donc.

Créer un utilisateur MySQL dédié pour la sauvegarde

De même pour l’utilisateur MySQL (ou MariaDB). On créé un utilisateur n’ayant pour permissions que la lecture (=SELECT).

On se connecte à MariaDB avec les droits root pour créer cet utilisateur:

ubuntu@serveur:~$ sudo mysql
MariaDB [(none)]> GRANT SELECT ON *.* TO 'backupuser'@'localhost' IDENTIFIED BY 'secret-password';

On peut maintenant se connecter avec cet utilisateur pour sauvegarder la base de données: il peut lire toutes les bases de données et ne peut en modifier aucune: parfait!

Script de sauvegarde automatique

Le programme de sauvegarde est piloté par le serveur de sauvegarde (mon Raspberry Pi). Il va se connecter en SSH, exécuter le programme de sauvegarde, rapatrier les fichiers de sauvegarde créés et supprimer ces fichiers du serveur web.

#!/bin/sh

SQL_USER="backupuser"
SQL_PASS="secret-password"
SQL_HOST="localhost"

SSH_USER="backupuser"
SSH_HOST="monServeur"

FILE_PREFIX="backup_db"
FILE_PATH="/media/smb/Backups/"

FILE_DATE=`date +%Y-%m-%d-%H-%M-%S`
TARGET_FILE_PATH="/tmp/backupuser/"

DB_SCRIPT="MYSQL_PWD=$SQL_PASS mysql -h $SQL_HOST -u $SQL_USER -e \"SHOW DATABASES;\" | tr -d \" | \" | grep -v -e Database -e _schema -e mysql"
DB_SAVE="MYSQL_PWD=$SQL_PASS mysqldump -h $SQL_HOST -u $SQL_USER --single-transaction --skip-lock-tables \$DB_NAME > $TARGET_FILE_PATH$FILE_PREFIX.\$DB_NAME.$FILE_DATE.sql"
DB_COMPRESS="gzip $TARGET_FILE_PATH$FILE_PREFIX.\$DB_NAME.$FILE_DATE.sql"

ssh -T $SSH_USER@$SSH_HOST << EOSSH
mkdir -p $TARGET_FILE_PATH
DATABASES=\$($DB_SCRIPT)
for DB_NAME in \$DATABASES; do
	\$($DB_SAVE)
	\$($DB_COMPRESS)
done
EOSSH

# On transfert les données du script client
scp $SSH_USER@$SSH_HOST:$TARGET_FILE_PATH$FILE_PREFIX.*.sql.gz $FILE_PATH

# On supprime le script client et les fichiers temporaires
ssh $SSH_USER@$SSH_HOST "rm $TARGET_FILE_PATH$FILE_PREFIX.*.sql.gz"

Déchiffrons le fonctionnement du script, point par point

1/ La configuration du script

Ici, ce sont les variables qu’il faut modifier pour que le script fonctionne.

  • Nom du serveur Web
  • Utilisateur SSH du serveur Web
  • Nom du serveur SQL
  • Utilisateur SQL
  • Mot de passe SQL
  • Chemin où seront enregistrés les fichiers de sauvegarde
  • Préfixe pour le nom des fichiers de sauvegarde
SQL_USER="backupuser"
SQL_PASS="secret-password"
SQL_HOST="localhost"

SSH_USER="backupuser"
SSH_HOST="monServeur"

FILE_PREFIX="backup_db"
FILE_PATH="/media/smb/Backups/"

2/ Les variables de travail

On stocke la date actuelle qui servira à nommer les fichiers, afin d’avoir des noms fichiers uniques.

Le chemin temporaire de travail peut être modifié. /tmp est généralement stocké en RAM. Si vous avez des grosses bases de données, ça pourrait ralentir le serveur web.

FILE_DATE=`date +%Y-%m-%d-%H-%M-%S`
TARGET_FILE_PATH="/tmp/backupuser/"

Les 3 fonctions à exécuter

On définit les 3 opérations à exécuter:

  • Lire la liste de la base de données
  • Sauvegarder une base de données
  • Compresser un fichier de sauvegarde

Ces fonctions seront exécutés dans un tunnel SSH.

Les options de mysqldump:

  • Single Transaction: la sauvegarde se fera dans une transaction SQL: ça permet de conserver l’intégrité des données sans bloquer la base de données.
  • Skip Lock Tables: pas besoin de vérouiller la base de données pendant le backup puisqu’on l’effectue dans une seule transaction SQL

Je me suis inspiré de cet article intéressant sur les options de mysqldump.

DB_SCRIPT="MYSQL_PWD=$SQL_PASS mysql -h $SQL_HOST -u $SQL_USER -e \"SHOW DATABASES;\" | tr -d \" | \" | grep -v -e Database -e _schema -e mysql"

DB_SAVE="MYSQL_PWD=$SQL_PASS mysqldump -h $SQL_HOST -u $SQL_USER --single-transaction --skip-lock-tables \$DB_NAME > $TARGET_FILE_PATH$FILE_PREFIX.\$DB_NAME.$FILE_DATE.sql"

DB_COMPRESS="gzip $TARGET_FILE_PATH$FILE_PREFIX.\$DB_NAME.$FILE_DATE.sql"

Le tunnel SSH

On ouvre le tunnel SSH et on créer le dossier qui va recevoir nos fichiers temporaires. On sort le liste des bases de données puis on boucle dessus pour créer et compresser une sauvegarde pour chaque base de données

ssh -T $SSH_USER@$SSH_HOST << EOSSH
mkdir -p $TARGET_FILE_PATH
DATABASES=\$($DB_SCRIPT)
for DB_NAME in \$DATABASES; do
	\$($DB_SAVE)
	\$($DB_COMPRESS)
done
EOSSH

Rapatriement des fichiers de sauvegarde

Une simple copie avec SSH de tous les fichiers backups compressés (*.sql.gz) vers notre répertoire de sauvegarde.

scp $SSH_USER@$SSH_HOST:$TARGET_FILE_PATH$FILE_PREFIX.*.sql.gz $FILE_PATH

Nettoyage des fichiers temporaires

Pour ne pas laisser trainer des fichiers inutiles sur le serveur, on supprime tous les fichiers backups compressés de notre répertoire de travail

ssh $SSH_USER@$SSH_HOST "rm $TARGET_FILE_PATH$FILE_PREFIX.*.sql.gz"

Planification de la sauvegarde automatique dans Cron

Il ne reste plus qu’à planifier une sauvegarde automatique de base de données toutes les nuits, et le tour est joué. On ouvre crontab pour un utilisateur standard du serveur de sauvegarde.

ubuntu@pi:~$ crontab -e

Et on ajoute cette ligne:

3 33 * * * /home/ubuntu/Scripts/backup-bdd.sh

Tous les jours, à 3h33, une sauvegarde automatique de la base de données du serveur Web sera effectuée.

Faire taire le message d’accueil SSH

Quand vous utiliserez ce script, il est possible que le message d’accueil SSH vous agace. C’est mon cas.

La solution est très simple, il suffit d’ajouter un fichier .hushlogin dans son répertoire personnel.

backupuser@serveur:~$ touch .hushlogin

Retour sur l’incident Soyouz du 11 octobre 2018

Photo par Bill Ingalls/NASA

Le 11 octobre, le lanceur russe Soyouz devait transporter le cosmonaute russe Alexeï Ovtchinine et l’astronaute américain Nick Hague vers l’ISS, la station spatiale internationale. Depuis 2011, Soyouz est l’unique vaisseau habilité à transporter des hommes vers l’ISS. Un problème au lancement a conduit à l’echec de la mission, l’équipage étant rappatrié sain et sauf dans la capsule de sécurité et laissant l’ISS sans aucun moyen de ravitaillement humain.

Comment Soyouz s’est retrouvé l’unique lanceur pour rejoindre l’ISS

L’ISS n’est pas vraiment internationale, mais surtout américaine, russe, européene, japonaise et canadienne. Depuis le démarrage du programme, les ravitaillements humains sont partagés entre la Russie et les États-Unis, les seuls pays du programme disposant de vaisseaux capables d’emporter des humains dans l’espace. Pour les États-Unis, il s’agit de Navettes Spatiales: Columbia, Challenger, Discovery, Atlantis et Endeavour. Pour la Russie, il s’agit de la fusée Soyouz.

Soyouz est un lanceur un peu ancien mais extremement fiable: elle a volé pour la 1ère fois en 1966! Il y a tout de même eu des modifications mais on reste sur la même conception. Petit point sur la fiabilité: Aucune perte humaine avec Soyouz, plus de 1800 tirs réussi et 3 échecs, dont celui de 2018. Seulement 3 échecs en 52 ans.

De l’autre côté, la navette américaine a volé pour la 1ère fois en 1981. En 1986, Challenger se désintègre au lancement au dessus de l’atlantique avec à bord 7 membres d’équipage. En 2003, Columbia se désintègre au retour, lors de l’entrée dans l’atmosphère, avec à bord 7 membres d’équipage. Ces problèmes de fiabilité ont conduit la NASA à abandonner ses navettes qui ont volés pour la dernière fois en 2011. En tout, les navettes auront effectués 133 missions pour 2 échecs et 14 morts. La Nasa a délégué la conception de fusée a des sociétés commerciales privés qui, encore en 2018, ne sont pas habilitées à transporter des humains: SpaceX, BlueOrigin, United Launch Alliance.

Voilà comment ce bon vieux Soyouz se retrouve, encore en 2018, et depuis 9 ans, comme l’unique moyen de rejoindre l’ISS.

L’incident du 11 octobre 2018

Au décollage, tout va bien. À 2mn45s, le premier étage – les 4 boosters – se sépare. C’est à ce moment que le pilote, Alexeï Ovtchinine annonce à la radio « Problème de lanceurs, deux minutes 45 secondes ».

À ce moment, la mission est abandonnée et la capsule contenant est séparée de la fusée pour retourner sur terre. Ce n’est pas un retour très agréable car il n’est pas du tout optimisé: l’équipage va encaisser jusqu’à 6,7G. Fort heuresement, le cosmonaute et l’astronaute sont récupérés sain et sauf.

Un problème au décollage signifie pas de nouveau vol tant que la cause n’est pas identifiée et corrigée. L’autre problème, c’est que les 3 humains qui peuplent l’ISS doivent rentrer à la fin de l’année – la capsule Soyouz de retour ne peut rester qu’environ 200 jours dans l’espace. Potentiellement, l’ISS pourrait être abandonnée à la fin de l’année…

L’enquête de Roscosmos

L’agence spatiale russe a débuté les investigations dès le 11 octobre. Il n’y a pas de temps à perdre! Rapidement, l’enquête se focalise sur les boosters puisque les problèmes ont débuté à la séparation des boosters.

La vidéo de la séparation des boosters est même publiée sur Twitter et même un novice peut voir qu’il y a un problème. Les 4 boosters sont parfaitement équilibré autour de la fusée et lorsqu’ils se séparent, ils forment une croix, appelée croix de Korolev (l’ingénieur en chef de programme spatiaux de l’Union Soviétique). Là, très clairement, la croix n’y est pas.

L’agence spatiale russe révèle le problème à l’origine de l’incident du 11 octobre

« Un capteur qui surveille la séparation des boosters était mal monté, de 6 degrés ». Le communiqué de presse précise que cette pièce est montée lors de l’assemblage finale sur le cosmodrome de Baïkonour, au Kazakhstan.

6 degrés, c’est pas grand chose. Mais ça a suffit à perturber la séparation du booster qui a ensuite hurté violemment le réservoir principal, ce qui a dévié fortement la fusée de sa trajectoire.

Voilà à quoi tient la conquête spatiale, à peu de chose. Finalement, tout rentre dans l’ordre et le prochain lancement de Soyouz le 16 Novembre (un vol non habité, de ravitaillement) devrait se dérouler sans encombre.

Photo par Bill Ingalls/NASA

[Dev] Test IAB

Publié le
Catégorisé comme Non classé