mirror of
https://github.com/python-pillow/Pillow.git
synced 2025-06-03 04:33:31 +03:00
Added DXT3 saving
This commit is contained in:
parent
9f619b814f
commit
f1a61a1e76
|
@ -436,6 +436,29 @@ def test_save_dxt1(tmp_path: Path) -> None:
|
||||||
assert reloaded.getpixel((0, 0)) == (0, 0, 0, 0)
|
assert reloaded.getpixel((0, 0)) == (0, 0, 0, 0)
|
||||||
|
|
||||||
|
|
||||||
|
def test_save_dxt3(tmp_path: Path) -> None:
|
||||||
|
# RGB
|
||||||
|
out = str(tmp_path / "temp.dds")
|
||||||
|
with Image.open(TEST_FILE_DXT3) as im:
|
||||||
|
im_rgb = im.convert("RGB")
|
||||||
|
im_rgb.save(out, pixel_format="DXT3")
|
||||||
|
assert_image_similar_tofile(im_rgb.convert("RGBA"), out, 1.26)
|
||||||
|
|
||||||
|
# RGBA
|
||||||
|
im.save(out, pixel_format="DXT3")
|
||||||
|
assert_image_similar_tofile(im, out, 3.81)
|
||||||
|
|
||||||
|
# L
|
||||||
|
im_l = im.convert("L")
|
||||||
|
im_l.save(out, pixel_format="DXT3")
|
||||||
|
assert_image_similar_tofile(im_l.convert("RGBA"), out, 5.89)
|
||||||
|
|
||||||
|
# LA
|
||||||
|
im_la = im.convert("LA")
|
||||||
|
im_la.save(out, pixel_format="DXT3")
|
||||||
|
assert_image_similar_tofile(im_la.convert("RGBA"), out, 8.44)
|
||||||
|
|
||||||
|
|
||||||
def test_save_dxt5(tmp_path: Path) -> None:
|
def test_save_dxt5(tmp_path: Path) -> None:
|
||||||
# RGB
|
# RGB
|
||||||
out = str(tmp_path / "temp.dds")
|
out = str(tmp_path / "temp.dds")
|
||||||
|
|
|
@ -525,18 +525,24 @@ def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None:
|
||||||
flags = DDSD.CAPS | DDSD.HEIGHT | DDSD.WIDTH | DDSD.PIXELFORMAT
|
flags = DDSD.CAPS | DDSD.HEIGHT | DDSD.WIDTH | DDSD.PIXELFORMAT
|
||||||
bitcount = len(im.getbands()) * 8
|
bitcount = len(im.getbands()) * 8
|
||||||
pixel_format = im.encoderinfo.get("pixel_format")
|
pixel_format = im.encoderinfo.get("pixel_format")
|
||||||
if pixel_format in ("DXT1", "BC3", "DXT5"):
|
args: tuple[int] | str
|
||||||
|
if pixel_format in ("DXT1", "DXT3", "BC3", "DXT5"):
|
||||||
codec_name = "bcn"
|
codec_name = "bcn"
|
||||||
flags |= DDSD.LINEARSIZE
|
flags |= DDSD.LINEARSIZE
|
||||||
pitch = (im.width + 3) * 4
|
pitch = (im.width + 3) * 4
|
||||||
args = pixel_format
|
|
||||||
rgba_mask = [0, 0, 0, 0]
|
rgba_mask = [0, 0, 0, 0]
|
||||||
pixel_flags = DDPF.FOURCC
|
pixel_flags = DDPF.FOURCC
|
||||||
fourcc = {"DXT1": D3DFMT.DXT1, "BC3": D3DFMT.DX10, "DXT5": D3DFMT.DXT5}[
|
if pixel_format == "DXT1":
|
||||||
pixel_format
|
fourcc = D3DFMT.DXT1
|
||||||
]
|
args = (1,)
|
||||||
if fourcc == D3DFMT.DX10:
|
elif pixel_format == "DXT3":
|
||||||
dxgi_format = DXGI_FORMAT.BC3_TYPELESS
|
fourcc = D3DFMT.DXT3
|
||||||
|
args = (2,)
|
||||||
|
else:
|
||||||
|
fourcc = D3DFMT.DXT5 if pixel_format == "DXT5" else D3DFMT.DX10
|
||||||
|
args = (3,)
|
||||||
|
if fourcc == D3DFMT.DX10:
|
||||||
|
dxgi_format = DXGI_FORMAT.BC3_TYPELESS
|
||||||
else:
|
else:
|
||||||
codec_name = "raw"
|
codec_name = "raw"
|
||||||
flags |= DDSD.PITCH
|
flags |= DDSD.PITCH
|
||||||
|
|
|
@ -360,19 +360,18 @@ PyImaging_BcnEncoderNew(PyObject *self, PyObject *args) {
|
||||||
ImagingEncoderObject *encoder;
|
ImagingEncoderObject *encoder;
|
||||||
|
|
||||||
char *mode;
|
char *mode;
|
||||||
char *pixel_format;
|
int n;
|
||||||
if (!PyArg_ParseTuple(args, "ss", &mode, &pixel_format)) {
|
if (!PyArg_ParseTuple(args, "si", &mode, &n)) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
encoder = PyImaging_EncoderNew(sizeof(BCNSTATE));
|
encoder = PyImaging_EncoderNew(0);
|
||||||
if (encoder == NULL) {
|
if (encoder == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
encoder->encode = ImagingBcnEncode;
|
encoder->encode = ImagingBcnEncode;
|
||||||
|
encoder->state.state = n;
|
||||||
((BCNSTATE *)encoder->state.context)->pixel_format = pixel_format;
|
|
||||||
|
|
||||||
return (PyObject *)encoder;
|
return (PyObject *)encoder;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,8 +10,6 @@
|
||||||
|
|
||||||
#include "Imaging.h"
|
#include "Imaging.h"
|
||||||
|
|
||||||
#include "Bcn.h"
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
UINT8 color[3];
|
UINT8 color[3];
|
||||||
} rgb;
|
} rgb;
|
||||||
|
@ -57,14 +55,18 @@ encode_bc1_color(Imaging im, ImagingCodecState state, UINT8 *dst, int separate_a
|
||||||
int transparency = 0;
|
int transparency = 0;
|
||||||
for (i = 0; i < 4; i++) {
|
for (i = 0; i < 4; i++) {
|
||||||
for (j = 0; j < 4; j++) {
|
for (j = 0; j < 4; j++) {
|
||||||
|
current_rgba = &block[i + j * 4];
|
||||||
|
|
||||||
int x = state->x + i * im->pixelsize;
|
int x = state->x + i * im->pixelsize;
|
||||||
int y = state->y + j;
|
int y = state->y + j;
|
||||||
if (x >= state->xsize * im->pixelsize || y >= state->ysize) {
|
if (x >= state->xsize * im->pixelsize || y >= state->ysize) {
|
||||||
// The 4x4 block extends past the edge of the image
|
// The 4x4 block extends past the edge of the image
|
||||||
|
for (k = 0; k < 3; k++) {
|
||||||
|
current_rgba->color[k] = 0;
|
||||||
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
current_rgba = &block[i + j * 4];
|
|
||||||
for (k = 0; k < 3; k++) {
|
for (k = 0; k < 3; k++) {
|
||||||
current_rgba->color[k] =
|
current_rgba->color[k] =
|
||||||
(UINT8)im->image[y][x + (im->pixelsize == 1 ? 0 : k)];
|
(UINT8)im->image[y][x + (im->pixelsize == 1 ? 0 : k)];
|
||||||
|
@ -152,6 +154,36 @@ encode_bc1_color(Imaging im, ImagingCodecState state, UINT8 *dst, int separate_a
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
encode_bc2_block(Imaging im, ImagingCodecState state, UINT8 *dst) {
|
||||||
|
int i, j;
|
||||||
|
UINT8 block[16], current_alpha;
|
||||||
|
for (i = 0; i < 4; i++) {
|
||||||
|
for (j = 0; j < 4; j++) {
|
||||||
|
int x = state->x + i * im->pixelsize;
|
||||||
|
int y = state->y + j;
|
||||||
|
if (x >= state->xsize * im->pixelsize || y >= state->ysize) {
|
||||||
|
// The 4x4 block extends past the edge of the image
|
||||||
|
block[i + j * 4] = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
current_alpha = (UINT8)im->image[y][x + 3];
|
||||||
|
block[i + j * 4] = current_alpha;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < 4; i++) {
|
||||||
|
UINT16 l = 0;
|
||||||
|
for (j = 3; j > -1; j--) {
|
||||||
|
current_alpha = block[i * 4 + j];
|
||||||
|
l |= current_alpha << (j * 4);
|
||||||
|
}
|
||||||
|
*dst++ = l;
|
||||||
|
*dst++ = l >> 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
encode_bc3_alpha(Imaging im, ImagingCodecState state, UINT8 *dst) {
|
encode_bc3_alpha(Imaging im, ImagingCodecState state, UINT8 *dst) {
|
||||||
int i, j;
|
int i, j;
|
||||||
|
@ -166,6 +198,7 @@ encode_bc3_alpha(Imaging im, ImagingCodecState state, UINT8 *dst) {
|
||||||
int y = state->y + j;
|
int y = state->y + j;
|
||||||
if (x >= state->xsize * im->pixelsize || y >= state->ysize) {
|
if (x >= state->xsize * im->pixelsize || y >= state->ysize) {
|
||||||
// The 4x4 block extends past the edge of the image
|
// The 4x4 block extends past the edge of the image
|
||||||
|
block[i + j * 4] = 0;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -217,17 +250,20 @@ encode_bc3_alpha(Imaging im, ImagingCodecState state, UINT8 *dst) {
|
||||||
|
|
||||||
int
|
int
|
||||||
ImagingBcnEncode(Imaging im, ImagingCodecState state, UINT8 *buf, int bytes) {
|
ImagingBcnEncode(Imaging im, ImagingCodecState state, UINT8 *buf, int bytes) {
|
||||||
char *pixel_format = ((BCNSTATE *)state->context)->pixel_format;
|
int n = state->state;
|
||||||
int n = strcmp(pixel_format, "DXT1") == 0 ? 1 : 3;
|
|
||||||
int has_alpha_channel =
|
int has_alpha_channel =
|
||||||
strcmp(im->mode, "RGBA") == 0 || strcmp(im->mode, "LA") == 0;
|
strcmp(im->mode, "RGBA") == 0 || strcmp(im->mode, "LA") == 0;
|
||||||
|
|
||||||
UINT8 *dst = buf;
|
UINT8 *dst = buf;
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (n == 3) {
|
if (n == 2 || n == 3) {
|
||||||
if (has_alpha_channel) {
|
if (has_alpha_channel) {
|
||||||
encode_bc3_alpha(im, state, dst);
|
if (n == 2) {
|
||||||
|
encode_bc2_block(im, state, dst);
|
||||||
|
} else {
|
||||||
|
encode_bc3_alpha(im, state, dst);
|
||||||
|
}
|
||||||
dst += 8;
|
dst += 8;
|
||||||
} else {
|
} else {
|
||||||
for (int i = 0; i < 8; i++) {
|
for (int i = 0; i < 8; i++) {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user