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