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