diff --git a/doc/users/next_whats_new/increased_figure_limits.rst b/doc/users/next_whats_new/increased_figure_limits.rst new file mode 100644 index 000000000000..499701cbca38 --- /dev/null +++ b/doc/users/next_whats_new/increased_figure_limits.rst @@ -0,0 +1,9 @@ +Increased Figure limits with Agg renderer +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Figures using the Agg renderer are now limited to 2**23 pixels in each +direction, instead of 2**16. Additionally, bugs that caused artists to not +render past 2**15 pixels horizontally have been fixed. + +Note that if you are using a GUI backend, it may have its own smaller limits +(which may themselves depend on screen size.) diff --git a/extern/agg24-svn/include/agg_rasterizer_cells_aa.h b/extern/agg24-svn/include/agg_rasterizer_cells_aa.h index d1cc705405dc..44a55417b492 100644 --- a/extern/agg24-svn/include/agg_rasterizer_cells_aa.h +++ b/extern/agg24-svn/include/agg_rasterizer_cells_aa.h @@ -325,8 +325,10 @@ namespace agg if(dx >= dx_limit || dx <= -dx_limit) { - int cx = (x1 + x2) >> 1; - int cy = (y1 + y2) >> 1; + // These are overflow safe versions of (x1 + x2) >> 1; divide each by 2 + // first, then add 1 if both were odd. + int cx = (x1 >> 1) + (x2 >> 1) + ((x1 & 1) & (x2 & 1)); + int cy = (y1 >> 1) + (y2 >> 1) + ((y1 & 1) & (y2 & 1)); line(x1, y1, cx, cy); line(cx, cy, x2, y2); return; diff --git a/lib/matplotlib/tests/test_agg.py b/lib/matplotlib/tests/test_agg.py index 80c1f165382c..59387793605a 100644 --- a/lib/matplotlib/tests/test_agg.py +++ b/lib/matplotlib/tests/test_agg.py @@ -199,7 +199,7 @@ def process_image(self, padded_src, dpi): def test_too_large_image(): - fig = plt.figure(figsize=(300, 1000)) + fig = plt.figure(figsize=(300, 2**25)) buff = io.BytesIO() with pytest.raises(ValueError): fig.savefig(buff) diff --git a/src/_backend_agg.cpp b/src/_backend_agg.cpp index 3460b429ec12..eed27323ba9e 100644 --- a/src/_backend_agg.cpp +++ b/src/_backend_agg.cpp @@ -33,10 +33,10 @@ RendererAgg::RendererAgg(unsigned int width, unsigned int height, double dpi) throw std::range_error("dpi must be positive"); } - if (width >= 1 << 16 || height >= 1 << 16) { + if (width >= 1 << 23 || height >= 1 << 23) { throw std::range_error( "Image size of " + std::to_string(width) + "x" + std::to_string(height) + - " pixels is too large. It must be less than 2^16 in each direction."); + " pixels is too large. It must be less than 2^23 in each direction."); } unsigned stride(width * 4); diff --git a/src/_backend_agg.h b/src/_backend_agg.h index 5549978cfb80..a0147f9832c3 100644 --- a/src/_backend_agg.h +++ b/src/_backend_agg.h @@ -117,10 +117,10 @@ class RendererAgg typedef agg::renderer_scanline_bin_solid renderer_bin; typedef agg::rasterizer_scanline_aa rasterizer; - typedef agg::scanline_p8 scanline_p8; - typedef agg::scanline_bin scanline_bin; + typedef agg::scanline32_p8 scanline_p8; + typedef agg::scanline32_bin scanline_bin; typedef agg::amask_no_clip_gray8 alpha_mask_type; - typedef agg::scanline_u8_am scanline_am; + typedef agg::scanline32_u8_am scanline_am; typedef agg::renderer_base renderer_base_alpha_mask_type; typedef agg::renderer_scanline_aa_solid renderer_alpha_mask_type; diff --git a/src/_image_resample.h b/src/_image_resample.h index ddf1a4050325..dbc6171f3ec2 100644 --- a/src/_image_resample.h +++ b/src/_image_resample.h @@ -712,6 +712,7 @@ void resample( using renderer_t = agg::renderer_base; using rasterizer_t = agg::rasterizer_scanline_aa; + using scanline_t = agg::scanline32_u8; using reflect_t = agg::wrap_mode_reflect; using image_accessor_t = agg::image_accessor_wrap; @@ -739,7 +740,7 @@ void resample( span_alloc_t span_alloc; rasterizer_t rasterizer; - agg::scanline_u8 scanline; + scanline_t scanline; span_conv_alpha_t conv_alpha(params.alpha);