--- /dev/null
+package eu.svjatoslav.meviz.htmlindexer;
+
+import javax.imageio.*;
+import javax.imageio.metadata.IIOInvalidTreeException;
+import javax.imageio.metadata.IIOMetadata;
+import javax.imageio.metadata.IIOMetadataNode;
+import javax.imageio.stream.ImageOutputStream;
+import java.awt.image.RenderedImage;
+import java.io.IOException;
+
+/**
+ * Source: https://memorynotfound.com/generate-gif-image-java-delay-infinite-loop-example/
+ */
+public class GifSequenceWriter {
+ protected ImageWriter writer;
+ protected ImageWriteParam params;
+ protected IIOMetadata metadata;
+
+ public GifSequenceWriter(ImageOutputStream out, int imageType, int delay, boolean loop) throws IOException {
+ writer = ImageIO.getImageWritersBySuffix("gif").next();
+ params = writer.getDefaultWriteParam();
+
+ ImageTypeSpecifier imageTypeSpecifier = ImageTypeSpecifier.createFromBufferedImageType(imageType);
+ metadata = writer.getDefaultImageMetadata(imageTypeSpecifier, params);
+
+ configureRootMetadata(delay, loop);
+
+ writer.setOutput(out);
+ writer.prepareWriteSequence(null);
+ }
+
+ private void configureRootMetadata(int delay, boolean loop) throws IIOInvalidTreeException {
+ String metaFormatName = metadata.getNativeMetadataFormatName();
+ IIOMetadataNode root = (IIOMetadataNode) metadata.getAsTree(metaFormatName);
+
+ IIOMetadataNode graphicsControlExtensionNode = getNode(root, "GraphicControlExtension");
+ graphicsControlExtensionNode.setAttribute("disposalMethod", "none");
+ graphicsControlExtensionNode.setAttribute("userInputFlag", "FALSE");
+ graphicsControlExtensionNode.setAttribute("transparentColorFlag", "FALSE");
+ graphicsControlExtensionNode.setAttribute("delayTime", Integer.toString(delay / 10));
+ graphicsControlExtensionNode.setAttribute("transparentColorIndex", "0");
+
+ IIOMetadataNode commentsNode = getNode(root, "CommentExtensions");
+ commentsNode.setAttribute("CommentExtension", "Created by: https://memorynotfound.com");
+
+ IIOMetadataNode appExtensionsNode = getNode(root, "ApplicationExtensions");
+ IIOMetadataNode child = new IIOMetadataNode("ApplicationExtension");
+ child.setAttribute("applicationID", "NETSCAPE");
+ child.setAttribute("authenticationCode", "2.0");
+
+ int loopContinuously = loop ? 0 : 1;
+ child.setUserObject(new byte[]{ 0x1, (byte) (loopContinuously & 0xFF), (byte) ((loopContinuously >> 8) & 0xFF)});
+ appExtensionsNode.appendChild(child);
+ metadata.setFromTree(metaFormatName, root);
+ }
+
+ private static IIOMetadataNode getNode(IIOMetadataNode rootNode, String nodeName){
+ int nNodes = rootNode.getLength();
+ for (int i = 0; i < nNodes; i++){
+ if (rootNode.item(i).getNodeName().equalsIgnoreCase(nodeName)){
+ return (IIOMetadataNode) rootNode.item(i);
+ }
+ }
+ IIOMetadataNode node = new IIOMetadataNode(nodeName);
+ rootNode.appendChild(node);
+ return(node);
+ }
+
+ public void writeToSequence(RenderedImage img) throws IOException {
+ writer.writeToSequence(new IIOImage(img, null, metadata), params);
+ }
+
+ public void close() throws IOException {
+ writer.endWriteSequence();
+ }
+
+}