-
Notifications
You must be signed in to change notification settings - Fork 223
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
8 changed files
with
2,453 additions
and
0 deletions.
There are no files selected for viewing
214 changes: 214 additions & 0 deletions
214
src/org/loklak/visualization/graphics/AnimationGIF.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,214 @@ | ||
/** | ||
* AnimationGIF | ||
* Copyright 2010 by Michael Christen | ||
* First released 20.11.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 <http://www.gnu.org/licenses/>. | ||
*/ | ||
|
||
package org.loklak.visualization.graphics; | ||
|
||
import java.awt.Color; | ||
import java.awt.Graphics; | ||
import java.awt.image.BufferedImage; | ||
import java.awt.image.RenderedImage; | ||
import java.io.ByteArrayOutputStream; | ||
import java.io.File; | ||
import java.io.FileOutputStream; | ||
import java.io.IOException; | ||
import java.util.Iterator; | ||
import java.util.Random; | ||
|
||
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 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"; | ||
private final static String aesNodeName = "ApplicationExtensions"; | ||
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; | ||
private ImageWriter writer; | ||
private ImageWriteParam iwp; | ||
private ImageOutputStream ios; | ||
private ByteArrayOutputStream baos; | ||
|
||
/** | ||
* create a gif animation producer | ||
* @param loops - number of loops for the animated images. -1 = no loops; 0 = indefinitely loops; else: number of loops | ||
*/ | ||
public AnimationGIF(int loops) { | ||
this.counter = 0; | ||
this.loops = loops; | ||
this.ios = null; | ||
this.writer = null; | ||
|
||
this.baos = new ByteArrayOutputStream(); | ||
Iterator<ImageWriter> writerIterator = ImageIO.getImageWritersByFormatName("GIF"); | ||
this.writer = writerIterator.next(); // com.sun.media.imageioimpl.plugins.gif.GIFImageWriter, com.sun.imageio.plugins.gif.GIFImageWriter | ||
this.ios = new MemoryCacheImageOutputStream(baos); | ||
this.writer.setOutput(ios); | ||
this.iwp = writer.getDefaultWriteParam(); | ||
} | ||
|
||
/** | ||
* add an image to the animation | ||
* @param image the image | ||
* @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 delayMillis, int transparencyColorIndex) throws IOException { | ||
if (this.counter == 0) { | ||
iiom = writer.getDefaultImageMetadata(ImageTypeSpecifier.createFromRenderedImage(image), iwp); | ||
writer.prepareWriteSequence(writer.getDefaultStreamMetadata(iwp)); | ||
} | ||
if (this.counter == 0 && loops >= 0) { | ||
IIOMetadata imageMetadata2 = writer.getDefaultImageMetadata(ImageTypeSpecifier.createFromRenderedImage(image), iwp); | ||
try { | ||
setMetadata(imageMetadata2, delayMillis, transparencyColorIndex); | ||
setLoops(imageMetadata2, this.loops); | ||
writer.writeToSequence(new IIOImage(image, null, imageMetadata2), iwp); | ||
} catch (final IIOInvalidTreeException e) { | ||
throw new IOException(e.getMessage()); | ||
} | ||
} else try { | ||
setMetadata(iiom, delayMillis, transparencyColorIndex); | ||
writer.writeToSequence(new IIOImage(image, null, iiom), iwp); | ||
} catch (final IIOInvalidTreeException e) { | ||
throw new IOException(e.getMessage()); | ||
} | ||
this.counter++; | ||
} | ||
|
||
/** | ||
* produce the gif image as byte array | ||
* @return the gif image | ||
*/ | ||
public byte[] get() { | ||
if (ios != null) try { | ||
ios.close(); | ||
ios = null; | ||
} catch (final IOException e) {} | ||
if (writer != null) { | ||
writer.dispose(); | ||
writer = null; | ||
} | ||
return baos.toByteArray(); | ||
} | ||
|
||
private static void setMetadata(IIOMetadata metaData, int delayMillis, int transparencyColorIndex) throws IIOInvalidTreeException { | ||
Node tree = metaData.getAsTree(formatName); | ||
NodeList nodeList = tree.getChildNodes(); | ||
Node gceNode = null; | ||
for (int i = 0, len = nodeList.getLength(); i < len; i++) { | ||
Node curNode = nodeList.item(i); | ||
if (curNode.getNodeName().equals(gceNodeName)) {gceNode = curNode; break;} | ||
} | ||
if (gceNode == null) throw new IIOInvalidTreeException("Invalid image metadata, could not find " + gceNodeName + "node.", null, tree); | ||
Node delayNode = gceNode.getAttributes().getNamedItem(delayNodeName); | ||
if (delayNode == null) { | ||
delayNode = tree.getOwnerDocument().createAttribute(delayNodeName); | ||
gceNode.appendChild(delayNode); | ||
} | ||
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); | ||
} | ||
|
||
/** | ||
* set number of loops for this animation | ||
* @param metaData | ||
* @param loops - 0 = loop continuously; 1-65535 = a specific number of loops | ||
* @throws IIOInvalidTreeException | ||
*/ | ||
private static void setLoops(IIOMetadata metaData, int loops) throws IIOInvalidTreeException { | ||
Node tree = metaData.getAsTree(formatName); | ||
IIOMetadataNode aes = new IIOMetadataNode(aesNodeName); | ||
IIOMetadataNode ae = new IIOMetadataNode(aeNodeName); | ||
ae.setAttribute("applicationID", "NETSCAPE"); | ||
ae.setAttribute("authenticationCode", "2.0"); | ||
ae.setUserObject(new byte[]{0x1, (byte) (loops & 0xFF), (byte) ((loops >> 8) & 0xFF)}); | ||
aes.appendChild(ae); | ||
tree.appendChild(aes); | ||
metaData.setFromTree(formatName, tree); | ||
} | ||
|
||
/** | ||
* test image generator | ||
*/ | ||
private static RenderedImage generateTestImage(int width, int height, Random r, double angle) { | ||
BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); | ||
Graphics g = img.getGraphics(); | ||
g.setColor(Color.white); g.fillRect(0, 0, width, height); g.setColor(Color.BLUE); | ||
int x = width / 2; | ||
int y = height / 2; | ||
int radius = Math.min(x, y); | ||
g.drawLine(x, y, x + (int) (radius * Math.cos(angle)), y + (int) (radius * Math.sin(angle))); | ||
g.drawString("giftest", r.nextInt(width), r.nextInt(height)); | ||
return img; | ||
} | ||
|
||
public static void main(String[] args) { | ||
System.setProperty("java.awt.headless", "true"); // go into headless awt mode | ||
Random r = new Random(System.currentTimeMillis()); | ||
int framescount = 100; | ||
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, 0); | ||
} | ||
FileOutputStream fos = new FileOutputStream(new File("/tmp/giftest.gif")); | ||
fos.write(generator.get()); | ||
fos.close(); | ||
} catch (final IOException e) { | ||
e.printStackTrace(); | ||
} | ||
} | ||
} |
97 changes: 97 additions & 0 deletions
97
src/org/loklak/visualization/graphics/AnimationPlotter.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
/** | ||
* AnimationPlotter | ||
* Copyright 2013 by Michael Christen | ||
* First released 9.9.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 <http://www.gnu.org/licenses/>. | ||
*/ | ||
|
||
package org.loklak.visualization.graphics; | ||
|
||
import java.awt.image.BufferedImage; | ||
import java.io.File; | ||
import java.io.FileOutputStream; | ||
import java.io.IOException; | ||
import java.util.ArrayList; | ||
import java.util.List; | ||
|
||
import javax.imageio.ImageIO; | ||
import javax.swing.ImageIcon; | ||
import javax.swing.JFrame; | ||
import javax.swing.JLabel; | ||
|
||
public class AnimationPlotter { | ||
|
||
public static class Frame { | ||
BufferedImage image; | ||
int delayMillis; | ||
public Frame(BufferedImage image, int delayMillis) { | ||
this.image = image; | ||
this.delayMillis = delayMillis; | ||
} | ||
} | ||
|
||
private final List<Frame> frames; | ||
|
||
|
||
public AnimationPlotter() { | ||
this.frames = new ArrayList<Frame>(); | ||
} | ||
|
||
public void addFrame(final BufferedImage image, final int delayMillis) { | ||
this.frames.add(new Frame(image, delayMillis)); | ||
} | ||
|
||
|
||
public void save(final File path, final String filestub, final String type) throws IOException { | ||
assert path.isDirectory(); | ||
for (int i = 0; i < this.frames.size(); i++) { | ||
Frame frame = this.frames.get(i); | ||
File file = new File(path, filestub + "_" + intformat(i) + '.' + type); | ||
final FileOutputStream fos = new FileOutputStream(file); | ||
ImageIO.write(frame.image, type, fos); | ||
fos.close(); | ||
} | ||
} | ||
|
||
private String intformat(final int i) { | ||
String n = Integer.toString(i); | ||
while (n.length() < 6) n = '0' + n; | ||
return n; | ||
} | ||
|
||
/** | ||
* show the images as stream of JFrame on desktop | ||
*/ | ||
public void show() { | ||
JFrame f = new JFrame(); | ||
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); | ||
f.setVisible(true); | ||
JLabel label = null; | ||
while (true) { | ||
for (int i = 0; i < this.frames.size(); i++) { | ||
Frame frame = this.frames.get(i); | ||
if (label == null) { | ||
label = new JLabel(new ImageIcon(frame.image)); | ||
f.getContentPane().add(label); | ||
f.pack(); | ||
} else { | ||
label.getGraphics().drawImage(frame.image,0,0, label); | ||
} | ||
try {Thread.sleep(frame.delayMillis);} catch (InterruptedException e) {} | ||
} | ||
} | ||
} | ||
} |
Oops, something went wrong.