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