From cb2ce97afa2f18427c1b4b3857fd56f69ce83d97 Mon Sep 17 00:00:00 2001 From: mio Date: Sat, 21 Sep 2024 12:10:59 +1000 Subject: [PATCH] Improve JasPer 3/4 support Versions prior to 3 registered an atexit hander which performed resource cleanup with 'jas_cleanup', this was removed in version 3 meaning we were leaking resources. The 'jas_init' and 'jas_cleanup' functions were deprecated in version 3, so we use the newer jas_init_library/jas_init_thread functions. The max memory that JasPer can use has been limited to (at most) 512 MB. Without this change, JasPer will use whatever JAS_DEFAULT_MAX_MEM_USAGE is configured to, which is 1 GB by default. Signed-off-by: mio --- kimgio/jp2.cpp | 91 ++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 84 insertions(+), 7 deletions(-) diff --git a/kimgio/jp2.cpp b/kimgio/jp2.cpp index ff64f9263..7cd6879b1 100644 --- a/kimgio/jp2.cpp +++ b/kimgio/jp2.cpp @@ -15,6 +15,7 @@ #ifdef HAVE_STDINT_H #include #endif +#include #include #include #include @@ -57,7 +58,7 @@ read_image( const TQImageIO* io ) tempf = new KTempFile(); if( tempf->status() != 0 ) { delete tempf; - return 0; + return nullptr; } // if tempf->setAutoDelete( true ); TQFile* out = tempf->file(); @@ -76,7 +77,7 @@ read_image( const TQImageIO* io ) } // else if( !in ) { delete tempf; - return 0; + return nullptr; } // if jas_image_t* image = jas_image_decode( in, -1, 0 ); @@ -148,16 +149,77 @@ render_view( gs_t& gs, TQImage& qti ) return true; } // render_view +static bool initializeJasper() +{ +#if defined(JAS_VERSION_MAJOR) && (JAS_VERSION_MAJOR >= 3) + jas_conf_clear(); + + // Limit JasPer memory usage to at most 512 MB + size_t memoryLimit = (512 * 1024) * 1024; + size_t jasperTotalMemory = jas_get_total_mem_size(); + if (!jasperTotalMemory) + { + jasperTotalMemory = JAS_DEFAULT_MAX_MEM_USAGE; + } + memoryLimit = memoryLimit < jasperTotalMemory ? memoryLimit : jasperTotalMemory; + jas_conf_set_max_mem_usage(memoryLimit); + + if (jas_init_library()) + { + return false; + } + + if (jas_init_thread()) + { + jas_cleanup_library(); + return false; + } + +#else + if (jas_init()) + { + return false; + } +#endif // defined(JAS_VERSION_MAJOR) && (JAS_VERSION_MAJOR >= 3) + + return true; +} + +static void cleanupJasper() +{ +#if defined(JAS_VERSION_MAJOR) && (JAS_VERSION_MAJOR >= 3) + jas_cleanup_thread(); + jas_cleanup_library(); +#endif +} + + TDE_EXPORT void kimgio_jp2_read( TQImageIO* io ) { - if( jas_init() ) return; + if (!initializeJasper()) + { + kdError(399) << "Failed to initialize JasPer library" << endl; + return; + } gs_t gs; - if( !(gs.image = read_image( io )) ) return; + gs.image = read_image(io); - if( !convert_colorspace( gs ) ) return; + if (!gs.image) + { + kdError(399) << "Failed to read JP2 image from IO." << endl; + cleanupJasper(); + return; + } + + if (!convert_colorspace(gs)) + { + kdError(399) << "Could not convert JP2 colorspace." << endl; + cleanupJasper(); + return; + } TQImage image; render_view( gs, image ); @@ -165,6 +227,8 @@ kimgio_jp2_read( TQImageIO* io ) if( gs.image ) jas_image_destroy( gs.image ); if( gs.altimage ) jas_image_destroy( gs.altimage ); + cleanupJasper(); + io->setImage( image ); io->setStatus( 0 ); } // kimgio_jp2_read @@ -236,7 +300,11 @@ write_components( jas_image_t* ji, const TQImage& qi ) TDE_EXPORT void kimgio_jp2_write( TQImageIO* io ) { - if( jas_init() ) return; + if (!initializeJasper()) + { + kdError(399) << "Failed to initialize JasPer library." << endl; + return; + } // open the stream. we write directly to the file if possible, to a // temporary file otherwise. @@ -255,12 +323,19 @@ kimgio_jp2_write( TQImageIO* io ) // by here, a jas_stream_t is open - if( !stream ) return; + if (!stream) + { + kdError(399) + << "Failed to create a stream to write JP2 image" << endl; + cleanupJasper(); + return; + } jas_image_t* ji = create_image( io->image() ); if( !ji ) { delete ktempf; jas_stream_close( stream ); + cleanupJasper(); return; } // if @@ -268,6 +343,7 @@ kimgio_jp2_write( TQImageIO* io ) delete ktempf; jas_stream_close( stream ); jas_image_destroy( ji ); + cleanupJasper(); return; } // if @@ -292,6 +368,7 @@ kimgio_jp2_write( TQImageIO* io ) jas_image_destroy( ji ); jas_stream_close( stream ); + cleanupJasper(); if( i != 0 ) { delete ktempf; return; }