Rimuovere oggetti da PDF con Inkscape via terminale
Ci è capitato in questi giorni di mandare in stampa presso un servizio specializzato online un PDF con alcuni appunti. Così com’era, però, il file non veniva accettato perché presentava uno sfondo giallo chiaro su tutte le pagine. O, per meglio dire, la stampa sarebbe costata di più. Poiché non posso pubblicare lo screenshot di una pagina reale, vi basti questa ricostruzione di fantasia che però rende l’idea di cosa avevamo davanti:

Figura 1. Un esempio di pagina con lo sfondo giallo chiaro da rimuovere.
Il PDF è composto da 358 pagine: come fare per rimuovere quello sfondo colorato, lasciando intatto tutto il resto?
La prima soluzione che mi è venuta in mente era di estrarre singolarmente le pagine dal PDF e darle in pasto a ImageMagick, dicendogli di applicare una correzione dei livelli di colore in modo da eliminare lo sfondo. Ma abbiamo scartato subito questa ipotesi perché il file risultante, composto interamente da immagini raster, sarebbe stato enorme.
Mi viene un’idea. Se i file sono vettoriali (cosa che ancora non sapevamo) e se
lo sfondo giallo chiaro sta su un suo livello separato o, per meglio dire, è un
oggetto separato da tutti gli altri, forse possiamo eliminarlo. Apriamo una
pagina con Inkscape e scopriamo che i file sono effettivamente vettoriali e che
lo sfondo è un oggetto separato, chiamato path1 (vedi fig. 2). Ma non solo:
scopriamo anche che i quadretti (che avremmo desiderato pure togliere) stanno
tutti assieme in un gruppo chiamato g27514, quindi un facile obiettivo per la
rimozione di massa.

Figura 2. I due oggetti di pagina 62, indicati dalla freccia, contenenti lo sfondo e i quadretti. In Inkscape è attualmente aperto un file PDF composto da due pagine.
Questi nomi di oggetti, per ovvie ragioni, non vengono mantenuti se apriamo con
Inkscape più pagine del PDF. Nella figura 2, ad esempio,
abbiamo aperto con Inkscape due pagine, cioè la 62 e la 63: come si vede
dall’immagine, lo sfondo della prima pagina (la 62) si chiama path1, così come
il gruppo dei quadretti si chiama g27514, ma non così dalla seconda pagina (la
63, vedi fig. 3) in poi, perché questi nomi sono, nel nostro caso, anche degli
ID che devono identificare univocamente un oggetto.

Figura 3. I due stessi oggetti ma di pagina 63, con nomi diversi rispetto alla pagina precedente.
Proviamo quindi a dividere il file PDF di 358 pagine in tanti file quante sono le sue pagine e a verificare se gli ID dello sfondo e del gruppo vengono sempre mantenuti: sì, vengono mantenuti! A qusto punto siamo pronti per mettere all’opera Inkscape, ma non per via grafica, che comporterebbe un sacco di tempo e un incredibile mal di testa, ma da terminale.
Estrazione delle pagine dal pdf
La prima operazione è, quindi, quella di suddividere l’intero PDF in 358 file, cioè un file per ogni pagina:
pdftk input.pdf burst
Rimozione degli oggetti
Mettiamo ora mano alla creazione di uno script Bash semplicissimo che processi
tutti i PDF di una directory mediante Inkscape. Ci siamo
dovuti spulciare il manuale di Inkscape (man inkscape) per capire quali
comandi (che lui chiama actions) potevano fare al caso nostro. Quello che è
venuto fuori è questo script:
1#!/bin/bash
2# Script per rimuovere oggetti da un PDF tramite ID.
3
4OBJECT_TO_REMOVE1=path1
5OBJECT_TO_REMOVE2=g27514
6
7mkdir -p modified
8
9for pdf in *.pdf; do
10 echo "Processo: $pdf"
11
12 inkscape --actions="select-by-id:$OBJECT_TO_REMOVE1;
13 delete-selection;
14 select-by-id:$OBJECT_TO_REMOVE2;
15 delete-selection;
16 export-filename:modified/$pdf;
17 export-do" "$pdf" > /dev/null 2>&1
18
19 echo "Completato: modified/$pdf"
20done
Dopo aver definito gli ID dei due oggetti da rimuovere
(righe 4 e 5), lo script, per ogni PDF che trova, esegue
il comando inkscape con alcune azioni in sequenza:
- seleziona il primo oggetto per ID;
- elimina l’oggetto selezionato;
- seleziona il secondo oggetto per ID;
- elimina l’oggetto selezionato;
- imposta il nome del file da esportare;
- esegue l’esportazione.
Infine, abbiamo anche reindirizzato l’output su /dev/null per evitare di
vedere un sacco di righe inutili al nostro scopo e, una volta salvato il file,
stampa a video il messaggio di conclusione per quel singolo file.
Questo è il risultato di una pagina dopo l’esecuzione dello script:

Figura 4. Un esempio di pagina senza lo sfondo giallo né i quadretti.
Riunione finale delle pagine in un unico file
Per riunire, alla fine, tutti i PDF basta dare:
pdftk modified/*.pdf cat output pdf_finale.pdf
Con poche righe di Bash e gli strumenti giusti, abbiamo risolto un problema concreto in poco tempo: è stata necessaria un’ora per il mio vecchissimo PC per fare questo lavoro. Il terminale, ancora una volta, si dimostra uno strumento insostituibile per chi lavora con tanti file. E ancora, dopo vent’anni d’uso di Linux, riesco a meravigliarmi per quello che abbiamo a disposizione!