Eu posso ver muitas respostas, não abordando realmente as três perguntas do OP.
1) Uma palavra sobre desempenho: é provável que as matrizes de bytes sejam ineficientes, a menos que você possa usar uma ordem exata de bytes de pixel que corresponda aos seus adaptadores de vídeo na resolução e profundidade de cores atuais.
Para obter o melhor desempenho de desenho, basta converter sua imagem em uma BufferedImage que é gerada com um tipo correspondente à sua configuração gráfica atual. Consulte createCompatibleImage em https://docs.oracle.com/javase/tutorial/2d/images/drawonimage.html
Essas imagens serão armazenadas em cache automaticamente na memória da placa de vídeo depois de desenhar algumas vezes sem nenhum esforço de programação (isso é padrão no Swing desde Java 6) e, portanto, o desenho real levará um tempo insignificante - se você não alterar a imagem .
A alteração da imagem vem com uma transferência de memória adicional entre a memória principal e a memória da GPU - que é lenta. Evite "redesenhar" a imagem em um BufferedImage, portanto, evite getPixel e setPixel de todas as formas.
Por exemplo, se você estiver desenvolvendo um jogo, em vez de desenhar todos os atores do jogo para uma BufferedImage e depois para um JPanel, é muito mais rápido carregar todos os atores como BufferedImages menores e desenhá-los um a um no seu código JPanel em sua posição correta - dessa forma, não há transferência de dados adicional entre a memória principal e a memória da GPU, exceto a transferência inicial das imagens para armazenamento em cache.
O ImageIcon usará uma BufferedImage sob o capô - mas basicamente a alocação de uma BufferedImage com o modo gráfico adequado é a chave, e não há esforço para fazer isso corretamente.
2) A maneira usual de fazer isso é desenhar uma BufferedImage em um método paintComponent substituído do JPanel. Embora o Java suporte uma boa quantidade de itens adicionais, como cadeias de buffer que controlam o VolatileImages armazenadas em cache na memória da GPU, não há necessidade de usá-las, pois o Java 6 faz um trabalho razoavelmente bom sem expor todos esses detalhes da aceleração da GPU.
Observe que a aceleração da GPU pode não funcionar em determinadas operações, como esticar imagens translúcidas.
3) Não adicione. Basta pintá-lo como mencionado acima:
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(image, 0, 0, this);
}
"Adicionar" faz sentido se a imagem fizer parte do layout. Se você precisar disso como uma imagem de plano de fundo ou primeiro plano preenchendo o JPanel, basta desenhar o paintComponent. Se você preferir criar um componente Swing genérico que possa mostrar sua imagem, é a mesma história (você pode usar um JComponent e substituir seu método paintComponent) - e depois adicioná- lo ao seu layout de componentes da GUI.
4) Como converter a matriz em uma imagem em buffer
Converter suas matrizes de bytes em PNG e carregá-las consome bastante recursos. Uma maneira melhor é converter sua matriz de bytes existente em uma BufferedImage.
Para isso: não use para loops e copie pixels. Isso é muito, muito lento. Em vez de:
- aprenda a estrutura de bytes preferida da BufferedImage (atualmente é seguro assumir RGB ou RGBA, que é de 4 bytes por pixel)
- aprenda a linha de varredura e o tamanho da digitalização em uso (por exemplo, você pode ter uma imagem de 142 pixels de largura - mas na vida real será armazenada como uma matriz de bytes de 256 pixels de largura, pois é mais rápido processar isso e mascarar os remixes não utilizados pelo hardware da GPU )
- depois que você criar uma matriz de acordo com esses princípios, o método de matriz setRGB da BufferedImage poderá copiar sua matriz para a BufferedImage.
MemoryImageSource
do que convertê-las para o formato JPEG ou PNG e ler com aImageIO
maioria das respostas. Você pode obter umImage
deMemoryImageSource
seus dados de imagem usandocreateImage
e exibir conforme sugerido em uma das respostas.