Merge pull request #2156 from libvips/add-openjpeg

Add JPEG2000 support
This commit is contained in:
John Cupitt 2021-03-27 17:10:42 +00:00 committed by GitHub
commit cb660b32fe
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 2665 additions and 80 deletions

View File

@ -56,6 +56,7 @@ jobs:
liblcms2-dev libpoppler-glib-dev librsvg2-dev liblcms2-dev libpoppler-glib-dev librsvg2-dev
libgif-dev libopenexr-dev libpango1.0-dev libgif-dev libopenexr-dev libpango1.0-dev
libgsf-1-dev libopenslide-dev libffi-dev libgsf-1-dev libopenslide-dev libffi-dev
libopenjp2-7-dev
- name: Install macOS dependencies - name: Install macOS dependencies
if: contains(matrix.os, 'macos') if: contains(matrix.os, 'macos')
@ -69,6 +70,7 @@ jobs:
librsvg libspng libtiff librsvg libspng libtiff
little-cms2 openexr openslide little-cms2 openexr openslide
orc pango poppler webp orc pango poppler webp
openjpeg
- name: Install Clang 10 - name: Install Clang 10
env: env:

View File

@ -20,6 +20,8 @@
- add vips_fitsload_source(), vips_niftiload_source() - add vips_fitsload_source(), vips_niftiload_source()
- png and gif load note background colour as metadata [781545872] - png and gif load note background colour as metadata [781545872]
- add vips_image_[set|get]_array_double() - add vips_image_[set|get]_array_double()
- add GIF load with libnsgif
- add JPEG2000 load and save
22/12/20 start 8.10.6 22/12/20 start 8.10.6
- don't seek on bad file descriptors [kleisauke] - don't seek on bad file descriptors [kleisauke]

View File

@ -770,6 +770,36 @@ VIPS_CFLAGS="$VIPS_CFLAGS $NIFTI_CFLAGS"
VIPS_INCLUDES="$VIPS_INCLUDES $NIFTI_INCLUDES" VIPS_INCLUDES="$VIPS_INCLUDES $NIFTI_INCLUDES"
VIPS_LIBS="$VIPS_LIBS $NIFTI_LIBS" VIPS_LIBS="$VIPS_LIBS $NIFTI_LIBS"
# openjpeg
AC_ARG_WITH([libopenjp2],
AS_HELP_STRING([--without-libopenjp2],
[build without libopenjp2 (default: test)]))
if test x"$with_libopenjp2" != x"no"; then
PKG_CHECK_MODULES(LIBOPENJP2, libopenjp2 >= 2.3,
[AC_DEFINE(HAVE_LIBOPENJP2,1,
[define if you have libopenjp2 >=2.2 installed.])
with_libopenjp2=yes
PACKAGES_USED="$PACKAGES_USED libopenjp2"
],
[AC_MSG_WARN([libopenjp2 not found; disabling libopenjp2 support])
with_libopenjp2=no
]
)
# 2.3 and earlier have threading problems
PKG_CHECK_MODULES(LIBOPENJP2_THREADING, libopenjp2 >= 2.4,
[AC_DEFINE(HAVE_LIBOPENJP2_THREADING,1,[define if your libopenjp2 threading works.])
],
[:
]
)
fi
VIPS_CFLAGS="$VIPS_CFLAGS $LIBOPENJP2_CFLAGS"
VIPS_INCLUDES="$VIPS_INCLUDES $LIBOPENJP2_INCLUDES"
VIPS_LIBS="$VIPS_LIBS $LIBOPENJP2_LIBS"
# libheif # libheif
AC_ARG_WITH([heif], AC_ARG_WITH([heif],
AS_HELP_STRING([--without-heif], [build without libheif (default: test)])) AS_HELP_STRING([--without-heif], [build without libheif (default: test)]))
@ -1420,6 +1450,8 @@ PDF load with poppler-glib: $with_poppler
SVG load with librsvg-2.0: $with_rsvg SVG load with librsvg-2.0: $with_rsvg
(requires librsvg-2.0 2.34.0 or later) (requires librsvg-2.0 2.34.0 or later)
EXR load with OpenEXR: $with_OpenEXR EXR load with OpenEXR: $with_OpenEXR
JPEG2000 load/save with libopenjp2: $with_libopenjp2
(requires libopenjp2 2.2 or later)
slide load with OpenSlide: $with_openslide slide load with OpenSlide: $with_openslide
(requires openslide-3.3.0 or later) (requires openslide-3.3.0 or later)
Matlab load with matio: $with_matio Matlab load with matio: $with_matio

View File

@ -263,12 +263,6 @@ TAB_SIZE = 8
ALIASES = ALIASES =
# This tag can be used to specify a number of word-keyword mappings (TCL only).
# A mapping has the form "name=value". For example adding "class=itcl::class"
# will allow you to use the command class in the itcl::class meaning.
TCL_SUBST =
# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
# only. Doxygen will then generate output that is more tailored for C. For # only. Doxygen will then generate output that is more tailored for C. For
# instance, some of the names that are used will be different. The list of all # instance, some of the names that are used will be different. The list of all

View File

@ -5,70 +5,72 @@ endif
noinst_LTLIBRARIES = libforeign.la noinst_LTLIBRARIES = libforeign.la
libforeign_la_SOURCES = \ libforeign_la_SOURCES = \
pforeign.h \ analyze2vips.c \
heifload.c \ analyzeload.c \
heifsave.c \
niftiload.c \
niftisave.c \
quantise.c \
exif.c \
nsgifload.c \
cairo.c \ cairo.c \
pdfload.c \
pdfiumload.c \
svgload.c \
radiance.c \
radload.c \
radsave.c \
ppmload.c \
ppmsave.c \
csvload.c \ csvload.c \
csvsave.c \ csvsave.c \
matrixload.c \
matrixsave.c \
dzsave.c \
rawload.c \
rawsave.c \
vipsload.c \
vipssave.c \
dbh.h \ dbh.h \
analyzeload.c \ dzsave.c \
analyze2vips.c \ exif.c \
foreign.c \
matlab.c \
matload.c \
magick.h \
magick.c \
magick2vips.c \
magickload.c \
magick7load.c \
magicksave.c \
spngload.c \
pngload.c \
pngsave.c \
vipspng.c \
openexr2vips.c \
openexrload.c \
fits.c \ fits.c \
fitsload.c \ fitsload.c \
fitssave.c \ fitssave.c \
tiff.h \ foreign.c \
tiff.c \ heifload.c \
vips2tiff.c \ heifsave.c \
tiff2vips.c \ jp2kload.c \
tiffload.c \ jp2ksave.c \
tiffsave.c \
openslide2vips.c \
openslideload.c \
webpload.c \
webpsave.c \
webp2vips.c \
vips2webp.c \
vips2jpeg.c \
jpeg2vips.c \ jpeg2vips.c \
jpeg.h \ jpeg.h \
jpegload.c \ jpegload.c \
jpegsave.c jpegsave.c \
magick2vips.c \
magick7load.c \
magick.c \
magick.h \
magickload.c \
magicksave.c \
matlab.c \
matload.c \
matrixload.c \
matrixsave.c \
niftiload.c \
niftisave.c \
nsgifload.c \
openexr2vips.c \
openexrload.c \
openslide2vips.c \
openslideload.c \
pdfiumload.c \
pdfload.c \
pforeign.h \
pngload.c \
pngsave.c \
ppmload.c \
ppmsave.c \
quantise.c \
radiance.c \
radload.c \
radsave.c \
rawload.c \
rawsave.c \
spngload.c \
svgload.c \
tiff2vips.c \
tiff.c \
tiff.h \
tiffload.c \
tiffsave.c \
vips2jpeg.c \
vips2tiff.c \
vips2webp.c \
vipsload.c \
vipspng.c \
vipssave.c \
webp2vips.c \
webpload.c \
webpsave.c
EXTRA_DIST = libnsgif EXTRA_DIST = libnsgif

View File

@ -2176,6 +2176,13 @@ vips_foreign_operation_init( void )
extern GType vips_foreign_load_svg_buffer_get_type( void ); extern GType vips_foreign_load_svg_buffer_get_type( void );
extern GType vips_foreign_load_svg_source_get_type( void ); extern GType vips_foreign_load_svg_source_get_type( void );
extern GType vips_foreign_load_jp2k_file_get_type( void );
extern GType vips_foreign_load_jp2k_buffer_get_type( void );
extern GType vips_foreign_load_jp2k_source_get_type( void );
extern GType vips_foreign_save_jp2k_file_get_type( void );
extern GType vips_foreign_save_jp2k_buffer_get_type( void );
extern GType vips_foreign_save_jp2k_target_get_type( void );
extern GType vips_foreign_load_heif_file_get_type( void ); extern GType vips_foreign_load_heif_file_get_type( void );
extern GType vips_foreign_load_heif_buffer_get_type( void ); extern GType vips_foreign_load_heif_buffer_get_type( void );
extern GType vips_foreign_load_heif_source_get_type( void ); extern GType vips_foreign_load_heif_source_get_type( void );
@ -2249,8 +2256,17 @@ vips_foreign_operation_init( void )
vips_foreign_load_svg_source_get_type(); vips_foreign_load_svg_source_get_type();
#endif /*HAVE_RSVG*/ #endif /*HAVE_RSVG*/
#ifdef HAVE_LIBOPENJP2
vips_foreign_load_jp2k_file_get_type();
vips_foreign_load_jp2k_buffer_get_type();
vips_foreign_load_jp2k_source_get_type();
vips_foreign_save_jp2k_file_get_type();
vips_foreign_save_jp2k_buffer_get_type();
vips_foreign_save_jp2k_target_get_type();
#endif /*HAVE_LIBOPENJP2*/
#ifdef HAVE_NSGIF #ifdef HAVE_NSGIF
vips_foreign_load_nsgif_file_get_type(); vips_foreign_load_nsgif_file_get_type();
vips_foreign_load_nsgif_buffer_get_type(); vips_foreign_load_nsgif_buffer_get_type();
vips_foreign_load_nsgif_source_get_type(); vips_foreign_load_nsgif_source_get_type();
#endif /*HAVE_NSGIF*/ #endif /*HAVE_NSGIF*/

View File

@ -230,7 +230,8 @@ vips_foreign_load_heif_build( VipsObject *object )
printf( "vips_foreign_load_heif_build:\n" ); printf( "vips_foreign_load_heif_build:\n" );
#endif /*DEBUG*/ #endif /*DEBUG*/
if( vips_source_rewind( heif->source ) ) if( heif->source &&
vips_source_rewind( heif->source ) )
return( -1 ); return( -1 );
if( !heif->ctx ) { if( !heif->ctx ) {
@ -245,7 +246,6 @@ vips_foreign_load_heif_build( VipsObject *object )
} }
} }
if( VIPS_OBJECT_CLASS( vips_foreign_load_heif_parent_class )-> if( VIPS_OBJECT_CLASS( vips_foreign_load_heif_parent_class )->
build( object ) ) build( object ) )
return( -1 ); return( -1 );
@ -253,7 +253,6 @@ vips_foreign_load_heif_build( VipsObject *object )
return( 0 ); return( 0 );
} }
static const char *heif_magic[] = { static const char *heif_magic[] = {
"ftypheic", /* A regular heif image */ "ftypheic", /* A regular heif image */
"ftypheix", /* Extended range (>8 bit) image */ "ftypheix", /* Extended range (>8 bit) image */

View File

@ -380,7 +380,7 @@ vips_foreign_save_heif_build( VipsObject *object )
chroma = heif->subsample_mode == VIPS_FOREIGN_SUBSAMPLE_OFF || chroma = heif->subsample_mode == VIPS_FOREIGN_SUBSAMPLE_OFF ||
( heif->subsample_mode == VIPS_FOREIGN_SUBSAMPLE_AUTO && ( heif->subsample_mode == VIPS_FOREIGN_SUBSAMPLE_AUTO &&
heif->Q > 90 ) ? "444" : "420"; heif->Q >= 90 ) ? "444" : "420";
error = heif_encoder_set_parameter_string( heif->encoder, error = heif_encoder_set_parameter_string( heif->encoder,
"chroma", chroma ); "chroma", chroma );
if( error.code && if( error.code &&
@ -738,7 +738,7 @@ vips_foreign_save_heif_target_init( VipsForeignSaveHeifTarget *target )
* Use @speed to control the CPU effort spent improving compression. * Use @speed to control the CPU effort spent improving compression.
* This is currently only applicable to AV1 encoders, defaults to 5. * This is currently only applicable to AV1 encoders, defaults to 5.
* *
* Chroma subsampling is normally automatically disabled for Q > 90. You can * Chroma subsampling is normally automatically disabled for Q >= 90. You can
* force the subsampling mode with @subsample_mode. * force the subsampling mode with @subsample_mode.
* *
* See also: vips_image_write_to_file(), vips_heifload(). * See also: vips_image_write_to_file(), vips_heifload().

1233
libvips/foreign/jp2kload.c Normal file

File diff suppressed because it is too large Load Diff

1181
libvips/foreign/jp2ksave.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -557,7 +557,7 @@ vips_foreign_save_jpeg_mime_init( VipsForeignSaveJpegMime *mime )
* If @strip is set, no EXIF data, IPTC data, ICC profile or XMP metadata is * If @strip is set, no EXIF data, IPTC data, ICC profile or XMP metadata is
* written into the output file. * written into the output file.
* *
* Chroma subsampling is normally automatically disabled for Q > 90. You can * Chroma subsampling is normally automatically disabled for Q >= 90. You can
* force the subsampling mode with @subsample_mode. * force the subsampling mode with @subsample_mode.
* *
* If @trellis_quant is set and the version of libjpeg supports it * If @trellis_quant is set and the version of libjpeg supports it

View File

@ -245,6 +245,8 @@ void vips__heif_error( struct heif_error *error );
struct heif_image; struct heif_image;
void vips__heif_image_print( struct heif_image *img ); void vips__heif_image_print( struct heif_image *img );
extern const char *vips__jp2k_suffs[];
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif /*__cplusplus*/ #endif /*__cplusplus*/

View File

@ -372,7 +372,7 @@ int vips_openslideload_source( VipsSource *source, VipsImage **out, ... )
/** /**
* VipsForeignSubsample: * VipsForeignSubsample:
* @VIPS_FOREIGN_SUBSAMPLE_AUTO: prevent subsampling when quality > 90 * @VIPS_FOREIGN_SUBSAMPLE_AUTO: prevent subsampling when quality >= 90
* @VIPS_FOREIGN_SUBSAMPLE_ON: always perform subsampling * @VIPS_FOREIGN_SUBSAMPLE_ON: always perform subsampling
* @VIPS_FOREIGN_SUBSAMPLE_OFF: never perform subsampling * @VIPS_FOREIGN_SUBSAMPLE_OFF: never perform subsampling
* *
@ -676,6 +676,19 @@ int vips_niftiload_source( VipsSource *source, VipsImage **out, ... )
int vips_niftisave( VipsImage *in, const char *filename, ... ) int vips_niftisave( VipsImage *in, const char *filename, ... )
__attribute__((sentinel)); __attribute__((sentinel));
int vips_jp2kload( const char *filename, VipsImage **out, ... )
__attribute__((sentinel));
int vips_jp2kload_buffer( void *buf, size_t len, VipsImage **out, ... )
__attribute__((sentinel));
int vips_jp2kload_source( VipsSource *source, VipsImage **out, ... )
__attribute__((sentinel));
int vips_jp2ksave( VipsImage *in, const char *filename, ... )
__attribute__((sentinel));
int vips_jp2ksave_buffer( VipsImage *in, void **buf, size_t *len, ... )
__attribute__((sentinel));
int vips_jp2ksave_target( VipsImage *in, VipsTarget *target, ... )
__attribute__((sentinel));
/** /**
* VipsForeignDzLayout: * VipsForeignDzLayout:
* @VIPS_FOREIGN_DZ_LAYOUT_DZ: use DeepZoom directory layout * @VIPS_FOREIGN_DZ_LAYOUT_DZ: use DeepZoom directory layout

View File

@ -136,11 +136,11 @@ typedef struct _VipsThumbnail {
int heif_thumbnail_width; int heif_thumbnail_width;
int heif_thumbnail_height; int heif_thumbnail_height;
/* For TIFF sources, open subifds to get pyr layers. /* Pyramids are stored in subifds.
*/ */
gboolean subifd_pyramid; gboolean subifd_pyramid;
/* For TIFF sources, open pages to get pyr layers. /* Pyramids are stored in pages.
*/ */
gboolean page_pyramid; gboolean page_pyramid;
@ -250,18 +250,18 @@ vips_thumbnail_read_header( VipsThumbnail *thumbnail, VipsImage *image )
} }
} }
/* Detect a TIFF pyramid made of pages following a roughly /2 shrink. /* Detect a pyramid made of pages following a roughly /2 shrink.
* *
* This may not be a pyr tiff, so no error if we can't find the layers. * This may not be a pyr tiff, so no error if we can't find the layers.
*/ */
static void static void
vips_thumbnail_get_tiff_pyramid_page( VipsThumbnail *thumbnail ) vips_thumbnail_get_pyramid_page( VipsThumbnail *thumbnail )
{ {
VipsThumbnailClass *class = VIPS_THUMBNAIL_GET_CLASS( thumbnail ); VipsThumbnailClass *class = VIPS_THUMBNAIL_GET_CLASS( thumbnail );
int i; int i;
#ifdef DEBUG #ifdef DEBUG
printf( "vips_thumbnail_get_tiff_pyramid_page:\n" ); printf( "vips_thumbnail_get_pyramid_page:\n" );
#endif /*DEBUG*/ #endif /*DEBUG*/
/* Single-page docs can't be pyramids. /* Single-page docs can't be pyramids.
@ -301,7 +301,7 @@ vips_thumbnail_get_tiff_pyramid_page( VipsThumbnail *thumbnail )
/* Now set level_count. This signals that we've found a pyramid. /* Now set level_count. This signals that we've found a pyramid.
*/ */
#ifdef DEBUG #ifdef DEBUG
printf( "vips_thumbnail_get_tiff_pyramid_page: " printf( "vips_thumbnail_get_pyramid_page: "
"%d layer pyramid detected\n", "%d layer pyramid detected\n",
thumbnail->n_pages ); thumbnail->n_pages );
#endif /*DEBUG*/ #endif /*DEBUG*/
@ -500,7 +500,7 @@ vips_thumbnail_find_jpegshrink( VipsThumbnail *thumbnail,
return( 1 ); return( 1 );
} }
/* Find the best pyramid (openslide or tiff) level. /* Find the best pyramid (openslide, tiff, etc.) level.
*/ */
static int static int
vips_thumbnail_find_pyrlevel( VipsThumbnail *thumbnail, vips_thumbnail_find_pyrlevel( VipsThumbnail *thumbnail,
@ -553,7 +553,21 @@ vips_thumbnail_open( VipsThumbnail *thumbnail )
thumbnail->subifd_pyramid = FALSE; thumbnail->subifd_pyramid = FALSE;
thumbnail->page_pyramid = TRUE; thumbnail->page_pyramid = TRUE;
vips_thumbnail_get_tiff_pyramid_page( thumbnail ); vips_thumbnail_get_pyramid_page( thumbnail );
if( thumbnail->level_count == 0 )
thumbnail->page_pyramid = FALSE;
}
}
/* jp2k uses page-based pyramids.
*/
if( vips_isprefix( "VipsForeignLoadJp2k", thumbnail->loader ) ) {
if( thumbnail->level_count == 0 ) {
thumbnail->subifd_pyramid = FALSE;
thumbnail->page_pyramid = TRUE;
vips_thumbnail_get_pyramid_page( thumbnail );
if( thumbnail->level_count == 0 ) if( thumbnail->level_count == 0 )
thumbnail->page_pyramid = FALSE; thumbnail->page_pyramid = FALSE;
@ -576,8 +590,9 @@ vips_thumbnail_open( VipsThumbnail *thumbnail )
factor = vips_thumbnail_find_jpegshrink( thumbnail, factor = vips_thumbnail_find_jpegshrink( thumbnail,
thumbnail->input_width, thumbnail->input_height ); thumbnail->input_width, thumbnail->input_height );
else if( vips_isprefix( "VipsForeignLoadTiff", thumbnail->loader ) || else if( vips_isprefix( "VipsForeignLoadTiff", thumbnail->loader ) ||
vips_isprefix( "VipsForeignLoadJp2k", thumbnail->loader ) ||
vips_isprefix( "VipsForeignLoadOpenslide", vips_isprefix( "VipsForeignLoadOpenslide",
thumbnail->loader ) ) { thumbnail->loader ) ) {
if( thumbnail->level_count > 0 ) if( thumbnail->level_count > 0 )
factor = vips_thumbnail_find_pyrlevel( thumbnail, factor = vips_thumbnail_find_pyrlevel( thumbnail,
thumbnail->input_width, thumbnail->input_width,
@ -1112,7 +1127,19 @@ vips_thumbnail_file_open( VipsThumbnail *thumbnail, double factor )
"scale", 1.0 / factor, "scale", 1.0 / factor,
NULL ) ); NULL ) );
} }
else if( vips_isprefix( "VipsForeignLoadJp2k", thumbnail->loader ) ) {
/* jp2k optionally uses page-based pyramids.
*/
if( thumbnail->page_pyramid )
return( vips_image_new_from_file( file->filename,
"access", VIPS_ACCESS_SEQUENTIAL,
"page", (int) factor,
NULL ) );
else
return( vips_image_new_from_file( file->filename,
"access", VIPS_ACCESS_SEQUENTIAL,
NULL ) );
}
else if( vips_isprefix( "VipsForeignLoadTiff", thumbnail->loader ) ) { else if( vips_isprefix( "VipsForeignLoadTiff", thumbnail->loader ) ) {
/* We support three modes: subifd pyramids, page-based /* We support three modes: subifd pyramids, page-based
* pyramids, and simple multi-page TIFFs (no pyramid). * pyramids, and simple multi-page TIFFs (no pyramid).
@ -1132,7 +1159,6 @@ vips_thumbnail_file_open( VipsThumbnail *thumbnail, double factor )
"access", VIPS_ACCESS_SEQUENTIAL, "access", VIPS_ACCESS_SEQUENTIAL,
NULL ) ); NULL ) );
} }
else if( vips_isprefix( "VipsForeignLoadHeif", thumbnail->loader ) ) { else if( vips_isprefix( "VipsForeignLoadHeif", thumbnail->loader ) ) {
return( vips_image_new_from_file( file->filename, return( vips_image_new_from_file( file->filename,
"access", VIPS_ACCESS_SEQUENTIAL, "access", VIPS_ACCESS_SEQUENTIAL,
@ -1325,6 +1351,23 @@ vips_thumbnail_buffer_open( VipsThumbnail *thumbnail, double factor )
"scale", 1.0 / factor, "scale", 1.0 / factor,
NULL ) ); NULL ) );
} }
else if( vips_isprefix( "VipsForeignLoadJp2k", thumbnail->loader ) ) {
/* Optional page-based pyramids.
*/
if( thumbnail->page_pyramid )
return( vips_image_new_from_buffer(
buffer->buf->data, buffer->buf->length,
buffer->option_string,
"access", VIPS_ACCESS_SEQUENTIAL,
"page", (int) factor,
NULL ) );
else
return( vips_image_new_from_buffer(
buffer->buf->data, buffer->buf->length,
buffer->option_string,
"access", VIPS_ACCESS_SEQUENTIAL,
NULL ) );
}
else if( vips_isprefix( "VipsForeignLoadTiff", thumbnail->loader ) ) { else if( vips_isprefix( "VipsForeignLoadTiff", thumbnail->loader ) ) {
/* We support three modes: subifd pyramids, page-based /* We support three modes: subifd pyramids, page-based
* pyramids, and simple multi-page TIFFs (no pyramid). * pyramids, and simple multi-page TIFFs (no pyramid).
@ -1521,6 +1564,23 @@ vips_thumbnail_source_open( VipsThumbnail *thumbnail, double factor )
"scale", 1.0 / factor, "scale", 1.0 / factor,
NULL ) ); NULL ) );
} }
else if( vips_isprefix( "VipsForeignLoadJp2k", thumbnail->loader ) ) {
/* Optional page-based pyramids.
*/
if( thumbnail->page_pyramid )
return( vips_image_new_from_source(
source->source,
source->option_string,
"access", VIPS_ACCESS_SEQUENTIAL,
"page", (int) factor,
NULL ) );
else
return( vips_image_new_from_source(
source->source,
source->option_string,
"access", VIPS_ACCESS_SEQUENTIAL,
NULL ) );
}
else if( vips_isprefix( "VipsForeignLoadTiff", thumbnail->loader ) ) { else if( vips_isprefix( "VipsForeignLoadTiff", thumbnail->loader ) ) {
/* We support three modes: subifd pyramids, page-based /* We support three modes: subifd pyramids, page-based
* pyramids, and simple multi-page TIFFs (no pyramid). * pyramids, and simple multi-page TIFFs (no pyramid).

View File

@ -56,6 +56,7 @@ MOSAIC_MARKS = [[489, 140], [66, 141],
MOSAIC_VERTICAL_MARKS = [[388, 44], [364, 346], MOSAIC_VERTICAL_MARKS = [[388, 44], [364, 346],
[384, 17], [385, 629], [384, 17], [385, 629],
[527, 42], [503, 959]] [527, 42], [503, 959]]
JP2K_FILE = os.path.join(IMAGES, "world.jp2")
unsigned_formats = [pyvips.BandFormat.UCHAR, unsigned_formats = [pyvips.BandFormat.UCHAR,
pyvips.BandFormat.USHORT, pyvips.BandFormat.USHORT,

Binary file not shown.

View File

@ -17,7 +17,7 @@ from helpers import \
GIF_ANIM_DISPOSE_PREVIOUS_EXPECTED_PNG_FILE, \ GIF_ANIM_DISPOSE_PREVIOUS_EXPECTED_PNG_FILE, \
temp_filename, assert_almost_equal_objects, have, skip_if_no, \ temp_filename, assert_almost_equal_objects, have, skip_if_no, \
TIF1_FILE, TIF2_FILE, TIF4_FILE, WEBP_LOOKS_LIKE_SVG_FILE, \ TIF1_FILE, TIF2_FILE, TIF4_FILE, WEBP_LOOKS_LIKE_SVG_FILE, \
WEBP_ANIMATED_FILE WEBP_ANIMATED_FILE, JP2K_FILE
class TestForeign: class TestForeign:
tempdir = None tempdir = None
@ -1119,6 +1119,54 @@ class TestForeign:
y = pyvips.Image.new_from_buffer(buf, "") y = pyvips.Image.new_from_buffer(buf, "")
assert y.get("exif-ifd0-Make").split(" ")[0] == "banana" assert y.get("exif-ifd0-Make").split(" ")[0] == "banana"
@skip_if_no("jp2kload")
def test_jp2kload(self):
def jp2k_valid(im):
a = im(402, 73)
assert_almost_equal_objects(a, [141, 144, 73], threshold=2)
assert im.width == 800
assert im.height == 400
assert im.bands == 3
self.file_loader("jp2kload", JP2K_FILE, jp2k_valid)
self.buffer_loader("jp2kload_buffer", JP2K_FILE, jp2k_valid)
@skip_if_no("jp2ksave")
def test_jp2ksave(self):
self.save_load_buffer("jp2ksave_buffer", "jp2kload_buffer",
self.colour, 80)
buf = self.colour.jp2ksave_buffer(lossless=True)
im2 = pyvips.Image.new_from_buffer(buf, "")
assert (self.colour == im2).min() == 255
# higher Q should mean a bigger buffer
b1 = self.mono.jp2ksave_buffer(Q=10)
b2 = self.mono.jp2ksave_buffer(Q=90)
assert len(b2) > len(b1)
# disabling chroma subsample should mean a bigger buffer
b1 = self.colour.jp2ksave_buffer(subsample_mode="on")
b2 = self.colour.jp2ksave_buffer(subsample_mode="off")
assert len(b2) > len(b1)
# enabling lossless should mean a bigger buffer
b1 = self.colour.jp2ksave_buffer(lossless=False)
b2 = self.colour.jp2ksave_buffer(lossless=True)
assert len(b2) > len(b1)
# 16-bit colour load and save
im = self.colour.colourspace("rgb16")
buf = im.jp2ksave_buffer(lossless=True)
im2 = pyvips.Image.new_from_buffer(buf, "")
assert (im == im2).min() == 255
# openjpeg 32-bit load and save doesn't seem to work, comment out
# im = self.colour.colourspace("rgb16").cast("uint") << 14
# buf = im.jp2ksave_buffer(lossless=True)
# im2 = pyvips.Image.new_from_buffer(buf, "")
# assert (im == im2).min() == 255
if __name__ == '__main__': if __name__ == '__main__':
pytest.main() pytest.main()