martedì 26 giugno 2012

Come creare PDF con Java e iText

Introduzione

iText è una libreria Java originariamente creata da Bruno Lowagie che permette di creare, leggere e manipolare PDF.
Il tutorial che segue spiegherà come creare file PDF con iText. Si richiede che il lettore conosca le basi di Java e di Eclipse.

iText ha una struttura gerarchica. L'unità di testo più piccola è il "Chunk", di cui è possibile specificare il font. La "Phrase" è l'insieme di più "Chunk" e permette di definire lo spazio tra le linee di testo. "Paragraph" è una sottoclasse di "Phrase" e permette di definire maggiori attributi, come i margini. La classe "Anchor" è una sottoclasse di "Paragraph" e permette di creare collegamenti ipertestuali nel PDF generato.

Installazione

Scaricare iText da http://sourceforge.net/projects/itext/. In Eclipse creare un nuovo progetto Java e chiamarlo "iTextTest". Creare all'interno del progetto la cartella "lib" e aggiungere al suo interno il file itextpdf-5.3.0.jar (il numero di versione potrebbe essere diverso) contenuto nell'archivio scaricato, quindi aggiungere la libreria al classpath del proprio progetto.

Creare un PDF

Creare la classe che segue. Il codice dovrebbe essere abbastanza comprensibile grazie ai commenti inseriti. Per esempi più complessi si rimanda al sito ufficiale di iText.

import java.io.FileOutputStream;
import java.util.Date;

import com.itextpdf.text.Anchor;
import com.itextpdf.text.BadElementException;
import com.itextpdf.text.BaseColor;
import com.itextpdf.text.Chapter;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Element;
import com.itextpdf.text.Font;
import com.itextpdf.text.List;
import com.itextpdf.text.ListItem;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.Phrase;
import com.itextpdf.text.Section;
import com.itextpdf.text.pdf.PdfPCell;
import com.itextpdf.text.pdf.PdfPTable;
import com.itextpdf.text.pdf.PdfWriter;


public class Test {
 private static String FILE = "C:/Test.pdf";
 private static Font bigFont  = new Font(Font.FontFamily.TIMES_ROMAN, 18,  Font.BOLD);
 private static Font redFont  = new Font(Font.FontFamily.TIMES_ROMAN, 12,  Font.NORMAL, BaseColor.RED);
 private static Font subFont  = new Font(Font.FontFamily.TIMES_ROMAN, 16,  Font.BOLD);
 private static Font smallBold  = new Font(Font.FontFamily.TIMES_ROMAN, 12,  Font.BOLD);

 public static void main(String[] args) {
  try {
   Document document = new Document();
   PdfWriter.getInstance(document, new FileOutputStream(FILE));
   document.open();
   aggiungiMetaDati(document);
   aggiungiPrefazione(document);
   aggiungiContenuto(document);
   document.close();
  } catch (Exception e) {
   e.printStackTrace();
  }
 }
 
 /* iText permette di aggiungere metadati al pdf che possono essere 
  * visualizzati in Adobe Reader da File -> Proprietà */
 private static void aggiungiMetaDati(Document document) {
  document.addTitle("Il mio primo PDF");
  document.addSubject("Uso di iText");
  document.addKeywords("Java, PDF, iText");
  document.addAuthor("Mario Rossi");
  document.addCreator("Luigi Bianchi");
 }

 private static void aggiungiPrefazione(Document document) throws DocumentException {
  Paragraph prefazione = new Paragraph();
  
  // Aggiungiamo una linea vuota
  aggiungiLineaVuota(prefazione, 1);
  
  // Aggiungiamo il titolo
  prefazione.add(new Paragraph("Titolo del documento", bigFont));

  aggiungiLineaVuota(prefazione, 1);
  
  // Questa linea scrive "Documento generato da: nome utente, data"
  prefazione.add(new Paragraph("Documento generato da: " + System.getProperty("user.name") + ", " + new Date(), smallBold));
  
  aggiungiLineaVuota(prefazione, 3);
  
  prefazione.add(new Paragraph("Generato da iText", smallBold));

  aggiungiLineaVuota(prefazione, 3);
  
  prefazione.add(new Paragraph("Generato da iText", redFont));

  aggiungiLineaVuota(prefazione, 3);
  
  Anchor anchor = new Anchor("Questo è un link");
  anchor.setName("LINK");
  anchor.setReference("http://www.lowagie.com");
  prefazione.add(anchor);

  // Aggiunta al documento
  document.add(prefazione);
  
  // Nuova pagina
  document.newPage();
 }

 private static void aggiungiContenuto(Document document) throws DocumentException {

  // Il secondo parametro è il numero di capitolo
  Chapter chapter = new Chapter(new Paragraph("Primo Capitolo", bigFont), 1);

  Paragraph sectionParagraph = new Paragraph("Sezione 1", subFont);
  Section section = chapter.addSection(sectionParagraph);
  section.add(new Paragraph("Paragrafo 1"));

  sectionParagraph = new Paragraph("Sezione 2", subFont);
  section = chapter.addSection(sectionParagraph);
  section.add(new Paragraph("Paragrafo 1"));
  section.add(new Paragraph("Paragrafo 2"));
  section.add(new Paragraph("Paragrafo 3"));

  // Aggiungiamo una lista
  creaLista(section);
  
  Paragraph paragraph = new Paragraph();
  aggiungiLineaVuota(paragraph, 2);
  section.add(paragraph);

  // Aggiungiamo una tabella
  creaTabella(section);

  // Aggiunta al documento
  document.add(chapter);

  // Prossimo capitolo

  // Il secondo parametro è il numero di capitolo
  chapter = new Chapter(new Paragraph("Secondo Capitolo", bigFont), 2);

  sectionParagraph = new Paragraph("Sezione 1", subFont);
  section = chapter.addSection(sectionParagraph);
  section.add(new Paragraph("Paragrafo 1"));

  // Aggiunta al documento
  document.add(chapter);
 }

 private static void creaTabella(Section section) throws BadElementException {
  PdfPTable tabella = new PdfPTable(3);

  // tabella.setBorderColor(BaseColor.GRAY);
  // tabella.setPadding(4);
  // tabella.setSpacing(4);
  // tabella.setBorderWidth(1);

  PdfPCell c1 = new PdfPCell(new Phrase("Titolo 1"));
  c1.setHorizontalAlignment(Element.ALIGN_CENTER);
  c1.setGrayFill(0.8f);
  tabella.addCell(c1);

  c1 = new PdfPCell(new Phrase("Titolo 2"));
  c1.setHorizontalAlignment(Element.ALIGN_CENTER);
  c1.setGrayFill(0.8f);
  tabella.addCell(c1);

  c1 = new PdfPCell(new Phrase("Titolo 3"));
  c1.setHorizontalAlignment(Element.ALIGN_CENTER);
  c1.setGrayFill(0.8f);
  tabella.addCell(c1);
  tabella.setHeaderRows(1);

  tabella.addCell("1.0");
  tabella.addCell("1.1");
  tabella.addCell("1.2");
  tabella.addCell("2.1");
  tabella.addCell("2.2");
  tabella.addCell("2.3");

  section.add(tabella);

 }

 private static void creaLista(Section section) {
  List list = new List(true, false, 10);
  list.add(new ListItem("Punto primo"));
  list.add(new ListItem("Punto secondo"));
  list.add(new ListItem("Punto terzo"));
  section.add(list);
 }

 private static void aggiungiLineaVuota(Paragraph paragraph, int number) {
  for (int i = 0; i < number; i++) {
   paragraph.add(new Paragraph(" "));
  }
 }
}


Formattare il testo

La classe Paragraph permette di specificare l'allineamento e l'indentazione. Per questo esempio creare il file Test2.java come segue:

import java.io.FileOutputStream;

import com.itextpdf.text.Document;
import com.itextpdf.text.Element;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.pdf.PdfWriter;

public class Test2 {
 private static String FILE = "C:/Test2.pdf";

 public static void main(String[] args) {
  try {
   Document document = new Document();
   PdfWriter.getInstance(document, new FileOutputStream(FILE));
   document.open();
   // Destra
   Paragraph paragraph = new Paragraph("Questo paragrafo è allineato a destra");
   paragraph.setAlignment(Element.ALIGN_RIGHT);
   document.add(paragraph);
   // Centro
   paragraph = new Paragraph("Questo paragrafo è centrato");
   paragraph.setAlignment(Element.ALIGN_CENTER);
   document.add(paragraph);
   // Sinistra
   paragraph = new Paragraph("Questo paragrafo è allineato a sinistra");
   paragraph.setAlignment(Element.ALIGN_LEFT);
   document.add(paragraph);
   // Sinistra con indentazione
   paragraph = new Paragraph("Questo paragrafo è allineato a sinistra con indentazione");
   paragraph.setAlignment(Element.ALIGN_LEFT);
   paragraph.setIndentationLeft(50);
   document.add(paragraph);

   document.close();
  } catch (Exception e) {
   e.printStackTrace();
  }
 }

}


Leggere un PDF esistente

iText permette di generare PDF che includono PDF già esistenti. L'esempio che segue creerà un PDF che contiene la pagina 2 del primo esempio (Test.pdf) e in più aggiungerà del contenuto in una seconda pagina.

import java.io.FileOutputStream;
import java.io.IOException;

import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Image;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.pdf.PdfImportedPage;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfWriter;

public class Test3 {
 private static String INPUTFILE  = "C:/Test.pdf";
 private static String OUTPUTFILE  = "C:/Test3.pdf";

 public static void main(String[] args) throws DocumentException, IOException {
  Document document = new Document();

  PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(OUTPUTFILE));
  document.open();
  PdfReader reader = new PdfReader(INPUTFILE);
  
  //Aggiunta pagina 2
  PdfImportedPage page = writer.getImportedPage(reader, 2);
  Image instance = Image.getInstance(page);
  document.add(instance);
  
  //Inserimento di contenuto aggiuntivo
  Paragraph newParagraph = new Paragraph("Contenuto aggiuntivo");
  document.add(newParagraph);
  
  document.close();

 }

}


Sorgenti dell'esempio

È possibile scaricare il progetto Eclipse contenente i sorgenti di questi esempi da questo link.

Grazie e spero questa piccola guida torni utile.

venerdì 22 giugno 2012

SMS Gateway in Java


Per il mio ultimo progetto ho avuto la necessità di inviare degli SMS di notifica dalla mia applicazione Java. Per poter effettuare operazioni di questo tipo è necessario utilizzare un gateway SMS che permetta di inviare gli SMS attraverso codice Java.

Prima di tutto è necessario scegliere da chi servirci.
Riporto di seguito i servizi che ho valutato; ci tengo a precisare che l'elenco non è affatto esaustivo e le informazioni sono quelle alla data in cui vi scrivo e potrebbero quindi essere ad oggi obsolete.

OVH

OVH, il gigante dell'hosting francese permette l'invio di SMS attraverso una web API di tipo SOAP.
Ho personalmente avuto difficoltà ad utilizzare la web API nel mio software Java, anche perché pur essendo presenti diversi esempi di invocazione della API nei linguaggi più comuni, non ve ne sono per Java. Un altro punto a sfavore è che non sono riuscito ad avere informazioni sufficienti sull'affidabilità del servizio.

Europ SMS

Europ SMS è un servizio che dichiara di avere il costo per SMS "più basso d'Europa" pur rimanendo affidabile. Sembra non sia disponibile una libreria specifica per Java, ma sia possibile effettuare l'invio con appositi Web Service. Io non ho avuto modo di provarlo, ma vi consiglio di farlo e magari di farci sapere com'è andata.

SMS Trend

SMS Trend è il servizio che mi è piaciuto di più, ecco perché:

  • Tre possibilità di scelta:
    • SMS Silver: SMS di bassa qualità senza garanzia di consegna e mittente fisso e inviati tramite operatori esteri;
    • SMS Gold: SMS di alta qualità con notifica di effettiva ricezione e mittente fisso impostato dagli operatori mobili;
    • SMS Gold Plus: SMS di alta qualità con notifica di effettiva ricezione e mittente personalizzato;
  • Librerie specifiche per Java disponibili scaricando l'apposito SDK, sufficientemente documentate;
  • Buon supporto tecnico;

Come inviare SMS in Java utilizzando SMS Trend

Prima di tutto bisogna creare un account su SMS Trend ed acquistare un pacchetto di sms. Nel caso di registrazione come azienda vengono forniti 5 SMS di prova gratuiti.

Una volta effettuata la registrazione e acquistato un pacchetto di sms, bisogna scaricare l'SDK dal sito, oppure fare clic qui per scaricarlo direttamente.

Adesso estraiamo il file zip, andiamo nella cartella SMStrendSDK e includiamo la libreria SMStrend.jar presente nella cartella nel nostro classpath.

Adesso possiamo effettuare invii di SMS tramite la nostra applicazione Java.

Ecco il codice per effettuare un semplice invio di prova:


E' possibile scaricare il progetto di prova per Eclipse facendo clic qui.

Spero questa piccolissima guida torni utile, per una comprensione più approfondita vi rimando alla guida ufficiale smstrend_sdk_java_ita.pdf contenuta nell'SDK.