2 Copyright (C) 1999, 2003, 2004, 2005, 2006 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. */
40 #include <gdk-pixbuf/gdk-pixbuf.h>
41 #include <gdk-pixbuf/gdk-pixbuf-loader.h>
45 #include "native_state.h"
46 #include "gnu_java_awt_peer_gtk_GdkPixbufDecoder.h"
51 static struct state_table
*native_pixbufdecoder_state_table
;
53 #define NSA_PB_INIT(env, clazz) \
54 native_pixbufdecoder_state_table = cp_gtk_init_state_table (env, clazz)
56 #define NSA_GET_PB_PTR(env, obj) \
57 cp_gtk_get_state (env, obj, native_pixbufdecoder_state_table)
59 #define NSA_SET_PB_PTR(env, obj, ptr) \
60 cp_gtk_set_state (env, obj, native_pixbufdecoder_state_table, (void *)ptr)
62 #define NSA_DEL_PB_PTR(env, obj) \
63 cp_gtk_remove_state_slot (env, obj, native_pixbufdecoder_state_table)
65 /* Union used for type punning. */
74 static jmethodID areaPreparedID
;
75 static jmethodID areaUpdatedID
;
76 static jmethodID dataOutputWriteID
;
77 static jmethodID registerFormatID
;
80 area_prepared_cb (GdkPixbufLoader
*loader
,
87 GdkPixbuf
*pixbuf
= NULL
;
89 pixbuf
= gdk_pixbuf_loader_get_pixbuf (loader
);
90 g_assert (pixbuf
!= NULL
);
92 width
= gdk_pixbuf_get_width (pixbuf
);
93 height
= gdk_pixbuf_get_height (pixbuf
);
95 g_assert (decoder
!= NULL
);
98 (*vm
)->GetEnv (vm
, e
.void_env
, JNI_VERSION_1_1
);
100 (*env
)->CallVoidMethod (env
,
107 area_updated_cb (GdkPixbufLoader
*loader
,
109 gint width
, gint height
,
114 jint stride_bytes
, stride_pixels
, n_channels
, n_pixels
;
119 GdkPixbuf
*pixbuf_no_alpha
= NULL
;
120 GdkPixbuf
*pixbuf
= NULL
;
122 #ifndef WORDS_BIGENDIAN
126 pixbuf_no_alpha
= gdk_pixbuf_loader_get_pixbuf (loader
);
127 if (pixbuf_no_alpha
== NULL
)
130 pixbuf
= gdk_pixbuf_add_alpha(pixbuf_no_alpha
, FALSE
, 0, 0, 0);
131 g_assert (gdk_pixbuf_get_has_alpha (pixbuf
));
133 stride_bytes
= gdk_pixbuf_get_rowstride (pixbuf
);
134 n_channels
= gdk_pixbuf_get_n_channels (pixbuf
);
135 stride_pixels
= stride_bytes
/ n_channels
;
136 n_pixels
= height
* stride_pixels
;
137 gdk_pixels
= gdk_pixbuf_get_pixels (pixbuf
);
140 (*vm
)->GetEnv (vm
, e
.void_env
, JNI_VERSION_1_1
);
142 jpixels
= (*env
)->NewIntArray (env
, n_pixels
);
144 java_pixels
= (*env
)->GetIntArrayElements (env
, jpixels
, NULL
);
147 gdk_pixels
+ (y
* stride_bytes
),
148 (height
* stride_bytes
));
150 #ifndef WORDS_BIGENDIAN
151 /* convert pixels from 0xBBGGRRAA to 0xAARRGGBB */
152 for (i
= 0; i
< n_pixels
; ++i
)
154 java_pixels
[i
] = SWAPU32 ((unsigned)java_pixels
[i
]);
158 g_object_unref (pixbuf
);
160 (*env
)->ReleaseIntArrayElements (env
, jpixels
, java_pixels
, 0);
162 (*env
)->CallVoidMethod (env
,
166 (jint
) width
, (jint
) height
,
170 (*env
)->DeleteLocalRef(env
, jpixels
);
174 closed_cb (GdkPixbufLoader
*loader
__attribute__((unused
)), jobject
*decoder
)
179 (*vm
)->GetEnv (vm
, e
.void_env
, JNI_VERSION_1_1
);
181 (*env
)->DeleteGlobalRef (env
, *decoder
);
187 JNIEXPORT
void JNICALL
188 Java_gnu_java_awt_peer_gtk_GdkPixbufDecoder_initState
189 (JNIEnv
*env
, jobject obj
)
191 GdkPixbufLoader
*loader
= NULL
;
192 jobject
*decoder
= NULL
;
194 decoder
= (jobject
*) g_malloc (sizeof (jobject
));
195 g_assert (decoder
!= NULL
);
196 *decoder
= (*env
)->NewGlobalRef (env
, obj
);
198 loader
= gdk_pixbuf_loader_new ();
199 g_assert (loader
!= NULL
);
200 g_signal_connect (loader
, "area-prepared", G_CALLBACK (area_prepared_cb
), decoder
);
201 g_signal_connect (loader
, "area-updated", G_CALLBACK (area_updated_cb
), decoder
);
202 g_signal_connect (loader
, "closed", G_CALLBACK (closed_cb
), decoder
);
204 NSA_SET_PB_PTR (env
, obj
, loader
);
208 query_formats (JNIEnv
*env
, jclass clazz
)
212 GdkPixbufFormat
*format
;
216 jmethodID addExtensionID
;
217 jmethodID addMimeTypeID
;
220 formatClass
= (*env
)->FindClass
221 (env
, "gnu/java/awt/peer/gtk/GdkPixbufDecoder$ImageFormatSpec");
223 g_assert(formatClass
!= NULL
);
225 addExtensionID
= (*env
)->GetMethodID (env
, formatClass
,
227 "(Ljava/lang/String;)V");
229 addMimeTypeID
= (*env
)->GetMethodID (env
, formatClass
,
231 "(Ljava/lang/String;)V");
233 formats
= gdk_pixbuf_get_formats ();
235 for (f
= formats
; f
; f
= f
->next
)
237 format
= (GdkPixbufFormat
*) f
->data
;
238 name
= gdk_pixbuf_format_get_name(format
);
240 string
= (*env
)->NewStringUTF(env
, name
);
241 g_assert(string
!= NULL
);
243 jformat
= (*env
)->CallStaticObjectMethod
244 (env
, clazz
, registerFormatID
, string
,
245 (jboolean
) gdk_pixbuf_format_is_writable(format
));
246 (*env
)->DeleteLocalRef(env
, string
);
248 g_assert(jformat
!= NULL
);
250 ch
= gdk_pixbuf_format_get_extensions(format
);
253 string
= (*env
)->NewStringUTF(env
, *ch
);
254 g_assert(string
!= NULL
);
255 (*env
)->CallVoidMethod (env
, jformat
, addExtensionID
, string
);
256 (*env
)->DeleteLocalRef(env
, string
);
260 ch
= gdk_pixbuf_format_get_mime_types(format
);
263 string
= (*env
)->NewStringUTF(env
, *ch
);
264 g_assert(string
!= NULL
);
265 (*env
)->CallVoidMethod (env
, jformat
, addMimeTypeID
, string
);
266 (*env
)->DeleteLocalRef(env
, string
);
270 (*env
)->DeleteLocalRef(env
, jformat
);
273 g_slist_free(formats
);
277 JNIEXPORT
void JNICALL
278 Java_gnu_java_awt_peer_gtk_GdkPixbufDecoder_initStaticState
279 (JNIEnv
*env
, jclass clazz
)
281 jclass dataOutputClass
;
283 (*env
)->GetJavaVM(env
, &vm
);
285 areaPreparedID
= (*env
)->GetMethodID (env
, clazz
,
289 areaUpdatedID
= (*env
)->GetMethodID (env
, clazz
,
293 registerFormatID
= (*env
)->GetStaticMethodID
296 "(Ljava/lang/String;Z)"
297 "Lgnu/java/awt/peer/gtk/GdkPixbufDecoder$ImageFormatSpec;");
300 dataOutputClass
= (*env
)->FindClass(env
, "java/io/DataOutput");
301 dataOutputWriteID
= (*env
)->GetMethodID (env
, dataOutputClass
,
304 query_formats (env
, clazz
);
306 NSA_PB_INIT (env
, clazz
);
310 JNIEXPORT
void JNICALL
311 Java_gnu_java_awt_peer_gtk_GdkPixbufDecoder_finish
312 (JNIEnv
*env
, jobject obj
, jboolean needs_close
)
314 GdkPixbufLoader
*loader
= NULL
;
316 loader
= (GdkPixbufLoader
*)NSA_DEL_PB_PTR (env
, obj
);
321 gdk_pixbuf_loader_close (loader
, NULL
);
322 g_object_unref (loader
);
325 JNIEXPORT
void JNICALL
326 Java_gnu_java_awt_peer_gtk_GdkPixbufDecoder_pumpDone
327 (JNIEnv
*env
, jobject obj
)
330 GdkPixbufLoader
*loader
= NULL
;
332 loader
= (GdkPixbufLoader
*)NSA_GET_PB_PTR (env
, obj
);
333 g_assert (loader
!= NULL
);
335 gdk_pixbuf_loader_close (loader
, &err
);
339 JCL_ThrowException (env
, "java/io/IOException", err
->message
);
344 struct stream_save_request
351 save_to_stream(const gchar
*buf
,
353 GError
**error
__attribute__((unused
)),
356 struct stream_save_request
*ssr
= (struct stream_save_request
*)data
;
361 /* FIXME. Don't call user code directly on this thread.
362 Store bytes and signal a "pump" thread to deliver to user code.
363 Then we don't have to drop/acquire any locks. */
364 gdk_threads_leave ();
366 jbuf
= (*(ssr
->env
))->NewByteArray ((ssr
->env
), count
);
367 cbuf
= (*(ssr
->env
))->GetByteArrayElements ((ssr
->env
), jbuf
, NULL
);
368 memcpy (cbuf
, buf
, count
);
369 (*(ssr
->env
))->ReleaseByteArrayElements ((ssr
->env
), jbuf
, cbuf
, 0);
370 (*(ssr
->env
))->CallVoidMethod ((ssr
->env
), *(ssr
->stream
),
371 dataOutputWriteID
, jbuf
);
372 (*(ssr
->env
))->DeleteLocalRef((ssr
->env
), jbuf
);
374 gdk_threads_enter ();
380 JNIEXPORT
void JNICALL
381 Java_gnu_java_awt_peer_gtk_GdkPixbufDecoder_streamImage
382 (JNIEnv
*env
, jclass clazz
__attribute__((unused
)),
383 jintArray jarr
, jstring jenctype
, jint width
, jint height
,
384 jboolean hasAlpha
, jobject stream
)
388 guchar a
, r
, g
, b
, *pix
, *p
;
392 struct stream_save_request ssr
;
394 ssr
.stream
= &stream
;
397 ints
= (*env
)->GetIntArrayElements (env
, jarr
, NULL
);
398 pix
= g_malloc(width
* height
* (hasAlpha
? 4 : 3));
400 enctype
= (*env
)->GetStringUTFChars (env
, jenctype
, NULL
);
401 g_assert(enctype
!= NULL
);
403 g_assert (pix
!= NULL
);
404 g_assert (ints
!= NULL
);
407 for (i
= 0; i
< width
*height
; ++i
)
410 * Java encodes pixels as integers in a predictable arithmetic order:
411 * 0xAARRGGBB. Since these are jints, JNI has already byte-swapped
412 * them for us if necessary, so they're in "our" endianness, whatever
413 * that is. It uses 4 bytes per pixel whether or not there's an alpha
417 a
= 0xff & (ints
[i
] >> 24);
418 r
= 0xff & (ints
[i
] >> 16);
419 g
= 0xff & (ints
[i
] >> 8);
423 * GDK-pixbuf has a very different storage model:
425 * - A different alpha order (alpha after colors).
426 * - A different packing model (no alpha -> 3-bytes-per-pixel).
427 * - A different "RGB" order (host memory order, not endian-neutral).
437 pixbuf
= gdk_pixbuf_new_from_data (pix
,
441 width
* (hasAlpha
? 4 : 3), /* rowstride */
443 g_assert (pixbuf
!= NULL
);
445 g_assert(gdk_pixbuf_save_to_callback (pixbuf
,
451 g_object_unref (pixbuf
);
455 (*env
)->ReleaseStringUTFChars (env
, jenctype
, enctype
);
456 (*env
)->ReleaseIntArrayElements (env
, jarr
, ints
, 0);
460 JNIEXPORT
void JNICALL
461 Java_gnu_java_awt_peer_gtk_GdkPixbufDecoder_pumpBytes
462 (JNIEnv
*env
, jobject obj
, jbyteArray jarr
, jint len
)
464 GdkPixbufLoader
*loader
= NULL
;
469 g_assert (jarr
!= NULL
);
471 bytes
= (*env
)->GetByteArrayElements (env
, jarr
, NULL
);
472 g_assert (bytes
!= NULL
);
473 loader
= (GdkPixbufLoader
*)NSA_GET_PB_PTR (env
, obj
);
474 g_assert (loader
!= NULL
);
476 gdk_pixbuf_loader_write (loader
, (const guchar
*) bytes
, len
, &err
);
478 (*env
)->ReleaseByteArrayElements (env
, jarr
, bytes
, 0);
482 JCL_ThrowException (env
, "java/io/IOException", err
->message
);