Sviluppo di componenti Java per i netbook


Procedura per lo sviluppo di librerie di classi Java* destinate agli sviluppatori di applicazioni per i netbook

Introduzione

I netbook si sono diffusi notevolmente in breve tempo. Sono dispositivi a cui spesso manca il lettore DVD e che non hanno la potenza di elaborazione, la memoria e le dimensioni delle unità e degli schermi tipiche dei laptop, ma che offrono in cambio un ingombro ridotto e una maggiore durata della batteria. Sono principalmente utilizzati per l'esplorazione del Web, le attività di e-mail e usano il "cloud computing" per l'archiviazione e la manipolazione dei file dell'utente su una "cloud" remota di server.

Java* è una scelta ovvia per lo sviluppo di piccole applicazioni dedicate che offrono funzioni utili agli utenti dei netbook. Java* è una piattaforma perfetta per le attività di sviluppo destinate ai netbook perché è una piattaforma di sviluppo matura, diffusa e ben documentata. Sviluppare in Java* ha costi praticamente nulli. I programmi Java* sono eseguiti su una Java* Virtual Machine (JVM) o macchina virtuale Java* usando una libreria comune cosicché l'applicazione è costituita da un insieme ridotto di codice binario che usa una piattaforma standardizzata. Per questo motivo le applicazioni Java* si scaricano rapidamente e si installano con facilità. Java oltretutto è installato ed eseguito su qualsiasi computer ovunque si trovi.

Quest'articolo tratta dell'uso di Java* per sviluppare applicazioni per i netbook e librerie di componenti delle classi Java* che offrono un insieme specifico di strumenti utilizzabile dagli sviluppatori per creare applicazioni per i netbook.

Il Programma per gli sviluppatori Intel AppUp(SM) è un programma Intel destinato agli sviluppatori che sono interessati a contribuire al mercato in espansione delle applicazioni per i netbook basati sui processori Intel® Atom™. Il Catalogo per gli sviluppatori è un archivio di elementi di base che possono essere incorporati nelle applicazioni per accelerarne lo sviluppo. È anche possibile sviluppare e pubblicare componenti che altri sviluppatori possono utilizzare.

In quest'articolo viene presentato un caso di studio sotto forma di esercitazione che descrive la creazione di una libreria di componenti Java* e il suo uso in un'applicazione, la creazione della documentazione di supporto e di altri metadati.

La libreria di componenti sviluppata per questo esempio si chiama VideoLibrary. È un insieme di classi Java* che sono usate per trovare un dispositivo video, creare un lettore che visualizzi il flusso video, visualizzare il flusso video, acquisire l'immagine di un fotogramma del video e salvarla come file JPEG. L'esempio continua mostrando l'uso della libreria in un'applicazione e la creazione dei metadati di supporto.

Il programma

Il Programma per gli sviluppatori Intel AppUp(SM) fa parte di un sistema più ampio che include:

  • Un sito Web studiato specificatamente per la comunità di sviluppatori di applicazioni per i netbook.
  • Un processo di convalida e approvazione per le applicazioni da distribuire nel sistema.
  • Un programma di distribuzione che rende le applicazioni disponibili ai clienti.
  • Un client da eseguire sui netbook dei clienti, che collega i clienti al programma di distribuzione.

Per iniziare

Software e attrezzatura

La libreria VideoSource è stata creata con Java* Standard Edition (SE) usando il kit di sviluppo del software Java* SE (JDK) versione 6, Java* Media Framework 2.1.1e e NetBeans 6.7.1. Gli strumenti e le librerie, necessari per creare la libreria e l'applicazione, e il relativo indirizzo Web sono:

Java* SE 6 JRE È il runtime di base richiesto per eseguire le applicazioni Java* http://java.sun.com/javase/downloads/index.jsp
Java* SE JDK 6 Sono le librerie di sviluppo http://java.sun.com/javase/downloads/index.jsp
Java* NetBeans IDE per SE È l'ambiente di sviluppo http://www.netbeans.org/downloads/index.html
Java* Media Framework 2.1.1e È una libreria del framework per i supporti e i dispositivi audio e video http://java.sun.com/javase/technologies/desktop/media/jmf/2.1.1/download.html

Lo sviluppo può essere fatto usando qualsiasi computer, ma per testare i componenti e le applicazioni è necessario usare un netbook Windows XP.

Creazione del progetto

Dopo aver installato gli strumenti e le librerie necessari, avviare l'IDE NetBeans. Appare la schermata iniziale.

Selezionare la voce di menu File - New Project (Nuovo progetto).

Selezionare Java* per la categoria e Java* Class Library (Libreria di classi Java*) per il tipo di progetto, quindi selezionare Next (Avanti).

Digitare il nome del progetto 'VideoLibrary' e selezionare il pulsante Finish (Fine).

Per incorporare meglio la libreria in un'applicazione, creare un pacchetto e chiamarlo VidLib. A tal fine, fare clic con il pulsante destro del mouse sulla voce Source Package (Pacchetto sorgente) e selezionare New (Nuovo), quindi Java* Package (Pacchetto Java*).

Chiamare il pacchetto 'VidLibPkg' e selezionare Finish (Fine).

L'ultimo passaggio è creare una prima classe di libreria. Fare clic con il pulsante destro del mouse sul nuovo pacchetto VidLibPkg e selezionare New (Nuovo) e Java Class (Classe Java).

Chiamare la classe VidLib e selezionare Finish (Fine).

Ora il progetto è pronto e si può iniziare a programmare.

Programmazione della libreria

Configurato il progetto della libreria, è possibile iniziare la programmazione. Questa è la parte difficile.

Pianificazione

Il primo passo per creare una libreria Java* è determinare cosa deve fornire la libreria. E questo a sua volta può essere meglio definito pensando al tipo di applicazioni che userebbero la libreria. L'idea da cui parte questa esercitazione è fornire a uno sviluppatore di applicazioni un insieme di strumenti di base per creare un'applicazione che è in grado di visualizzare un flusso video e acquisire dal video l'immagine di un fotogramma. È un esempio che potrebbe sembrare un po' troppo semplicistico per la libreria di un'applicazione. Ricordarsi, tuttavia che ci occupiamo di applicazioni per netbook, che più leggere sono e meglio è. Poiché le librerie possono essere combinate per creare applicazioni contenenti molte più funzioni, dovrebbero essere progettate per fornire una sola funzione fondamentale.

Un altro fattore da considerare è capire quali saranno le funzioni richieste. Che cosa desidererebbe avere l'utente del netbook? Che cos'è disponibile in un netbook che può essere potenziato con il software?

Una volta stabilito cosa deve fornire la libreria, studiare le librerie e le classi che offriranno gli strumenti di base necessari.

Consultando la documentazione Java* e Internet si determina che è necessario Java* Media Framework come interfaccia per usare i dispositivi video. Si trova nelle importazioni javax.media.*.

Codifica

Il codice per la libreria e l'applicazione è riportato qui alla fine di quest'articolo.

Il primo passo è fornire un modo per determinare se una videocamera è collegata al computer che esegue l'applicazione. Il primo metodo da codificare nella classe è quindi quello di fornire l'elenco dei dispositivi video possibili da usare. La classe CaptureDeviceManager è una classe di gestione che ha accesso a un elenco dei dispositivi di acquisizione disponibili. Può restituire oggetti CaptureDeviceInfo per i dispositivi disponibili.

I netbook (e la maggior parte dei computer) hanno normalmente un solo dispositivo video. Se vi sono voci nell'elenco, il codice usa la prima come valore predefinito, perlomeno in quest'esempio. Il primo metodo da codificare è getVideoDeviceList. Notare che il codice aggiunto presenta diversi elementi sottolineati in rosso. Questo perché non sono definiti. Per risolvere questo problema occorre importare le librerie corrette. Nell'IDE NetBeans quest'operazione può essere fatta automaticamente facendo clic con il pulsante destro del mouse nel pannello del codice sorgente e selezionando Fix Imports (Correggi importazioni).

Sono create le corrette voci di importazione e il codice sorgente è ora corretto.

Le importazioni corrette sono ora state aggiunte al codice sorgente.

Notare che il metodo getVideoDeviceList è pubblico, vale a dire che l'applicazione che usa questa classe ha accesso alla funzione. Notare anche che è definito come statico. Ciò significa che è possibile accedere al metodo senza creare istanze (cioè senza usare New (Nuovo) per creare un'istanza) utilizzando il nome della classe nel seguente modo: VidLib. getVideoDeviceList(). Indipendentemente dal numero di istanze della classe VidLib che sono create, vi sarà inoltre solo un'istanza del metodo.

Il passo successivo è fornire allo sviluppatore dell'applicazione un mezzo per usare il dispositivo selezionato e visualizzare l'output video. Component è il componente visivo del lettore usato per visualizzare il flusso video. È necessario un metodo per creare il lettore e restituire un Component. L'oggetto Player è usato per avviare e arrestare il video. Ogni classe VidLib deve avere il proprio Player per cui uno viene aggiunto come elemento della classe.

Viene creato un oggetto MediaLocator dall'oggetto CaptureDeviceInfo fornito come parametro della chiamata al metodo. La classe javax.Media.Manager è il punto di accesso per ottenere risorse dipendenti dal sistema. Qui viene creato un lettore video e dal lettore si ottiene un componente visivo. Il componente restituito può essere usato direttamente come schermo video in un oggetto JPanel utilizzando il metodo Add.

Ora che i metodi per trovare e visualizzare un video sono creati, è necessario avere un modo per acquisire un'immagine dal lettore video e salvarla in un file. Il metodo getVideoFrameImage restituisce un'immagine dal lettore che può essere quindi salvata in un file.

FrameGrabbingControl è un'interfaccia usata per acquisire un fotogramma da un flusso video e inserirlo in javax.media.Buffer. Questo controllo è esportato da Player usando il metodo getControl. Il fotogramma viene restituito in un formato non elaborato e decodificato. La classe BufferToImage viene usata per convertirlo in un oggetto AWT Image. Image è una classe astratta ed è la superclasse di tutte le classi che rappresentano immagini grafiche e deve essere ottenuta secondo un modo specifico della piattaforma.

Nota:
il metodo finale che è necessario allo sviluppatore dell'applicazione è quello che prende l'immagine catturata e la salva in un file. Il metodo saveVidioFrameImage_to_JPEG_File usa gli argomenti dell'immagine del percorso file per creare un'immagine salvata in formato JPEG.

BufferedImage è una sottoclasse Image usata per creare un oggetto Graphics2D che esegue il rendering dell'immagine usando il metodo drawImage. La classe FileOutputStream è semplicemente un file di output usato da JPEGImageEncoder per salvare l'immagine dopo che ha codificato i dati del buffer dell'immagine in un flusso di dati JPEG. JPEGEncodeParam incapsula le tabelle e le opzioni necessarie per controllare la codifica dei flussi di dati JPEG e imposta la qualità dell'immagine salvata.

Test della libreria delle classi

Per testare la libreria delle classi non occorre creare un'applicazione separata con cui testare la libreria. Creando un metodo public static void main(String[] args) si può eseguire la libreria come un'applicazione e testare il codice. Quando la libreria delle classi viene distribuita (vedere oltre) potrebbe essere prudente rimuovere il codice, cosicché la libreria ha dimensioni minori e non usa ulteriori librerie UI (in questo caso, swing) che non servono alle applicazioni che utilizzano la libreria.

Questa è la schermata dell'applicazione che mostra l'output video della finestra dell'applicazione.

Uso della libreria delle classi in un'applicazione

Creare un progetto di applicazione chiamato VideoSave usando le selezioni di menu File - New Project (File - Nuovo progetto).

Fare clic con il pulsante destro del mouse sul progetto e selezionare le proprietà.

Selezionare ora la categoria Libraries (Librerie), la scheda Compile (Compila) e il pulsante Add JAR/Folder (Aggiungi JAR/cartella).

Andare alla cartella di distribuzione (dist) del progettoVideoLibrary.

Selezionare quindi il fileVideoLibrary.jar usando il pulsante Open (Apri). Questa è la libreria delle classi.

Selezionare il pulsante OK e tornare all'IDE di modifica. La voce di importazione che consente di usare l'importazione della libreria delle classiVidLibPkg.VidLib; è stata aggiunta.

Per testare la libreria a questo punto si può usare lo stesso codice del metodo main dalla libreria delle classi VidLib.

Documentazione della libreria delle classi

Una delle funzioni migliori di Java* è la capacità di documentazione automatica tramite Javadoc. Fare clic con il pulsante destro del mouse su un progetto e selezionare la voce Javadoc.

Per documentare meglio il codice è possibile e consigliabile aggiungere la documentazione dello sviluppatore. Per maggiori informazioni, vedere Come scrivere commenti ai documenti per lo strumento Javadoc.

Lo strumento Javadoc crea file HTML che sono inseriti nella directory di distribuzione dist.

Distribuzione della libreria

La sottodirectory dist del progetto contiene tutti i file necessari a usare la libreria.

Per ulteriori informazioni, consultare le Specifiche dei file JAR e Creare pacchetti JAR dei programmi.

Risorse


Codice sorgente

Libreria delle classi VidLibPkg VidLib

package VidLibPkg;

import com.sun.image.codec.jpeg.JPEGCodec;
import com.sun.image.codec.jpeg.JPEGEncodeParam;
import com.sun.image.codec.jpeg.JPEGImageEncoder;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Enumeration;
import java.util.Vector;
import javax.media.CannotRealizeException;
import javax.media.CaptureDeviceInfo;
import javax.media.CaptureDeviceManager;
import javax.media.Manager;
import javax.media.MediaLocator;
import javax.media.Player;
import javax.media.control.FrameGrabbingControl;
import javax.media.format.VideoFormat;
import javax.media.util.BufferToImage;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class VidLib {

    public static void main(String[] args) {
        final VidLib vs = new VidLib();
        Vector<CaptureDeviceInfo> dl = VidLib.getVideoDeviceList();
        final Component comp = vs.getVideoComponent(dl.get(0));
        JButton btnCapture = new JButton("Capture");
        btnCapture.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent ae) {
                // capture an image and save it to a file when the button is pressed
                Image img = vs.getVideoFrameImage();
                vs.saveVidioFrameImage_to_JPEG_File(img, ".\\SavedImage.jpg");
            }
        });
        // Create and add a video display panel
        JPanel vp = new JPanel();
        vp.setLayout(new BorderLayout());
        // add the capture button and the video display componnent to the video panel
        vp.add(btnCapture, BorderLayout.SOUTH);
        vp.add(comp, BorderLayout.NORTH);
        // Create the dialog frame
        JFrame f = new JFrame("Video Capture");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setResizable(true);
        f.add("Center", vp);
        // size the Window to fit the preferred size and layouts of its subcomponents.
        f.pack();
        // Center the frame
        f.setLocationRelativeTo(null);
        // let them see it
        f.setVisible(true);
        return;
    }

    public boolean saveVidioFrameImage_to_JPEG_File(Image img, String FilePath) {
        boolean bSuccess = false;
        if ((null == FilePath) || (FilePath.isEmpty())) {
            return (false);
        }
        BufferedImage bi = new BufferedImage(img.getWidth(null),
                img.getHeight(null), BufferedImage.TYPE_INT_RGB);
        Graphics2D g2 = bi.createGraphics();
        g2.drawImage(img, null, null);
        FileOutputStream jpegFileOut = null;
        JPEGImageEncoder encoder = null;
        try {
            jpegFileOut = new FileOutputStream(FilePath);
        } catch (java.io.FileNotFoundException io) {
            io.printStackTrace();
        }
        try {
            encoder = JPEGCodec.createJPEGEncoder(jpegFileOut);
            JPEGEncodeParam param = encoder.getDefaultJPEGEncodeParam(bi);

            // 0.75 high quality 0.5  medium quality 0.25 low quality
            // forceBaseline - force baseline quantization table
            param.setQuality(1.0f, false);
            encoder.setJPEGEncodeParam(param);
        } catch (Exception e) {
            e.printStackTrace();
        }
        try {
            encoder.encode(bi);
            jpegFileOut.close();
            bSuccess = true;
        } catch (java.io.IOException io) {
            io.printStackTrace();
        }
        return (bSuccess);
    }

    public Image getVideoFrameImage() {
        Image img = null;
        try {
            FrameGrabbingControl fgc =
                    (FrameGrabbingControl) vidplayer.getControl("javax.media.control.FrameGrabbingControl");
            javax.media.Buffer buf = fgc.grabFrame();
            // Convert it to an image
            BufferToImage btoi = new BufferToImage((VideoFormat) buf.getFormat());
            img = btoi.createImage(buf);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return (img);
    }
    Player vidplayer = null;

    public Component getVideoComponent(CaptureDeviceInfo cdi) {
        Component comp = null;
        MediaLocator ml = null;
        if (null != cdi) {
            try {
                ml = cdi.getLocator();
            } catch (Exception e) {
                e.printStackTrace();
            }
            try {
                try {
                    vidplayer = Manager.createRealizedPlayer(ml);
                } catch (IOException e) {
                    e.printStackTrace();
                } catch (CannotRealizeException e) {
                    e.printStackTrace();
                }
            } catch (javax.media.NoPlayerException e) {
                e.printStackTrace();
            }
            try {
                comp = vidplayer.getVisualComponent();
            } catch (Exception e) {
                e.printStackTrace();
            }
            try {
                vidplayer.start();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return (comp);
    }

    public static Vector<CaptureDeviceInfo> getVideoDeviceList() {

        Vector devices;
        Enumeration dev_enum;
        CaptureDeviceInfo cdi;
        // <CaptureDeviceInfo> checks that the type is CaptureDeviceInfo
        Vector<CaptureDeviceInfo> videoDevices = null;
        try {
            devices = (Vector) CaptureDeviceManager.getDeviceList(null).clone();
            dev_enum = devices.elements();

            if (devices != null && devices.size() > 0) {
                // <CaptureDeviceInfo> checks that the type is CaptureDeviceInfo
                videoDevices = new Vector<CaptureDeviceInfo>();
                javax.media.Format[] formats;

                while (dev_enum.hasMoreElements()) {
                    cdi = (CaptureDeviceInfo) dev_enum.nextElement();
                    formats = cdi.getFormats();

                    for (int j = 0; j < formats.length; j++) {
                        if (formats[j] instanceof VideoFormat) {
                            videoDevices.addElement(cdi);
                            break;
                        }
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return (videoDevices);
    }
}

VideoSave Application Main.java

package videosave;

import VidLibPkg.VidLib;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Vector;
import javax.media.CaptureDeviceInfo;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;

/**
 *
 * @author me
 */
public class Main {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        final VidLib vs = new VidLib();
        Vector<CaptureDeviceInfo> dl = VidLib.getVideoDeviceList();
        final Component comp = vs.getVideoComponent(dl.get(0));
        JButton btnCapture = new JButton("Capture");
        btnCapture.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent ae) {
                // capture an image and save it to a file when the button is pressed
                Image img = vs.getVideoFrameImage();
                vs.saveVidioFrameImage_to_JPEG_File(img, ".\\SavedImage.jpg");
            }
        });
        // Create and add a video display panel
        JPanel vp = new JPanel();
        vp.setLayout(new BorderLayout());
        // add the capture button and the video display componnent to the video panel
        vp.add(btnCapture, BorderLayout.SOUTH);
        vp.add(comp, BorderLayout.NORTH);
        // Create the dialog frame
        JFrame f = new JFrame("Video Capture");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setResizable(true);
        f.add("Center", vp);
        // size the Window to fit the preferred size and layouts of its subcomponents.
        f.pack();
        // Center the frame
        f.setLocationRelativeTo(null);
        // let them see it
        f.setVisible(true);
        return;
    }

}
Per informazioni più dettagliate sulle ottimizzazioni basate su compilatore, vedere il nostro Avviso sull'ottimizzazione.