Включить массив пикселей в объект изображения с помощью Java ImageIO?
В настоящее время я превращаю массив значений пикселей (первоначально созданных с помощью объекта java.awt.image.PixelGrabber) в объект Image, используя следующий код:
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);
}
Можно ли достичь такого же результата с помощью классов из пакета ImageIO, поэтому мне не нужно использовать набор инструментов AWT?
Toolkit.getDefaultToolkit(), похоже, не на 100% надежнее и иногда выдает AWTError, тогда как классы ImageIO всегда должны быть доступны, поэтому меня интересует изменение моего метода.
Ответы
Ответ 1
Вы можете создать изображение без использования ImageIO. Просто создайте BufferedImage, используя тип изображения, соответствующий содержимому массива пикселей.
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;
}
При работе с PixelGrabber не забудьте извлечь информацию RGBA из массива пикселей до вызова getImageFromArray
. Вот пример этого в дескриптор метода в javadoc PixelGrabber. После этого убедитесь, что тип изображения в конструкторе BufferedImage равен BufferedImage.TYPE_INT_ARGB
.
Ответ 2
С помощью растра я получил ArrayIndexOutOfBoundsException
, даже когда я создал BufferedImage
с TYPE_INT_ARGB
. Однако использование setRGB(...)
метода BufferedImage
работало для меня.
Ответ 3
JavaDoc в BufferedImage.getData() говорит: "Растр, который является копией данных изображения."
Этот код работает для меня, но я сомневаюсь в его эффективности:
// Получаем картинку из массива.
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);
Ответ 4
У меня был хороший успех, используя java.awt.Robot, чтобы захватить снимок экрана (или сегмент экрана), но для работы с ImageIO вам необходимо сохранить его в BufferedImage вместо образа памяти источник. Затем вы можете вызвать один статический метод ImageIO и сохранить файл. Попробуйте что-то вроде:
// 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);
Ответ 5
Поскольку это один из самых высоких проголосовавших вопросов, отмеченных ImageIO на SO, я думаю, что есть еще место для лучшего решения, даже если вопрос старый.: -)
Взгляните на класс BufferedImageFactory.java из моего проекта с открытым исходным кодом изображения в GitHub.
С его помощью вы можете просто написать:
BufferedImage image = new BufferedImageFactory(image).getBufferedImage();
Другое дело, что этот подход, в худшем случае, имеет одинаковую производительность (время) в качестве примеров, основанных на PixelGrabber
уже в этом потоке. Для большинства распространенных случаев (обычно JPEG) это примерно в два раза быстрее. В любом случае он использует меньше памяти.
В качестве бонусного бонуса сохраняется цветовая модель и макет пикселя исходного изображения, а не переводится в int ARGB с цветной моделью по умолчанию. Это может сэкономить дополнительную память.
(PS: factory также поддерживает подвыборку, регионы интереса и слушателей прогресса, если кому-то интересно.: -)
Ответ 6
У меня была та же проблема, что и все остальные, пытающиеся применить правильный ответ на этот вопрос, мой массив int фактически получает OutOfboundException, где я исправил его, добавив еще один индекс, потому что длина массива должна быть widht * height * 3 после этого я не смог получить изображение, поэтому я исправил его, установив растровое изображение
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;
}
И вы можете увидеть изображение, если и показать его на ярлыке на jframe, подобном этому
JFrame frame = new JFrame();
frame.getContentPane().setLayout(new FlowLayout());
frame.getContentPane().add(new JLabel(new ImageIcon(image)));
frame.pack();
frame.setVisible(true);
настройка изображения на изображенииIcon().
Последний совет, который вы можете попробовать изменить Bufferedimage.TYPE_INT_ARGB на что-то еще, что соответствует изображению, полученному вами от этого типа, очень важно. У меня был массив из 0 и -1, поэтому я использовал этот тип BufferedImage.TYPE_3BYTE_BGR