Help generation: order md5s
[scilab.git] / scilab / modules / helptools / src / java / org / scilab / modules / helptools / image / ImageConverter.java
1 /*
2  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  * Copyright (C) 2010 - Calixte DENIZET
4  *
5  * This file must be used under the terms of the CeCILL.
6  * This source file is licensed as described in the file COPYING, which
7  * you should have received as part of this distribution.  The terms
8  * are also available at
9  * http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt
10  *
11  */
12
13 package org.scilab.modules.helptools.image;
14
15 import java.awt.Graphics2D;
16 import java.awt.Color;
17 import java.awt.image.BufferedImage;
18 import java.io.BufferedReader;
19 import java.io.BufferedWriter;
20 import java.io.File;
21 import java.io.FileInputStream;
22 import java.io.FileOutputStream;
23 import java.io.FileReader;
24 import java.io.FileWriter;
25 import java.io.IOException;
26 import java.io.OutputStream;
27 import java.io.StringReader;
28 import java.net.URI;
29 import java.net.URISyntaxException;
30 import java.nio.channels.FileChannel;
31 import java.util.HashMap;
32 import java.util.Map;
33 import java.util.TreeMap;
34
35 import javax.activation.MimetypesFileTypeMap;
36 import javax.imageio.ImageIO;
37 import javax.swing.Icon;
38 import javax.swing.ImageIcon;
39 import javax.swing.JLabel;
40
41 import org.scilab.modules.commons.ScilabCommonsUtils;
42
43 /**
44  * Class to handle the image conversion
45  * @author Calixte DENIZET
46  */
47 public final class ImageConverter {
48
49     private static final String MD5_FILE = "images_md5.txt";
50
51     private static Map<String, ExternalImageConverter> externalConverters = new HashMap<String, ExternalImageConverter>();
52     private static MimetypesFileTypeMap mimeMap = new MimetypesFileTypeMap();
53     private static Map<String, String> md5s;
54
55     static {
56         mimeMap.addMimeTypes("type=image/latex exts=tex,latex");
57         mimeMap.addMimeTypes("type=image/mathml exts=mml,mathml");
58         mimeMap.addMimeTypes("type=image/svg exts=svg");
59         mimeMap.addMimeTypes("type=image/scilab exts=sce");
60         mimeMap.addMimeTypes("type=image/scilab-xcos exts=xcos,zcos");
61     }
62
63     /**
64      * Register a new ExternalImageConverter
65      * @param c the converter to register
66      */
67     public static void registerExternalImageConverter(ExternalImageConverter c) {
68         if (c != null) {
69             externalConverters.put(c.getMimeType(), c);
70         }
71     }
72
73     /**
74      * Load file containing md5s
75      * @param dir the directory where to find the file
76      */
77     public static void loadMD5s(String dir) {
78         md5s = getMD5s(dir);
79     }
80
81     /**
82      * Save file containing md5s
83      * @param dir the directory where to find the file
84      */
85     public static void saveMD5s(String dir) {
86         writeMD5s(dir, md5s);
87         md5s = null;
88     }
89
90     /**
91      * Compare md5
92      * @param code the code to compare
93      * @param file the file name of the future image
94      */
95     public static boolean compareMD5(String code, String file) {
96         if (md5s != null && code != null && file != null && !file.isEmpty()) {
97             code = code.trim().replaceAll("[ \t]*[\n]+[ \t]*", "");
98             String md5 = ScilabCommonsUtils.getMD5(code);
99             String oldmd5 = md5s.get(file);
100             if (oldmd5 != null && md5.equals(oldmd5)) {
101                 return true;
102             }
103             md5s.put(file, md5);
104         }
105
106         return false;
107     }
108
109     /**
110      * Get the generated md5s
111      * @param dir the dir where to find the files
112      * @return a map filename -&gt; md5 of the code
113      */
114     private static Map<String, String> getMD5s(String dir) {
115         File f = new File(dir + File.separator + MD5_FILE);
116         Map<String, String> map = new HashMap<String, String>();
117         if (f.exists() && f.canRead()) {
118             BufferedReader reader = null;
119             try {
120                 reader = new BufferedReader(new FileReader(f));
121                 String line = reader.readLine();
122                 while (line != null) {
123                     String[] arr = line.split("=");
124                     map.put(arr[0], arr[1]);
125                     line = reader.readLine();
126                 }
127             } catch (IOException e) {
128                 System.err.println(e);
129             } finally {
130                 if (reader != null) {
131                     try {
132                         reader.close();
133                     } catch (IOException e) {
134
135                     }
136                 }
137             }
138         }
139
140         return map;
141     }
142
143     /**
144      * Write the generated md5s
145      * @param dir the dir where to find the files
146      * @param a map filename -&gt; md5 of the code
147      */
148     private static void writeMD5s(String dir, Map<String, String> map) {
149         File f = new File(dir + File.separator + MD5_FILE);
150         if (!f.exists()) {
151             try {
152                 f.createNewFile();
153             } catch (IOException e) {
154                 System.err.println(e);
155                 return;
156             }
157         }
158
159         if (f.canWrite()) {
160             BufferedWriter writer = null;
161             try {
162                 writer = new BufferedWriter(new FileWriter(f));
163                 Map<String, String> tree = new TreeMap<String, String>(map);
164                 for (Map.Entry<String, String> entry : tree.entrySet()) {
165                     String s = entry.getKey() + "=" + entry.getValue();
166                     writer.write(s, 0, s.length());
167                     writer.newLine();
168                 }
169                 writer.flush();
170             } catch (IOException e) {
171                 System.err.println(e);
172             } finally {
173                 if (writer != null) {
174                     try {
175                         writer.close();
176                     } catch (IOException e) {
177
178                     }
179                 }
180             }
181         }
182     }
183
184     /**
185      * @param attrs the attribute of the image
186      * @param path the current XML file which is parsed
187      * @param image the filename
188      * @param destDir the destination directory
189      * @return the HTML code to insert the image
190      */
191     public static String getImageByFile(Map<String, String> attrs, String path, String image, String outputDir, String destDir, String baseImagePath) {
192         File f = new File(image);
193         if (!f.isAbsolute()) {
194             f = new File(path + File.separator + image);
195         }
196
197         String destFile = outputDir + File.separator + destDir + File.separator + f.getName();
198
199         ExternalImageConverter conv = externalConverters.get(mimeMap.getContentType(f));
200         if (conv != null) {
201             destFile += ".png";
202         }
203         File imageFile = new File(destFile);
204         String imageName = destDir + "/" + imageFile.getName();
205
206         if (f.lastModified() > imageFile.lastModified()) {
207             if (conv != null) {
208                 return conv.convertToImage(f, attrs, imageFile, imageName);
209             }
210             copyImageFile(f, outputDir + File.separator + destDir);
211         }
212
213         return "<img src=\'" + baseImagePath + imageName + "\'/>";
214     }
215
216     /**
217      * @param code the code to translate
218      * @param attrs the attribute of the image
219      * @param mime type
220      * @param imageFile the filename
221      * @return the HTML code to insert the image
222      */
223     public static String getImageByCode(String currentFile, String code, Map<String, String> attrs, String mime, File imageFile, String imageName, String baseImagePath) {
224         File current = null;
225         try {
226             current = new File(new URI(currentFile));
227         } catch (URISyntaxException e) { }
228
229         ExternalImageConverter conv = externalConverters.get(mime);
230         if (conv == null) {
231             System.err.println("In file " + currentFile + "invalid code:\n" + code);
232             return null;
233         }
234
235         // if (conv.mustRegenerate() || current == null || current.lastModified() > imageFile.lastModified()) {
236         if (!compareMD5(code, imageFile.getName())) {
237             System.err.println("Info: Create image " + imageFile.getName());
238             return conv.convertToImage(currentFile, code, attrs, imageFile, imageName);
239         }
240
241         return "<img src=\'" + baseImagePath + imageName + "\'/>";
242     }
243
244     /**
245      * @param code the code to translate
246      * @param img image informations
247      * @param fileName the filename
248      * @param attrs the attribute of the image
249      * @return the HTML code to insert the image
250      */
251     public static String generateCode(Image img, String fileName, Map<String, String> attrs) {
252         String style = attrs.get("style");
253         String top = "";
254         boolean display = style != null && style.equals("display");
255
256         if (!display) {
257             top = "top:" + img.descent + "px;";
258         }
259
260         String alignAttr = attrs.get("align");
261         String align = "";
262         String div = "div";
263         if (alignAttr != null) {
264             align = " style=\'text-align:" + alignAttr + "\'";
265         } else if (display) {
266             align = " style=\'text-align:center\'";
267         } else {
268             div = "span";
269         }
270
271         return "<" + div + align + "><img src=\'" + fileName + "\' style=\'position:relative;" + top  + "width:" + img.width + "px;height:" + img.height + "px\'/></" + div + ">";
272     }
273
274     /**
275      * Test if an image file exists.
276      * @param path of the parsed file
277      * @param image the image name
278      * @return null if the image exists, the expected file path otherwise.
279      */
280     public static File imageExists(String path, String image) {
281         File f = new File(image);
282         if (!f.isAbsolute()) {
283             f = new File(path + File.separator + image);
284         }
285
286         if (f.exists()) {
287             return null;
288         } else {
289             return f;
290         }
291     }
292
293     /**
294      * @param f the file to copy
295      * @param destDir the destination directory
296      */
297     public static void copyImageFile(File f, String destDir) {
298         FileChannel src = null;
299         FileChannel dest = null;
300         try {
301             File destFile = new File(destDir + File.separator + f.getName());
302             if (!destFile.exists()) {
303                 destFile.createNewFile();
304             } else if (f.lastModified() <= destFile.lastModified()) {
305                 return;
306             }
307
308             src = new FileInputStream(f).getChannel();
309             dest = new FileOutputStream(destFile).getChannel();
310             dest.transferFrom(src, 0, src.size());
311         } catch (IOException e) {
312             System.err.println(e);
313         } finally {
314             try {
315                 if (src != null) {
316                     src.close();
317                 }
318                 if (dest != null) {
319                     dest.close();
320                 }
321             } catch (IOException e) {
322                 System.err.println(e);
323             }
324         }
325     }
326
327     /**
328      * @param icon the icon to convert into PNG
329      * @param imageFile the destination file
330      * @return true if all is ok
331      */
332     public static boolean convertIconToPNG(Icon icon, File imageFile) {
333         BufferedImage image = new BufferedImage(icon.getIconWidth(), icon.getIconHeight(), BufferedImage.TYPE_INT_ARGB);
334         Graphics2D g2d = image.createGraphics();
335         icon.paintIcon(null, g2d, 0, 0);
336
337         try {
338             ImageIO.write(image, "png", imageFile.getAbsoluteFile());
339         } catch (IOException ex) {
340             return false;
341         }
342
343         g2d.dispose();
344
345         return true;
346     }
347 }