2 Copyright (C) 2005 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
39 #include "gnu_java_awt_peer_gtk_GtkImage.h"
40 #include <gdk-pixbuf/gdk-pixbuf.h>
42 /* The constant fields in java.awt.Image */
43 #define SCALE_DEFAULT 1
45 #define SCALE_SMOOTH 4
46 #define SCALE_REPLICATE 8
47 #define SCALE_AREA_AVERAGING 16
50 static GdkInterpType mapHints(jint hints);
51 static jboolean offScreen (JNIEnv * env, jobject obj);
52 static void *getData (JNIEnv * env, jobject obj);
53 static void createRawData (JNIEnv * env, jobject obj, void *ptr);
54 static void setWidthHeight (JNIEnv * env, jobject obj, int width, int height);
57 * Loads a pixmap from a file.
59 JNIEXPORT jboolean JNICALL
60 Java_gnu_java_awt_peer_gtk_GtkImage_loadPixbuf
61 (JNIEnv *env, jobject obj, jstring name)
69 /* Don't use the JCL convert function because it throws an exception
71 filename = (*env)->GetStringUTFChars (env, name, 0);
79 pixbuf = gdk_pixbuf_new_from_file (filename, NULL);
82 (*env)->ReleaseStringUTFChars (env, name, filename);
87 width = gdk_pixbuf_get_width (pixbuf);
88 height = gdk_pixbuf_get_height (pixbuf);
90 createRawData (env, obj, pixbuf);
91 setWidthHeight(env, obj, width, height);
92 (*env)->ReleaseStringUTFChars (env, name, filename);
100 * Returns a copy of the pixel data as a java array.
102 JNIEXPORT jintArray JNICALL
103 Java_gnu_java_awt_peer_gtk_GtkImage_getPixels(JNIEnv *env, jobject obj)
106 int width, height, rowstride;
108 jintArray result_array;
109 jint *result_array_iter, *dst;
112 gdk_threads_enter ();
114 pixbuf = cp_gtk_image_get_pixbuf (env, obj);
115 width = gdk_pixbuf_get_width (pixbuf);
116 height = gdk_pixbuf_get_height (pixbuf);
117 rowstride = gdk_pixbuf_get_rowstride (pixbuf);
119 /* Must release the GDK lock before allocating memory through the
120 JVM, since some JVMs use the same lock for allocations and
121 finalization. Deadlock can occur on those JVMs. */
122 gdk_threads_leave ();
124 result_array = (*env)->NewIntArray (env, (width * height));
126 gdk_threads_enter ();
128 dst = result_array_iter =
129 (*env)->GetIntArrayElements (env, result_array, NULL);
132 pixeldata = gdk_pixbuf_get_pixels (pixbuf);
134 g_assert (gdk_pixbuf_get_bits_per_sample (pixbuf) == 8);
136 if (gdk_pixbuf_get_has_alpha (pixbuf))
138 for(i = 0 ; i < height; i++)
140 memcpy(dst, (void *)pixeldata, width * 4);
142 pixeldata += rowstride;
145 for(i = 0; i < height; i++)
147 for(j = 0; j < width; j++)
148 dst[j] = 0xFF000000 |
149 (pixeldata[j*3 + 2] & 0xFF) << 16 |
150 (pixeldata[j*3 + 1] & 0xFF) << 8 |
151 (pixeldata[j*3] & 0xFF);
153 pixeldata += rowstride;
157 if (offScreen (env, obj) == JNI_TRUE)
158 gdk_pixbuf_unref (pixbuf);
160 (*env)->ReleaseIntArrayElements (env, result_array, result_array_iter, 0);
162 gdk_threads_leave ();
168 * Returns a copy of the pixel data as a java array.
171 JNIEXPORT void JNICALL
172 Java_gnu_java_awt_peer_gtk_GtkImage_setPixels(JNIEnv *env, jobject obj,
175 GdkPixbuf *pixbuf = (GdkPixbuf *)getData (env, obj);
176 int width, height, rowstride;
178 jint *src_array_iter, *src;
181 gdk_threads_enter ();
183 width = gdk_pixbuf_get_width (pixbuf);
184 height = gdk_pixbuf_get_height (pixbuf);
185 rowstride = gdk_pixbuf_get_rowstride (pixbuf);
187 src = src_array_iter =
188 (*env)->GetIntArrayElements (env, pixels, NULL);
190 pixeldata = gdk_pixbuf_get_pixels (pixbuf);
191 for(i = 0 ; i < height; i++)
193 memcpy((void *)pixeldata, (void *)src, width * 4);
195 pixeldata += rowstride;
198 (*env)->ReleaseIntArrayElements (env, pixels, src_array_iter, 0);
200 gdk_threads_leave ();
204 * Allocates a Gtk Pixbuf or Pixmap.
206 JNIEXPORT void JNICALL
207 Java_gnu_java_awt_peer_gtk_GtkImage_createPixmap(JNIEnv *env, jobject obj)
213 gdk_threads_enter ();
215 cls = (*env)->GetObjectClass (env, obj);
216 field = (*env)->GetFieldID (env, cls, "width", "I");
217 g_assert (field != 0);
218 width = (*env)->GetIntField (env, obj, field);
220 field = (*env)->GetFieldID (env, cls, "height", "I");
221 g_assert (field != 0);
222 height = (*env)->GetIntField (env, obj, field);
224 if (offScreen (env, obj) == JNI_FALSE)
225 createRawData (env, obj, gdk_pixbuf_new (GDK_COLORSPACE_RGB,
231 createRawData (env, obj, gdk_pixmap_new (NULL, width, height,
232 gdk_rgb_get_visual ()->depth));
234 gdk_threads_leave ();
238 * Frees the Gtk Pixmap.
240 JNIEXPORT void JNICALL
241 Java_gnu_java_awt_peer_gtk_GtkImage_freePixmap(JNIEnv *env, jobject obj)
243 gdk_threads_enter ();
244 if (offScreen (env, obj) == JNI_FALSE)
245 gdk_pixbuf_unref ((GdkPixbuf *)getData (env, obj));
247 gdk_pixmap_unref ((GdkPixmap *)getData (env, obj));
249 gdk_threads_leave ();
253 * Sets this pixmap to a scaled version of the source pixmap.
254 * width and height of the destination GtkImage must be set.
256 JNIEXPORT void JNICALL
257 Java_gnu_java_awt_peer_gtk_GtkImage_createScaledPixmap(JNIEnv *env,
269 gdk_threads_enter ();
271 cls = (*env)->GetObjectClass (env, destination);
272 field = (*env)->GetFieldID (env, cls, "width", "I");
273 g_assert (field != 0);
274 width = (*env)->GetIntField (env, destination, field);
276 field = (*env)->GetFieldID (env, cls, "height", "I");
277 g_assert (field != 0);
278 height = (*env)->GetIntField (env, destination, field);
280 pixbuf = cp_gtk_image_get_pixbuf (env, source);
282 dst = gdk_pixbuf_scale_simple(pixbuf,
286 if (offScreen (env, source) == JNI_TRUE)
287 gdk_pixbuf_unref (pixbuf);
289 createRawData (env, destination, (void *)dst);
291 gdk_threads_leave ();
295 * Draws the pixbuf at x, y, scaled to width and height and
296 * optionally composited with a given background color.
298 JNIEXPORT void JNICALL
299 Java_gnu_java_awt_peer_gtk_GtkImage_drawPixelsScaled
300 (JNIEnv *env, jobject obj, jobject gc_obj,
301 jint bg_red, jint bg_green, jint bg_blue,
302 jint x, jint y, jint width, jint height, jboolean composite)
308 gdk_threads_enter ();
310 bgColor = ((bg_red & 0xFF) << 16) |
311 ((bg_green & 0xFF) << 8) | (bg_blue & 0xFF);
313 g = (struct graphics *) NSA_GET_PTR (env, gc_obj);
315 if (!g || !GDK_IS_DRAWABLE (g->drawable))
317 gdk_threads_leave ();
321 if (offScreen (env, obj) == JNI_FALSE)
323 GdkPixbuf* pixbuf = (GdkPixbuf *)getData (env, obj);
325 /* Scale and composite the image */
326 if (composite == JNI_TRUE)
327 dst = gdk_pixbuf_composite_color_simple (pixbuf,
336 dst = gdk_pixbuf_scale_simple(pixbuf,
338 GDK_INTERP_BILINEAR);
340 gdk_draw_pixbuf (g->drawable,
344 x + g->x_offset, y + g->y_offset,
346 GDK_RGB_DITHER_NORMAL, 0, 0);
347 gdk_pixbuf_unref (dst);
351 GdkPixmap* pixmap = (GdkPixmap *)getData (env, obj);
352 gdk_draw_drawable (g->drawable,
356 x + g->x_offset, y + g->y_offset,
360 gdk_threads_leave ();
364 * Draws the pixbuf at x, y, scaled to width and height and
365 * optionally composited and/or flipped with a given background color.
367 JNIEXPORT void JNICALL
368 Java_gnu_java_awt_peer_gtk_GtkImage_drawPixelsScaledFlipped
369 (JNIEnv *env, jobject obj, jobject gc_obj,
370 jint bg_red, jint bg_green, jint bg_blue,
371 jboolean flipx, jboolean flipy,
372 jint srcx, jint srcy, jint srcwidth, jint srcheight,
373 jint dstx, jint dsty, jint dstwidth, jint dstheight,
377 GdkPixbuf *tmp, *dst;
381 gdk_threads_enter ();
383 bgColor = ((bg_red & 0xFF) << 16) |
384 ((bg_green & 0xFF) << 8) | (bg_blue & 0xFF);
386 g = (struct graphics *) NSA_GET_PTR (env, gc_obj);
388 if (!g || !GDK_IS_DRAWABLE (g->drawable))
390 gdk_threads_leave ();
394 if (offScreen (env, obj) == JNI_FALSE)
396 pixbuf = (GdkPixbuf *)getData (env, obj);
398 /* Get the source area */
399 tmp = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
405 gdk_pixbuf_copy_area (pixbuf,
409 0, 0); /* dst x , dst y */
411 /* Get a pixbuf from the pixmap */
412 GdkDrawable *pixmap = (GdkDrawable *)getData(env, obj);
413 tmp = gdk_pixbuf_get_from_drawable (NULL,
415 gdk_drawable_get_colormap( pixmap ),
417 0, 0, /* dst x , dst y */
418 srcwidth, srcheight);
421 /* FIXME: This #if should be discarded once I feel comfortable about
422 GTK 2.6 dependence */
423 #if GTK_MINOR_VERSION > 4
424 /* Flip it if necessary. */
425 if (flipx == JNI_TRUE)
427 GdkPixbuf *tmp2 = gdk_pixbuf_flip (tmp, TRUE);
428 gdk_pixbuf_unref (tmp);
431 if (flipy == JNI_TRUE)
433 GdkPixbuf *tmp2 = gdk_pixbuf_flip (tmp, FALSE);
434 gdk_pixbuf_unref (tmp);
439 /* Scale and composite the image */
440 if (composite == JNI_TRUE)
441 dst = gdk_pixbuf_composite_color_simple (tmp,
450 dst = gdk_pixbuf_scale_simple(tmp,
452 GDK_INTERP_BILINEAR);
453 gdk_pixbuf_unref (tmp);
455 gdk_draw_pixbuf (g->drawable,
459 dstx + g->x_offset, dsty + g->y_offset,
461 GDK_RGB_DITHER_NORMAL, 0, 0);
463 gdk_pixbuf_unref (dst);
465 gdk_threads_leave ();
469 * Used by GtkFramePeer
471 GdkPixbuf *cp_gtk_image_get_pixbuf (JNIEnv *env, jobject obj)
479 if (offScreen (env, obj) == JNI_FALSE)
480 return (GdkPixbuf *)getData (env, obj);
482 cls = (*env)->GetObjectClass (env, obj);
483 field = (*env)->GetFieldID (env, cls, "width", "I");
484 g_assert (field != 0);
485 width = (*env)->GetIntField (env, obj, field);
487 field = (*env)->GetFieldID (env, cls, "height", "I");
488 g_assert (field != 0);
489 height = (*env)->GetIntField (env, obj, field);
492 pixmap = (GdkPixmap *)getData (env, obj);
493 pixbuf = gdk_pixbuf_get_from_drawable (NULL,
495 gdk_drawable_get_colormap( pixmap ),
496 0, 0, /* src x , src y */
497 0, 0, /* dst x , dst y */
503 * Used by GdkGraphics
505 GdkPixmap *cp_gtk_image_get_pixmap (JNIEnv *env, jobject obj)
507 if (offScreen (env, obj) == JNI_FALSE)
509 return (GdkPixmap *)getData (env, obj);
512 jboolean cp_gtk_image_is_offscreen (JNIEnv *env, jobject obj)
514 return offScreen(env, obj);
518 * Maps java.awt.Image scaling hints to the native GDK ones.
520 static GdkInterpType mapHints(jint hints)
524 /* For FAST, we use the nearest-neighbor. Fastest and lowest quality. */
526 case SCALE_REPLICATE:
527 return GDK_INTERP_NEAREST;
529 /* Hyperbolic for smooth. Slowest too. */
531 return GDK_INTERP_HYPER;
533 /* the inbetweenish method */
534 case SCALE_AREA_AVERAGING:
535 return GDK_INTERP_TILES;
537 /* default to bilinear */
539 return GDK_INTERP_BILINEAR;
542 /* Sets the width and height fields of a GtkImage object. */
543 static void setWidthHeight (JNIEnv * env, jobject obj, int width, int height)
548 cls = (*env)->GetObjectClass (env, obj);
550 field = (*env)->GetFieldID (env, cls, "width", "I");
551 g_assert (field != 0);
552 (*env)->SetIntField (env, obj, field, (jint)width);
554 field = (*env)->GetFieldID (env, cls, "height", "I");
555 g_assert (field != 0);
556 (*env)->SetIntField (env, obj, field, (jint)height);
559 /* Returns the value of the offScreen field. */
560 static jboolean offScreen (JNIEnv *env, jobject obj)
565 cls = (*env)->GetObjectClass (env, obj);
566 field = (*env)->GetFieldID (env, cls, "offScreen", "Z");
567 g_assert (field != 0);
568 return (*env)->GetBooleanField (env, obj, field);
571 /* Store and get the pixbuf pointer */
573 createRawData (JNIEnv * env, jobject obj, void *ptr)
580 cls = (*env)->GetObjectClass (env, obj);
581 data_fid = (*env)->GetFieldID (env, cls, "pixmap",
582 "Lgnu/classpath/RawData;");
583 g_assert (data_fid != 0);
585 #if SIZEOF_VOID_P == 8
586 cls = (*env)->FindClass (env, "gnu/classpath/RawData64");
587 method = (*env)->GetMethodID (env, cls, "<init>", "(J)V");
588 data = (*env)->NewObject (env, cls, method, (jlong) ptr);
590 cls = (*env)->FindClass (env, "gnu/classpath/RawData32");
591 method = (*env)->GetMethodID (env, cls, "<init>", "(I)V");
592 data = (*env)->NewObject (env, cls, method, (jint) ptr);
595 (*env)->SetObjectField (env, obj, data_fid, data);
599 getData (JNIEnv * env, jobject obj)
606 cls = (*env)->GetObjectClass (env, obj);
607 data_fid = (*env)->GetFieldID (env, cls, "pixmap",
608 "Lgnu/classpath/RawData;");
609 g_assert (data_fid != 0);
610 data = (*env)->GetObjectField (env, obj, data_fid);
612 #if SIZEOF_VOID_P == 8
613 cls = (*env)->FindClass (env, "gnu/classpath/RawData64");
614 field = (*env)->GetFieldID (env, cls, "data", "J");
615 return (void *) (*env)->GetLongField (env, data, field);
617 cls = (*env)->FindClass (env, "gnu/classpath/RawData32");
618 field = (*env)->GetFieldID (env, cls, "data", "I");
619 return (void *) (*env)->GetIntField (env, data, field);