Merge pull request #6449 from ShadelessFox/main

Added DDS BC6 reading
This commit is contained in:
Andrew Murray 2022-10-11 12:58:24 +11:00 committed by GitHub
commit 28878c68e1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 76 additions and 51 deletions

BIN
Tests/images/bc6h.dds Normal file

Binary file not shown.

BIN
Tests/images/bc6h.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

BIN
Tests/images/bc6h_sf.dds Normal file

Binary file not shown.

BIN
Tests/images/bc6h_sf.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

View File

@ -16,6 +16,8 @@ TEST_FILE_DX10_BC5_TYPELESS = "Tests/images/bc5_typeless.dds"
TEST_FILE_DX10_BC5_UNORM = "Tests/images/bc5_unorm.dds"
TEST_FILE_DX10_BC5_SNORM = "Tests/images/bc5_snorm.dds"
TEST_FILE_BC5S = "Tests/images/bc5s.dds"
TEST_FILE_BC6H = "Tests/images/bc6h.dds"
TEST_FILE_BC6HS = "Tests/images/bc6h_sf.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"
@ -114,6 +116,20 @@ def test_dx10_bc5(image_path, expected_path):
assert_image_equal_tofile(im, expected_path.replace(".dds", ".png"))
@pytest.mark.parametrize("image_path", (TEST_FILE_BC6H, TEST_FILE_BC6HS))
def test_dx10_bc6h(image_path):
"""Check DX10 BC6H/BC6HS images can be opened"""
with Image.open(image_path) as im:
im.load()
assert im.format == "DDS"
assert im.mode == "RGB"
assert im.size == (128, 128)
assert_image_equal_tofile(im, image_path.replace(".dds", ".png"))
def test_dx10_bc7():
"""Check DX10 images can be opened"""

View File

@ -101,6 +101,8 @@ DXGI_FORMAT_R8G8B8A8_UNORM_SRGB = 29
DXGI_FORMAT_BC5_TYPELESS = 82
DXGI_FORMAT_BC5_UNORM = 83
DXGI_FORMAT_BC5_SNORM = 84
DXGI_FORMAT_BC6H_UF16 = 95
DXGI_FORMAT_BC6H_SF16 = 96
DXGI_FORMAT_BC7_TYPELESS = 97
DXGI_FORMAT_BC7_UNORM = 98
DXGI_FORMAT_BC7_UNORM_SRGB = 99
@ -181,6 +183,14 @@ class DdsImageFile(ImageFile.ImageFile):
self.pixel_format = "BC5S"
n = 5
self.mode = "RGB"
elif dxgi_format == DXGI_FORMAT_BC6H_UF16:
self.pixel_format = "BC6H"
n = 6
self.mode = "RGB"
elif dxgi_format == DXGI_FORMAT_BC6H_SF16:
self.pixel_format = "BC6HS"
n = 6
self.mode = "RGB"
elif dxgi_format in (DXGI_FORMAT_BC7_TYPELESS, DXGI_FORMAT_BC7_UNORM):
self.pixel_format = "BC7"
n = 7

View File

@ -376,11 +376,8 @@ PyImaging_BcnDecoderNew(PyObject *self, PyObject *args) {
actual = "L";
break;
case 5: /* BC5: 2-channel 8-bit via 2 BC3 alpha blocks */
actual = "RGB";
break;
case 6: /* BC6: 3-channel 16-bit float */
/* TODO: support 4-channel floating point images */
actual = "RGBAF";
actual = "RGB";
break;
default:
PyErr_SetString(PyExc_ValueError, "block compression type unknown");

View File

@ -23,10 +23,6 @@ typedef struct {
UINT8 l;
} lum;
typedef struct {
FLOAT32 r, g, b;
} rgb32f;
typedef struct {
UINT16 c0, c1;
UINT32 lut;
@ -536,53 +532,53 @@ static const bc6_mode_info bc6_modes[] = {
/* Table.F, encoded as a sequence of bit indices */
static const UINT8 bc6_bit_packings[][75] = {
{116, 132, 176, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 16, 17,
{116, 132, 180, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 16, 17,
18, 19, 20, 21, 22, 23, 24, 25, 32, 33, 34, 35, 36, 37, 38,
39, 40, 41, 48, 49, 50, 51, 52, 164, 112, 113, 114, 115, 64, 65,
66, 67, 68, 172, 160, 161, 162, 163, 80, 81, 82, 83, 84, 173, 128,
129, 130, 131, 96, 97, 98, 99, 100, 174, 144, 145, 146, 147, 148, 175},
{117, 164, 165, 0, 1, 2, 3, 4, 5, 6, 172, 173, 132, 16, 17,
18, 19, 20, 21, 22, 133, 174, 116, 32, 33, 34, 35, 36, 37, 38,
175, 177, 176, 48, 49, 50, 51, 52, 53, 112, 113, 114, 115, 64, 65,
66, 67, 68, 176, 160, 161, 162, 163, 80, 81, 82, 83, 84, 177, 128,
129, 130, 131, 96, 97, 98, 99, 100, 178, 144, 145, 146, 147, 148, 179},
{117, 164, 165, 0, 1, 2, 3, 4, 5, 6, 176, 177, 132, 16, 17,
18, 19, 20, 21, 22, 133, 178, 116, 32, 33, 34, 35, 36, 37, 38,
179, 181, 180, 48, 49, 50, 51, 52, 53, 112, 113, 114, 115, 64, 65,
66, 67, 68, 69, 160, 161, 162, 163, 80, 81, 82, 83, 84, 85, 128,
129, 130, 131, 96, 97, 98, 99, 100, 101, 144, 145, 146, 147, 148, 149},
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 16, 17, 18, 19, 20,
21, 22, 23, 24, 25, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41,
48, 49, 50, 51, 52, 10, 112, 113, 114, 115, 64, 65, 66, 67, 26,
172, 160, 161, 162, 163, 80, 81, 82, 83, 42, 173, 128, 129, 130, 131,
96, 97, 98, 99, 100, 174, 144, 145, 146, 147, 148, 175},
176, 160, 161, 162, 163, 80, 81, 82, 83, 42, 177, 128, 129, 130, 131,
96, 97, 98, 99, 100, 178, 144, 145, 146, 147, 148, 179},
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 16, 17, 18, 19, 20,
21, 22, 23, 24, 25, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41,
48, 49, 50, 51, 10, 164, 112, 113, 114, 115, 64, 65, 66, 67, 68,
26, 160, 161, 162, 163, 80, 81, 82, 83, 42, 173, 128, 129, 130, 131,
96, 97, 98, 99, 172, 174, 144, 145, 146, 147, 116, 175},
26, 160, 161, 162, 163, 80, 81, 82, 83, 42, 177, 128, 129, 130, 131,
96, 97, 98, 99, 176, 178, 144, 145, 146, 147, 116, 179},
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 16, 17, 18, 19, 20,
21, 22, 23, 24, 25, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41,
48, 49, 50, 51, 10, 132, 112, 113, 114, 115, 64, 65, 66, 67, 26,
172, 160, 161, 162, 163, 80, 81, 82, 83, 84, 42, 128, 129, 130, 131,
96, 97, 98, 99, 173, 174, 144, 145, 146, 147, 176, 175},
176, 160, 161, 162, 163, 80, 81, 82, 83, 84, 42, 128, 129, 130, 131,
96, 97, 98, 99, 177, 178, 144, 145, 146, 147, 180, 179},
{0, 1, 2, 3, 4, 5, 6, 7, 8, 132, 16, 17, 18, 19, 20,
21, 22, 23, 24, 116, 32, 33, 34, 35, 36, 37, 38, 39, 40, 176,
21, 22, 23, 24, 116, 32, 33, 34, 35, 36, 37, 38, 39, 40, 180,
48, 49, 50, 51, 52, 164, 112, 113, 114, 115, 64, 65, 66, 67, 68,
172, 160, 161, 162, 163, 80, 81, 82, 83, 84, 173, 128, 129, 130, 131,
96, 97, 98, 99, 100, 174, 144, 145, 146, 147, 148, 175},
176, 160, 161, 162, 163, 80, 81, 82, 83, 84, 177, 128, 129, 130, 131,
96, 97, 98, 99, 100, 178, 144, 145, 146, 147, 148, 179},
{0, 1, 2, 3, 4, 5, 6, 7, 164, 132, 16, 17, 18, 19, 20,
21, 22, 23, 174, 116, 32, 33, 34, 35, 36, 37, 38, 39, 175, 176,
21, 22, 23, 178, 116, 32, 33, 34, 35, 36, 37, 38, 39, 179, 180,
48, 49, 50, 51, 52, 53, 112, 113, 114, 115, 64, 65, 66, 67, 68,
172, 160, 161, 162, 163, 80, 81, 82, 83, 84, 173, 128, 129, 130, 131,
176, 160, 161, 162, 163, 80, 81, 82, 83, 84, 177, 128, 129, 130, 131,
96, 97, 98, 99, 100, 101, 144, 145, 146, 147, 148, 149},
{0, 1, 2, 3, 4, 5, 6, 7, 172, 132, 16, 17, 18, 19, 20,
21, 22, 23, 117, 116, 32, 33, 34, 35, 36, 37, 38, 39, 165, 176,
{0, 1, 2, 3, 4, 5, 6, 7, 176, 132, 16, 17, 18, 19, 20,
21, 22, 23, 117, 116, 32, 33, 34, 35, 36, 37, 38, 39, 165, 180,
48, 49, 50, 51, 52, 164, 112, 113, 114, 115, 64, 65, 66, 67, 68,
69, 160, 161, 162, 163, 80, 81, 82, 83, 84, 173, 128, 129, 130, 131,
96, 97, 98, 99, 100, 174, 144, 145, 146, 147, 148, 175},
{0, 1, 2, 3, 4, 5, 6, 7, 173, 132, 16, 17, 18, 19, 20,
21, 22, 23, 133, 116, 32, 33, 34, 35, 36, 37, 38, 39, 177, 176,
69, 160, 161, 162, 163, 80, 81, 82, 83, 84, 177, 128, 129, 130, 131,
96, 97, 98, 99, 100, 178, 144, 145, 146, 147, 148, 179},
{0, 1, 2, 3, 4, 5, 6, 7, 177, 132, 16, 17, 18, 19, 20,
21, 22, 23, 133, 116, 32, 33, 34, 35, 36, 37, 38, 39, 181, 180,
48, 49, 50, 51, 52, 164, 112, 113, 114, 115, 64, 65, 66, 67, 68,
172, 160, 161, 162, 163, 80, 81, 82, 83, 84, 85, 128, 129, 130, 131,
96, 97, 98, 99, 100, 174, 144, 145, 146, 147, 148, 175},
{0, 1, 2, 3, 4, 5, 164, 172, 173, 132, 16, 17, 18, 19, 20,
21, 117, 133, 174, 116, 32, 33, 34, 35, 36, 37, 165, 175, 177, 176,
176, 160, 161, 162, 163, 80, 81, 82, 83, 84, 85, 128, 129, 130, 131,
96, 97, 98, 99, 100, 178, 144, 145, 146, 147, 148, 179},
{0, 1, 2, 3, 4, 5, 164, 176, 177, 132, 16, 17, 18, 19, 20,
21, 117, 133, 178, 116, 32, 33, 34, 35, 36, 37, 165, 179, 181, 180,
48, 49, 50, 51, 52, 53, 112, 113, 114, 115, 64, 65, 66, 67, 68,
69, 160, 161, 162, 163, 80, 81, 82, 83, 84, 85, 128, 129, 130, 131,
96, 97, 98, 99, 100, 101, 144, 145, 146, 147, 148, 149},
@ -681,20 +677,31 @@ bc6_finalize(int v, int sign) {
}
}
static UINT8
bc6_clamp(float value) {
if (value < 0.0f) {
return 0;
} else if (value > 1.0f) {
return 255;
} else {
return (UINT8) (value * 255.0f);
}
}
static void
bc6_lerp(rgb32f *col, int *e0, int *e1, int s, int sign) {
bc6_lerp(rgba *col, int *e0, int *e1, int s, int sign) {
int r, g, b;
int t = 64 - s;
r = (e0[0] * t + e1[0] * s) >> 6;
g = (e0[1] * t + e1[1] * s) >> 6;
b = (e0[2] * t + e1[2] * s) >> 6;
col->r = bc6_finalize(r, sign);
col->g = bc6_finalize(g, sign);
col->b = bc6_finalize(b, sign);
col->r = bc6_clamp(bc6_finalize(r, sign));
col->g = bc6_clamp(bc6_finalize(g, sign));
col->b = bc6_clamp(bc6_finalize(b, sign));
}
static void
decode_bc6_block(rgb32f *col, const UINT8 *src, int sign) {
decode_bc6_block(rgba *col, const UINT8 *src, int sign) {
UINT16 endpoints[12]; /* storage for r0, g0, b0, r1, ... */
int ueps[12];
int i, i0, ib2, di, dw, mask, numep, s;
@ -744,21 +751,16 @@ decode_bc6_block(rgb32f *col, const UINT8 *src, int sign) {
}
if (sign || info->tr) { /* sign-extend e1,2,3 if signed or deltas */
for (i = 3; i < numep; i += 3) {
bc6_sign_extend(&endpoints[i + 0], info->rb);
bc6_sign_extend(&endpoints[i], info->rb);
bc6_sign_extend(&endpoints[i + 1], info->gb);
bc6_sign_extend(&endpoints[i + 2], info->bb);
}
}
if (info->tr) { /* apply deltas */
for (i = 3; i < numep; i++) {
for (i = 3; i < numep; i += 3) {
endpoints[i] = (endpoints[i] + endpoints[0]) & mask;
}
if (sign) {
for (i = 3; i < numep; i += 3) {
bc6_sign_extend(&endpoints[i + 0], info->rb);
bc6_sign_extend(&endpoints[i + 1], info->gb);
bc6_sign_extend(&endpoints[i + 2], info->bb);
}
endpoints[i + 1] = (endpoints[i + 1] + endpoints[1]) & mask;
endpoints[i + 2] = (endpoints[i + 2] + endpoints[2]) & mask;
}
}
for (i = 0; i < numep; i++) {
@ -862,8 +864,8 @@ decode_bcn(
break;
case 6:
while (bytes >= 16) {
rgb32f col[16];
decode_bc6_block(col, ptr, (state->state >> 4) & 1);
rgba col[16];
decode_bc6_block(col, ptr, strcmp(pixel_format, "BC6HS") == 0 ? 1 : 0);
put_block(im, state, (const char *)col, sizeof(col[0]), C);
ptr += 16;
bytes -= 16;