From df99d48a0cb98cad2f6ee5ae65b0be5df8d84ef3 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Wed, 10 Jan 2024 09:26:56 +1100 Subject: [PATCH 1/2] Simplified code --- src/PIL/PsdImagePlugin.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/PIL/PsdImagePlugin.py b/src/PIL/PsdImagePlugin.py index 5cff564137d..9f7bf78290b 100644 --- a/src/PIL/PsdImagePlugin.py +++ b/src/PIL/PsdImagePlugin.py @@ -185,14 +185,13 @@ def read(size): # image info mode = [] ct_types = i16(read(2)) - types = list(range(ct_types)) - if len(types) > 4: - fp.seek(len(types) * 6 + 12, io.SEEK_CUR) + if ct_types > 4: + fp.seek(ct_types * 6 + 12, io.SEEK_CUR) size = i32(read(4)) fp.seek(size, io.SEEK_CUR) continue - for _ in types: + for _ in range(ct_types): type = i16(read(2)) if type == 65535: From c2907dc04967109391a77eea00f7d583a0a0395f Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Wed, 10 Jan 2024 23:53:45 +1100 Subject: [PATCH 2/2] Layer co-ordinates may be negative --- Tests/images/negative_top_left_layer.psd | Bin 0 -> 8220 bytes Tests/test_file_psd.py | 5 +++++ src/PIL/PsdImagePlugin.py | 9 +++++---- src/PIL/_binary.py | 10 ++++++++++ 4 files changed, 20 insertions(+), 4 deletions(-) create mode 100644 Tests/images/negative_top_left_layer.psd diff --git a/Tests/images/negative_top_left_layer.psd b/Tests/images/negative_top_left_layer.psd new file mode 100644 index 0000000000000000000000000000000000000000..be9d9d6d03e357d4e3c31aecf0d3f90f9fc49974 GIT binary patch literal 8220 zcmeHLOKclO82+84w2B(Fg$kj{J{Py>O@s5)Tnk;DCfU!vP66^uVR05)uyyaj1IWz(WGT1y$ysS-%1)G!l)3h{_mtCT}}nG*az3o1HEcM}Oi^6FbX3af3SXscWnN8yQRS zkv;f{D6LjB3(OcF9sQ9%?~YCK@mQzlGb7Uxh;VkX$C1md)eI*XI|AUip+A3OS~z{? zDPjBfh(8Y7;a->|Mo>RmD$TJO8<*d|jC}e+WLO*9+)_JX(!fA>1hhC})cp|UXHZTz z!a9>*MR~8WNRX-6`zTNPxIvV^X8KAb|G?xbm(f9#{qp<_`nDHkq1q=``eb9#chE*d zn**lfBL2wfNH&@L9Fv{e67G!`7PXz!eS87?1K1vb6HtI6lt6$AEP)L*2tmZ&MNI(n zI6i%g`TO|%63(jNEE^1*F$*3zK=^!MF+dwEJ#GUlsd80p=QO~!?^>;29|YL`62Q%i zt=1oJwOTjd1{nPo;8V9Z-@A+v{|)sQd%6Q}0_=Jo;DakYUF8*k4=(`R_YLM7;p?!R z9I-5bU)}|nI0JCcHGuJ_Bi?X~jl(-%0hE!exvK!Ly$8HWg)-I`3h#FGOp7j4~@bc%4L8hTQ2-6pAH5O(=3Ana26Ds_C+#E3%+u zbv3EWGFrzj_jbgPxNj_zV8WU@+^iGh91VpEt=eur{_{tl#0A^T$Dd3U!Izr0>dN~Zz;^j<2WvK_UF`##V))XB=~LtY<8-MGLd} zINPsodWLQ4TuiEFI+IbdVkVukM9oU2#9W1@#foYeNjXI`ik0qzD!4&NT!S(w1W(wA zqgh&p=2TfsB~4A#vW6y-6g5RtlXGb$XXbKQtq`YT)&9jXQTZ1fa8)@**71c9Fmofwe|0a>Pzdx#Yc;WwsRrT7AAXKY7r zZQA_1aF)L?NBC*oxY&s>YDH<`}MGrhHY~b&bqgCV)xxx(PuRq~n z6vT%)30?EXB4rUm#za{W75T4>No|iM_TK2YJSF{&lqqh|_oBghkq%#A_&$`nFT^%! zxPv=c+QGP!O9;YnkxlVCq-#jmrWn|i@i4oFbZv@(O&Jff>p!DwymzIdF8&N^;Drg` zuFtStX|eJ-Yk2u$cWM>J*ncUpOYAm=pX_#b3GiANyTop3F8-Em|J8DYS+KHgj;v5W zy2aI&TpLxpnHuKs4!;5vI%7r+C4O-`rTwfiCIzSP* zx;hXQBQmxHbt}H9hJM^W1H*XSHUn!n)>?zmw&GXT+I8e=0NR#tbrrc9fVL%EwblUH L`ro%zxbyW->#0jd literal 0 HcmV?d00001 diff --git a/Tests/test_file_psd.py b/Tests/test_file_psd.py index 8b06ce2b163..e3c1f447af2 100644 --- a/Tests/test_file_psd.py +++ b/Tests/test_file_psd.py @@ -112,6 +112,11 @@ def test_rgba(): assert_image_equal_tofile(im, "Tests/images/imagedraw_square.png") +def test_negative_top_left_layer() -> None: + with Image.open("Tests/images/negative_top_left_layer.psd") as im: + assert im.layers[0][2] == (-50, -50, 50, 50) + + def test_layer_skip(): with Image.open("Tests/images/five_channels.psd") as im: assert im.n_frames == 1 diff --git a/src/PIL/PsdImagePlugin.py b/src/PIL/PsdImagePlugin.py index 9f7bf78290b..d29bcf9970c 100644 --- a/src/PIL/PsdImagePlugin.py +++ b/src/PIL/PsdImagePlugin.py @@ -24,6 +24,7 @@ from ._binary import i16be as i16 from ._binary import i32be as i32 from ._binary import si16be as si16 +from ._binary import si32be as si32 MODES = { # (photoshop mode, bits) -> (pil mode, required channels) @@ -177,10 +178,10 @@ def read(size): for _ in range(abs(ct)): # bounding box - y0 = i32(read(4)) - x0 = i32(read(4)) - y1 = i32(read(4)) - x1 = i32(read(4)) + y0 = si32(read(4)) + x0 = si32(read(4)) + y1 = si32(read(4)) + x1 = si32(read(4)) # image info mode = [] diff --git a/src/PIL/_binary.py b/src/PIL/_binary.py index 0a07e8d0e12..4594ccce361 100644 --- a/src/PIL/_binary.py +++ b/src/PIL/_binary.py @@ -77,6 +77,16 @@ def si32le(c: bytes, o: int = 0) -> int: return unpack_from(" int: + """ + Converts a 4-bytes (32 bits) string to a signed integer, big endian. + + :param c: string containing bytes to convert + :param o: offset of bytes to convert in string + """ + return unpack_from(">i", c, o)[0] + + def i16be(c: bytes, o: int = 0) -> int: return unpack_from(">H", c, o)[0]