2013-06-09 6 views
1

Я пытаюсь отправить BufferedImage поверх сокета, я делаю это, преобразовывая изображение в byte[], а затем отправляю его после кодирования в Base64. Я отправляю более 2 BufferedImages, один из них «полный», другой - прозрачный на 50%. Проблема, с которой я столкнулась, заключается в том, что когда они приходят, второе изображение все еще визуально прозрачно, но когда я получаю массив данных через Raster, он был изменен.ByteArrayOutput/InputStream на прозрачном изображении

Я сделал небольшой тестовый код, чтобы продемонстрировать проблему;

 BufferedImage levelBufferedOriginal = ... 
     BufferedImage backgroundBufferedOriginal = ... 

     byte[] levelDataOriginal = ((DataBufferByte) levelBufferedOriginal.getRaster().getDataBuffer()).getData(); 
     byte[] backgroundDataOriginal = ((DataBufferByte) backgroundBufferedOriginal.getRaster().getDataBuffer()).getData(); 

     ByteArrayOutputStream baos = new ByteArrayOutputStream(); 
     byte[] temp = null, temp2=null; 
     try { 
      ImageIO.write(levelBufferedOriginal, "png", baos); 
      baos.flush(); 
      temp = baos.toByteArray(); 
      baos.close(); 

      baos=new ByteArrayOutputStream(); 
      ImageIO.write(backgroundBufferedOriginal, "png", baos); 
      baos.flush(); 
      temp2 = baos.toByteArray(); 
      baos.close(); 
     } catch (IOException e1) { 
      e1.printStackTrace(); 
     } 



     BufferedImage levelBufferedNew = null; 
     BufferedImage backgroundBufferedNew = null; 

     try { 
      levelBufferedNew = ImageIO.read(new ByteArrayInputStream(temp)); 
      backgroundBufferedNew = ImageIO.read(new ByteArrayInputStream(temp2)); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 

     byte[] levelDataNew = ((DataBufferByte) levelBufferedNew.getRaster().getDataBuffer()).getData(); 
     byte[] backgroundDataNew = ((DataBufferByte) backgroundBufferedNew.getRaster().getDataBuffer()).getData(); 


     System.out.println("LEVEL: " + Arrays.equals(levelDataOriginal, levelDataNew)); 
     System.out.println("BACKGROUND: " + Arrays.equals(backgroundDataOriginal, backgroundDataNew)); 

Все, что я здесь делать, просто преобразование BufferedImage в byte[], а затем обратно, и сравнить данные, которые я получаю от DataBufferByte. Выход

УРОВЕНЬ: ложные

ПРЕДПОСЫЛКИ: истинная

Фон «полный» образ, и уровень является тот, с некоторыми прозрачными пикселями.

Если общая идея неправильная, я хотел бы услышать другую, все, что я хочу, - это точно воссоздать 2 bufferedImages.

+0

Изображения визуально отличаются? Как вы говорите, изображения полупрозрачны. Возможно, что конвертирование PNG-кодирования/декодирования изменяет значения для некоторых прозрачных пикселей, не затрагивая визуальные изображения. См. Премультипликацию альфы против не-преувеличенной. – haraldK

+0

Изображения визуально одинаковы. Проблема, которую я получаю, - это когда я начинаю редактировать данные уровня изображения (levelDataNew) до «-1» (чтобы установить прозрачный пиксель), вместо этого он становится черным, поэтому я не вижу фона позади него. В то время как редактирование уровняDataOriginal будет устанавливать пиксель прозрачным. – Limon

+0

Что вы подразумеваете под "-1"? 0xFF? Полностью прозрачный пиксель равен 0x0, а полностью непрозрачный - 0xff. Кроме того, премультиплексовое состояние важно, если вы пытаетесь «угасать» то, что у вас уже «исчезло» (сделано прозрачным). – haraldK

ответ

1

редактировать: То, что мы установили до сих пор:

  • Изображения (как до, так и после) являются TYPE_BYTE_INDEXED (13) с IndexColorModel (цвет карты)
  • перед тем изображение имеет прозрачный цвет в цветовой карте, с индексом 255 (который является значением -1 в массиве байтов, поскольку Java использует подписанные byte s). После этого изображение имеет другое значение, что не является прозрачным.
  • Изображения сериализируются/десериализации в формате PNG, используя ImageIO
  • Изображения визуально равны, но необработанные данные пикселов (массив) отличается

что приводит к выводу о том, что ImageIO PNGImageWriter перезаписывает записи в цветовой карте при записи, что приводит к различным пиксельным данным/цветовой карте.

В основном это оставляет нас с двумя вариантами:

  1. Serialize данные изображения по-другому, чтобы обеспечить данные карты цветов/пиксел не изменяется. Можно отправить массив данных пикселей, а также массив цветных карт и высоту/ширину изображения, а затем повторно создать изображение точно на клиенте. Это довольно немного кода, и, вероятно, он охватывает другие вопросы о SO.

  2. Не полагайтесь на то, что данные о пикселях/цветовых картах одинаковы. Используйте значение ((IndexColorModel) levelBufferedNew.getColorModel()).getTransparentPixel(), чтобы проверить/установить прозрачность вместо жестко заданного значения -1. Это не требует значительных изменений кода.

Примечание: Эти решения будут работать только для изображений TYPE_BYTE_INDEXED (13).

Для более общего (но возможно более медленного) подхода используйте код в исходном ответе для установки прозрачных частей и используйте (levelBufferedNew.getRGB(x, y) >> 24) == 0 для проверки прозрачности. Это должно работать даже для TYPE_INT_ARGB или TYPE_4BYTE_ABGR.

оригинальный ответ:

Вместо возился с изображением на уровне массива байтов, то почему бы не попробовать использовать обычный Java2D? ;-)

Что-то вроде:

Graphics2D g = levelBufferedNew.createGraphics(); 
try { 
    g.setComposite(AlphaComposite.Clear); 
    g.fillOval(x, y, w, h); // The area you want to make transparent 
} 
finally { 
    g.dispose(); 
} 

... должно работать.

PS: Поскольку изображения используются IndexColorModel, вы можете использовать getTransparentPixel(), чтобы получить прозрачный индекс пикселя, вместо того чтобы полагаться на то, что он имеет определенный индекс (-1/255). Затем вы можете манипулировать на уровне массива байтов. ;-)

+0

Другая причина использования байтового массива - это то, что я могу выяснить, где находится земля; Я могу спросить, есть ли пиксель (x, y)! = -1, а затем его сплошная земля, чтобы объект столкнулся с ним, и это является сердцем проблемы, несмотря на то, что изображения выглядят одинаково, данные массива байтов испорчены вверх. Ячейки, которые в оригинале равны -1, не являются -1 в передаваемой версии. – Limon

+0

Вы принимаете -1 (или действительно 255) означает прозрачность. Это не так. Любое значение может быть прозрачным. Вы должны запросить IndexColorModel. – haraldK

+0

Ну, я отредактировал изображение в Paint.NET, а прозрачные части изображения имели значение -1. Если он имеет значение! = -1, я вижу цвет, как только я меняю его на -1, его уходит. – Limon

Смежные вопросы