From 7603c4b6abc40ca8488a9d16ce5c900e8756e408 Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Fri, 30 Apr 2021 10:42:32 +0100 Subject: [PATCH] fix some small bugs - disable chroma subsample for jp2k-in-tiff ... it didn't work due to opj bugs - revise numresolutions setting - require opj 2.4 or later --- configure.ac | 17 ++++---------- libvips/foreign/jp2kload.c | 19 +++++++++++----- libvips/foreign/jp2ksave.c | 45 +++++++++++++++++-------------------- libvips/foreign/vips2tiff.c | 18 ++++++++++++++- 4 files changed, 54 insertions(+), 45 deletions(-) diff --git a/configure.ac b/configure.ac index 1b92a872..623fd5b7 100644 --- a/configure.ac +++ b/configure.ac @@ -836,10 +836,11 @@ AC_ARG_WITH([libopenjp2], AS_HELP_STRING([--without-libopenjp2], [build without libopenjp2 (default: test)])) +# 2.4 is the first one to have working threading and tiling if test x"$with_libopenjp2" != x"no"; then - PKG_CHECK_MODULES(LIBOPENJP2, libopenjp2 >= 2.3, + PKG_CHECK_MODULES(LIBOPENJP2, libopenjp2 >= 2.4, [AC_DEFINE(HAVE_LIBOPENJP2,1, - [define if you have libopenjp2 >=2.2 installed.]) + [define if you have libopenjp2 >=2.4 installed.]) with_libopenjp2=yes PACKAGES_USED="$PACKAGES_USED libopenjp2" ], @@ -847,14 +848,6 @@ if test x"$with_libopenjp2" != x"no"; then 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" @@ -1555,7 +1548,7 @@ EXIF metadata support with libexif: $with_libexif JPEG load/save with libjpeg: $with_jpeg JXL load/save with libjxl: $with_libjxl JPEG2000 load/save with libopenjp2: $with_libopenjp2 - (requires libopenjp2 2.2 or later) + (requires libopenjp2 2.4 or later) PNG load with libspng: $with_libspng (requires libspng-0.6 or later) PNG load/save with libpng: $with_png @@ -1574,8 +1567,6 @@ 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 -JPEG2000 load/save with libopenjp2: $with_libopenjp2 - (requires libopenjp2 2.2 or later) slide load with OpenSlide: $with_openslide (dynamic module: $with_openslide_module) (requires openslide-3.3.0 or later) Matlab load with matio: $with_matio diff --git a/libvips/foreign/jp2kload.c b/libvips/foreign/jp2kload.c index 34df14f4..d6fb775d 100644 --- a/libvips/foreign/jp2kload.c +++ b/libvips/foreign/jp2kload.c @@ -496,12 +496,7 @@ vips_foreign_load_jp2k_header( VipsForeignLoad *load ) if( !opj_setup_decoder( jp2k->codec, &jp2k->parameters ) ) return( -1 ); -#ifdef HAVE_LIBOPENJP2_THREADING - /* Use eg. VIPS_CONCURRENCY etc. to set n-cpus, if this openjpeg has - * stable support. - */ opj_codec_set_threads( jp2k->codec, vips_concurrency_get() ); -#endif /*HAVE_LIBOPENJP2_THREADING*/ if( !opj_read_header( jp2k->stream, jp2k->codec, &jp2k->image ) ) return( -1 ); @@ -608,6 +603,12 @@ vips_foreign_load_jp2k_pack( gboolean upsample, int x, i; +#ifdef DEBUG_VERBOSE + printf( "vips_foreign_load_jp2k_pack: " + "upsample = %d, left = %d, top = %d, length = %d\n", + upsample, left, top, length ); +#endif /*DEBUG_VERBOSE*/ + for( i = 0; i < b; i++ ) { opj_image_comp_t *comp = &image->comps[i]; @@ -1152,7 +1153,7 @@ typedef struct _TileDecompress { opj_image_t *image; } TileDecompress; -void +static void vips__foreign_load_jp2k_decompress_free( TileDecompress *decompress ) { VIPS_FREEF( opj_destroy_codec, decompress->codec ); @@ -1182,6 +1183,12 @@ vips__foreign_load_jp2k_decompress( VipsImage *out, VipsPel *q; int y; +#ifdef DEBUG + printf( "vips__foreign_load_jp2k_decompress: width = %d, height = %d, " + "ycc_to_rgb = %d, from_length = %zd, to_length = %zd\n", + width, height, ycc_to_rgb, from_length, to_length ); +#endif /*DEBUG*/ + /* Our ycc->rgb only works for exactly 3 bands. */ ycc_to_rgb = ycc_to_rgb && out->Bands == 3; diff --git a/libvips/foreign/jp2ksave.c b/libvips/foreign/jp2ksave.c index f743e7e6..e9474933 100644 --- a/libvips/foreign/jp2ksave.c +++ b/libvips/foreign/jp2ksave.c @@ -737,11 +737,13 @@ vips_foreign_save_jp2k_set_profile( opj_cparameters_t *parameters, * -I -p RPCL -n 7 \ * -c[256,256],[256,256],[256,256],[256,256],[256,256],[256,256],[256,256] \ * -b 64,64 + * + * except we don't set numresolution -- our caller does that, + * depending on the image size and compression requirements. */ parameters->irreversible = TRUE; parameters->prog_order = OPJ_RPCL; - parameters->numresolution = 7; parameters->cblockw_init = 64; parameters->cblockh_init = 64; parameters->cp_disto_alloc = 1; @@ -817,12 +819,21 @@ vips_foreign_save_jp2k_build( VipsObject *object ) */ opj_set_default_encoder_parameters( &jp2k->parameters ); + /* Set compression profile. + */ + vips_foreign_save_jp2k_set_profile( &jp2k->parameters, + jp2k->lossless, jp2k->Q ); + /* Always tile. */ jp2k->parameters.tile_size_on = OPJ_TRUE; jp2k->parameters.cp_tdx = jp2k->tile_width; jp2k->parameters.cp_tdy = jp2k->tile_height; + /* Makes three band images smaller, somehow. + */ + jp2k->parameters.tcp_mct = save->ready->Bands >= 3 ? 1 : 0; + /* Number of layers to write. Smallest layer is c. 2^5 on the smallest * axis. */ @@ -834,15 +845,6 @@ vips_foreign_save_jp2k_build( VipsObject *object ) jp2k->parameters.numresolution ); #endif /*DEBUG*/ - /* Makes three band images smaller, somehow. - */ - jp2k->parameters.tcp_mct = save->ready->Bands >= 3 ? 1 : 0; - - /* Set compression profile. - */ - vips_foreign_save_jp2k_set_profile( &jp2k->parameters, - jp2k->lossless, jp2k->Q ); - /* Set up compressor. */ @@ -858,12 +860,7 @@ vips_foreign_save_jp2k_build( VipsObject *object ) if( !opj_setup_encoder( jp2k->codec, &jp2k->parameters, jp2k->image ) ) return( -1 ); -#ifdef HAVE_LIBOPENJP2_THREADING - /* Use eg. VIPS_CONCURRENCY etc. to set n-cpus, if this openjpeg has - * stable support. - */ opj_codec_set_threads( jp2k->codec, vips_concurrency_get() ); -#endif /*HAVE_LIBOPENJP2_THREADING*/ if( !(jp2k->stream = vips_foreign_save_jp2k_target( jp2k->target )) ) return( -1 ); @@ -1315,16 +1312,19 @@ vips__foreign_load_jp2k_compress( VipsRegion *region, /* Set compression params. */ opj_set_default_encoder_parameters( ¶meters ); - parameters.numresolution = 1; - - /* Makes three band images smaller, somehow. - */ - parameters.tcp_mct = (region->im->Bands >= 3 && !subsample) ? 1 : 0; /* Set compression profile. */ vips_foreign_save_jp2k_set_profile( ¶meters, lossless, Q ); + /* Makes three band images smaller, somehow. + */ + parameters.tcp_mct = region->im->Bands >= 3 ? 1 : 0; + + /* Only one pyramid level. + */ + parameters.numresolution = 1; + /* Create output image. TRUE means we alloc memory for the image * planes. */ @@ -1351,12 +1351,7 @@ vips__foreign_load_jp2k_compress( VipsRegion *region, return( -1 ); } -#ifdef HAVE_LIBOPENJP2_THREADING - /* Use eg. VIPS_CONCURRENCY etc. to set n-cpus, if this openjpeg has - * stable support. - */ opj_codec_set_threads( compress.codec, vips_concurrency_get() ); -#endif /*HAVE_LIBOPENJP2_THREADING*/ if( save_as_ycc ) vips_foreign_save_jp2k_rgb_to_ycc( region, diff --git a/libvips/foreign/vips2tiff.c b/libvips/foreign/vips2tiff.c index 74ba9163..b75dfd4d 100644 --- a/libvips/foreign/vips2tiff.c +++ b/libvips/foreign/vips2tiff.c @@ -1558,11 +1558,27 @@ wtiff_layer_write_tiles( Wtiff *wtiff, Layer *layer, VipsRegion *strip ) switch( wtiff->compression ) { case JP2K_LOSSY: + /* Sadly chroma subsample seems not to work + * for edge tiles in tiff with jp2k + * compression, so we always pass FALSE + * instead of: + * + * !wtiff->rgbjpeg && wtiff->Q < 90, + * + * I've verified that the libvips jp2k + * encode and decode subsample operations fill + * the comps[i].data arrays correctly, so it + * seems to be a openjpeg bug. + * + * FIXME ... try again with openjpeg 2.5, + * when that comes. + */ result = vips__foreign_load_jp2k_compress( strip, &tile, target, wtiff->tilew, wtiff->tileh, !wtiff->rgbjpeg, - !wtiff->rgbjpeg && wtiff->Q < 90, + // !wtiff->rgbjpeg && wtiff->Q < 90, + FALSE, wtiff->lossless, wtiff->Q ); break;