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
|
@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()
|
@see Rescale()
|
||||||
*/
|
*/
|
||||||
wxImage Scale(int width, int height,
|
wxImage Scale(int width, int height,
|
||||||
|
@@ -503,10 +503,19 @@ wxImage wxImage::ResampleNearest(int width, int height) const
|
|||||||
{
|
{
|
||||||
wxImage image;
|
wxImage image;
|
||||||
|
|
||||||
const unsigned long old_width = M_IMGDATA->m_width;
|
// We use wxUIntPtr to rescale images of larger size in 64-bit builds:
|
||||||
const unsigned long old_height = M_IMGDATA->m_height;
|
// using long wouldn't allow using images larger than 2^16 in either
|
||||||
wxCHECK_MSG(old_width <= (ULONG_MAX >> 16) &&
|
// direction because of the check below, as sizeof(long) == 4 even in 64
|
||||||
old_height <= (ULONG_MAX >> 16), image, "image dimension too large");
|
// 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 );
|
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 wxUIntPtr x_delta = (old_width << 16) / width;
|
||||||
const unsigned long y_delta = (old_height << 16) / height;
|
const wxUIntPtr y_delta = (old_height << 16) / height;
|
||||||
|
|
||||||
unsigned char* dest_pixel = target_data;
|
unsigned char* dest_pixel = target_data;
|
||||||
|
|
||||||
unsigned long y = 0;
|
wxUIntPtr y = 0;
|
||||||
for (int j = 0; j < height; j++)
|
for (int j = 0; j < height; j++)
|
||||||
{
|
{
|
||||||
const unsigned char* src_line = &source_data[(y>>16)*old_width*3];
|
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 ;
|
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++)
|
for (int i = 0; i < width; i++)
|
||||||
{
|
{
|
||||||
const unsigned char* src_pixel = &src_line[(x>>16)*3];
|
const unsigned char* src_pixel = &src_line[(x>>16)*3];
|
||||||
|
@@ -2249,6 +2249,18 @@ TEST_CASE("wxImage::ChangeColours", "[image]")
|
|||||||
CHECK_THAT(test, RGBSameAs(expected));
|
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
|
TODO: add lots of more tests to wxImage functions
|
||||||
*/
|
*/
|
||||||
|
Reference in New Issue
Block a user