Allow rescaling larger images in Win64 builds
Use wxUIntPtr rather than (unsigned) long in wxImage::ResampleNearest() as long is still 32 bits under Win64 and so doesn't allow the code there to work with images larger than 2^16 in either direction, when it could be allowed in this case. Document the current limits on the size of the image and add a unit test checking that resizing images of size greater than 2^16 works in 64 bits. See #18550.
This commit is contained in:
@@ -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,
|
||||
|
@@ -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<wxUIntPtr>(-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];
|
||||
|
@@ -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
|
||||
*/
|
||||
|
Reference in New Issue
Block a user