Превратить массив пикселей в объект Image с помощью 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?

Toolkit.getDefaultToolkit () не выглядит на 100% надежным и иногда выдает ошибку AWTError, тогда как классы ImageIO должны быть доступны всегда, поэтому я заинтересован в изменении моего метода.


person Chris Carruthers    schedule 24.09.2008    source источник


Ответы (6)


Вы можете создать изображение без использования 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. Пример этого есть в handlepixelmethod в javadoc PixelGrabber. После этого убедитесь, что тип изображения в конструкторе BufferedImage равен BufferedImage.TYPE_INT_ARGB.

person Brendan Cashman    schedule 24.09.2008
comment
Спасибо, bcash, но я получаю исключение java.lang.ArrayIndexOutOfBoundsException, когда пробую этот код. Любые идеи? - person Chris Carruthers; 24.09.2008
comment
Я думаю, это близко, нам может понадобиться больше деталей от Криса с деталями? похоже, это должно работать ... Какие у вас ints? они RGB? ARGB? какой-то упакованный формат? - person John Gardner; 24.09.2008
comment
Пиксели поступают из PixelGrabber как такового: int [] pixels = new int [width * height]; PixelGrabber pg = new PixelGrabber (img, 0, 0, ширина, высота, пиксели, 0, ширина); pg.grabPixels (); - person Chris Carruthers; 24.09.2008
comment
Крис, вы получаете исключение AOOB, потому что размер изображения BufferedImage равен width * height * 3, потому что он имеет тип int RGB. Смотрите редактирование. - person Brendan Cashman; 24.09.2008
comment
Когда я попробовал этот код, у меня появилось черное изображение. Это похоже на то, что raster.setPixels вообще не повлиял на BufferedImage. - person Mutant Bob; 09.01.2016
comment
Как сообщил @haraldK (в сообщениях ниже), в документации Java упоминается, что BufferedImage.getData() возвращает Raster, а BufferedImage.getRaster() возвращает WritableRaster. Таким образом, если вы используете getData(), кажется, что он возвращает копию, а после setPixels() вы должны вернуть ее, используя BufferedImage.setData(), что является накладными расходами. Так что лучше использовать getRaster() и работать с ним. - person Alireza Kazemi; 18.01.2019

Используя растр, я получил ArrayIndexOutOfBoundsException, даже когда я создал BufferedImage с TYPE_INT_ARGB. Однако использование setRGB(...) метода BufferedImage у меня сработало.

person mdm    schedule 29.04.2009
comment
У меня была аналогичная проблема, хотя размер массива ввода и вывода совпадал. В итоге я тоже использовал setRGB. Это может быть тривиально медленнее, но это работает. Они бы не думали, что альфа и не альфа должны изменить размер массива, поскольку это просто 2 наиболее значимых байта для отдельного int. - person bobtheowl2; 12.04.2012
comment
Как можно использовать setRGB () в приведенном выше коде? Спасибо... - person GhostDede; 10.12.2020

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);
person beemaster    schedule 03.02.2011
comment
..или используйте getRaster() вместо getData(). - person Harald K; 05.06.2013

У меня был хороший успех с использованием 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);
person Steve Moyer    schedule 24.09.2008

Поскольку это один из самых популярных вопросов с тегом ImageIO на SO, я думаю, что еще есть место для лучшего решения, даже если вопрос старый. :-)

Взгляните на BufferedImageFactory.java из моего проекта imageio с открытым исходным кодом на GitHub.

С его помощью вы можете просто написать:

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

Еще одна хорошая вещь заключается в том, что этот подход, в худшем случае, имеет примерно такую ​​же производительность (время), что и примеры на основе PixelGrabber уже в этом потоке. В большинстве распространенных случаев (обычно в формате JPEG) это примерно в два раза быстрее. В любом случае он использует меньше памяти.

В качестве дополнительного бонуса цветовая модель и макет пикселей исходного изображения сохраняются, а не переводятся в int ARGB с цветовой моделью по умолчанию. Это может сэкономить дополнительную память.

(PS: Factory также поддерживает подвыборку, область интереса и прослушиватели прогресса, если кому-то интересно. :-)

person Harald K    schedule 04.06.2013

У меня была та же проблема, что и все остальные, пытающиеся применить правильный ответ на этот вопрос, мой массив int фактически получил OutOfboundException, где я исправил его, добавив еще один индекс, потому что длина массива должна быть widht * height * 3 после этого i не удалось получить изображение, поэтому я исправил его, установив растр на изображение

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.TYPE_3BYTE_BGR

person Raul H    schedule 21.06.2016