update Fill.c functions to handle more pixel sizes

This commit is contained in:
Yay295 2022-08-21 18:41:38 -05:00
parent 31ad2bc133
commit bdd292f2cd
3 changed files with 307 additions and 89 deletions

View File

@ -531,19 +531,42 @@ class TestImage:
px = im.load() px = im.load()
assert px[0, 0] == 5 assert px[0, 0] == 5
def test_linear_gradient_wrong_mode(self): @pytest.mark.parametrize("wrong_mode", [
# Arrange "bad",
wrong_mode = "RGB" "I;16N",
# "LAB",
# Act / Assert "BGR;15",
"BGR;16",
"BGR;24",
"BGR;32",
])
def test_linear_gradient_wrong_mode(self, wrong_mode):
with pytest.raises(ValueError): with pytest.raises(ValueError):
Image.linear_gradient(wrong_mode) Image.linear_gradient(wrong_mode)
def test_linear_gradient(self): @pytest.mark.parametrize("mode,pixel_a,pixel_b", [
("1", 0, 255),
("P", 0, 255),
("PA", (0, 255), (255, 255)),
("L", 0, 255),
("LA", (0, 255), (255, 255)),
("La", (0, 255), (255, 255)),
("F", 0, 255),
("I", 0, 255),
("I;16", 0, 255),
("I;16L", 0, 255),
("I;16B", 0, 255),
("RGB", (0, 0, 0), (255, 255, 255)),
("RGBX", (0, 0, 0, 255), (255, 255, 255, 255)),
("RGBA", (0, 0, 0, 255), (255, 255, 255, 255)),
("RGBa", (0, 0, 0, 255), (255, 255, 255, 255)),
("CMYK", (0, 0, 0, 255), (0, 0, 0, 0)),
("YCbCr", (0, 128, 128), (255, 128, 128)),
("HSV", (0, 0, 0), (0, 0, 255)),
])
def test_linear_gradient(self, mode, pixel_a, pixel_b):
# Arrange # Arrange
target_file = "Tests/images/linear_gradient.png" target_file = "Tests/images/linear_gradient.png"
for mode in ["L", "P", "I", "F"]:
# Act # Act
im = Image.linear_gradient(mode) im = Image.linear_gradient(mode)
@ -551,25 +574,48 @@ class TestImage:
# Assert # Assert
assert im.size == (256, 256) assert im.size == (256, 256)
assert im.mode == mode assert im.mode == mode
assert im.getpixel((0, 0)) == 0 assert im.getpixel((0, 0)) == pixel_a
assert im.getpixel((255, 255)) == 255 assert im.getpixel((255, 255)) == pixel_b
with Image.open(target_file) as target: with Image.open(target_file) as target:
target = target.convert(mode) target = target.convert(mode, dither=0)
assert_image_equal(im, target) assert_image_equal(im, target)
def test_radial_gradient_wrong_mode(self): @pytest.mark.parametrize("wrong_mode", [
# Arrange "bad",
wrong_mode = "RGB" "I;16N",
# "LAB",
# Act / Assert "BGR;15",
"BGR;16",
"BGR;24",
"BGR;32",
])
def test_radial_gradient_wrong_mode(self, wrong_mode):
with pytest.raises(ValueError): with pytest.raises(ValueError):
Image.radial_gradient(wrong_mode) Image.radial_gradient(wrong_mode)
def test_radial_gradient(self): @pytest.mark.parametrize("mode,pixel_a,pixel_b", [
("1", 255, 0),
("P", 255, 0),
("PA", (255, 255), (0, 255)),
("L", 255, 0),
("LA", (255, 255), (0, 255)),
("La", (255, 255), (0, 255)),
("F", 255, 0),
("I", 255, 0),
("I;16", 255, 0),
("I;16L", 255, 0),
("I;16B", 255, 0),
("RGB", (255, 255, 255), (0, 0, 0)),
("RGBX", (255, 255, 255, 255), (0, 0, 0, 255)),
("RGBA", (255, 255, 255, 255), (0, 0, 0, 255)),
("RGBa", (255, 255, 255, 255), (0, 0, 0, 255)),
("CMYK", (0, 0, 0, 0), (0, 0, 0, 255)),
("YCbCr", (255, 128, 128), (0, 128, 128)),
("HSV", (0, 0, 255), (0, 0, 0)),
])
def test_radial_gradient(self, mode, pixel_a, pixel_b):
# Arrange # Arrange
target_file = "Tests/images/radial_gradient.png" target_file = "Tests/images/radial_gradient.png"
for mode in ["L", "P", "I", "F"]:
# Act # Act
im = Image.radial_gradient(mode) im = Image.radial_gradient(mode)
@ -577,10 +623,10 @@ class TestImage:
# Assert # Assert
assert im.size == (256, 256) assert im.size == (256, 256)
assert im.mode == mode assert im.mode == mode
assert im.getpixel((0, 0)) == 255 assert im.getpixel((0, 0)) == pixel_a
assert im.getpixel((128, 128)) == 0 assert im.getpixel((128, 128)) == pixel_b
with Image.open(target_file) as target: with Image.open(target_file) as target:
target = target.convert(mode) target = target.convert(mode, dither=0)
assert_image_equal(im, target) assert_image_equal(im, target)
def test_register_extensions(self): def test_register_extensions(self):

View File

@ -926,10 +926,12 @@ static struct {
{"L", "1", l2bit}, {"L", "1", l2bit},
{"L", "LA", l2la}, {"L", "LA", l2la},
{"L", "La", l2la},
{"L", "I", l2i}, {"L", "I", l2i},
{"L", "F", l2f}, {"L", "F", l2f},
{"L", "RGB", l2rgb}, {"L", "RGB", l2rgb},
{"L", "RGBA", l2rgb}, {"L", "RGBA", l2rgb},
{"L", "RGBa", l2rgb},
{"L", "RGBX", l2rgb}, {"L", "RGBX", l2rgb},
{"L", "CMYK", l2cmyk}, {"L", "CMYK", l2cmyk},
{"L", "YCbCr", l2ycbcr}, {"L", "YCbCr", l2ycbcr},

View File

@ -24,40 +24,45 @@ ImagingFill(Imaging im, const void *colour) {
int x, y; int x, y;
ImagingSectionCookie cookie; ImagingSectionCookie cookie;
if (im->type == IMAGING_TYPE_SPECIAL) { // Check if every byte in the given color is the same.
/* use generic API */ // If they are, we can use memset.
int allSame = 1;
const UINT8 b = *(UINT8 *)colour;
for (x = 1; x < im->pixelsize; ++x) {
if (((UINT8 *)colour)[x] != b) {
allSame = 0;
break;
}
}
ImagingSectionEnter(&cookie);
if (allSame) {
for (y = 0; y < im->ysize; ++y) {
memset(im->image[y], b, im->linesize);
}
} else if (im->type == IMAGING_TYPE_SPECIAL) {
ImagingAccess access = ImagingAccessNew(im); ImagingAccess access = ImagingAccessNew(im);
if (access) { if (access) {
for (y = 0; y < im->ysize; y++) { for (y = 0; y < im->ysize; ++y) {
for (x = 0; x < im->xsize; x++) { for (x = 0; x < im->xsize; ++x) {
access->put_pixel(im, x, y, colour); access->put_pixel(im, x, y, colour);
} }
} }
ImagingAccessDelete(im, access); ImagingAccessDelete(im, access);
} else { } else {
/* wipe the image */ for (y = 0; y < im->ysize; ++y) {
for (y = 0; y < im->ysize; y++) {
memset(im->image[y], 0, im->linesize); memset(im->image[y], 0, im->linesize);
} }
} }
} else { } else {
INT32 c = 0L; for (y = 0; y < im->ysize; ++y) {
ImagingSectionEnter(&cookie); UINT8 *out = (UINT8 *)im->image[y];
memcpy(&c, colour, im->pixelsize); for (x = 0; x < im->xsize; ++x) {
if (im->image32 && c != 0L) { memcpy(out + x * im->pixelsize, colour, im->pixelsize);
for (y = 0; y < im->ysize; y++) {
for (x = 0; x < im->xsize; x++) {
im->image32[y][x] = c;
} }
} }
} else {
unsigned char cc = (unsigned char)*(UINT8 *)colour;
for (y = 0; y < im->ysize; y++) {
memset(im->image[y], cc, im->linesize);
}
} }
ImagingSectionLeave(&cookie); ImagingSectionLeave(&cookie);
}
return im; return im;
} }
@ -65,70 +70,235 @@ ImagingFill(Imaging im, const void *colour) {
Imaging Imaging
ImagingFillLinearGradient(const char *mode) { ImagingFillLinearGradient(const char *mode) {
Imaging im; Imaging im;
int y;
if (strlen(mode) != 1) { if (strcmp(mode, "P") == 0 || strcmp(mode, "PA") == 0) {
return (Imaging)ImagingError_ModeError(); Imaging imTemp = ImagingFillLinearGradient("L");
im = ImagingConvert(imTemp, mode, NULL, 0);
ImagingDelete(imTemp);
return im;
} }
im = ImagingNewDirty(mode, 256, 256); const int size = 256;
im = ImagingNewDirty(mode, size, size);
if (!im) { if (!im) {
return NULL; return NULL;
} }
if (im->image8) { int y, x;
for (y = 0; y < 256; y++) { switch (im->type) {
memset(im->image8[y], (unsigned char)y, 256); case IMAGING_TYPE_UINT8:
if (strcmp(mode, "1") == 0) {
for (y = 0; y < size; ++y) {
memset(im->image[y], y < 128 ? 0 : 255, size);
}
} else if (strcmp(mode, "LA") == 0 || strcmp(mode, "La") == 0) {
for (y = 0; y < size; ++y) {
UINT8 *out = (UINT8 *)im->image[y];
for (x = 0; x < size; ++x) {
*out++ = y;
*out++ = 255;
}
}
} else if (strcmp(mode, "RGBA") == 0 || strcmp(mode, "RGBa") == 0 || strcmp(mode, "RGBX") == 0) {
for (y = 0; y < size; ++y) {
UINT8 *out = (UINT8 *)im->image[y];
for (x = 0; x < size; ++x) {
memset(out + x * 4, y, 3);
out[x * 4 + 3] = 255;
}
}
} else if (strcmp(mode, "CMYK") == 0) {
for (y = 0; y < size; ++y) {
UINT8 *out = (UINT8 *)im->image[y];
for (x = 0; x < size; ++x) {
memset(out + x * 4, 0, 3);
out[x * 4 + 3] = ~(UINT8)y;
}
}
} else if (strcmp(mode, "YCbCr") == 0) {
for (y = 0; y < size; ++y) {
UINT8 *out = (UINT8 *)im->image[y];
for (x = 0; x < size; ++x) {
*out++ = y;
*out++ = 128;
*out++ = 128;
*out++ = 255;
}
}
} else if (strcmp(mode, "HSV") == 0) {
for (y = 0; y < size; ++y) {
UINT8 *out = (UINT8 *)im->image[y];
for (x = 0; x < size; ++x) {
*out++ = 0;
*out++ = 0;
*out++ = y;
*out++ = 255;
}
} }
} else { } else {
int x; for (y = 0; y < size; ++y) {
for (y = 0; y < 256; y++) { memset(im->image[y], y, im->linesize);
for (x = 0; x < 256; x++) { }
if (im->type == IMAGING_TYPE_FLOAT32) { }
IMAGING_PIXEL_FLOAT32(im, x, y) = y; break;
} else { case IMAGING_TYPE_INT32:
for (y = 0; y < size; ++y) {
for (x = 0; x < size; ++x) {
IMAGING_PIXEL_INT32(im, x, y) = y; IMAGING_PIXEL_INT32(im, x, y) = y;
} }
} }
break;
case IMAGING_TYPE_FLOAT32:
for (y = 0; y < size; ++y) {
for (x = 0; x < size; ++x) {
IMAGING_PIXEL_FLOAT32(im, x, y) = y;
}
}
break;
case IMAGING_TYPE_SPECIAL: {
ImagingAccess access = ImagingAccessNew(im);
if (access) {
for (y = 0; y < im->ysize; ++y) {
for (x = 0; x < im->xsize; ++x) {
access->put_pixel(im, x, y, &y);
}
}
ImagingAccessDelete(im, access);
} else {
ImagingDelete(im);
return (Imaging)ImagingError_ModeError();
}
break;
} }
} }
return im; return im;
} }
#define CALC_RADIAL_COLOUR(c, x, y) c = ((int)sqrt(\
(double)((x - 128) * (x - 128) + (y - 128) * (y - 128)) * 2.0));\
if (c >= 255) {c = 255;}
Imaging Imaging
ImagingFillRadialGradient(const char *mode) { ImagingFillRadialGradient(const char *mode) {
Imaging im; Imaging im;
int x, y;
int d;
if (strlen(mode) != 1) { if (strcmp(mode, "P") == 0 || strcmp(mode, "PA") == 0) {
return (Imaging)ImagingError_ModeError(); Imaging imTemp = ImagingFillRadialGradient("L");
im = ImagingConvert(imTemp, mode, NULL, 0);
ImagingDelete(imTemp);
return im;
} }
im = ImagingNewDirty(mode, 256, 256); const int size = 256;
im = ImagingNewDirty(mode, size, size);
if (!im) { if (!im) {
return NULL; return NULL;
} }
for (y = 0; y < 256; y++) { int y, x, c;
for (x = 0; x < 256; x++) { switch (im->type) {
d = (int)sqrt( case IMAGING_TYPE_UINT8:
(double)((x - 128) * (x - 128) + (y - 128) * (y - 128)) * 2.0); if (strcmp(mode, "1") == 0) {
if (d >= 255) { for (y = 0; y < size; ++y) {
d = 255; UINT8 *out = (UINT8 *)im->image[y];
for (x = 0; x < size; ++x) {
CALC_RADIAL_COLOUR(c, x, y)
out[x] = c < 128 ? 0 : 255;
}
}
} else if (strcmp(mode, "LA") == 0 || strcmp(mode, "La") == 0) {
for (y = 0; y < size; ++y) {
UINT8 *out = (UINT8 *)im->image[y];
for (x = 0; x < size; ++x) {
CALC_RADIAL_COLOUR(c, x, y)
*out++ = c;
*out++ = 255;
}
}
} else if (strcmp(mode, "RGBA") == 0 || strcmp(mode, "RGBa") == 0 || strcmp(mode, "RGBX") == 0) {
for (y = 0; y < size; ++y) {
UINT8 *out = (UINT8 *)im->image[y];
for (x = 0; x < size; ++x) {
CALC_RADIAL_COLOUR(c, x, y)
memset(out + x * 4, c, 3);
out[x * 4 + 3] = 255;
}
}
} else if (strcmp(mode, "CMYK") == 0) {
for (y = 0; y < size; ++y) {
UINT8 *out = (UINT8 *)im->image[y];
for (x = 0; x < size; ++x) {
CALC_RADIAL_COLOUR(c, x, y)
memset(out + x * 4, 0, 3);
out[x * 4 + 3] = ~(UINT8)c;
}
}
} else if (strcmp(mode, "YCbCr") == 0) {
for (y = 0; y < size; ++y) {
UINT8 *out = (UINT8 *)im->image[y];
for (x = 0; x < size; ++x) {
CALC_RADIAL_COLOUR(c, x, y)
*out++ = c;
*out++ = 128;
*out++ = 128;
*out++ = 255;
}
}
} else if (strcmp(mode, "HSV") == 0) {
for (y = 0; y < size; ++y) {
UINT8 *out = (UINT8 *)im->image[y];
for (x = 0; x < size; ++x) {
CALC_RADIAL_COLOUR(c, x, y)
*out++ = 0;
*out++ = 0;
*out++ = c;
*out++ = 255;
}
} }
if (im->image8) {
im->image8[y][x] = d;
} else { } else {
if (im->type == IMAGING_TYPE_FLOAT32) { for (y = 0; y < size; ++y) {
IMAGING_PIXEL_FLOAT32(im, x, y) = d; UINT8 *out = (UINT8 *)im->image[y];
for (x = 0; x < size; ++x) {
CALC_RADIAL_COLOUR(c, x, y)
memset(out + x * im->pixelsize, c, im->pixelsize);
}
}
}
break;
case IMAGING_TYPE_INT32:
for (y = 0; y < size; ++y) {
for (x = 0; x < size; ++x) {
CALC_RADIAL_COLOUR(c, x, y)
IMAGING_PIXEL_INT32(im, x, y) = c;
}
}
break;
case IMAGING_TYPE_FLOAT32:
for (y = 0; y < size; ++y) {
for (x = 0; x < size; ++x) {
CALC_RADIAL_COLOUR(c, x, y)
IMAGING_PIXEL_FLOAT32(im, x, y) = c;
}
}
break;
case IMAGING_TYPE_SPECIAL: {
ImagingAccess access = ImagingAccessNew(im);
if (access) {
for (y = 0; y < im->ysize; ++y) {
for (x = 0; x < im->xsize; ++x) {
CALC_RADIAL_COLOUR(c, x, y)
access->put_pixel(im, x, y, &c);
}
}
ImagingAccessDelete(im, access);
} else { } else {
IMAGING_PIXEL_INT32(im, x, y) = d; ImagingDelete(im);
} return (Imaging)ImagingError_ModeError();
} }
break;
} }
} }
return im; return im;
} }
#undef CALC_RADIAL_COLOUR