Pergunta

Atualmente estou virando uma matriz de valores de pixel (originalmente criados com um objeto java.awt.image.PixelGrabber) em um objeto de imagem usando o seguinte código:

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);
}

É possível alcançar o mesmo resultado usando classes do pacote ImageIO (s), então eu não tenho que usar o AWT Toolkit?

Toolkit.getDefaultToolkit () parece não ser 100% confiável e às vezes vai lançar uma AWTError, enquanto as classes ImageIO deve estar sempre disponível, que é por isso que estou interessado em mudar o meu método.

Foi útil?

Solução

Você pode criar a imagem sem usar ImageIO. Basta criar um BufferedImage usando um tipo de imagem combinando o conteúdo do conjunto de pixels.

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;
        }

Ao trabalhar com o PixelGrabber, não se esqueça de extrair a informação RGBA da matriz de pixels antes de chamar getImageFromArray. Há um exemplo disto na handlepixelmethod no javadoc PixelGrabber. Depois de fazer isso, certifique-se o tipo de imagem no construtor BufferedImage para BufferedImage.TYPE_INT_ARGB.

Outras dicas

Usando o raster recebi um ArrayIndexOutOfBoundsException mesmo quando eu criei o BufferedImage com TYPE_INT_ARGB. No entanto, usando o método setRGB(...) de BufferedImage funcionou para mim.

JavaDoc em BufferedImage.getData () diz: "um Raster que é um cópia dos dados de imagem"

Esse código funciona para mim, mas eu duvido nele de eficiência:

        // Получаем картинку из массива.
        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);

Eu tive um bom sucesso usando java.awt.Robot para pegar uma captura de tela (ou um segmento da tela), mas para trabalhar com ImageIO, você vai precisar para armazená-lo em um BufferedImage em vez da imagem de memória fonte. Depois, você pode chamar um método estático de ImageIO e salve o arquivo. Tente algo como:

// 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);

Como este é um dos mais votado questão marcados com ImageIO no SO, eu acho que ainda há espaço para uma solução melhor, mesmo que a questão é antiga. : -)

Tenha um olhar para o BufferedImageFactory.java classe do meu projeto ImageIO open source no GitHub.

Com ele, você pode simplesmente escrever:

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

A outra coisa boa é que essa abordagem, como um pior caso, tem aproximadamente o mesmo desempenho (tempo) como os exemplos baseados em PixelGrabber já em esta discussão. Para a maioria dos casos comuns (tipicamente JPEG), é duas vezes mais rápido. Em qualquer caso, ele usa menos memória.

Como um bônus lado, o modelo de cores e layout de pixel da imagem original é mantido, em vez de traduzidos para int ARGB com o modelo de cor padrão. Isso pode economizar memória adicional.

(PS: A fábrica também suporta subamostragem, e de progresso ouvintes se alguém interessado juros região-de-: -).

Eu tive o mesmo problema de todo mundo tentando aplicar a resposta correta da questão, minha matriz int realmente obter uma OutOfboundException onde eu fixa-lo adicionando mais um índice porque o comprimento da matriz tem que ser Largura * height * 3 depois disto, eu não poderia obter a imagem assim que eu fixa-lo definindo o raster para a imagem

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 você pode ver a imagem se u mostrá-lo em uma etiqueta em um JFrame como este

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

definir a imagem na ImageIcon (). Última conselho que você pode tentar mudar o Bufferedimage.TYPE_INT_ARGB para outra coisa que corresponde à imagem que você tem a matriz deste tipo é muito importante que eu tinha um conjunto de 0 e -1, então eu usei este tipo BufferedImage.TYPE_3BYTE_BGR

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top