mirror of
https://github.com/python-pillow/Pillow.git
synced 2025-01-26 17:24:31 +03:00
Merge pull request #1933 from uploadcare/resample-vertical-pass
Resample horizontal + vertical pass
This commit is contained in:
commit
62551a8b49
|
@ -39,7 +39,9 @@ def getmode(mode):
|
|||
for m, (basemode, basetype, bands) in Image._MODEINFO.items():
|
||||
_modes[m] = ModeDescriptor(m, bands, basemode, basetype)
|
||||
# extra experimental modes
|
||||
_modes["RGBa"] = ModeDescriptor("RGBa", ("R", "G", "B", "a"), "RGB", "L")
|
||||
_modes["LA"] = ModeDescriptor("LA", ("L", "A"), "L", "L")
|
||||
_modes["La"] = ModeDescriptor("La", ("L", "a"), "L", "L")
|
||||
_modes["PA"] = ModeDescriptor("PA", ("P", "A"), "RGB", "L")
|
||||
# mapping modes
|
||||
_modes["I;16"] = ModeDescriptor("I;16", "I", "L", "L")
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
from helper import unittest, PillowTestCase, hopper
|
||||
from PIL import Image, ImageDraw
|
||||
from PIL import Image, ImageDraw, ImageMode
|
||||
|
||||
|
||||
class TestImagingResampleVulnerability(PillowTestCase):
|
||||
|
@ -35,7 +35,7 @@ class TestImagingResampleVulnerability(PillowTestCase):
|
|||
|
||||
|
||||
class TestImagingCoreResampleAccuracy(PillowTestCase):
|
||||
def make_case(self, size, color):
|
||||
def make_case(self, mode, size, color):
|
||||
"""Makes a sample image with two dark and two bright squares.
|
||||
For example:
|
||||
e0 e0 1f 1f
|
||||
|
@ -43,14 +43,12 @@ class TestImagingCoreResampleAccuracy(PillowTestCase):
|
|||
1f 1f e0 e0
|
||||
1f 1f e0 e0
|
||||
"""
|
||||
dark = (255 - color, 255 - color, 255 - color, 255 - color)
|
||||
bright = (color, color, color, color)
|
||||
case = Image.new('L', size, 255 - color)
|
||||
rectangle = ImageDraw.Draw(case).rectangle
|
||||
rectangle((0, 0, size[0] // 2 - 1, size[1] // 2 - 1), color)
|
||||
rectangle((size[0] // 2, size[1] // 2, size[0], size[1]), color)
|
||||
|
||||
i = Image.new('RGBX', size, dark)
|
||||
rectangle = ImageDraw.Draw(i).rectangle
|
||||
rectangle((0, 0, size[0] // 2 - 1, size[1] // 2 - 1), bright)
|
||||
rectangle((size[0] // 2, size[1] // 2, size[0], size[1]), bright)
|
||||
return i
|
||||
return Image.merge(mode, [case] * len(mode))
|
||||
|
||||
def make_sample(self, data, size):
|
||||
"""Restores a sample image from given data string which contains
|
||||
|
@ -70,17 +68,16 @@ class TestImagingCoreResampleAccuracy(PillowTestCase):
|
|||
return sample
|
||||
|
||||
def check_case(self, case, sample):
|
||||
for channel in case.split():
|
||||
s_px = sample.load()
|
||||
c_px = channel.load()
|
||||
for y in range(case.size[1]):
|
||||
for x in range(case.size[0]):
|
||||
if c_px[x, y] != s_px[x, y]:
|
||||
message = '\nHave: \n{}\n\nExpected: \n{}'.format(
|
||||
self.serialize_image(channel),
|
||||
self.serialize_image(sample),
|
||||
)
|
||||
self.assertEqual(s_px[x, y], c_px[x, y], message)
|
||||
s_px = sample.load()
|
||||
c_px = case.load()
|
||||
for y in range(case.size[1]):
|
||||
for x in range(case.size[0]):
|
||||
if c_px[x, y] != s_px[x, y]:
|
||||
message = '\nHave: \n{}\n\nExpected: \n{}'.format(
|
||||
self.serialize_image(case),
|
||||
self.serialize_image(sample),
|
||||
)
|
||||
self.assertEqual(s_px[x, y], c_px[x, y], message)
|
||||
|
||||
def serialize_image(self, image):
|
||||
s_px = image.load()
|
||||
|
@ -93,61 +90,67 @@ class TestImagingCoreResampleAccuracy(PillowTestCase):
|
|||
)
|
||||
|
||||
def test_reduce_bilinear(self):
|
||||
case = self.make_case((8, 8), 0xe1)
|
||||
data = ('e1 c9'
|
||||
'c9 b7')
|
||||
self.check_case(
|
||||
case.resize((4, 4), Image.BILINEAR),
|
||||
self.make_sample(data, (4, 4)))
|
||||
for mode in ['RGBX', 'RGB', 'La', 'L']:
|
||||
case = self.make_case(mode, (8, 8), 0xe1)
|
||||
case = case.resize((4, 4), Image.BILINEAR)
|
||||
data = ('e1 c9'
|
||||
'c9 b7')
|
||||
for channel in case.split():
|
||||
self.check_case(channel, self.make_sample(data, (4, 4)))
|
||||
|
||||
def test_reduce_bicubic(self):
|
||||
case = self.make_case((12, 12), 0xe1)
|
||||
data = ('e1 e3 d4'
|
||||
'e3 e5 d6'
|
||||
'd4 d6 c9')
|
||||
self.check_case(
|
||||
case.resize((6, 6), Image.BICUBIC),
|
||||
self.make_sample(data, (6, 6)))
|
||||
for mode in ['RGBX', 'RGB', 'La', 'L']:
|
||||
case = self.make_case(mode, (12, 12), 0xe1)
|
||||
case = case.resize((6, 6), Image.BICUBIC)
|
||||
data = ('e1 e3 d4'
|
||||
'e3 e5 d6'
|
||||
'd4 d6 c9')
|
||||
for channel in case.split():
|
||||
self.check_case(channel, self.make_sample(data, (6, 6)))
|
||||
|
||||
def test_reduce_lanczos(self):
|
||||
case = self.make_case((16, 16), 0xe1)
|
||||
data = ('e1 e0 e4 d7'
|
||||
'e0 df e3 d6'
|
||||
'e4 e3 e7 da'
|
||||
'd7 d6 d9 ce')
|
||||
self.check_case(
|
||||
case.resize((8, 8), Image.LANCZOS),
|
||||
self.make_sample(data, (8, 8)))
|
||||
for mode in ['RGBX', 'RGB', 'La', 'L']:
|
||||
case = self.make_case(mode, (16, 16), 0xe1)
|
||||
case = case.resize((8, 8), Image.LANCZOS)
|
||||
data = ('e1 e0 e4 d7'
|
||||
'e0 df e3 d6'
|
||||
'e4 e3 e7 da'
|
||||
'd7 d6 d9 ce')
|
||||
for channel in case.split():
|
||||
self.check_case(channel, self.make_sample(data, (8, 8)))
|
||||
|
||||
def test_enlarge_bilinear(self):
|
||||
case = self.make_case((2, 2), 0xe1)
|
||||
data = ('e1 b0'
|
||||
'b0 98')
|
||||
self.check_case(
|
||||
case.resize((4, 4), Image.BILINEAR),
|
||||
self.make_sample(data, (4, 4)))
|
||||
for mode in ['RGBX', 'RGB', 'La', 'L']:
|
||||
case = self.make_case(mode, (2, 2), 0xe1)
|
||||
case = case.resize((4, 4), Image.BILINEAR)
|
||||
data = ('e1 b0'
|
||||
'b0 98')
|
||||
for channel in case.split():
|
||||
self.check_case(channel, self.make_sample(data, (4, 4)))
|
||||
|
||||
def test_enlarge_bicubic(self):
|
||||
case = self.make_case((4, 4), 0xe1)
|
||||
data = ('e1 e5 ee b9'
|
||||
'e5 e9 f3 bc'
|
||||
'ee f3 fd c1'
|
||||
'b9 bc c1 a2')
|
||||
self.check_case(
|
||||
case.resize((8, 8), Image.BICUBIC),
|
||||
self.make_sample(data, (8, 8)))
|
||||
for mode in ['RGBX', 'RGB', 'La', 'L']:
|
||||
case = self.make_case(mode, (4, 4), 0xe1)
|
||||
case = case.resize((8, 8), Image.BICUBIC)
|
||||
data = ('e1 e5 ee b9'
|
||||
'e5 e9 f3 bc'
|
||||
'ee f3 fd c1'
|
||||
'b9 bc c1 a2')
|
||||
for channel in case.split():
|
||||
self.check_case(channel, self.make_sample(data, (8, 8)))
|
||||
|
||||
def test_enlarge_lanczos(self):
|
||||
case = self.make_case((6, 6), 0xe1)
|
||||
data = ('e1 e0 db ed f5 b8'
|
||||
'e0 df da ec f3 b7'
|
||||
'db db d6 e7 ee b5'
|
||||
'ed ec e6 fb ff bf'
|
||||
'f5 f4 ee ff ff c4'
|
||||
'b8 b7 b4 bf c4 a0')
|
||||
self.check_case(
|
||||
case.resize((12, 12), Image.LANCZOS),
|
||||
self.make_sample(data, (12, 12)))
|
||||
for mode in ['RGBX', 'RGB', 'La', 'L']:
|
||||
case = self.make_case(mode, (6, 6), 0xe1)
|
||||
case = case.resize((12, 12), Image.LANCZOS)
|
||||
data = ('e1 e0 db ed f5 b8'
|
||||
'e0 df da ec f3 b7'
|
||||
'db db d6 e7 ee b5'
|
||||
'ed ec e6 fb ff bf'
|
||||
'f5 f4 ee ff ff c4'
|
||||
'b8 b7 b4 bf c4 a0')
|
||||
for channel in case.split():
|
||||
self.check_case(channel, self.make_sample(data, (12, 12)))
|
||||
|
||||
|
||||
class CoreResampleConsistencyTest(PillowTestCase):
|
||||
|
|
|
@ -91,7 +91,7 @@ ImagingPrecompute(int inSize, int outSize, struct filter *filterp,
|
|||
/* determine support size (length of resampling filter) */
|
||||
support = filterp->support * filterscale;
|
||||
|
||||
/* maximum number of coofs */
|
||||
/* maximum number of coeffs */
|
||||
kmax = (int) ceil(support) * 2 + 1;
|
||||
|
||||
// check for overflow
|
||||
|
@ -103,11 +103,11 @@ ImagingPrecompute(int inSize, int outSize, struct filter *filterp,
|
|||
return 0;
|
||||
|
||||
/* coefficient buffer */
|
||||
kk = calloc(outSize * kmax, sizeof(double));
|
||||
kk = malloc(outSize * kmax * sizeof(double));
|
||||
if ( ! kk)
|
||||
return 0;
|
||||
|
||||
xbounds = calloc(outSize * 2, sizeof(int));
|
||||
xbounds = malloc(outSize * 2 * sizeof(int));
|
||||
if ( ! xbounds) {
|
||||
free(kk);
|
||||
return 0;
|
||||
|
@ -134,6 +134,10 @@ ImagingPrecompute(int inSize, int outSize, struct filter *filterp,
|
|||
if (ww != 0.0)
|
||||
k[x] /= ww;
|
||||
}
|
||||
// Remaining values should stay empty if they are used despite of xmax.
|
||||
for (; x < kmax; x++) {
|
||||
k[x] = 0;
|
||||
}
|
||||
xbounds[xx * 2 + 0] = xmin;
|
||||
xbounds[xx * 2 + 1] = xmax;
|
||||
}
|
||||
|
@ -160,7 +164,7 @@ ImagingResampleHorizontal_8bpc(Imaging imIn, int xsize, struct filter *filterp)
|
|||
return (Imaging) ImagingError_MemoryError();
|
||||
}
|
||||
|
||||
kk = calloc(xsize * kmax, sizeof(int));
|
||||
kk = malloc(xsize * kmax * sizeof(int));
|
||||
if ( ! kk) {
|
||||
free(xbounds);
|
||||
free(prekk);
|
||||
|
@ -200,13 +204,13 @@ ImagingResampleHorizontal_8bpc(Imaging imIn, int xsize, struct filter *filterp)
|
|||
xmin = xbounds[xx * 2 + 0];
|
||||
xmax = xbounds[xx * 2 + 1];
|
||||
k = &kk[xx * kmax];
|
||||
ss0 = ss1 = 1 << (PRECISION_BITS -1);
|
||||
ss0 = ss3 = 1 << (PRECISION_BITS -1);
|
||||
for (x = 0; x < xmax; x++) {
|
||||
ss0 += ((UINT8) imIn->image[yy][(x + xmin)*4 + 0]) * k[x];
|
||||
ss1 += ((UINT8) imIn->image[yy][(x + xmin)*4 + 3]) * k[x];
|
||||
ss3 += ((UINT8) imIn->image[yy][(x + xmin)*4 + 3]) * k[x];
|
||||
}
|
||||
imOut->image[yy][xx*4 + 0] = clip8(ss0);
|
||||
imOut->image[yy][xx*4 + 3] = clip8(ss1);
|
||||
imOut->image[yy][xx*4 + 3] = clip8(ss3);
|
||||
}
|
||||
}
|
||||
} else if (imIn->bands == 3) {
|
||||
|
@ -255,6 +259,118 @@ ImagingResampleHorizontal_8bpc(Imaging imIn, int xsize, struct filter *filterp)
|
|||
}
|
||||
|
||||
|
||||
Imaging
|
||||
ImagingResampleVertical_8bpc(Imaging imIn, int ysize, struct filter *filterp)
|
||||
{
|
||||
ImagingSectionCookie cookie;
|
||||
Imaging imOut;
|
||||
int ss0, ss1, ss2, ss3;
|
||||
int xx, yy, y, kmax, ymin, ymax;
|
||||
int *xbounds;
|
||||
int *k, *kk;
|
||||
double *prekk;
|
||||
|
||||
|
||||
kmax = ImagingPrecompute(imIn->ysize, ysize, filterp, &xbounds, &prekk);
|
||||
if ( ! kmax) {
|
||||
return (Imaging) ImagingError_MemoryError();
|
||||
}
|
||||
|
||||
kk = malloc(ysize * kmax * sizeof(int));
|
||||
if ( ! kk) {
|
||||
free(xbounds);
|
||||
free(prekk);
|
||||
return (Imaging) ImagingError_MemoryError();
|
||||
}
|
||||
|
||||
for (y = 0; y < ysize * kmax; y++) {
|
||||
kk[y] = (int) (0.5 + prekk[y] * (1 << PRECISION_BITS));
|
||||
}
|
||||
|
||||
free(prekk);
|
||||
|
||||
imOut = ImagingNew(imIn->mode, imIn->xsize, ysize);
|
||||
if ( ! imOut) {
|
||||
free(kk);
|
||||
free(xbounds);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ImagingSectionEnter(&cookie);
|
||||
if (imIn->image8) {
|
||||
for (yy = 0; yy < ysize; yy++) {
|
||||
k = &kk[yy * kmax];
|
||||
ymin = xbounds[yy * 2 + 0];
|
||||
ymax = xbounds[yy * 2 + 1];
|
||||
for (xx = 0; xx < imOut->xsize; xx++) {
|
||||
ss0 = 1 << (PRECISION_BITS -1);
|
||||
for (y = 0; y < ymax; y++)
|
||||
ss0 += ((UINT8) imIn->image8[y + ymin][xx]) * k[y];
|
||||
imOut->image8[yy][xx] = clip8(ss0);
|
||||
}
|
||||
}
|
||||
} else if (imIn->type == IMAGING_TYPE_UINT8) {
|
||||
if (imIn->bands == 2) {
|
||||
for (yy = 0; yy < ysize; yy++) {
|
||||
k = &kk[yy * kmax];
|
||||
ymin = xbounds[yy * 2 + 0];
|
||||
ymax = xbounds[yy * 2 + 1];
|
||||
for (xx = 0; xx < imOut->xsize; xx++) {
|
||||
ss0 = ss3 = 1 << (PRECISION_BITS -1);
|
||||
for (y = 0; y < ymax; y++) {
|
||||
ss0 += ((UINT8) imIn->image[y + ymin][xx*4 + 0]) * k[y];
|
||||
ss3 += ((UINT8) imIn->image[y + ymin][xx*4 + 3]) * k[y];
|
||||
}
|
||||
imOut->image[yy][xx*4 + 0] = clip8(ss0);
|
||||
imOut->image[yy][xx*4 + 3] = clip8(ss3);
|
||||
}
|
||||
}
|
||||
} else if (imIn->bands == 3) {
|
||||
for (yy = 0; yy < ysize; yy++) {
|
||||
k = &kk[yy * kmax];
|
||||
ymin = xbounds[yy * 2 + 0];
|
||||
ymax = xbounds[yy * 2 + 1];
|
||||
for (xx = 0; xx < imOut->xsize; xx++) {
|
||||
ss0 = ss1 = ss2 = 1 << (PRECISION_BITS -1);
|
||||
for (y = 0; y < ymax; y++) {
|
||||
ss0 += ((UINT8) imIn->image[y + ymin][xx*4 + 0]) * k[y];
|
||||
ss1 += ((UINT8) imIn->image[y + ymin][xx*4 + 1]) * k[y];
|
||||
ss2 += ((UINT8) imIn->image[y + ymin][xx*4 + 2]) * k[y];
|
||||
}
|
||||
imOut->image[yy][xx*4 + 0] = clip8(ss0);
|
||||
imOut->image[yy][xx*4 + 1] = clip8(ss1);
|
||||
imOut->image[yy][xx*4 + 2] = clip8(ss2);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (yy = 0; yy < ysize; yy++) {
|
||||
k = &kk[yy * kmax];
|
||||
ymin = xbounds[yy * 2 + 0];
|
||||
ymax = xbounds[yy * 2 + 1];
|
||||
for (xx = 0; xx < imOut->xsize; xx++) {
|
||||
ss0 = ss1 = ss2 = ss3 = 1 << (PRECISION_BITS -1);
|
||||
for (y = 0; y < ymax; y++) {
|
||||
ss0 += ((UINT8) imIn->image[y + ymin][xx*4 + 0]) * k[y];
|
||||
ss1 += ((UINT8) imIn->image[y + ymin][xx*4 + 1]) * k[y];
|
||||
ss2 += ((UINT8) imIn->image[y + ymin][xx*4 + 2]) * k[y];
|
||||
ss3 += ((UINT8) imIn->image[y + ymin][xx*4 + 3]) * k[y];
|
||||
}
|
||||
imOut->image[yy][xx*4 + 0] = clip8(ss0);
|
||||
imOut->image[yy][xx*4 + 1] = clip8(ss1);
|
||||
imOut->image[yy][xx*4 + 2] = clip8(ss2);
|
||||
imOut->image[yy][xx*4 + 3] = clip8(ss3);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ImagingSectionLeave(&cookie);
|
||||
free(kk);
|
||||
free(xbounds);
|
||||
return imOut;
|
||||
}
|
||||
|
||||
|
||||
Imaging
|
||||
ImagingResampleHorizontal_32bpc(Imaging imIn, int xsize, struct filter *filterp)
|
||||
{
|
||||
|
@ -315,13 +431,74 @@ ImagingResampleHorizontal_32bpc(Imaging imIn, int xsize, struct filter *filterp)
|
|||
}
|
||||
|
||||
|
||||
Imaging
|
||||
ImagingResampleVertical_32bpc(Imaging imIn, int ysize, struct filter *filterp)
|
||||
{
|
||||
ImagingSectionCookie cookie;
|
||||
Imaging imOut;
|
||||
double ss;
|
||||
int xx, yy, y, kmax, ymin, ymax;
|
||||
int *xbounds;
|
||||
double *k, *kk;
|
||||
|
||||
kmax = ImagingPrecompute(imIn->ysize, ysize, filterp, &xbounds, &kk);
|
||||
if ( ! kmax) {
|
||||
return (Imaging) ImagingError_MemoryError();
|
||||
}
|
||||
|
||||
imOut = ImagingNew(imIn->mode, imIn->xsize, ysize);
|
||||
if ( ! imOut) {
|
||||
free(kk);
|
||||
free(xbounds);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ImagingSectionEnter(&cookie);
|
||||
switch(imIn->type) {
|
||||
case IMAGING_TYPE_INT32:
|
||||
for (yy = 0; yy < ysize; yy++) {
|
||||
ymin = xbounds[yy * 2 + 0];
|
||||
ymax = xbounds[yy * 2 + 1];
|
||||
k = &kk[yy * kmax];
|
||||
for (xx = 0; xx < imOut->xsize; xx++) {
|
||||
ss = 0.0;
|
||||
for (y = 0; y < ymax; y++)
|
||||
ss += IMAGING_PIXEL_I(imIn, xx, y + ymin) * k[y];
|
||||
IMAGING_PIXEL_I(imOut, xx, yy) = ROUND_UP(ss);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case IMAGING_TYPE_FLOAT32:
|
||||
for (yy = 0; yy < ysize; yy++) {
|
||||
ymin = xbounds[yy * 2 + 0];
|
||||
ymax = xbounds[yy * 2 + 1];
|
||||
k = &kk[yy * kmax];
|
||||
for (xx = 0; xx < imOut->xsize; xx++) {
|
||||
ss = 0.0;
|
||||
for (y = 0; y < ymax; y++)
|
||||
ss += IMAGING_PIXEL_F(imIn, xx, y + ymin) * k[y];
|
||||
IMAGING_PIXEL_F(imOut, xx, yy) = ss;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
ImagingSectionLeave(&cookie);
|
||||
free(kk);
|
||||
free(xbounds);
|
||||
return imOut;
|
||||
}
|
||||
|
||||
|
||||
Imaging
|
||||
ImagingResample(Imaging imIn, int xsize, int ysize, int filter)
|
||||
{
|
||||
Imaging imTemp1, imTemp2, imTemp3;
|
||||
Imaging imTemp;
|
||||
Imaging imOut;
|
||||
struct filter *filterp;
|
||||
Imaging (*ResampleHorizontal)(Imaging imIn, int xsize, struct filter *filterp);
|
||||
Imaging (*ResampleVertical)(Imaging imIn, int xsize, struct filter *filterp);
|
||||
|
||||
if (strcmp(imIn->mode, "P") == 0 || strcmp(imIn->mode, "1") == 0)
|
||||
return (Imaging) ImagingError_ModeError();
|
||||
|
@ -330,14 +507,17 @@ ImagingResample(Imaging imIn, int xsize, int ysize, int filter)
|
|||
return (Imaging) ImagingError_ModeError();
|
||||
} else if (imIn->image8) {
|
||||
ResampleHorizontal = ImagingResampleHorizontal_8bpc;
|
||||
ResampleVertical = ImagingResampleVertical_8bpc;
|
||||
} else {
|
||||
switch(imIn->type) {
|
||||
case IMAGING_TYPE_UINT8:
|
||||
ResampleHorizontal = ImagingResampleHorizontal_8bpc;
|
||||
ResampleVertical = ImagingResampleVertical_8bpc;
|
||||
break;
|
||||
case IMAGING_TYPE_INT32:
|
||||
case IMAGING_TYPE_FLOAT32:
|
||||
ResampleHorizontal = ImagingResampleHorizontal_32bpc;
|
||||
ResampleVertical = ImagingResampleVertical_32bpc;
|
||||
break;
|
||||
default:
|
||||
return (Imaging) ImagingError_ModeError();
|
||||
|
@ -362,25 +542,13 @@ ImagingResample(Imaging imIn, int xsize, int ysize, int filter)
|
|||
}
|
||||
|
||||
/* two-pass resize, first pass */
|
||||
imTemp1 = ResampleHorizontal(imIn, xsize, filterp);
|
||||
if ( ! imTemp1)
|
||||
return NULL;
|
||||
|
||||
/* transpose image once */
|
||||
imTemp2 = ImagingTransposeToNew(imTemp1);
|
||||
ImagingDelete(imTemp1);
|
||||
if ( ! imTemp2)
|
||||
imTemp = ResampleHorizontal(imIn, xsize, filterp);
|
||||
if ( ! imTemp)
|
||||
return NULL;
|
||||
|
||||
/* second pass */
|
||||
imTemp3 = ResampleHorizontal(imTemp2, ysize, filterp);
|
||||
ImagingDelete(imTemp2);
|
||||
if ( ! imTemp3)
|
||||
return NULL;
|
||||
|
||||
/* transpose result */
|
||||
imOut = ImagingTransposeToNew(imTemp3);
|
||||
ImagingDelete(imTemp3);
|
||||
imOut = ResampleVertical(imTemp, ysize, filterp);
|
||||
ImagingDelete(imTemp);
|
||||
if ( ! imOut)
|
||||
return NULL;
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user