diff --git a/src/_image_resample.h b/src/_image_resample.h index 5af48c8f5e57..66577ea4ae96 100644 --- a/src/_image_resample.h +++ b/src/_image_resample.h @@ -504,7 +504,8 @@ template struct is_grayscale> : std:: template constexpr bool is_grayscale_v = is_grayscale::value; -template +// rgb_step is only used if input_has_alpha=false. +template struct type_mapping { using input_blender_type = std::conditional_t< @@ -526,7 +527,7 @@ struct type_mapping std::conditional_t< input_has_alpha, agg::pixfmt_alpha_blend_rgba, - agg::pixfmt_alpha_blend_rgb + agg::pixfmt_alpha_blend_rgb > >; using output_blender_type = std::conditional_t< @@ -722,13 +723,14 @@ static void get_filter(const resample_params_t ¶ms, } -template +// rgb_step is only used if input_has_alpha=false. +template void resample( const void *input, int in_width, int in_height, int in_stride, void *output, int out_width, int out_height, int out_stride, resample_params_t ¶ms) { - using type_mapping_t = type_mapping; + using type_mapping_t = type_mapping; using input_pixfmt_t = typename type_mapping_t::input_pixfmt_type; using output_pixfmt_t = typename type_mapping_t::output_pixfmt_type; diff --git a/src/_image_wrapper.cpp b/src/_image_wrapper.cpp index c791899c7f88..5b30282b140a 100644 --- a/src/_image_wrapper.cpp +++ b/src/_image_wrapper.cpp @@ -107,17 +107,29 @@ image_resample(py::array input_array, } py::ssize_t ncomponents = 0; + int rgb_step = 0; if (ndim == 3) { ncomponents = input_array.shape(2); - if (ncomponents != 3 && ncomponents != 4) { + if (ncomponents == 3) { + // We special-case a few options in order to avoid copying in the common case. + auto rgb_stride = input_array.strides(1); + auto item_stride = input_array.strides(2); + if (rgb_stride == 3 * item_stride) { + rgb_step = 3; + } else if (rgb_stride == 4 * item_stride) { + rgb_step = 4; + } + } else if (ncomponents != 4) { throw std::invalid_argument( "3D input array must be RGB with shape (M, N, 3) or RGBA with shape (M, N, 4), " "has trailing dimension of {}"_s.format(ncomponents)); } } - // Ensure input array is contiguous, regardless of dtype - input_array = py::array::ensure(input_array, py::array::c_style); + if (rgb_step == 0) { + // Ensure input array is contiguous, regardless of dtype + input_array = py::array::ensure(input_array, py::array::c_style); + } // Validate output array auto out_ndim = output_array.ndim(); @@ -194,13 +206,22 @@ image_resample(py::array input_array, dtype.equal(py::dtype::of()) ? resample : nullptr ) : ( - dtype.equal(py::dtype::of()) ? resample : - dtype.equal(py::dtype::of()) ? resample : - dtype.equal(py::dtype::of()) ? resample : - dtype.equal(py::dtype::of()) ? resample : - dtype.equal(py::dtype::of()) ? resample : - dtype.equal(py::dtype::of()) ? resample : - nullptr))) + (rgb_step == 4) ? ( + dtype.equal(py::dtype::of()) ? resample : + dtype.equal(py::dtype::of()) ? resample : + dtype.equal(py::dtype::of()) ? resample : + dtype.equal(py::dtype::of()) ? resample : + dtype.equal(py::dtype::of()) ? resample : + dtype.equal(py::dtype::of()) ? resample : + nullptr + ) : ( + dtype.equal(py::dtype::of()) ? resample : + dtype.equal(py::dtype::of()) ? resample : + dtype.equal(py::dtype::of()) ? resample : + dtype.equal(py::dtype::of()) ? resample : + dtype.equal(py::dtype::of()) ? resample : + dtype.equal(py::dtype::of()) ? resample : + nullptr)))) { Py_BEGIN_ALLOW_THREADS resampler(