使用 GifSequenceWriter 将 BufferedImages 的 ArrayList 转换为 GIF 时出现问题 - Java
Issue with converting an ArrayList of BufferedImages to a GIF using GifSequenceWriter - Java
我正在尝试在隐写术项目的 .gif 文件中隐藏一条消息。
我已将输入的 gif 转换为 BufferedImages 的 ArrayList,并应用了我的隐写术算法。
但是,我遇到了将 BufferedImages 的 ArrayList 转换回 .gif 的问题。
在从原始 gif 图像元数据中获取帧之间的原始延迟后,我使用此 GifSequenceWriter class 将 BufferedImages 数组转换为新的 .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 here.
在 java 中是否有更好的创建 .gif 的方法?
提前致谢。
使用调色板图像时 GifSequenceWriter
存在问题(BufferedImage.TYPE_BYTE_INDEXED
和 IndexColorModel
)。这将基于 默认 216 调色板 (web safe palette)创建元数据,这与图像中的颜色明显不同。
GifSequenceWriter
中有问题的行:
ImageTypeSpecifier imageTypeSpecifier = ImageTypeSpecifier.createFromBufferedImageType(imageType);
imageMetaData = gifWriter.getDefaultImageMetadata(imageTypeSpecifier, imageWriteParam);
相反,元数据应基于图像索引颜色模型中的调色板。但好消息是,没有它也能正常工作。
您可以简单地使用:
GifSequenceWriter writer = new GifSequenceWriter(output, BufferedImage.TYPE_INT_ARGB, delayTimeMS, true);
...编写器会根据您的实际图像数据根据需要自动创建调色板。
也可以修复 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);
我正在尝试在隐写术项目的 .gif 文件中隐藏一条消息。 我已将输入的 gif 转换为 BufferedImages 的 ArrayList,并应用了我的隐写术算法。 但是,我遇到了将 BufferedImages 的 ArrayList 转换回 .gif 的问题。 在从原始 gif 图像元数据中获取帧之间的原始延迟后,我使用此 GifSequenceWriter class 将 BufferedImages 数组转换为新的 .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 here.
在 java 中是否有更好的创建 .gif 的方法? 提前致谢。
使用调色板图像时 GifSequenceWriter
存在问题(BufferedImage.TYPE_BYTE_INDEXED
和 IndexColorModel
)。这将基于 默认 216 调色板 (web safe palette)创建元数据,这与图像中的颜色明显不同。
GifSequenceWriter
中有问题的行:
ImageTypeSpecifier imageTypeSpecifier = ImageTypeSpecifier.createFromBufferedImageType(imageType);
imageMetaData = gifWriter.getDefaultImageMetadata(imageTypeSpecifier, imageWriteParam);
相反,元数据应基于图像索引颜色模型中的调色板。但好消息是,没有它也能正常工作。
您可以简单地使用:
GifSequenceWriter writer = new GifSequenceWriter(output, BufferedImage.TYPE_INT_ARGB, delayTimeMS, true);
...编写器会根据您的实际图像数据根据需要自动创建调色板。
也可以修复 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);