1
2
3
4
5
6
7
8 package com.buckosoft.PicMan.image;
9
10 import java.awt.BasicStroke;
11 import java.awt.Color;
12 import java.awt.Dimension;
13 import java.awt.Graphics2D;
14 import java.awt.Image;
15 import java.awt.geom.AffineTransform;
16 import java.awt.image.AffineTransformOp;
17 import java.awt.image.BufferedImage;
18 import java.io.File;
19 import java.util.Iterator;
20 import java.util.concurrent.locks.ReentrantLock;
21
22 import javax.imageio.ImageIO;
23 import javax.imageio.ImageReader;
24 import javax.imageio.stream.ImageInputStream;
25
26 import org.apache.commons.logging.Log;
27 import org.apache.commons.logging.LogFactory;
28
29 import com.buckosoft.PicMan.business.PicManFacade;
30 import com.buckosoft.PicMan.domain.Pic;
31 import com.buckosoft.PicMan.domain.Thumbnail;
32 import com.drew.imaging.ImageMetadataReader;
33 import com.drew.metadata.Metadata;
34 import com.drew.metadata.exif.ExifIFD0Directory;
35
36
37
38
39
40
41 public class PicReader {
42
43 private PicManFacade pmf;
44 private ThumbCache thumbCache;
45 private QueueDepth queueDepth = new QueueDepth();
46 private ReentrantLock lock = new ReentrantLock();
47
48
49 private static final boolean DEBUG = true;
50 protected final Log log = LogFactory.getLog(getClass());
51
52 public void setPicMan(PicManFacade pmf) {
53 this.pmf = pmf;
54 }
55
56
57
58
59 public void setThumbCache(ThumbCache thumbCache) {
60 this.thumbCache = thumbCache;
61 }
62
63 public PicManFacade getPicMan() { return(pmf); }
64
65
66
67
68 public int getQueueDepth() { return(queueDepth.getDepth()); }
69
70 public Thumbnail getThumbNail(Pic pic, int height, String label) {
71 Thumbnail tn = null;
72 if (pic == null)
73 return(getXThumb(height));
74
75 tn = thumbCache.getThumbNail(pic, height);
76 if (tn == null) {
77 enterQueue();
78 try {
79 tn = readThumbNail(pic, height, label);
80 } catch (Throwable t) {
81 exitQueue();
82 RuntimeException e1 = new RuntimeException("Failed to read ThumbNail for \"" + pic.getName() + "\"", t);
83 throw(e1);
84 }
85 exitQueue();
86 }
87 if (label != null) {
88 int xp = 0;
89 int yp = 0+tn.getImage().getHeight() - 1;
90 Graphics2D g = tn.getImage().createGraphics();
91 g.setColor(Color.BLACK);
92 g.drawString(label, xp+1, yp+1);
93 g.setColor(Color.WHITE);
94 g.drawString(label, xp, yp);
95 }
96 return(tn);
97 }
98
99
100
101
102
103
104
105
106 public int getFilesInDirCount(int rid, String dir) {
107 String fullPath = pmf.getDB().getRoot(rid).getPath() + "/" + dir;
108 File f = new File(fullPath);
109 String list[] = f.list();
110 int count = 0;
111 int i;
112 if (list == null)
113 return(0);
114 for (i=0; i<list.length; i++) {
115 if (list[i].endsWith(".jpg"))
116 count++;
117 }
118 return(count);
119 }
120
121
122
123
124
125
126 private Thumbnail readThumbNail(Pic pic, int thumbHeight, String label) {
127 String fullPath;
128 fullPath = getFullPath(pmf, pic);
129 if (DEBUG)
130 log.info("Read: " + pic.getPid() + ": " + fullPath);
131 Thumbnail tn;
132
133 File f = null;
134 try {
135 f = new File(fullPath);
136 } catch (Exception e) {
137 return(getXThumb(thumbHeight));
138 }
139 Iterator<ImageReader> readers = ImageIO.getImageReadersByFormatName("jpg");
140 ImageReader reader = (ImageReader)readers.next();
141 BufferedImage bi;
142 Graphics2D g;
143 if (DEBUG)
144 log.debug("Trying to read f=" + f);
145 ImageInputStream iis = null;
146 try {
147 iis = ImageIO.createImageInputStream(f);
148 if (DEBUG)
149 log.debug("iis = " + iis);
150 if (iis == null) {
151 return(getXThumb(thumbHeight));
152 }
153 reader.setInput(iis, true);
154 bi = reader.read(0);
155 iis.close();
156 } catch (IllegalStateException ise) {
157 if (DEBUG)
158 log.info("caught IllegalStateException");
159 reader.dispose();
160 bi = null;
161 if (iis != null) {
162 try {
163 iis.close();
164 } catch (Exception e) {}
165 }
166 return(getXThumb(thumbHeight));
167 } catch (Exception e) {
168
169 log.info("caught Exception");
170 reader.dispose();
171 bi = null;
172 if (iis != null) {
173 try {
174 iis.close();
175 } catch (Exception ex) {}
176 }
177 return(getXThumb(thumbHeight));
178 }
179 reader.dispose();
180 Metadata metadata = null;
181 try {
182 metadata = ImageMetadataReader.readMetadata(f);
183
184 } catch (Exception e) {
185
186 e.printStackTrace();
187 }
188 log.debug("readThumbNail: File " + fullPath);
189 ExifIFD0Directory directory = metadata.getDirectory(ExifIFD0Directory.class);
190 String s = "--";
191 try {
192 s = directory.getString(ExifIFD0Directory.TAG_ORIENTATION);
193 } catch (Exception e) {}
194 int rot = 0;
195 try {
196 rot = directory.getInt(ExifIFD0Directory.TAG_ORIENTATION);
197 } catch (Exception e) {
198
199 }
200 log.debug(" Orientation: '" + s + "' rot: " + rot);
201
202
203
204
205
206
207
208 int width = bi.getWidth();
209 int height = bi.getHeight();
210
211 double dW = ((double)thumbHeight/(double)height) * width;
212 double dH = ((double)thumbHeight/(double)width) * height;
213 int newW = (int)dW;
214 int newH = thumbHeight;
215
216 BufferedImage small;
217 if (rot == 6) {
218 log.debug("******* rotating 90");
219 small = new BufferedImage((int)dH, thumbHeight, BufferedImage.TYPE_INT_BGR);
220 BufferedImage bix;
221 bix = new BufferedImage(bi.getHeight(), bi.getWidth(), BufferedImage.TYPE_INT_BGR);
222 g = bix.createGraphics();
223 AffineTransform trans = new AffineTransform(0.0, 1.0, -1.0, 0.0, bi.getHeight(), 0.0);
224 g.transform(trans);
225 g.drawImage(bi, 0, 0, bi.getWidth(), bi.getHeight(), null);
226 bi = bix;
227 g = small.createGraphics();
228 g.drawImage(bix.getScaledInstance(-1, thumbHeight, Image.SCALE_SMOOTH), 0, 0, small.getWidth(), small.getHeight(), null);
229 } else if (rot == 3) {
230 log.debug("******* rotating 180");
231 small = new BufferedImage((int)dW, thumbHeight, BufferedImage.TYPE_INT_BGR);
232 BufferedImage bix;
233 bix = new BufferedImage(bi.getWidth(), bi.getHeight(), BufferedImage.TYPE_INT_BGR);
234
235 AffineTransform trans = AffineTransform.getScaleInstance(-1, -1);
236 trans.translate(-bix.getWidth(), -bix.getHeight());
237 AffineTransformOp op = new AffineTransformOp(trans, AffineTransformOp.TYPE_NEAREST_NEIGHBOR);
238 bix = op.filter(bi, null);
239 g = small.createGraphics();
240 g.drawImage(bix.getScaledInstance(-1, thumbHeight, Image.SCALE_SMOOTH), 0, 0, small.getWidth(), small.getHeight(), null);
241 } else if (rot == 8) {
242 log.debug("******* rotating -90");
243 small = new BufferedImage((int)dH, thumbHeight, BufferedImage.TYPE_INT_BGR);
244 BufferedImage bix;
245 bix = new BufferedImage(bi.getHeight(), bi.getWidth(), BufferedImage.TYPE_INT_BGR);
246 g = bix.createGraphics();
247 AffineTransform trans = new AffineTransform(0.0, 1.0, -1.0, 0.0, bi.getHeight(), 0.0);
248 g.transform(trans);
249 g.drawImage(bi, 0, 0, bi.getWidth(), bi.getHeight(), null);
250 bi = bix;
251 bix = new BufferedImage(bi.getWidth(), bi.getHeight(), BufferedImage.TYPE_INT_BGR);
252
253 trans = AffineTransform.getScaleInstance(-1, -1);
254 trans.translate(-bix.getWidth(), -bix.getHeight());
255 AffineTransformOp op = new AffineTransformOp(trans, AffineTransformOp.TYPE_NEAREST_NEIGHBOR);
256 bix = op.filter(bi, null);
257 g = small.createGraphics();
258 g.drawImage(bix.getScaledInstance(-1, thumbHeight, Image.SCALE_SMOOTH), 0, 0, small.getWidth(), small.getHeight(), null);
259
260 } else {
261 small = new BufferedImage(newW, newH, BufferedImage.TYPE_INT_BGR);
262 g = small.createGraphics();
263 g.drawImage(bi.getScaledInstance(-1, newH, Image.SCALE_SMOOTH), null, null);
264 }
265 tn = new Thumbnail();
266 tn.setName(pic.getName());
267 tn.setImage(small);
268 g = null;
269 bi = null;
270 if (!pic.isImportPic())
271 thumbCache.addToCache(pic, tn);
272 return(tn);
273 }
274
275 public Thumbnail getXThumb(int thumbHeight) {
276 int z = thumbHeight;
277 Thumbnail tn = new Thumbnail();
278 BufferedImage small = new BufferedImage(z, z, BufferedImage.TYPE_INT_BGR);
279 Graphics2D g = small.createGraphics();
280 g.setBackground(Color.BLACK);
281 g.setColor(Color.RED);
282
283 g.setStroke(new BasicStroke((float)5.0));
284 g.drawLine(0, 0, z, z);
285 g.drawLine(0, z, z, 0);
286 tn.setImage(small);
287 tn.setXThumb(true);
288 return(tn);
289 }
290
291 public static String getFullPath(PicManFacade pmf, Pic pic) {
292 String fullPath;
293 if (pic.isImportPic())
294 fullPath = pmf.getDB().getSystem().getImportDirectory() + "/" + pic.getName();
295 else
296 fullPath = pmf.getDB().getRoot(pic.getRid()).getPath() + "/" + pic.getLocation()
297 + "/" + pic.getName() + ".jpg";
298 return(fullPath);
299 }
300
301 private void enterQueue() {
302 queueDepth.incDepth();
303 log.info("Enter New queue depth " + queueDepth.getDepth());
304 lock.lock();
305 }
306 private void exitQueue() {
307 lock.unlock();
308 queueDepth.decDepth();
309 log.info("Exit New queue depth " + queueDepth.getDepth());
310 }
311
312
313 public Dimension determinePicSize(Pic pic) {
314 BufferedImage bi = readPic(pic);
315 if (bi == null)
316 return(new Dimension(-1, -1));
317 return(new Dimension(bi.getWidth(), bi.getHeight()));
318
319 }
320
321 public BufferedImage readPic(Pic pic) {
322
323 try {
324 return(readPic(getFullPath(pmf, pic)));
325 } catch (Exception e) {
326 e.printStackTrace();
327 return(null);
328 }
329 }
330
331 public BufferedImage readPic(String path) {
332 File f = null;
333 try {
334 f = new File(path);
335 } catch (Exception e) {
336 return(null);
337 }
338 Iterator<ImageReader> readers = ImageIO.getImageReadersByFormatName("jpg");
339 ImageReader reader = (ImageReader)readers.next();
340 BufferedImage bi;
341 if (DEBUG)
342 log.info("readPic: " + f);
343 ImageInputStream iis = null;
344 try {
345 iis = ImageIO.createImageInputStream(f);
346
347
348 if (iis == null) {
349 return(null);
350 }
351 reader.setInput(iis, true);
352 bi = reader.read(0);
353 iis.close();
354 } catch (IllegalStateException ise) {
355 if (DEBUG)
356 log.info("caught IllegalStateException");
357 reader.dispose();
358 bi = null;
359 if (iis != null) {
360 try {
361 iis.close();
362 } catch (Exception ex) {}
363 }
364 return(null);
365 } catch (Exception e) {
366 if (DEBUG)
367 log.info("caught Exception");
368 reader.dispose();
369 bi = null;
370 if (iis != null) {
371 try {
372 iis.close();
373 } catch (Exception ex) {}
374 }
375 return(null);
376 }
377 reader.dispose();
378 Metadata metadata = null;
379 try {
380 metadata = ImageMetadataReader.readMetadata(f);
381
382 } catch (Throwable t) {
383 t.printStackTrace();
384 }
385 log.debug("readPic: File " + path);
386 int rot = 0;
387 String s = "--";
388 if (metadata != null) {
389 ExifIFD0Directory directory = metadata.getDirectory(ExifIFD0Directory.class);
390 try {
391 s = directory.getString(ExifIFD0Directory.TAG_ORIENTATION);
392 } catch (Exception e) {}
393 try {
394 rot = directory.getInt(ExifIFD0Directory.TAG_ORIENTATION);
395 } catch (Exception e) {
396 log.debug("failed directory.getInt(ExifIFD0Directory.TAG_ORIENTATION) " + e.getLocalizedMessage());
397 }
398 }
399 log.debug(" Orientation: '" + s + "' rot: " + rot);
400 if (rot == 6 || rot == 8) {
401 log.info("******* rotating 90 ********");
402 BufferedImage bix;
403 bix = new BufferedImage(bi.getHeight(), bi.getWidth(), BufferedImage.TYPE_INT_BGR);
404 Graphics2D g = (Graphics2D)bix.createGraphics();
405 AffineTransform trans = new AffineTransform(0.0, 1.0, -1.0, 0.0, bi.getHeight(), 0.0);
406 g.transform(trans);
407 g.drawImage(bi, 0, 0, bi.getWidth(), bi.getHeight(), null);
408 bi = bix;
409
410
411
412
413
414
415
416
417
418 }
419 if (rot == 3 || rot == 8) {
420 log.debug("******* rotating 180 ");
421 BufferedImage bix;
422 bix = new BufferedImage(bi.getWidth(), bi.getHeight(), BufferedImage.TYPE_INT_BGR);
423 AffineTransform trans = AffineTransform.getScaleInstance(-1, -1);
424 trans.translate(-bix.getWidth(), -bix.getHeight());
425 AffineTransformOp op = new AffineTransformOp(trans, AffineTransformOp.TYPE_NEAREST_NEIGHBOR);
426 bix = op.filter(bi, null);
427 bi = bix;
428 }
429 return(bi);
430 }
431 private class QueueDepth {
432 private int queueDepth = 0;
433
434 public void incDepth() {
435 synchronized(this) {
436 queueDepth++;
437 }
438 }
439 public void decDepth() {
440 synchronized(this) {
441 queueDepth--;
442 }
443 }
444 public int getDepth() {
445 synchronized(this) {
446 return(queueDepth);
447 }
448 }
449 }
450 }