F mode support

This commit is contained in:
Alexander 2019-12-01 22:28:16 +03:00
parent d970a39840
commit a576b14056
2 changed files with 848 additions and 846 deletions

View File

@ -46,8 +46,10 @@ class TestImageReduce(PillowTestCase):
im.reduce(3)
def get_image(self, mode):
mode_info = ImageMode.getmode(mode)
if mode_info.basetype == 'L':
bands = [self.gradients_image]
for _ in ImageMode.getmode(mode).bands[1:]:
for _ in mode_info.bands[1:]:
# rotate previous image
band = bands[-1].transpose(Image.ROTATE_90)
bands.append(band)
@ -56,6 +58,9 @@ class TestImageReduce(PillowTestCase):
if mode.endswith('A'):
bands[-1] = bands[-1].point(lambda x: int(85 + x / 1.5))
return Image.merge(mode, bands)
else:
assert len(mode_info.bands) == 1
return self.gradients_image.convert(mode)
def compare_reduce_with_reference(self, im, factor, average_diff=0.4, max_diff=1):
"""Image.reduce() should look very similar to Image.resize(BOX).
@ -172,7 +177,7 @@ class TestImageReduce(PillowTestCase):
for factor in self.remarkable_factors:
self.compare_reduce_with_reference(im, factor)
def test_mode_CMYK(self):
im = self.get_image("CMYK")
def test_mode_F(self):
im = self.get_image("F")
for factor in self.remarkable_factors:
self.compare_reduce_with_reference(im, factor)

View File

@ -55,8 +55,6 @@ ImagingReduceNxN(Imaging imOut, Imaging imIn, int xscale, int yscale)
}
}
} else {
switch(imIn->type) {
case IMAGING_TYPE_UINT8:
for (y = 0; y < imIn->ysize / yscale; y++) {
if (imIn->bands == 2) {
for (x = 0; x < imIn->xsize / xscale; x++) {
@ -189,14 +187,6 @@ ImagingReduceNxN(Imaging imOut, Imaging imIn, int xscale, int yscale)
}
}
}
break;
case IMAGING_TYPE_INT32:
break;
case IMAGING_TYPE_FLOAT32:
break;
}
}
}
@ -228,8 +218,6 @@ ImagingReduce1xN(Imaging imOut, Imaging imIn, int yscale)
}
}
} else {
switch(imIn->type) {
case IMAGING_TYPE_UINT8:
for (y = 0; y < imIn->ysize / yscale; y++) {
if (imIn->bands == 2) {
for (x = 0; x < imIn->xsize / xscale; x++) {
@ -299,14 +287,6 @@ ImagingReduce1xN(Imaging imOut, Imaging imIn, int yscale)
}
}
}
break;
case IMAGING_TYPE_INT32:
break;
case IMAGING_TYPE_FLOAT32:
break;
}
}
}
@ -338,8 +318,6 @@ ImagingReduceNx1(Imaging imOut, Imaging imIn, int xscale)
}
}
} else {
switch(imIn->type) {
case IMAGING_TYPE_UINT8:
for (y = 0; y < imIn->ysize / yscale; y++) {
UINT8 *line = (UINT8 *)imIn->image[y];
if (imIn->bands == 2) {
@ -407,14 +385,6 @@ ImagingReduceNx1(Imaging imOut, Imaging imIn, int xscale)
}
}
}
break;
case IMAGING_TYPE_INT32:
break;
case IMAGING_TYPE_FLOAT32:
break;
}
}
}
@ -439,8 +409,6 @@ ImagingReduce2x1(Imaging imOut, Imaging imIn)
}
}
} else {
switch(imIn->type) {
case IMAGING_TYPE_UINT8:
for (y = 0; y < imIn->ysize / yscale; y++) {
UINT8 *line0 = (UINT8 *)imIn->image[y*yscale + 0];
if (imIn->bands == 2) {
@ -475,14 +443,6 @@ ImagingReduce2x1(Imaging imOut, Imaging imIn)
}
}
}
break;
case IMAGING_TYPE_INT32:
break;
case IMAGING_TYPE_FLOAT32:
break;
}
}
}
@ -509,8 +469,6 @@ ImagingReduce1x2(Imaging imOut, Imaging imIn)
}
}
} else {
switch(imIn->type) {
case IMAGING_TYPE_UINT8:
for (y = 0; y < imIn->ysize / yscale; y++) {
UINT8 *line0 = (UINT8 *)imIn->image[y*yscale + 0];
UINT8 *line1 = (UINT8 *)imIn->image[y*yscale + 1];
@ -555,14 +513,6 @@ ImagingReduce1x2(Imaging imOut, Imaging imIn)
}
}
}
break;
case IMAGING_TYPE_INT32:
break;
case IMAGING_TYPE_FLOAT32:
break;
}
}
}
@ -589,8 +539,6 @@ ImagingReduce2x2(Imaging imOut, Imaging imIn)
}
}
} else {
switch(imIn->type) {
case IMAGING_TYPE_UINT8:
for (y = 0; y < imIn->ysize / yscale; y++) {
UINT8 *line0 = (UINT8 *)imIn->image[y*yscale + 0];
UINT8 *line1 = (UINT8 *)imIn->image[y*yscale + 1];
@ -635,14 +583,6 @@ ImagingReduce2x2(Imaging imOut, Imaging imIn)
}
}
}
break;
case IMAGING_TYPE_INT32:
break;
case IMAGING_TYPE_FLOAT32:
break;
}
}
}
@ -668,8 +608,6 @@ ImagingReduce3x1(Imaging imOut, Imaging imIn)
}
}
} else {
switch(imIn->type) {
case IMAGING_TYPE_UINT8:
for (y = 0; y < imIn->ysize / yscale; y++) {
UINT8 *line0 = (UINT8 *)imIn->image[y*yscale + 0];
if (imIn->bands == 2) {
@ -707,14 +645,6 @@ ImagingReduce3x1(Imaging imOut, Imaging imIn)
}
}
}
break;
case IMAGING_TYPE_INT32:
break;
case IMAGING_TYPE_FLOAT32:
break;
}
}
}
@ -744,8 +674,6 @@ ImagingReduce1x3(Imaging imOut, Imaging imIn)
}
}
} else {
switch(imIn->type) {
case IMAGING_TYPE_UINT8:
for (y = 0; y < imIn->ysize / yscale; y++) {
UINT8 *line0 = (UINT8 *)imIn->image[y*yscale + 0];
UINT8 *line1 = (UINT8 *)imIn->image[y*yscale + 1];
@ -803,14 +731,6 @@ ImagingReduce1x3(Imaging imOut, Imaging imIn)
}
}
}
break;
case IMAGING_TYPE_INT32:
break;
case IMAGING_TYPE_FLOAT32:
break;
}
}
}
@ -840,8 +760,6 @@ ImagingReduce3x3(Imaging imOut, Imaging imIn)
}
}
} else {
switch(imIn->type) {
case IMAGING_TYPE_UINT8:
for (y = 0; y < imIn->ysize / yscale; y++) {
UINT8 *line0 = (UINT8 *)imIn->image[y*yscale + 0];
UINT8 *line1 = (UINT8 *)imIn->image[y*yscale + 1];
@ -899,14 +817,6 @@ ImagingReduce3x3(Imaging imOut, Imaging imIn)
}
}
}
break;
case IMAGING_TYPE_INT32:
break;
case IMAGING_TYPE_FLOAT32:
break;
}
}
}
@ -936,8 +846,6 @@ ImagingReduce4x4(Imaging imOut, Imaging imIn)
}
}
} else {
switch(imIn->type) {
case IMAGING_TYPE_UINT8:
for (y = 0; y < imIn->ysize / yscale; y++) {
UINT8 *line0 = (UINT8 *)imIn->image[y*yscale + 0];
UINT8 *line1 = (UINT8 *)imIn->image[y*yscale + 1];
@ -1002,14 +910,6 @@ ImagingReduce4x4(Imaging imOut, Imaging imIn)
}
}
}
break;
case IMAGING_TYPE_INT32:
break;
case IMAGING_TYPE_FLOAT32:
break;
}
}
}
@ -1043,8 +943,6 @@ ImagingReduce5x5(Imaging imOut, Imaging imIn)
}
}
} else {
switch(imIn->type) {
case IMAGING_TYPE_UINT8:
for (y = 0; y < imIn->ysize / yscale; y++) {
UINT8 *line0 = (UINT8 *)imIn->image[y*yscale + 0];
UINT8 *line1 = (UINT8 *)imIn->image[y*yscale + 1];
@ -1122,14 +1020,6 @@ ImagingReduce5x5(Imaging imOut, Imaging imIn)
}
}
}
break;
case IMAGING_TYPE_INT32:
break;
case IMAGING_TYPE_FLOAT32:
break;
}
}
}
@ -1191,8 +1081,6 @@ ImagingReduceCorners(Imaging imOut, Imaging imIn, int xscale, int yscale)
imOut->image8[y][x] = (ss * multiplier) >> 24;
}
} else {
switch(imIn->type) {
case IMAGING_TYPE_UINT8:
if (imIn->xsize % xscale) {
int scale = (imIn->xsize % xscale) * yscale;
UINT32 multiplier = division_UINT32(scale, 8);
@ -1262,14 +1150,112 @@ ImagingReduceCorners(Imaging imOut, Imaging imIn, int xscale, int yscale)
(ss2 * multiplier) >> 24, (ss3 * multiplier) >> 24);
memcpy(imOut->image[y] + x * sizeof(v), &v, sizeof(v));
}
break;
}
}
void
ImagingReduceNxN_32bpc(Imaging imOut, Imaging imIn, int xscale, int yscale)
{
/* The most general implementation for any xscale and yscale
*/
int x, y, xx, yy, xi;
double multiplier = 1.0 / (yscale * xscale);
switch(imIn->type) {
case IMAGING_TYPE_INT32:
break;
case IMAGING_TYPE_FLOAT32:
for (y = 0; y < imIn->ysize / yscale; y++) {
for (x = 0; x < imIn->xsize / xscale; x++) {
double ss = 0;
for (yy = y*yscale; yy < y*yscale + yscale - 1; yy += 2) {
float *line0 = (float *)imIn->image[yy];
float *line1 = (float *)imIn->image[yy + 1];
for (xi = 0; xi < xscale - 1; xi += 2) {
xx = x*xscale + xi;
ss += line0[xx + 0] + line0[xx + 1] +
line1[xx + 0] + line1[xx + 1];
}
if (xscale & 0x01) {
xx = x*xscale + xi;
ss += line0[xx + 0] + line1[xx + 0];
}
}
if (yscale & 0x01) {
float *line = (float *)imIn->image[yy];
for (xi = 0; xi < xscale - 1; xi += 2) {
xx = x*xscale + xi;
ss += line[xx + 0] + line[xx + 1];
}
if (xscale & 0x01) {
xx = x*xscale + xi;
ss += line[xx + 0];
}
}
IMAGING_PIXEL_F(imOut, x, y) = ss * multiplier;
}
}
break;
}
}
void
ImagingReduceCorners_32bpc(Imaging imOut, Imaging imIn, int xscale, int yscale)
{
/* Fill the last row and the last column for any xscale and yscale.
*/
int x, y, xx, yy;
switch(imIn->type) {
case IMAGING_TYPE_INT32:
break;
case IMAGING_TYPE_FLOAT32:
if (imIn->xsize % xscale) {
double multiplier = 1.0 / ((imIn->xsize % xscale) * yscale);
for (y = 0; y < imIn->ysize / yscale; y++) {
double ss = 0;
x = imIn->xsize / xscale;
for (yy = y*yscale; yy < y*yscale + yscale; yy++) {
float *line = (float *)imIn->image[yy];
for (xx = x*xscale; xx < imIn->xsize; xx++) {
ss += line[xx + 0];
}
}
IMAGING_PIXEL_F(imOut, x, y) = ss * multiplier;
}
}
if (imIn->ysize % yscale) {
double multiplier = 1.0 / (xscale * (imIn->ysize % yscale));
y = imIn->ysize / yscale;
for (x = 0; x < imIn->xsize / xscale; x++) {
double ss = 0;
for (yy = y*yscale; yy < imIn->ysize; yy++) {
float *line = (float *)imIn->image[yy];
for (xx = x*xscale; xx < x*xscale + xscale; xx++) {
ss += line[xx + 0];
}
}
IMAGING_PIXEL_F(imOut, x, y) = ss * multiplier;
}
}
if (imIn->xsize % xscale && imIn->ysize % yscale) {
double multiplier = 1.0 / ((imIn->xsize % xscale) * (imIn->ysize % yscale));
double ss = 0;
x = imIn->xsize / xscale;
y = imIn->ysize / yscale;
for (yy = y*yscale; yy < imIn->ysize; yy++) {
float *line = (float *)imIn->image[yy];
for (xx = x*xscale; xx < imIn->xsize; xx++) {
ss += line[xx + 0];
}
}
IMAGING_PIXEL_F(imOut, x, y) = ss * multiplier;
}
break;
}
}
@ -1295,6 +1281,8 @@ ImagingReduce(Imaging imIn, int xscale, int yscale)
ImagingSectionEnter(&cookie);
switch(imIn->type) {
case IMAGING_TYPE_UINT8:
if (xscale == 1) {
if (yscale == 2) {
ImagingReduce1x2(imOut, imIn);
@ -1326,6 +1314,15 @@ ImagingReduce(Imaging imIn, int xscale, int yscale)
}
ImagingReduceCorners(imOut, imIn, xscale, yscale);
break;
case IMAGING_TYPE_INT32:
case IMAGING_TYPE_FLOAT32:
ImagingReduceNxN_32bpc(imOut, imIn, xscale, yscale);
ImagingReduceCorners_32bpc(imOut, imIn, xscale, yscale);
break;
}
ImagingSectionLeave(&cookie);