Превратить массив пикселей в объект изображения с помощью Java ImageIO?
-
02-07-2019 - |
Вопрос
В настоящее время я превращаю массив значений пикселей (первоначально созданный с помощью объекта java.awt.image.PixelGrabber) в объект изображения, используя следующий код:
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?
Toolkit.getDefaultToolkit() не кажется надежным на 100% и иногда выдает AWTError, тогда как классы ImageIO всегда должны быть доступны, вот почему я заинтересован в изменении моего метода.
Решение
Вы можете создать изображение без использования 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
.Пример этого есть в handlepixelметод в javadoc PixelGrabber.Как только вы это сделаете, убедитесь, что тип изображения в конструкторе BufferedImage равен BufferedImage.TYPE_INT_ARGB
.
Другие советы
Используя растр, я получил ArrayIndexOutOfBoundsException
даже когда я создавал BufferedImage
с TYPE_INT_ARGB
.Однако, используя setRGB(...)
способ получения BufferedImage
сработало на меня.
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);
Я добился хорошего успеха, используя 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);
Поскольку это один из самых популярных вопросов, помеченных ImageIO на SO, я думаю, что все еще есть место для лучшего решения, даже если вопрос старый.:-)
Взгляните на BufferedImageFactory.java класс из моего проекта imageio с открытым исходным кодом на GitHub.
С его помощью вы можете просто написать:
BufferedImage image = new BufferedImageFactory(image).getBufferedImage();
Другой хорошей вещью является то, что этот подход, в наихудшем случае, имеет примерно ту же производительность (время), что и PixelGrabber
-основанные примеры уже есть в этой теме.Для большинства распространенных случаев (обычно в формате JPEG) это примерно в два раза быстрее.В любом случае, он использует меньше памяти.
В качестве дополнительного бонуса цветовая модель и расположение пикселей исходного изображения сохранены, вместо перевода в формат int ARGB с цветовой моделью по умолчанию.Это могло бы сэкономить дополнительную память.
(ПС:Фабрика также поддерживает субдискретизацию, просмотр интересующего региона и прослушивание прогресса, если кому-то это интересно.:-)
У меня была та же проблема, что и у всех остальных, пытающихся применить правильный ответ на этот вопрос, мой массив 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);
установка изображения в ImageIcon().Последний совет: вы можете попробовать изменить Bufferedimage.TYPE_INT_ARGB для чего-то другого, что соответствует изображению, которое вы получили, массив из этого типа очень важен, у меня был массив из 0 и -1, поэтому я использовал этот тип BufferedImage.ТИП_3BYTE_BGR