From c1a2175fbcf2b489ba7eb709f4c2f1a68de3c0e4 Mon Sep 17 00:00:00 2001 From: Michael Peter Christen Date: Sun, 21 Apr 2013 12:29:05 +0200 Subject: [PATCH] added transparency to gif image animation and the integration to the YaCy httpd for on-the-fly generated gifs (including animated gifs) --- source/net/yacy/kelondro/util/ByteBuffer.java | 6 +++ .../net/yacy/peers/graphics/EncodedImage.java | 37 ++++++++++++++++- .../yacy/server/http/HTTPDFileHandler.java | 2 +- .../net/yacy/visualization/AnimationGIF.java | 40 +++++++++++++------ 4 files changed, 71 insertions(+), 14 deletions(-) diff --git a/source/net/yacy/kelondro/util/ByteBuffer.java b/source/net/yacy/kelondro/util/ByteBuffer.java index e4c6d2681..ae9475af8 100644 --- a/source/net/yacy/kelondro/util/ByteBuffer.java +++ b/source/net/yacy/kelondro/util/ByteBuffer.java @@ -52,6 +52,12 @@ public final class ByteBuffer extends OutputStream { this.offset = 0; } + public ByteBuffer(final byte[] bb) { + this.buffer = bb; + this.length = bb.length; + this.offset = 0; + } + public ByteBuffer(final String s) { this.buffer = UTF8.getBytes(s); this.length = this.buffer.length; diff --git a/source/net/yacy/peers/graphics/EncodedImage.java b/source/net/yacy/peers/graphics/EncodedImage.java index 9fa99fdd3..960412b2e 100644 --- a/source/net/yacy/peers/graphics/EncodedImage.java +++ b/source/net/yacy/peers/graphics/EncodedImage.java @@ -1,17 +1,52 @@ +/** + * EncodedImage + * Copyright 2010 by Michael Christen + * First released 28.07.2010 at http://yacy.net + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program in the file lgpl21.txt + * If not, see . + */ + package net.yacy.peers.graphics; +import java.io.ByteArrayOutputStream; +import java.io.IOException; + import net.yacy.kelondro.util.ByteBuffer; +import net.yacy.visualization.AnimationGIF; import net.yacy.visualization.RasterPlotter; public class EncodedImage { private ByteBuffer image; private String extension; - + public EncodedImage(final RasterPlotter sourceImage, final String targetExt) { this.image = "png".equals(targetExt) ? sourceImage.exportPng() : RasterPlotter.exportImage(sourceImage.getImage(), targetExt); this.extension = targetExt; } + public EncodedImage(final AnimationGIF sourceImage) { + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + try { + bos.write(sourceImage.get()); + bos.close(); + } catch (IOException e) { + } + this.image = new ByteBuffer(bos.toByteArray()); + this.extension = "gif"; + } + public ByteBuffer getImage() { return this.image; } diff --git a/source/net/yacy/server/http/HTTPDFileHandler.java b/source/net/yacy/server/http/HTTPDFileHandler.java index 07df304de..30ae40d5c 100644 --- a/source/net/yacy/server/http/HTTPDFileHandler.java +++ b/source/net/yacy/server/http/HTTPDFileHandler.java @@ -574,7 +574,7 @@ public final class HTTPDFileHandler { servletProperties templatePatterns = null; Date targetDate; - if ((targetClass != null) && (path.endsWith("png"))) { + if ((targetClass != null) && ((path.endsWith("png") || path.endsWith("gif")))) { // call an image-servlet to produce an on-the-fly - generated image Object img = null; requestHeader.put(HeaderFramework.CONNECTION_PROP_CLIENTIP, (String) conProp.get(HeaderFramework.CONNECTION_PROP_CLIENTIP)); diff --git a/source/net/yacy/visualization/AnimationGIF.java b/source/net/yacy/visualization/AnimationGIF.java index 6d52596f8..ee8750a50 100644 --- a/source/net/yacy/visualization/AnimationGIF.java +++ b/source/net/yacy/visualization/AnimationGIF.java @@ -2,10 +2,6 @@ * AnimationGIF * Copyright 2010 by Michael Christen * First released 20.11.2010 at http://yacy.net - * - * $LastChangedDate$ - * $LastChangedRevision$ - * $LastChangedBy$ * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -49,7 +45,10 @@ import javax.imageio.stream.MemoryCacheImageOutputStream; import org.w3c.dom.Node; import org.w3c.dom.NodeList; - +/* + * for a GIF Image Metadata Format Specification, see: + * http://docs.oracle.com/javase/6/docs/api/javax/imageio/metadata/doc-files/gif_metadata.html + */ public class AnimationGIF { private final static String formatName = "javax_imageio_gif_image_1.0"; @@ -57,6 +56,8 @@ public class AnimationGIF { private final static String aeNodeName = "ApplicationExtension"; private final static String gceNodeName = "GraphicControlExtension"; private final static String delayNodeName = "delayTime"; + private final static String transparencyFlagNodeName = "transparentColorFlag"; + private final static String transparencyIndexNodeName = "transparentColorIndex"; private int counter, loops; private IIOMetadata iiom; @@ -86,10 +87,11 @@ public class AnimationGIF { /** * add an image to the animation * @param image the image - * @param duration the frame time of the image in milliseconds + * @param delayMillis the frame time of the image in milliseconds + * @param transparencyColorIndex the index of the transparent color, -1 if not used * @throws IOException */ - public void addImage(RenderedImage image, int duration) throws IOException { + public void addImage(RenderedImage image, int delayMillis, int transparencyColorIndex) throws IOException { if (this.counter == 0) { iiom = writer.getDefaultImageMetadata(ImageTypeSpecifier.createFromRenderedImage(image), iwp); writer.prepareWriteSequence(writer.getDefaultStreamMetadata(iwp)); @@ -97,14 +99,14 @@ public class AnimationGIF { if (this.counter == 0 && loops >= 0) { IIOMetadata imageMetadata2 = writer.getDefaultImageMetadata(ImageTypeSpecifier.createFromRenderedImage(image), iwp); try { - setDelay(imageMetadata2, duration); + setMetadata(imageMetadata2, delayMillis, transparencyColorIndex); setLoops(imageMetadata2, this.loops); writer.writeToSequence(new IIOImage(image, null, imageMetadata2), iwp); } catch (IIOInvalidTreeException e) { throw new IOException(e.getMessage()); } } else try { - setDelay(iiom, duration); + setMetadata(iiom, delayMillis, transparencyColorIndex); writer.writeToSequence(new IIOImage(image, null, iiom), iwp); } catch (IIOInvalidTreeException e) { throw new IOException(e.getMessage()); @@ -128,7 +130,7 @@ public class AnimationGIF { return baos.toByteArray(); } - private static void setDelay(IIOMetadata metaData, int delay) throws IIOInvalidTreeException { + private static void setMetadata(IIOMetadata metaData, int delayMillis, int transparencyColorIndex) throws IIOInvalidTreeException { Node tree = metaData.getAsTree(formatName); NodeList nodeList = tree.getChildNodes(); Node gceNode = null; @@ -142,7 +144,21 @@ public class AnimationGIF { delayNode = tree.getOwnerDocument().createAttribute(delayNodeName); gceNode.appendChild(delayNode); } - delayNode.setNodeValue(Integer.valueOf(delay / 10).toString()); + delayNode.setNodeValue(Integer.valueOf(delayMillis / 10).toString()); + if (transparencyColorIndex >= 0) { + Node transparencyFlagNode = gceNode.getAttributes().getNamedItem(transparencyFlagNodeName); + if (transparencyFlagNode == null) { + transparencyFlagNode = tree.getOwnerDocument().createAttribute(transparencyFlagNodeName); + gceNode.appendChild(transparencyFlagNode); + } + transparencyFlagNode.setNodeValue("TRUE"); + Node transparencyIndexNode = gceNode.getAttributes().getNamedItem(transparencyIndexNodeName); + if (transparencyIndexNode == null) { + transparencyIndexNode = tree.getOwnerDocument().createAttribute(transparencyIndexNodeName); + gceNode.appendChild(transparencyIndexNode); + } + transparencyIndexNode.setNodeValue(Integer.valueOf(transparencyColorIndex).toString()); + } metaData.setFromTree(formatName, tree); } @@ -186,7 +202,7 @@ public class AnimationGIF { AnimationGIF generator = new AnimationGIF(0); try { for (int i = 0; i < framescount; i++) { - generator.addImage(generateTestImage(320, 160, r, i * 2 * Math.PI / framescount), 10); + generator.addImage(generateTestImage(320, 160, r, i * 2 * Math.PI / framescount), 10, 0); } FileOutputStream fos = new FileOutputStream(new File("/tmp/giftest.gif")); fos.write(generator.get());