View Javadoc

1   /*
2    * JCaptcha, the open source java framework for captcha definition and integration
3    * Copyright (c)  2007 jcaptcha.net. All Rights Reserved.
4    * See the LICENSE.txt file distributed with this package.
5    */
6   
7   package com.octo.captcha.component.image.backgroundgenerator;
8   
9   import com.octo.captcha.CaptchaException;
10  
11  import javax.imageio.ImageIO;
12  import java.awt.*;
13  import java.awt.image.BufferedImage;
14  import java.io.File;
15  import java.io.FileInputStream;
16  import java.io.IOException;
17  import java.io.UnsupportedEncodingException;
18  import java.net.URL;
19  import java.net.URLDecoder;
20  
21  import java.util.*;
22  import java.util.List;
23  
24  /***
25   * <p>File reader background generator that return a random image from the ones found in the directory </p>
26   * <p>You can place images in the classpath directory, in this case take care to use a unique directory name (not already contained in a jar file)</p>
27   *
28   * @author <a href="mailto:mag@octo.com">Marc-Antoine Garrigue</a>
29   * @version 1.0
30   */
31  public class FileReaderRandomBackgroundGenerator extends
32          AbstractBackgroundGenerator {
33  
34      private List images = new ArrayList();
35      private String rootPath = ".";
36  
37      public FileReaderRandomBackgroundGenerator(Integer width,
38                                                 Integer height, String rootPath) {
39          super(width, height);
40  
41          if (rootPath != null)
42              this.rootPath = rootPath;
43  
44          File dir = findDirectory(this.rootPath);
45  
46          File[] files = dir.listFiles();
47  
48          //get all jpeg
49          if (files != null) {
50              for (File file : files) {
51                  BufferedImage out = null;
52                  if (file.isFile()) {
53                      out = getImage(file);
54                  }
55                  if (out != null) {
56                      images.add(images.size(), out);
57                  }
58              }
59  
60  
61              if (images.size() != 0) {
62                  for (int i = 0; i < images.size(); i++) {
63                      BufferedImage bufferedImage = (BufferedImage) images.get(i);
64                      images.set(i, tile(bufferedImage));
65                  }
66              } else {
67                  throw new CaptchaException("Root path directory is valid but " +
68                          "does not contains any image (jpg) files");
69              }
70          }
71      }
72  
73      /***
74       *
75       */
76      protected static final Map cachedDirectories = new HashMap();
77  
78      protected File findDirectory(String rootPath) {
79          if (cachedDirectories.containsKey(rootPath)) {
80              return (File) cachedDirectories.get(rootPath);
81          }
82  
83          //try direct path
84          File dir = new File(rootPath);
85          StringBuffer triedPath = new StringBuffer();
86          appendFilePath(triedPath, dir);
87          if (isNotReadable(dir)) {
88              //try with . parent
89              dir = new File(".", rootPath);
90              appendFilePath(triedPath, dir);
91              if (isNotReadable(dir)) {
92                  //try with / parent
93                  dir = new File("/", rootPath);
94                  appendFilePath(triedPath, dir);
95  
96                  if (isNotReadable(dir)) {
97                      //trying with ressource
98                      URL url = FileReaderRandomBackgroundGenerator.class.getClassLoader().getResource(rootPath);
99                      if (url != null) {
100                         dir = new File(getFilePath(url));
101                         appendFilePath(triedPath, dir);
102 
103                     } else {
104                         //trying the class path
105                         url = ClassLoader.getSystemClassLoader().getResource(rootPath);
106 
107                         if (url != null) {
108                             dir = new File(getFilePath(url));
109                             appendFilePath(triedPath, dir);
110 
111                         }
112                     }
113                 }
114             }
115         }
116         // FIXME - avoid double-checking
117         if (isNotReadable(dir)) {
118             // dir is still no good -- let's try directories in the system classpath
119             StringTokenizer token = getClasspathFromSystemProperty();
120             while (token.hasMoreElements()) {
121                 String path = token.nextToken();
122                 if (!path.endsWith(".jar")) {
123                     dir = new File(path, rootPath);
124                     appendFilePath(triedPath, dir);
125                     if (dir.canRead() && dir.isDirectory()) {
126                         break;
127                     }
128                 }
129             }
130         }
131 
132 
133         if (isNotReadable(dir)) {
134             throw new CaptchaException("All tried paths :'" + triedPath.toString() + "' is not" +
135                     " a directory or cannot be read");
136         }
137 
138         // cache answer for later
139         cachedDirectories.put(rootPath, dir);
140 
141         return dir;
142     }
143 
144 	private String getFilePath(URL url) {
145 		String file = null;
146 		try {
147 			file = URLDecoder.decode(url.getFile(), "UTF-8");
148 		} catch (UnsupportedEncodingException e) {
149 			// Do Nothing			
150 		}
151 		return file;
152 	}
153 
154     
155 
156 	private boolean isNotReadable(File dir) {
157 		return !dir.canRead() || !dir.isDirectory();
158 	}
159 
160     private StringTokenizer getClasspathFromSystemProperty() {
161 
162         String classpath = System.getProperty("java.class.path");
163         return new StringTokenizer(classpath, File.pathSeparator);
164     }
165 
166 
167     private void appendFilePath(StringBuffer triedPath, File dir) {
168         triedPath.append(dir.getAbsolutePath());
169         triedPath.append("\n");
170     }
171 
172     private BufferedImage tile(BufferedImage tileImage) {
173         BufferedImage image = new BufferedImage(getImageWidth(),
174                 getImageHeight(), tileImage.getType());
175         Graphics2D g2 = (Graphics2D) image.getGraphics();
176         int NumberX = (getImageWidth() / tileImage.getWidth());
177         int NumberY = (getImageHeight() / tileImage.getHeight());
178         for (int k = 0; k <= NumberY; k++) {
179             for (int l = 0; l <= NumberX; l++) {
180                 g2.drawImage(tileImage, l * tileImage.getWidth(), k *
181                         tileImage.getHeight(),
182                         Math.min(tileImage.getWidth(), getImageWidth()),
183                         Math.min(tileImage.getHeight(), getImageHeight()),
184                         null);
185             }
186         }
187         g2.dispose();
188         return image;
189     }
190 
191     private static BufferedImage getImage(File o) {
192         
193         try {
194             FileInputStream fis = new FileInputStream(o);
195             BufferedImage out =ImageIO.read(fis);
196             fis.close();
197 
198             // Return the format name
199             return out;
200             
201         } catch (IOException e) {
202             throw new CaptchaException("Unknown error during file reading ", e);
203         } 
204     }
205 
206     /***
207      * Generates a backround image on wich text will be paste. Implementations must take into account the imageHeigt and
208      * imageWidth.
209      *
210      * @return the background image
211      */
212     public BufferedImage getBackground() {
213         return (BufferedImage) images.get(myRandom.nextInt(images.size()));
214     }
215 
216 }