All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.bloodshura.x.assets.image.gif.GifImage Maven / Gradle / Ivy

There is a newer version: 1.1.0
Show newest version
/*
 * Copyright (c) 2013-2018, João Vitor Verona Biazibetti - All Rights Reserved
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see .
 *
 * https://www.github.com/BloodShura
 */

package com.github.bloodshura.x.assets.image.gif;

import com.github.bloodshura.x.collection.list.impl.XArrayList;
import com.github.bloodshura.x.io.file.File;
import org.w3c.dom.Node;

import javax.annotation.Nonnull;
import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageTypeSpecifier;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import javax.imageio.metadata.IIOInvalidTreeException;
import javax.imageio.metadata.IIOMetadata;
import javax.imageio.metadata.IIOMetadataNode;
import javax.imageio.stream.ImageOutputStream;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.OutputStream;

public class GifImage extends XArrayList {
	public void save(@Nonnull File file) throws IOException {
		try (OutputStream output = file.newOutputStream()) {
			ImageOutputStream imageOutput = ImageIO.createImageOutputStream(output);

			if (imageOutput == null) {
				throw new IOException("ImageIO::createImageOutputStream returned null");
			}

			ImageWriter writer = ImageIO.getImageWritersByFormatName("gif").next();
			int index = 0;

			writer.setOutput(imageOutput);
			writer.prepareWriteSequence(null);

			for (GifFrame frame : this) {
				BufferedImage image = frame.getImage().getImage();
				ImageWriteParam writeParam = writer.getDefaultWriteParam();
				IIOMetadata ioMetadata = writer.getDefaultImageMetadata(new ImageTypeSpecifier(image), writeParam);
				IIOImage ioImage = new IIOImage(image, null, ioMetadata);

				configureGIFFrame(ioMetadata, String.valueOf(frame.getDelay() / 10L), index++, frame.getDisposalMethod().getMethodName(), frame.getLoopCount());
				writer.writeToSequence(ioImage, null);
			}

			writer.endWriteSequence();
		}
	}

	/**
	 * @author riven8192
	 */
	protected static void configureGIFFrame(@Nonnull IIOMetadata meta, @Nonnull String delayTime, int imageIndex, @Nonnull String disposalMethod, int loopCount) {
		String metaFormat = meta.getNativeMetadataFormatName();

		if (!"javax_imageio_gif_image_1.0".equals(metaFormat)) {
			throw new IllegalArgumentException("Unfamiliar gif metadata format: " + metaFormat);
		}

		Node root = meta.getAsTree(metaFormat);
		Node child = root.getFirstChild();

		while (child != null) {
			if ("GraphicControlExtension".equals(child.getNodeName())) {
				break;
			}

			child = child.getNextSibling();
		}

		if (child != null && child instanceof IIOMetadataNode) {
			IIOMetadataNode gce = (IIOMetadataNode) child;

			gce.setAttribute("userDelay", "FALSE");
			gce.setAttribute("delayTime", delayTime);
			gce.setAttribute("disposalMethod", disposalMethod);
		}

		if (imageIndex == 0) {
			IIOMetadataNode aes = new IIOMetadataNode("ApplicationExtensions");
			IIOMetadataNode ae = new IIOMetadataNode("ApplicationExtension");

			ae.setAttribute("applicationID", "NETSCAPE");
			ae.setAttribute("authenticationCode", "2.0");

			byte[] uo = new byte[] { 0x1, (byte) (loopCount & 0xFF), (byte) (loopCount >> 8 & 0xFF) };

			ae.setUserObject(uo);
			aes.appendChild(ae);
			root.appendChild(aes);
		}

		try {
			meta.setFromTree(metaFormat, root);
		}
		catch (IIOInvalidTreeException e) {
			throw new Error(e);
		}
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy