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.

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.

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.

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.

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!