Questo sito utilizza i cookie per migliorare servizi ed esperienza del lettore. Se decidi di continuare la navigazione consideriamo che accetti il loro uso . Per e informazioni sulla Privacy leggere la Google Policies Privacy

Se continui nella navigazione accetti il loro uso. OK
Visualizzazione post con etichetta PDF. Mostra tutti i post
Visualizzazione post con etichetta PDF. Mostra tutti i post

martedì 10 agosto 2010

Aggiungere un watermark trasparente a un PDF

Torniamo a parlare di PDF e della libreria iTextSharp che mi sta esaltando sempre di più.
Vedremo come applicare un watermark trasparente con un testo a piacere su tutte le pagine di un pdf esistente.
Iniziamo a vedere come aprire un pdf:
MemoryStream m = new MemoryStream();
PdfReader read = new PdfReader(@"c:\sample.pdf");
PdfStamper st = new PdfStamper(read, m);
Il MemoryStream conterrà in nuovo pdf modificato, il PdfReader si occuperà di aprere il flusso e il PdfStamper si occuparà di modificare il pdf e salvarlo nello strem.
Vediamo ora di analizzare il problema della stampa del testo che ovviamente vorremo vederlo ruotato lungo la diagonale del foglio. Quindi dobbiamo intanto calcolare l'angolo di rotazione del testo:
iTextSharp.text.Rectangle r = read.GetPageSize(1);
double ipo = Math.Sqrt(r.Width * r.Width + r.Height * r.Height);
double angolo = Math.Acos(r.Width / ipo) * 180 / Math.PI;
Premetto che la trigonometria non è il mio forte, ma avendo la base e l'altezza del triangolo, quella dovrebbe essere la formula corretta per calcolare l'angolo.
Ora vediamo di creare un font con cui scrivere nel nostro pdf e di impostare una dimensione e un colore con cui scrivere:
//Font standard (HELVETICA)
BaseFont bf = BaseFont.CreateFont(BaseFont.HELVETICA, BaseFont.WINANSI, BaseFont.EMBEDDED);

//Acquisisco un 'livello' sopra al contenuto del pdf
PdfContentByte content = st.GetOverContent(1);

//Inizio a scrivere un testo, imposto size e colore
content.BeginText();
content.SetFontAndSize(bf, 120);
content.SetRGBColorFill(100, 100, 100);

//Disegno un testoa allineato al centro e ruotato
content.ShowTextAligned(Element.ALIGN_CENTER, "RESERVED", r.Width / 2, r.Height / 2, (float)angolo);
content.EndText();
Aggiungiamo una finezza ulteriore: la trasparenza del testo. La otteniamo creando uno GraphicState con:
PdfGState trasparenza = new PdfGState();
trasparenza.FillOpacity = 0.3f;
Dobbiamo ricordarci di impostare anche lo stato della grafica al contenuto.
Vediamo il codice completo (dovevamo anche scrivere su tutte le pagine!):
MemoryStream m = new MemoryStream();
PdfReader read = new PdfReader(@"c:\sample.pdf");
PdfStamper st = new PdfStamper(read, m);


PdfGState trasparenza = new PdfGState();
trasparenza.FillOpacity = 0.3f;

BaseFont bf = BaseFont.CreateFont(BaseFont.HELVETICA, BaseFont.WINANSI, BaseFont.EMBEDDED);

//Le pagine vengono conteggiate a partire da 1
for (int i = 1; i <= read.NumberOfPages; i++) {
    iTextSharp.text.Rectangle r = read.GetPageSize(i);
    double ipo = Math.Sqrt(r.Width * r.Width + r.Height * r.Height);
    double angolo = Math.Acos(r.Width / ipo) * 180 / Math.PI;

    PdfContentByte content = st.GetOverContent(i);

    content.SaveState();
    content.SetGState(trasparenza);
    content.BeginText();
    content.SetFontAndSize(bf, 120);
    content.SetRGBColorFill(100, 100, 100);


    content.ShowTextAligned(Element.ALIGN_CENTER, "RESERVED", r.Width / 2, r.Height / 2, (float)angolo);
    content.EndText();
    content.RestoreState();
}

st.Close();
File.WriteAllBytes(@"c:\result.pdf", m.ToArray());

lunedì 9 agosto 2010

Inserimento di un codice a barre in un report RDLC

I report RDLC sono un potente mezzo messo a disposizione agli sviluppatori .NET per la creazione di report, potrebbero non avere l'eleganza di strumenti professionali, ma si distinguono per semplicità d'uso e facilità di installazione. Spesso ci si trova a dover inserire immagini al suo interno e ci si accorge che in fase di generazione di un PDF l'immagine stessa è inserita come parte dello stream del file. Fantastico penso io, questo vuol dire che se per esempio devo creare un bel report con un codice a barre stampigliato sopra mi basta indicarlo come font da usare per un'etichetta di testo e il gioco è fatto, durante il packing del file verrà inserita la risorsa del font (cosa che il formato pdf permette perfettamente) e anche se porto il mio pdf su un computer in cui non c'è il font indicato (o, ancor meglio, lo renderizzo da un'applicazione ASP.NET e lo faccio scaricare a chiunque), esso verrà comunque renderizzato senza problemi. E qui il mio sogno si infrange. Il font NON viene inserito come risorsa ma solo come riferimento, di conseguenza se nel mio sistema non c'è installato quel determinato font leggerò una serie senza senso di numeri e lettere.
A questo punto ho cominciato a cercare una libreria che mi permettesse di aprire un file pdf esistente (il file generato dal mio motore di reportistica) e modificarlo per inserire 'a mano' il codice a barre.
Nei miei pellegrinaggi mi sono imbattuto in una libreria opensource iTextSharp che è il porting .NET della potente libreria iText di java.
La mia idea iniziale era quella di andare ad includere il file ttf come risorsa all'interno del pdf, idea che poi è naufragata per la mia scarsa conoscenza della libreria (se qualcuno è riuscito a fare questo, può postare un commento sul blog nel quale può spiegare la tecnica a tutti o deridermi!).
Alla fine mi sono arreso a una soluzione paliativa, ma comunque funzionante. La libreria iTextSharp contiene svariate classi per la generazione di codici a barre, quindi non mi serviva altro che utilizzarle per modificare il mio file.
Partiamo con i passi base: prendere lo stream del nostro file pdf e renderlo modificabile con iTextSharp:
MemoryStream m = new MemoryStream();
PdfReader r = new PdfReader(pdfContent);
PdfStamper pdf = new PdfStamper(r, m);
Lo strem iniziale conterrà il file finale con la modifica, il PdfReader permette di leggere il flusso stream del file (pdfContent è un byte[]) e PdfStamper permette di prendere il file letto dal reader, eseguire delle modifice e scrivere il nuovo contenuto nel MemoryStream.
A questo punto dobbiamo andare a aprire una pagina del pdf (alla fine inseriremo il codice a barre su ogni pagina), creare una classe che ci permetterà di controllare il codice a barre, stampigliarlo sopra e salvare il tutto.
for (int i = 1; i <= r.NumberOfPages; i++){
   //Craezione della classe per la generazione del codice a barre
   Barcode128 b = new Barcode128();
   b.Code = '1234656789ABCDE'
   b.StartStopText = true;
   b.GenerateChecksum = false;
   b.Extended = true;
   b.BarHeight = 30;

   //Apertura della pagina
   PdfContentByte cb = pdf.GetOverContent(i);
   iTextSharp.text.Image img = b.CreateImageWithBarcode(cb, null, null);

   //Aggiunta in una posizione fissa del codice a barre
   img.SetAbsolutePosition(200, 20);
   cb.AddImage(img);
}
pdf.Close();

Response.Clear();
Response.AddHeader("content-disposition", "attachment;filename=" + "PDF.pdf");
Response.Charset = "";
Response.ContentType = "application/pdf";
Response.BinaryWrite(m.ToArray());
Response.Flush();
Response.End();
L'unico difetto di questa tecnica è la posizione assoluta del codice a barre. Ma con un pochino di fantasia possiamo andare a cercare qualche elemento sempre presente nel pdf e a leggere la sua posizione, quindi impostare il left e il top in base a questo valore. Ma questa è un'altra storia.