1 /*
   2  * Copyright (c) 1997, 2020, 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     public static native int transformBI(BufferedImage src, BufferedImage dst,
  77                                          double[] matrix, int interpType);
  78     public static native int transformRaster(Raster src, Raster dst,
  79                                              double[] matrix,
  80                                              int interpType);
  81     public static native int convolveBI(BufferedImage src, BufferedImage dst,
  82                                         Kernel kernel, int edgeHint);
  83     public static native int convolveRaster(Raster src, Raster dst,
  84                                             Kernel kernel, int edgeHint);
  85     public static native int lookupByteBI(BufferedImage src, BufferedImage dst,
  86                                         byte[][] table);
  87     public static 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                     try {
  98                         System.loadLibrary("mlib_image");
  99                     } catch (UnsatisfiedLinkError e) {
 100                         return Boolean.FALSE;
 101                     }
 102                     boolean success = init();
 103                     return Boolean.valueOf(success);
 104                 }
 105             };
 106 
 107         useLib = AccessController.doPrivileged(doMlibInitialization);
 108 
 109         //
 110         // Cache the class references of the operations we know about
 111         // at the time this class is initially loaded.
 112         //
 113         try {
 114             nativeOpClass[LOOKUP_OP] =
 115                 Class.forName("java.awt.image.LookupOp");
 116         } catch (ClassNotFoundException e) {
 117             System.err.println("Could not find class: "+e);
 118         }
 119         try {
 120             nativeOpClass[AFFINE_OP] =
 121                 Class.forName("java.awt.image.AffineTransformOp");
 122         } catch (ClassNotFoundException e) {
 123             System.err.println("Could not find class: "+e);
 124         }
 125         try {
 126             nativeOpClass[CONVOLVE_OP] =
 127                 Class.forName("java.awt.image.ConvolveOp");
 128         } catch (ClassNotFoundException e) {
 129             System.err.println("Could not find class: "+e);
 130         }
 131 
 132     }
 133 
 134     private static int getNativeOpIndex(Class<?> opClass) {
 135         //
 136         // Search for this class in cached list of
 137         // classes supplying native acceleration
 138         //
 139         int opIndex = -1;
 140         for (int i=0; i<NUM_NATIVE_OPS; i++) {
 141             if (opClass == nativeOpClass[i]) {
 142                 opIndex = i;
 143                 break;
 144             }
 145         }
 146         return opIndex;
 147     }
 148 
 149 
 150     public static WritableRaster filter(RasterOp op, Raster src,
 151                                         WritableRaster dst) {
 152         if (useLib == false) {
 153             return null;
 154         }
 155 
 156         // Create the destination tile
 157         if (dst == null) {
 158             dst = op.createCompatibleDestRaster(src);
 159         }
 160 
 161 
 162         WritableRaster retRaster = null;
 163         switch (getNativeOpIndex(op.getClass())) {
 164 
 165           case LOOKUP_OP:
 166             // REMIND: Fix this!
 167             LookupTable table = ((LookupOp)op).getTable();
 168             if (table.getOffset() != 0) {
 169                 // Right now the native code doesn't support offsets
 170                 return null;
 171             }
 172             if (table instanceof ByteLookupTable) {
 173                 ByteLookupTable bt = (ByteLookupTable) table;
 174                 if (lookupByteRaster(src, dst, bt.getTable()) > 0) {
 175                     retRaster = dst;
 176                 }
 177             }
 178             break;
 179 
 180           case AFFINE_OP:
 181             AffineTransformOp bOp = (AffineTransformOp) op;
 182             double[] matrix = new double[6];
 183             bOp.getTransform().getMatrix(matrix);
 184             if (transformRaster(src, dst, matrix,
 185                                 bOp.getInterpolationType()) > 0) {
 186                 retRaster =  dst;
 187             }
 188             break;
 189 
 190           case CONVOLVE_OP:
 191             ConvolveOp cOp = (ConvolveOp) op;
 192             if (convolveRaster(src, dst,
 193                                cOp.getKernel(), cOp.getEdgeCondition()) > 0) {
 194                 retRaster = dst;
 195             }
 196             break;
 197 
 198           default:
 199             break;
 200         }
 201 
 202         if (retRaster != null) {
 203             SunWritableRaster.markDirty(retRaster);
 204         }
 205 
 206         return retRaster;
 207     }
 208 
 209 
 210     public static BufferedImage filter(BufferedImageOp op, BufferedImage src,
 211                                        BufferedImage dst)
 212     {
 213         if (verbose) {
 214             System.out.println("in filter and op is "+op
 215                                + "bufimage is "+src+" and "+dst);
 216         }
 217 
 218         if (useLib == false) {
 219             return null;
 220         }
 221 
 222         // Create the destination image
 223         if (dst == null) {
 224             dst = op.createCompatibleDestImage(src, null);
 225         }
 226 
 227         BufferedImage retBI = null;
 228         switch (getNativeOpIndex(op.getClass())) {
 229 
 230           case LOOKUP_OP:
 231             // REMIND: Fix this!
 232             LookupTable table = ((LookupOp)op).getTable();
 233             if (table.getOffset() != 0) {
 234                 // Right now the native code doesn't support offsets
 235                 return null;
 236             }
 237             if (table instanceof ByteLookupTable) {
 238                 ByteLookupTable bt = (ByteLookupTable) table;
 239                 if (lookupByteBI(src, dst, bt.getTable()) > 0) {
 240                     retBI = dst;
 241                 }
 242             }
 243             break;
 244 
 245           case AFFINE_OP:
 246             AffineTransformOp bOp = (AffineTransformOp) op;
 247             double[] matrix = new double[6];
 248             AffineTransform xform = bOp.getTransform();
 249             bOp.getTransform().getMatrix(matrix);
 250 
 251             if (transformBI(src, dst, matrix,
 252                             bOp.getInterpolationType())>0) {
 253                 retBI = dst;
 254             }
 255             break;
 256 
 257           case CONVOLVE_OP:
 258             ConvolveOp cOp = (ConvolveOp) op;
 259             if (convolveBI(src, dst, cOp.getKernel(),
 260                            cOp.getEdgeCondition()) > 0) {
 261                 retBI = dst;
 262             }
 263             break;
 264 
 265           default:
 266             break;
 267         }
 268 
 269         if (retBI != null) {
 270             SunWritableRaster.markDirty(retBI);
 271         }
 272 
 273         return retBI;
 274     }
 275 }