Skip to content

Commit 3cab8da

Browse files
committed
If height is being scaled down, but not width, resize vertically first
1 parent 7cf4dac commit 3cab8da

2 files changed

Lines changed: 83 additions & 59 deletions

File tree

src/PIL/Image.py

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2428,14 +2428,7 @@ def resize(
24282428
(box[3] - reduce_box[1]) / factor_y,
24292429
)
24302430

2431-
if self.size[1] > self.size[0] * 100 and size[1] < self.size[1]:
2432-
im = self.im.resize(
2433-
(self.size[0], size[1]), resample, (0, box[1], self.size[0], box[3])
2434-
)
2435-
im = im.resize(size, resample, (box[0], 0, box[2], size[1]))
2436-
else:
2437-
im = self.im.resize(size, resample, box)
2438-
return self._new(im)
2431+
return self._new(self.im.resize(size, resample, box))
24392432

24402433
def reduce(
24412434
self,

src/libImaging/Resample.c

Lines changed: 82 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -717,82 +717,113 @@ ImagingResampleInner(
717717
Imaging imTemp = NULL;
718718
Imaging imOut = NULL;
719719

720-
int i, need_horizontal, need_vertical;
720+
int i, second_pass, need_horizontal, need_vertical, error = 0;
721721
int ybox_first, ybox_last;
722-
int ksize_horiz, ksize_vert;
722+
int ksize_horiz = 0, ksize_vert = 0;
723723
int *bounds_horiz, *bounds_vert;
724724
double *kk_horiz, *kk_vert;
725725

726726
need_horizontal = xsize != imIn->xsize || box[0] || box[2] != xsize;
727727
need_vertical = ysize != imIn->ysize || box[1] || box[3] != ysize;
728728

729-
ksize_vert = precompute_coeffs(
730-
imIn->ysize, box[1], box[3], ysize, filterp, &bounds_vert, &kk_vert
731-
);
732-
if (!ksize_vert) {
733-
return NULL;
734-
}
729+
// If height is being scaled down, but not width,
730+
// then run the vertical pass first, to make the horizontal pass faster
731+
int horizontal_first = !(xsize >= (box[2] - box[0]) && ysize < (box[3] - box[1]));
735732

736-
// First used row in the source image
737-
ybox_first = bounds_vert[0];
738-
// Last used row in the source image
739-
ybox_last = bounds_vert[ysize * 2 - 2] + bounds_vert[ysize * 2 - 1];
740-
741-
/* two-pass resize, horizontal pass */
733+
if ((need_horizontal && horizontal_first) || need_vertical) {
734+
ksize_vert = precompute_coeffs(
735+
imIn->ysize, box[1], box[3], ysize, filterp, &bounds_vert, &kk_vert
736+
);
737+
if (!ksize_vert) {
738+
return NULL;
739+
}
740+
}
742741
if (need_horizontal) {
742+
if (horizontal_first) {
743+
// First used row in the source image
744+
ybox_first = bounds_vert[0];
745+
// Last used row in the source image
746+
ybox_last = bounds_vert[ysize * 2 - 2] + bounds_vert[ysize * 2 - 1];
747+
748+
// Shift bounds for vertical pass
749+
for (i = 0; i < ysize; i++) {
750+
bounds_vert[i * 2] -= ybox_first;
751+
}
752+
}
753+
743754
ksize_horiz = precompute_coeffs(
744755
imIn->xsize, box[0], box[2], xsize, filterp, &bounds_horiz, &kk_horiz
745756
);
746757
if (!ksize_horiz) {
747-
free(bounds_vert);
748-
free(kk_vert);
749-
return NULL;
758+
error = 1;
759+
goto end;
750760
}
761+
}
751762

752-
// Shift bounds for vertical pass
753-
for (i = 0; i < ysize; i++) {
754-
bounds_vert[i * 2] -= ybox_first;
763+
#define PASS(function, w, h, offset, ksize, bounds, kk) \
764+
second_pass = imTemp != NULL; \
765+
imTemp = ImagingNewDirty(imIn->mode, w, h); \
766+
if (!imTemp) { \
767+
error = 1; \
768+
goto end; \
769+
} \
770+
function(imTemp, imIn, offset, ksize, bounds, kk); \
771+
if (second_pass) { \
772+
ImagingDelete(imIn); \
773+
} \
774+
imIn = imTemp;
775+
776+
if (horizontal_first) {
777+
if (need_horizontal) {
778+
PASS(
779+
ResampleHorizontal,
780+
xsize,
781+
ybox_last - ybox_first,
782+
ybox_first,
783+
ksize_horiz,
784+
bounds_horiz,
785+
kk_horiz
786+
);
755787
}
756-
757-
imTemp = ImagingNewDirty(imIn->mode, xsize, ybox_last - ybox_first);
758-
if (imTemp) {
759-
ResampleHorizontal(
760-
imTemp, imIn, ybox_first, ksize_horiz, bounds_horiz, kk_horiz
788+
if (need_vertical) {
789+
PASS(ResampleVertical, xsize, ysize, 0, ksize_vert, bounds_vert, kk_vert);
790+
}
791+
} else {
792+
if (need_vertical) {
793+
PASS(
794+
ResampleVertical,
795+
imIn->xsize,
796+
ysize,
797+
0,
798+
ksize_vert,
799+
bounds_vert,
800+
kk_vert
761801
);
762802
}
763-
free(bounds_horiz);
764-
free(kk_horiz);
765-
if (!imTemp) {
766-
free(bounds_vert);
767-
free(kk_vert);
768-
return NULL;
803+
if (need_horizontal) {
804+
PASS(
805+
ResampleHorizontal, xsize, ysize, 0, ksize_horiz, bounds_horiz, kk_horiz
806+
);
769807
}
770-
imOut = imIn = imTemp;
771808
}
772809

773-
/* vertical pass */
774-
if (need_vertical) {
775-
imOut = ImagingNewDirty(imIn->mode, imIn->xsize, ysize);
776-
if (imOut) {
777-
/* imIn can be the original image or horizontally resampled one */
778-
ResampleVertical(imOut, imIn, 0, ksize_vert, bounds_vert, kk_vert);
779-
}
780-
/* it's safe to call ImagingDelete with empty value
781-
if previous step was not performed. */
782-
ImagingDelete(imTemp);
783-
free(bounds_vert);
784-
free(kk_vert);
785-
if (!imOut) {
786-
return NULL;
787-
}
788-
} else {
789-
// Free in any case
810+
end:
811+
if (ksize_horiz) {
812+
free(bounds_horiz);
813+
free(kk_horiz);
814+
}
815+
if (ksize_vert) {
790816
free(bounds_vert);
791817
free(kk_vert);
792818
}
819+
if (error) {
820+
return NULL;
821+
}
793822

794-
/* none of the previous steps are performed, copying */
795-
if (!imOut) {
823+
if (imTemp) {
824+
imOut = imTemp;
825+
} else {
826+
// none of the previous steps are performed, copying
796827
imOut = ImagingCopy(imIn);
797828
}
798829

0 commit comments

Comments
 (0)