Mokabyte

Dal 1996, architetture, metodologie, sviluppo software

  • Argomenti
    • Programmazione & Linguaggi
      • Java
      • DataBase & elaborazione dei dati
      • Frameworks & Tools
      • Processi di sviluppo
    • Architetture dei sistemi
      • Sicurezza informatica
      • DevOps
    • Project Management
      • Organizzazione aziendale
      • HR
      • Soft skills
    • Lean/Agile
      • Scrum
      • Teoria della complessità
      • Apprendimento & Serious Gaming
    • Internet & Digital
      • Cultura & Società
      • Conferenze & Reportage
      • Marketing & eCommerce
    • Hardware & Tecnologia
      • Intelligenza artificiale
      • UX design & Grafica
  • Ultimo numero
  • Archivio
    • Archivio dal 2006 ad oggi
    • Il primo sito web – 1996-2005
  • Chi siamo
  • Ventennale
  • Libri
  • Contatti
  • Argomenti
    • Programmazione & Linguaggi
      • Java
      • DataBase & elaborazione dei dati
      • Frameworks & Tools
      • Processi di sviluppo
    • Architetture dei sistemi
      • Sicurezza informatica
      • DevOps
    • Project Management
      • Organizzazione aziendale
      • HR
      • Soft skills
    • Lean/Agile
      • Scrum
      • Teoria della complessità
      • Apprendimento & Serious Gaming
    • Internet & Digital
      • Cultura & Società
      • Conferenze & Reportage
      • Marketing & eCommerce
    • Hardware & Tecnologia
      • Intelligenza artificiale
      • UX design & Grafica
  • Ultimo numero
  • Archivio
    • Archivio dal 2006 ad oggi
    • Il primo sito web – 1996-2005
  • Chi siamo
  • Ventennale
  • Libri
  • Contatti

Nel numero:

201 dicembre
, anno 2014

API per applicazioni

I parte: Manipolare le immagini con Java grazie ad Apache Commons Imaging

Yuri Cervoni

Yuri Cervoni si è laureato alla facoltà di Ingegneria Informatica dell’Università “La Sapienza” di Roma nel maggio 2009 con la tesi: “Implementazione e realizzazione di un metodo per l’animazione dell’algoritmo di Dijkstra”. Dall’Aprile 2009, prima come stagista e poi come sviluppatore software, lavora nella Società degli Studi di Settore. Nel tempo libero cerca di ampliare le sue conoscenze informatiche partecipando a progetti software presenti su SourceForge.net come “FlaQuizTV” e la documentazione italiana di “Argo UML”.

MokaByte

API per applicazioni

I parte: Manipolare le immagini con Java grazie ad Apache Commons Imaging

Picture of Yuri Cervoni

Yuri Cervoni

  • Questo articolo parla di: Frameworks & Tools, Programmazione & Linguaggi

Cominciamo con questo numero una serie tecnica che, in maniera molto sintetica, si occuperà di presentare delle API Java in grado di interagire con applicazioni desktop e/o mobile. La disponibilità di API, specie per certe funzioni e per certe applicazioni è infatti un elemento cruciale per il lavoro degli sviluppatori. Cominciamo questa carrellata con Apache Commons Imaging.

Introduzione

Apache Commons imaging è una libreria che risultare molto utile nella manipolazione delle immagini, in operazioni quali conversioni, scale di colore, lettura e inserimento di metadati all’interno di esse. Ancora una volta la comunità Apache ci aiuta fornendoci questa preziosa libreria, precedentemente conosciuta come Apache Commons Sanselan.

Si tratta di una libreria Java che permette di leggere e scrivere diversi formati di immagini e lavora su tutte le loro proprietà (dimensioni, colori, profili, e così via). Questa libreria è al 100% puro codice Java: ciò implica che sia più lenta, ma anche la sua perfetta portabilità.

Rispetto a ImageIO  / JAI / toolkit (supportate da Java), Apache Commons Imaging è più facile da usare, e inoltre supporta più formati rispetto a quelli standard, consentendo poi di accedere ai metadati in maniera più semplice e diretta. I requisiti e le caratteristiche sono illustrate di seguito:

  • Java 1.5+
  • zero dipendenza da altri JAR
  • non usa ImageIO / AWT

Supporto per formati immagine

Vediamo anzitutto le capacità di Apache Commons Imaging per il supporto dei diversi formati immagine, riportando l’estensione, le capacità di lettura e scrittura dello stesso e una serie di note esplicative

BMP

Supporto in lettura e scrittura. Quasi completo, ma potrebbe non leggere qualche cursore, qualche icona e qualche bitmpa OS/2. Non è ancora completo il controllo del formato esatto quando si scrive.

GIF

Supporto in lettura e scrittura per entrambe le versioni 87a e 89a. La lettura delle GIF animate è supportata fino al punto di poter leggere tutte le immagini contenute in una GIF, ma la temporizzazione e la visualizzazione ciclica sono ignorate.  Non è ancora completo il controllo del formato esatto quando si scrive.

JPEG / JFIF

Parziale supporto in lettura, mancanza di supporto in scrittura. Legge solo immagini JPEG semplici in scala di grici o YCbCr a linea di base sequenziale, senza marcatori RST, che devono usare 8 bit per componente ed essere compresse secondo la codidica di Huffmann. Può leggere le informazioni e i metadati delle immagini ed estrarre i profili ICC, sia dalle JFIF che da DCF/EXIF. Fornisce commenti JPEG in ImageInfo.

ICNS

Supporto in massima parte sia in lettura che in scrittura. Manca il supporto per le icone JPEG2000, ma tutti gli altri formati e le altre misure sono lette e scritte correttamente. Testato estensivamente per la correttezza in Mac OS X, compreso il comportamento in caso di mancanza di maschera.

!CO / CUR

Supporto in lettura e, in massima parte, anche in scrittura. Legge fil .ico e .cur a 1 / 4 / 8 / 16 / 24 / 32 bpp. Supporta i file ICO di Windows con i PNG incorporati. Gestisce correttamente i problemi di trasparenza del canale alfa vs. btmask a profondità di colore di 32 bit per pixel. Supporta i bitmap co compressione bitfield. Testato estensivamente, è con ogni probabilità la migliore implementazione open source disponibile di questo supporto.

PCX / DCX

Supporto in lettura e scrittura. Legge immagini a 1 piano e 1 / 2 / 4 / 8 bit, 1 bit e 1 / 2 / 3 / 4 piani, 3 piani a 8 bit, 1 piano a 24 bit e 1 piano a 32 bit. Le immagini monocrome vengono correttamente interpretate. Legge e può scrivere il formato non compresso e non documentato PCX, compresa la lettura delle tabelle DCX ridotte. Testato completamente.

PNM / PGM / PBM / PPM / PAM Portable Pixmap

Supporto completo in lettura e, in massima parte, anche in scrittura. Scrittura del PAM solo nel formato RGB_ALPHA.

PNG

Supporto in lettura e scrittura. Supportato fino a tutta la versione 1.2 in standard ISO/IEC (15948:2003). Non è ancora completo il controllo del formato esatto quando si scrive.

PSD / Photoshop

Supporto in lettura ma non in scrittura. Supporto delle funzioni base: può leggere solo il primo layer, senza supporto per i canali extra. Supporto per tutte le modalità eccetto che per la multicanale. Può keggere alcuni metadati dell’immagine.

RGBE / Radiance HDR

Supporto in lettura ma non in scrittura. Supporto delle funzioni base.

TIFF

Supporto in lettura e scrittura. Supportato fino a tutta la versione 6.0. Il TIFF è un formato “contenitore” aperto, quindi non è possibile supportare ogni sua possibile variante. Sono supportate le immagini bi-level, palette / indexed, RGB, CMYK, YCbCr, CIELab e LOGLUV. Supporta la lettura e la scrittura degli algoritmi di compressione CCITT / modified Huffman / Group 3 / Group 4  e Packbits / RLE compression. Mancano però altre forme di compressione, segnatamente la JPEG. Supporta la lettura di immagini sezionate.

WBMP

Supporto in lettura e scrittura. Supporto completo per i bitmap WBMP tipo 0.

XBM

Supporto in lettura e scrittura completo.

XPM

Supporto in lettura e scrittura. Attualmente è supportata solo la versione 3 di XPM, ma le altre versioni sono obsolete. Legge tutti i formati di colore, compresi quelli che utilizzano nomi simbolici provenienti da rgb.txt. La scrittura scrve solo i dati sul colore.

Supporto per formati metadati

Apache Commons Imaging supporta i seguenti formati di metadati.

Metadati EXIF per JPEG/JFIF

Supporto in lettura e scrittura. Può leggere e scrivere dati EXIF da e verso file JPEG/JFIF esistenti senza modificare i dati immagine.

Metadati IPTC per JPEG/JFIF

Supporto in lettura già presente, supporto in scrittura ancora da implementare, ma ormai prossimo. Può leggere dati IPTC da file JPEG/JFIF esistenti senza modificare i dati immagine.

XMP

Supporto in lettura e scrittura. Riesce a leggere XMP XML (come String) da TIFF, GIF, PNG, JPEG e PSD. Può incorporare XMP XML in scrittura su GIF, PNG e TIFF. Può rimuovere, inserire e aggiornare XMP XML dentro file JPEG esistenti.

Preparazione dell’ambiente di lavoro

Ora che abbiamo visto le caratteristiche di supporto a formati immagine e formati di metadati, cerchiamo di capire come fare per installare Apache Commons Imaging. Per scaricare questa libreria andiamo sul sito internet della comunità Apache

http://commons.apache.org/proper/commons-imaging/index.html

dove troveremo tutte le informazioni sulla nostra libreria. Spostiamoci sul menu Imaging ->  Download e scarichiamo i file binari

apache-sanselan-incubating-0.97-bin.zip

 

 

 

Figura 1 – La pagina del progetto, da cui scaricare i file della libreria.

 

Una volta scaricata la libreria, includiamola nel nostro progetto e saremo pronti per iniziare a scrivere un po’ di codice.

Lettura di un’immagine

La lettura di un’immagine attraverso questa libreria avviene con il metodo getBufferedImage() che vuole come parametri d’ingresso il file dell’immagine e i parametri relativi all’immagine.

Imaging.getBufferedImage(file, params);

Le informazioni sui parametri possono essere consultate all’interno della documentazione ufficiale [1]. Di seguito mostriamo una breve lista di parametri che si possono utilizzare (tabella 1).

 

 

Tabella 1 – Elenco di parametri da utilizzare per la lettura di una immagine.

 

Scrittura di un’immagine

Per scrivere un immagine su un file, invece, viene usata la funzione writeImageToBytes()

Imaging.writeImageToBytes(image, format, params);

che richiede come parametri di ingresso l’immagine, il tipo di formato e parametri opzionali sull’immagine. Ecco un esempio:

public class ScritturaImgEsempio {
    public static byte[] imageWriteExample(final File file)
            throws ImageReadException, ImageWriteException, IOException {
        // lettura
        final BufferedImage image = Imaging.getBufferedImage(file);
          
        final ImageFormat format = ImageFormats.TIFF;
        final Map<String, Object> params = new HashMap<String, Object>();
          
        // settaggio di parametri opzionali
        params.put(ImagingConstants.PARAM_KEY_COMPRESSION, new Integer(
            TiffConstants.TIFF_COMPRESSION_UNCOMPRESSED));
          
            final byte[] bytes = Imaging.writeImageToBytes(image, format, params);
          
            return bytes;
        }
          
}

Profili ICC

I profili ICC (International Color Consortium) descrivono gli attributi di colore di un particolare dispositivo. Per una definizione più dettagliata, vi rimandiamo voce “Profilo ICC” [2]. Ora andiamo a vedere come questi profili vengono usati in Java attraverso la libreria di Apache.

    final byte iccProfileBytes[] = Imaging.getICCProfileBytes(imageBytes);
 
    final ICC_Profile iccProfile = Imaging.getICCProfile(imageBytes);

Metadati

I metadati contenuti nelle immagini sono molto usati al giorno d’oggi e vengono salvati nelle foto scattate da uno smarthpone o da un tablet ma anche in quelle realizzate con fotocamere reflex digitali.

Infatti insieme alle foto possono essere salvate informazioni riguardanti la data di creazione, l’orientamento della foto, la distanza focale, il tempo di esposizione, lo spazio colore, le coordinate GPS, e molte altre. Questi dati sono molto importanti sia, ad esempio, per georiferire le fotografie e collocarle su una mappa, sia per poter effettuare elaborazioni di tipo fotografico con gli appositi programmi di fotoritocco. Non vanno poi sottovalutate le attenzioni da riservare alla sicurezza di tali informazioni.

Vedremo ora di seguito il codice che mostra un esempio pratico di lettura e di scrittura di metadati in un’immagine: i brevi commenti riportati nel codice specificano alcuni aspetti cui raccomandiamo di prestare attenzione, ma il codice non dovrebbe risultare di difficile interpretazione.

Lettura di metadati

public class MetadataExample {
              public static void metadataExample(final File file) throws ImageReadException,
                      IOException {
          
                  // ottengo metadata nel formato EXIF (es. JPEG o TIFF)
                  final IImageMetadata metadata = Imaging.getMetadata(file);
          
                  if (metadata instanceof JpegImageMetadata) {
                      final JpegImageMetadata jpegMetadata 
                      = (JpegImageMetadata) metadata;
          
                      System.out.println("file: " + file.getPath());
          
                      // print out various interesting EXIF tags.
                      printTagValue(jpegMetadata, TiffTagConstants.TIFF_TAG_XRESOLUTION);
                      printTagValue(jpegMetadata, TiffTagConstants.TIFF_TAG_DATE_TIME);
                      printTagValue(jpegMetadata,
                              ExifTagConstants.EXIF_TAG_DATE_TIME_ORIGINAL);
                      printTagValue(jpegMetadata, 
                              ExifTagConstants.EXIF_TAG_DATE_TIME_DIGITIZED);
                      printTagValue(jpegMetadata, ExifTagConstants.EXIF_TAG_ISO);
                      printTagValue(jpegMetadata,
                              ExifTagConstants.EXIF_TAG_SHUTTER_SPEED_VALUE);
                      printTagValue(jpegMetadata,
                              ExifTagConstants.EXIF_TAG_APERTURE_VALUE);
                      printTagValue(jpegMetadata,
                              ExifTagConstants.EXIF_TAG_BRIGHTNESS_VALUE);
                      printTagValue(jpegMetadata,
                              GpsTagConstants.GPS_TAG_GPS_LATITUDE_REF);
                      printTagValue(jpegMetadata, GpsTagConstants.GPS_TAG_GPS_LATITUDE);
                      printTagValue(jpegMetadata,
                              GpsTagConstants.GPS_TAG_GPS_LONGITUDE_REF);
                      printTagValue(jpegMetadata, GpsTagConstants.GPS_TAG_GPS_LONGITUDE);
          
                      System.out.println();
          
                      // Semplice interfaccia GPS
                      final TiffImageMetadata exifMetadata = jpegMetadata.getExif();
                      if (null != exifMetadata) {
                          final TiffImageMetadata.GPSInfo gpsInfo = exifMetadata.getGPS();
                          if (null != gpsInfo) {
                              final String gpsDescription = gpsInfo.toString();
                              final double longitude = gpsInfo.getLongitudeAsDegreesEast();
                              final double latitude = gpsInfo.getLatitudeAsDegreesNorth();
          
                              System.out.println("    " + "GPS Description: "
                                      + gpsDescription);
                              System.out.println("    "
                                      + "GPS Longitude (Degrees East): " + longitude);
                              System.out.println("    "
                                      + "GPS Latitude (Degrees North): " + latitude);
                          }
                      }
          
                      // Esempi specifici di come accedere alle coordinate GPS
                      final TiffField gpsLatitudeRefField 
                      = jpegMetadata.findEXIFValueWithExactMatch(
                          GpsTagConstants.GPS_TAG_GPS_LATITUDE_REF);
                      final TiffField gpsLatitudeField 
                      = jpegMetadata.findEXIFValueWithExactMatch(
                          GpsTagConstants.GPS_TAG_GPS_LATITUDE);
                      final TiffField gpsLongitudeRefField 
                      = jpegMetadata.findEXIFValueWithExactMatch(
                          GpsTagConstants.GPS_TAG_GPS_LONGITUDE_REF);
                      final TiffField gpsLongitudeField 
                      = jpegMetadata.findEXIFValueWithExactMatch(
                          GpsTagConstants.GPS_TAG_GPS_LONGITUDE);
                      if (gpsLatitudeRefField != null && gpsLatitudeField != null
                              && gpsLongitudeRefField != null
                              && gpsLongitudeField != null) {
                          // all of these values are strings.
                          final String gpsLatitudeRef 
                          = (String) gpsLatitudeRefField.getValue();
                          final RationalNumber gpsLatitude[] 
                          = (RationalNumber[]) (gpsLatitudeField
                                  .getValue());
                          final String gpsLongitudeRef 
                          = (String) gpsLongitudeRefField.getValue();
                          final RationalNumber gpsLongitude[] 
                          = (RationalNumber[]) gpsLongitudeField.getValue();
          
                          final RationalNumber gpsLatitudeDegrees = gpsLatitude[0];
                          final RationalNumber gpsLatitudeMinutes = gpsLatitude[1];
                          final RationalNumber gpsLatitudeSeconds = gpsLatitude[2];
          
                          final RationalNumber gpsLongitudeDegrees = gpsLongitude[0];
                          final RationalNumber gpsLongitudeMinutes = gpsLongitude[1];
                          final RationalNumber gpsLongitudeSeconds = gpsLongitude[2];
          
                          // Stampa del formato GPS
                          System.out.println("    " + "GPS Latitude: "
                                  + gpsLatitudeDegrees.toDisplayString() + " degrees, "
                                  + gpsLatitudeMinutes.toDisplayString() + " minutes, "
                                  + gpsLatitudeSeconds.toDisplayString() + " seconds "
                                  + gpsLatitudeRef);
                          System.out.println("    " + "GPS Longitude: "
                                  + gpsLongitudeDegrees.toDisplayString() + " degrees, "
                                  + gpsLongitudeMinutes.toDisplayString() + " minutes, "
                                  + gpsLongitudeSeconds.toDisplayString() + " seconds "
                                  + gpsLongitudeRef);
                      }
          
                      System.out.println();
                      final List items = jpegMetadata.getItems();
                      for (int i = 0; i < items.size(); i++) {
                          final IImageMetadataItem item = items.get(i);
                          System.out.println("    " + "item: " + item);
                      }
          
                      System.out.println();
                  }
          }

              // Stampa valori metadata
              private static void printTagValue(final JpegImageMetadata jpegMetadata,
                      final TagInfo tagInfo) {
                  final TiffField field = jpegMetadata.findEXIFValueWithExactMatch(tagInfo);
                  if (field == null) {
                      System.out.println(tagInfo.name + ": " + "Not Found.");
                  } else {
                      System.out.println(tagInfo.name + ": "
                              + field.getValueDescription());
                  }
              }
          
          }

Scrittura metadati

Vediamo ora come scrivere i metadati su una immagine grazie alle funzionalità della libreria Apache Commons Imaging. Anche in questo caso, raccomandiamo particolare attenzione ai commenti nel codice, che ne illustrano alcuni aspetti importanti.

public class WriteExifMetadataExample {
              public void removeExifMetadata(final File jpegImageFile, final File dst)
                      throws IOException, ImageReadException, ImageWriteException {
                  OutputStream os = null;
                  boolean canThrow = false;
                  try {
                      os = new FileOutputStream(dst);
                      os = new BufferedOutputStream(os);
                      new ExifRewriter().removeExifMetadata(jpegImageFile, os);
                      canThrow = true;
                  } finally {
                      IoUtils.closeQuietly(canThrow, os);
                  }
              }

              // Questo esempio spiega come aggiungere o aggiornare dati EXIF in un JPEG
              public void changeExifMetadata(final File jpegImageFile, final File dst)
                      throws IOException, ImageReadException, ImageWriteException {
                  OutputStream os = null;
                  boolean canThrow = false;
                  try {
                      TiffOutputSet outputSet = null;

                      // se non viene trovato alcun metadato,
                      // i metadati potrebbero essere null 
                      final IImageMetadata metadata = Imaging.getMetadata(jpegImageFile);
                      final JpegImageMetadata jpegMetadata = (JpegImageMetadata) metadata;
                      if (null != jpegMetadata) {
         
                      // notare che gli EXIF potrebbero essere null 
                      //se non viene trovato alcun EXIF
                          final TiffImageMetadata exif = jpegMetadata.getExif();
          
                          if (null != exif) {
                    // Classe TiffImageMetadata è immutabile (sola lettura).
                    // Classe TiffOutputSet rappresenta i dati EXIF da scrivere.
         
                    // Di solito, vogliamo aggiornare i metadati EXIF esistenti cambiando
                    // i valori di alcuni campi o aggiungendo un campo.
                    // In questi casi, è più facile usare getOutputSet () per
                    // copiare dei campi letti dall'immagine.
          
                              outputSet = exif.getOutputSet();
                          }
                      }
          
                     // Se il file non contiene metadati EXIF, creiamo un vuoto
                           if (null == outputSet) {
                          outputSet = new TiffOutputSet();
                      }
          
                      {
                          // Esempio di come aggiungere un campo / tag all'output
                          // si veda  org.apache.commons.imaging.formats
                          // .tiff.constants.AllTagConstants
                          final TiffOutputDirectory exifDirectory = outputSet
                                  .getOrCreateExifDirectory();
          
                          // Assicurarsi di rimuovere il vecchio valore se presente
                          // altrimenti andrà in eccezione perchè il tag non esiste
          
                          exifDirectory
                                  .removeField(ExifTagConstants.EXIF_TAG_APERTURE_VALUE);
                          exifDirectory.add(ExifTagConstants.EXIF_TAG_APERTURE_VALUE,
                                  new RationalNumber(3, 10));
                      }
          
                      {
                          //Esempio di come aggiungere / aggiornare informazioni GPS 
                          // New York City
                          final double longitude = -74.0;
                          final double latitude = 40 + 43 / 60.0; 
                          outputSet.setGPSInDegrees(longitude, latitude);
                      }
          
                      os = new FileOutputStream(dst);
                      os = new BufferedOutputStream(os);
                      new ExifRewriter().updateExifMetadataLossless(jpegImageFile, os,
                              outputSet);
                      canThrow = true;
                  } finally {
                      IoUtils.closeQuietly(canThrow, os);
                  }
              }
          
              // Questo esempio illustra come rimuovere un tag (se presente) da EXIF   
              public void removeExifTag(final File jpegImageFile, final File dst) 
                          throws IOException,ImageReadException, ImageWriteException {
                  OutputStream os = null;
                  boolean canThrow = false;
                  try {
                      TiffOutputSet outputSet = null;

                      // notare che i metadati potrebbero essere null 
                      // se non viene trovato alcun  metadato         
                      final IImageMetadata metadata = Imaging.getMetadata(jpegImageFile);
                      final JpegImageMetadata jpegMetadata = (JpegImageMetadata) metadata;
                      if (null != jpegMetadata) {

                      // notare che gli EXIF potrebbero essere null 
                      //se non viene trovato alcun EXIF
                          final TiffImageMetadata exif = jpegMetadata.getExif();
          
                          if (null != exif) {
                              // Classe TiffImageMetadata è immutabile (sola lettura) .
                              // Classe TiffOutputSet rappresenta i dati EXIF da scrivere .
          
                              // Di solito, vogliamo aggiornare i metadati EXIF esistenti 
                              // cambiando i valori di alcuni campi o aggiungere un campo.
                              // In questi casi, è più facile usare getOutputSet () per
                              // copiare dei campi letti dall'immagine.
          
                              outputSet = exif.getOutputSet();
                          }
                      }
          
                      if (null == outputSet) {
                          // Il file non contiene tutti i metadati EXIF. 
                          // Non abbiamo bisogno di aggiornare il file; basta copiarlo.
                          FileUtils.copyFile(jpegImageFile, dst);
                          return;
                      }
          
                      {
                          // Esempio di come rimuovere un singolo tag / campo.
                          final TiffOutputDirectory exifDirectory = outputSet
                                  .getExifDirectory();
                          if (null != exifDirectory) {
                              exifDirectory
                                      .removeField(ExifTagConstants.EXIF_TAG_APERTURE_VALUE);
                          }
                      }
          
                      os = new FileOutputStream(dst);
                      os = new BufferedOutputStream(os);
                      new ExifRewriter().updateExifMetadataLossless(jpegImageFile, os,
                              outputSet);
                      canThrow = true;
                  } finally {
                      IoUtils.closeQuietly(canThrow, os);
                  }
              }
          
              // Questo esempio mostra come salvare i valori 
              // delle coordinate GPS nel JPEG EXIF   
              public void setExifGPSTag(final File jpegImageFile, final File dst) 
                  throws IOException,
                      ImageReadException, ImageWriteException {
                  OutputStream os = null;
                  boolean canThrow = false;
                  try {
                      TiffOutputSet outputSet = null;          
                      final IImageMetadata metadata = Imaging.getMetadata(jpegImageFile);
                      final JpegImageMetadata jpegMetadata = (JpegImageMetadata) metadata;
                      if (null != jpegMetadata) {         
                          final TiffImageMetadata exif = jpegMetadata.getExif();         
                          if (null != exif) {
                              outputSet = exif.getOutputSet();
                          }
                      }          
                      if (null == outputSet) {
                          outputSet = new TiffOutputSet();
                      }
          
                      {

                          // Esempio di come aggiungere o aggiornare coordinate GPS
                          outputSet.setGPSInDegrees(longitude, latitude);
                      }
                      os = new FileOutputStream(dst);
                      os = new BufferedOutputStream(os);
                      new ExifRewriter().updateExifMetadataLossless(jpegImageFile, os,
                              outputSet);
                      canThrow = true;
                  } finally {
                      IoUtils.closeQuietly(canThrow, os);
                  }
              }
          
          }

Un esempio riassuntivo

Di seguito, si riporta un ulteriore esempio riassuntivo del modo in cui può essere utilizzata questa libreria. Ancora una volta, raccomandiamo ai lettori di fare attenzione ai commenti nel codice.

public class SampleUsage {
    public SampleUsage() {
        try {
          
            //Il codice non funziona a meno che queste variabili 
            // siano correttamente inizializzate
            //Imaging funziona altrettanto bene con File,
            // array di byte o InputStream.
          
            final BufferedImage someImage = null;
            final byte someBytes[] = null;
            final File someFile = null;
            final InputStream someInputStream = null;
            final OutputStream someOutputStream = null;
          
            // Leggere una immagine
            final byte imageBytes[] = someBytes;
            final BufferedImage image_1 
            = Imaging.getBufferedImage(imageBytes);
          
            final BufferedImage image_2 
            = Imaging.getBufferedImage(imageBytes);
            final File file = someFile;
            final BufferedImage image_3 = Imaging.getBufferedImage(file);
            final InputStream is = someInputStream;
            final BufferedImage image_4 = Imaging.getBufferedImage(is);
          
            // Scrivere un'immagine
            final BufferedImage image = someImage;
            final File dst = someFile;
            final ImageFormat format = ImageFormats.PNG;
            final Map<String, Object> optionalParams 
            = new HashMap<String, Object>();
            Imaging.writeImage(image, dst, format, optionalParams);
          
            final OutputStream os = someOutputStream;
            Imaging.writeImage(image, os, format, optionalParams);
          
            // Ottengo il Profilo ICC se esiste
            final byte iccProfileBytes[] 
            = Imaging.getICCProfileBytes(imageBytes);
          
            final ICC_Profile iccProfile 
            = Imaging.getICCProfile(imageBytes);
          
            // Altezza e larghezza dell'immagine
            final Dimension d = Imaging.getImageSize(imageBytes);
          
            // Ottengo info sull'immagine come bit per pixel,
            // dimensioni, trasparenza, etc.
            final ImageInfo imageInfo = Imaging.getImageInfo(imageBytes);
            if (imageInfo.getColorType() == ImageInfo.COLOR_TYPE_GRAYSCALE) {
                System.out.println("Grayscale image.");
            }
            if (imageInfo.getHeight() > 1000) {
                System.out.println("Large image.");
            }
          
            // Prova a desumere il formato dell'immagine
            final ImageFormat imageFormat 
            = Imaging.guessFormat(imageBytes);
            imageFormat.equals(ImageFormats.PNG);
          
            // Ottiene tutti i metadati in formato EXIF 
            final IImageMetadata metadata 
            = Imaging.getMetadata(imageBytes);
          
            // Stampa informazioni su file
            Imaging.dumpImageFile(imageBytes);
          
            /* Ottenere indice degli errori */
            final FormatCompliance formatCompliance 
            = Imaging.getFormatCompliance(imageBytes);
          
            } catch (final Exception e) {
          
        }
    }
}

Conclusioni

Apache Commons Imaging si dimostra una buona libreria, soprattutto pratica per manipolare immagini e  metadati che possono essere aggiunti ad esse. Ha ancora margini di miglioramento e speriamo che la grande comunità Apache la aggiorni con una certa costanza.

Nei prossimi articoli affronteremo altre API, tra le quali, solo per citarne alcune, Apache POI per l’interazione con la suite Microsoft Office, PDFbox per lavorare su file PDF e Twitter4J per interfacciarsi alla piattaforma social di microblogging.

 

 

Yuri Cervoni

Yuri Cervoni si è laureato alla facoltà di Ingegneria Informatica dell’Università “La Sapienza” di Roma nel maggio 2009 con la tesi: “Implementazione e realizzazione di un metodo per l’animazione dell’algoritmo di Dijkstra”. Dall’Aprile 2009, prima come stagista e poi come sviluppatore software, lavora nella Società degli Studi di Settore. Nel tempo libero cerca di ampliare le sue conoscenze informatiche partecipando a progetti software presenti su SourceForge.net come “FlaQuizTV” e la documentazione italiana di “Argo UML”.

Facebook
Twitter
LinkedIn
Picture of Yuri Cervoni

Yuri Cervoni

Yuri Cervoni si è laureato alla facoltà di Ingegneria Informatica dell’Università “La Sapienza” di Roma nel maggio 2009 con la tesi: “Implementazione e realizzazione di un metodo per l’animazione dell’algoritmo di Dijkstra”. Dall’Aprile 2009, prima come stagista e poi come sviluppatore software, lavora nella Società degli Studi di Settore. Nel tempo libero cerca di ampliare le sue conoscenze informatiche partecipando a progetti software presenti su SourceForge.net come “FlaQuizTV” e la documentazione italiana di “Argo UML”.
Tutti gli articoli
Nello stesso numero
Loading...

Kanban, dall’idea alla pratica

II parte: Impariamo a progettare e usare la Kanban board

ESB con SwitchYard JBoss

II parte: Enterprise Service Bus

Guida alla retrospettiva

VIII parte: Far funzionare al meglio le retrospettive

Nella stessa serie
Loading...

API per applicazioni

VI parte: Linear Algebra for Java

API per applicazioni

V parte: Apache PDFBox, una libreria Java per file PDF

API per applicazioni

IV parte: JFreeChart, una libreria per disegnare grafici

API per applicazioni

III parte: Twitter4J

API per applicazioni

II parte: Interagire con le applicazioni MS Office grazie ad Apache POI

Mokabyte

MokaByte è una rivista online nata nel 1996, dedicata alla comunità degli sviluppatori java.
La rivista tratta di vari argomenti, tra cui architetture enterprise e integrazione, metodologie di sviluppo lean/agile e aspetti sociali e culturali del web.

Imola Informatica

MokaByte è un marchio registrato da:
Imola Informatica S.P.A.
Via Selice 66/a 40026 Imola (BO)
C.F. e Iscriz. Registro imprese BO 03351570373
P.I. 00614381200
Cap. Soc. euro 100.000,00 i.v.

Privacy | Cookie Policy

Contatti

Contattaci tramite la nostra pagina contatti, oppure scrivendo a redazione@mokabyte.it

Seguici sui social

Facebook Linkedin Rss
Imola Informatica
Mokabyte