Needs refactoring.
--- /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();
+ }
+
+}
package eu.svjatoslav.meviz.htmlindexer;
-class ImageFormatError extends Exception {
+public class ImageFormatError extends Exception {
private static final long serialVersionUID = 4037233564457071385L;
import eu.svjatoslav.meviz.htmlindexer.layouts.Layout;
import eu.svjatoslav.meviz.htmlindexer.layouts.MixedLayout;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import javax.imageio.ImageReader;
+import javax.imageio.metadata.IIOMetadata;
+import javax.imageio.metadata.IIOMetadataNode;
+import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
+import java.util.ArrayList;
import java.util.HashSet;
import java.util.zip.CRC32;
// throw new RuntimeException(e);
// }
}
+
+ public static ImageFrame[] readGIF(ImageReader reader) throws IOException {
+ ArrayList<ImageFrame> frames = new ArrayList<ImageFrame>(2);
+
+ int width = -1;
+ int height = -1;
+
+ IIOMetadata metadata = reader.getStreamMetadata();
+ if (metadata != null) {
+ IIOMetadataNode globalRoot = (IIOMetadataNode) metadata.getAsTree(metadata.getNativeMetadataFormatName());
+
+ NodeList globalScreenDescriptor = globalRoot.getElementsByTagName("LogicalScreenDescriptor");
+
+ if (globalScreenDescriptor != null && globalScreenDescriptor.getLength() > 0) {
+ IIOMetadataNode screenDescriptor = (IIOMetadataNode) globalScreenDescriptor.item(0);
+
+ if (screenDescriptor != null) {
+ width = Integer.parseInt(screenDescriptor.getAttribute("logicalScreenWidth"));
+ height = Integer.parseInt(screenDescriptor.getAttribute("logicalScreenHeight"));
+ }
+ }
+ }
+
+ BufferedImage master = null;
+ Graphics2D masterGraphics = null;
+
+ for (int frameIndex = 0;; frameIndex++) {
+ BufferedImage image;
+ try {
+ image = reader.read(frameIndex);
+ } catch (IndexOutOfBoundsException io) {
+ break;
+ }
+
+ if (width == -1 || height == -1) {
+ width = image.getWidth();
+ height = image.getHeight();
+ }
+
+ IIOMetadataNode root = (IIOMetadataNode) reader.getImageMetadata(frameIndex).getAsTree("javax_imageio_gif_image_1.0");
+ IIOMetadataNode gce = (IIOMetadataNode) root.getElementsByTagName("GraphicControlExtension").item(0);
+ int delay = Integer.valueOf(gce.getAttribute("delayTime"));
+ String disposal = gce.getAttribute("disposalMethod");
+
+ int x = 0;
+ int y = 0;
+
+ if (master == null) {
+ master = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
+ masterGraphics = master.createGraphics();
+ masterGraphics.setBackground(new Color(0, 0, 0, 0));
+ } else {
+ NodeList children = root.getChildNodes();
+ for (int nodeIndex = 0; nodeIndex < children.getLength(); nodeIndex++) {
+ Node nodeItem = children.item(nodeIndex);
+ if (nodeItem.getNodeName().equals("ImageDescriptor")) {
+ NamedNodeMap map = nodeItem.getAttributes();
+ x = Integer.valueOf(map.getNamedItem("imageLeftPosition").getNodeValue());
+ y = Integer.valueOf(map.getNamedItem("imageTopPosition").getNodeValue());
+ }
+ }
+ }
+ masterGraphics.drawImage(image, x, y, null);
+
+ BufferedImage copy = new BufferedImage(master.getColorModel(), master.copyData(null), master.isAlphaPremultiplied(), null);
+ frames.add(new ImageFrame(copy, delay, disposal));
+
+ if (disposal.equals("restoreToPrevious")) {
+ BufferedImage from = null;
+ for (int i = frameIndex - 1; i >= 0; i--) {
+ if (!frames.get(i).getDisposal().equals("restoreToPrevious") || frameIndex == 0) {
+ from = frames.get(i).image;
+ break;
+ }
+ }
+
+ master = new BufferedImage(from.getColorModel(), from.copyData(null), from.isAlphaPremultiplied(), null);
+ masterGraphics = master.createGraphics();
+ masterGraphics.setBackground(new Color(0, 0, 0, 0));
+ } else if (disposal.equals("restoreToBackgroundColor")) {
+ masterGraphics.clearRect(x, y, image.getWidth(), image.getHeight());
+ }
+ }
+ reader.dispose();
+
+ return frames.toArray(new ImageFrame[frames.size()]);
+ }
+
+ public static class ImageFrame {
+ private final int delay;
+ public BufferedImage image;
+ private final String disposal;
+
+ public ImageFrame(BufferedImage image, int delay, String disposal) {
+ this.image = image;
+ this.delay = delay;
+ this.disposal = disposal;
+ }
+
+ public int getDelay() {
+ return delay;
+ }
+
+ public String getDisposal() {
+ return disposal;
+ }
+ }
}
import static eu.svjatoslav.meviz.htmlindexer.Constants.SUPPORTED_IMAGE_EXTENSIONS;
import static eu.svjatoslav.meviz.htmlindexer.Constants.SUPPORTED_VIDEO_EXTENSIONS;
+import static java.util.Arrays.stream;
public abstract class AbstractIndexer {
public static boolean isImage(final String fileExtension) {
- for (final String ext : SUPPORTED_IMAGE_EXTENSIONS)
- if (ext.equals(fileExtension))
- return true;
- return false;
+ return stream(SUPPORTED_IMAGE_EXTENSIONS)
+ .anyMatch(ext -> ext.equals(fileExtension));
}
public static boolean isVideo(final String fileExtension) {
package eu.svjatoslav.meviz.htmlindexer.metadata.fileTypes;
import eu.svjatoslav.commons.file.FilePathParser;
+import eu.svjatoslav.commons.file.IOHelper;
import eu.svjatoslav.meviz.htmlindexer.Constants;
+import eu.svjatoslav.meviz.htmlindexer.GifSequenceWriter;
+import eu.svjatoslav.meviz.htmlindexer.ImageFormatError;
import eu.svjatoslav.meviz.htmlindexer.Utils;
import eu.svjatoslav.meviz.htmlindexer.metadata.Dimension;
import javax.imageio.ImageIO;
+import javax.imageio.ImageReader;
+import javax.imageio.stream.FileImageOutputStream;
+import javax.imageio.stream.ImageInputStream;
+import javax.imageio.stream.ImageOutputStream;
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.awt.image.FilteredImageSource;
import java.awt.image.ImageFilter;
import java.awt.image.ImageProducer;
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.OutputStream;
+import java.io.*;
import java.util.ArrayList;
import java.util.List;
final File outputFile,
final java.awt.Dimension preferredTargetDimensions) {
+ String fileExtension = FilePathParser.getFileExtension(inputFile.getName());
+
try {
+ if ("gif".equalsIgnoreCase(fileExtension))
+ makeGifThumbnail(inputFile, outputFile, preferredTargetDimensions);
+ else
+ makeJpegThumbnail(inputFile, outputFile, preferredTargetDimensions);
+ } catch (final Exception exception) {
+ System.out.println(exception.toString());
+ exception.printStackTrace();
+ }
+ }
+
+ private static void makeJpegThumbnail(File inputFile, File outputFile, java.awt.Dimension preferredTargetDimensions)
+ throws IOException, ImageFormatError {
final BufferedImage inputImage = getBufferedImage(inputFile);
ImageIO.write(bufferedImage, "jpg", out);
out.close();
+ }
- } catch (final Exception exception) {
- System.out.println(exception.toString());
- exception.printStackTrace();
+ private static void makeGifThumbnail(
+ File inputFile, File outputFile, java.awt.Dimension preferredTargetDimensions) throws IOException {
+ ImageIcon imageIcon = new ImageIcon(IOHelper.getFileContents(inputFile));
+
+ final java.awt.Dimension sourceImageDimension = new java.awt.Dimension(
+ imageIcon.getIconWidth(), imageIcon.getIconHeight());
+
+ System.out.println("Source image dimensions:" + sourceImageDimension);
+
+ final java.awt.Dimension targetDimensions = getTargetThumbnailDimension(
+ sourceImageDimension, preferredTargetDimensions);
+
+ System.out.println("Desired target image dimensions:" + targetDimensions);
+
+ FileInputStream fiStream = new FileInputStream( inputFile );
+
+ ImageReader reader = ImageIO.getImageReadersByFormatName("gif").next();
+ ImageInputStream stream = ImageIO.createImageInputStream(inputFile);
+ reader.setInput(stream);
+
+ Utils.ImageFrame[] frames = Utils.readGIF(reader);
+ for (Utils.ImageFrame frame : frames) {
+ Image scaleImage = scaleImage(frame.image, targetDimensions.width, targetDimensions.height);
+ BufferedImage bimage = new BufferedImage(
+ targetDimensions.width, targetDimensions.height, BufferedImage.TYPE_INT_ARGB);
+ Graphics2D bGr = bimage.createGraphics();
+ bGr.drawImage(scaleImage, 0, 0, null);
+ bGr.dispose();
+ frame.image = bimage;
}
+
+ ImageOutputStream output = new FileImageOutputStream(outputFile );
+
+ GifSequenceWriter writer =
+ new GifSequenceWriter( output, frames[0].image.getType(), frames[0].getDelay(), true );
+
+ writer.writeToSequence( frames[0].image );
+ for ( int i = 1; i < frames.length; i++ ) {
+ BufferedImage nextImage = frames[i].image;
+ writer.writeToSequence( nextImage );
+ }
+
+ writer.close();
+ output.close();
}
/**