mirror of
https://github.com/python-pillow/Pillow.git
synced 2025-01-26 17:24:31 +03:00
Added BC5_SNORM reading
This commit is contained in:
parent
68ac6d151e
commit
2e7f40e0b8
BIN
Tests/images/bc5_snorm.dds
Normal file
BIN
Tests/images/bc5_snorm.dds
Normal file
Binary file not shown.
BIN
Tests/images/bc5_snorm.png
Normal file
BIN
Tests/images/bc5_snorm.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 82 KiB |
|
@ -10,7 +10,8 @@ from .helper import assert_image_equal, assert_image_equal_tofile
|
|||
TEST_FILE_DXT1 = "Tests/images/dxt1-rgb-4bbp-noalpha_MipMaps-1.dds"
|
||||
TEST_FILE_DXT3 = "Tests/images/dxt3-argb-8bbp-explicitalpha_MipMaps-1.dds"
|
||||
TEST_FILE_DXT5 = "Tests/images/dxt5-argb-8bbp-interpolatedalpha_MipMaps-1.dds"
|
||||
TEST_FILE_DX10_BC5 = "Tests/images/bc5_unorm.dds"
|
||||
TEST_FILE_DX10_BC5_UNORM = "Tests/images/bc5_unorm.dds"
|
||||
TEST_FILE_DX10_BC5_SNORM = "Tests/images/bc5_snorm.dds"
|
||||
TEST_FILE_DX10_BC7 = "Tests/images/bc7-argb-8bpp_MipMaps-1.dds"
|
||||
TEST_FILE_DX10_BC7_UNORM_SRGB = "Tests/images/DXGI_FORMAT_BC7_UNORM_SRGB.dds"
|
||||
TEST_FILE_DX10_R8G8B8A8 = "Tests/images/argb-32bpp_MipMaps-1.dds"
|
||||
|
@ -59,17 +60,30 @@ def test_sanity_dxt3():
|
|||
assert_image_equal_tofile(im, TEST_FILE_DXT3.replace(".dds", ".png"))
|
||||
|
||||
|
||||
def test_dx10_bc5():
|
||||
def test_dx10_bc5_unorm():
|
||||
"""Check DX10 images can be opened"""
|
||||
|
||||
with Image.open(TEST_FILE_DX10_BC5) as im:
|
||||
with Image.open(TEST_FILE_DX10_BC5_UNORM) as im:
|
||||
im.load()
|
||||
|
||||
assert im.format == "DDS"
|
||||
assert im.mode == "RGB"
|
||||
assert im.size == (256, 256)
|
||||
|
||||
assert_image_equal_tofile(im, TEST_FILE_DX10_BC5.replace(".dds", ".png"))
|
||||
assert_image_equal_tofile(im, TEST_FILE_DX10_BC5_UNORM.replace(".dds", ".png"))
|
||||
|
||||
|
||||
def test_dx10_bc5_snorm():
|
||||
"""Check DX10 images can be opened"""
|
||||
|
||||
with Image.open(TEST_FILE_DX10_BC5_SNORM) as im:
|
||||
im.load()
|
||||
|
||||
assert im.format == "DDS"
|
||||
assert im.mode == "RGB"
|
||||
assert im.size == (256, 256)
|
||||
|
||||
assert_image_equal_tofile(im, TEST_FILE_DX10_BC5_SNORM.replace(".dds", ".png"))
|
||||
|
||||
|
||||
def test_dx10_bc7():
|
||||
|
|
|
@ -151,6 +151,10 @@ class DdsImageFile(ImageFile.ImageFile):
|
|||
elif fourcc == b"DXT5":
|
||||
self.pixel_format = "DXT5"
|
||||
n = 3
|
||||
elif fourcc == b"BC5S":
|
||||
self.pixel_format = "BC5S"
|
||||
n = 5
|
||||
self.mode = "RGB"
|
||||
elif fourcc == b"DX10":
|
||||
data_start += 20
|
||||
# ignoring flags which pertain to volume textures and cubemaps
|
||||
|
@ -183,7 +187,9 @@ class DdsImageFile(ImageFile.ImageFile):
|
|||
else:
|
||||
raise NotImplementedError(f"Unimplemented pixel format {repr(fourcc)}")
|
||||
|
||||
self.tile = [("bcn", (0, 0) + self.size, data_start, (n))]
|
||||
self.tile = [
|
||||
("bcn", (0, 0) + self.size, data_start, (n, self.pixel_format))
|
||||
]
|
||||
|
||||
def load_seek(self, pos):
|
||||
pass
|
||||
|
|
11
src/decode.c
11
src/decode.c
|
@ -34,9 +34,10 @@
|
|||
|
||||
#include "libImaging/Imaging.h"
|
||||
|
||||
#include "libImaging/Bit.h"
|
||||
#include "libImaging/Bcn.h"
|
||||
#include "libImaging/Gif.h"
|
||||
#include "libImaging/Raw.h"
|
||||
#include "libImaging/Bit.h"
|
||||
#include "libImaging/Sgi.h"
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
@ -359,8 +360,8 @@ PyImaging_BcnDecoderNew(PyObject *self, PyObject *args) {
|
|||
char *mode;
|
||||
char *actual;
|
||||
int n = 0;
|
||||
int ystep = 1;
|
||||
if (!PyArg_ParseTuple(args, "s|ii", &mode, &n, &ystep)) {
|
||||
char *pixel_format = "";
|
||||
if (!PyArg_ParseTuple(args, "si|s", &mode, &n, &pixel_format)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -391,14 +392,14 @@ PyImaging_BcnDecoderNew(PyObject *self, PyObject *args) {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
decoder = PyImaging_DecoderNew(0);
|
||||
decoder = PyImaging_DecoderNew(sizeof(char *));
|
||||
if (decoder == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
decoder->decode = ImagingBcnDecode;
|
||||
decoder->state.state = n;
|
||||
decoder->state.ystep = ystep;
|
||||
((BCNSTATE *)decoder->state.context)->pixel_format = pixel_format;
|
||||
|
||||
return (PyObject *)decoder;
|
||||
}
|
||||
|
|
3
src/libImaging/Bcn.h
Normal file
3
src/libImaging/Bcn.h
Normal file
|
@ -0,0 +1,3 @@
|
|||
typedef struct {
|
||||
char *pixel_format;
|
||||
} BCNSTATE;
|
|
@ -13,6 +13,8 @@
|
|||
|
||||
#include "Imaging.h"
|
||||
|
||||
#include "Bcn.h"
|
||||
|
||||
typedef struct {
|
||||
UINT8 r, g, b, a;
|
||||
} rgba;
|
||||
|
@ -35,6 +37,11 @@ typedef struct {
|
|||
UINT8 lut[6];
|
||||
} bc3_alpha;
|
||||
|
||||
typedef struct {
|
||||
INT8 a0, a1;
|
||||
UINT8 lut[6];
|
||||
} bc5s_alpha;
|
||||
|
||||
#define LOAD16(p) (p)[0] | ((p)[1] << 8)
|
||||
|
||||
#define LOAD32(p) (p)[0] | ((p)[1] << 8) | ((p)[2] << 16) | ((p)[3] << 24)
|
||||
|
@ -46,11 +53,6 @@ bc1_color_load(bc1_color *dst, const UINT8 *src) {
|
|||
dst->lut = LOAD32(src + 4);
|
||||
}
|
||||
|
||||
static void
|
||||
bc3_alpha_load(bc3_alpha *dst, const UINT8 *src) {
|
||||
memcpy(dst, src, sizeof(bc3_alpha));
|
||||
}
|
||||
|
||||
static rgba
|
||||
decode_565(UINT16 x) {
|
||||
rgba c;
|
||||
|
@ -113,15 +115,26 @@ decode_bc1_color(rgba *dst, const UINT8 *src, int separate_alpha) {
|
|||
}
|
||||
|
||||
static void
|
||||
decode_bc3_alpha(char *dst, const UINT8 *src, int stride, int o) {
|
||||
bc3_alpha b;
|
||||
decode_bc3_alpha(char *dst, const UINT8 *src, int stride, int o, int sign) {
|
||||
UINT16 a0, a1;
|
||||
UINT8 a[8];
|
||||
int n, lut, aw;
|
||||
bc3_alpha_load(&b, src);
|
||||
int n, lut1, lut2, aw;
|
||||
if (sign == 1) {
|
||||
bc5s_alpha b;
|
||||
memcpy(&b, src, sizeof(bc5s_alpha));
|
||||
a0 = (b.a0 + 255) / 2;
|
||||
a1 = (b.a1 + 255) / 2;
|
||||
lut1 = b.lut[0] | (b.lut[1] << 8) | (b.lut[2] << 16);
|
||||
lut2 = b.lut[3] | (b.lut[4] << 8) | (b.lut[5] << 16);
|
||||
} else {
|
||||
bc3_alpha b;
|
||||
memcpy(&b, src, sizeof(bc3_alpha));
|
||||
a0 = b.a0;
|
||||
a1 = b.a1;
|
||||
lut1 = b.lut[0] | (b.lut[1] << 8) | (b.lut[2] << 16);
|
||||
lut2 = b.lut[3] | (b.lut[4] << 8) | (b.lut[5] << 16);
|
||||
}
|
||||
|
||||
a0 = b.a0;
|
||||
a1 = b.a1;
|
||||
a[0] = (UINT8)a0;
|
||||
a[1] = (UINT8)a1;
|
||||
if (a0 > a1) {
|
||||
|
@ -139,14 +152,12 @@ decode_bc3_alpha(char *dst, const UINT8 *src, int stride, int o) {
|
|||
a[6] = 0;
|
||||
a[7] = 0xff;
|
||||
}
|
||||
lut = b.lut[0] | (b.lut[1] << 8) | (b.lut[2] << 16);
|
||||
for (n = 0; n < 8; n++) {
|
||||
aw = 7 & (lut >> (3 * n));
|
||||
aw = 7 & (lut1 >> (3 * n));
|
||||
dst[stride * n + o] = a[aw];
|
||||
}
|
||||
lut = b.lut[3] | (b.lut[4] << 8) | (b.lut[5] << 16);
|
||||
for (n = 0; n < 8; n++) {
|
||||
aw = 7 & (lut >> (3 * n));
|
||||
aw = 7 & (lut2 >> (3 * n));
|
||||
dst[stride * (8 + n) + o] = a[aw];
|
||||
}
|
||||
}
|
||||
|
@ -172,18 +183,18 @@ decode_bc2_block(rgba *col, const UINT8 *src) {
|
|||
static void
|
||||
decode_bc3_block(rgba *col, const UINT8 *src) {
|
||||
decode_bc1_color(col, src + 8, 1);
|
||||
decode_bc3_alpha((char *)col, src, sizeof(col[0]), 3);
|
||||
decode_bc3_alpha((char *)col, src, sizeof(col[0]), 3, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
decode_bc4_block(lum *col, const UINT8 *src) {
|
||||
decode_bc3_alpha((char *)col, src, sizeof(col[0]), 0);
|
||||
decode_bc3_alpha((char *)col, src, sizeof(col[0]), 0, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
decode_bc5_block(rgba *col, const UINT8 *src) {
|
||||
decode_bc3_alpha((char *)col, src, sizeof(col[0]), 0);
|
||||
decode_bc3_alpha((char *)col, src + 8, sizeof(col[0]), 1);
|
||||
decode_bc5_block(rgba *col, const UINT8 *src, int sign) {
|
||||
decode_bc3_alpha((char *)col, src, sizeof(col[0]), 0, sign);
|
||||
decode_bc3_alpha((char *)col, src + 8, sizeof(col[0]), 1, sign);
|
||||
}
|
||||
|
||||
/* BC6 and BC7 are described here:
|
||||
|
@ -813,7 +824,7 @@ put_block(Imaging im, ImagingCodecState state, const char *col, int sz, int C) {
|
|||
|
||||
static int
|
||||
decode_bcn(
|
||||
Imaging im, ImagingCodecState state, const UINT8 *src, int bytes, int N, int C) {
|
||||
Imaging im, ImagingCodecState state, const UINT8 *src, int bytes, int N, int C, char *pixel_format) {
|
||||
int ymax = state->ysize + state->yoff;
|
||||
const UINT8 *ptr = src;
|
||||
switch (N) {
|
||||
|
@ -836,7 +847,19 @@ decode_bcn(
|
|||
DECODE_LOOP(2, 16, rgba);
|
||||
DECODE_LOOP(3, 16, rgba);
|
||||
DECODE_LOOP(4, 8, lum);
|
||||
DECODE_LOOP(5, 16, rgba);
|
||||
case 5:
|
||||
while (bytes >= 16) {
|
||||
rgba col[16];
|
||||
memset(col, 0, 16 * sizeof(col[0]));
|
||||
decode_bc5_block(col, ptr, strcmp(pixel_format, "BC5S") == 0 ? 1 : 0);
|
||||
put_block(im, state, (const char *)col, sizeof(col[0]), C);
|
||||
ptr += 16;
|
||||
bytes -= 16;
|
||||
if (state->y >= ymax) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 6:
|
||||
while (bytes >= 16) {
|
||||
rgb32f col[16];
|
||||
|
@ -849,7 +872,7 @@ decode_bcn(
|
|||
}
|
||||
}
|
||||
break;
|
||||
DECODE_LOOP(7, 16, rgba);
|
||||
DECODE_LOOP(7, 16, rgba);
|
||||
#undef DECODE_LOOP
|
||||
}
|
||||
return (int)(ptr - src);
|
||||
|
@ -860,9 +883,7 @@ ImagingBcnDecode(Imaging im, ImagingCodecState state, UINT8 *buf, Py_ssize_t byt
|
|||
int N = state->state & 0xf;
|
||||
int width = state->xsize;
|
||||
int height = state->ysize;
|
||||
if ((width & 3) | (height & 3)) {
|
||||
return decode_bcn(im, state, buf, bytes, N, 1);
|
||||
} else {
|
||||
return decode_bcn(im, state, buf, bytes, N, 0);
|
||||
}
|
||||
int C = (width & 3) | (height & 3) ? 1 : 0;
|
||||
char *pixel_format = ((BCNSTATE *)state->context)->pixel_format;
|
||||
return decode_bcn(im, state, buf, bytes, N, C, pixel_format);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user