Domanda

Attualmente sto trasformando una matrice di valori di pixel (originariamente creati con un oggetto java.awt.image.PixelGrabber) in un oggetto Image utilizzando il seguente codice:

public Image getImageFromArray(int[] pixels, int width, int height) {
    MemoryImageSource mis = new MemoryImageSource(width, height, pixels, 0, width);
    Toolkit tk = Toolkit.getDefaultToolkit();
    return tk.createImage(mis);
}

È possibile ottenere lo stesso risultato usando le classi dei pacchetti ImageIO, quindi non devo usare AWT Toolkit?

Toolkit.getDefaultToolkit () non sembra affidabile al 100% e talvolta genera un errore AWTE, mentre le classi ImageIO dovrebbero essere sempre disponibili, motivo per cui sono interessato a cambiare il mio metodo.

È stato utile?

Soluzione

Puoi creare l'immagine senza usare ImageIO. Basta creare un BufferedImage usando un tipo di immagine che corrisponda al contenuto dell'array di pixel.

public static Image getImageFromArray(int[] pixels, int width, int height) {
            BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
            WritableRaster raster = (WritableRaster) image.getData();
            raster.setPixels(0,0,width,height,pixels);
            return image;
        }

Quando si lavora con PixelGrabber, non dimenticare di estrarre le informazioni RGBA dall'array di pixel prima di chiamare getImageFromArray . Ne esiste un esempio nel handlepixelmethod nel PixelGrabber javadoc. Una volta fatto ciò, assicurati che il tipo di immagine nel costruttore BufferedImage sia BufferedImage.TYPE_INT_ARGB .

Altri suggerimenti

Usando il raster ho ottenuto un ArrayIndexOutOfBoundsException anche quando ho creato BufferedImage con TYPE_INT_ARGB . Tuttavia, l'utilizzo del metodo setRGB (...) di BufferedImage ha funzionato per me.

JavaDoc su BufferedImage.getData () dice: " un raster che è una copia dei dati dell'immagine. "

Questo codice funziona per me, ma dubito della sua efficienza:

        // Получаем картинку из массива.
        int[] pixels = new int[width*height];
            // Рисуем диагональ.
            for (int j = 0; j < height; j++) {
                for (int i = 0; i < width; i++) {
                    if (i == j) {
                        pixels[j*width + i] = Color.RED.getRGB();
                    }
                    else {
                        pixels[j*width + i] = Color.BLUE.getRGB();
                        //pixels[j*width + i] = 0x00000000;
                    }
                }
            }

BufferedImage pixelImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);    
    pixelImage.setRGB(0, 0, width, height, pixels, 0, width);

Ho avuto un buon successo usando java.awt.Robot per catturare una schermata (o un segmento dello schermo), ma per lavorare con ImageIO, dovrai memorizzarlo in un'immagine tamponata anziché nell'immagine di memoria fonte. Quindi è possibile chiamare un metodo statico di ImageIO e salvare il file. Prova qualcosa del tipo:

// Capture whole screen
Rectangle region = new Rectangle(Toolkit.getDefaultToolkit().getScreenSize());
BufferedImage capturedImage = new Robot().createScreenCapture(region);

// Save as PNG
File imageFile = new File("capturedImage.png");
ImageIO.write(capturedImage, "png", imageFile);

Poiché questa è una delle domande più votate taggate con ImageIO su SO, penso che ci sia ancora spazio per una soluzione migliore, anche se la domanda è vecchia. : -)

Dai un'occhiata a BufferedImageFactory.java dal mio progetto imageio open source su GitHub.

Con esso, puoi semplicemente scrivere:

BufferedImage image = new BufferedImageFactory(image).getBufferedImage();

L'altra cosa positiva è che questo approccio, nel peggiore dei casi, ha circa le stesse prestazioni (tempo) degli esempi basati su PixelGrabber già presenti in questo thread. Per la maggior parte dei casi comuni (in genere JPEG), è circa il doppio più veloce. In ogni caso, utilizza meno memoria.

Come bonus laterale, il modello di colore e il layout dei pixel dell'immagine originale vengono mantenuti, anziché essere tradotti in ARGB int con modello di colore predefinito. Ciò potrebbe risparmiare memoria aggiuntiva.

(PS: la fabbrica supporta anche gli ascoltatori di subsampling, regione di interesse e progresso se qualcuno è interessato. :-)

Ho avuto lo stesso problema di tutti gli altri che cercavano di applicare la risposta corretta a questa domanda, il mio array int in realtà ottiene una OutOfboundException dove l'ho risolto aggiungendo un altro indice perché la lunghezza dell'array deve essere widht * height * 3 dopo questo non sono riuscito a ottenere l'immagine, quindi l'ho risolto impostando il raster sull'immagine

public static Image getImageFromArray(int[] pixels, int width, int height) {
        BufferedImage image = new BufferedImage(width, height,     BufferedImage.TYPE_INT_ARGB);
        WritableRaster raster = (WritableRaster) image.getData();
        raster.setPixels(0,0,width,height,pixels);
        image.setData(raster); 
        return image;
    }

E puoi vedere l'immagine se la mostri su un'etichetta su un jframe come questo

    JFrame frame = new JFrame();
    frame.getContentPane().setLayout(new FlowLayout());
    frame.getContentPane().add(new JLabel(new ImageIcon(image)));
    frame.pack();
    frame.setVisible(true);

impostazione dell'immagine su imageIcon (). L'ultimo consiglio che puoi provare a cambiare Bufferedimage.TYPE_INT_ARGB in qualcos'altro che corrisponde all'immagine che hai ottenuto l'array da questo tipo è molto importante, avevo un array di 0 e -1, quindi ho usato questo tipo BufferedImage.TYPE_3BYTE_BGR

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top