From 9bb86119e3e3accf2b5f99b7e1f75cfb30c1475f Mon Sep 17 00:00:00 2001 From: Kleis Auke Wolthuizen Date: Mon, 23 Nov 2020 14:32:36 +0100 Subject: [PATCH 1/4] Ensure vipsload only byte swaps if necessary Prior to this commit, MSB-ordered vips images were always byte swapped on both little- and big endian systems. And LSB-ordered vips images were loaded without a byte swap. This works correctly on little endian systems, but will not work on big endian systems where the byte swap must be done vice versa. This commit ensures that the byte swap only takes place when needed. See https://github.com/libvips/libvips/issues/1847. --- libvips/iofuncs/image.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/libvips/iofuncs/image.c b/libvips/iofuncs/image.c index 2516351d..2a0120a8 100644 --- a/libvips/iofuncs/image.c +++ b/libvips/iofuncs/image.c @@ -859,10 +859,7 @@ vips_image_build( VipsObject *object ) if( (magic = vips__file_magic( filename )) ) { /* We may need to byteswap. */ - guint32 us = vips_amiMSBfirst() ? - VIPS_MAGIC_INTEL : VIPS_MAGIC_SPARC; - - if( magic == us ) { + if( GUINT_FROM_BE( magic ) == image->magic ) { /* Native open. */ if( vips_image_open_input( image ) ) From d9dec2c02753e98c38118fb78bcd44dcafbd7f4e Mon Sep 17 00:00:00 2001 From: Kleis Auke Wolthuizen Date: Mon, 23 Nov 2020 14:35:03 +0100 Subject: [PATCH 2/4] Simplify MSB-ordered image check --- libvips/iofuncs/vips.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libvips/iofuncs/vips.c b/libvips/iofuncs/vips.c index 232773af..81530277 100644 --- a/libvips/iofuncs/vips.c +++ b/libvips/iofuncs/vips.c @@ -354,7 +354,7 @@ vips__read_header_bytes( VipsImage *im, unsigned char *from ) /* We need to swap for other fields if the file byte order is * different from ours. */ - swap = vips_amiMSBfirst() != (im->magic == VIPS_MAGIC_SPARC); + swap = vips_amiMSBfirst() != vips_image_isMSBfirst( im ); for( i = 0; i < VIPS_NUMBER( fields ); i++ ) { fields[i].copy( swap, @@ -435,7 +435,7 @@ vips__write_header_bytes( VipsImage *im, unsigned char *to ) /* Swap if the byte order we are asked to write the header in is * different from ours. */ - gboolean swap = vips_amiMSBfirst() != (im->magic == VIPS_MAGIC_SPARC); + gboolean swap = vips_amiMSBfirst() != vips_image_isMSBfirst( im ); int i; unsigned char *q; From 77de1c473a74b5ba473b099dd608324357f65cb4 Mon Sep 17 00:00:00 2001 From: Kleis Auke Wolthuizen Date: Mon, 23 Nov 2020 14:37:01 +0100 Subject: [PATCH 3/4] Determine endianness at compile time --- libvips/iofuncs/util.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/libvips/iofuncs/util.c b/libvips/iofuncs/util.c index c78b0e0d..b986e275 100644 --- a/libvips/iofuncs/util.c +++ b/libvips/iofuncs/util.c @@ -1602,16 +1602,13 @@ vips_ispoweroftwo( int p ) int vips_amiMSBfirst( void ) { - int test; - unsigned char *p = (unsigned char *) &test; - - test = 0; - p[0] = 255; - - if( test == 255 ) - return( 0 ); - else - return( 1 ); +#if G_BYTE_ORDER == G_BIG_ENDIAN + return( 1 ); +#elif G_BYTE_ORDER == G_LITTLE_ENDIAN + return( 0 ); +#else +#error "Byte order not recognised" +#endif } /* Return the tmp dir. On Windows, GetTempPath() will also check the values of From ea53660a6bf3de1024c621ebefb45f20ea0b9ce5 Mon Sep 17 00:00:00 2001 From: Kleis Auke Wolthuizen Date: Mon, 23 Nov 2020 14:38:08 +0100 Subject: [PATCH 4/4] Port Ruby test case to Python --- test/test-suite/test_foreign.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/test/test-suite/test_foreign.py b/test/test-suite/test_foreign.py index fa196aae..a0cb4966 100644 --- a/test/test-suite/test_foreign.py +++ b/test/test-suite/test_foreign.py @@ -128,6 +128,17 @@ class TestForeign: for i in range(len(before_exif)): assert before_exif[i] == after_exif[i] + # https://github.com/libvips/libvips/issues/1847 + filename = temp_filename(self.tempdir, ".v") + x = pyvips.Image.black(16, 16) + 128 + x.write_to_file(filename) + + x = pyvips.Image.new_from_file(filename) + assert x.width == 16 + assert x.height == 16 + assert x.bands == 1 + assert x.avg() == 128 + x = None @skip_if_no("jpegload")