Merge branch '8.11' of github.com:libvips/libvips into 8.11
This commit is contained in:
commit
336ee9420a
@ -1,3 +1,7 @@
|
||||
14/8/20 started 8.11.1
|
||||
- add more example code to C docs
|
||||
- update libtool support in configure.ac
|
||||
|
||||
14/8/20 started 8.11
|
||||
- add vips_jpegload_source() and vips_svgload_source() to public C API
|
||||
- integrate doxygen in build system to generate C++ API docs
|
||||
|
75
configure.ac
75
configure.ac
@ -2,9 +2,9 @@
|
||||
|
||||
# also update the version number in the m4 macros below
|
||||
|
||||
AC_INIT([vips], [8.11.0], [vipsip@jiscmail.ac.uk])
|
||||
AC_INIT([vips],[8.11.1],[vipsip@jiscmail.ac.uk])
|
||||
# required for gobject-introspection
|
||||
AC_PREREQ(2.62)
|
||||
AC_PREREQ([2.69])
|
||||
|
||||
# gobject-introspection recommends -Wno-portability
|
||||
# foreign stops complaints about a missing README (we use README.md instead)
|
||||
@ -18,7 +18,7 @@ AC_CONFIG_MACRO_DIR([m4])
|
||||
# user-visible library versioning
|
||||
m4_define([vips_major_version], [8])
|
||||
m4_define([vips_minor_version], [11])
|
||||
m4_define([vips_micro_version], [0])
|
||||
m4_define([vips_micro_version], [1])
|
||||
m4_define([vips_version],
|
||||
[vips_major_version.vips_minor_version.vips_micro_version])
|
||||
|
||||
@ -117,8 +117,7 @@ AC_DEFINE_UNQUOTED(G_LOG_DOMAIN, "VIPS", [Domain for glib logging messages.])
|
||||
|
||||
m4_define([debug_default], [no])
|
||||
AC_ARG_ENABLE(debug,
|
||||
AC_HELP_STRING([--enable-debug=@<:@no/minimum/yes@:>@],
|
||||
[turn on debugging @<:@default=debug_default()@:>@]),,
|
||||
AS_HELP_STRING([--enable-debug=@<:@no/minimum/yes@:>@],[turn on debugging @<:@default=debug_default()@:>@]),,
|
||||
enable_debug=debug_default())
|
||||
|
||||
if test x"$enable_debug" = x"yes"; then
|
||||
@ -180,8 +179,8 @@ AC_DEFINE_UNQUOTED(VIPS_ICC_DIR,"$profile_dir",[default directory for ICC profil
|
||||
# we want largefile support, if possible
|
||||
AC_SYS_LARGEFILE
|
||||
|
||||
# we use libtool
|
||||
LT_INIT
|
||||
# we use libtool and can generate DLLs cleanly on win32 if necessary
|
||||
LT_INIT([win32-dll])
|
||||
|
||||
# Checks for programs.
|
||||
AC_PROG_AWK
|
||||
@ -285,21 +284,6 @@ AC_HEADER_DIRENT
|
||||
AC_HEADER_STDC
|
||||
AC_CHECK_HEADERS([errno.h math.h fcntl.h limits.h stdlib.h string.h sys/file.h sys/ioctl.h sys/param.h sys/time.h sys/mman.h sys/types.h sys/stat.h unistd.h io.h direct.h windows.h])
|
||||
|
||||
# uncomment to change which libs we build
|
||||
# AC_DISABLE_SHARED
|
||||
# AC_DISABLE_STATIC
|
||||
AC_LIBTOOL_WIN32_DLL
|
||||
AC_CHECK_TOOL(DLLWRAP, dllwrap)
|
||||
AC_CHECK_TOOL(DLLTOOL, dlltool)
|
||||
AC_CHECK_TOOL(OBJDUMP, objdump)
|
||||
AC_CHECK_TOOL(RANLIB, ranlib)
|
||||
AC_CHECK_TOOL(STRIP, strip)
|
||||
AC_CHECK_TOOL(AR, ar)
|
||||
AC_CHECK_TOOL(AS, as)
|
||||
AC_CHECK_TOOL(LD, ld)
|
||||
AC_PROVIDE([AC_LIBTOOL_WIN32_DLL])
|
||||
AC_PROG_LIBTOOL
|
||||
|
||||
# Checks for typedefs, structures, and compiler characteristics.
|
||||
AC_C_RESTRICT
|
||||
AX_GCC_VAR_ATTRIBUTE(vector_size)
|
||||
@ -322,14 +306,14 @@ fi
|
||||
if test x"$ax_cv_have_var_attribute_vector_size" = x"yes"; then
|
||||
AC_MSG_CHECKING([for C++ vector shuffle])
|
||||
AC_LANG_PUSH([C++])
|
||||
AC_TRY_COMPILE([
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
|
||||
typedef float v4f __attribute__((vector_size(4 * sizeof(float)),aligned(16)));
|
||||
],[
|
||||
]], [[
|
||||
v4f f; f[3] = 99;
|
||||
],[
|
||||
]])],[
|
||||
AC_MSG_RESULT([yes])
|
||||
have_vector_shuffle=yes
|
||||
], [
|
||||
],[
|
||||
AC_MSG_RESULT([no])
|
||||
have_vector_shuffle=no
|
||||
])
|
||||
@ -345,15 +329,15 @@ fi
|
||||
if test x"$have_vector_shuffle" = x"yes"; then
|
||||
AC_MSG_CHECKING([for C++ vector arithmetic])
|
||||
AC_LANG_PUSH([C++])
|
||||
AC_TRY_COMPILE([
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
|
||||
typedef float v4f __attribute__((vector_size(4 * sizeof(float)),aligned(16)));
|
||||
],[
|
||||
]], [[
|
||||
v4f f = {1, 2, 3, 4}; f *= 12.0;
|
||||
v4f g = {5, 6, 7, 8}; f = g > 0 ? g : -1 * g;
|
||||
],[
|
||||
]])],[
|
||||
AC_MSG_RESULT([yes])
|
||||
have_vector_arith=yes
|
||||
], [
|
||||
],[
|
||||
AC_MSG_RESULT([no])
|
||||
have_vector_arith=no
|
||||
])
|
||||
@ -365,7 +349,7 @@ fi
|
||||
if test x"$have_vector_arith" = x"yes"; then
|
||||
AC_MSG_CHECKING([for C++ signed constants in vector templates])
|
||||
AC_LANG_PUSH([C++])
|
||||
AC_TRY_COMPILE([
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
|
||||
typedef float v4f __attribute__((vector_size(4 * sizeof(float)),aligned(16)));
|
||||
template <typename T>
|
||||
static void
|
||||
@ -374,10 +358,10 @@ if test x"$have_vector_arith" = x"yes"; then
|
||||
v4f f;
|
||||
f = -1 * B;
|
||||
}
|
||||
],[
|
||||
],[
|
||||
]], [[
|
||||
]])],[
|
||||
AC_MSG_RESULT([yes])
|
||||
], [
|
||||
],[
|
||||
AC_MSG_RESULT([no])
|
||||
have_vector_arith=no
|
||||
])
|
||||
@ -1429,32 +1413,29 @@ fi
|
||||
VIPS_CFLAGS="$VIPS_CFLAGS $VIPS_DEBUG_FLAGS $REQUIRED_CFLAGS"
|
||||
VIPS_LIBS="$VIPS_LIBS $REQUIRED_LIBS -lm"
|
||||
|
||||
# autoconf hates multi-line AC_SUBST so we have to have another copy of this
|
||||
# thing
|
||||
# build options relevant at runtime ... this becomes `vips --vips-config`
|
||||
# output
|
||||
VIPS_CONFIG="\
|
||||
enable debug: $enable_debug, \
|
||||
enable deprecated library components: $enable_deprecated, \
|
||||
enable modules: $gmodule_supported_flag, \
|
||||
enable docs with gtkdoc: $enable_gtk_doc, \
|
||||
gobject introspection: $found_introspection, \
|
||||
RAD load/save: $with_radiance, \
|
||||
Analyze7 load/save: $with_analyze, \
|
||||
PPM load/save: $with_ppm, \
|
||||
GIF load: $with_nsgif, \
|
||||
generate C++ docs: $with_doxygen, \
|
||||
use fftw3 for FFT: $with_fftw, \
|
||||
accelerate loops with orc: $with_orc, \
|
||||
ICC profile support with lcms: $with_lcms, \
|
||||
zlib: $with_zlib, \
|
||||
text rendering with pangocairo: $with_pangocairo, \
|
||||
font file support with fontconfig: $with_fontconfig, \
|
||||
RAD load/save: $with_radiance, \
|
||||
Analyze7 load/save: $with_analyze, \
|
||||
PPM load/save: $with_ppm, \
|
||||
GIF load: $with_nsgif, \
|
||||
EXIF metadata support with libexif: $with_libexif, \
|
||||
JPEG load/save with libjpeg: $with_jpeg, \
|
||||
JXL load/save with libjxl: $with_libjxl (dynamic module: $with_libjxl_module), \
|
||||
JPEG2000 load/save with libopenjp2: $with_libopenjp2, \
|
||||
PNG load with libspng: $with_libspng, \
|
||||
PNG load/save with libpng: $with_png, \
|
||||
8bpp PNG quantisation: $with_imagequant, \
|
||||
PNG quantisation to 8 bit: $with_imagequant, \
|
||||
TIFF load/save with libtiff: $with_tiff, \
|
||||
image pyramid save: $with_gsf, \
|
||||
HEIC/AVIF load/save with libheif: $with_heif (dynamic module: $with_heif_module), \
|
||||
@ -1463,7 +1444,7 @@ PDF load with PDFium: $with_pdfium, \
|
||||
PDF load with poppler-glib: $with_poppler (dynamic module: $with_poppler_module), \
|
||||
SVG load with librsvg-2.0: $with_rsvg, \
|
||||
EXR load with OpenEXR: $with_OpenEXR, \
|
||||
slide load with OpenSlide: $with_openslide (dynamic module: $with_openslide_module), \
|
||||
OpenSlide load: $with_openslide (dynamic module: $with_openslide_module), \
|
||||
Matlab load with matio: $with_matio, \
|
||||
NIfTI load/save with niftiio: $with_nifti, \
|
||||
FITS load/save with cfitsio: $with_cfitsio, \
|
||||
@ -1568,7 +1549,7 @@ PNG load with libspng: $with_libspng
|
||||
(requires libspng-0.6 or later)
|
||||
PNG load/save with libpng: $with_png
|
||||
(requires libpng-1.2.9 or later)
|
||||
8bpp PNG quantisation: $with_imagequant
|
||||
PNG quantisation to 8 bit: $with_imagequant
|
||||
(requires libimagequant)
|
||||
TIFF load/save with libtiff: $with_tiff
|
||||
image pyramid save: $with_gsf
|
||||
@ -1582,7 +1563,7 @@ PDF load with poppler-glib: $with_poppler (dynamic module: $with_pop
|
||||
SVG load with librsvg-2.0: $with_rsvg
|
||||
(requires librsvg-2.0 2.34.0 or later)
|
||||
EXR load with OpenEXR: $with_OpenEXR
|
||||
slide load with OpenSlide: $with_openslide (dynamic module: $with_openslide_module)
|
||||
OpenSlide support: $with_openslide (dynamic module: $with_openslide_module)
|
||||
(requires openslide-3.3.0 or later)
|
||||
Matlab load with matio: $with_matio
|
||||
NIfTI load/save with niftiio: $with_nifti
|
||||
|
123
doc/using-C.xml
123
doc/using-C.xml
@ -76,9 +76,12 @@
|
||||
</para>
|
||||
|
||||
<para>
|
||||
See #VipsOperation for more detail on VIPS
|
||||
reference counting conventions.
|
||||
See #VipsOperation for more detail on VIPS
|
||||
reference counting conventions. See the <link
|
||||
linkend="reference-pools-ref">Reference pools</link>
|
||||
section below for a way to automate reference counting in C.
|
||||
</para>
|
||||
|
||||
</refsect3>
|
||||
|
||||
<refsect3 id="using-C-operations">
|
||||
@ -133,21 +136,21 @@ where:
|
||||
in - Input image, input VipsImage
|
||||
out - Output image, output VipsImage
|
||||
x - Left edge of input in output, input gint
|
||||
default: 0
|
||||
min: -1000000000, max: 1000000000
|
||||
default: 0
|
||||
min: -1000000000, max: 1000000000
|
||||
y - Top edge of input in output, input gint
|
||||
default: 0
|
||||
min: -1000000000, max: 1000000000
|
||||
default: 0
|
||||
min: -1000000000, max: 1000000000
|
||||
width - Image width in pixels, input gint
|
||||
default: 1
|
||||
min: 1, max: 1000000000
|
||||
default: 1
|
||||
min: 1, max: 1000000000
|
||||
height - Image height in pixels, input gint
|
||||
default: 1
|
||||
min: 1, max: 1000000000
|
||||
default: 1
|
||||
min: 1, max: 1000000000
|
||||
optional arguments:
|
||||
extend - How to generate the extra pixels, input VipsExtend
|
||||
default: black
|
||||
allowed: black, copy, repeat, mirror, white, background
|
||||
default: black
|
||||
allowed: black, copy, repeat, mirror, white, background
|
||||
background - Colour for background pixels, input VipsArrayDouble
|
||||
operation flags: sequential-unbuffered
|
||||
</programlisting>
|
||||
@ -260,6 +263,102 @@ main( int argc, char **argv )
|
||||
return( 0 );
|
||||
}
|
||||
</programlisting>
|
||||
</example>
|
||||
|
||||
</refsect3>
|
||||
|
||||
<refsect3 id="reference-pools-ref">
|
||||
<title>Reference pools</title>
|
||||
<para>
|
||||
libvips has a simple system to automate at least some reference counting
|
||||
issues. Reference pools are arrays of object pointers which will be
|
||||
released automatically when some other object is finalized.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The code below crops a many-page image (perhaps a GIF or PDF). It
|
||||
splits the image into separate pages, crops each page, reassembles the
|
||||
cropped areas, and saves again. It creates a <code>context</code>
|
||||
object representing the state of processing, and
|
||||
<code>crop_animation</code> allocates two reference pools off that using
|
||||
<code>vips_object_local_array</code>, one to hold the cropped frames,
|
||||
and one to assemble and copy the result.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
All unreffing is handled by <code>main</code>, and it doesn't need to
|
||||
know anything about <code>crop_animation</code>.
|
||||
</para>
|
||||
|
||||
<example>
|
||||
<title>Reference pool example</title>
|
||||
<programlisting language="C">
|
||||
#include <vips/vips.h>
|
||||
|
||||
static int
|
||||
crop_animation( VipsObject *context, VipsImage *image, VipsImage **out,
|
||||
int left, int top, int width, int height )
|
||||
{
|
||||
int page_height = vips_image_get_page_height( image );
|
||||
int n_pages = image->Ysize / page_height;
|
||||
VipsImage **page = (VipsImage **) vips_object_local_array( context, n_pages );
|
||||
VipsImage **copy = (VipsImage **) vips_object_local_array( context, 1 );
|
||||
|
||||
int i;
|
||||
|
||||
/* Split the image into cropped frames.
|
||||
*/
|
||||
for( i = 0; i < n_pages; i++ )
|
||||
if( vips_crop( image, &page[i],
|
||||
left, page_height * i + top, width, height, NULL ) )
|
||||
return( -1 );
|
||||
|
||||
/* Reassemble the frames and set the page height. You must copy before
|
||||
* modifying metadata.
|
||||
*/
|
||||
if( vips_arrayjoin( page, &copy[0], n_pages, "across", 1, NULL ) ||
|
||||
vips_copy( copy[0], out, NULL ) )
|
||||
return( -1 );
|
||||
vips_image_set_int( *out, "page-height", height );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
int
|
||||
main( int argc, char **argv )
|
||||
{
|
||||
VipsImage *image;
|
||||
VipsObject *context;
|
||||
VipsImage *x;
|
||||
|
||||
if( VIPS_INIT( NULL ) )
|
||||
vips_error_exit( NULL );
|
||||
|
||||
if( !(image = vips_image_new_from_file( argv[1],
|
||||
"access", VIPS_ACCESS_SEQUENTIAL,
|
||||
NULL )) )
|
||||
vips_error_exit( NULL );
|
||||
|
||||
context = VIPS_OBJECT( vips_image_new() );
|
||||
if( crop_animation( context, image, &x, 10, 10, 500, 500 ) ) {
|
||||
g_object_unref( image );
|
||||
g_object_unref( context );
|
||||
vips_error_exit( NULL );
|
||||
}
|
||||
g_object_unref( image );
|
||||
g_object_unref( context );
|
||||
image = x;
|
||||
|
||||
if( vips_image_write_to_file( image, argv[2], NULL ) ) {
|
||||
g_object_unref( image );
|
||||
vips_error_exit( NULL );
|
||||
}
|
||||
|
||||
g_object_unref( image );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
</programlisting>
|
||||
</example>
|
||||
|
||||
</refsect3>
|
||||
|
@ -5703,16 +5703,3 @@ vips_popenf( const char *fmt, const char *mode, ... )
|
||||
return( NULL );
|
||||
}
|
||||
|
||||
GThread *
|
||||
vips_g_thread_new( const char *domain, GThreadFunc func, gpointer data )
|
||||
{
|
||||
vips_error( "vips_g_thread_new", "%s", _( "deprecated" ) );
|
||||
return( NULL );
|
||||
}
|
||||
|
||||
void *
|
||||
vips_g_thread_join( GThread *thread )
|
||||
{
|
||||
vips_error( "vips_g_thread_join", "%s", _( "deprecated" ) );
|
||||
return( NULL );
|
||||
}
|
||||
|
@ -350,6 +350,7 @@ vips_foreign_load_svg_generate( VipsRegion *or,
|
||||
* running inside a non-threaded tilecache.
|
||||
*/
|
||||
if( !rsvg_handle_render_cairo( svg->page, cr ) ) {
|
||||
cairo_destroy( cr );
|
||||
vips_operation_invalidate( VIPS_OPERATION( svg ) );
|
||||
vips_error( class->nickname,
|
||||
"%s", _( "SVG rendering failed" ) );
|
||||
|
@ -47,6 +47,11 @@ void vips_g_mutex_free( GMutex * );
|
||||
GCond *vips_g_cond_new( void );
|
||||
void vips_g_cond_free( GCond * );
|
||||
|
||||
/* ... and for GThread.
|
||||
*/
|
||||
GThread *vips_g_thread_new( const char *, GThreadFunc, gpointer );
|
||||
void *vips_g_thread_join( GThread *thread );
|
||||
|
||||
gboolean vips_thread_isworker( void );
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@ -1224,11 +1224,6 @@ VipsWindow *vips_window_ref( VipsImage *im, int top, int height );
|
||||
FILE *vips_popenf( const char *fmt, const char *mode, ... )
|
||||
__attribute__((format(printf, 1, 3)));
|
||||
|
||||
/* old GThread API.
|
||||
*/
|
||||
GThread *vips_g_thread_new( const char *, GThreadFunc, gpointer );
|
||||
void *vips_g_thread_join( GThread *thread );
|
||||
|
||||
/* This stuff is very, very old and should not be used by anyone now.
|
||||
*/
|
||||
#ifdef VIPS_ENABLE_ANCIENT
|
||||
|
@ -167,29 +167,22 @@ typedef struct _RenderThreadStateClass {
|
||||
|
||||
G_DEFINE_TYPE( RenderThreadState, render_thread_state, VIPS_TYPE_THREAD_STATE );
|
||||
|
||||
/* A boolean indicating if the bg render thread is running.
|
||||
/* The BG thread which sits waiting to do some calculations, and the semaphore
|
||||
* it waits on holding the number of renders with dirty tiles.
|
||||
*/
|
||||
static gboolean render_running = FALSE;
|
||||
static GThread *render_thread = NULL;
|
||||
|
||||
/* Set this to ask the render thread to quit.
|
||||
*/
|
||||
static gboolean render_kill = FALSE;
|
||||
|
||||
/* All the renders with dirty tiles.
|
||||
/* All the renders with dirty tiles, and a semaphore that the bg render thread
|
||||
* waits on.
|
||||
*/
|
||||
static GMutex *render_dirty_lock = NULL;
|
||||
static GSList *render_dirty_all = NULL;
|
||||
|
||||
/* A semaphore where the bg render thread waits on holding the number of
|
||||
* renders with dirty tiles
|
||||
*/
|
||||
static VipsSemaphore n_render_dirty_sem;
|
||||
|
||||
/* A semaphore where the main thread waits for when the bg render thread
|
||||
* is shutdown.
|
||||
*/
|
||||
static VipsSemaphore render_finish;
|
||||
|
||||
/* Set this to make the bg thread stop and reschedule.
|
||||
*/
|
||||
static gboolean render_reschedule = FALSE;
|
||||
@ -452,7 +445,10 @@ vips__render_shutdown( void )
|
||||
if( render_dirty_lock ) {
|
||||
g_mutex_lock( render_dirty_lock );
|
||||
|
||||
if( render_running ) {
|
||||
if( render_thread ) {
|
||||
GThread *thread;
|
||||
|
||||
thread = render_thread;
|
||||
render_reschedule = TRUE;
|
||||
render_kill = TRUE;
|
||||
|
||||
@ -460,16 +456,13 @@ vips__render_shutdown( void )
|
||||
|
||||
vips_semaphore_up( &n_render_dirty_sem );
|
||||
|
||||
vips_semaphore_down( &render_finish );
|
||||
|
||||
render_running = FALSE;
|
||||
(void) vips_g_thread_join( thread );
|
||||
}
|
||||
else
|
||||
g_mutex_unlock( render_dirty_lock );
|
||||
|
||||
VIPS_FREEF( vips_g_mutex_free, render_dirty_lock );
|
||||
vips_semaphore_destroy( &n_render_dirty_sem );
|
||||
vips_semaphore_destroy( &render_finish );
|
||||
}
|
||||
}
|
||||
|
||||
@ -1008,8 +1001,8 @@ render_dirty_get( void )
|
||||
|
||||
/* Loop for the background render manager thread.
|
||||
*/
|
||||
static void
|
||||
render_thread_main( void *data, void *user_data )
|
||||
static void *
|
||||
render_thread_main( void *client )
|
||||
{
|
||||
Render *render;
|
||||
|
||||
@ -1044,29 +1037,28 @@ render_thread_main( void *data, void *user_data )
|
||||
}
|
||||
}
|
||||
|
||||
/* We are exiting: tell the main thread.
|
||||
/* We are exiting, so render_thread must now be NULL.
|
||||
*/
|
||||
vips_semaphore_up( &render_finish );
|
||||
render_thread = NULL;
|
||||
|
||||
return( NULL );
|
||||
}
|
||||
|
||||
static void *
|
||||
vips__sink_screen_init( void *data )
|
||||
vips__sink_screen_once( void *data )
|
||||
{
|
||||
g_assert( !render_running );
|
||||
g_assert( !render_thread );
|
||||
g_assert( !render_dirty_lock );
|
||||
|
||||
render_dirty_lock = vips_g_mutex_new();
|
||||
vips_semaphore_init( &n_render_dirty_sem, 0, "n_render_dirty" );
|
||||
vips_semaphore_init( &render_finish, 0, "render_finish" );
|
||||
|
||||
if( vips__thread_execute( "sink_screen", render_thread_main,
|
||||
NULL ) ) {
|
||||
vips_error( "vips_sink_screen_init",
|
||||
"%s", _( "unable to init render thread" ) );
|
||||
return( NULL );
|
||||
}
|
||||
|
||||
render_running = TRUE;
|
||||
/* Don't use vips__thread_execute() since this thread will only be
|
||||
* ended by _shutdown, and that isn't always called early enough on
|
||||
* windows from atexit().
|
||||
*/
|
||||
render_thread = vips_g_thread_new( "sink_screen",
|
||||
render_thread_main, NULL );
|
||||
|
||||
return( NULL );
|
||||
}
|
||||
@ -1132,7 +1124,7 @@ vips_sink_screen( VipsImage *in, VipsImage *out, VipsImage *mask,
|
||||
|
||||
Render *render;
|
||||
|
||||
VIPS_ONCE( &once, vips__sink_screen_init, NULL );
|
||||
VIPS_ONCE( &once, vips__sink_screen_once, NULL );
|
||||
|
||||
if( tile_width <= 0 || tile_height <= 0 ||
|
||||
max_tiles < -1 ) {
|
||||
|
@ -182,6 +182,77 @@ vips_thread_isworker( void )
|
||||
return( g_private_get( is_worker_key ) != NULL );
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
const char *domain;
|
||||
GThreadFunc func;
|
||||
gpointer data;
|
||||
} VipsThreadInfo;
|
||||
|
||||
static void *
|
||||
vips_thread_run( gpointer data )
|
||||
{
|
||||
VipsThreadInfo *info = (VipsThreadInfo *) data;
|
||||
|
||||
void *result;
|
||||
|
||||
/* Set this to something (anything) to tag this thread as a vips
|
||||
* worker.
|
||||
*/
|
||||
g_private_set( is_worker_key, data );
|
||||
|
||||
if( vips__thread_profile )
|
||||
vips__thread_profile_attach( info->domain );
|
||||
|
||||
result = info->func( info->data );
|
||||
|
||||
g_free( info );
|
||||
|
||||
vips_thread_shutdown();
|
||||
|
||||
return( result );
|
||||
}
|
||||
|
||||
GThread *
|
||||
vips_g_thread_new( const char *domain, GThreadFunc func, gpointer data )
|
||||
{
|
||||
GThread *thread;
|
||||
VipsThreadInfo *info;
|
||||
GError *error = NULL;
|
||||
|
||||
info = g_new( VipsThreadInfo, 1 );
|
||||
info->domain = domain;
|
||||
info->func = func;
|
||||
info->data = data;
|
||||
|
||||
thread = g_thread_try_new( domain, vips_thread_run, info, &error );
|
||||
|
||||
VIPS_DEBUG_MSG_RED( "vips_g_thread_new: g_thread_create( %s ) = %p\n",
|
||||
domain, thread );
|
||||
|
||||
if( !thread ) {
|
||||
if( error )
|
||||
vips_g_error( &error );
|
||||
else
|
||||
vips_error( domain,
|
||||
"%s", _( "unable to create thread" ) );
|
||||
}
|
||||
|
||||
return( thread );
|
||||
}
|
||||
|
||||
void *
|
||||
vips_g_thread_join( GThread *thread )
|
||||
{
|
||||
void *result;
|
||||
|
||||
result = g_thread_join( thread );
|
||||
|
||||
VIPS_DEBUG_MSG_RED( "vips_g_thread_join: g_thread_join( %p )\n",
|
||||
thread );
|
||||
|
||||
return( result );
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
/* An name for this thread.
|
||||
*/
|
||||
|
Loading…
Reference in New Issue
Block a user