From 700a98588c995458d893d9288359de01e3d7e557 Mon Sep 17 00:00:00 2001 From: Eric Williams Date: Fri, 24 May 2019 09:35:24 -0400 Subject: Revert "Bug 545032 - [GTK] Implement native ImageLoader" This reverts commit 719370e9e5d83ce319f5ebade0ff5ecb80cf8497. I had to revert the original ImageLoader patch as there were too many regressions to handle in time for 4.12. Attached to this revert commit are also two bug snippets (which show the regressions), and updates to the ImageLoader JUnit test. Change-Id: Id7ef4693481d9eed7d90250e1184a127228d9d91 Signed-off-by: Eric Williams --- .../Eclipse SWT PI/gtk/library/os.c | 188 ------ .../Eclipse SWT PI/gtk/library/os_stats.c | 16 - .../Eclipse SWT PI/gtk/library/os_stats.h | 16 - .../gtk/org/eclipse/swt/internal/gtk/GDK.java | 152 ----- .../gtk/org/eclipse/swt/internal/gtk/OS.java | 24 - .../org/eclipse/swt/graphics/ImageLoader.java | 348 ----------- .../common/org/eclipse/swt/graphics/ImageData.java | 2 - .../org/eclipse/swt/graphics/ImageLoader.java | 348 +++++++++++ .../gtk/org/eclipse/swt/graphics/ImageLoader.java | 664 --------------------- .../org/eclipse/swt/graphics/ImageLoader.java | 348 ----------- .../snippets/Bug545032_ImageLoaderBenchmark.java | 43 -- .../gtk/snippets/Bug547529_ControlPrintBroken.java | 111 ++++ .../snippets/Bug547529_ImageLoaderStriping.java | 85 +++ .../Test_org_eclipse_swt_graphics_ImageLoader.java | 58 ++ 14 files changed, 602 insertions(+), 1801 deletions(-) delete mode 100644 bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/ImageLoader.java create mode 100644 bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/graphics/ImageLoader.java delete mode 100644 bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/graphics/ImageLoader.java delete mode 100644 bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/ImageLoader.java delete mode 100644 tests/org.eclipse.swt.tests.gtk/ManualTests/org/eclipse/swt/tests/gtk/snippets/Bug545032_ImageLoaderBenchmark.java create mode 100644 tests/org.eclipse.swt.tests.gtk/ManualTests/org/eclipse/swt/tests/gtk/snippets/Bug547529_ControlPrintBroken.java create mode 100644 tests/org.eclipse.swt.tests.gtk/ManualTests/org/eclipse/swt/tests/gtk/snippets/Bug547529_ImageLoaderStriping.java diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os.c b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os.c index f88e3fd40d..698a049061 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os.c +++ b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os.c @@ -1527,90 +1527,6 @@ fail: } #endif -#ifndef NO__1gdk_1pixbuf_1animation_1get_1iter -JNIEXPORT jlong JNICALL GDK_NATIVE(_1gdk_1pixbuf_1animation_1get_1iter) - (JNIEnv *env, jclass that, jlong arg0, jlong arg1) -{ - jlong rc = 0; - GDK_NATIVE_ENTER(env, that, _1gdk_1pixbuf_1animation_1get_1iter_FUNC); - rc = (jlong)gdk_pixbuf_animation_get_iter((GdkPixbufAnimation *)arg0, (const GTimeVal *)arg1); - GDK_NATIVE_EXIT(env, that, _1gdk_1pixbuf_1animation_1get_1iter_FUNC); - return rc; -} -#endif - -#ifndef NO__1gdk_1pixbuf_1animation_1get_1static_1image -JNIEXPORT jlong JNICALL GDK_NATIVE(_1gdk_1pixbuf_1animation_1get_1static_1image) - (JNIEnv *env, jclass that, jlong arg0) -{ - jlong rc = 0; - GDK_NATIVE_ENTER(env, that, _1gdk_1pixbuf_1animation_1get_1static_1image_FUNC); - rc = (jlong)gdk_pixbuf_animation_get_static_image((GdkPixbufAnimation *)arg0); - GDK_NATIVE_EXIT(env, that, _1gdk_1pixbuf_1animation_1get_1static_1image_FUNC); - return rc; -} -#endif - -#ifndef NO__1gdk_1pixbuf_1animation_1is_1static_1image -JNIEXPORT jboolean JNICALL GDK_NATIVE(_1gdk_1pixbuf_1animation_1is_1static_1image) - (JNIEnv *env, jclass that, jlong arg0) -{ - jboolean rc = 0; - GDK_NATIVE_ENTER(env, that, _1gdk_1pixbuf_1animation_1is_1static_1image_FUNC); - rc = (jboolean)gdk_pixbuf_animation_is_static_image((GdkPixbufAnimation *)arg0); - GDK_NATIVE_EXIT(env, that, _1gdk_1pixbuf_1animation_1is_1static_1image_FUNC); - return rc; -} -#endif - -#ifndef NO__1gdk_1pixbuf_1animation_1iter_1advance -JNIEXPORT jboolean JNICALL GDK_NATIVE(_1gdk_1pixbuf_1animation_1iter_1advance) - (JNIEnv *env, jclass that, jlong arg0, jlong arg1) -{ - jboolean rc = 0; - GDK_NATIVE_ENTER(env, that, _1gdk_1pixbuf_1animation_1iter_1advance_FUNC); - rc = (jboolean)gdk_pixbuf_animation_iter_advance((GdkPixbufAnimationIter *)arg0, (const GTimeVal *)arg1); - GDK_NATIVE_EXIT(env, that, _1gdk_1pixbuf_1animation_1iter_1advance_FUNC); - return rc; -} -#endif - -#ifndef NO__1gdk_1pixbuf_1animation_1iter_1get_1delay_1time -JNIEXPORT jint JNICALL GDK_NATIVE(_1gdk_1pixbuf_1animation_1iter_1get_1delay_1time) - (JNIEnv *env, jclass that, jlong arg0) -{ - jint rc = 0; - GDK_NATIVE_ENTER(env, that, _1gdk_1pixbuf_1animation_1iter_1get_1delay_1time_FUNC); - rc = (jint)gdk_pixbuf_animation_iter_get_delay_time((GdkPixbufAnimationIter *)arg0); - GDK_NATIVE_EXIT(env, that, _1gdk_1pixbuf_1animation_1iter_1get_1delay_1time_FUNC); - return rc; -} -#endif - -#ifndef NO__1gdk_1pixbuf_1animation_1iter_1get_1pixbuf -JNIEXPORT jlong JNICALL GDK_NATIVE(_1gdk_1pixbuf_1animation_1iter_1get_1pixbuf) - (JNIEnv *env, jclass that, jlong arg0) -{ - jlong rc = 0; - GDK_NATIVE_ENTER(env, that, _1gdk_1pixbuf_1animation_1iter_1get_1pixbuf_FUNC); - rc = (jlong)gdk_pixbuf_animation_iter_get_pixbuf((GdkPixbufAnimationIter *)arg0); - GDK_NATIVE_EXIT(env, that, _1gdk_1pixbuf_1animation_1iter_1get_1pixbuf_FUNC); - return rc; -} -#endif - -#ifndef NO__1gdk_1pixbuf_1copy -JNIEXPORT jlong JNICALL GDK_NATIVE(_1gdk_1pixbuf_1copy) - (JNIEnv *env, jclass that, jlong arg0) -{ - jlong rc = 0; - GDK_NATIVE_ENTER(env, that, _1gdk_1pixbuf_1copy_FUNC); - rc = (jlong)gdk_pixbuf_copy((const GdkPixbuf *)arg0); - GDK_NATIVE_EXIT(env, that, _1gdk_1pixbuf_1copy_FUNC); - return rc; -} -#endif - #ifndef NO__1gdk_1pixbuf_1copy_1area JNIEXPORT void JNICALL GDK_NATIVE(_1gdk_1pixbuf_1copy_1area) (JNIEnv *env, jclass that, jlong arg0, jint arg1, jint arg2, jint arg3, jint arg4, jlong arg5, jint arg6, jint arg7) @@ -1621,42 +1537,6 @@ JNIEXPORT void JNICALL GDK_NATIVE(_1gdk_1pixbuf_1copy_1area) } #endif -#ifndef NO__1gdk_1pixbuf_1format_1get_1name -JNIEXPORT jlong JNICALL GDK_NATIVE(_1gdk_1pixbuf_1format_1get_1name) - (JNIEnv *env, jclass that, jlong arg0) -{ - jlong rc = 0; - GDK_NATIVE_ENTER(env, that, _1gdk_1pixbuf_1format_1get_1name_FUNC); - rc = (jlong)gdk_pixbuf_format_get_name((GdkPixbufFormat *)arg0); - GDK_NATIVE_EXIT(env, that, _1gdk_1pixbuf_1format_1get_1name_FUNC); - return rc; -} -#endif - -#ifndef NO__1gdk_1pixbuf_1get_1bits_1per_1sample -JNIEXPORT jint JNICALL GDK_NATIVE(_1gdk_1pixbuf_1get_1bits_1per_1sample) - (JNIEnv *env, jclass that, jlong arg0) -{ - jint rc = 0; - GDK_NATIVE_ENTER(env, that, _1gdk_1pixbuf_1get_1bits_1per_1sample_FUNC); - rc = (jint)gdk_pixbuf_get_bits_per_sample((const GdkPixbuf *)arg0); - GDK_NATIVE_EXIT(env, that, _1gdk_1pixbuf_1get_1bits_1per_1sample_FUNC); - return rc; -} -#endif - -#ifndef NO__1gdk_1pixbuf_1get_1byte_1length -JNIEXPORT jlong JNICALL GDK_NATIVE(_1gdk_1pixbuf_1get_1byte_1length) - (JNIEnv *env, jclass that, jlong arg0) -{ - jlong rc = 0; - GDK_NATIVE_ENTER(env, that, _1gdk_1pixbuf_1get_1byte_1length_FUNC); - rc = (jlong)gdk_pixbuf_get_byte_length((const GdkPixbuf *)arg0); - GDK_NATIVE_EXIT(env, that, _1gdk_1pixbuf_1get_1byte_1length_FUNC); - return rc; -} -#endif - #ifndef NO__1gdk_1pixbuf_1get_1has_1alpha JNIEXPORT jboolean JNICALL GDK_NATIVE(_1gdk_1pixbuf_1get_1has_1alpha) (JNIEnv *env, jclass that, jlong arg0) @@ -1681,18 +1561,6 @@ JNIEXPORT jint JNICALL GDK_NATIVE(_1gdk_1pixbuf_1get_1height) } #endif -#ifndef NO__1gdk_1pixbuf_1get_1n_1channels -JNIEXPORT jint JNICALL GDK_NATIVE(_1gdk_1pixbuf_1get_1n_1channels) - (JNIEnv *env, jclass that, jlong arg0) -{ - jint rc = 0; - GDK_NATIVE_ENTER(env, that, _1gdk_1pixbuf_1get_1n_1channels_FUNC); - rc = (jint)gdk_pixbuf_get_n_channels((const GdkPixbuf *)arg0); - GDK_NATIVE_EXIT(env, that, _1gdk_1pixbuf_1get_1n_1channels_FUNC); - return rc; -} -#endif - #ifndef NO__1gdk_1pixbuf_1get_1pixels JNIEXPORT jlong JNICALL GDK_NATIVE(_1gdk_1pixbuf_1get_1pixels) (JNIEnv *env, jclass that, jlong arg0) @@ -1745,30 +1613,6 @@ fail: } #endif -#ifndef NO__1gdk_1pixbuf_1loader_1get_1animation -JNIEXPORT jlong JNICALL GDK_NATIVE(_1gdk_1pixbuf_1loader_1get_1animation) - (JNIEnv *env, jclass that, jlong arg0) -{ - jlong rc = 0; - GDK_NATIVE_ENTER(env, that, _1gdk_1pixbuf_1loader_1get_1animation_FUNC); - rc = (jlong)gdk_pixbuf_loader_get_animation((GdkPixbufLoader *)arg0); - GDK_NATIVE_EXIT(env, that, _1gdk_1pixbuf_1loader_1get_1animation_FUNC); - return rc; -} -#endif - -#ifndef NO__1gdk_1pixbuf_1loader_1get_1format -JNIEXPORT jlong JNICALL GDK_NATIVE(_1gdk_1pixbuf_1loader_1get_1format) - (JNIEnv *env, jclass that, jlong arg0) -{ - jlong rc = 0; - GDK_NATIVE_ENTER(env, that, _1gdk_1pixbuf_1loader_1get_1format_FUNC); - rc = (jlong)gdk_pixbuf_loader_get_format((GdkPixbufLoader *)arg0); - GDK_NATIVE_EXIT(env, that, _1gdk_1pixbuf_1loader_1get_1format_FUNC); - return rc; -} -#endif - #ifndef NO__1gdk_1pixbuf_1loader_1get_1pixbuf JNIEXPORT jlong JNICALL GDK_NATIVE(_1gdk_1pixbuf_1loader_1get_1pixbuf) (JNIEnv *env, jclass that, jlong arg0) @@ -1821,18 +1665,6 @@ JNIEXPORT jlong JNICALL GDK_NATIVE(_1gdk_1pixbuf_1new) } #endif -#ifndef NO__1gdk_1pixbuf_1new_1from_1data -JNIEXPORT jlong JNICALL GDK_NATIVE(_1gdk_1pixbuf_1new_1from_1data) - (JNIEnv *env, jclass that, jlong arg0, jint arg1, jboolean arg2, jint arg3, jint arg4, jint arg5, jint arg6, jlong arg7, jlong arg8) -{ - jlong rc = 0; - GDK_NATIVE_ENTER(env, that, _1gdk_1pixbuf_1new_1from_1data_FUNC); - rc = (jlong)gdk_pixbuf_new_from_data((const guchar *)arg0, (GdkColorspace)arg1, (gboolean)arg2, arg3, arg4, arg5, arg6, (GdkPixbufDestroyNotify)arg7, (gpointer)arg8); - GDK_NATIVE_EXIT(env, that, _1gdk_1pixbuf_1new_1from_1data_FUNC); - return rc; -} -#endif - #ifndef NO__1gdk_1pixbuf_1new_1from_1file JNIEXPORT jlong JNICALL GDK_NATIVE(_1gdk_1pixbuf_1new_1from_1file) (JNIEnv *env, jclass that, jbyteArray arg0, jlongArray arg1) @@ -15024,16 +14856,6 @@ fail: } #endif -#ifndef NO__1g_1get_1current_1time -JNIEXPORT void JNICALL OS_NATIVE(_1g_1get_1current_1time) - (JNIEnv *env, jclass that, jlong arg0) -{ - OS_NATIVE_ENTER(env, that, _1g_1get_1current_1time_FUNC); - g_get_current_time((GTimeVal *)arg0); - OS_NATIVE_EXIT(env, that, _1g_1get_1current_1time_FUNC); -} -#endif - #ifndef NO__1g_1getenv JNIEXPORT jlong JNICALL OS_NATIVE(_1g_1getenv) (JNIEnv *env, jclass that, jbyteArray arg0) @@ -15999,16 +15821,6 @@ fail: } #endif -#ifndef NO__1g_1time_1val_1add -JNIEXPORT void JNICALL OS_NATIVE(_1g_1time_1val_1add) - (JNIEnv *env, jclass that, jlong arg0, jlong arg1) -{ - OS_NATIVE_ENTER(env, that, _1g_1time_1val_1add_FUNC); - g_time_val_add((GTimeVal *)arg0, (glong)arg1); - OS_NATIVE_EXIT(env, that, _1g_1time_1val_1add_FUNC); -} -#endif - #ifndef NO__1g_1timeout_1add JNIEXPORT jint JNICALL OS_NATIVE(_1g_1timeout_1add) (JNIEnv *env, jclass that, jint arg0, jlong arg1, jlong arg2) diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_stats.c b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_stats.c index 3d9d40141a..dcb6536bff 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_stats.c +++ b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_stats.c @@ -125,31 +125,17 @@ char * GDK_nativeFunctionNames[] = { "_1gdk_1monitor_1get_1workarea", "_1gdk_1pango_1context_1get", "_1gdk_1pango_1layout_1get_1clip_1region", - "_1gdk_1pixbuf_1animation_1get_1iter", - "_1gdk_1pixbuf_1animation_1get_1static_1image", - "_1gdk_1pixbuf_1animation_1is_1static_1image", - "_1gdk_1pixbuf_1animation_1iter_1advance", - "_1gdk_1pixbuf_1animation_1iter_1get_1delay_1time", - "_1gdk_1pixbuf_1animation_1iter_1get_1pixbuf", - "_1gdk_1pixbuf_1copy", "_1gdk_1pixbuf_1copy_1area", - "_1gdk_1pixbuf_1format_1get_1name", - "_1gdk_1pixbuf_1get_1bits_1per_1sample", - "_1gdk_1pixbuf_1get_1byte_1length", "_1gdk_1pixbuf_1get_1has_1alpha", "_1gdk_1pixbuf_1get_1height", - "_1gdk_1pixbuf_1get_1n_1channels", "_1gdk_1pixbuf_1get_1pixels", "_1gdk_1pixbuf_1get_1rowstride", "_1gdk_1pixbuf_1get_1width", "_1gdk_1pixbuf_1loader_1close", - "_1gdk_1pixbuf_1loader_1get_1animation", - "_1gdk_1pixbuf_1loader_1get_1format", "_1gdk_1pixbuf_1loader_1get_1pixbuf", "_1gdk_1pixbuf_1loader_1new", "_1gdk_1pixbuf_1loader_1write", "_1gdk_1pixbuf_1new", - "_1gdk_1pixbuf_1new_1from_1data", "_1gdk_1pixbuf_1new_1from_1file", "_1gdk_1pixbuf_1save_1to_1bufferv", "_1gdk_1pixbuf_1scale_1simple", @@ -1239,7 +1225,6 @@ char * OS_nativeFunctionNames[] = { "_1g_1filename_1from_1utf8", "_1g_1filename_1to_1uri", "_1g_1filename_1to_1utf8", - "_1g_1get_1current_1time", "_1g_1getenv", "_1g_1hash_1table_1get_1values", "_1g_1icon_1new_1for_1string", @@ -1314,7 +1299,6 @@ char * OS_nativeFunctionNames[] = { "_1g_1string_1free", "_1g_1string_1new_1len", "_1g_1strtod", - "_1g_1time_1val_1add", "_1g_1timeout_1add", "_1g_1type_1add_1interface_1static", "_1g_1type_1class_1peek", diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_stats.h b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_stats.h index acb253ec53..c81fa779a3 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_stats.h +++ b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_stats.h @@ -135,31 +135,17 @@ typedef enum { _1gdk_1monitor_1get_1workarea_FUNC, _1gdk_1pango_1context_1get_FUNC, _1gdk_1pango_1layout_1get_1clip_1region_FUNC, - _1gdk_1pixbuf_1animation_1get_1iter_FUNC, - _1gdk_1pixbuf_1animation_1get_1static_1image_FUNC, - _1gdk_1pixbuf_1animation_1is_1static_1image_FUNC, - _1gdk_1pixbuf_1animation_1iter_1advance_FUNC, - _1gdk_1pixbuf_1animation_1iter_1get_1delay_1time_FUNC, - _1gdk_1pixbuf_1animation_1iter_1get_1pixbuf_FUNC, - _1gdk_1pixbuf_1copy_FUNC, _1gdk_1pixbuf_1copy_1area_FUNC, - _1gdk_1pixbuf_1format_1get_1name_FUNC, - _1gdk_1pixbuf_1get_1bits_1per_1sample_FUNC, - _1gdk_1pixbuf_1get_1byte_1length_FUNC, _1gdk_1pixbuf_1get_1has_1alpha_FUNC, _1gdk_1pixbuf_1get_1height_FUNC, - _1gdk_1pixbuf_1get_1n_1channels_FUNC, _1gdk_1pixbuf_1get_1pixels_FUNC, _1gdk_1pixbuf_1get_1rowstride_FUNC, _1gdk_1pixbuf_1get_1width_FUNC, _1gdk_1pixbuf_1loader_1close_FUNC, - _1gdk_1pixbuf_1loader_1get_1animation_FUNC, - _1gdk_1pixbuf_1loader_1get_1format_FUNC, _1gdk_1pixbuf_1loader_1get_1pixbuf_FUNC, _1gdk_1pixbuf_1loader_1new_FUNC, _1gdk_1pixbuf_1loader_1write_FUNC, _1gdk_1pixbuf_1new_FUNC, - _1gdk_1pixbuf_1new_1from_1data_FUNC, _1gdk_1pixbuf_1new_1from_1file_FUNC, _1gdk_1pixbuf_1save_1to_1bufferv_FUNC, _1gdk_1pixbuf_1scale_1simple_FUNC, @@ -1213,7 +1199,6 @@ typedef enum { _1g_1filename_1from_1utf8_FUNC, _1g_1filename_1to_1uri_FUNC, _1g_1filename_1to_1utf8_FUNC, - _1g_1get_1current_1time_FUNC, _1g_1getenv_FUNC, _1g_1hash_1table_1get_1values_FUNC, _1g_1icon_1new_1for_1string_FUNC, @@ -1288,7 +1273,6 @@ typedef enum { _1g_1string_1free_FUNC, _1g_1string_1new_1len_FUNC, _1g_1strtod_FUNC, - _1g_1time_1val_1add_FUNC, _1g_1timeout_1add_FUNC, _1g_1type_1add_1interface_1static_FUNC, _1g_1type_1class_1peek_FUNC, diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/org/eclipse/swt/internal/gtk/GDK.java b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/org/eclipse/swt/internal/gtk/GDK.java index 6132c5c132..9de1f9675d 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/org/eclipse/swt/internal/gtk/GDK.java +++ b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/org/eclipse/swt/internal/gtk/GDK.java @@ -1459,72 +1459,6 @@ public class GDK extends OS { lock.unlock(); } } - /** @param animation cast=(GdkPixbufAnimation *) */ - public static final native boolean _gdk_pixbuf_animation_is_static_image(long animation); - public static final boolean gdk_pixbuf_animation_is_static_image(long animation) { - lock.lock(); - try { - return _gdk_pixbuf_animation_is_static_image(animation); - } finally { - lock.unlock(); - } - } - /** @param iter cast=(GdkPixbufAnimationIter *) */ - public static final native int _gdk_pixbuf_animation_iter_get_delay_time(long iter); - public static final int gdk_pixbuf_animation_iter_get_delay_time(long iter) { - lock.lock(); - try { - return _gdk_pixbuf_animation_iter_get_delay_time(iter); - } finally { - lock.unlock(); - } - } - /** @param iter cast=(GdkPixbufAnimationIter *) */ - public static final native long _gdk_pixbuf_animation_iter_get_pixbuf(long iter); - public static final long gdk_pixbuf_animation_iter_get_pixbuf(long iter) { - lock.lock(); - try { - return _gdk_pixbuf_animation_iter_get_pixbuf(iter); - } finally { - lock.unlock(); - } - } - /** - * @param iter cast=(GdkPixbufAnimationIter *) - * @param current_time cast=(const GTimeVal *) - */ - public static final native boolean _gdk_pixbuf_animation_iter_advance(long iter, long current_time); - public static final boolean gdk_pixbuf_animation_iter_advance(long iter, long current_time) { - lock.lock(); - try { - return _gdk_pixbuf_animation_iter_advance(iter, current_time); - } finally { - lock.unlock(); - } - } - /** - * @param animation cast=(GdkPixbufAnimation *) - * @param start_time cast=(const GTimeVal *) - */ - public static final native long _gdk_pixbuf_animation_get_iter(long animation, long start_time); - public static final long gdk_pixbuf_animation_get_iter(long animation, long start_time) { - lock.lock(); - try { - return _gdk_pixbuf_animation_get_iter(animation, start_time); - } finally { - lock.unlock(); - } - } - /** @param animation cast=(GdkPixbufAnimation *) */ - public static final native long _gdk_pixbuf_animation_get_static_image(long animation); - public static final long gdk_pixbuf_animation_get_static_image(long animation) { - lock.lock(); - try { - return _gdk_pixbuf_animation_get_static_image(animation); - } finally { - lock.unlock(); - } - } /** * @param src_pixbuf cast=(GdkPixbuf *) * @param dest_pixbuf cast=(GdkPixbuf *) @@ -1588,92 +1522,6 @@ public class GDK extends OS { lock.unlock(); } } - /** @param pixbuf cast=(const GdkPixbuf *) */ - public static final native long _gdk_pixbuf_get_byte_length(long pixbuf); - public static final long gdk_pixbuf_get_byte_length(long pixbuf) { - lock.lock(); - try { - return _gdk_pixbuf_get_byte_length(pixbuf); - } finally { - lock.unlock(); - } - } - /** @param pixbuf cast=(const GdkPixbuf *) */ - public static final native int _gdk_pixbuf_get_n_channels(long pixbuf); - public static final int gdk_pixbuf_get_n_channels(long pixbuf) { - lock.lock(); - try { - return _gdk_pixbuf_get_n_channels(pixbuf); - } finally { - lock.unlock(); - } - } - /** @param pixbuf cast=(const GdkPixbuf *) */ - public static final native int _gdk_pixbuf_get_bits_per_sample(long pixbuf); - public static final int gdk_pixbuf_get_bits_per_sample(long pixbuf) { - lock.lock(); - try { - return _gdk_pixbuf_get_bits_per_sample(pixbuf); - } finally { - lock.unlock(); - } - } - /** @param pixbuf cast=(const GdkPixbuf *) */ - public static final native long _gdk_pixbuf_copy(long pixbuf); - public static final long gdk_pixbuf_copy(long pixbuf) { - lock.lock(); - try { - return _gdk_pixbuf_copy(pixbuf); - } finally { - lock.unlock(); - } - } - /** @param loader cast=(GdkPixbufLoader *) */ - public static final native long _gdk_pixbuf_loader_get_format(long loader); - public static final long gdk_pixbuf_loader_get_format(long loader) { - lock.lock(); - try { - return _gdk_pixbuf_loader_get_format(loader); - } finally { - lock.unlock(); - } - } - /** @param format cast=(GdkPixbufFormat *) */ - public static final native long _gdk_pixbuf_format_get_name(long format); - public static final long gdk_pixbuf_format_get_name(long format) { - lock.lock(); - try { - return _gdk_pixbuf_format_get_name(format); - } finally { - lock.unlock(); - } - } - /** @param loader cast=(GdkPixbufLoader *) */ - public static final native long _gdk_pixbuf_loader_get_animation(long loader); - public static final long gdk_pixbuf_loader_get_animation(long loader) { - lock.lock(); - try { - return _gdk_pixbuf_loader_get_animation(loader); - } finally { - lock.unlock(); - } - } - /** - * @param data cast=(const guchar *) - * @param colorspace cast=(GdkColorspace) - * @param has_alpha cast=(gboolean) - * @param destroy_fn cast=(GdkPixbufDestroyNotify) - * @param destroy_fn_data cast=(gpointer) - */ - public static final native long _gdk_pixbuf_new_from_data(long data, int colorspace, boolean has_alpha, int bits_per_sample, int width, int height, int rowstride, long destroy_fn, long destroy_fn_data); - public static final long gdk_pixbuf_new_from_data(long data, int colorspace, boolean has_alpha, int bits_per_sample, int width, int height, int rowstride, long destroy_fn, long destroy_fn_data) { - lock.lock(); - try { - return _gdk_pixbuf_new_from_data(data, colorspace, has_alpha, bits_per_sample, width, height, rowstride, destroy_fn, destroy_fn_data); - } finally { - lock.unlock(); - } - } public static final native long _gdk_pixbuf_loader_new(); public static final long gdk_pixbuf_loader_new() { lock.lock(); diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/org/eclipse/swt/internal/gtk/OS.java b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/org/eclipse/swt/internal/gtk/OS.java index a6f45d5a87..07ff45dec4 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/org/eclipse/swt/internal/gtk/OS.java +++ b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/org/eclipse/swt/internal/gtk/OS.java @@ -588,30 +588,6 @@ public class OS extends C { } } - /** @param result cast=(GTimeVal *)*/ - public static final native void _g_get_current_time(long result); - public static final void g_get_current_time(long result) { - lock.lock(); - try { - _g_get_current_time(result); - } finally { - lock.unlock(); - } - } - /** - * @param result cast=(GTimeVal *) - * @param microseconds cast=(glong) - */ - public static final native void _g_time_val_add(long result, long microseconds); - public static final void g_time_val_add(long result, long microseconds) { - lock.lock(); - try { - _g_time_val_add(result, microseconds); - } finally { - lock.unlock(); - } - } - /** @param str cast=(const gchar *) * @category custom */ diff --git a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/ImageLoader.java b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/ImageLoader.java deleted file mode 100644 index a8914ea4af..0000000000 --- a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/ImageLoader.java +++ /dev/null @@ -1,348 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2016 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.swt.graphics; - - -import java.io.*; -import java.util.*; - -import org.eclipse.swt.*; -import org.eclipse.swt.internal.image.*; - -/** - * Instances of this class are used to load images from, - * and save images to, a file or stream. - *

- * Currently supported image formats are: - *

- * ImageLoaders can be used to: - * - * - *

- * NOTE: ImageLoader is implemented in Java on some platforms, which has - * certain performance implications. Performance and memory sensitive applications may - * benefit from using one of the constructors provided by Image, as these - * are implemented natively.

- * - * @see SWT Example: ImageAnalyzer - * @see Sample code and further information - */ -public class ImageLoader { - - /** - * the array of ImageData objects in this ImageLoader. - * This array is read in when the load method is called, - * and it is written out when the save method is called - */ - public ImageData[] data; - - /** - * the width of the logical screen on which the images - * reside, in pixels (this corresponds to the GIF89a - * Logical Screen Width value) - */ - public int logicalScreenWidth; - - /** - * the height of the logical screen on which the images - * reside, in pixels (this corresponds to the GIF89a - * Logical Screen Height value) - */ - public int logicalScreenHeight; - - /** - * the background pixel for the logical screen (this - * corresponds to the GIF89a Background Color Index value). - * The default is -1 which means 'unspecified background' - * - */ - public int backgroundPixel; - - /** - * the number of times to repeat the display of a sequence - * of animated images (this corresponds to the commonly-used - * GIF application extension for "NETSCAPE 2.0 01"). - * The default is 1. A value of 0 means 'display repeatedly' - */ - public int repeatCount; - - /** - * This is the compression used when saving jpeg and png files. - *

- * When saving jpeg files, the value is from 1 to 100, - * where 1 is very high compression but low quality, and 100 is - * no compression and high quality; default is 75. - *

- * When saving png files, the value is from 0 to 3, but they do not impact the quality - * because PNG is lossless compression. 0 is uncompressed, 1 is low compression and fast, - * 2 is default compression, and 3 is high compression but slow. - *

- * - * @since 3.8 - */ - public int compression; - - /* - * the set of ImageLoader event listeners, created on demand - */ - List imageLoaderListeners; - -/** - * Construct a new empty ImageLoader. - */ -public ImageLoader() { - reset(); -} - -/** - * Resets the fields of the ImageLoader, except for the - * imageLoaderListeners field. - */ -void reset() { - data = null; - logicalScreenWidth = 0; - logicalScreenHeight = 0; - backgroundPixel = -1; - repeatCount = 1; - compression = -1; -} - -/** - * Loads an array of ImageData objects from the - * specified input stream. Throws an error if either an error - * occurs while loading the images, or if the images are not - * of a supported type. Returns the loaded image data array. - * - * @param stream the input stream to load the images from - * @return an array of ImageData objects loaded from the specified input stream - * - * @exception IllegalArgumentException - * @exception SWTException - */ -public ImageData[] load(InputStream stream) { - if (stream == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); - reset(); - data = FileFormat.load(stream, this); - return data; -} - -/** - * Loads an array of ImageData objects from the - * file with the specified name. Throws an error if either - * an error occurs while loading the images, or if the images are - * not of a supported type. Returns the loaded image data array. - * - * @param filename the name of the file to load the images from - * @return an array of ImageData objects loaded from the specified file - * - * @exception IllegalArgumentException - * @exception SWTException - */ -public ImageData[] load(String filename) { - if (filename == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); - InputStream stream = null; - try { - stream = new FileInputStream(filename); - return load(stream); - } catch (IOException e) { - SWT.error(SWT.ERROR_IO, e); - } finally { - try { - if (stream != null) stream.close(); - } catch (IOException e) { - // Ignore error - } - } - return null; -} - -/** - * Saves the image data in this ImageLoader to the specified stream. - * The format parameter can have one of the following values: - *
- *
IMAGE_BMP
- *
Windows BMP file format, no compression
- *
IMAGE_BMP_RLE
- *
Windows BMP file format, RLE compression if appropriate
- *
IMAGE_GIF
- *
GIF file format
- *
IMAGE_ICO
- *
Windows ICO file format
- *
IMAGE_JPEG
- *
JPEG file format
- *
IMAGE_PNG
- *
PNG file format
- *
- * - * @param stream the output stream to write the images to - * @param format the format to write the images in - * - * @exception IllegalArgumentException - * @exception SWTException - */ -public void save(OutputStream stream, int format) { - if (stream == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); - FileFormat.save(stream, format, this); -} - -/** - * Saves the image data in this ImageLoader to a file with the specified name. - * The format parameter can have one of the following values: - *
- *
IMAGE_BMP
- *
Windows BMP file format, no compression
- *
IMAGE_BMP_RLE
- *
Windows BMP file format, RLE compression if appropriate
- *
IMAGE_GIF
- *
GIF file format
- *
IMAGE_ICO
- *
Windows ICO file format
- *
IMAGE_JPEG
- *
JPEG file format
- *
IMAGE_PNG
- *
PNG file format
- *
- * - * @param filename the name of the file to write the images to - * @param format the format to write the images in - * - * @exception IllegalArgumentException - * @exception SWTException - */ -public void save(String filename, int format) { - if (filename == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); - OutputStream stream = null; - try { - stream = new FileOutputStream(filename); - } catch (IOException e) { - SWT.error(SWT.ERROR_IO, e); - } - save(stream, format); - try { - stream.close(); - } catch (IOException e) { - } -} - -/** - * Adds the listener to the collection of listeners who will be - * notified when image data is either partially or completely loaded. - *

- * An ImageLoaderListener should be added before invoking - * one of the receiver's load methods. The listener's - * imageDataLoaded method is called when image - * data has been partially loaded, as is supported by interlaced - * GIF/PNG or progressive JPEG images. - * - * @param listener the listener which should be notified - * - * @exception IllegalArgumentException

- * - * @see ImageLoaderListener - * @see ImageLoaderEvent - */ -public void addImageLoaderListener(ImageLoaderListener listener) { - if (listener == null) SWT.error (SWT.ERROR_NULL_ARGUMENT); - if (imageLoaderListeners == null) { - imageLoaderListeners = new ArrayList<>(); - } - imageLoaderListeners.add(listener); -} - -/** - * Removes the listener from the collection of listeners who will be - * notified when image data is either partially or completely loaded. - * - * @param listener the listener which should no longer be notified - * - * @exception IllegalArgumentException - * - * @see #addImageLoaderListener(ImageLoaderListener) - */ -public void removeImageLoaderListener(ImageLoaderListener listener) { - if (listener == null) SWT.error (SWT.ERROR_NULL_ARGUMENT); - if (imageLoaderListeners == null) return; - imageLoaderListeners.remove(listener); -} - -/** - * Returns true if the receiver has image loader - * listeners, and false otherwise. - * - * @return true if there are ImageLoaderListeners, and false otherwise - * - * @see #addImageLoaderListener(ImageLoaderListener) - * @see #removeImageLoaderListener(ImageLoaderListener) - */ -public boolean hasListeners() { - return imageLoaderListeners != null && imageLoaderListeners.size() > 0; -} - -/** - * Notifies all image loader listeners that an image loader event - * has occurred. Pass the specified event object to each listener. - * - * @param event the ImageLoaderEvent to send to each ImageLoaderListener - */ -public void notifyListeners(ImageLoaderEvent event) { - if (!hasListeners()) return; - int size = imageLoaderListeners.size(); - for (int i = 0; i < size; i++) { - ImageLoaderListener listener = imageLoaderListeners.get(i); - listener.imageDataLoaded(event); - } -} - -} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/graphics/ImageData.java b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/graphics/ImageData.java index d13ecb1105..2811d54805 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/graphics/ImageData.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/graphics/ImageData.java @@ -333,7 +333,6 @@ public ImageData(int width, int height, int depth, PaletteData palette, int scan */ public ImageData(InputStream stream) { ImageData[] data = ImageDataLoader.load(stream); - if (data == null || data.length < 1) SWT.error(SWT.ERROR_INVALID_IMAGE); if (data.length < 1) SWT.error(SWT.ERROR_INVALID_IMAGE); ImageData i = data[0]; setAllFields( @@ -380,7 +379,6 @@ public ImageData(InputStream stream) { */ public ImageData(String filename) { ImageData[] data = ImageDataLoader.load(filename); - if (data == null || data.length < 1) SWT.error(SWT.ERROR_INVALID_IMAGE); if (data.length < 1) SWT.error(SWT.ERROR_INVALID_IMAGE); ImageData i = data[0]; setAllFields( diff --git a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/graphics/ImageLoader.java b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/graphics/ImageLoader.java new file mode 100644 index 0000000000..89c2cccd8b --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/graphics/ImageLoader.java @@ -0,0 +1,348 @@ +/******************************************************************************* + * Copyright (c) 2000, 2016 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.swt.graphics; + + +import java.io.*; +import java.util.*; + +import org.eclipse.swt.*; +import org.eclipse.swt.internal.image.*; + +/** + * Instances of this class are used to load images from, + * and save images to, a file or stream. + *

+ * Currently supported image formats are: + *

+ * ImageLoaders can be used to: + * + * + *

+ * NOTE: ImageLoader is implemented in Java, which has certain performance + * implications. Performance and memory sensitive applications may benefit from using + * one of the constructors provided by Image, as these are implemented + * natively.

+ * + * @see SWT Example: ImageAnalyzer + * @see Sample code and further information + */ +public class ImageLoader { + + /** + * the array of ImageData objects in this ImageLoader. + * This array is read in when the load method is called, + * and it is written out when the save method is called + */ + public ImageData[] data; + + /** + * the width of the logical screen on which the images + * reside, in pixels (this corresponds to the GIF89a + * Logical Screen Width value) + */ + public int logicalScreenWidth; + + /** + * the height of the logical screen on which the images + * reside, in pixels (this corresponds to the GIF89a + * Logical Screen Height value) + */ + public int logicalScreenHeight; + + /** + * the background pixel for the logical screen (this + * corresponds to the GIF89a Background Color Index value). + * The default is -1 which means 'unspecified background' + * + */ + public int backgroundPixel; + + /** + * the number of times to repeat the display of a sequence + * of animated images (this corresponds to the commonly-used + * GIF application extension for "NETSCAPE 2.0 01"). + * The default is 1. A value of 0 means 'display repeatedly' + */ + public int repeatCount; + + /** + * This is the compression used when saving jpeg and png files. + *

+ * When saving jpeg files, the value is from 1 to 100, + * where 1 is very high compression but low quality, and 100 is + * no compression and high quality; default is 75. + *

+ * When saving png files, the value is from 0 to 3, but they do not impact the quality + * because PNG is lossless compression. 0 is uncompressed, 1 is low compression and fast, + * 2 is default compression, and 3 is high compression but slow. + *

+ * + * @since 3.8 + */ + public int compression; + + /* + * the set of ImageLoader event listeners, created on demand + */ + List imageLoaderListeners; + +/** + * Construct a new empty ImageLoader. + */ +public ImageLoader() { + reset(); +} + +/** + * Resets the fields of the ImageLoader, except for the + * imageLoaderListeners field. + */ +void reset() { + data = null; + logicalScreenWidth = 0; + logicalScreenHeight = 0; + backgroundPixel = -1; + repeatCount = 1; + compression = -1; +} + +/** + * Loads an array of ImageData objects from the + * specified input stream. Throws an error if either an error + * occurs while loading the images, or if the images are not + * of a supported type. Returns the loaded image data array. + * + * @param stream the input stream to load the images from + * @return an array of ImageData objects loaded from the specified input stream + * + * @exception IllegalArgumentException
    + *
  • ERROR_NULL_ARGUMENT - if the stream is null
  • + *
+ * @exception SWTException
    + *
  • ERROR_IO - if an IO error occurs while reading from the stream
  • + *
  • ERROR_INVALID_IMAGE - if the image stream contains invalid data
  • + *
  • ERROR_UNSUPPORTED_FORMAT - if the image stream contains an unrecognized format
  • + *
+ */ +public ImageData[] load(InputStream stream) { + if (stream == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + reset(); + data = FileFormat.load(stream, this); + return data; +} + +/** + * Loads an array of ImageData objects from the + * file with the specified name. Throws an error if either + * an error occurs while loading the images, or if the images are + * not of a supported type. Returns the loaded image data array. + * + * @param filename the name of the file to load the images from + * @return an array of ImageData objects loaded from the specified file + * + * @exception IllegalArgumentException
    + *
  • ERROR_NULL_ARGUMENT - if the file name is null
  • + *
+ * @exception SWTException
    + *
  • ERROR_IO - if an IO error occurs while reading from the file
  • + *
  • ERROR_INVALID_IMAGE - if the image file contains invalid data
  • + *
  • ERROR_UNSUPPORTED_FORMAT - if the image file contains an unrecognized format
  • + *
+ */ +public ImageData[] load(String filename) { + if (filename == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + InputStream stream = null; + try { + stream = new FileInputStream(filename); + return load(stream); + } catch (IOException e) { + SWT.error(SWT.ERROR_IO, e); + } finally { + try { + if (stream != null) stream.close(); + } catch (IOException e) { + // Ignore error + } + } + return null; +} + +/** + * Saves the image data in this ImageLoader to the specified stream. + * The format parameter can have one of the following values: + *
+ *
IMAGE_BMP
+ *
Windows BMP file format, no compression
+ *
IMAGE_BMP_RLE
+ *
Windows BMP file format, RLE compression if appropriate
+ *
IMAGE_GIF
+ *
GIF file format
+ *
IMAGE_ICO
+ *
Windows ICO file format
+ *
IMAGE_JPEG
+ *
JPEG file format
+ *
IMAGE_PNG
+ *
PNG file format
+ *
+ * + * @param stream the output stream to write the images to + * @param format the format to write the images in + * + * @exception IllegalArgumentException
    + *
  • ERROR_NULL_ARGUMENT - if the stream is null
  • + *
+ * @exception SWTException
    + *
  • ERROR_IO - if an IO error occurs while writing to the stream
  • + *
  • ERROR_INVALID_IMAGE - if the image data contains invalid data
  • + *
  • ERROR_UNSUPPORTED_FORMAT - if the image data cannot be saved to the requested format
  • + *
+ */ +public void save(OutputStream stream, int format) { + if (stream == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + FileFormat.save(stream, format, this); +} + +/** + * Saves the image data in this ImageLoader to a file with the specified name. + * The format parameter can have one of the following values: + *
+ *
IMAGE_BMP
+ *
Windows BMP file format, no compression
+ *
IMAGE_BMP_RLE
+ *
Windows BMP file format, RLE compression if appropriate
+ *
IMAGE_GIF
+ *
GIF file format
+ *
IMAGE_ICO
+ *
Windows ICO file format
+ *
IMAGE_JPEG
+ *
JPEG file format
+ *
IMAGE_PNG
+ *
PNG file format
+ *
+ * + * @param filename the name of the file to write the images to + * @param format the format to write the images in + * + * @exception IllegalArgumentException
    + *
  • ERROR_NULL_ARGUMENT - if the file name is null
  • + *
+ * @exception SWTException
    + *
  • ERROR_IO - if an IO error occurs while writing to the file
  • + *
  • ERROR_INVALID_IMAGE - if the image data contains invalid data
  • + *
  • ERROR_UNSUPPORTED_FORMAT - if the image data cannot be saved to the requested format
  • + *
+ */ +public void save(String filename, int format) { + if (filename == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + OutputStream stream = null; + try { + stream = new FileOutputStream(filename); + } catch (IOException e) { + SWT.error(SWT.ERROR_IO, e); + } + save(stream, format); + try { + stream.close(); + } catch (IOException e) { + } +} + +/** + * Adds the listener to the collection of listeners who will be + * notified when image data is either partially or completely loaded. + *

+ * An ImageLoaderListener should be added before invoking + * one of the receiver's load methods. The listener's + * imageDataLoaded method is called when image + * data has been partially loaded, as is supported by interlaced + * GIF/PNG or progressive JPEG images. + * + * @param listener the listener which should be notified + * + * @exception IllegalArgumentException

    + *
  • ERROR_NULL_ARGUMENT - if the listener is null
  • + *
+ * + * @see ImageLoaderListener + * @see ImageLoaderEvent + */ +public void addImageLoaderListener(ImageLoaderListener listener) { + if (listener == null) SWT.error (SWT.ERROR_NULL_ARGUMENT); + if (imageLoaderListeners == null) { + imageLoaderListeners = new ArrayList<>(); + } + imageLoaderListeners.add(listener); +} + +/** + * Removes the listener from the collection of listeners who will be + * notified when image data is either partially or completely loaded. + * + * @param listener the listener which should no longer be notified + * + * @exception IllegalArgumentException
    + *
  • ERROR_NULL_ARGUMENT - if the listener is null
  • + *
+ * + * @see #addImageLoaderListener(ImageLoaderListener) + */ +public void removeImageLoaderListener(ImageLoaderListener listener) { + if (listener == null) SWT.error (SWT.ERROR_NULL_ARGUMENT); + if (imageLoaderListeners == null) return; + imageLoaderListeners.remove(listener); +} + +/** + * Returns true if the receiver has image loader + * listeners, and false otherwise. + * + * @return true if there are ImageLoaderListeners, and false otherwise + * + * @see #addImageLoaderListener(ImageLoaderListener) + * @see #removeImageLoaderListener(ImageLoaderListener) + */ +public boolean hasListeners() { + return imageLoaderListeners != null && imageLoaderListeners.size() > 0; +} + +/** + * Notifies all image loader listeners that an image loader event + * has occurred. Pass the specified event object to each listener. + * + * @param event the ImageLoaderEvent to send to each ImageLoaderListener + */ +public void notifyListeners(ImageLoaderEvent event) { + if (!hasListeners()) return; + int size = imageLoaderListeners.size(); + for (int i = 0; i < size; i++) { + ImageLoaderListener listener = imageLoaderListeners.get(i); + listener.imageDataLoaded(event); + } +} + +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/graphics/ImageLoader.java b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/graphics/ImageLoader.java deleted file mode 100644 index a7542f5fd7..0000000000 --- a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/graphics/ImageLoader.java +++ /dev/null @@ -1,664 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2019 Red Hat and others. All rights reserved. - * The contents of this file are made available under the terms - * of the GNU Lesser General Public License (LGPL) Version 2.1 that - * accompanies this distribution (lgpl-v21.txt). The LGPL is also - * available at http://www.gnu.org/licenses/lgpl.html. If the version - * of the LGPL at http://www.gnu.org is different to the version of - * the LGPL accompanying this distribution and there is any conflict - * between the two license versions, the terms of the LGPL accompanying - * this distribution shall govern. - * - * Contributors: - * Red Hat - initial API and implementation - *******************************************************************************/ -package org.eclipse.swt.graphics; - - -import java.io.*; -import java.util.*; - -import org.eclipse.swt.*; -import org.eclipse.swt.internal.*; -import org.eclipse.swt.internal.gtk.*; - -/** - * Instances of this class are used to load images from, - * and save images to, a file or stream. - *

- * Currently supported image formats are: - *

    - *
  • BMP (Windows or OS/2 Bitmap)
  • - *
  • ICO (Windows Icon)
  • - *
  • JPEG
  • - *
  • GIF
  • - *
  • PNG
  • - *
  • TIFF
  • - *
- * ImageLoaders can be used to: - *
    - *
  • load/save single images in all formats
  • - *
  • load/save multiple images (GIF/ICO/TIFF)
  • - *
  • load/save animated GIF images
  • - *
  • load interlaced GIF/PNG images
  • - *
  • load progressive JPEG images
  • - *
- * - *

- * NOTE: ImageLoader is implemented in Java on some platforms, which has - * certain performance implications. Performance and memory sensitive applications may - * benefit from using one of the constructors provided by Image, as these - * are implemented natively.

- * - * @see SWT Example: ImageAnalyzer - * @see Sample code and further information - */ -public class ImageLoader { - - /** - * the array of ImageData objects in this ImageLoader. - * This array is read in when the load method is called, - * and it is written out when the save method is called - */ - public ImageData[] data; - - /** - * the width of the logical screen on which the images - * reside, in pixels (this corresponds to the GIF89a - * Logical Screen Width value) - */ - public int logicalScreenWidth; - - /** - * the height of the logical screen on which the images - * reside, in pixels (this corresponds to the GIF89a - * Logical Screen Height value) - */ - public int logicalScreenHeight; - - /** - * the background pixel for the logical screen (this - * corresponds to the GIF89a Background Color Index value). - * The default is -1 which means 'unspecified background' - * - */ - public int backgroundPixel; - - /** - * the number of times to repeat the display of a sequence - * of animated images (this corresponds to the commonly-used - * GIF application extension for "NETSCAPE 2.0 01"). - * The default is 1. A value of 0 means 'display repeatedly' - */ - public int repeatCount; - - /** - * This is the compression used when saving jpeg and png files. - *

- * When saving jpeg files, the value is from 1 to 100, - * where 1 is very high compression but low quality, and 100 is - * no compression and high quality; default is 75. - *

- * When saving png files, the value is from 0 to 3, but they do not impact the quality - * because PNG is lossless compression. 0 is uncompressed, 1 is low compression and fast, - * 2 is default compression, and 3 is high compression but slow. - *

- * - * @since 3.8 - */ - public int compression; - - /** - * If the 29th byte of the PNG file is not zero, then it is interlaced. - */ - final static int PNG_INTERLACE_METHOD_OFFSET = 28; - - /* - * the set of ImageLoader event listeners, created on demand - */ - List imageLoaderListeners; - -/** - * Construct a new empty ImageLoader. - */ -public ImageLoader() { - reset(); -} - -/** - * Resets the fields of the ImageLoader, except for the - * imageLoaderListeners field. - */ -void reset() { - data = null; - logicalScreenWidth = 0; - logicalScreenHeight = 0; - backgroundPixel = -1; - repeatCount = 1; - compression = -1; -} - -/** - * Loads an array of ImageData objects from the - * specified input stream. Throws an error if either an error - * occurs while loading the images, or if the images are not - * of a supported type. Returns the loaded image data array. - * - * @param stream the input stream to load the images from - * @return an array of ImageData objects loaded from the specified input stream - * - * @exception IllegalArgumentException
    - *
  • ERROR_NULL_ARGUMENT - if the stream is null
  • - *
- * @exception SWTException
    - *
  • ERROR_IO - if an IO error occurs while reading from the stream
  • - *
  • ERROR_INVALID_IMAGE - if the image stream contains invalid data
  • - *
  • ERROR_UNSUPPORTED_FORMAT - if the image stream contains an unrecognized format
  • - *
- */ -public ImageData[] load(InputStream stream) { - if (stream == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); - reset(); - ImageData [] imgDataArray = getImageDataArrayFromStream(stream); - data = imgDataArray; - return imgDataArray; -} - -/** - * Return true if the image is an interlaced PNG file. - * This is used to check whether ImageLoaderEvent should be fired when loading images. - * @param imageAsByteArray - * @return true iff 29th byte of PNG files is not zero - */ -boolean isInterlacedPNG(byte [] imageAsByteArray) { - return imageAsByteArray.length > PNG_INTERLACE_METHOD_OFFSET && imageAsByteArray[PNG_INTERLACE_METHOD_OFFSET] != 0; -} - -ImageData [] getImageDataArrayFromStream(InputStream stream) { - byte[] buffer = new byte[2048]; - long loader = GDK.gdk_pixbuf_loader_new(); - int length; - List imgDataList = new ArrayList<>(); - try { - // 1) Load InputStream into byte array - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - while ((length = stream.read(buffer)) > -1) { - baos.write(buffer, 0, length); - } - baos.flush(); - byte[] data_buffer = baos.toByteArray(); - if (data_buffer.length == 0) SWT.error(SWT.ERROR_UNSUPPORTED_FORMAT); // empty stream - - // 2) Copy byte array to C memory, write to GdkPixbufLoader - long buffer_ptr = OS.g_malloc(data_buffer.length); - C.memmove(buffer_ptr, data_buffer, data_buffer.length); - GDK.gdk_pixbuf_loader_write(loader, buffer_ptr, data_buffer.length, null); - GDK.gdk_pixbuf_loader_close(loader, null); - - // 3) Get GdkPixbufAnimation from loader - long pixbuf_animation = GDK.gdk_pixbuf_loader_get_animation(loader); - if (pixbuf_animation == 0) SWT.error(SWT.ERROR_INVALID_IMAGE); - - boolean isStatic = GDK.gdk_pixbuf_animation_is_static_image(pixbuf_animation); - if (isStatic) { - // Static image, get as single pixbuf and convert it to ImageData - long pixbuf = GDK.gdk_pixbuf_animation_get_static_image(pixbuf_animation); - ImageData imgData = pixbufToImageData(pixbuf); - imgData.type = getImageFormat(loader); - imgDataList.add(imgData); - } else { - // Image with multiple frames, iterate through each frame and convert - // each frame to ImageData - long start_time = OS.g_malloc(8); - OS.g_get_current_time(start_time); - long animation_iter = GDK.gdk_pixbuf_animation_get_iter (pixbuf_animation, start_time); - int delay_time = 0; - int time_offset = 0; - // Fix the number of GIF frames as GdkPixbufAnimation does not provide an API to - // determine number of frames. - int num_frames = 32; - for (int i = 0; i < num_frames; i++) { - // Calculate time offset from start_time to next frame - delay_time = GDK.gdk_pixbuf_animation_iter_get_delay_time (animation_iter); - time_offset += delay_time; - OS.g_time_val_add(start_time, time_offset * 1000); - boolean update = GDK.gdk_pixbuf_animation_iter_advance (animation_iter, start_time); - if (update) { - long curr_pixbuf = GDK.gdk_pixbuf_animation_iter_get_pixbuf (animation_iter); - long pixbuf_copy = GDK.gdk_pixbuf_copy(curr_pixbuf); // copy because curr_pixbuf might get disposed on next advance - ImageData imgData = pixbufToImageData(pixbuf_copy); - if (this.logicalScreenHeight == 0 && this.logicalScreenWidth == 0) { - this.logicalScreenHeight = imgData.height; - this.logicalScreenWidth = imgData.width; - } - OS.g_object_unref(pixbuf_copy); - imgData.type = getImageFormat(loader); - imgData.delayTime = delay_time; - imgDataList.add(imgData); - } else { - break; - } - } - } - ImageData [] imgDataArray = new ImageData [imgDataList.size()]; - for (int i = 0; i < imgDataList.size(); i++) { - imgDataArray [i] = imgDataList.get(i); - // Loading completed, notify listeners - // listener should only be called when loading interlaced/progressive PNG/JPG/GIF ? - ImageData data = (ImageData) imgDataArray [i].clone(); - if (this.hasListeners() && imgDataArray != null) { - if (data.type == SWT.IMAGE_PNG && isInterlacedPNG(data_buffer)) { - this.notifyListeners(new ImageLoaderEvent(this, data, i, true)); - } else if (data.type != SWT.IMAGE_PNG) { - this.notifyListeners(new ImageLoaderEvent(this, data, i, true)); - } - } - } - OS.g_free(buffer_ptr); - OS.g_object_unref(loader); - stream.close(); - return imgDataArray; - } catch (IOException e) { - SWT.error(SWT.ERROR_IO); - } - return null; -} - -/** - * Loads an array of ImageData objects from the - * file with the specified name. Throws an error if either - * an error occurs while loading the images, or if the images are - * not of a supported type. Returns the loaded image data array. - * - * @param filename the name of the file to load the images from - * @return an array of ImageData objects loaded from the specified file - * - * @exception IllegalArgumentException
    - *
  • ERROR_NULL_ARGUMENT - if the file name is null
  • - *
- * @exception SWTException
    - *
  • ERROR_IO - if an IO error occurs while reading from the file
  • - *
  • ERROR_INVALID_IMAGE - if the image file contains invalid data
  • - *
  • ERROR_UNSUPPORTED_FORMAT - if the image file contains an unrecognized format
  • - *
- */ -public ImageData[] load(String filename) { - if (filename == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); - InputStream stream = null; - try { - stream = new FileInputStream(filename); - return load(stream); - } catch (IOException e) { - SWT.error(SWT.ERROR_IO, e); - } finally { - try { - if (stream != null) stream.close(); - } catch (IOException e) { - // Ignore error - } - } - return null; -} - -/** - * Load GdkPixbuf directly using gdk_pixbuf_new_from_file, - * without FileInputStream. - * @param filename - * @return - */ -ImageData[] loadFromFile(String filename) { - long pixbuf = gdk_pixbuf_new_from_file(filename); - if (pixbuf == 0) return null; - ImageData imgData= pixbufToImageData(pixbuf); - return data = new ImageData[] {imgData}; -} - -/** - * Return the type of file from which the image was read - * by inspecting GdkPixbufFormat from GdkPixbufLoader - * - * It is expressed as one of the following values: - *
- *
IMAGE_BMP
- *
Windows BMP file format, no compression
- *
IMAGE_BMP_RLE
- *
Windows BMP file format, RLE compression if appropriate
- *
IMAGE_GIF
- *
GIF file format
- *
IMAGE_ICO
- *
Windows ICO file format
- *
IMAGE_JPEG
- *
JPEG file format
- *
IMAGE_PNG
- *
PNG file format
- *
- */ -int getImageFormat(long loader) { - long format = GDK.gdk_pixbuf_loader_get_format(loader); - long name = GDK.gdk_pixbuf_format_get_name(format); - String nameStr = Converter.cCharPtrToJavaString(name, false); - switch (nameStr) { - case "bmp": return SWT.IMAGE_BMP; - case "gif": return SWT.IMAGE_GIF; - case "ico": return SWT.IMAGE_ICO; - case "jpeg": return SWT.IMAGE_JPEG; - case "png": return SWT.IMAGE_PNG; - default: return SWT.IMAGE_UNDEFINED; - } -} - -/** - * Convert GdkPixbuf pointer to Java object ImageData - * @param pixbuf - * @return ImageData with pixbuf data - */ -static ImageData pixbufToImageData(long pixbuf) { - boolean hasAlpha = GDK.gdk_pixbuf_get_has_alpha(pixbuf); - int width = GDK.gdk_pixbuf_get_width(pixbuf); - int height = GDK.gdk_pixbuf_get_height(pixbuf); - int stride = GDK.gdk_pixbuf_get_rowstride(pixbuf); - int n_channels = GDK.gdk_pixbuf_get_n_channels(pixbuf); // only 3 or 4 samples per pixel are supported - int bits_per_sample = GDK.gdk_pixbuf_get_bits_per_sample(pixbuf); // only 8 bit per sample are supported - long pixels = GDK.gdk_pixbuf_get_pixels(pixbuf); - /* - * From GDK Docs: last row in the pixbuf may not be as wide as the full rowstride, - * but rather just as wide as the pixel data needs to be. Compute the width in bytes - * of the last row to copy raw pixbuf data. - */ - int lastRowWidth = width * ((n_channels * bits_per_sample + 7) / 8); - byte[] srcData = new byte[stride * height]; - C.memmove(srcData, pixels, stride * (height - 1) + lastRowWidth); - /* - * Note: GdkPixbuf only supports 3/4 n_channels and 8 bits_per_sample, - * This means all images are of depth 24 / depth 32. This means loading - * images will result in a direct PaletteData with RGB masks, since - * there is no way to determine indexed PaletteData info. - * - * See https://www.eclipse.org/articles/Article-SWT-images/graphics-resources.html#PaletteData - */ - PaletteData palette = new PaletteData(0xFF0000, 0xFF00, 0xFF); - ImageData imgData = new ImageData(width, height, bits_per_sample * n_channels, palette, stride, srcData); - if (hasAlpha) { - byte[] alphaData = imgData.alphaData = new byte[width * height]; - for (int y = 0, offset = 0, alphaOffset = 0; y < height; y++) { - for (int x = 0; x < width; x++, offset += n_channels) { - byte r = srcData[offset + 0]; - byte g = srcData[offset + 1]; - byte b = srcData[offset + 2]; - byte a = srcData[offset + 3]; - srcData[offset + 0] = 0; - alphaData[alphaOffset++] = a; - if (a != 0) { - srcData[offset + 1] = r; - srcData[offset + 2] = g; - srcData[offset + 3] = b; - } - } - } - } else { - for (int y = 0, offset = 0; y < height; y++) { - for (int x = 0; x < width; x++, offset += n_channels) { - byte r = srcData[offset + 0]; - byte g = srcData[offset + 1]; - byte b = srcData[offset + 2]; - srcData[offset + 0] = r; - srcData[offset + 1] = g; - srcData[offset + 2] = b; - } - } - } - return imgData; -} - -/** - * Returns GdkPixbuf pointer by loading an image from filename (Java string) - * @param filename - * @return - */ -static long gdk_pixbuf_new_from_file(String filename) { - int length = filename.length (); - char [] chars = new char [length]; - filename.getChars (0, length, chars, 0); - byte [] buffer = Converter.wcsToMbcs(chars, true); - return GDK.gdk_pixbuf_new_from_file(buffer, null); -} - -/** - * Saves the image data in this ImageLoader to the specified stream. - * The format parameter can have one of the following values: - *
- *
IMAGE_BMP
- *
Windows BMP file format, no compression
- *
IMAGE_BMP_RLE
- *
Windows BMP file format, RLE compression if appropriate
- *
IMAGE_GIF
- *
GIF file format
- *
IMAGE_ICO
- *
Windows ICO file format
- *
IMAGE_JPEG
- *
JPEG file format
- *
IMAGE_PNG
- *
PNG file format
- *
IMAGE_TIFF
- *
TIFF file format
- *
- * - * @param stream the output stream to write the images to - * @param format the format to write the images in - * - * @exception IllegalArgumentException
    - *
  • ERROR_NULL_ARGUMENT - if the stream is null
  • - *
- * @exception SWTException
    - *
  • ERROR_IO - if an IO error occurs while writing to the stream
  • - *
  • ERROR_INVALID_IMAGE - if the image data contains invalid data
  • - *
  • ERROR_UNSUPPORTED_FORMAT - if the image data cannot be saved to the requested format
  • - *
- */ -public void save(OutputStream stream, int format) { - if (stream == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); - if (format == -1) SWT.error(SWT.ERROR_UNSUPPORTED_FORMAT); - if (this.data == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); - ImageData imgData = this.data [0]; - int colorspace = GDK.GDK_COLORSPACE_RGB; - boolean has_alpha = imgData.alphaData != null; - int width = imgData.width; - int height = imgData.height; - int n_channels = imgData.bytesPerLine / width; // original n_channels 3 or 4 - int bytes_per_pixel = imgData.bytesPerLine / width; // n_channels for original ImageData (width * height * bytes_per_pixel) = imgData.length - - if (has_alpha && bytes_per_pixel == 3) { - // Original is RGB -> we want RGBA - bytes_per_pixel += 1; - } - int oa, or, og, ob; - if (OS.BIG_ENDIAN) { - oa = 0; or = 1; og = 2; ob = 3; - } else { - oa = 3; or = 2; og = 1; ob = 0; - } - byte[] srcData = new byte[(width * height * bytes_per_pixel)]; - - if (has_alpha) { - for (int y = 0, offset = 0, new_offset = 0, alphaOffset = 0; y < height; y++) { - for (int x = 0; x < width; x++, offset += n_channels, new_offset += bytes_per_pixel) { - byte a = imgData.alphaData[alphaOffset++]; - int offset_alpha = n_channels == 4 ? 1 : 0; - byte r = imgData.data[offset + offset_alpha + 0]; - byte g = imgData.data[offset + offset_alpha + 1]; - byte b = imgData.data[offset + offset_alpha + 2]; - - srcData[new_offset + ob] = b; - srcData[new_offset + og] = g; - srcData[new_offset + or] = r; - srcData[new_offset + oa] = a; - } - } - } else { - srcData = imgData.data; - } - - // Get GdkPixbuf from pixel data buffer - long buffer_ptr = OS.g_malloc(srcData.length); - C.memmove(buffer_ptr, srcData, srcData.length); - int rowstride = srcData.length / height; - long pixbuf = GDK.gdk_pixbuf_new_from_data (buffer_ptr, colorspace, has_alpha, 8, width, height, rowstride, 0, 0); - if (pixbuf == 0) { - OS.g_free(buffer_ptr); - SWT.error(SWT.ERROR_NULL_ARGUMENT); - } - - // Write pixbuf to byte array and then to OutputStream - String typeStr = ""; - switch (format) { - case SWT.IMAGE_BMP_RLE: typeStr = "bmp"; break; - case SWT.IMAGE_BMP: typeStr = "bmp"; break; - case SWT.IMAGE_GIF: typeStr = "gif"; break; - case SWT.IMAGE_ICO: typeStr = "ico"; break; - case SWT.IMAGE_JPEG: typeStr = "jpeg"; break; - case SWT.IMAGE_PNG: typeStr = "png"; break; - case SWT.IMAGE_TIFF: typeStr = "tiff"; break; - } - - byte [] type = Converter.wcsToMbcs(typeStr, true); - - long [] buffer = new long [1]; - if (type == null || typeStr == "") { - OS.g_free(buffer_ptr); - SWT.error(SWT.ERROR_UNSUPPORTED_FORMAT); - } - long [] len = new long [1]; - GDK.gdk_pixbuf_save_to_bufferv(pixbuf, buffer, len, type, null, null, null); - byte[] byteArray = new byte[(int) len[0]]; - C.memmove(byteArray, buffer[0], byteArray.length); - try { - stream.write(byteArray); - } catch (IOException e) { - OS.g_free(buffer_ptr); - SWT.error(SWT.ERROR_IO); - } - // must free buffer_ptr last otherwise we get half/corrupted image - OS.g_free(buffer_ptr); -} - -/** - * Saves the image data in this ImageLoader to a file with the specified name. - * The format parameter can have one of the following values: - *
- *
IMAGE_BMP
- *
Windows BMP file format, no compression
- *
IMAGE_BMP_RLE
- *
Windows BMP file format, RLE compression if appropriate
- *
IMAGE_GIF
- *
GIF file format
- *
IMAGE_ICO
- *
Windows ICO file format
- *
IMAGE_JPEG
- *
JPEG file format
- *
IMAGE_PNG
- *
PNG file format
- *
IMAGE_TIFF
- *
TIFF file format
- *
- * - * @param filename the name of the file to write the images to - * @param format the format to write the images in - * - * @exception IllegalArgumentException
    - *
  • ERROR_NULL_ARGUMENT - if the file name is null
  • - *
- * @exception SWTException
    - *
  • ERROR_IO - if an IO error occurs while writing to the file
  • - *
  • ERROR_INVALID_IMAGE - if the image data contains invalid data
  • - *
  • ERROR_UNSUPPORTED_FORMAT - if the image data cannot be saved to the requested format
  • - *
- */ -public void save(String filename, int format) { - if (filename == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); - OutputStream stream = null; - try { - stream = new FileOutputStream(filename); - } catch (IOException e) { - SWT.error(SWT.ERROR_IO, e); - } - save(stream, format); - try { - stream.close(); - } catch (IOException e) { - } -} - -/** - * Adds the listener to the collection of listeners who will be - * notified when image data is either partially or completely loaded. - *

- * An ImageLoaderListener should be added before invoking - * one of the receiver's load methods. The listener's - * imageDataLoaded method is called when image - * data has been partially loaded, as is supported by interlaced - * GIF/PNG or progressive JPEG images. - * - * @param listener the listener which should be notified - * - * @exception IllegalArgumentException

    - *
  • ERROR_NULL_ARGUMENT - if the listener is null
  • - *
- * - * @see ImageLoaderListener - * @see ImageLoaderEvent - */ -public void addImageLoaderListener(ImageLoaderListener listener) { - if (listener == null) SWT.error (SWT.ERROR_NULL_ARGUMENT); - if (imageLoaderListeners == null) { - imageLoaderListeners = new ArrayList<>(); - } - imageLoaderListeners.add(listener); -} - -/** - * Removes the listener from the collection of listeners who will be - * notified when image data is either partially or completely loaded. - * - * @param listener the listener which should no longer be notified - * - * @exception IllegalArgumentException
    - *
  • ERROR_NULL_ARGUMENT - if the listener is null
  • - *
- * - * @see #addImageLoaderListener(ImageLoaderListener) - */ -public void removeImageLoaderListener(ImageLoaderListener listener) { - if (listener == null) SWT.error (SWT.ERROR_NULL_ARGUMENT); - if (imageLoaderListeners == null) return; - imageLoaderListeners.remove(listener); -} - -/** - * Returns true if the receiver has image loader - * listeners, and false otherwise. - * - * @return true if there are ImageLoaderListeners, and false otherwise - * - * @see #addImageLoaderListener(ImageLoaderListener) - * @see #removeImageLoaderListener(ImageLoaderListener) - */ -public boolean hasListeners() { - return imageLoaderListeners != null && imageLoaderListeners.size() > 0; -} - -/** - * Notifies all image loader listeners that an image loader event - * has occurred. Pass the specified event object to each listener. - * - * @param event the ImageLoaderEvent to send to each ImageLoaderListener - */ -public void notifyListeners(ImageLoaderEvent event) { - if (!hasListeners()) return; - int size = imageLoaderListeners.size(); - for (int i = 0; i < size; i++) { - ImageLoaderListener listener = imageLoaderListeners.get(i); - listener.imageDataLoaded(event); - } -} - -} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/ImageLoader.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/ImageLoader.java deleted file mode 100644 index a8914ea4af..0000000000 --- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/ImageLoader.java +++ /dev/null @@ -1,348 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2016 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.swt.graphics; - - -import java.io.*; -import java.util.*; - -import org.eclipse.swt.*; -import org.eclipse.swt.internal.image.*; - -/** - * Instances of this class are used to load images from, - * and save images to, a file or stream. - *

- * Currently supported image formats are: - *

    - *
  • BMP (Windows or OS/2 Bitmap)
  • - *
  • ICO (Windows Icon)
  • - *
  • JPEG
  • - *
  • GIF
  • - *
  • PNG
  • - *
  • TIFF
  • - *
- * ImageLoaders can be used to: - *
    - *
  • load/save single images in all formats
  • - *
  • load/save multiple images (GIF/ICO/TIFF)
  • - *
  • load/save animated GIF images
  • - *
  • load interlaced GIF/PNG images
  • - *
  • load progressive JPEG images
  • - *
- * - *

- * NOTE: ImageLoader is implemented in Java on some platforms, which has - * certain performance implications. Performance and memory sensitive applications may - * benefit from using one of the constructors provided by Image, as these - * are implemented natively.

- * - * @see SWT Example: ImageAnalyzer - * @see Sample code and further information - */ -public class ImageLoader { - - /** - * the array of ImageData objects in this ImageLoader. - * This array is read in when the load method is called, - * and it is written out when the save method is called - */ - public ImageData[] data; - - /** - * the width of the logical screen on which the images - * reside, in pixels (this corresponds to the GIF89a - * Logical Screen Width value) - */ - public int logicalScreenWidth; - - /** - * the height of the logical screen on which the images - * reside, in pixels (this corresponds to the GIF89a - * Logical Screen Height value) - */ - public int logicalScreenHeight; - - /** - * the background pixel for the logical screen (this - * corresponds to the GIF89a Background Color Index value). - * The default is -1 which means 'unspecified background' - * - */ - public int backgroundPixel; - - /** - * the number of times to repeat the display of a sequence - * of animated images (this corresponds to the commonly-used - * GIF application extension for "NETSCAPE 2.0 01"). - * The default is 1. A value of 0 means 'display repeatedly' - */ - public int repeatCount; - - /** - * This is the compression used when saving jpeg and png files. - *

- * When saving jpeg files, the value is from 1 to 100, - * where 1 is very high compression but low quality, and 100 is - * no compression and high quality; default is 75. - *

- * When saving png files, the value is from 0 to 3, but they do not impact the quality - * because PNG is lossless compression. 0 is uncompressed, 1 is low compression and fast, - * 2 is default compression, and 3 is high compression but slow. - *

- * - * @since 3.8 - */ - public int compression; - - /* - * the set of ImageLoader event listeners, created on demand - */ - List imageLoaderListeners; - -/** - * Construct a new empty ImageLoader. - */ -public ImageLoader() { - reset(); -} - -/** - * Resets the fields of the ImageLoader, except for the - * imageLoaderListeners field. - */ -void reset() { - data = null; - logicalScreenWidth = 0; - logicalScreenHeight = 0; - backgroundPixel = -1; - repeatCount = 1; - compression = -1; -} - -/** - * Loads an array of ImageData objects from the - * specified input stream. Throws an error if either an error - * occurs while loading the images, or if the images are not - * of a supported type. Returns the loaded image data array. - * - * @param stream the input stream to load the images from - * @return an array of ImageData objects loaded from the specified input stream - * - * @exception IllegalArgumentException
    - *
  • ERROR_NULL_ARGUMENT - if the stream is null
  • - *
- * @exception SWTException
    - *
  • ERROR_IO - if an IO error occurs while reading from the stream
  • - *
  • ERROR_INVALID_IMAGE - if the image stream contains invalid data
  • - *
  • ERROR_UNSUPPORTED_FORMAT - if the image stream contains an unrecognized format
  • - *
- */ -public ImageData[] load(InputStream stream) { - if (stream == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); - reset(); - data = FileFormat.load(stream, this); - return data; -} - -/** - * Loads an array of ImageData objects from the - * file with the specified name. Throws an error if either - * an error occurs while loading the images, or if the images are - * not of a supported type. Returns the loaded image data array. - * - * @param filename the name of the file to load the images from - * @return an array of ImageData objects loaded from the specified file - * - * @exception IllegalArgumentException
    - *
  • ERROR_NULL_ARGUMENT - if the file name is null
  • - *
- * @exception SWTException
    - *
  • ERROR_IO - if an IO error occurs while reading from the file
  • - *
  • ERROR_INVALID_IMAGE - if the image file contains invalid data
  • - *
  • ERROR_UNSUPPORTED_FORMAT - if the image file contains an unrecognized format
  • - *
- */ -public ImageData[] load(String filename) { - if (filename == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); - InputStream stream = null; - try { - stream = new FileInputStream(filename); - return load(stream); - } catch (IOException e) { - SWT.error(SWT.ERROR_IO, e); - } finally { - try { - if (stream != null) stream.close(); - } catch (IOException e) { - // Ignore error - } - } - return null; -} - -/** - * Saves the image data in this ImageLoader to the specified stream. - * The format parameter can have one of the following values: - *
- *
IMAGE_BMP
- *
Windows BMP file format, no compression
- *
IMAGE_BMP_RLE
- *
Windows BMP file format, RLE compression if appropriate
- *
IMAGE_GIF
- *
GIF file format
- *
IMAGE_ICO
- *
Windows ICO file format
- *
IMAGE_JPEG
- *
JPEG file format
- *
IMAGE_PNG
- *
PNG file format
- *
- * - * @param stream the output stream to write the images to - * @param format the format to write the images in - * - * @exception IllegalArgumentException
    - *
  • ERROR_NULL_ARGUMENT - if the stream is null
  • - *
- * @exception SWTException
    - *
  • ERROR_IO - if an IO error occurs while writing to the stream
  • - *
  • ERROR_INVALID_IMAGE - if the image data contains invalid data
  • - *
  • ERROR_UNSUPPORTED_FORMAT - if the image data cannot be saved to the requested format
  • - *
- */ -public void save(OutputStream stream, int format) { - if (stream == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); - FileFormat.save(stream, format, this); -} - -/** - * Saves the image data in this ImageLoader to a file with the specified name. - * The format parameter can have one of the following values: - *
- *
IMAGE_BMP
- *
Windows BMP file format, no compression
- *
IMAGE_BMP_RLE
- *
Windows BMP file format, RLE compression if appropriate
- *
IMAGE_GIF
- *
GIF file format
- *
IMAGE_ICO
- *
Windows ICO file format
- *
IMAGE_JPEG
- *
JPEG file format
- *
IMAGE_PNG
- *
PNG file format
- *
- * - * @param filename the name of the file to write the images to - * @param format the format to write the images in - * - * @exception IllegalArgumentException
    - *
  • ERROR_NULL_ARGUMENT - if the file name is null
  • - *
- * @exception SWTException
    - *
  • ERROR_IO - if an IO error occurs while writing to the file
  • - *
  • ERROR_INVALID_IMAGE - if the image data contains invalid data
  • - *
  • ERROR_UNSUPPORTED_FORMAT - if the image data cannot be saved to the requested format
  • - *
- */ -public void save(String filename, int format) { - if (filename == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); - OutputStream stream = null; - try { - stream = new FileOutputStream(filename); - } catch (IOException e) { - SWT.error(SWT.ERROR_IO, e); - } - save(stream, format); - try { - stream.close(); - } catch (IOException e) { - } -} - -/** - * Adds the listener to the collection of listeners who will be - * notified when image data is either partially or completely loaded. - *

- * An ImageLoaderListener should be added before invoking - * one of the receiver's load methods. The listener's - * imageDataLoaded method is called when image - * data has been partially loaded, as is supported by interlaced - * GIF/PNG or progressive JPEG images. - * - * @param listener the listener which should be notified - * - * @exception IllegalArgumentException

    - *
  • ERROR_NULL_ARGUMENT - if the listener is null
  • - *
- * - * @see ImageLoaderListener - * @see ImageLoaderEvent - */ -public void addImageLoaderListener(ImageLoaderListener listener) { - if (listener == null) SWT.error (SWT.ERROR_NULL_ARGUMENT); - if (imageLoaderListeners == null) { - imageLoaderListeners = new ArrayList<>(); - } - imageLoaderListeners.add(listener); -} - -/** - * Removes the listener from the collection of listeners who will be - * notified when image data is either partially or completely loaded. - * - * @param listener the listener which should no longer be notified - * - * @exception IllegalArgumentException
    - *
  • ERROR_NULL_ARGUMENT - if the listener is null
  • - *
- * - * @see #addImageLoaderListener(ImageLoaderListener) - */ -public void removeImageLoaderListener(ImageLoaderListener listener) { - if (listener == null) SWT.error (SWT.ERROR_NULL_ARGUMENT); - if (imageLoaderListeners == null) return; - imageLoaderListeners.remove(listener); -} - -/** - * Returns true if the receiver has image loader - * listeners, and false otherwise. - * - * @return true if there are ImageLoaderListeners, and false otherwise - * - * @see #addImageLoaderListener(ImageLoaderListener) - * @see #removeImageLoaderListener(ImageLoaderListener) - */ -public boolean hasListeners() { - return imageLoaderListeners != null && imageLoaderListeners.size() > 0; -} - -/** - * Notifies all image loader listeners that an image loader event - * has occurred. Pass the specified event object to each listener. - * - * @param event the ImageLoaderEvent to send to each ImageLoaderListener - */ -public void notifyListeners(ImageLoaderEvent event) { - if (!hasListeners()) return; - int size = imageLoaderListeners.size(); - for (int i = 0; i < size; i++) { - ImageLoaderListener listener = imageLoaderListeners.get(i); - listener.imageDataLoaded(event); - } -} - -} diff --git a/tests/org.eclipse.swt.tests.gtk/ManualTests/org/eclipse/swt/tests/gtk/snippets/Bug545032_ImageLoaderBenchmark.java b/tests/org.eclipse.swt.tests.gtk/ManualTests/org/eclipse/swt/tests/gtk/snippets/Bug545032_ImageLoaderBenchmark.java deleted file mode 100644 index 3e2c712f63..0000000000 --- a/tests/org.eclipse.swt.tests.gtk/ManualTests/org/eclipse/swt/tests/gtk/snippets/Bug545032_ImageLoaderBenchmark.java +++ /dev/null @@ -1,43 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2018 Red Hat and others. All rights reserved. - * The contents of this file are made available under the terms - * of the GNU Lesser General Public License (LGPL) Version 2.1 that - * accompanies this distribution (lgpl-v21.txt). The LGPL is also - * available at http://www.gnu.org/licenses/lgpl.html. If the version - * of the LGPL at http://www.gnu.org is different to the version of - * the LGPL accompanying this distribution and there is any conflict - * between the two license versions, the terms of the LGPL accompanying - * this distribution shall govern. - * - * Contributors: - * Red Hat - initial API and implementation - *******************************************************************************/ -package org.eclipse.swt.tests.gtk.snippets; - -import java.io.File; - -import org.eclipse.swt.graphics.ImageData; -import org.eclipse.swt.graphics.ImageLoader; - -public class Bug545032_ImageLoaderBenchmark { - // Absolute path to a directory containing benchmark images - static final String BENCHMARK_DIR = new String("/home/xiyan/Pictures/benchmarks/"); - - public static void main(String[] args) { - final File folder = new File(BENCHMARK_DIR); - - ImageLoader loader = new ImageLoader(); - - for (File fileEntry : folder.listFiles()) { - String filePath = fileEntry.getAbsolutePath(); - long startTime = System.nanoTime(); - ImageData [] imgData = loader.load(filePath); - long endTime = System.nanoTime(); - long duration = (endTime - startTime) / 1000000; - if (imgData != null && imgData.length > 0) { - ImageData img = imgData[0]; - System.out.println("Loading " + fileEntry.getName() + " (" + img.width + "x" + img.height + ") takes " + duration + "ms"); - } - } - } -} diff --git a/tests/org.eclipse.swt.tests.gtk/ManualTests/org/eclipse/swt/tests/gtk/snippets/Bug547529_ControlPrintBroken.java b/tests/org.eclipse.swt.tests.gtk/ManualTests/org/eclipse/swt/tests/gtk/snippets/Bug547529_ControlPrintBroken.java new file mode 100644 index 0000000000..a8241329b7 --- /dev/null +++ b/tests/org.eclipse.swt.tests.gtk/ManualTests/org/eclipse/swt/tests/gtk/snippets/Bug547529_ControlPrintBroken.java @@ -0,0 +1,111 @@ +/******************************************************************************* + * Copyright (c) 2019 Andrey Loskutov and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Andrey Loskutov - initial API and implementation + *******************************************************************************/ +package org.eclipse.swt.tests.gtk.snippets; +import java.io.File; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.graphics.GC; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.ImageData; +import org.eclipse.swt.graphics.ImageLoader; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.layout.RowData; +import org.eclipse.swt.layout.RowLayout; +import org.eclipse.swt.widgets.Canvas; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Shell; + +class Bug547529_ControlPrintBroken { + public static void main(String[] args) { + String filename = System.getenv("HOME") + "/some_canvas"; + + Display display = new Display(); + Shell shell = new Shell(display); + shell.setLayout(new RowLayout()); + shell.setSize(200, 200); + shell.setText("Canvas Bug"); + + Composite composite = canvas(display, shell); + + shell.open(); + + snapshot(display, composite, filename); + + while (!shell.isDisposed()) { + if (!display.readAndDispatch()) { + display.sleep(); + } + } + display.dispose(); + } + + private static Composite canvas(Display display, Shell shell) { + Composite composite = new Composite(shell, SWT.NONE); + RowData layoutData = new RowData(100, 100); + composite.setLayoutData(layoutData); + + composite.setLayout(new RowLayout()); + Canvas canvas = new Canvas(composite, SWT.NONE); + layoutData = new RowData(10, 10); + canvas.setLayoutData(layoutData); + + Color white = display.getSystemColor(SWT.COLOR_WHITE); + Color red = display.getSystemColor(SWT.COLOR_RED); + Color green = display.getSystemColor(SWT.COLOR_GREEN); + Color blue = display.getSystemColor(SWT.COLOR_BLUE); + + canvas.addPaintListener(e -> { + Rectangle clientArea = canvas.getClientArea(); + e.gc.setBackground(red); + e.gc.fillRectangle(0, 0, clientArea.width / 2, clientArea.height / 2); + e.gc.setBackground(green); + e.gc.fillRectangle(clientArea.width / 2, 0, clientArea.width, clientArea.height / 2); + e.gc.setBackground(blue); + e.gc.fillRectangle(0, clientArea.height / 2, clientArea.width, clientArea.height); + e.gc.setBackground(white); + e.gc.fillRectangle(clientArea.width / 2, clientArea.height / 2, clientArea.width, clientArea.height); + }); + return canvas; + } + + private static void snapshot(Display display, Composite composite, String filename) { + Rectangle bounds = composite.getBounds(); + Image image = new Image(display, bounds); + GC gc = new GC(image); + composite.print(gc); + gc.dispose(); + + ImageLoader loader = new ImageLoader(); + loader.data = new ImageData[] { image.getImageData() }; + File file = new File(filename + ".png"); + file.delete(); + loader.save(filename + ".png", SWT.IMAGE_PNG); + + + loader = new ImageLoader(); + ImageData[] loaded = loader.load(file.getAbsolutePath()); + Shell shell = display.getShells()[0]; + for (ImageData d : loaded) { + Label l = new Label(shell, SWT.NONE); + image = new Image(display, d); + l.setImage(image); + } + + loader.save(filename + "_2.png", SWT.IMAGE_PNG); + shell.pack(); + } +} diff --git a/tests/org.eclipse.swt.tests.gtk/ManualTests/org/eclipse/swt/tests/gtk/snippets/Bug547529_ImageLoaderStriping.java b/tests/org.eclipse.swt.tests.gtk/ManualTests/org/eclipse/swt/tests/gtk/snippets/Bug547529_ImageLoaderStriping.java new file mode 100644 index 0000000000..d4fb5cc528 --- /dev/null +++ b/tests/org.eclipse.swt.tests.gtk/ManualTests/org/eclipse/swt/tests/gtk/snippets/Bug547529_ImageLoaderStriping.java @@ -0,0 +1,85 @@ +/******************************************************************************* + * Copyright (c) 2019 Patrick Tasse and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Patrick Tasse - initial API and implementation + *******************************************************************************/ +package org.eclipse.swt.tests.gtk.snippets; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.graphics.GC; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.ImageData; +import org.eclipse.swt.graphics.ImageLoader; +import org.eclipse.swt.layout.FillLayout; +import org.eclipse.swt.layout.RowLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.FileDialog; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Shell; + +public class Bug547529_ImageLoaderStriping { + + public static void main(String[] args) { + Display display = new Display(); + String gtkVersion = System.getProperty("org.eclipse.swt.internal.gtk.version"); + Shell shell = new Shell(display); + shell.setText(gtkVersion); + + shell.setLayout(new FillLayout()); + + Composite composite = new Composite(shell, SWT.NONE); + composite.setLayout(new RowLayout(SWT.VERTICAL)); + Label label = new Label(composite, SWT.NONE); + label.setText(gtkVersion); + + Button button = new Button(composite, SWT.PUSH); + button.setText("Take Snapshot..."); + button.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + FileDialog dialog = new FileDialog(shell, SWT.SAVE); + dialog.setFilterExtensions(new String[] { "*.png" }); + dialog.setFilterIndex(0); + dialog.setFileName("Untitled.png"); + String filename = dialog.open(); + if ((filename != null) && !filename.isEmpty()) { + saveImage(composite, filename, SWT.IMAGE_PNG); + } + } + }); + + shell.pack(); + shell.open(); + while (!shell.isDisposed()) { + if (!display.readAndDispatch()) { + display.sleep(); + } + } + display.dispose(); + } + + private static void saveImage(Control control, String filename, int format) { + Image image = new Image(control.getDisplay(), control.getBounds()); + GC gc = new GC(image); + control.print(gc); + gc.dispose(); + ImageData data = image.getImageData(); + ImageLoader loader = new ImageLoader(); + loader.data = new ImageData[] { data }; + loader.save(filename, format); + image.dispose(); + } +} diff --git a/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_graphics_ImageLoader.java b/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_graphics_ImageLoader.java index 9689deab13..16a5ad56bd 100644 --- a/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_graphics_ImageLoader.java +++ b/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_graphics_ImageLoader.java @@ -15,18 +15,25 @@ package org.eclipse.swt.tests.junit; +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; +import org.eclipse.swt.SWT; import org.eclipse.swt.SWTException; +import org.eclipse.swt.graphics.ImageData; import org.eclipse.swt.graphics.ImageLoader; import org.eclipse.swt.graphics.ImageLoaderEvent; import org.eclipse.swt.graphics.ImageLoaderListener; +import org.eclipse.swt.graphics.PaletteData; +import org.eclipse.swt.widgets.Display; import org.junit.Test; /** @@ -171,6 +178,57 @@ public void test_saveLjava_lang_StringI() { } } +/** + * Ensure that saving and loading an image with {@link ImageLoader} + * does not result in different {@link ImageData#data} arrays. + */ +@Test +public void test_bug547529() { + Display display = Display.getDefault(); + try { + int imageWidth = 8; + int imageHeight = 8; + int imageDepth = 24; + + int RED = 0xFF0000; + int GREEN = 0x00FF00; + int BLUE = 0x0000FF; + PaletteData palette = new PaletteData(RED, GREEN, BLUE); + ImageData imageData = new ImageData(imageWidth, imageHeight, imageDepth, palette); + int w = imageWidth / 2; + int h = imageHeight / 2; + + for (int y = 0; y < imageHeight; ++y) { + for (int x = 0; x < imageWidth; ++x) { + int color = 0x000000; + if (x < w && y < h) { + color = RED; + } else if (x < w && y >= h) { + color = GREEN; + } else if (x >= w && y < h) { + color = BLUE; + } + imageData.setPixel(x, y, color); + } + } + + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + ImageLoader saver = new ImageLoader(); + saver.data = new ImageData[] { imageData }; + saver.save(outputStream, SWT.IMAGE_PNG); + byte[] savedBytes = imageData.data; + ByteArrayInputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray()); + ImageLoader loader = new ImageLoader(); + loader.load(inputStream); + ImageData[] loadedData = loader.data; + assertEquals("ImageLoader loaded incorrect number of ImageData objects", 1, loadedData.length); + byte[] loadedBytes = loadedData[0].data; + assertArrayEquals(savedBytes, loadedBytes); + } finally { + display.dispose(); + } +} + /* custom */ boolean loaderListenerCalled; } -- cgit v1.2.3