Подтвердить что ты не робот

Как преобразовать байт [] в BufferedImage в Java?

Я публикую эту тему, потому что у меня есть некоторые трудности с обработкой изображений на Java. Я хотел бы иметь возможность конвертировать изображение в массив byte [], а затем иметь возможность выполнять обратную операцию, поэтому я могу изменить RGB каждого пикселя, а затем создать новое изображение. Я хочу использовать это решение, потому что setRGB() и getRGB() BufferedImage могут быть слишком медленными для огромных изображений (исправьте меня, если я ошибаюсь).

Я прочитал несколько сообщений здесь, чтобы получить массив byte [] (такой как здесь), так что каждый пиксель представлен 3 или 4 ячейками массива, содержащего красный, зеленый и синий (с дополнительным альфа-значением, когда есть 4 ячейки), что очень полезно и легко для меня использовать. Вот код, который я использую для получения этого массива (хранящегося в классе PixelArray, который я создал):

public PixelArray(BufferedImage image)
{
    width = image.getWidth();
    height = image.getHeight();
    DataBuffer toArray = image.getRaster().getDataBuffer();
    array = ((DataBufferByte) toArray).getData();
    hasAlphaChannel = image.getAlphaRaster() != null;
}

Моя большая проблема заключается в том, что я не нашел эффективного метода для преобразования этого байтового [] массива в новое изображение, если бы я хотел преобразовать изображение (например, удалить значения синего/зеленого цвета и сохранить только красный один). Я пробовал эти решения:

1) Создание объекта DataBuffer, затем создание SampleModel, чтобы, наконец, создать WritableRaster, а затем BufferedImage (с дополнительными объектами ColorModel и Hashtable). Это не сработало, потому что я, видимо, не располагаю всей необходимой информацией (я не знаю, что такое Hashtable для конструктора BufferedImage()).

2) Использование ByteArrayInputStream. Это не сработало, потому что массив байтов, ожидаемый с ByteArrayInputStream, не имеет ничего общего с моим: он представляет каждый байт файла, а не каждый компонент каждого пикселя (с 3-4 байтами для каждого пикселя)...

Может кто-нибудь мне помочь?

4b9b3361

Ответ 1

Попробуйте следующее:

private BufferedImage createImageFromBytes(byte[] imageData) {
    ByteArrayInputStream bais = new ByteArrayInputStream(imageData);
    try {
        return ImageIO.read(bais);
    } catch (IOException e) {
        throw new RuntimeException(e);
    }
}

Ответ 2

Я попробовал подходы, упомянутые здесь, но почему-то никто из них не работал. Использование ByteArrayInputStream и ImageIO.read(...) возвращает null, тогда как byte[] array = ((DataBufferByte) image.getRaster().getDataBuffer()).getData(); возвращает копию данных изображения, а не прямую ссылку на них (см. Также здесь).

Однако для меня это работало. Предположим, что размеры и тип данных изображения известны. Пусть также byte[] srcbuf - буфер данных, подлежащих преобразованию в BufferedImage. Тогда,

  • Создайте пустое изображение, например

    img=new BufferedImage(width, height, BufferedImage.TYPE_3BYTE_BGR);
    
  • Преобразуйте массив данных в Raster и используйте setData для заполнения изображения, т.е.

    img.setData(Raster.createRaster(img.getSampleModel(), new DataBufferByte(srcbuf, srcbuf.length), new Point() ) );
    

Ответ 3

BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_3BYTE_BGR);
byte[] array = ((DataBufferByte) image.getRaster().getDataBuffer()).getData();
System.arrayCopy(pixelArray, 0, array, 0, array.length);

Этот метод имеет тенденцию выходить из синхронизации при попытке использовать объект Graphics полученного изображения. Если вам нужно нарисовать поверх своего изображения, создайте второе изображение (которое может быть устойчивым, т.е. Не создаваться каждый раз, но повторно используется) и drawImage первый на нем.

Ответ 4

Несколько человек подтвердили комментарий, что принятый ответ неверен.

Если принятый ответ не работает, возможно, потому, что Image.IO не поддерживает тип изображения, которое вы пытаетесь (например, tiff).

Добавьте это в свой pom (aka put jai-imageio-core-1.3.1.jar в вашем пути к классам):

    <!-- https://mvnrepository.com/artifact/com.github.jai-imageio/jai-imageio-core -->
    <dependency>
        <groupId>com.github.jai-imageio</groupId>
        <artifactId>jai-imageio-core</artifactId>
        <version>1.3.1</version>
    </dependency>

Чтобы добавить поддержку для:

  • WBMP
  • ВМР
  • PCX
  • рпт
  • сырые
  • размолвка
  • gif (написать)

Вы можете просмотреть список поддерживаемых форматов с помощью:

     for(String format : ImageIO.getReaderFormatNames())
        System.out.println(format);

Обратите внимание, что вам нужно только отбросить, например, jai-imageio-core-1.3.1.jar в свой путь к классам, чтобы он работал.

Другие проекты, которые добавляют дополнительную поддержку, включают: