1 /*
   2  * Copyright (c) 2012, 2015, 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 #include "jni_utils.h"
  27 #include "com_sun_javafx_iio_ios_IosImageLoader.h"
  28 
  29 #import "ImageLoader.h"
  30 
  31 #include "debug.h"
  32 
  33 #define BUFFER_SIZE 8 * 1024
  34 
  35 
  36 // NOTE:
  37 // It seems to be inefficient to decode the stream progressively.
  38 // Thus we download the input stream to memory at once and decompress it then.
  39 
  40 // Maybe we could get motivated here:
  41 //http://www.cocoaintheshell.com/2011/05/progressive-images-download-imageio/
  42 
  43 
  44 #ifdef __cplusplus
  45 extern "C" {
  46 #endif
  47 
  48     static jmethodID InputStream_readID;
  49     static jmethodID InputStream_skipID;
  50     static jmethodID IosImageLoader_setInputParametersID;
  51     static jmethodID IosImageLoader_updateImageProgressID;
  52 
  53     JNIEXPORT jint JNICALL
  54     JNI_OnLoad_nativeiio(JavaVM *vm, void *reserved) {
  55 #ifdef JNI_VERSION_1_8
  56     //min. returned JNI_VERSION required by JDK8 for builtin libraries
  57     JNIEnv *env;
  58     if ((*vm)->GetEnv(vm, (void **)&env, JNI_VERSION_1_8) != JNI_OK) {
  59         return JNI_VERSION_1_2;
  60     }
  61     return JNI_VERSION_1_8;
  62 #else
  63     return JNI_VERSION_1_2;
  64 #endif
  65     }
  66 
  67 
  68     /*
  69      * Class:     com_sun_javafx_iio_ios_IosImageLoader
  70      * Method:    initNativeLoading
  71      * Signature: ()V
  72      */
  73     JNIEXPORT void JNICALL Java_com_sun_javafx_iio_ios_IosImageLoader_initNativeLoading
  74     (JNIEnv *env, jclass klazz) {
  75 
  76         IIOLog(@"IosImageLoader_initNativeLoading");
  77 
  78         jclass cls_InputStream = (*env)->FindClass(env, "java/io/InputStream");
  79         if (cls_InputStream == NULL) {
  80 
  81             throwException(env,
  82                            "java/lang/ClassNotFoundException",
  83                            "Cannot find class java.io.InputStream");
  84 
  85             return;
  86         }
  87 
  88         InputStream_readID = (*env)->GetMethodID(env,
  89                                                  cls_InputStream,
  90                                                  "read",
  91                                                  "([BII)I");
  92         InputStream_skipID = (*env)->GetMethodID(env,
  93                                                  cls_InputStream,
  94                                                  "skip",
  95                                                  "(J)J");
  96 
  97         IosImageLoader_setInputParametersID = (*env)->GetMethodID(env,
  98                                                                   klazz,
  99                                                                   "setInputParameters",
 100                                                                   "(IIII)V");
 101         IosImageLoader_updateImageProgressID = (*env)->GetMethodID(env,
 102                                                                    klazz,
 103                                                                    "updateProgress",
 104                                                                    "(F)V");
 105 
 106         (*env)->DeleteLocalRef(env, cls_InputStream);
 107     }
 108 
 109     /*
 110      * Class:     com_sun_javafx_iio_ios_IosImageLoader
 111      * Method:    loadImage
 112      * Signature: (Ljava/lang/String;Z)J
 113      */
 114     JNIEXPORT jlong JNICALL Java_com_sun_javafx_iio_ios_IosImageLoader_loadImageFromURL
 115     (JNIEnv *env, jobject obj, jstring jStringURL, jboolean reportProgress) {
 116 
 117         IIOLog(@"IosImageLoader_loadImageFromURL");
 118 
 119         NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
 120 
 121         ImageLoader *loader = [[ImageLoader alloc] init];
 122 
 123         const char *urlNativeString = (*env)->GetStringUTFChars(env, jStringURL, 0);
 124         NSString *url = [NSString stringWithCString : urlNativeString
 125                                            encoding : NSUTF8StringEncoding];
 126         (*env)->ReleaseStringUTFChars(env, jStringURL, urlNativeString);
 127 
 128         IIOLog(@"Image URL: %@", url);
 129 
 130         BOOL isLoaded = [loader loadFromURL : url
 131                                      JNIEnv : env];
 132 
 133         if (!isLoaded) {
 134             [pool release];
 135             return 0L;
 136         }
 137 
 138         (*env)->CallVoidMethod(env,
 139                                obj,
 140                                IosImageLoader_setInputParametersID,
 141                                (jint) [loader width],
 142                                (jint) [loader height],
 143                                (jint) [loader nImages],
 144                                (jint) [loader loopCount]);
 145 
 146         (*env)->CallVoidMethod(env,
 147                                obj,
 148                                IosImageLoader_updateImageProgressID,
 149                                100.0f);
 150 
 151         [pool release];
 152 
 153         return ptr_to_jlong(loader);
 154 
 155     }
 156 
 157     /*
 158      * Class:     com_sun_javafx_iio_ios_IosImageLoader
 159      * Method:    loadImage
 160      * Signature: (Ljava/io/InputStream;Z)J
 161      */
 162     JNIEXPORT jlong JNICALL Java_com_sun_javafx_iio_ios_IosImageLoader_loadImage
 163     (JNIEnv *env, jobject obj, jobject inputStream, jboolean reportProgress) {
 164 
 165         IIOLog(@"IosImageLoader_loadImage");
 166 
 167         NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
 168 
 169         jbyteArray buffer = (*env)->NewByteArray(env, BUFFER_SIZE);
 170         if (buffer == NULL) {
 171             throwException(env,
 172                            "java/lang/OutOfMemoryError",
 173                            "Cannot initilialize memory buffer for native image loader");
 174 
 175             [pool release];
 176             return 0L;
 177         }
 178 
 179         ImageLoader *loader = [[ImageLoader alloc] init];
 180 
 181         int bytesRead = 0;
 182         jboolean iscopy = FALSE;
 183         jbyte *primitiveArray = (*env)->GetPrimitiveArrayCritical(env, buffer, &iscopy);
 184 
 185         do {
 186             bytesRead = (*env)->CallIntMethod(env,
 187                                               inputStream,
 188                                               InputStream_readID,
 189                                               buffer,
 190                                               0,
 191                                               (jint) BUFFER_SIZE);
 192             if (bytesRead != -1) {
 193                 [loader addToBuffer : (const unsigned char *) primitiveArray
 194                              length : bytesRead];
 195             }
 196         } while (bytesRead != -1);
 197 
 198         BOOL isLoaded = [loader loadFromBuffer : env];
 199 
 200         (*env)->ReleasePrimitiveArrayCritical(env, buffer, primitiveArray, JNI_ABORT);
 201 
 202         if (!isLoaded) {
 203             [pool release];
 204             return 0L;
 205         }
 206 
 207         (*env)->CallVoidMethod(env,
 208                                obj,
 209                                IosImageLoader_setInputParametersID,
 210                                (jint) [loader width],
 211                                (jint) [loader height],
 212                                (jint) [loader nImages],
 213                                (jint) [loader loopCount]);
 214 
 215         (*env)->CallVoidMethod(env,
 216                                obj,
 217                                IosImageLoader_updateImageProgressID,
 218                                100.0f);
 219 
 220         [pool release];
 221 
 222         return ptr_to_jlong(loader);
 223     }
 224 
 225 
 226     /*
 227      * Class:     com_sun_javafx_iio_ios_IosImageLoader
 228      * Method:    resizeImage
 229      * Signature: (JII)V
 230      */
 231     JNIEXPORT void JNICALL Java_com_sun_javafx_iio_ios_IosImageLoader_resizeImage
 232     (JNIEnv *env, jobject obj, jlong loaderRef, jint width, jint height) {
 233 
 234         IIOLog(@"IosImageLoader_resizeImage");
 235 
 236         ImageLoader *loader = (ImageLoader *) jlong_to_ptr(loaderRef);
 237 
 238         [loader resize : (int) width
 239                        : (int) height];
 240     }
 241 
 242     /*
 243      * Class:     com_sun_javafx_iio_ios_IosImageLoader
 244      * Method:    getImageBuffer
 245      * Signature: (JI)[B
 246      */
 247     JNIEXPORT jbyteArray JNICALL Java_com_sun_javafx_iio_ios_IosImageLoader_getImageBuffer
 248     (JNIEnv *env, jobject obj, jlong loaderRef, jint imageIndex) {
 249 
 250         IIOLog(@"IosImageLoader_getImageBuffer for image number %ld", imageIndex);
 251 
 252         ImageLoader *loader = (ImageLoader *) jlong_to_ptr(loaderRef);
 253 
 254         return [loader getDecompressedBuffer : env
 255                                   imageIndex : imageIndex];
 256 
 257     }
 258 
 259     /*
 260      * Class:     com_sun_javafx_iio_ios_IosImageLoader
 261      * Method:    getNumberOfComponents
 262      * Signature: (J)I
 263      */
 264     JNIEXPORT jint JNICALL Java_com_sun_javafx_iio_ios_IosImageLoader_getNumberOfComponents
 265     (JNIEnv *env, jobject obj, jlong loaderRef) {
 266 
 267         IIOLog(@"IosImageLoader_getNumberOfComponents");
 268 
 269         ImageLoader *loader = (ImageLoader *) jlong_to_ptr(loaderRef);
 270 
 271         return (jint) [loader nComponents];
 272     }
 273 
 274     /*
 275      * Class:     com_sun_javafx_iio_ios_IosImageLoader
 276      * Method:    getColorSpaceCode
 277      * Signature: (J)I
 278      */
 279     JNIEXPORT jint JNICALL Java_com_sun_javafx_iio_ios_IosImageLoader_getColorSpaceCode
 280     (JNIEnv *env, jobject obj, jlong loaderRef) {
 281 
 282         IIOLog(@"IosImageLoader_getColorSpaceCode");
 283 
 284         ImageLoader *loader = (ImageLoader *) jlong_to_ptr(loaderRef);
 285 
 286         return (jint) [loader colorSpace];
 287     }
 288 
 289     /*
 290      * Class:     com_sun_javafx_iio_ios_IosImageLoader
 291      * Method:    getDelayTime
 292      * Signature: (J)I
 293      */
 294     JNIEXPORT jint JNICALL Java_com_sun_javafx_iio_ios_IosImageLoader_getDelayTime
 295     (JNIEnv *env, jobject obj, jlong loaderRef) {
 296 
 297         IIOLog(@"IosImageLoader_getDelayTime");
 298 
 299         ImageLoader *loader = (ImageLoader *) jlong_to_ptr(loaderRef);
 300 
 301         return (jint) [loader delayTime];
 302     }
 303 
 304     /*
 305      * Class:     com_sun_javafx_iio_ios_IosImageLoader
 306      * Method:    disposeLoader
 307      * Signature: (J)V
 308      */
 309     JNIEXPORT void JNICALL Java_com_sun_javafx_iio_ios_IosImageLoader_disposeLoader
 310     (JNIEnv *env, jclass klazz, jlong loaderRef) {
 311 
 312         IIOLog(@"IosImageLoader_disposeLoader");
 313 
 314         ImageLoader *loader = (ImageLoader *) jlong_to_ptr(loaderRef);
 315 
 316         [loader release];
 317     }
 318 
 319 #ifdef __cplusplus
 320 }
 321 #endif