我目前正在创建一个导入图像的程序(使用Java),然后使用这些图像创建.gif文件。
我的大多数图片都有透明背景,alpha设置为0。
我目前的问题是在我将一系列8个图像转换为一个.gif后,它们相互流血。换句话说,在绘制下一帧之前,.gif不会在图像上重新绘制。因此,例如,如果苹果从树上掉落,它将看起来像红色条纹,直到.gif循环。
我认为自己对Java非常了不起,但我在搜索互联网档案时找到的脚本远远超出了我的联盟。考虑我的8本Java书籍都没有涵盖IIOMETANODE。互联网上的资源有限。所以我不确定iio的功能是什么。
这是脚本:
import javax.imageio.*;
import javax.imageio.metadata.*;
import javax.imageio.stream.*;
import java.awt.image.*;
import java.io.*;
import java.util.Iterator;
public class GifCreator {
private ImageWriter gifWriter;
private ImageWriteParam imageWriteParam;
private IIOMetadata imageMetaData;
public GifCreator(){}
/**
* Creates a new GifSequenceWriter
*
* @param output the ImageOutputStream to be written to
* @param imgType one of the imageTypes specified in BufferedImage
* @param frameTime the time between frames in miliseconds
* @param loop wether the gif should loop repeatedly
* @throws IIOException if no gif ImageWriters are found
*
*/
public GifCreator(ImageOutputStream output, int imgType, int frameTime, boolean loop)
{
try {
gifWriter = getWriter();
imageWriteParam = gifWriter.getDefaultWriteParam();
ImageTypeSpecifier imageTypeSpecifier = ImageTypeSpecifier.createFromBufferedImageType(imgType);
imageMetaData = gifWriter.getDefaultImageMetadata(imageTypeSpecifier, imageWriteParam);
String metaFormatName = imageMetaData.getNativeMetadataFormatName();
IIOMetadataNode root = (IIOMetadataNode) imageMetaData.getAsTree(metaFormatName);
IIOMetadataNode graphicsControlExtensionNode = getNode(root, "GraphicControlExtension");
graphicsControlExtensionNode.setAttribute("disposalMethod", "none");
graphicsControlExtensionNode.setAttribute("userInputFlag", "FALSE");
graphicsControlExtensionNode.setAttribute("transparentColorFlag", "FALSE");
graphicsControlExtensionNode.setAttribute("delayTime", Integer.toString(frameTime / 10));
graphicsControlExtensionNode.setAttribute("transparentColorIndex", "0");
IIOMetadataNode appEntensionsNode = getNode(root, "ApplicationExtensions");
IIOMetadataNode child = new IIOMetadataNode("ApplicationExtension");
child.setAttribute("applicationID", "NETSCAPE");
child.setAttribute("authenticationCode", "2.0");
int aLoop = loop ? 0 : 1;
child.setUserObject(new byte[]{ 0x1, (byte) (aLoop & 0xFF), (byte) ((aLoop >> 8) & 0xFF)});
appEntensionsNode.appendChild(child);
imageMetaData.setFromTree(metaFormatName, root);
gifWriter.setOutput(output);
gifWriter.prepareWriteSequence(null);
} catch (Exception e) {
e.printStackTrace();
}
}
private void writeToSequence(RenderedImage img) throws IOException
{
gifWriter.writeToSequence(new IIOImage(img, null, imageMetaData), imageWriteParam);
}
/**
* Close this GifSequenceWriter object. This does not close the underlying
* stream, just finishes off the GIF.
*/
public void close() throws IOException
{
gifWriter.endWriteSequence();
}
/**
* Returns the first available GIF ImageWriter using
* ImageIO.getImageWritersBySuffix("gif").
*
* @return a GIF ImageWriter object
* @throws IIOException if no GIF image writers are returned
*/
private static ImageWriter getWriter() throws IIOException
{
Iterator<ImageWriter> iter = ImageIO.getImageWritersBySuffix("gif");
if (!iter.hasNext()) {
throw new IIOException("No GIF Image Writers Exist");
} else {
return iter.next();
}
}
/**
* Returns an existing child node, or creates and returns a new child node (if
* the requested node does not exist).
*
* @param rootNode the <tt>IIOMetadataNode</tt> to search for the child node.
* @param nodeName the name of the child node.
*
* @return the child node, if found or a new node created with the given name.
*/
private static IIOMetadataNode getNode(IIOMetadataNode rootNode, String nodeName)
{
int nNodes = rootNode.getLength();
for (int i = 0; i < nNodes; i++) {
if (rootNode.item(i).getNodeName().compareToIgnoreCase(nodeName) == 0)
return((IIOMetadataNode) rootNode.item(i));
}
IIOMetadataNode node = new IIOMetadataNode(nodeName);
rootNode.appendChild(node);
return(node);
}
public GifCreator(BufferedImage[] imgs, String path)
{
if (imgs.length <= 1)
return;
// Grabs the first BufferedImage from the array.
BufferedImage first = imgs[0];
try {
// Creates a new BufferedOutputStream with the incoming path.
ImageOutputStream output = new FileImageOutputStream(new File(path));
// Creates a gif sequence with the type of the first image, .1 second
// between frames, which loops continuously
GifCreator writer = new GifCreator(output, first.getType(), 100, true);
// write out the first image to our sequence...
writer.writeToSequence((RenderedImage) first);
for (int i = 1; i < imgs.length; i++) {
BufferedImage next = imgs[i];
writer.writeToSequence(next);
}
writer.close();
output.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
我再一次试图将.gif从出血图像中一起改变。我尝试在两者之间创建一个缓冲区BufferedImage,但这是一个失败。
答案 0 :(得分:1)
基本上,您需要更改disposalMethod
...
graphicsControlExtensionNode.setAttribute("disposalMethod", "restoreToBackgroundColor");
graphicsControlExtensionNode.setAttribute("userInputFlag", "FALSE");
graphicsControlExtensionNode.setAttribute(
"transparentColorFlag",
"TRUE");
假设您要添加的每个图像都是完整的图像,并且图像的优化“添加”
请查看GIF Animation and Disposal Methods以获取更多详情,如果您真的喜欢冒险,GIF specification和Image :: Java Animated GIFs (with transparant pixel disposal modes)列出了可能的处理方法,那么您可以玩一下看看有什么用......