1 /*
   2  * Copyright (c) 1997, 2007, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package sun.awt.image;
  27 
  28 import java.awt.geom.AffineTransform;
  29 import java.awt.image.AffineTransformOp;
  30 import java.awt.image.BufferedImage;
  31 import java.awt.image.BufferedImageOp;
  32 import java.awt.image.ByteLookupTable;
  33 import java.awt.image.ConvolveOp;
  34 import java.awt.image.Kernel;
  35 import java.awt.image.LookupOp;
  36 import java.awt.image.LookupTable;
  37 import java.awt.image.RasterOp;
  38 import java.awt.image.Raster;
  39 import java.awt.image.WritableRaster;
  40 import java.security.AccessController;
  41 import java.security.PrivilegedAction;
  42 
  43 /**
  44  * This class provides a hook to access platform-specific
  45  * imaging code.
  46  *
  47  * If the implementing class cannot handle the op, tile format or
  48  * image format, the method will return null;
  49  * If there is an error when processing the
  50  * data, the implementing class may either return null
  51  * (in which case our java code will be executed) or may throw
  52  * an exception.
  53  */
  54 public class ImagingLib {
  55 
  56     static boolean useLib = true;
  57     static boolean verbose = false;
  58 
  59     private static final int NUM_NATIVE_OPS = 3;
  60     private static final int LOOKUP_OP   = 0;
  61     private static final int AFFINE_OP   = 1;
  62     private static final int CONVOLVE_OP = 2;
  63 
  64     private static Class[] nativeOpClass = new Class[NUM_NATIVE_OPS];
  65 
  66     /**
  67      * Returned value indicates whether the library initailization was
  68      * succeded.
  69      *
  70      * There could be number of reasons to failure:
  71      * - failed to load library.
  72      * - failed to get all required entry points.
  73      */
  74     private static native boolean init();
  75 
  76     static public native int transformBI(BufferedImage src, BufferedImage dst,
  77                                          double[] matrix, int interpType);
  78     static public native int transformRaster(Raster src, Raster dst,
  79                                              double[] matrix,
  80                                              int interpType);
  81     static public native int convolveBI(BufferedImage src, BufferedImage dst,
  82                                         Kernel kernel, int edgeHint);
  83     static public native int convolveRaster(Raster src, Raster dst,
  84                                             Kernel kernel, int edgeHint);
  85     static public native int lookupByteBI(BufferedImage src, BufferedImage dst,
  86                                         byte[][] table);
  87     static public native int lookupByteRaster(Raster src, Raster dst,
  88                                               byte[][] table);
  89 
  90     static {
  91 
  92         PrivilegedAction<Boolean> doMlibInitialization =
  93             new PrivilegedAction<Boolean>() {
  94                 public Boolean run() {
  95                     String arch = System.getProperty("os.arch");
  96 
  97                     if (arch == null || !arch.startsWith("sparc")) {
  98                         try {
  99                             System.loadLibrary("mlib_image");
 100                         } catch (UnsatisfiedLinkError e) {
 101                             return Boolean.FALSE;
 102                         }
 103 
 104                     }
 105                     boolean success =  init();
 106                     return Boolean.valueOf(success);
 107                 }
 108             };
 109 
 110         useLib = AccessController.doPrivileged(doMlibInitialization);
 111 
 112         //
 113         // Cache the class references of the operations we know about
 114         // at the time this class is initially loaded.
 115         //
 116         try {
 117             nativeOpClass[LOOKUP_OP] =
 118                 Class.forName("java.awt.image.LookupOp");
 119         } catch (ClassNotFoundException e) {
 120             System.err.println("Could not find class: "+e);
 121         }
 122         try {
 123             nativeOpClass[AFFINE_OP] =
 124                 Class.forName("java.awt.image.AffineTransformOp");
 125         } catch (ClassNotFoundException e) {
 126             System.err.println("Could not find class: "+e);
 127         }
 128         try {
 129             nativeOpClass[CONVOLVE_OP] =
 130                 Class.forName("java.awt.image.ConvolveOp");
 131         } catch (ClassNotFoundException e) {
 132             System.err.println("Could not find class: "+e);
 133         }
 134 
 135     }
 136 
 137     private static int getNativeOpIndex(Class opClass) {
 138         //
 139         // Search for this class in cached list of
 140         // classes supplying native acceleration
 141         //
 142         int opIndex = -1;
 143         for (int i=0; i<NUM_NATIVE_OPS; i++) {
 144             if (opClass == nativeOpClass[i]) {
 145                 opIndex = i;
 146                 break;
 147             }
 148         }
 149         return opIndex;
 150     }
 151 
 152 
 153     public static WritableRaster filter(RasterOp op, Raster src,
 154                                         WritableRaster dst) {
 155         if (useLib == false) {
 156             return null;
 157         }
 158 
 159         // Create the destination tile
 160         if (dst == null) {
 161             dst = op.createCompatibleDestRaster(src);
 162         }
 163 
 164 
 165         WritableRaster retRaster = null;
 166         switch (getNativeOpIndex(op.getClass())) {
 167 
 168           case LOOKUP_OP:
 169             // REMIND: Fix this!
 170             LookupTable table = ((LookupOp)op).getTable();
 171             if (table.getOffset() != 0) {
 172                 // Right now the native code doesn't support offsets
 173                 return null;
 174             }
 175             if (table instanceof ByteLookupTable) {
 176                 ByteLookupTable bt = (ByteLookupTable) table;
 177                 if (lookupByteRaster(src, dst, bt.getTable()) > 0) {
 178                     retRaster = dst;
 179                 }
 180             }
 181             break;
 182 
 183           case AFFINE_OP:
 184             AffineTransformOp bOp = (AffineTransformOp) op;
 185             double[] matrix = new double[6];
 186             bOp.getTransform().getMatrix(matrix);
 187             if (transformRaster(src, dst, matrix,
 188                                 bOp.getInterpolationType()) > 0) {
 189                 retRaster =  dst;
 190             }
 191             break;
 192 
 193           case CONVOLVE_OP:
 194             ConvolveOp cOp = (ConvolveOp) op;
 195             if (convolveRaster(src, dst,
 196                                cOp.getKernel(), cOp.getEdgeCondition()) > 0) {
 197                 retRaster = dst;
 198             }
 199             break;
 200 
 201           default:
 202             break;
 203         }
 204 
 205         if (retRaster != null) {
 206             SunWritableRaster.markDirty(retRaster);
 207         }
 208 
 209         return retRaster;
 210     }
 211 
 212 
 213     public static BufferedImage filter(BufferedImageOp op, BufferedImage src,
 214                                        BufferedImage dst)
 215     {
 216         if (verbose) {
 217             System.out.println("in filter and op is "+op
 218                                + "bufimage is "+src+" and "+dst);
 219         }
 220 
 221         if (useLib == false) {
 222             return null;
 223         }
 224 
 225         // Create the destination image
 226         if (dst == null) {
 227             dst = op.createCompatibleDestImage(src, null);
 228         }
 229 
 230         BufferedImage retBI = null;
 231         switch (getNativeOpIndex(op.getClass())) {
 232 
 233           case LOOKUP_OP:
 234             // REMIND: Fix this!
 235             LookupTable table = ((LookupOp)op).getTable();
 236             if (table.getOffset() != 0) {
 237                 // Right now the native code doesn't support offsets
 238                 return null;
 239             }
 240             if (table instanceof ByteLookupTable) {
 241                 ByteLookupTable bt = (ByteLookupTable) table;
 242                 if (lookupByteBI(src, dst, bt.getTable()) > 0) {
 243                     retBI = dst;
 244                 }
 245             }
 246             break;
 247 
 248           case AFFINE_OP:
 249             AffineTransformOp bOp = (AffineTransformOp) op;
 250             double[] matrix = new double[6];
 251             AffineTransform xform = bOp.getTransform();
 252             bOp.getTransform().getMatrix(matrix);
 253 
 254             if (transformBI(src, dst, matrix,
 255                             bOp.getInterpolationType())>0) {
 256                 retBI = dst;
 257             }
 258             break;
 259 
 260           case CONVOLVE_OP:
 261             ConvolveOp cOp = (ConvolveOp) op;
 262             if (convolveBI(src, dst, cOp.getKernel(),
 263                            cOp.getEdgeCondition()) > 0) {
 264                 retBI = dst;
 265             }
 266             break;
 267 
 268           default:
 269             break;
 270         }
 271 
 272         if (retBI != null) {
 273             SunWritableRaster.markDirty(retBI);
 274         }
 275 
 276         return retBI;
 277     }
 278 }