diff --git a/ChangeLog b/ChangeLog index 24bcfd63..88717fe8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -7,6 +7,8 @@ - fix includes of glib headers in C++ [lovell] - fix build with more modern librsvg [lovell] - fix a possible segv with very wide images [f1ac] +- revise premultiply, again [jjonesrs] +- revise profile handling in vipsthumbnail - fix tiff deflate predictor setting [Adios] 18/12/20 started 8.10.5 diff --git a/libvips/conversion/flatten.c b/libvips/conversion/flatten.c index 912644c9..7c9f3527 100644 --- a/libvips/conversion/flatten.c +++ b/libvips/conversion/flatten.c @@ -67,7 +67,7 @@ typedef struct _VipsFlatten { */ VipsArrayDouble *background; - /* The [double] converted to the input image format. + /* The [double] background converted to the input image format. */ VipsPel *ink; diff --git a/libvips/conversion/unpremultiply.c b/libvips/conversion/unpremultiply.c index 219fac28..88bbbed2 100644 --- a/libvips/conversion/unpremultiply.c +++ b/libvips/conversion/unpremultiply.c @@ -7,6 +7,8 @@ * - max_alpha defaults to 65535 for RGB16/GREY16 * 24/11/17 lovell * - match normalised alpha to output type + * 27/2/21 jjonesrs + * - revise range clipping and 1/x, again */ /* @@ -70,7 +72,8 @@ typedef VipsConversionClass VipsUnpremultiplyClass; G_DEFINE_TYPE( VipsUnpremultiply, vips_unpremultiply, VIPS_TYPE_CONVERSION ); -/* Unpremultiply an N-band image. +/* Unpremultiply an N-band image. Don't use clip_alpha to calculate factor: we + * want over and undershoots on alpha and RGB to cancel. */ #define UNPRE_MANY( IN, OUT ) { \ IN * restrict p = (IN *) in; \ @@ -78,18 +81,11 @@ G_DEFINE_TYPE( VipsUnpremultiply, vips_unpremultiply, VIPS_TYPE_CONVERSION ); \ for( x = 0; x < width; x++ ) { \ IN alpha = p[alpha_band]; \ + OUT factor = alpha == 0 ? 0 : max_alpha / alpha; \ \ - if( alpha != 0 ) { \ - OUT factor = max_alpha / alpha; \ - \ - for( i = 0; i < alpha_band; i++ ) \ - q[i] = factor * p[i]; \ - q[alpha_band] = alpha; \ - } \ - else \ - for( i = 0; i < alpha_band + 1; i++ ) \ - q[i] = 0; \ - \ + for( i = 0; i < alpha_band; i++ ) \ + q[i] = factor * p[i]; \ + q[alpha_band] = VIPS_CLIP( 0, alpha, max_alpha ); \ for( i = alpha_band + 1; i < bands; i++ ) \ q[i] = p[i]; \ \ @@ -106,21 +102,12 @@ G_DEFINE_TYPE( VipsUnpremultiply, vips_unpremultiply, VIPS_TYPE_CONVERSION ); \ for( x = 0; x < width; x++ ) { \ IN alpha = p[3]; \ + OUT factor = alpha == 0 ? 0 : max_alpha / alpha; \ \ - if( alpha != 0 ) { \ - OUT factor = max_alpha / alpha; \ - \ - q[0] = factor * p[0]; \ - q[1] = factor * p[1]; \ - q[2] = factor * p[2]; \ - q[3] = alpha; \ - } \ - else { \ - q[0] = 0; \ - q[1] = 0; \ - q[2] = 0; \ - q[3] = 0; \ - } \ + q[0] = factor * p[0]; \ + q[1] = factor * p[1]; \ + q[2] = factor * p[2]; \ + q[3] = VIPS_CLIP( 0, alpha, max_alpha ); \ \ p += 4; \ q += 4; \ diff --git a/libvips/resample/thumbnail.c b/libvips/resample/thumbnail.c index 88b18d8a..40826a43 100644 --- a/libvips/resample/thumbnail.c +++ b/libvips/resample/thumbnail.c @@ -30,6 +30,9 @@ * - add thumbnail_source * 2/6/20 * - add subifd pyr support + * 27/2/21 + * - simplify rules re. processing space, colour management and linear + * mode */ /* @@ -626,16 +629,19 @@ vips_thumbnail_build( VipsObject *object ) int preshrunk_page_height; double hshrink; double vshrink; - VipsInterpretation interpretation; /* TRUE if we've done the import of an ICC transform and still need to * export. */ gboolean have_imported; - /* TRUE if we've premultiplied and need to unpremultiply. + /* If we shrink in linear space, we need to return to the input + * colourspace after the shrink. + */ + VipsInterpretation input_interpretation; + + /* The format we need to revert to after unpremultiply. */ - gboolean have_premultiplied; VipsBandFormat unpremultiplied_format; #ifdef DEBUG @@ -681,60 +687,78 @@ vips_thumbnail_build( VipsObject *object ) in = t[12]; } - /* In linear mode, we import right at the start. - * - * We also have to import the whole image if it's CMYK, since - * vips_colourspace() (see below) doesn't let you specify the fallback - * profile. - * - * This is only going to work for images in device space. If you have - * an image in PCS which also has an attached profile, strange things - * will happen. + /* In linear mode, we need to transform to a linear space before + * vips_resize(). */ have_imported = FALSE; - if( thumbnail->linear && - in->Coding == VIPS_CODING_NONE && - (in->BandFmt == VIPS_FORMAT_UCHAR || - in->BandFmt == VIPS_FORMAT_USHORT) && - (vips_image_get_typeof( in, VIPS_META_ICC_NAME ) || - thumbnail->import_profile) ) { - g_info( "importing to XYZ PCS" ); - if( thumbnail->import_profile ) - g_info( "fallback input profile %s", - thumbnail->import_profile ); + if( thumbnail->linear ) { + /* If we are doing colour management (there's an import + * profile), then we can use XYZ PCS as the resize space. + */ + if( in->Coding == VIPS_CODING_NONE && + (in->BandFmt == VIPS_FORMAT_UCHAR || + in->BandFmt == VIPS_FORMAT_USHORT) && + (vips_image_get_typeof( in, VIPS_META_ICC_NAME ) || + thumbnail->import_profile) ) { + g_info( "importing to XYZ PCS" ); + if( thumbnail->import_profile ) + g_info( "fallback input profile %s", + thumbnail->import_profile ); - if( vips_icc_import( in, &t[1], - "input_profile", thumbnail->import_profile, - "embedded", TRUE, - "intent", thumbnail->intent, - "pcs", VIPS_PCS_XYZ, - NULL ) ) - return( -1 ); + if( vips_icc_import( in, &t[1], + "input_profile", thumbnail->import_profile, + "embedded", TRUE, + "intent", thumbnail->intent, + "pcs", VIPS_PCS_XYZ, + NULL ) ) + return( -1 ); + in = t[1]; - in = t[1]; + have_imported = TRUE; + } + else { + /* Otherwise, use scRGB or GREY16 for linear shrink. + */ + VipsInterpretation interpretation; - have_imported = TRUE; + /* Note the interpretation we will revert to after + * linear. + */ + input_interpretation = in->Type; + + if( in->Bands < 3 ) + interpretation = VIPS_INTERPRETATION_GREY16; + else + interpretation = VIPS_INTERPRETATION_scRGB; + + g_info( "converting to processing space %s", + vips_enum_nick( VIPS_TYPE_INTERPRETATION, + interpretation ) ); + if( vips_colourspace( in, &t[2], interpretation, + NULL ) ) + return( -1 ); + in = t[2]; + } } + else { + /* In non-linear mode, use sRGB or B_W as the processing + * space. + */ + VipsInterpretation interpretation; - /* To the processing colourspace. This will unpack LABQ, import CMYK, - * etc. - * - * If this is a CMYK image, we need to set have_imported since we only - * want to export at the end. - */ - if( in->Type == VIPS_INTERPRETATION_CMYK ) - have_imported = TRUE; - if( thumbnail->linear ) - interpretation = VIPS_INTERPRETATION_scRGB; - else if( in->Bands < 3 ) - interpretation = VIPS_INTERPRETATION_B_W; - else - interpretation = VIPS_INTERPRETATION_sRGB; - g_info( "converting to processing space %s", - vips_enum_nick( VIPS_TYPE_INTERPRETATION, interpretation ) ); - if( vips_colourspace( in, &t[2], interpretation, NULL ) ) - return( -1 ); - in = t[2]; + if( in->Bands < 3 ) + interpretation = VIPS_INTERPRETATION_B_W; + else + interpretation = VIPS_INTERPRETATION_sRGB; + + g_info( "converting to processing space %s", + vips_enum_nick( VIPS_TYPE_INTERPRETATION, + interpretation ) ); + if( vips_colourspace( in, &t[2], interpretation, + NULL ) ) + return( -1 ); + in = t[2]; + } /* Shrink to preshrunk_page_height, so we work for multi-page images. */ @@ -753,23 +777,23 @@ vips_thumbnail_build( VipsObject *object ) vshrink = (double) in->Ysize / target_image_height; } + /* vips_premultiply() makes a float image, so when we unpremultiply + * below we must cast back to the original format. Use NOTSET to + * meran no pre/unmultiply. + */ + unpremultiplied_format = VIPS_FORMAT_NOTSET; + /* If there's an alpha, we have to premultiply before shrinking. See * https://github.com/libvips/libvips/issues/291 */ - have_premultiplied = FALSE; if( vips_image_hasalpha( in ) && hshrink != 1.0 && vshrink != 1.0 ) { g_info( "premultiplying alpha" ); + unpremultiplied_format = in->BandFmt; + if( vips_premultiply( in, &t[3], NULL ) ) return( -1 ); - have_premultiplied = TRUE; - - /* vips_premultiply() makes a float image. When we - * vips_unpremultiply() below, we need to cast back to the - * pre-premultiply format. - */ - unpremultiplied_format = in->BandFmt; in = t[3]; } @@ -779,6 +803,14 @@ vips_thumbnail_build( VipsObject *object ) return( -1 ); in = t[4]; + if( unpremultiplied_format != VIPS_FORMAT_NOTSET ) { + g_info( "unpremultiplying alpha" ); + if( vips_unpremultiply( in, &t[5], NULL ) || + vips_cast( t[5], &t[6], unpremultiplied_format, NULL ) ) + return( -1 ); + in = t[6]; + } + /* Only set page-height if we have more than one page, or this could * accidentally turn into an animated image later. */ @@ -794,21 +826,12 @@ vips_thumbnail_build( VipsObject *object ) VIPS_META_PAGE_HEIGHT, output_page_height ); } - if( have_premultiplied ) { - g_info( "unpremultiplying alpha" ); - if( vips_unpremultiply( in, &t[5], NULL ) || - vips_cast( t[5], &t[6], unpremultiplied_format, NULL ) ) - return( -1 ); - in = t[6]; - } - /* Colour management. - * - * If we've already imported, just export. Otherwise, we're in - * device space and we need a combined import/export to transform to - * the target space. */ if( have_imported ) { + /* We've already imported, just export. Go to sRGB if there's + * no export profile. + */ if( thumbnail->export_profile || vips_image_get_typeof( in, VIPS_META_ICC_NAME ) ) { g_info( "exporting to device space with a profile" ); @@ -827,21 +850,54 @@ vips_thumbnail_build( VipsObject *object ) in = t[7]; } } - else if( thumbnail->export_profile && - (vips_image_get_typeof( in, VIPS_META_ICC_NAME ) || - thumbnail->import_profile) ) { + else if( thumbnail->export_profile ) { + /* Not imported, but we are doing colour management. Transform + * to the output space. + */ g_info( "transforming to %s", thumbnail->export_profile ); - if( thumbnail->import_profile ) - g_info( "fallback input profile %s", - thumbnail->import_profile ); - if( vips_icc_transform( in, &t[7], - thumbnail->export_profile, - "input_profile", thumbnail->import_profile, - "intent", thumbnail->intent, - "embedded", TRUE, - NULL ) ) - return( -1 ); + /* If there's some kind of import profile, we can transform to + * the output. Otherwise we have to convert to PCS and then + * export. + */ + if( thumbnail->import_profile || + (vips_image_get_typeof( in, VIPS_META_ICC_NAME ) || + thumbnail->import_profile) ) { + g_info( "transforming with supplied profiles" ); + if( vips_icc_transform( in, &t[7], + thumbnail->export_profile, + "input_profile", thumbnail->import_profile, + "intent", thumbnail->intent, + "embedded", TRUE, + NULL ) ) + return( -1 ); + + in = t[7]; + } + else { + g_info( "exporting with %s", + thumbnail->export_profile ); + if( vips_colourspace( in, &t[7], + VIPS_INTERPRETATION_XYZ, NULL ) || + vips_icc_export( t[7], &t[8], + "output_profile", + thumbnail->export_profile, + "intent", thumbnail->intent, + NULL ) ) + return( -1 ); + in = t[8]; + } + } + else if( thumbnail->linear ) { + /* Linear mode, no colour management. We went to scRGB for + * processing, so we now revert to the input colourspace. + */ + g_info( "reverting to input space %s", + vips_enum_nick( VIPS_TYPE_INTERPRETATION, + input_interpretation ) ); + if( vips_colourspace( in, &t[7], + input_interpretation, NULL ) ) + return( -1 ); in = t[7]; } @@ -1370,7 +1426,7 @@ vips_thumbnail_buffer_init( VipsThumbnailBuffer *buffer ) * * @intent: #VipsIntent, rendering intent * * @option_string: %gchararray, extra loader options * - * Exacty as vips_thumbnail(), but read from a memory buffer. One extra + * Exactly as vips_thumbnail(), but read from a memory buffer. One extra * optional argument, @option_string, lets you pass options to the underlying * loader. * @@ -1566,7 +1622,7 @@ vips_thumbnail_source_init( VipsThumbnailSource *source ) * * @intent: #VipsIntent, rendering intent * * @option_string: %gchararray, extra loader options * - * Exacty as vips_thumbnail(), but read from a source. One extra + * Exactly as vips_thumbnail(), but read from a source. One extra * optional argument, @option_string, lets you pass options to the underlying * loader. * @@ -1673,7 +1729,7 @@ vips_thumbnail_image_init( VipsThumbnailImage *image ) * * @export_profile: %gchararray, export ICC profile * * @intent: #VipsIntent, rendering intent * - * Exacty as vips_thumbnail(), but read from an existing image. + * Exactly as vips_thumbnail(), but read from an existing image. * * This operation * is not able to exploit shrink-on-load features of image load libraries, so diff --git a/test/test-suite/helpers/helpers.py b/test/test-suite/helpers/helpers.py index 585a7f0c..0eee4e7d 100644 --- a/test/test-suite/helpers/helpers.py +++ b/test/test-suite/helpers/helpers.py @@ -42,6 +42,8 @@ BMP_FILE = os.path.join(IMAGES, "MARBLES.BMP") NIFTI_FILE = os.path.join(IMAGES, "avg152T1_LR_nifti.nii.gz") ICO_FILE = os.path.join(IMAGES, "favicon.ico") HEIC_FILE = os.path.join(IMAGES, "heic-orientation-6.heic") +RGBA_FILE = os.path.join(IMAGES, "rgba.png") +RGBA_CORRECT_FILE = os.path.join(IMAGES, "rgba-correct.ppm") MOSAIC_FILES = [os.path.join(IMAGES, "cd1.1.jpg"), os.path.join(IMAGES, "cd1.2.jpg"), os.path.join(IMAGES, "cd2.1.jpg"), os.path.join(IMAGES, "cd2.2.jpg"), os.path.join(IMAGES, "cd3.1.jpg"), os.path.join(IMAGES, "cd3.2.jpg"), diff --git a/test/test-suite/images/rgba-correct.ppm b/test/test-suite/images/rgba-correct.ppm new file mode 100644 index 00000000..b83fdce9 --- /dev/null +++ b/test/test-suite/images/rgba-correct.ppm @@ -0,0 +1,5 @@ +P6 +#vips2ppm - 2021-02-27T15:39:39.437028Z +64 64 +255 +’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’žžžžžž’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’žžžžžžžžž’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’ééėöö÷’’’’’’’’’’’’’’’žžžžžž’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’¶³¼¾»ĀÉĒĶŻÜąźźģųųł’’’’’’’’’’’’žžžžžž’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’³®µ¶²¹»“½Į»Ć¾¹æĄ»ĆĶĖŃįįäńņóżżż’’’’’’’’’žžžžžž’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’Ŗ¦«¬§­°«²“­³ŗ²¹°§Æŗ“»³°·»¹ĀĖŹŃŽŽāņóō’’’’’’’’’žžžžžž’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’­ŖÆ­©Æؤ©­©®²­“±Ŗ±°«±“®“±¬²µ²ŗø¶¾¹¹ĀŠŠ×čéģüüż’’’’’’žžžžžž’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’Æ©ÆŖ„Ŗ££­Ø­±®²­Ø®§¢Ø²­²ÆŖÆŖ¤Ŗ°«±¬¦®°­²»¹ĀĖĒŃāāēūūü’’’’’’žžž’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’®§­­§­Ŗ„Ŗ«§­ÆŖ²¦Ÿ„«¦­“°¶“Æ“°Ŗ°³­“ÆØ®¢œ ¬¤Ŗ·±¹ŗ¶ĄĒÅĶäåčżżż’’’žžžžžž’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’“®³§¢§Ŗ¦¬®Ŗ°§Ÿ¦©¢Ø©£©«§­«¦­Ŗ£«ÆØ°­§¬”›ŸŖ£Ŗ“­“²«±µ±¶¶³¹ÅĀĖééģ’’’’’’žžžžžž’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’Ŗ¤Ø„Ÿ„©£«¦”§„ž¤®Ø®®ŖÆ£ž£ž—Ŗ„«Ŗ„«ž—¢›”„Ÿ„©¢Ŗ®¦­¤¢©¢§²«²²°øČŹŠńńó’’’’’’žžž’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’³­²°ŖƧ¢©š•›„ ¦±¬²¦”§§”§££­Ŗ®²®“­ŖÆŖ¦ŖŖ„Ŗ¦”§©£Ø¦Ÿ„ž™Ÿ­©­­§¬µ°¹µ³½ÕŌŁüüü’’’žžžžžž’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’«¦«®§¬„ §©£Ŗ¤Ÿ¤™Ÿ¤Ÿ¦Ŗ„Ŗ¤£££©¤Ŗ¬ŖƧ¤Ŗ£ž£©„Ŗ§”§Ŗ£ŖŖ„«§£Ŗ¬§­“¬±­¦«²­“¾¼Äźźģ’’’’’’žžž’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’§”§ÆØ­Ŗ„«§”§Ÿ›Ÿ¢ž£¦¢§žšž£ž£Ŗ¤©§£Ŗœ˜ž¢£”™ „Ÿ¤£ž¤£ž¤¦”§Ø£©Ø£§²«Æ®Ø«”œ ©£Ŗ·³»ÕŌŁśśū’’’žžž’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’§Ÿ§²­²§”§¦”¦ž›Ÿ¢ž£žšžš”šŖ¤Ŗ©£Ø©„«§¢§Ÿ—žØ¢Ø££¦Ÿ¦­Ø°°Ŗ±°Ø®Ÿšžž™””¦£Ŗž›Ÿ§ ¦®©Æŗ¹Įķķļ’’’’’’žžž’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’£œ£„Ÿ¤”› Ø£Ø›•›£Ÿ¤£Ÿ¤š”šØ¢§§”¦ ›¢„”§¤Ÿ„ؤŖ„ ¦Ø Ø¬¤­²­“©£Ø›–›”œ¢”¢”Ÿ„§£Ø£”أثحŖ©°ŪŪą’’’’’’žžž’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’¦ „¢”¢ž£„ž£ŸšŸ¢Ÿ¤­ŖƦŸ£¦ž£®Ø­£ž„ž˜ŸŖ¤Ŗ£ž£©£©›•œ™’˜œš­Ø­ž™«§¬Æ«Æ˜”›£Ÿ„§”¦ž˜”œ ”œŸ¬Ø±ĘĘĪųłś’’’žžž’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’¬¦¬Ÿ›ŸŸ›Ÿ”› „Ÿ„Ÿ› ¬Ø®­¦­«£ØÆØ® ›”£Ÿ¤ÆŖ®Ÿ™œŸ› Ÿ™Ÿš“š›„ ¤Ø£§©£Ø§”§“Ž•¢ž¤§£Ø££¤ž£œ–œ ™ž£ Ø±±¹ģģļ’’’’’’žžž’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’˜§£§§£§–œ˜£Ÿ¤Ø£©¢›”§”§££Ø£©ž™Ÿ¤ž¤¤ž£—›£ž£—™”š££—”–š’— ™Ÿ™Ÿ£ ¦Ŗ¦«¬§¬˜›•šžšž œŸ¢£Ŗ§±āįę’’’’’’žžž’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’”¢¤ ¦„ §”•›•›—œ¤”¤Ÿ›žž˜¢œ”–”˜š”›˜’™ž™Ÿž™ŸšŸŸ› ’Œ’˜”™š•›œ•œ£Ÿ„š–›ž™Ÿ”› ””—“˜ œ”—”˜ŸšŸš”š°¬¶ŻŻć’’’’’’žžž’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’§£§ ›¢—’œž˜Ÿ™”™¤Ÿ£Ŗ¦©£ž”¦Ÿ„££™”š„Ÿ„˜ž‹’›”œ ˜Ÿœ•œŸ™Ÿ£ž¤Ŗ¦¬Ÿ› ”Ž”££Ÿš ˜“˜£›¢˜“˜ ›”˜’š™Ÿ›•›—›”šÆ«¶ŽŻä’’’žžž’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’£Ÿ„¦Ÿ§žšŸ˜“™™“™”œ”§”¦›”š–•ž™ŸŸ›Ÿ«§¬˜•™ž™Ÿ—‘—£›£Ÿš ›ŸŸ›¢§£«™Ÿ—’—™Ÿ„ §›—œ”Ž”›—œ‘‘Ž“£Ÿ„¢£ž–™“˜†Œ­Ø“ąąå’’’żżž’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’¤ž„£ž£¦ ¤˜“›˜‘™“”‹›—’“„”§Ø„Ŗž› ”Ž”˜“™ŸšŸ˜’–ž™ž™Ÿ‘Œ‰„ˆ°ŖÆ„ž£——“˜Ÿšž””ŒˆŒ‘Œ›—›–œ”Œ“–Ž”•”Ž‰Ž§„Æźźķ’’’żżż’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’›–œ£ž£—’›œ—Ÿ££š•œ›˜Ÿ™”›—“™•––‘˜Ÿ™”–‘˜Œ’ž™–›„Ÿ£˜“™—›”Ž’™’— šŸœ•›””•“Ÿ›Ÿ“”Ÿ› ™•›Ÿš “Ž”š’˜œ–›™”™”œ ‰‘Ø©±ņóõ’’’žžž’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’”’Œ”š”œŒ”›—ž¦”§¢£–‘˜’Œ“Ÿ™ ž–žŖ”Ŗ’Ž”•”˜œ™ž œ ›–›™žš•›œ—˜’˜˜œ”™Ÿ•–‰…ŠŠ…‹™Ÿ˜”›“”—”™Ÿ› ˜”˜‡„ˆŸ› ›•›“Š‘“—²²½śśū’’’žžž’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’ ›Ÿ™‘”£›”ŽˆŽ˜“›žš”‘‰Ž£›Ÿ©£Ŗ˜‘™£œ¢œ˜œ‘Œ“—“™Š†ŒŽ‰„ ¦™”š‘’‹…‹“Š‘˜”˜’‹‘’‹“‰’~xŒ‡‰„‹‹†Œ“Œ’“Ž“š•šŠ…‰›•œ••”Œ““”–•ÅÄĖ’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’Ŗ¤© ›ž›”—Ž‰œ—Ÿ”–ž–œ£¢”Ž“”•–‘˜—”š™”›’”“Ž”“Ž•ž™ŸŖ£Ŗ”›¢–˜‘–•”–‘•›–ž”€|‚„†–’˜“”•”Œ‘Œ‡Œ•‘•‡ŽŽˆ“Œ““Œ’‹’š˜ ŪŪß’’’żżž’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’œ–•‘–‹†Š”•„”Ø¢£—’–z€Š‘ ›¢–”™–“™Ÿ›£”–”™Œ‰žš š•›”¢Ÿ˜ž™”™‰…ŠŽ‰ŽŽ‰Ž‰Š…Œ’Œ“Š‘ŽŠ‘Œ‘…€†’“‰‰‘Œ†ƒ}ƒŒ†Œ‡„ˆ¢ Ŗķķļ’’’žžž’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’••‘–ˆ‡ƒ‰‹‘“–•—Š†Œš•œ”•’•”’—~ƒ”“—ŽŠ‘†…‰“‘–Š‡•’–›•›‹†‹—’˜‘‹“˜“›‰…‹““Š†ŒŽ‰ŠŒ”Œ’‘’‡ƒ‰„†’Œ”‰„ŠŠ„‹‘‹‘‹„Šˆƒ‹°®øūūü’’’žžž’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’Ž‰‘Š‘•’—‰…Š’–”––‘—‹‡Ž‰™•›Š†ŒˆŽ‘‰’”Œ“™–—‘–’”™”›“‘–‹‡€}ƒ…Š‘”‘šŠ‘š”™””…†’“”–ˆ„ŠŠ…‹Š†‹„†”–“Ž”‹‘†‹ƒ‰~‚•’œĘĘĶ’’’žžž’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’—˜Žˆ”•‘‹š—œš–œ„ƒ–—”Ž”›—Œ†Œ‹‘ž—ž”˜ž–Œ“œ”œœ–ž‹…‹‘‹’˜‘—”“‡‚‡ˆŽ””™•›€{‚‹‡Ž‰†Œ‹†Œ‹‘xsw‰…Šœ˜žŒ†”–ˆ„…Ž‡Œ…Œ‡‚†Š…Š—˜¢įāå’’’žžž’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’œ–ž“Ž“š”˜’‹•‘”˜“˜“Šœ”›š”›™”œ›—Ÿ”—”‘—Š‡€ˆš’šŸ˜Ÿ–•”Œ“˜‘—˜’——’•„€†˜”™‹†Œxrzyt}ŒˆŽ‡‚ˆ‘Œ‘…€†ƒ€ƒ’ŒˆŽ‰‡„‚ˆ{z€€z€‡‚††€„‡ƒ‹««³÷÷ł’’’žžž’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’ˆ„ŠŽ‰Žš”š‡ŒŠ¢œ”›“—‡~ƒ‡…‚ˆŒŠ‘Ž‹‘ˆ„‰‘Œ“‰Ž‡”Œ”›”œ‰„Š†‚‰“”Ž‹…‚ˆ‘‰—‘—ˆƒŠˆƒ‹‚~ƒ…€…ŽˆŽŠ‘„ƒ‚~‚}ƒwt{~„€~„}‚…†ƒ~ƒ‹…Œz‰“ĘÅĪ’’’žžžžžžžžžžžžžžž’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’”Ž”–ž¢œ¤‡‚ˆ‹‡›–›““€x~”“’Ž”‘•‘”’Œ“‘Š‰„‰€z€Œ†Ž‡Ž‡Ž‹“„…Œ‰…‡’‰‘”Ž”ŠƒŠ™“˜ˆŽ‰„Š‰ŽŠ‹ƒ„~z€‚~„zv}ƒ€‡‘•‹ˆ‚}„„€‡{‚„…£ «āćč’’’’’’’’’’’’’’’’’’’’’’’’žžžžžž’’’’’’’’’’’’’’’’’’’’’’’’’’’ŽŠ‘“—•’™ŽŠ‰‡‹‡˜“™‡‚ˆ‰„‰Š…‹–”˜‘“Œ‡Œ‰ƒˆŒ‡‹›˜ŒˆŒŽ†˜“™{x{{~…‚‰‰…‹–‘•…€‡…€ˆ‘‹‘–‘–‹’‚ƒ~yŠ†Œ€|‚€z}xzv~†ƒŠ‡„‹„‡|ƒ…€‡}y{€‰„Œ©§±ģģńõõųšļņššņóóōüüü’’’’’’’’’’’’’’’žžžžžž’’’’’’’’’’’’’’’’’’{zƒ„€ˆŠˆ‹“‹ŠŽŒ“Œ†Ž‡‚ˆ‹‰…ƒ‡‚|ŽŠ‰†‹€}ƒŠ…}zƒ””‘Œ“†‡xtx‡ƒˆ‹‡Ž…€‡ˆŽ‹…Œ…†y€ŽˆŽ“”sosxsx‰ƒŠˆ‚‰yu{…€†‚}ƒ‚}ƒ…€‡‹†ŒŠ†Œˆ„‰…€……}‚‡~…ŒƒÅĆĪééóčęļéēīźčīšīóéēķåäéīķņļīšųųų’’’’’’žžžžžž’’’’’’’’’’’’Œ”Š††‚ˆŒ‡–“™Œ‘ˆ†Œyw}‡„‰Š‡ˆ‰z‚‚…‰„‹…‚‰ur{‚~„‹‡‡‚ˆš”š‰…Š}y„†‹‘”˜“Ž–€z~w~‹†Œzwsyƒ~„‰„‹ˆƒ‹„}…‰ƒ‹y€†€‡ˆƒ‰‡ƒˆ††‡€†ˆ‡ŒƒŠ…Ž œØēęńńļųóš÷õółöōūöōūöóūōńśķźóćąéźčķõõö’’’’’’žžž’’’’’’’’’•’—‰†Œˆ…ŠŒ†ˆ‡˜’—~‚{z~Š‰ˆ‚‰ˆ„ŠŒ‰““ˆˆ‰|ƒƒ…‘’”Ž”•”…}„}w’ŽŠ‘€|ƒ‚…‚}ƒ‹…‹†ˆƒŠ{v|{v}€{‚‡‰‡‰Š…Œ}w~„~…vov‚z€‰‚ˆz•–™”§ ÆąŻźģźņōń÷óš÷šīöńīöńīöīģõģéóšģöōńłįŽēįąå÷÷÷’’’žžžžžž’’’|Œ‡Ž’Ž”€|ƒ‚~…’”Š…‰‰†‰‹…ŒŒˆŽ‚ƒuty†„Š’Š‡|…‡~ˆ‹…€z‚††xrv‹…‹Ž†‚~…ƒ†‹†Ž€y€Œ†Œx~††‡ƒˆƒ}ƒzv|xty|v}ˆ‚‰ƒ~„”•…„rlrysxƒ}‚x€…}†•š¹“æßŪęīģõšķõņńųńīöņļ÷ņš÷ļģōģéņģéņėčńźęļęįėćßźŻŪćīīš’’’’’’žžž‘Ž“xsy‰Žƒ„|z~Š†‚}ƒ…€ˆˆ‚|x‚‚„€~„ˆ†Œ…‹‘‰€}‚‚}„Š„‹†‚}€‰„‰’•‡‚‡ˆ„‰Ž‰‘mfn|v|ˆ‚ˆ‰„Šzw{~x~}y~ƒ}‚~w~{uzw}Š„Š„~„„}‚~x~tms…~…ššĖÄŠėčńöōśóńųņļ÷ņš÷ńīöšīöńīöīģōģčńīėóéęīęćģćŻčęāėčęļŚŲćāįå’’’’’’‰…‹Œ’Ž‹Ž”’}w|ƒ~„ws|y‚Šƒ‹‹…‡ƒ‰|‚‚…‚„tnsqps~zˆ‰‚‰|w|wqwƒ†~x}}vzw}}uz|wzx„~„ƒ„zv||w}}x}z†‡umstnu~xy€y‚——¹°»ŲÓŻńīųõóśõņųņļ÷ņļ÷ōņłņļ÷īėōļķõļķõģéóčåļēćķāŻčāŻēēćķāŽčÓĻŚÕŃÜŲׯśūś‚~ƒ•‘—y}‡ˆ†‚ˆvrx~ƒ€|€ˆƒ‹€}…xr{zv|‚~ƒ……yvzxu{yv}{v}x~|v}}x€””€yˆ€†Œ‡Œ‰ƒ‡’‹‡ƒ‡xsxvqv|uz}u{wpuwqwqjqmgm™˜»“¾ČĮĶÜÕāģēņöóūöōśōóųōņųóńųšīöšķöńīöļķõļīöķźņęćķéåšģčńąŪęåąėćßźŲÕßĪŹÕÖŃÜÖŃŪŁŲŽƒ‡„€‡…‡‡†ˆ‡Ž‹…Œˆ„Š€|‚„€†ƒ…ˆ}x‰…‰•”|w}yu||x~xsxŽˆŒtpv…†”Ž”†€…ˆˆ‡Ž€y‹„‹‰Ž{wz…~ƒŒ„‹ƒ|nhnqin–‘˜·³»ŅĢÖŲÓßåąėńī÷óšųóńųõółšīöšīöņš÷īģōļėōńīöčäīēćīéēļäąėäßźčäīÜ×湌åŪÕߊŹÕ×ŌŽŪ×āĻČÓĢÉՄ†“•‹†|Š‰…‹~z€|ƒ}…‰„Œ‹Ž€z„€‡‚€†…‚†Š‘y‚…†‚}ƒtqvrpw~y€“Ž’‹…‹|v}‚}„„…vow}ƒ€{umstmux– Ą·ĀŌĪŲ×ÓŽßÜčķźōõōśōółńļöóńųņš÷ļģõļīöļķõļėōėēšéćīēāķźęļźēńćßźāŽéÜŲäŅĖ×ßŪęßŪꊏÕŪ×āŅĪŁ¼¶Į¼¶Ć‡ƒ‰––‡ƒ‰†ƒˆ„~„z€}}wqjs‹‡ˆ„‹|x€€}ƒ}yˆ†‹‚~ƒ}xˆƒŠ‡ˆ}xvsxysxxryyt{wrxyt{rnvyu~qls{s{™’šĖÄĪŪÕąćŻéēćīīėōōņłõóśņļ÷šīöņļ÷óņłńīöļģōńīöķéņēäīėēńčćīģčņ掟Ż×äÜ×ćąÜēŪ×āŚÕąŽŚåŚ×āÉÄŠŹĘŅŗ¶Ā°Ŗø¹“Ā†ƒ‰„€„ƒ‡‚}†~yzv~Œ†z~w|„~„†„‡}„‚}„Œˆ‰„‰‰†‹wrwpkr~x€ˆ‚‰„…xsytmt…~…€zyvyysw‹„Š‚y€ —žČĀŹäŽčåąėčäīóńłöōūóņųōņųóņųńīöńīöļģõšķöńīöķéóķéōķźóēäīéåļéåļßŪēŻŲåŽŚę掟äßźßŪꎌåŠĖÖľŹ¼“ĀĒĮĪÄĄĶĄ¼ĖÉÅŅƒ„}x‡ƒ‹…ˆ|w~y‚†‡Œ…Š’‡’‰ƒ}xuyxqz†ƒˆ‰†‹„‚‰„~„€xxsy‚z‚ƒ}ƒ~xz‚‰ƒ‰‡…‰Œˆ£˜Ÿæ¶¾ŁŅŚåßčéćķńīöóńłöōūōņųņļöóńųńļ÷ļģõńīöļģōšķöļģõķźóķéóėēņźēńźęšßŚęąŪč×ŌßąŻčäßģŻŚåÕŠŪĪÉŌČĆĪĀ¾ŹĄŗÅ·±¾ÄæĢŗ“Į½¹ĒĮ¾Ė˜”šws|Š‡Šˆvrxƒ††‚‰zu}{v}„~„ƒ}ƒ}ƒzw~tqx‡ƒŠ‹ˆŽ|sy~u|‰€ˆ…Žzvmrshn‹‚ˆ“­µŹÄĶŽÖąäßźōńłņšųōšųóš÷ōņųņļöóļ÷ņīöīźņšķõšķõīģōėēóźęńéęļåąėźēńėčńŽŚę掟ŽŚåąÜéåąģąÜ莌ęĶČÕÅĄĪĻŹÖĪÉÕĄ»ÉĀ¾ĖĒĮĪÄĄĢ”œŖŖ§“Ŗ§“{vqow~|‚€{|w~~x~†‡tqx|w~‡‰‚}†qoujinxu|‚‡~y‚wrww‡~†„|ƒˆ~†§ §Ā¼ĀŲŅÜŽŁćźåļļķöņšųōņųōńųńīöńļöņšųšīöķźóšķõļģõīźņģēšéåļēäļėēńėēńčäīęįģÜÖāŚÕįäßģāŻéąŻčŻŁåŃĢŲĶČÖĘĮŠĖĘŌÖŃŻĻŹ×ŹÅŅĶĒŌÄĄĶ¤£²œ›Ŗ¦£²§£°…†ƒ†zƒxqw‚|‚ƒ~„x…}„†€†ytz~x€…€†~y€|x}wrx„€…limƒ}„„~…ÆØÆęąéģźōäßģīźõšīöõóśóńųņš÷šīöóņųšīöšķõńīöģéņīėōėčńģéņģčńćŻčėēńéęļęāķāßźŚÖāŽŲåŚŅŽßŪęāŽź×ŅŻŌĪŁĒĀĪľĖĢĒŌĶŹ×ŠĢŁĖČÓ²­ŗ¹³ĄĆæĖØ¢±œšØœ›«Ŗض©§µ„~ƒ€zrjs~w…€„y}w~ˆ€ˆzƒplq~x}€x~ˆ…‹onsrlq~v|—Š”ČĮĖÖŅÜčäļķźōņšųīėõņļųōņłóń÷ńļöšīöńīöņš÷ņļųėčńėēńīģōźēšćßźėēšéåīßŪåęäīäāģßŪęŻŪęßÜēäąģąÜčŪÖćÓĪŪČĀĶĻŹÕŹÄŃŠĖŁŌŃŽČĒÓŹČÕ»¶Ä”›Ŗø“Ā«©µ‘Œ›„”ÆŖ¦“Ŗ§“››Ŗ}u}‹„Š†€…~x…‡wsw„…x€‡€‡„€…}v|{s{ysy†Žø±¹ĪČŃ׊ÜāŻźŻ×åīėõóńųöōśõółńļöņļųōóśńļöīźóņš÷īģõėēńļīõėéņģčóīėóęāķčåļįŻéŽŚåčęļŻŚåŁÕąÜ×äßŪēŁ×įĪŹÕŹĀŠÅĄĪÅĮĻŠĢŲĻĖ×ĪŹ×½¼ĒŖ©¶¦„³§¤²­Ø·²®½£Ÿ­ž›Ŗ§¢°ÆŖø”œ«›˜Ø„‡ŽˆŽ€y~umu†€ˆoin}w}~xuqwjekŽ†š”™Į¹Ąęąéķčńņīųźčóņšųōņśóńųōółōņłšīöļģõóńłńļ÷ļķõļķöļķöļīöźęńźęšäąźäßėąÜēŻŲäÜŚęŌĻÜŁŌßŌĻŚĪĒÓÖŠÜŅĢŲŹÄŃÄæĖČĀĻĪČÕČÄŃĒĆŃĖČÕ¹µĀ­§µ¢ž­£ŸÆ”­›©¦£±¢ž­˜•¦£ °£ Æ››©—•£œŖŒ†‰„Šuns|t|}urjsgbj~y~•—Æ«²ŚÕŽęāėóļų÷öżņšųõņłõółōółōņųńļöšīöņšųļģõńļ÷ņšųšīöėčóėéóģźōāŽźäąģŪŲåŽŪęęāķęāģäąźćąģÕŅŽŽÜēÕŅŻŃĢ×ÖŅŽÖŅŽŃĶŚĢČÖĪĖŁĖČÕČĘŅÄĀĻ»¹Ē­Ø¶Ŗ¤µŖ§¶­Ŗŗ°­¾²Æ½¦£±–”¤›«¤ °–”””“ ”“ŸŖ‚}…ˆ„‰yvxxuyqls~w|§£ØŹÅĢćŽčćßģģéóöóūńī÷ōółōółņš÷ļīöņšųōņłļīöļīöóńųīģõķėōķėōčäļźčņäįģėčņęāķęćīźēņęćķćßėŚÕßŌĪŚĪĒŌĶČŌŌŃÜŹÅÓŠĖ×ŌŃŻŹĒŅĶŹÕĒĆŠĒĀŠ½¹ĘÆ­¹Ø¤²”ž­Ŗ¦“ø³Ć±®¾Æ­½©§¶Ø¦³ ž­”“”Ÿœ¬ ž­˜•£–”¢˜–£š›§†‰pjp{u|‘Š·±øŁŌÜčäīéåļšī÷ģéņņš÷õōśņńųņńųóńłšīöńļöńī÷ļķöšī÷ėéóļīöķėōźēńīģöėźóģźóéēńęāķęāīßŪčćąėßŪēĶČÕĻŹ×ĻÉÖĪČÕÖŅŻŲŌßĘĄĢĆ½ŹĄ½É³°½µ²æ®§³Ŗ£±ŸœŖ¤”ƤŸ®¤”°©§“¬Øø”ÆŸœ­”“”™˜¦””£š™§¢ Æœš©›š§ Ÿ­›Ŗ£¤² \ No newline at end of file diff --git a/test/test-suite/images/rgba.png b/test/test-suite/images/rgba.png new file mode 100644 index 00000000..50fd86f2 Binary files /dev/null and b/test/test-suite/images/rgba.png differ diff --git a/test/test-suite/test_resample.py b/test/test-suite/test_resample.py index afd21422..ea376e90 100644 --- a/test/test-suite/test_resample.py +++ b/test/test-suite/test_resample.py @@ -2,7 +2,8 @@ import pytest import pyvips -from helpers import JPEG_FILE, OME_FILE, HEIC_FILE, TIF_FILE, all_formats, have +from helpers import JPEG_FILE, OME_FILE, HEIC_FILE, TIF_FILE, all_formats, \ + have, RGBA_FILE, RGBA_CORRECT_FILE # Run a function expecting a complex image on a two-band image @@ -193,6 +194,11 @@ class TestResample: im2 = pyvips.Image.thumbnail_buffer(buf, 100) assert abs(im1.avg() - im2.avg()) < 1 + # linear shrink should work on rgba images + im1 = pyvips.Image.thumbnail(RGBA_FILE, 64, linear=True) + im2 = pyvips.Image.new_from_file(RGBA_CORRECT_FILE) + assert abs(im1.flatten(background=255).avg() - im2.avg()) < 1 + if have("heifload"): # this image is orientation 6 ... thumbnail should flip it im = pyvips.Image.new_from_file(HEIC_FILE)