net.d53dev.dslfy.web.service.GifService.java Source code

Java tutorial

Introduction

Here is the source code for net.d53dev.dslfy.web.service.GifService.java

Source

package net.d53dev.dslfy.web.service;

import org.springframework.stereotype.Service;
import org.w3c.dom.Node;

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.*;
import java.awt.image.BufferedImage;
import java.awt.image.IndexColorModel;
import java.awt.image.WritableRaster;
import java.io.OutputStream;
import java.util.List;

/**
 * Created by davidsere on 18/11/15.
 * Adapted from http://riven8192.blogspot.ro/2010/02/image-java-animated-gifs.html
 * under BSD-3 license
 */
@Service
public class GifService {

    public class GifFrame {
        public static final String NONE = "none";
        public static final String DO_NOT_DISPOSE = "doNotDispose";
        public static final String RESTORE_TO_BGCOLOR = "restoreToBackgroundColor";
        public static final String RESTORE_TO_PREVIOUS = "restoreToPrevious";

        public final BufferedImage img;
        public final long delay; // in millis
        public final String disposalMethod;

        public GifFrame(BufferedImage img, long delay) {
            this(img, delay, NONE);
        }

        public GifFrame(BufferedImage img, long delay, String disposalMethod) {
            this.img = img;
            this.delay = delay;
            this.disposalMethod = disposalMethod;
        }
    }

    public BufferedImage convertRGBAToGIF(BufferedImage src, int transColor) {
        BufferedImage dst = new BufferedImage(src.getWidth(), src.getHeight(), BufferedImage.TYPE_BYTE_INDEXED);
        Graphics g = dst.getGraphics();
        g.setColor(new Color(transColor));
        g.fillRect(0, 0, dst.getWidth(), dst.getHeight());
        {
            IndexColorModel indexedModel = (IndexColorModel) dst.getColorModel();
            WritableRaster raster = dst.getRaster();
            int sample = raster.getSample(0, 0, 0);
            int size = indexedModel.getMapSize();
            byte[] rr = new byte[size];
            byte[] gg = new byte[size];
            byte[] bb = new byte[size];
            indexedModel.getReds(rr);
            indexedModel.getGreens(gg);
            indexedModel.getBlues(bb);
            IndexColorModel newModel = new IndexColorModel(8, size, rr, gg, bb, sample);
            dst = new BufferedImage(newModel, raster, dst.isAlphaPremultiplied(), null);
        }
        dst.createGraphics().drawImage(src, 0, 0, null);
        return dst;
    }

    public void saveAnimatedGIF(OutputStream out, List<GifFrame> frames, int loopCount) throws Exception {
        ImageWriter iw = ImageIO.getImageWritersByFormatName("gif").next();

        ImageOutputStream ios = ImageIO.createImageOutputStream(out);
        iw.setOutput(ios);
        iw.prepareWriteSequence(null);

        int p = 0;
        for (GifFrame frame : frames) {
            ImageWriteParam iwp = iw.getDefaultWriteParam();
            IIOMetadata metadata = iw.getDefaultImageMetadata(new ImageTypeSpecifier(frame.img), iwp);
            this.configureGIFFrame(metadata, String.valueOf(frame.delay / 10L), p++, frame.disposalMethod,
                    loopCount);
            IIOImage ii = new IIOImage(frame.img, null, metadata);
            iw.writeToSequence(ii, null);
        }

        iw.endWriteSequence();
        ios.close();
    }

    private void configureGIFFrame(IIOMetadata meta, String delayTime, int imageIndex, 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();
        }

        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);
        }
    }
}