View Javadoc
1   package fr.ifremer.quadrige3.core.dao.technical;
2   
3   /*
4    * #%L
5    * Reef DB :: Core
6    * $Id:$
7    * $HeadURL:$
8    * %%
9    * Copyright (C) 2014 - 2015 Ifremer
10   * %%
11   * This program is free software: you can redistribute it and/or modify
12   * it under the terms of the GNU Affero General Public License as published by
13   * the Free Software Foundation, either version 3 of the License, or
14   * (at your option) any later version.
15   *
16   * This program is distributed in the hope that it will be useful,
17   * but WITHOUT ANY WARRANTY; without even the implied warranty of
18   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19   * GNU General Public License for more details.
20   *
21   * You should have received a copy of the GNU Affero General Public License
22   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
23   * #L%
24   */
25  
26  import com.google.common.collect.ImmutableList;
27  import fr.ifremer.quadrige3.core.exception.QuadrigeTechnicalException;
28  import org.apache.commons.io.FileUtils;
29  import org.apache.commons.io.FilenameUtils;
30  import org.apache.commons.logging.Log;
31  import org.apache.commons.logging.LogFactory;
32  import org.imgscalr.Scalr;
33  
34  import javax.imageio.ImageIO;
35  import javax.imageio.ImageReader;
36  import javax.imageio.stream.FileImageInputStream;
37  import javax.imageio.stream.ImageInputStream;
38  import java.awt.Dimension;
39  import java.awt.image.BufferedImage;
40  import java.io.File;
41  import java.io.IOException;
42  import java.util.Iterator;
43  import java.util.List;
44  
45  /**
46   * Utility class for Image manipulation
47   * <p/>
48   * Created by Ludovic on 31/07/2015.
49   */
50  public class Images {
51  
52      private static final String JPG_EXTENSION = "jpg";
53      private static final String JPEG_EXTENSION = "jpeg";
54      private static final String PNG_EXTENSION = "png";
55      public static final List<String> AVAILABLE_EXTENSION_LIST = ImmutableList.of(JPG_EXTENSION, JPEG_EXTENSION, PNG_EXTENSION);
56      /**
57       * Constant <code>AVAILABLE_EXTENSION="JPG_EXTENSION + '|' + JPEG_EXTENSION + "{trunked}</code>
58       */
59      public static final String AVAILABLE_EXTENSION = JPG_EXTENSION + '|' + JPEG_EXTENSION + '|' + PNG_EXTENSION;
60  
61      private static final Log LOG = LogFactory.getLog(Images.class);
62  
63      /**
64       * <p>getImageDimension.</p>
65       *
66       * @param imageFile a {@link File} object.
67       * @return a {@link Dimension} object.
68       */
69      public static Dimension getImageDimension(File imageFile) {
70  
71          Iterator<ImageReader> iterator = ImageIO.getImageReadersBySuffix(getImageFileExtension(imageFile));
72          if (iterator.hasNext()) {
73              ImageReader reader = iterator.next();
74              try {
75                  ImageInputStream stream = new FileImageInputStream(imageFile);
76                  reader.setInput(stream);
77                  int width = reader.getWidth(reader.getMinIndex());
78                  int height = reader.getHeight(reader.getMinIndex());
79                  return new Dimension(width, height);
80              } catch (IOException e) {
81                  LOG.warn("Error reading: " + imageFile.getAbsolutePath(), e);
82              } finally {
83                  reader.dispose();
84              }
85          }
86  
87          throw new QuadrigeTechnicalException("Not a known image file: " + imageFile.getAbsolutePath());
88      }
89  
90      /**
91       * <p>importAndPrepareImageFile.</p>
92       *
93       * @param inputFile a {@link File} object.
94       * @param targetDir a {@link File} object.
95       * @return a {@link File} object.
96       */
97      public static File importAndPrepareImageFile(File inputFile, File targetDir) {
98  
99          try {
100             // generate temp file name
101             String baseName = String.format("%s", System.currentTimeMillis());
102             String fileExtension = getImageFileExtension(inputFile);
103 
104             // copy to temp dir
105             File bigFile = new File(targetDir, String.format("%s.%s", baseName, fileExtension));
106             FileUtils.copyFile(inputFile, bigFile);
107 
108             prepareImageFile(bigFile);
109 
110             return bigFile;
111 
112         } catch (IOException ioe) {
113 
114             throw new QuadrigeTechnicalException(ioe);
115         }
116     }
117 
118     /**
119      * <p>prepareImageFile.</p>
120      *
121      * @param inputFile a {@link File} object.
122      */
123     public static void prepareImageFile(File inputFile) {
124 
125         String fileExtension = getImageFileExtension(inputFile);
126         try {
127 
128             // read input image
129             BufferedImage bigImage = ImageIO.read(inputFile);
130 
131             // resize to medium
132             ImageIO.write(Scalr.resize(bigImage, ImageType.DIAPO.getMaxSize()), fileExtension, getMediumImageFile(inputFile));
133 
134             // resize to small
135             ImageIO.write(Scalr.resize(bigImage, ImageType.THUMBNAIL.getMaxSize()), fileExtension, getSmallImageFile(inputFile));
136 
137         } catch (IOException ioe) {
138 
139             throw new QuadrigeTechnicalException(ioe);
140         }
141 
142     }
143 
144     public static File getMediumImageFile(File baseImageFile) {
145         return getImageFile(baseImageFile, ImageType.DIAPO);
146     }
147 
148     public static File getSmallImageFile(File baseImageFile) {
149         return getImageFile(baseImageFile, ImageType.THUMBNAIL);
150     }
151 
152     private static File getImageFile(File baseImageFile, ImageType imageType) {
153         return new File(baseImageFile.getParentFile(),
154                 String.format("%s%s.%s", getValidBaseName(baseImageFile), imageType.getSuffix(), getImageFileExtension(baseImageFile)));
155     }
156 
157     /**
158      * <p>loadImage.</p>
159      *
160      * @param inputFile         a {@link File} object.
161      * @param imageType         a ImageType.
162      * @param createIfNotExists a boolean.
163      * @return a {@link BufferedImage} object.
164      */
165     public static BufferedImage loadImage(File inputFile, ImageType imageType, boolean createIfNotExists) {
166 
167         if (!inputFile.exists()) {
168             LOG.warn("the image to load doesn't exist : " + inputFile);
169             return null;
170         }
171 
172         File targetFile = getImageFile(inputFile, imageType);
173 
174         if (targetFile.exists()) {
175             try {
176                 return ImageIO.read(targetFile);
177             } catch (IOException ioe) {
178                 throw new QuadrigeTechnicalException(ioe);
179             }
180         } else if (createIfNotExists && imageType != ImageType.BASE) {
181 
182             prepareImageFile(inputFile);
183 
184             return loadImage(inputFile, imageType, false);
185         }
186 
187         return null;
188 
189     }
190 
191     /**
192      * <p>deleteImage.</p>
193      *
194      * @param inputFile a {@link File} object.
195      */
196     public static void deleteImage(File inputFile) {
197 
198         getValidBaseName(inputFile);
199 
200         FileUtils.deleteQuietly(inputFile);
201 
202         deleteOtherImage(inputFile);
203     }
204 
205     /**
206      * <p>deleteOtherImage.</p>
207      *
208      * @param inputFile a {@link File} object.
209      */
210     public static void deleteOtherImage(File inputFile) {
211         FileUtils.deleteQuietly(getMediumImageFile(inputFile));
212         FileUtils.deleteQuietly(getSmallImageFile(inputFile));
213     }
214 
215     private static String getValidBaseName(File inputFile) {
216         String baseName = FilenameUtils.getBaseName(inputFile.getName());
217         if (baseName.endsWith(ImageType.THUMBNAIL.getSuffix()) || baseName.endsWith(ImageType.DIAPO.getSuffix())) {
218             throw new QuadrigeTechnicalException("inputFile name must not have the suffix " + ImageType.THUMBNAIL.getSuffix() + " or " + ImageType.DIAPO.getSuffix());
219         }
220         return baseName;
221     }
222 
223     private static String getImageFileExtension(File inputFile) {
224         String fileExtension = FilenameUtils.getExtension(inputFile.getName());
225         if (!AVAILABLE_EXTENSION_LIST.contains(fileExtension.toLowerCase())) {
226             throw new QuadrigeTechnicalException("inputFile is not a '" + AVAILABLE_EXTENSION + "' file");
227         }
228         return fileExtension;
229     }
230 
231     public enum ImageType {
232         BASE("", null),
233         DIAPO("$MID", 500),
234         THUMBNAIL("$LOW", 200);
235 
236         private final String suffix;
237         private final Integer maxSize;
238 
239         ImageType(String suffix, Integer maxSize) {
240             this.suffix = suffix;
241             this.maxSize = maxSize;
242         }
243 
244         public String getSuffix() {
245             return suffix;
246         }
247 
248         public Integer getMaxSize() {
249             return maxSize;
250         }
251     }
252 }