Creare file PDF/A pronti per l’archiviazione documentale dai documenti di Mago.Net

Questa procedura permette di produrre file in formato PDF/A, idonei per l’archiviazione documentale e la conservazione sostitutiva, a partire dai documenti di Mago.Net ed utilizzando esclusivamente software Open Source.

Software necessario

Altro software utile

L’idea

Mago.Net è in grado di produrre stampe e di inviarle ad una qualsiasi stampante disponibile nel sistema. L’idea è di creare una stampante virtuale di tipo PostScript, intercettare il flusso di dati durante la stampa, analizzarlo con Perl per estrarne i metadati necessari alla corretta indicizzazione del documento (numero, data, tipo di documento, ecc.), quindi passare il flusso a Ghostscript che, tramite opportuni parametri, produrrà il file PDF conforme ai requisiti ISO 19005-1:2005. A tale scopo, dovremo installare e configurare i software elencati sopra, e apportare alcune modifiche ai report di Mago.Net che vogliamo abilitare all’esportazione in PDF/A.

1. Installare Perl

Consiglio di scaricare il pacchetto Perl più idoneo alla propria piattaforma (32 o 64 bit). Durante l’installazione mantenere i valori proposti per default (installazione completa in C:\Perl\ per sistemi a 32 bit o C:\Perl64\ per sistemi a 64 bit).

2. Installare Ghostscript

Anche Ghostscript viene distribuito nelle due versioni a 32 e 64 bit: scegliere la più idonea. Anche in questo caso, consiglio di mantenere le impostazioni di default proposte dall’installer.

3. Installare Multi File Port Monitor

L’installazione di Multi File Port Monitor non presenta difficoltà: installare mantenendo le impostazioni di default. L’installer determina automaticamente la versione di sistema operativo in uso (32 o 64 bit).

4. Creare la directory di lavoro e lo script Perl

Per gli scopi di questo tutorial creiamo una directory in C:\ che chiameremo pdfa. Al suo interno creiamo un file di testo e rinominiamolo pdfa.pl (ATTENZIONE: se è stata abilitata l’opzione “nascondi le estensioni per i tipi di file conosciuti”, potreste aver creato un file con doppia estensione: pdfa.pl.txt. Consiglio di disabilitare definitivamente questa opzione che sfiora la demenza, e che per default è abilitata in tutti i sistemi Microsoft, persino nella fascia server). Editiamo lo script usando l’editor preferito (il mio è senza dubbio Notepad++). ATTENZIONE: NON usare Microsoft Word, LibreOffice Writer o simili, che applicano formattazione al testo inserito. Il file deve essere puro ASCII. Ecco il listato:

# script di redirect fatture e note di credito su file PDF/A
# by Lorenzo Monti
#
# rel 0.2 del 11-06-2012
#
# Principio di funzionamento:
# i metadati necessari alla creazione del file PDF vengono inseriti nel flusso
# PostScript, tramite dei testi di colore bianco e con un apposito prefisso
# e suffisso che ne permettono il riconoscimento (§§§, carattere ASCII dec 167 oct 247).
# Questi tag vengono intercettati dal presente script perl, ma non compaiono
# sul documento, essendo di colore bianco.

use strict;
use File::Path qw(make_path);
use File::Basename qw(dirname);
use File::Spec qw(rel2abs);

# modificare secondo la propria configurazione
use constant GS => "C:\\Program Files\\gs\\gs9.05\\bin\\gswin64c.exe";

# la seguente routine sostituisce con degli underscore
# tutti i caratteri non validi per un nome di file
sub sanitize {
	# caratteri non validi
	$_[0] =~ s/[\\\/*?"<>|:]/_/g;
	# strip extra spazi
	$_[0] =~ s/^[[:space:]]*//g;
	$_[0] =~ s/[[:space:]]*$//g;
}

# variabili locali
my ($line, $file, %params, $year, $path, $gsparams, $title);

# devo ricevere il nome del file temporaneo sulla command line
die 'Sintassi: ' . __FILE__ . ' <tempfile>'
	unless (@ARGV > 0);

# apro il file temporaneo in scrittura
open(HFILE, '>', $ARGV[0])
	or die $!;

# i dati PostScript arrivano da standard input
while ($line = <STDIN>) {
	# cerca i parametri all'interno del flusso PostScript tramite una espressione regolare.
	# i parametri sono passati nella forma:
	# (\247\247\247NOME:VALORE\247\247\247)
	# vi possono essere spazi immediatamente vicino alle parentesi di apertura e chiusura
	if ($line =~ m/\([[:blank:]]*(?:\\247){3}([[:alpha:]]+):((?:[^\\]|\\(?!247))+)(?:\\247){3}[[:blank:]]*\)/) {
		# il primo match è il nome del parametro, il secondo match (dopo i due punti) è il valore
		$params{$1} = $2;
	}

	# scrivo la riga sul file temporaneo
	print HFILE $line;
}

close(HFILE);

# abbiamo trovato i parametri che cercavamo?
die 'Impossibile trovare alcuni parametri necessari all\'interno del flusso PostScript!'
	unless (defined($params{'TIPO'}) &&
		defined($params{'DOCNO'}) &&
		defined($params{'DATA'}));

# il titolo del PDF - obbligatorio per file conformi alla specifica PDF/A
$title = "$params{'TIPO'} numero $params{'DOCNO'} del $params{'DATA'}";

# eliminiamo caratteri non validi per il nome file
sanitize($params{'TIPO'});
sanitize($params{'DOCNO'});
sanitize($params{'DATA'});

# componiamo il nome del file PDF
$year = substr($params{'DATA'}, 6, 4);
$path = dirname(File::Spec->rel2abs(__FILE__)) . "\\files\\$year\\$params{'TIPO'}";
$file = "$path\\$params{'DOCNO'}-$params{'DATA'}.pdf";

# assicuriamoci che il path esiste
unless (-d $path) {
	make_path($path)
		or die 'Impossibile creare la directory di output!';
}

#
# avvio del Ghostscript
#

# parametri tarati per la produzione di un file conforme PDF/A
$gsparams = "-dPDFA -dBATCH -dNOPAUSE -dUseCIEColor -dSAFER -dQUIET " .
	"-sDEVICE=pdfwrite -dPDFSETTINGS=/prepress -dAutoRotatePages=/PageByPage -r600 " .
	"-sOutputFile=\"$file\" -";

# apriamo una pipe verso Ghostscript
open(HGS, "| \"" . GS . "\" $gsparams")
	or die $!;

# riapriamo il file PostScript temporaneo in lettura
open(HFILE, '<', $ARGV[0])
    or die $!;

# come prima cosa iniettiamo il titolo del PDF/A
print HGS <<__EOT__;
%!
[ /Title ($title)
  /DOCINFO pdfmark
__EOT__

# passiamo a Ghostscript il contenuto del file PostScript temporaneo
while ($line = <HFILE>) {
    print HGS $line;
}

# chiudiamo i vari handle
close(HFILE)
	or die $!;
close(HGS)
	or die $!;

# cancelliamo il file temporaneo
unlink($ARGV[0]);

__END__

Cliccare qui per scaricare il listato. L’unica modifica che potrebbe rendersi necessaria, per ora, è alla seguente riga:

use constant GS => "C:\\Program Files\\gs\\gs9.05\\bin\\gswin64c.exe";

Su sistemi a 32 bit, l’eseguibile Ghostscript si chiama gswin32c.exe. Inoltre bisogna controllare che il percorso dell’eseguibile corrisponda a quello dove effettivamente è stato installato Ghostscript sul proprio sistema. Ricordarsi di raddoppiare i backslash poiché, nelle stringhe del Perl, il backslash è usato come carattere di escape. Salvare, et voilà: lo script è pronto:
La directory di lavoro con lo script Perl
Esso riceve il nome del file PostScript temporaneo sulla command line, e il flusso PostScript dallo standard input; lo analizza in cerca dei parametri che gli servono per comporre il nome del file ed i metadati, ed infine lo passa a Ghostscript.

5. Configurare la stampante PDF/A

Avviare la procedura di installazione per una nuova stampante di Windows. Dovremo aggiungere una stampante locale:
Finestra di dialogo di aggiunta di una nuova stampante
Scegliere di creare una nuova porta, e come tipo selezionare “Multi File Port Monitor”:
Scelta o creazione di una porta per la stampante
Forniamo un nome alla nuova porta per la stampante (io ho usato il nome “PDF/A:”):
Nome della nuova porta
Quindi inseriamo i vari parametri per la porta. Dobbiamo dire a Multi File Port Monitor di generare dei nomi di file temporanei in C:\pdfa\temp\, numerandoli automaticamente, di passare i dati attraverso lo standard input (pipe) allo script che abbiamo creato poco fa, e di passargli inoltre il nome del file temporaneo sulla command line. Ecco come:
Parametri della nuova porta

  • Percorso per l’output: C:\pdfa\temp
  • Formato nome file: %i.ps
  • Comando utente: C:\Perl64\bin\perl.exe C:\pdfa\pdfa.pl “%f”
  • Esegui da: C:\pdfa
  • Usa pipe per inviare i dati al comando utente:

Confermare. Viene quindi chiesto di fornire il driver della stampante. Useremo il driver PostScript fornito con Ghostscript, che si trova nella sottodirectory lib della directory di installazione di Ghostscript. Cliccare su “Disco driver…”, quindi su “Sfoglia…”, posizionarsi nella directory descritta poco fa (nel mio caso: C:\Program Files\gs\gs9.05\lib), scegliere il file ghostpdf.inf e dare ok. Viene mostrato un modello di stampante denominato “Ghostscript PDF”: sceglierlo e premere “Avanti”:
Driver Ghostscript
Windows potrebbe avvertire che il driver non è firmato, e chiedere consenso all’installazione: dare il consenso e proseguire. Chiamiamo la nostra stampante PDF/A (ma va?) e disabilitiamo la condivisione (per ora). NON bisogna stampare la pagina di prova, né scegliere questa stampante come predefinita.

6. Modificare i fincati di Mago.Net

A questo punto dobbiamo modificare i fincati di Mago.Net che vogliamo abilitare all’esportazione in PDF/A. La modifica consta essenzialmente nell’inserimento di speciali tag, delimitati da una speciale sequenza di caratteri perché lo script Perl li possa intercettare. Io ho scelto la sequenza “§§§” perché mi sembra molto improbabile che possa comparire in altre parti del testo. Il carattere § è l’ASCII 167 (ottale 247).
Dunque apriamo, ad esempio, la form Fatture, scegliamo una fattura e lanciamo l’anteprima di stampa. Entriamo in modifica del report.
Dobbiamo aggiungere tre campi funzione, per passare al Perl rispettivamente:

  • il tipo documento
  • il numero documento
  • la data documento

Creiamo il primo, denominiamolo PDFA_DocNo e inseriamo l’espressione:

"§§§DOCNO:" + w_DocumentNumber + "§§§"

(Ovviamente il nome della variabile che contiene il numero del documento, nel vostro report potrebbe avere un nome diverso da w_DocumentNumber). Piazziamo il campo in un’area libera del report.
Con lo stesso criterio, creiamo gli altri due campi espressione. Per prima cosa il campo PDFA_Tipo, contenente l’espressione:

"§§§TIPO:" + Format(w_DocumentType) + "§§§"

Quindi, il campo PDFA_Data, contenente l’espressione:

"§§§DATA:" + Format(w_DocumentDate) + "§§§"

Eliminiamo i bordi. Rieseguiamo il report con F9. Ecco il nostro report quasi finito (i campi appena creati sono visibili in alto a sinistra):
Mago.Net: report in lavorazione
Manca un ultimo tocco. Vogliamo che i campi appena definiti giungano fino al nostro script Perl attraverso il PostScript, ma non vogliamo che appaiano sulla stampa. Il trucco è colorarli di bianco. Selezioniamoli uno alla volta, scegliamo l’opzione “Colori…”, ed assegniamo un bel bianco al colore del “Valore”. Salviamo ed usciamo dalla modalità modifica. I nostri parametri ci sono, ma non si vedono:
Mago.Net: il report finito
Il listato completo del report è disponibile per il download.

7. Test

Se abbiamo fatto tutto correttamente, dovremmo poter stampare la nostra fattura sulla stampante PDF/A, ed ottenere come risultato un file denominato

C:\pdfa\files\<anno-documento>\<tipo-documento>\<numero-documento>_<data-documento>.pdf

PDF/A: risultato
Aprendolo, Adobe Reader ci dirà che si tratta di un documento conforme allo standard PDF/A e che quindi le modifiche sono interdette. Esaminando le proprietà del documento, possiamo notare che anche il titolo è stato forgiato dallo script Perl tramite i metadati passati dal PostScript:
Proprietà del PDF creato
Naturalmente questo è solo un esercizio per illustrare i concetti e la tecnica usata. Per un programmatore creativo non dovrebbe essere un problema estendere il meccanismo (includendo, ad esempio, tag aggiuntivi per arricchire i metadati incorporati nel PDF, oppure automatizzando l’archiviazione in un software DMS o in un blob di database).

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *

*