Skip to content

Commit 42b385b

Browse files
committed
Fix encoding/decoding on big endian systems
1 parent cb4cb10 commit 42b385b

File tree

3 files changed

+50
-77
lines changed

3 files changed

+50
-77
lines changed

build.py

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -26,14 +26,9 @@ def build(setup_kwargs: Any) -> Any:
2626
setup_oj()
2727

2828
# Determine if system is big endian or not
29-
macros = [
30-
("NPY_NO_DEPRECATED_API", "NPY_1_7_API_VERSION"),
31-
# ("USE_JPIP", "0"),
32-
]
29+
macros = [("NPY_NO_DEPRECATED_API", "NPY_1_7_API_VERSION")]
3330
if unpack("h", b"\x00\x01")[0] == 1:
34-
# macros.append(("ON_BE_SYSTEM", None))
35-
macros.append(("OPJ_BIG_ENDIAN", None))
36-
# macros.append(("__BIG_ENDIAN__", None))
31+
macros.append(("PYOJ_BIG_ENDIAN", None))
3732

3833
ext = Extension(
3934
"_openjpeg",
@@ -151,14 +146,6 @@ def setup_oj() -> None:
151146
f.write("\n")
152147
f.write("#define USE_JPIP 0")
153148

154-
# Use our own OPJ_BIG_ENDIAN macro
155-
if os.path.exists(INTERFACE_SRC / "opj_config_private.h"):
156-
with open(INTERFACE_SRC / "opj_config_private.h", "r") as f:
157-
lines = f.readlines()
158-
159-
with open(INTERFACE_SRC / "opj_config_private.h", "w") as f:
160-
f.writelines(lines[:-5])
161-
162149

163150
def reset_oj() -> None:
164151
# Restore submodule to original state

lib/interface/decode.c

Lines changed: 33 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -635,24 +635,25 @@ extern int Decode(PyObject* fd, unsigned char *out, int codec_format)
635635
{
636636
u16.val = (unsigned short)(*p_component[ii]);
637637
// Ensure little endian output
638-
#ifdef OPJ_BIG_ENDIAN
639-
*out = u16.vals[1];
640-
out++;
641-
*out = u16.vals[0];
642-
out++;
643-
#else
644-
*out = u16.vals[0];
645-
out++;
646-
*out = u16.vals[1];
647-
out++;
648-
#endif
638+
#ifdef PYOJ_BIG_ENDIAN
639+
*out = u16.vals[1];
640+
out++;
641+
*out = u16.vals[0];
642+
out++;
643+
#else
644+
*out = u16.vals[0];
645+
out++;
646+
*out = u16.vals[1];
647+
out++;
648+
#endif
649+
649650
p_component[ii]++;
650651
}
651652
}
652653
}
653654
} else if (precision <= 32) {
654655
union {
655-
unsigned long val;
656+
OPJ_INT32 val;
656657
unsigned char vals[4];
657658
} u32;
658659

@@ -663,27 +664,27 @@ extern int Decode(PyObject* fd, unsigned char *out, int codec_format)
663664
{
664665
for (ii = 0; ii < NR_COMPONENTS; ii++)
665666
{
666-
u32.val = (unsigned long)(*p_component[ii]);
667+
u32.val = (OPJ_INT32)(*p_component[ii]);
667668
// Ensure little endian output
668-
#ifdef OPJ_BIG_ENDIAN
669-
*out = u32.vals[3];
670-
out++;
671-
*out = u32.vals[2];
672-
out++;
673-
*out = u32.vals[1];
674-
out++;
675-
*out = u32.vals[0];
676-
out++;
677-
#else
678-
*out = u32.vals[0];
679-
out++;
680-
*out = u32.vals[1];
681-
out++;
682-
*out = u32.vals[2];
683-
out++;
684-
*out = u32.vals[3];
685-
out++;
686-
#endif
669+
#ifdef PYOJ_BIG_ENDIAN
670+
*out = u32.vals[3];
671+
out++;
672+
*out = u32.vals[2];
673+
out++;
674+
*out = u32.vals[1];
675+
out++;
676+
*out = u32.vals[0];
677+
out++;
678+
#else
679+
*out = u32.vals[0];
680+
out++;
681+
*out = u32.vals[1];
682+
out++;
683+
*out = u32.vals[2];
684+
out++;
685+
*out = u32.vals[3];
686+
out++;
687+
#endif
687688

688689
p_component[ii]++;
689690
}

openjpeg/tests/test_encode.py

Lines changed: 15 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -425,21 +425,16 @@ def test_lossless_unsigned(self):
425425
assert out.dtype.kind == "u"
426426
assert np.array_equal(arr, out)
427427

428-
# @pytest.mark.skipif(sys.byteorder == "big", reason="Running on BE system")
429428
def test_lossless_unsigned_u4(self):
430429
"""Test encoding unsigned data for bit-depth 17-32"""
431-
dtype = "<u4" if sys.byteorder == "little" else ">u4"
432430
rows = 123
433431
cols = 234
434432
planes = 3
435433
for bit_depth in range(17, 25):
436434
maximum = 2**bit_depth - 1
437-
arr = np.random.randint(0, high=maximum + 1, size=(rows, cols), dtype=dtype)
438-
# if sys.byteorder == "big":
439-
# arr = arr.byteswap().astype("<u4")
435+
arr = np.random.randint(0, high=maximum + 1, size=(rows, cols), dtype="u4")
440436
buffer = encode_array(arr, photometric_interpretation=PI.MONOCHROME2)
441437
out = decode(buffer)
442-
print(bit_depth, out.min(), out.max())
443438

444439
param = parse_j2k(buffer)
445440
assert param["precision"] == bit_depth
@@ -451,7 +446,7 @@ def test_lossless_unsigned_u4(self):
451446
assert np.array_equal(arr, out)
452447

453448
arr = np.random.randint(
454-
0, high=maximum + 1, size=(rows, cols, planes), dtype=dtype
449+
0, high=maximum + 1, size=(rows, cols, planes), dtype="u4"
455450
)
456451
buffer = encode_array(arr, photometric_interpretation=PI.RGB, use_mct=False)
457452
out = decode(buffer)
@@ -521,8 +516,7 @@ def test_lossless_signed(self):
521516
assert out.dtype.kind == "i"
522517
assert np.array_equal(arr, out)
523518

524-
# @pytest.mark.skipif(sys.byteorder == "big", reason="Running on BE system")
525-
def test_lossless_signed_u4(self):
519+
def test_lossless_signed_i4(self):
526520
"""Test encoding signed data for bit-depth 17-32"""
527521
rows = 123
528522
cols = 234
@@ -531,7 +525,7 @@ def test_lossless_signed_u4(self):
531525
maximum = 2 ** (bit_depth - 1) - 1
532526
minimum = -(2 ** (bit_depth - 1))
533527
arr = np.random.randint(
534-
low=minimum, high=maximum + 1, size=(rows, cols), dtype="<i4"
528+
low=minimum, high=maximum + 1, size=(rows, cols), dtype="i4"
535529
)
536530
buffer = encode_array(arr, photometric_interpretation=PI.MONOCHROME2)
537531
out = decode(buffer)
@@ -546,7 +540,7 @@ def test_lossless_signed_u4(self):
546540
assert np.array_equal(arr, out)
547541

548542
arr = np.random.randint(
549-
low=minimum, high=maximum + 1, size=(rows, cols, planes), dtype="<i4"
543+
low=minimum, high=maximum + 1, size=(rows, cols, planes), dtype="i4"
550544
)
551545
buffer = encode_array(arr, photometric_interpretation=PI.RGB, use_mct=False)
552546
out = decode(buffer)
@@ -1227,7 +1221,7 @@ def test_lossless_unsigned_u4(self):
12271221
rows = 123
12281222
cols = 234
12291223
planes = 3
1230-
for bit_depth in range(24, 32):
1224+
for bit_depth in range(17, 25):
12311225
maximum = 2**bit_depth - 1
12321226
arr = np.random.randint(0, high=maximum + 1, size=(rows, cols), dtype="u4")
12331227
if sys.byteorder == "big":
@@ -1243,14 +1237,6 @@ def test_lossless_unsigned_u4(self):
12431237
photometric_interpretation=PI.MONOCHROME2,
12441238
)
12451239
out = decode(buffer)
1246-
print(bit_depth, arr.min(), arr.max())
1247-
print(bit_depth, out.min(), out.max())
1248-
import matplotlib.pyplot as plt
1249-
1250-
fig, (ax1, ax2) = plt.subplots(1, 2)
1251-
ax1.imshow(arr)
1252-
ax2.imshow(out)
1253-
plt.show()
12541240

12551241
param = parse_j2k(buffer)
12561242
assert param["precision"] == bit_depth
@@ -1462,12 +1448,15 @@ def test_lossless_signed_i4(self):
14621448
rows = 123
14631449
cols = 234
14641450
planes = 3
1465-
for bit_depth in range(24, 32):
1451+
for bit_depth in range(17, 25):
14661452
maximum = 2 ** (bit_depth - 1) - 1
14671453
minimum = -(2 ** (bit_depth - 1))
14681454
arr = np.random.randint(
1469-
low=minimum, high=maximum + 1, size=(rows, cols), dtype="<i4"
1455+
low=minimum, high=maximum + 1, size=(rows, cols), dtype="i4"
14701456
)
1457+
if sys.byteorder == "big":
1458+
arr = arr.byteswap().view("<i4")
1459+
14711460
buffer = encode_buffer(
14721461
arr.tobytes(),
14731462
cols,
@@ -1478,14 +1467,7 @@ def test_lossless_signed_i4(self):
14781467
photometric_interpretation=PI.MONOCHROME2,
14791468
)
14801469
out = decode(buffer)
1481-
print(bit_depth, arr.min(), arr.max())
1482-
print(bit_depth, out.min(), out.max())
1483-
import matplotlib.pyplot as plt
14841470

1485-
fig, (ax1, ax2) = plt.subplots(1, 2)
1486-
ax1.imshow(arr)
1487-
ax2.imshow(out)
1488-
plt.show()
14891471

14901472
param = parse_j2k(buffer)
14911473
assert param["precision"] == bit_depth
@@ -1497,8 +1479,11 @@ def test_lossless_signed_i4(self):
14971479
assert np.array_equal(arr, out)
14981480

14991481
arr = np.random.randint(
1500-
low=minimum, high=maximum + 1, size=(rows, cols, planes), dtype="<i4"
1482+
low=minimum, high=maximum + 1, size=(rows, cols, planes), dtype="i4"
15011483
)
1484+
if sys.byteorder == "big":
1485+
arr = arr.byteswap().view("<i4")
1486+
15021487
buffer = encode_buffer(
15031488
arr.tobytes(),
15041489
cols,

0 commit comments

Comments
 (0)