Превратить массив пикселей в объект изображения с помощью Java ImageIO?

StackOverflow https://stackoverflow.com/questions/124630

Вопрос

В настоящее время я превращаю массив значений пикселей (первоначально созданный с помощью объекта 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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top