diff --git a/interface/wx/image.h b/interface/wx/image.h index ff6baefdb5..46f339dd3b 100644 --- a/interface/wx/image.h +++ b/interface/wx/image.h @@ -972,6 +972,11 @@ public: } @endcode + @note The algorithm used for the default (normal) quality value doesn't + work with images larger than 65536 (2^16) pixels in either dimension + for 32-bit programs. For 64-bit programs the limit is 2^48 and so not + relevant in practice. + @see Rescale() */ wxImage Scale(int width, int height, diff --git a/src/common/image.cpp b/src/common/image.cpp index e4fe44769e..7df6d86fab 100644 --- a/src/common/image.cpp +++ b/src/common/image.cpp @@ -503,10 +503,19 @@ wxImage wxImage::ResampleNearest(int width, int height) const { wxImage image; - const unsigned long old_width = M_IMGDATA->m_width; - const unsigned long old_height = M_IMGDATA->m_height; - wxCHECK_MSG(old_width <= (ULONG_MAX >> 16) && - old_height <= (ULONG_MAX >> 16), image, "image dimension too large"); + // We use wxUIntPtr to rescale images of larger size in 64-bit builds: + // using long wouldn't allow using images larger than 2^16 in either + // direction because of the check below, as sizeof(long) == 4 even in 64 + // bit builds under MSW, but sizeof(wxUIntPtr) == 8 in this case. + const wxUIntPtr old_width = M_IMGDATA->m_width; + const wxUIntPtr old_height = M_IMGDATA->m_height; + + // We use "x << 16" in the code below, so check that this doesn't wrap + // around, as the code wouldn't work correctly if it did. + static const wxUIntPtr SIZE_LIMIT = static_cast(-1) >> 16; + + wxCHECK_MSG(old_width <= SIZE_LIMIT && + old_height <= SIZE_LIMIT, image, "image dimension too large"); image.Create( width, height, false ); @@ -529,18 +538,18 @@ wxImage wxImage::ResampleNearest(int width, int height) const } } - const unsigned long x_delta = (old_width << 16) / width; - const unsigned long y_delta = (old_height << 16) / height; + const wxUIntPtr x_delta = (old_width << 16) / width; + const wxUIntPtr y_delta = (old_height << 16) / height; unsigned char* dest_pixel = target_data; - unsigned long y = 0; + wxUIntPtr y = 0; for (int j = 0; j < height; j++) { const unsigned char* src_line = &source_data[(y>>16)*old_width*3]; const unsigned char* src_alpha_line = source_alpha ? &source_alpha[(y>>16)*old_width] : 0 ; - unsigned long x = 0; + wxUIntPtr x = 0; for (int i = 0; i < width; i++) { const unsigned char* src_pixel = &src_line[(x>>16)*3]; diff --git a/tests/image/image.cpp b/tests/image/image.cpp index d75ee42caa..adaf352afc 100644 --- a/tests/image/image.cpp +++ b/tests/image/image.cpp @@ -2249,6 +2249,18 @@ TEST_CASE("wxImage::ChangeColours", "[image]") CHECK_THAT(test, RGBSameAs(expected)); } +TEST_CASE("wxImage::SizeLimits", "[image]") +{ +#if SIZEOF_VOID_P == 8 + // Check that we can resample an image of size greater than 2^16, which is + // the limit used in 32-bit code to avoid integer overflows. + wxImage image(100000, 2); + REQUIRE_NOTHROW( image = image.ResampleNearest(100000, 1) ); + CHECK( image.GetWidth() == 100000 ); + CHECK( image.GetHeight() == 1 ); +#endif // SIZEOF_VOID_P == 8 +} + /* TODO: add lots of more tests to wxImage functions */