Had fight with maven. It decided to block HTTP repositories.
[meviz.git] / src / main / java / eu / svjatoslav / meviz / htmlindexer / metadata / fileTypes / Picture.java
1 /*
2  * Meviz - Various tools collection to work with multimedia.
3  * Copyright (C) 2012 -- 2019, Svjatoslav Agejenko, svjatoslav@svjatoslav.eu
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of version 3 of the GNU Lesser General Public License
7  * or later as published by the Free Software Foundation.
8  */
9
10 package eu.svjatoslav.meviz.htmlindexer.metadata.fileTypes;
11
12 import eu.svjatoslav.commons.file.FilePathParser;
13 import eu.svjatoslav.commons.file.IOHelper;
14 import eu.svjatoslav.meviz.htmlindexer.Constants;
15 import eu.svjatoslav.meviz.htmlindexer.GifSequenceWriter;
16 import eu.svjatoslav.meviz.htmlindexer.ImageFormatError;
17 import eu.svjatoslav.meviz.htmlindexer.Utils;
18 import eu.svjatoslav.meviz.htmlindexer.metadata.Dimension;
19
20 import javax.imageio.*;
21 import javax.imageio.stream.FileImageOutputStream;
22 import javax.imageio.stream.ImageInputStream;
23 import javax.imageio.stream.ImageOutputStream;
24 import javax.swing.*;
25 import java.awt.*;
26 import java.awt.image.BufferedImage;
27 import java.awt.image.FilteredImageSource;
28 import java.awt.image.ImageFilter;
29 import java.awt.image.ImageProducer;
30 import java.io.File;
31 import java.io.IOException;
32 import java.util.ArrayList;
33 import java.util.Iterator;
34 import java.util.List;
35
36 import static eu.svjatoslav.meviz.htmlindexer.Utils.getBufferedImage;
37 import static java.awt.image.BufferedImage.TYPE_INT_RGB;
38
39 public class Picture extends AbstractFile {
40
41     private static final long serialVersionUID = -4156533490858298387L;
42     /**
43      * Picture dimensions.
44      */
45     private Dimension dimensions;
46
47     public Picture(final File parentDirectory, final String fileName)
48             throws Exception {
49         super(parentDirectory, fileName);
50     }
51
52     private static void ensureNonzeroImageArea(final java.awt.Dimension result) {
53         if (result.width < 1)
54             result.width = 1;
55         if (result.height < 1)
56             result.height = 1;
57     }
58
59     /**
60      * Actual returned target thumbnail size will be adjusted from desired one
61      * by attempting to generate as large as possible thumbnail, while not
62      * exceeding provided thumbnail width and height, and preserving aspect
63      * ratio of original image.
64      */
65     private static java.awt.Dimension getTargetThumbnailDimension(
66             final java.awt.Dimension originalImageDimension,
67             final java.awt.Dimension desiredTargetDimension) {
68
69         final double thumbWidthToHeightRatio = (double) desiredTargetDimension.width
70                 / (double) desiredTargetDimension.height;
71         final double inputImageWidthToHeightRatio = (double) originalImageDimension.width
72                 / (double) originalImageDimension.height;
73
74         if (thumbWidthToHeightRatio < inputImageWidthToHeightRatio) {
75
76             final java.awt.Dimension result = new java.awt.Dimension(
77                     desiredTargetDimension.width,
78                     (int) (desiredTargetDimension.width / inputImageWidthToHeightRatio));
79
80             ensureNonzeroImageArea(result);
81
82             return result;
83         } else {
84
85             final java.awt.Dimension result = new java.awt.Dimension(
86                     (int) (desiredTargetDimension.height * inputImageWidthToHeightRatio),
87                     desiredTargetDimension.height);
88
89             ensureNonzeroImageArea(result);
90
91             return result;
92         }
93     }
94
95     /**
96      * Propose list of thumbnail dimensions.
97      */
98     public static List<Dimension> getThumbnailDimensions(Dimension current) {
99         final ArrayList<Dimension> result = new ArrayList<>();
100         result.add(current);
101
102         while (current.getArea() > 1000000) {
103             current = current.getScaled(0.5d);
104             result.add(current);
105         }
106
107         return result;
108
109     }
110
111     public static void makeThumbnail(final File inputFile,
112                                      final File outputFile,
113                                      final java.awt.Dimension preferredTargetDimensions) {
114
115         String fileExtension = FilePathParser.getFileExtension(inputFile.getName());
116
117         try {
118             if ("gif".equalsIgnoreCase(fileExtension))
119                 makeGifThumbnail(inputFile, outputFile, preferredTargetDimensions);
120             else
121                 makeJpegThumbnail(inputFile, outputFile, preferredTargetDimensions);
122         } catch (final Exception exception) {
123             System.out.println(exception.toString());
124             exception.printStackTrace();
125         }
126     }
127
128     private static void makeJpegThumbnail(File inputFile, File outputFile, java.awt.Dimension preferredTargetDimensions)
129             throws IOException, ImageFormatError {
130
131         final BufferedImage inputImage = getBufferedImage(inputFile);
132
133         final java.awt.Dimension sourceImageDimension = new java.awt.Dimension(
134                 inputImage.getWidth(), inputImage.getHeight());
135
136         final java.awt.Dimension targetDimensions = getTargetThumbnailDimension(
137                 sourceImageDimension, preferredTargetDimensions);
138
139
140         final Image scaledImage = scaleImage(inputImage,
141                 targetDimensions.width, targetDimensions.height);
142
143         final BufferedImage bufferedImage = new BufferedImage(
144                 scaledImage.getWidth(null), scaledImage.getHeight(null),
145                 TYPE_INT_RGB);
146
147         final Graphics2D g = bufferedImage.createGraphics();
148         g.drawImage(scaledImage, 0, 0, null);
149         g.dispose();
150
151
152
153         ImageOutputStream  ios =  ImageIO.createImageOutputStream(outputFile);
154         Iterator<ImageWriter> iter = ImageIO.getImageWritersByFormatName("webp");
155         ImageWriter writer = iter.next();
156         ImageWriteParam iwp = writer.getDefaultWriteParam();
157         iwp.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
158         iwp.setCompressionType("Lossy");
159         iwp.setCompressionQuality(0.8f);
160
161         writer.setOutput(ios);
162         writer.write(null, new IIOImage(bufferedImage,null,null),iwp);
163         writer.dispose();
164     }
165
166     private static void makeGifThumbnail(
167             File inputFile, File outputFile, java.awt.Dimension preferredTargetDimensions) throws IOException {
168         ImageIcon imageIcon = new ImageIcon(IOHelper.getFileContents(inputFile));
169
170         final java.awt.Dimension sourceImageDimension = new java.awt.Dimension(
171                 imageIcon.getIconWidth(), imageIcon.getIconHeight());
172
173         System.out.println("Source image dimensions:" + sourceImageDimension);
174
175         final java.awt.Dimension targetDimensions = getTargetThumbnailDimension(
176                 sourceImageDimension, preferredTargetDimensions);
177
178         System.out.println("Desired target image dimensions:" + targetDimensions);
179
180         ImageReader reader = ImageIO.getImageReadersByFormatName("gif").next();
181         ImageInputStream stream = ImageIO.createImageInputStream(inputFile);
182         reader.setInput(stream);
183
184         Utils.ImageFrame[] frames = Utils.readGIF(reader);
185         for (Utils.ImageFrame frame : frames) {
186             Image scaleImage = scaleImage(frame.image, targetDimensions.width, targetDimensions.height);
187             BufferedImage bImage = new BufferedImage(
188                     targetDimensions.width, targetDimensions.height, BufferedImage.TYPE_INT_ARGB);
189             Graphics2D bGr = bImage.createGraphics();
190             bGr.drawImage(scaleImage, 0, 0, null);
191             bGr.dispose();
192             frame.image = bImage;
193         }
194
195         ImageOutputStream output = new FileImageOutputStream(outputFile);
196
197         GifSequenceWriter writer =
198                 new GifSequenceWriter(output, frames[0].image.getType(), frames[0].getDelay(), true);
199
200         writer.writeToSequence(frames[0].image);
201         for (int i = 1; i < frames.length; i++) {
202             BufferedImage nextImage = frames[i].image;
203             writer.writeToSequence(nextImage);
204         }
205
206         writer.close();
207         output.close();
208     }
209
210     /**
211      * @return new image scaled to desired dimensions
212      */
213     private static Image scaleImage(final Image srcImage, final int width,
214                                     final int height) {
215
216         final ImageFilter filter = new java.awt.image.AreaAveragingScaleFilter(
217                 width, height);
218
219         final ImageProducer prod = new FilteredImageSource(
220                 srcImage.getSource(), filter);
221
222         final Image newImage = Toolkit.getDefaultToolkit().createImage(prod);
223
224         return new ImageIcon(newImage).getImage();
225     }
226
227     private String computeThumbnailHash(final Dimension targetDimension) {
228
229         // compute new thumbnails hash number
230         final String forMagicHash = fileName + " "
231                 + targetDimension.width + " "
232                 + targetDimension.height + " "
233                 + getFileLength() + " "
234                 + Constants.THUMBNAIL_VERSION;
235
236         return Utils.getStringCrcAsHex(forMagicHash);
237     }
238
239     public Dimension getDimensions() {
240         return dimensions;
241     }
242
243     /**
244      * Get thumbnail file name for this image and desired thumbnail dimensions
245      * relative to designated thumbnails directory within parent directory.
246      */
247     public String getRelativeThumbnailFileName(final Dimension targetDimension) {
248         String thumbnailExtension = "gif".equalsIgnoreCase(getFileExtension()) ? "gif" : "webp";
249
250         return FilePathParser.getFileNameWithoutExtension(fileName) + " ("
251                 + computeThumbnailHash(targetDimension) + ")." + thumbnailExtension;
252     }
253
254     @Override
255     public void updateFileMetadata(final File parentDirectory) throws Exception {
256         final BufferedImage image = getBufferedImage(getFile(parentDirectory));
257         dimensions = new Dimension(image.getWidth(), image.getHeight());
258     }
259
260 }