Проблема с преобразованием ArrayList BufferedImages в GIF с использованием GifSequenceWriter - Java

Я пытаюсь скрыть сообщение в.gif для стеганографического проекта. Я преобразовал входной GIF в ArrayList из BufferedImages и применил мой алгоритм стеганографии. Но я столкнулся с проблемой преобразования ArrayList BufferedImages обратно в.gif. Я использовал этот класс GifSequenceWriter для преобразования массива BufferedImages в новый.gif после получения исходной задержки между кадрами из метаданных исходного изображения gif.

  File encoded_img = new File("output.gif");
  ImageOutputStream output = new FileImageOutputStream(encoded_img);
  GifSequenceWriter writer =  new GifSequenceWriter(output, frames.get(0).getType(), delayTimeMS, true);
  writer.writeToSequence(frames.get(0));
  for(int k=1; k<frames.size()-1; k++) {
    writer.writeToSequence(frames.get(k));
  }
  writer.close();
  output.close();

Но полученный.gif выглядит очень плохо, и я сохранил отдельные кадры с алгоритмом стеганографии и без него, и они выглядят хорошо. Вы можете посмотреть пример исходного изображения, 10 сохраненных кадров и полученный.gif здесь.

Есть ли лучший способ для создания.gifs в Java? Заранее спасибо.

1 ответ

Решение

Есть проблема с GifSequenceWriter при использовании палитры изображений (BufferedImage.TYPE_BYTE_INDEXED с IndexColorModel). Это создаст метаданные на основе цветовой палитры 216 по умолчанию ( безопасная веб-палитра), которая явно отличается от цветов на изображении.

Проблемные линии в GifSequenceWriter:

ImageTypeSpecifier imageTypeSpecifier = ImageTypeSpecifier.createFromBufferedImageType(imageType);
imageMetaData = gifWriter.getDefaultImageMetadata(imageTypeSpecifier, imageWriteParam);

Вместо этого метаданные должны основываться на цветовой палитре в индексной цветовой модели вашего изображения. Но хорошая новость в том, что без нее все работает нормально.

Вы можете просто использовать:

GifSequenceWriter writer = new GifSequenceWriter(output, BufferedImage.TYPE_INT_ARGB, delayTimeMS, true);

... и автор автоматически создаст палитру по мере необходимости из ваших фактических данных изображения.

Анимированный GIF, созданный с кодом выше


Также возможно исправить GifSequenceWriter, чтобы принять ImageTypeSpecifier вместо int imageType однако, это будет работать, только если все кадры используют одну и ту же палитру, я думаю:

public GifSequenceWriter(
        ImageOutputStream outputStream,
        ImageTypeSpecifier imageTypeSpecifier, 
        int timeBetweenFramesMS,
        boolean loopContinuously) throws IIOException, IOException {
    // my method to create a writer
    gifWriter = getWriter();
    imageWriteParam = gifWriter.getDefaultWriteParam();

    imageMetaData = gifWriter.getDefaultImageMetadata(imageTypeSpecifier, imageWriteParam);

    // ... rest of the method unchanged. 

Использование:

ColorModel cm = firstImage.getColorModel();
ImageTypeSpecifier imageType = new ImageTypeSpecifier(cm, cm.createCompatibleSampleModel(1, 1));
GifSequenceWriter writer = new GifSequenceWriter(output, imageType, delayTimeMS, true);
Другие вопросы по тегам