【发布时间】:2021-11-20 23:32:38
【问题描述】:
我想创建一个逻辑屏幕描述符大于我的 gif 图像序列中的任何图像的 GIF。 gif 中的每个图像都将修改其顶部和左侧偏移量。这是我的代码,看起来它应该可以工作,但它没有
void test() throws IOException {
Image image1 = textToImage ("m",12.0 );
Image image2 = textToImage("n", 24.0);
Image[] images = {image2, image1};
String[] imageTopOffset = {"6", "30"};
String[] imageLeftOffset = {"6", "36"};
ImageWriter iw = ImageIO.getImageWritersByFormatName("gif").next();
ImageWriteParam params = iw.getDefaultWriteParam();
int type = ((BufferedImage)getRenderedImage(image1)).getType();
ImageTypeSpecifier imageTypeSpecifier = ImageTypeSpecifier.createFromBufferedImageType(type);
IIOMetadata metadata = iw.getDefaultImageMetadata(imageTypeSpecifier, params);
IIOMetadataNode root = (IIOMetadataNode)metadata.getAsTree(metadata.getNativeMetadataFormatName());
IIOMetadataNode lsdNode = getNode(root, "LogicalScreenDescriptor");
lsdNode.setAttribute("logicalScreenHeight", "100");
lsdNode.setAttribute("logicalScreenWidth", "75");
IIOMetadataNode graphicsControlExtensionNode = getNode(root, "GraphicControlExtension");
graphicsControlExtensionNode.setAttribute("disposalMethod", "none");
graphicsControlExtensionNode.setAttribute("userInputFlag", "FALSE");
graphicsControlExtensionNode.setAttribute("transparentColorFlag", "FALSE");
graphicsControlExtensionNode.setAttribute("delayTime", "100");
graphicsControlExtensionNode.setAttribute("transparentColorIndex", "0");
IIOMetadataNode commentsNode = getNode(root, "CommentExtensions");
commentsNode.setAttribute("CommentExtension", "Created by: http://example.com");
IIOMetadataNode appExtensionsNode = getNode(root, "ApplicationExtensions");
IIOMetadataNode child = new IIOMetadataNode("ApplicationExtension");
child.setAttribute("applicationID", "NETSCAPE");
child.setAttribute("authenticationCode", "2.0");
boolean loop = true;
int loopContinuously = loop ? 0 : 1;
child.setUserObject(new byte[]{ 0x1, (byte) (loopContinuously & 0xFF), (byte) ((loopContinuously >> 8) & 0xFF)});
appExtensionsNode.appendChild(child);
ByteArrayOutputStream os = new ByteArrayOutputStream();
ImageOutputStream ios = ImageIO.createImageOutputStream(os);
iw.setOutput(ios);
iw.prepareWriteSequence(metadata);
int i = 0;
for (Image image : images) {
graphicsControlExtensionNode = getNode(root, "GraphicControlExtension");
graphicsControlExtensionNode.setAttribute("delayTime", "50");
IIOMetadataNode imageDescriptorNode = getNode(root, "ImageDescriptor");
imageDescriptorNode.setAttribute("imageLeftPosition", imageLeftOffset[i]);
imageDescriptorNode.setAttribute("imageTopPosition", imageTopOffset[i]);
imageDescriptorNode.setAttribute("imageWidth", String.valueOf(image.getWidth()));
imageDescriptorNode.setAttribute("imageHeight", String.valueOf(image.getHeight()));
imageDescriptorNode.setAttribute("interlaceFlag", "FALSE");
IIOImage ii = new IIOImage(getRenderedImage(image), null, metadata);
iw.writeToSequence(ii, params);
i++;
}
iw.endWriteSequence();
ios.close();
byte[] gifContent = os.toByteArray();
os.close();
File outputFile = new File("test.gif");
try (FileOutputStream outputStream = new FileOutputStream(outputFile)) {
outputStream.write(gifContent);
outputStream.close();
}
}
private WritableImage textToImage(String text, Double size) {
Text t = new Text();
t.setFont(getFont("Calibi",
"NORMAL",
"REGULAR",
size));
t.setStroke(Color.BLACK);
t.setText(text);
Scene scene = new Scene(new StackPane(t));
return t.snapshot(null, null);
}
IIOMetadataNode getNode(IIOMetadataNode rootNode, String name) {
NodeList childNodes = rootNode.getChildNodes();
for (int i=0; i<childNodes.getLength(); i++) {
if (childNodes.item(i).getNodeName().equals(name) ) {
return (IIOMetadataNode)childNodes.item(i);
}
}
// no child node with the given name found, create one!
IIOMetadataNode metadataNode = new IIOMetadataNode(name);
rootNode.appendChild(metadataNode);
return metadataNode;
}
Font getFont(String fontname, String fontWeight, String fontPosture, double size) {
FontPosture posture = FontPosture.valueOf(fontPosture);
FontWeight weight = FontWeight.valueOf(fontWeight);
Font font = Font.font (fontname, weight, posture, size);
return font;
}
public RenderedImage getRenderedImage(Image image) {
return SwingFXUtils.fromFXImage(image, null);
}
它生成的 gif 图像是序列中第一个图像的大小,即使我将 LogicalScreenDescriptor 设置为比写出的图像更大的大小。 gif 的实际大小是第一张图像的大小。另一个问题是 imageTopPosition 和 imageLeftPosition 没有被应用。
两张图片大小不同。生成两张图片,一张是字母m的12点图像,另一张是字母n的24点图像。
那么,如何制作更大的逻辑屏幕描述符以及如何更改图像描述符偏移量。尽管上面的代码看起来应该可以工作,但实际上并没有。我发现的大多数示例都假设 gif 中的所有图像都具有相同的大小,并且 gif 中后续图像的显示完全取代了之前的图像。
【问题讨论】:
-
调试时,我查看了 iw.canReplaceStreamMetadata() 并得到了 false 的值。这似乎可以解释为什么设置 LogicalScreenDiscriptor 参数无效。事实上,当我转储我制作的 gif 文件时,我也找不到我添加的评论。因此,“canReplaceStreamMetadata”是错误的事实也可以解释这一点。我不明白的是我必须改变或做些什么才能替换streamMetadata。我需要不同的 GIF ImageWriter 吗?
标签: image image-processing javafx gif