1 /* 2 * Copyright (c) 2011, 2014, 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 #import "jni_util.h" 26 27 #import <Cocoa/Cocoa.h> 28 29 #import "GeomUtilities.h" 30 #import "ThreadUtilities.h" 31 32 #import "sun_lwawt_macosx_CImage.h" 33 34 35 static void CImage_CopyArrayIntoNSImageRep 36 (jint *srcPixels, jint *dstPixels, int width, int height) 37 { 38 int x, y; 39 // TODO: test this on big endian systems (not sure if its correct)... 40 for (y = 0; y < height; y++) { 41 for (x = 0; x < width; x++) { 42 jint pix = srcPixels[x]; 43 jint a = (pix >> 24) & 0xff; 44 jint r = (pix >> 16) & 0xff; 45 jint g = (pix >> 8) & 0xff; 46 jint b = (pix ) & 0xff; 47 dstPixels[x] = (b << 24) | (g << 16) | (r << 8) | a; 48 } 49 srcPixels += width; // TODO: use explicit scanStride 50 dstPixels += width; 51 } 52 } 53 54 static void CImage_CopyNSImageIntoArray 55 (NSImage *srcImage, jint *dstPixels, NSRect fromRect, NSRect toRect) 56 { 57 int width = toRect.size.width; 58 int height = toRect.size.height; 59 CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB(); 60 CGContextRef cgRef = CGBitmapContextCreate(dstPixels, width, height, 61 8, width * 4, colorspace, 62 kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host); 63 CGColorSpaceRelease(colorspace); 64 NSGraphicsContext *context = [NSGraphicsContext graphicsContextWithGraphicsPort:cgRef flipped:NO]; 65 CGContextRelease(cgRef); 66 NSGraphicsContext *oldContext = [[NSGraphicsContext currentContext] retain]; 67 [NSGraphicsContext setCurrentContext:context]; 68 [srcImage drawInRect:toRect 69 fromRect:fromRect 70 operation:NSCompositeSourceOver 71 fraction:1.0]; 72 [NSGraphicsContext setCurrentContext:oldContext]; 73 [oldContext release]; 74 } 75 76 static NSBitmapImageRep* CImage_CreateImageRep(JNIEnv *env, jintArray buffer, jint width, jint height) 77 { 78 NSBitmapImageRep* imageRep = [[[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL 79 pixelsWide:width 80 pixelsHigh:height 81 bitsPerSample:8 82 samplesPerPixel:4 83 hasAlpha:YES 84 isPlanar:NO 85 colorSpaceName:NSDeviceRGBColorSpace 86 bitmapFormat:NSAlphaFirstBitmapFormat 87 bytesPerRow:width*4 // TODO: use explicit scanStride 88 bitsPerPixel:32] autorelease]; 89 90 jint *imgData = (jint *)[imageRep bitmapData]; 91 if (imgData == NULL) return 0L; 92 93 jint *src = (*env)->GetPrimitiveArrayCritical(env, buffer, NULL); 94 if (src == NULL) return 0L; 95 96 CImage_CopyArrayIntoNSImageRep(src, imgData, width, height); 97 98 (*env)->ReleasePrimitiveArrayCritical(env, buffer, src, JNI_ABORT); 99 100 return imageRep; 101 } 102 103 /* 104 * Class: sun_lwawt_macosx_CImage 105 * Method: nativeCreateNSImageFromArray 106 * Signature: ([III)J 107 */ 108 JNIEXPORT jlong JNICALL Java_sun_lwawt_macosx_CImage_nativeCreateNSImageFromArray 109 (JNIEnv *env, jclass klass, jintArray buffer, jint width, jint height) 110 { 111 jlong result = 0L; 112 113 JNI_COCOA_ENTER(env); 114 115 NSBitmapImageRep* imageRep = CImage_CreateImageRep(env, buffer, width, height); 116 if (imageRep) { 117 NSImage *nsImage = [[NSImage alloc] initWithSize:NSMakeSize(width, height)]; 118 [nsImage addRepresentation:imageRep]; 119 result = ptr_to_jlong(nsImage); 120 } 121 122 JNI_COCOA_EXIT(env); 123 124 return result; 125 } 126 127 /* 128 * Class: sun_lwawt_macosx_CImage 129 * Method: nativeCreateNSImageFromArrays 130 * Signature: ([[I[I[I)J 131 */ 132 JNIEXPORT jlong JNICALL Java_sun_lwawt_macosx_CImage_nativeCreateNSImageFromArrays 133 (JNIEnv *env, jclass klass, jobjectArray buffers, jintArray widths, jintArray heights) 134 { 135 jlong result = 0L; 136 137 JNI_COCOA_ENTER(env); 138 139 jsize num = (*env)->GetArrayLength(env, buffers); 140 NSMutableArray * reps = [NSMutableArray arrayWithCapacity: num]; 141 142 jint * ws = (*env)->GetIntArrayElements(env, widths, NULL); 143 if (ws != NULL) { 144 jint * hs = (*env)->GetIntArrayElements(env, heights, NULL); 145 if (hs != NULL) { 146 jsize i; 147 for (i = 0; i < num; i++) { 148 jintArray buffer = (*env)->GetObjectArrayElement(env, buffers, i); 149 150 NSBitmapImageRep* imageRep = CImage_CreateImageRep(env, buffer, ws[i], hs[i]); 151 if (imageRep) { 152 [reps addObject: imageRep]; 153 } 154 } 155 156 (*env)->ReleaseIntArrayElements(env, heights, hs, JNI_ABORT); 157 } 158 (*env)->ReleaseIntArrayElements(env, widths, ws, JNI_ABORT); 159 } 160 if ([reps count]) { 161 NSImage *nsImage = [[NSImage alloc] initWithSize:NSMakeSize(0, 0)]; 162 [nsImage addRepresentations: reps]; 163 result = ptr_to_jlong(nsImage); 164 } 165 166 JNI_COCOA_EXIT(env); 167 168 return result; 169 } 170 171 /* 172 * Class: sun_lwawt_macosx_CImage 173 * Method: nativeCreateNSImageFromIconSelector 174 * Signature: (I)J 175 */ 176 JNIEXPORT jlong JNICALL Java_sun_lwawt_macosx_CImage_nativeCreateNSImageFromIconSelector 177 (JNIEnv *env, jclass klass, jint selector) 178 { 179 NSImage *image = nil; 180 181 JNI_COCOA_ENTER(env); 182 183 IconRef iconRef; 184 if (noErr == GetIconRef(kOnSystemDisk, kSystemIconsCreator, selector, &iconRef)) { 185 image = [[NSImage alloc] initWithIconRef:iconRef]; 186 ReleaseIconRef(iconRef); 187 } 188 189 JNI_COCOA_EXIT(env); 190 191 return ptr_to_jlong(image); 192 } 193 194 /* 195 * Class: sun_lwawt_macosx_CImage 196 * Method: nativeCreateNSImageFromFileContents 197 * Signature: (Ljava/lang/String;)J 198 */ 199 JNIEXPORT jlong JNICALL Java_sun_lwawt_macosx_CImage_nativeCreateNSImageFromFileContents 200 (JNIEnv *env, jclass klass, jstring file) 201 { 202 NSImage *image = nil; 203 204 JNI_COCOA_ENTER(env); 205 206 NSString *path = NormalizedPathNSStringFromJavaString(env, file); 207 image = [[NSImage alloc] initByReferencingFile:path]; 208 209 JNI_COCOA_EXIT(env); 210 211 return ptr_to_jlong(image); 212 } 213 214 /* 215 * Class: sun_lwawt_macosx_CImage 216 * Method: nativeCreateNSImageOfFileFromLaunchServices 217 * Signature: (Ljava/lang/String;)J 218 */ 219 JNIEXPORT jlong JNICALL Java_sun_lwawt_macosx_CImage_nativeCreateNSImageOfFileFromLaunchServices 220 (JNIEnv *env, jclass klass, jstring file) 221 { 222 __block NSImage *image = nil; 223 224 JNI_COCOA_ENTER(env); 225 226 NSString *path = NormalizedPathNSStringFromJavaString(env, file); 227 [ThreadUtilities performOnMainThreadWaiting:YES block:^(){ 228 image = [[[NSWorkspace sharedWorkspace] iconForFile:path] retain]; 229 [image setScalesWhenResized:TRUE]; 230 }]; 231 232 JNI_COCOA_EXIT(env); 233 234 return ptr_to_jlong(image); 235 } 236 237 /* 238 * Class: sun_lwawt_macosx_CImage 239 * Method: nativeCreateNSImageFromImageName 240 * Signature: (Ljava/lang/String;)J 241 */ 242 JNIEXPORT jlong JNICALL Java_sun_lwawt_macosx_CImage_nativeCreateNSImageFromImageName 243 (JNIEnv *env, jclass klass, jstring name) 244 { 245 NSImage *image = nil; 246 247 JNI_COCOA_ENTER(env); 248 249 image = [[NSImage imageNamed:JavaStringToNSString(env, name)] retain]; 250 251 JNI_COCOA_EXIT(env); 252 253 return ptr_to_jlong(image); 254 } 255 256 /* 257 * Class: sun_lwawt_macosx_CImage 258 * Method: nativeCopyNSImageIntoArray 259 * Signature: (J[IIIII)V 260 */ 261 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CImage_nativeCopyNSImageIntoArray 262 (JNIEnv *env, jclass klass, jlong nsImgPtr, jintArray buffer, jint sw, jint sh, 263 jint dw, jint dh) 264 { 265 JNI_COCOA_ENTER(env); 266 267 NSImage *img = (NSImage *)jlong_to_ptr(nsImgPtr); 268 jint *dst = (*env)->GetPrimitiveArrayCritical(env, buffer, NULL); 269 if (dst) { 270 NSRect fromRect = NSMakeRect(0, 0, sw, sh); 271 NSRect toRect = NSMakeRect(0, 0, dw, dh); 272 CImage_CopyNSImageIntoArray(img, dst, fromRect, toRect); 273 (*env)->ReleasePrimitiveArrayCritical(env, buffer, dst, JNI_ABORT); 274 } 275 276 JNI_COCOA_EXIT(env); 277 } 278 279 /* 280 * Class: sun_lwawt_macosx_CImage 281 * Method: nativeGetNSImageSize 282 * Signature: (J)Ljava/awt/geom/Dimension2D; 283 */ 284 JNIEXPORT jobject JNICALL Java_sun_lwawt_macosx_CImage_nativeGetNSImageSize 285 (JNIEnv *env, jclass klass, jlong nsImgPtr) 286 { 287 jobject size = NULL; 288 289 JNI_COCOA_ENTER(env); 290 291 size = NSToJavaSize(env, [(NSImage *)jlong_to_ptr(nsImgPtr) size]); 292 293 JNI_COCOA_EXIT(env); 294 295 return size; 296 } 297 298 /* 299 * Class: sun_lwawt_macosx_CImage 300 * Method: nativeSetNSImageSize 301 * Signature: (JDD)V 302 */ 303 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CImage_nativeSetNSImageSize 304 (JNIEnv *env, jclass clazz, jlong image, jdouble w, jdouble h) 305 { 306 if (!image) return; 307 NSImage *i = (NSImage *)jlong_to_ptr(image); 308 309 JNI_COCOA_ENTER(env); 310 311 [i setScalesWhenResized:TRUE]; 312 [i setSize:NSMakeSize(w, h)]; 313 314 JNI_COCOA_EXIT(env); 315 } 316 317 /* 318 * Class: sun_lwawt_macosx_CImage 319 * Method: nativeResizeNSImageRepresentations 320 * Signature: (JDD)V 321 */ 322 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CImage_nativeResizeNSImageRepresentations 323 (JNIEnv *env, jclass clazz, jlong image, jdouble w, jdouble h) 324 { 325 if (!image) return; 326 NSImage *i = (NSImage *)jlong_to_ptr(image); 327 328 JNI_COCOA_ENTER(env); 329 330 NSImageRep *imageRep = nil; 331 NSArray *imageRepresentations = [i representations]; 332 NSEnumerator *imageEnumerator = [imageRepresentations objectEnumerator]; 333 while ((imageRep = [imageEnumerator nextObject]) != nil) { 334 [imageRep setSize:NSMakeSize(w, h)]; 335 } 336 337 JNI_COCOA_EXIT(env); 338 } 339 340 NSComparisonResult getOrder(BOOL order){ 341 return (NSComparisonResult) (order ? NSOrderedAscending : NSOrderedDescending); 342 } 343 344 /* 345 * Class: sun_lwawt_macosx_CImage 346 * Method: nativeGetNSImageRepresentationsCount 347 * Signature: (JDD)[Ljava/awt/geom/Dimension2D; 348 */ 349 JNIEXPORT jobjectArray JNICALL 350 Java_sun_lwawt_macosx_CImage_nativeGetNSImageRepresentationSizes 351 (JNIEnv *env, jclass clazz, jlong image, jdouble w, jdouble h) 352 { 353 if (!image) return NULL; 354 jobjectArray jreturnArray = NULL; 355 NSImage *img = (NSImage *)jlong_to_ptr(image); 356 357 JNI_COCOA_ENTER(env); 358 359 NSArray *imageRepresentations = [img representations]; 360 if([imageRepresentations count] == 0){ 361 return NULL; 362 } 363 364 NSArray *sortedImageRepresentations = [imageRepresentations 365 sortedArrayUsingComparator: ^(id obj1, id obj2) { 366 367 NSImageRep *imageRep1 = (NSImageRep *) obj1; 368 NSImageRep *imageRep2 = (NSImageRep *) obj2; 369 NSSize size1 = [imageRep1 size]; 370 NSSize size2 = [imageRep2 size]; 371 372 if (NSEqualSizes(size1, size2)) { 373 return getOrder([imageRep1 pixelsWide] <= [imageRep2 pixelsWide] && 374 [imageRep1 pixelsHigh] <= [imageRep2 pixelsHigh]); 375 } 376 377 return getOrder(size1.width <= size2.width && size1.height <= size2.height); 378 }]; 379 380 NSMutableArray *sortedPixelSizes = [[[NSMutableArray alloc] init] autorelease]; 381 NSSize lastSize = [[sortedImageRepresentations lastObject] size]; 382 383 NSUInteger i = [sortedImageRepresentations indexOfObjectPassingTest: 384 ^BOOL(id obj, NSUInteger idx, BOOL *stop) { 385 NSSize imageRepSize = [obj size]; 386 return (w <= imageRepSize.width && h <= imageRepSize.height) 387 || NSEqualSizes(imageRepSize, lastSize); 388 }]; 389 390 NSUInteger count = [sortedImageRepresentations count]; 391 i = (i == NSNotFound) ? count - 1 : i; 392 NSSize bestFitSize = [[sortedImageRepresentations objectAtIndex: i] size]; 393 394 for(; i < count; i++){ 395 NSImageRep *imageRep = [sortedImageRepresentations objectAtIndex: i]; 396 397 if (!NSEqualSizes([imageRep size], bestFitSize)) { 398 break; 399 } 400 401 NSSize pixelSize = NSMakeSize( 402 [imageRep pixelsWide], [imageRep pixelsHigh]); 403 [sortedPixelSizes addObject: [NSValue valueWithSize: pixelSize]]; 404 } 405 406 count = [sortedPixelSizes count]; 407 DECLARE_CLASS_RETURN(jc_Dimension, "java/awt/Dimension", jreturnArray); 408 jreturnArray = (*env)->NewObjectArray(env, count, jc_Dimension, NULL); 409 CHECK_NULL_RETURN(jreturnArray, NULL); 410 411 for(i = 0; i < count; i++){ 412 NSSize pixelSize = [[sortedPixelSizes objectAtIndex: i] sizeValue]; 413 414 (*env)->SetObjectArrayElement(env, jreturnArray, i, 415 NSToJavaSize(env, pixelSize)); 416 JNU_CHECK_EXCEPTION_RETURN(env, NULL); 417 } 418 419 JNI_COCOA_EXIT(env); 420 421 return jreturnArray; 422 } 423 424 /* 425 * Class: sun_lwawt_macosx_CImage 426 * Method: nativeGetPlatformImageBytes 427 * Signature: ([III)[B 428 */ 429 JNIEXPORT jbyteArray JNICALL Java_sun_lwawt_macosx_CImage_nativeGetPlatformImageBytes 430 (JNIEnv *env, jclass klass, jintArray buffer, jint width, jint height) 431 { 432 jbyteArray result = 0L; 433 434 JNI_COCOA_ENTER(env); 435 436 NSBitmapImageRep* imageRep = CImage_CreateImageRep(env, buffer, width, height); 437 if (imageRep) { 438 NSData *tiffImage = [imageRep TIFFRepresentation]; 439 jsize tiffSize = (jsize)[tiffImage length]; 440 result = (*env)->NewByteArray(env, tiffSize); 441 CHECK_NULL_RETURN(result, nil); 442 jbyte *tiffData = (jbyte *)(*env)->GetPrimitiveArrayCritical(env, result, 0); 443 CHECK_NULL_RETURN(tiffData, nil); 444 [tiffImage getBytes:tiffData]; 445 (*env)->ReleasePrimitiveArrayCritical(env, result, tiffData, 0); 446 } 447 448 JNI_COCOA_EXIT(env); 449 450 return result; 451 } 452 453 /* 454 * Class: sun_lwawt_macosx_CImage 455 * Method: nativeCreateNSImageFromBytes 456 * Signature: ([B)J 457 */ 458 JNIEXPORT jlong JNICALL Java_sun_lwawt_macosx_CImage_nativeCreateNSImageFromBytes 459 (JNIEnv *env, jclass klass, jbyteArray sourceData) 460 { 461 jlong result = 0L; 462 CHECK_NULL_RETURN(sourceData, 0L); 463 464 JNI_COCOA_ENTER(env); 465 466 jsize sourceSize = (*env)->GetArrayLength(env, sourceData); 467 if (sourceSize == 0) return 0L; 468 469 jbyte *sourceBytes = (*env)->GetPrimitiveArrayCritical(env, sourceData, NULL); 470 CHECK_NULL_RETURN(sourceBytes, 0L); 471 NSData *rawData = [NSData dataWithBytes:sourceBytes length:sourceSize]; 472 NSImage *newImage = [[NSImage alloc] initWithData:rawData]; 473 474 (*env)->ReleasePrimitiveArrayCritical(env, sourceData, sourceBytes, JNI_ABORT); 475 CHECK_NULL_RETURN(newImage, 0L); 476 477 result = ptr_to_jlong(newImage); 478 JNI_COCOA_EXIT(env); 479 480 return result; 481 }