Coverage Report - org.webslinger.ext.image.ImageUtils
 
Classes in this File Line Coverage Branch Coverage Complexity
ImageUtils
0%
0/129
0%
0/24
0
 
 1  
 package org.webslinger.ext.image;
 2  
 
 3  
 import java.awt.Dimension;
 4  
 import java.awt.Point;
 5  
 import java.awt.Rectangle;
 6  
 import java.io.File;
 7  
 import java.io.InputStream;
 8  
 import java.io.IOException;
 9  
 import java.util.ArrayList;
 10  
 import java.util.Arrays;
 11  
 import java.util.List;
 12  
 import java.util.ListIterator;
 13  
 import java.util.Map;
 14  
 import java.util.concurrent.CopyOnWriteArrayList;
 15  
 import static java.lang.Math.max;
 16  
 import static java.lang.Math.min;
 17  
 import javax.servlet.ServletException;
 18  
 
 19  
 import org.apache.commons.collections.Transformer;
 20  
 import org.apache.commons.lang.StringUtils;
 21  
 import org.apache.commons.vfs.FileContent;
 22  
 import org.apache.commons.vfs.FileObject;
 23  
 
 24  
 import org.webslinger.PathContext;
 25  
 import org.webslinger.TypeHandler;
 26  
 import org.webslinger.Webslinger;
 27  
 import org.webslinger.WebslingerServletContext;
 28  
 import org.webslinger.collections.CollectionUtil;
 29  
 import org.webslinger.commons.vfs.VFSUtil;
 30  
 import org.webslinger.io.IOUtil;
 31  
 import org.webslinger.lang.ConcurrentCache;
 32  
 import static org.webslinger.lang.NumberUtil.parseInt;
 33  
 import org.webslinger.servlet.Binary;
 34  
 import org.webslinger.util.GeneratedResult;
 35  
 import org.webslinger.util.TTLObject;
 36  
 
 37  0
 public class ImageUtils {
 38  0
     private static final ImageSizeCache imageBoxes = new ImageSizeCache(ImageUtils.class, "imageBoxes", null);
 39  
 
 40  
     protected FileObject root;
 41  
 
 42  
     public static String runImageMagick(String[] commandAndArgs) throws InterruptedException, IOException {
 43  0
         ProcessBuilder builder = new ProcessBuilder(commandAndArgs);
 44  0
         Map<String, String> env = builder.environment();
 45  0
         env.remove("DISPLAY");
 46  0
         Process process = builder
 47  
                             .directory(new File("/"))
 48  
                             .redirectErrorStream(true)
 49  
                             .start();
 50  0
         String output = IOUtil.readString(process.getInputStream());
 51  0
         process.waitFor();
 52  0
         return process.exitValue() == 0 ? output : null;
 53  
     }
 54  
 
 55  
     private static Rectangle getImageBox(String prefix, InputStream in) throws InterruptedException, IOException {
 56  0
         File tmpFile = File.createTempFile(prefix, ".tmp");
 57  0
         tmpFile.deleteOnExit();
 58  
         try {
 59  0
             IOUtil.copy(in, true, tmpFile);
 60  0
             return getImageBox(tmpFile);
 61  
         } finally {
 62  0
             tmpFile.delete();
 63  
         }
 64  
     }
 65  
 
 66  
     public static Rectangle getImageBoxCached(File file) throws InterruptedException, IOException {
 67  0
         return imageBoxes.get(file).getObject();
 68  
     }
 69  
 
 70  
     public static Rectangle getImageBox(File file) throws InterruptedException, IOException {
 71  0
         String output = runImageMagick(new String[] {"identify", file.getPath()});
 72  0
         if (output == null) return null;
 73  
         //  "/tmp/identify50184.image JPEG 800x600 DirectClass 82kb"
 74  
         String[] dimensions;
 75  
         try {
 76  0
             dimensions = (output.substring(file.getPath().length() + 1).split(" "))[1].split("x");
 77  0
         } catch (RuntimeException e) {
 78  0
             System.err.println("error parsing(" + file + "->" + output + ")");
 79  0
             throw e;
 80  0
         }
 81  0
         return new Rectangle(0, 0, Integer.parseInt(dimensions[0]), Integer.parseInt(dimensions[1]));
 82  
     }
 83  
 
 84  
     public static void convertType(File file, String type) throws InterruptedException, IOException {
 85  0
         if (type != null) runImageMagick(new String[] {"mogrify", "-format", type, file.getPath()});
 86  0
     }
 87  
 
 88  
     public static Rectangle getImageBox(FileObject file) throws InterruptedException, IOException {
 89  
         File localFile;
 90  
         try {
 91  0
             localFile = VFSUtil.findLocalFile(file);
 92  0
         } catch (IOException e) {
 93  0
             localFile = null;
 94  0
         }
 95  0
         if (localFile != null) return getImageBoxCached(localFile);
 96  0
         return getImageBox("image-box-commons-vfs-", file.getContent().getInputStream());
 97  
     }
 98  
 
 99  
     public static Rectangle getImageBox(Binary.FileContent content) throws InterruptedException, IOException {
 100  0
         return getImageBox(content.getFile());
 101  
     }
 102  
 
 103  
     public static Rectangle getImageBox(Binary.Content content) throws InterruptedException, IOException {
 104  0
         if (content instanceof Binary.FileContent) return getImageBox((Binary.FileContent) content);
 105  0
         return getImageBox("image-box-binary-content-", content.getInputStream());
 106  
     }
 107  
 
 108  
     public static Rectangle cropImage(File file, Rectangle cropArea) throws InterruptedException, IOException {
 109  0
         return cropImage(file, cropArea, false);
 110  
     }
 111  
 
 112  
     public static Rectangle cropImage(File file, Rectangle cropArea, boolean preview) throws InterruptedException, IOException {
 113  0
         Rectangle imageBox = getImageBox(file);
 114  0
         if (imageBox == null) return null;
 115  0
         cropArea = imageBox.intersection(cropArea);
 116  0
         if (!preview) {
 117  0
             runImageMagick(new String[] {"mogrify", "-crop", ((int) cropArea.getWidth()) + "x" + ((int) cropArea.getHeight()) + "+" + ((int) cropArea.getX()) + "+" + ((int) cropArea.getY()), file.getPath()});
 118  0
             return cropArea;
 119  
         }
 120  0
         int x0 = (int) cropArea.getX();
 121  0
         int y0 = (int) cropArea.getY();
 122  0
         int x1 = (int) (cropArea.getX() + cropArea.getWidth());
 123  0
         int y1 = (int) (cropArea.getY() + cropArea.getHeight());
 124  0
         int width = (int) imageBox.getWidth();
 125  0
         int height = (int) imageBox.getHeight();
 126  
         /*
 127  
          *
 128  
          * 0        x0        x1         width
 129  
          * /--------+---------+---------\ 0
 130  
          * |........|.........|.........|
 131  
          * |........|...   ...|.........|
 132  
          * |........|... C ...|.........|
 133  
          * |........|...   ...|.........|
 134  
          * |........|.........|.........|
 135  
          * |........+---------+.........| y0
 136  
          * |........|         |.........| 
 137  
          * |..   ...|         |...   ...|
 138  
          * |.. A ...|         |... B ...|
 139  
          * |..   ...|         |...   ...|
 140  
          * |........|         |.........|
 141  
          * |........|         |.........| y1
 142  
          * |........+---------+.........|
 143  
          * |........|.........|.........|
 144  
          * |........|...   ...|.........|
 145  
          * |........|... D ...|.........|
 146  
          * |........|...   ...|.........|
 147  
          * |........|.........|.........|
 148  
          * \--------+---------+---------/ height
 149  
          */
 150  0
         int[][] rectangles = new int[][] {
 151  
             {0, 0,      x0, height},
 152  
             {x1, 0,     width, height},
 153  
             {x0, 0,     x1, y0},
 154  
             {x0, y1,    x1, height},
 155  
         };
 156  0
         List<String> args = new ArrayList<String>();
 157  0
         args.addAll(Arrays.asList("mogrify", "-fill", "#0000003f"));
 158  0
         for (int[] r: rectangles) {
 159  0
             args.add("-draw");
 160  0
             args.add("rectangle " + r[0] + "," + r[1] + " " + r[2] + "," + r[3]);
 161  
         }
 162  0
         args.add(file.getPath());
 163  0
         runImageMagick(args.toArray(new String[args.size()]));
 164  0
         return imageBox;
 165  
     }
 166  
 
 167  
     public static Rectangle resizeImage(File file, int width, int height) throws InterruptedException, IOException {
 168  0
         StringBuilder sizeArg = new StringBuilder();
 169  0
         if (width > 0) sizeArg.append(width);
 170  0
         sizeArg.append('x');
 171  0
         if (height > 0) sizeArg.append(height);
 172  0
         sizeArg.append('!');
 173  0
         if (runImageMagick(new String[] {"mogrify", "-resize", sizeArg.toString(), file.getPath()}) == null) return null;
 174  0
         return getImageBox(file);
 175  
     }
 176  
 
 177  
     public static Rectangle constrainImage(File file, int width, int height) throws InterruptedException, IOException {
 178  0
         StringBuilder sizeArg = new StringBuilder();
 179  0
         if (width > 0) sizeArg.append(width);
 180  0
         sizeArg.append('x');
 181  0
         if (height > 0) sizeArg.append(height);
 182  0
         sizeArg.append('>');
 183  0
         runImageMagick(new String[] {"mogrify", "-resize", sizeArg.toString(), file.getPath()});
 184  0
         Rectangle box = getImageBox(file);
 185  0
         if (box == null) return null;
 186  0
         if (box.getWidth() <= width && box.getHeight() <= height) return box;
 187  0
         if (box.getWidth() < width) {
 188  0
             return resizeImage(file, (int) box.getWidth(), height);
 189  
         } else {
 190  0
             return resizeImage(file, width, (int) box.getHeight());
 191  
         }
 192  
     }
 193  
 
 194  
     public static Rectangle constrainImage(File file, String fillColor, float wantedRatio) throws InterruptedException, IOException {
 195  0
         Rectangle imageBox = getImageBox(file);
 196  0
         int width = (int) imageBox.getWidth(), height = (int) imageBox.getHeight();
 197  0
         float gotRatio = (float) height / width;
 198  0
         int pageWidth = width, pageHeight = height;
 199  0
         if (width > height) {
 200  0
             if (wantedRatio > gotRatio) {
 201  0
                 pageHeight = (int) (width * wantedRatio);
 202  
             } else {
 203  0
                 pageWidth = (int) (height / wantedRatio);
 204  
             }
 205  
         } else {
 206  0
             if (wantedRatio > gotRatio) {
 207  0
                 pageWidth = (int) (height / wantedRatio);
 208  
             } else {
 209  0
                 pageHeight = (int) (width * wantedRatio);
 210  
             }
 211  
         }
 212  0
         if (pageWidth == width && pageHeight == height) return imageBox;
 213  0
         int x = (pageWidth - width) / 2;
 214  0
         int y = (pageHeight - height) / 2;
 215  0
         List<String> args = new ArrayList<String>();
 216  0
         args.add("mogrify");
 217  0
         args.add("-fill"); args.add(fillColor);
 218  0
         args.add("-page"); args.add(pageWidth + "x" + pageHeight);
 219  0
         args.add("-extent"); args.add(pageWidth + "x" + pageHeight);
 220  0
         args.add("-draw"); args.add("image Over " + x + "," + y + " " + width + "x" + height + " '" + file.getPath() + "'");
 221  0
         args.add("-fill"); args.add(fillColor);
 222  0
         args.add("-draw"); args.add("rectangle 0,0 " + pageWidth + "," + y);
 223  0
         args.add("-fill"); args.add(fillColor);
 224  0
         args.add("-draw"); args.add("rectangle 0,0 " + x + "," + pageHeight);
 225  0
         args.add("-fill"); args.add(fillColor);
 226  0
         args.add("-draw"); args.add("rectangle 0," + (pageHeight - y - 1) + " " + pageWidth + "," + pageHeight);
 227  0
         args.add("-fill"); args.add(fillColor);
 228  0
         args.add("-draw"); args.add("rectangle " + (pageWidth - x - 1) + ",0 " + pageWidth + "," + pageHeight);
 229  0
         args.add(file.getPath());
 230  0
         runImageMagick(args.toArray(new String[args.size()]));
 231  0
         imageBox = getImageBox(file);
 232  0
         return imageBox;
 233  
     }
 234  
 
 235  
     public static Rectangle constrainBox(int width, int height, int containerWidth, int containerHeight) {
 236  
         int boxHeight, boxWidth;
 237  0
         if (width > containerWidth) {
 238  0
             if (height > containerHeight) {
 239  0
                 double widthRatio = (float) containerWidth / width;
 240  0
                 double heightRatio = (float) containerHeight / height;
 241  0
                 if (widthRatio > heightRatio) {
 242  0
                     boxHeight = containerHeight;
 243  0
                     boxWidth = (int) (width * heightRatio);
 244  
                 } else {
 245  0
                     boxHeight = (int) (height * widthRatio);
 246  0
                     boxWidth = containerWidth;
 247  
                 }
 248  0
             } else {
 249  0
                 double widthRatio = (float) containerWidth / width;
 250  0
                 boxHeight = (int) (height * widthRatio);
 251  0
                 boxWidth = containerWidth;
 252  0
             }
 253  
         } else {
 254  0
             double widthRatio = (float) containerWidth / width;
 255  0
             double heightRatio = (float) containerHeight / height;
 256  0
             if (widthRatio > heightRatio) {
 257  0
                 boxHeight = containerHeight;
 258  0
                 boxWidth = (int) (width * heightRatio);
 259  
             } else {
 260  0
                 boxHeight = (int) (height * widthRatio);
 261  0
                 boxWidth = containerWidth;
 262  
             }
 263  
         }
 264  0
         return new Rectangle(0, 0, boxWidth, boxHeight);
 265  
     }
 266  
 }