mirror of
https://github.com/python-pillow/Pillow.git
synced 2025-01-27 09:44: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_DXT1 = "Tests/images/dxt1-rgb-4bbp-noalpha_MipMaps-1.dds"
|
||||||
TEST_FILE_DXT3 = "Tests/images/dxt3-argb-8bbp-explicitalpha_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_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 = "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_BC7_UNORM_SRGB = "Tests/images/DXGI_FORMAT_BC7_UNORM_SRGB.dds"
|
||||||
TEST_FILE_DX10_R8G8B8A8 = "Tests/images/argb-32bpp_MipMaps-1.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"))
|
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"""
|
"""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()
|
im.load()
|
||||||
|
|
||||||
assert im.format == "DDS"
|
assert im.format == "DDS"
|
||||||
assert im.mode == "RGB"
|
assert im.mode == "RGB"
|
||||||
assert im.size == (256, 256)
|
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():
|
def test_dx10_bc7():
|
||||||
|
|
|
@ -151,6 +151,10 @@ class DdsImageFile(ImageFile.ImageFile):
|
||||||
elif fourcc == b"DXT5":
|
elif fourcc == b"DXT5":
|
||||||
self.pixel_format = "DXT5"
|
self.pixel_format = "DXT5"
|
||||||
n = 3
|
n = 3
|
||||||
|
elif fourcc == b"BC5S":
|
||||||
|
self.pixel_format = "BC5S"
|
||||||
|
n = 5
|
||||||
|
self.mode = "RGB"
|
||||||
elif fourcc == b"DX10":
|
elif fourcc == b"DX10":
|
||||||
data_start += 20
|
data_start += 20
|
||||||
# ignoring flags which pertain to volume textures and cubemaps
|
# ignoring flags which pertain to volume textures and cubemaps
|
||||||
|
@ -183,7 +187,9 @@ class DdsImageFile(ImageFile.ImageFile):
|
||||||
else:
|
else:
|
||||||
raise NotImplementedError(f"Unimplemented pixel format {repr(fourcc)}")
|
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):
|
def load_seek(self, pos):
|
||||||
pass
|
pass
|
||||||
|
|
11
src/decode.c
11
src/decode.c
|
@ -34,9 +34,10 @@
|
||||||
|
|
||||||
#include "libImaging/Imaging.h"
|
#include "libImaging/Imaging.h"
|
||||||
|
|
||||||
|
#include "libImaging/Bit.h"
|
||||||
|
#include "libImaging/Bcn.h"
|
||||||
#include "libImaging/Gif.h"
|
#include "libImaging/Gif.h"
|
||||||
#include "libImaging/Raw.h"
|
#include "libImaging/Raw.h"
|
||||||
#include "libImaging/Bit.h"
|
|
||||||
#include "libImaging/Sgi.h"
|
#include "libImaging/Sgi.h"
|
||||||
|
|
||||||
/* -------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------- */
|
||||||
|
@ -359,8 +360,8 @@ PyImaging_BcnDecoderNew(PyObject *self, PyObject *args) {
|
||||||
char *mode;
|
char *mode;
|
||||||
char *actual;
|
char *actual;
|
||||||
int n = 0;
|
int n = 0;
|
||||||
int ystep = 1;
|
char *pixel_format = "";
|
||||||
if (!PyArg_ParseTuple(args, "s|ii", &mode, &n, &ystep)) {
|
if (!PyArg_ParseTuple(args, "si|s", &mode, &n, &pixel_format)) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -391,14 +392,14 @@ PyImaging_BcnDecoderNew(PyObject *self, PyObject *args) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
decoder = PyImaging_DecoderNew(0);
|
decoder = PyImaging_DecoderNew(sizeof(char *));
|
||||||
if (decoder == NULL) {
|
if (decoder == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
decoder->decode = ImagingBcnDecode;
|
decoder->decode = ImagingBcnDecode;
|
||||||
decoder->state.state = n;
|
decoder->state.state = n;
|
||||||
decoder->state.ystep = ystep;
|
((BCNSTATE *)decoder->state.context)->pixel_format = pixel_format;
|
||||||
|
|
||||||
return (PyObject *)decoder;
|
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 "Imaging.h"
|
||||||
|
|
||||||
|
#include "Bcn.h"
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
UINT8 r, g, b, a;
|
UINT8 r, g, b, a;
|
||||||
} rgba;
|
} rgba;
|
||||||
|
@ -35,6 +37,11 @@ typedef struct {
|
||||||
UINT8 lut[6];
|
UINT8 lut[6];
|
||||||
} bc3_alpha;
|
} bc3_alpha;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
INT8 a0, a1;
|
||||||
|
UINT8 lut[6];
|
||||||
|
} bc5s_alpha;
|
||||||
|
|
||||||
#define LOAD16(p) (p)[0] | ((p)[1] << 8)
|
#define LOAD16(p) (p)[0] | ((p)[1] << 8)
|
||||||
|
|
||||||
#define LOAD32(p) (p)[0] | ((p)[1] << 8) | ((p)[2] << 16) | ((p)[3] << 24)
|
#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);
|
dst->lut = LOAD32(src + 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
bc3_alpha_load(bc3_alpha *dst, const UINT8 *src) {
|
|
||||||
memcpy(dst, src, sizeof(bc3_alpha));
|
|
||||||
}
|
|
||||||
|
|
||||||
static rgba
|
static rgba
|
||||||
decode_565(UINT16 x) {
|
decode_565(UINT16 x) {
|
||||||
rgba c;
|
rgba c;
|
||||||
|
@ -113,15 +115,26 @@ decode_bc1_color(rgba *dst, const UINT8 *src, int separate_alpha) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
decode_bc3_alpha(char *dst, const UINT8 *src, int stride, int o) {
|
decode_bc3_alpha(char *dst, const UINT8 *src, int stride, int o, int sign) {
|
||||||
bc3_alpha b;
|
|
||||||
UINT16 a0, a1;
|
UINT16 a0, a1;
|
||||||
UINT8 a[8];
|
UINT8 a[8];
|
||||||
int n, lut, aw;
|
int n, lut1, lut2, aw;
|
||||||
bc3_alpha_load(&b, src);
|
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[0] = (UINT8)a0;
|
||||||
a[1] = (UINT8)a1;
|
a[1] = (UINT8)a1;
|
||||||
if (a0 > a1) {
|
if (a0 > a1) {
|
||||||
|
@ -139,14 +152,12 @@ decode_bc3_alpha(char *dst, const UINT8 *src, int stride, int o) {
|
||||||
a[6] = 0;
|
a[6] = 0;
|
||||||
a[7] = 0xff;
|
a[7] = 0xff;
|
||||||
}
|
}
|
||||||
lut = b.lut[0] | (b.lut[1] << 8) | (b.lut[2] << 16);
|
|
||||||
for (n = 0; n < 8; n++) {
|
for (n = 0; n < 8; n++) {
|
||||||
aw = 7 & (lut >> (3 * n));
|
aw = 7 & (lut1 >> (3 * n));
|
||||||
dst[stride * n + o] = a[aw];
|
dst[stride * n + o] = a[aw];
|
||||||
}
|
}
|
||||||
lut = b.lut[3] | (b.lut[4] << 8) | (b.lut[5] << 16);
|
|
||||||
for (n = 0; n < 8; n++) {
|
for (n = 0; n < 8; n++) {
|
||||||
aw = 7 & (lut >> (3 * n));
|
aw = 7 & (lut2 >> (3 * n));
|
||||||
dst[stride * (8 + n) + o] = a[aw];
|
dst[stride * (8 + n) + o] = a[aw];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -172,18 +183,18 @@ decode_bc2_block(rgba *col, const UINT8 *src) {
|
||||||
static void
|
static void
|
||||||
decode_bc3_block(rgba *col, const UINT8 *src) {
|
decode_bc3_block(rgba *col, const UINT8 *src) {
|
||||||
decode_bc1_color(col, src + 8, 1);
|
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
|
static void
|
||||||
decode_bc4_block(lum *col, const UINT8 *src) {
|
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
|
static void
|
||||||
decode_bc5_block(rgba *col, const UINT8 *src) {
|
decode_bc5_block(rgba *col, const UINT8 *src, int sign) {
|
||||||
decode_bc3_alpha((char *)col, src, sizeof(col[0]), 0);
|
decode_bc3_alpha((char *)col, src, sizeof(col[0]), 0, sign);
|
||||||
decode_bc3_alpha((char *)col, src + 8, sizeof(col[0]), 1);
|
decode_bc3_alpha((char *)col, src + 8, sizeof(col[0]), 1, sign);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* BC6 and BC7 are described here:
|
/* 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
|
static int
|
||||||
decode_bcn(
|
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;
|
int ymax = state->ysize + state->yoff;
|
||||||
const UINT8 *ptr = src;
|
const UINT8 *ptr = src;
|
||||||
switch (N) {
|
switch (N) {
|
||||||
|
@ -836,7 +847,19 @@ decode_bcn(
|
||||||
DECODE_LOOP(2, 16, rgba);
|
DECODE_LOOP(2, 16, rgba);
|
||||||
DECODE_LOOP(3, 16, rgba);
|
DECODE_LOOP(3, 16, rgba);
|
||||||
DECODE_LOOP(4, 8, lum);
|
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:
|
case 6:
|
||||||
while (bytes >= 16) {
|
while (bytes >= 16) {
|
||||||
rgb32f col[16];
|
rgb32f col[16];
|
||||||
|
@ -849,7 +872,7 @@ decode_bcn(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
DECODE_LOOP(7, 16, rgba);
|
DECODE_LOOP(7, 16, rgba);
|
||||||
#undef DECODE_LOOP
|
#undef DECODE_LOOP
|
||||||
}
|
}
|
||||||
return (int)(ptr - src);
|
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 N = state->state & 0xf;
|
||||||
int width = state->xsize;
|
int width = state->xsize;
|
||||||
int height = state->ysize;
|
int height = state->ysize;
|
||||||
if ((width & 3) | (height & 3)) {
|
int C = (width & 3) | (height & 3) ? 1 : 0;
|
||||||
return decode_bcn(im, state, buf, bytes, N, 1);
|
char *pixel_format = ((BCNSTATE *)state->context)->pixel_format;
|
||||||
} else {
|
return decode_bcn(im, state, buf, bytes, N, C, pixel_format);
|
||||||
return decode_bcn(im, state, buf, bytes, N, 0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user