From 2488167f33b7e357315c7052273b973fe2cad8e8 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Mon, 10 Jul 2023 22:00:30 +1000 Subject: [PATCH 1/3] Allow for zero-byte padding at end of XMP data --- Tests/images/xmp_padded.jpg | Bin 0 -> 778 bytes Tests/test_file_jpeg.py | 8 ++++++++ src/PIL/JpegImagePlugin.py | 2 +- 3 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 Tests/images/xmp_padded.jpg diff --git a/Tests/images/xmp_padded.jpg b/Tests/images/xmp_padded.jpg new file mode 100644 index 0000000000000000000000000000000000000000..9ecfb3efebed10b67eb90a997088c52bb76762b2 GIT binary patch literal 778 zcmex=s)|yBtNcQetFn_V zQ_WTR(nVgxdTk&}~?hnq)&msi3_QAW{-Wbpq0gCGYeoR}Gv7?=bZnFSgD zA7PLO1|2IS7%)HqBNHRO;Y1B)Q5kfNa@ zn{Z$vyHcTuQRBpg9Li1`4~hm|{Gei-RMf=DB_=K*DW$5WuA!-AVrph?VQJ;;;_Bw^ z;pr6|5*ijB5gC=7lA4yDk(pIoQd(ACQCZd8(%RPE(b+X=@|3C5rq7r;YtiB*OP4KQ zv2xX>&0Dr^+rDGxu0w~996fgY#K}{aE?>EN?fQ+Iw;n!v{N(Ag=PzEq`uOSdm#^Qx z|M>X}Pb?HxGHT=y zahkYr<3UbkKb$@|Xn~>=}Ok L>(W@j|NkZcQRV=4 literal 0 HcmV?d00001 diff --git a/Tests/test_file_jpeg.py b/Tests/test_file_jpeg.py index 0247527f5b2..904fecebfb2 100644 --- a/Tests/test_file_jpeg.py +++ b/Tests/test_file_jpeg.py @@ -898,6 +898,14 @@ def test_getxmp(self): with Image.open("Tests/images/hopper.jpg") as im: assert im.getxmp() == {} + def test_getxmp_padded(self): + with Image.open("Tests/images/xmp_padded.jpg") as im: + if ElementTree is None: + with pytest.warns(UserWarning): + assert im.getxmp() == {} + else: + assert im.getxmp() == {"xmpmeta": None} + @pytest.mark.timeout(timeout=1) def test_eof(self): # Even though this decoder never says that it is finished diff --git a/src/PIL/JpegImagePlugin.py b/src/PIL/JpegImagePlugin.py index dfc7e6e9f56..a28cd036748 100644 --- a/src/PIL/JpegImagePlugin.py +++ b/src/PIL/JpegImagePlugin.py @@ -496,7 +496,7 @@ def getxmp(self): for segment, content in self.applist: if segment == "APP1": - marker, xmp_tags = content.rsplit(b"\x00", 1) + marker, xmp_tags = content.split(b"\x00")[:2] if marker == b"http://ns.adobe.com/xap/1.0/": return self._getxmp(xmp_tags) return {} From 3f78ba80f9d1f1f0e5276c11bfe42a8efad69a29 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Mon, 10 Jul 2023 22:05:28 +1000 Subject: [PATCH 2/3] Do not require curly bracket in tag name --- Tests/images/xmp_no_prefix.jpg | Bin 0 -> 788 bytes Tests/test_file_jpeg.py | 8 ++++++++ src/PIL/Image.py | 2 +- 3 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 Tests/images/xmp_no_prefix.jpg diff --git a/Tests/images/xmp_no_prefix.jpg b/Tests/images/xmp_no_prefix.jpg new file mode 100644 index 0000000000000000000000000000000000000000..bcd78c7ed23a62208fc42bd90d8911b33e870e7e GIT binary patch literal 788 zcmex=s)|yBtNcQetFn_V zQHEAm;@P_1sVSzVUPy~A}b>pFhBt#6Eh1d8#@Ol7dKGBRsjYkMrLLv7G_pf78aoD zTA(}wiy*6zqM;+3a9|?4QlW@Z(iUwW$pkka<)WpdpCN3cY31zV>gMj@=@lFj8WtWA8I_!pnwFlCnN?g;T2@|BS=HRq+ScCD*)?hMl&RCE z&zL!D(c&dbmn~nha@D5ITefc7zGLUELx+zXJ$C%W$y1juU%7hi`i+~n9zJ^f@(s#)lOnK WGb1qam<1W^8Gioj(pbR%|0V!ePy~kn literal 0 HcmV?d00001 diff --git a/Tests/test_file_jpeg.py b/Tests/test_file_jpeg.py index 904fecebfb2..217ad74f85a 100644 --- a/Tests/test_file_jpeg.py +++ b/Tests/test_file_jpeg.py @@ -898,6 +898,14 @@ def test_getxmp(self): with Image.open("Tests/images/hopper.jpg") as im: assert im.getxmp() == {} + def test_getxmp_no_prefix(self): + with Image.open("Tests/images/xmp_no_prefix.jpg") as im: + if ElementTree is None: + with pytest.warns(UserWarning): + assert im.getxmp() == {} + else: + assert im.getxmp() == {"xmpmeta": {"key": "value"}} + def test_getxmp_padded(self): with Image.open("Tests/images/xmp_padded.jpg") as im: if ElementTree is None: diff --git a/src/PIL/Image.py b/src/PIL/Image.py index a519a28af36..6d3715a9239 100644 --- a/src/PIL/Image.py +++ b/src/PIL/Image.py @@ -1380,7 +1380,7 @@ def getextrema(self): def _getxmp(self, xmp_tags): def get_name(tag): - return tag.split("}")[1] + return re.sub("^{[^}]+}", "", tag) def get_value(element): value = {get_name(k): v for k, v in element.attrib.items()} From a3fd0098750c17f4f944f7c2202f361c6e342be5 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Fri, 6 Oct 2023 17:31:06 +1100 Subject: [PATCH 3/3] Match warning message --- Tests/test_file_jpeg.py | 15 ++++++++++++--- Tests/test_file_png.py | 5 ++++- Tests/test_file_tiff.py | 5 ++++- Tests/test_file_webp_metadata.py | 5 ++++- 4 files changed, 24 insertions(+), 6 deletions(-) diff --git a/Tests/test_file_jpeg.py b/Tests/test_file_jpeg.py index 4d350f5d2ff..769d7ed969a 100644 --- a/Tests/test_file_jpeg.py +++ b/Tests/test_file_jpeg.py @@ -882,7 +882,10 @@ def read(n=-1): def test_getxmp(self): with Image.open("Tests/images/xmp_test.jpg") as im: if ElementTree is None: - with pytest.warns(UserWarning): + with pytest.warns( + UserWarning, + match="XMP data cannot be read without defusedxml dependency", + ): assert im.getxmp() == {} else: xmp = im.getxmp() @@ -908,7 +911,10 @@ def test_getxmp(self): def test_getxmp_no_prefix(self): with Image.open("Tests/images/xmp_no_prefix.jpg") as im: if ElementTree is None: - with pytest.warns(UserWarning): + with pytest.warns( + UserWarning, + match="XMP data cannot be read without defusedxml dependency", + ): assert im.getxmp() == {} else: assert im.getxmp() == {"xmpmeta": {"key": "value"}} @@ -916,7 +922,10 @@ def test_getxmp_no_prefix(self): def test_getxmp_padded(self): with Image.open("Tests/images/xmp_padded.jpg") as im: if ElementTree is None: - with pytest.warns(UserWarning): + with pytest.warns( + UserWarning, + match="XMP data cannot be read without defusedxml dependency", + ): assert im.getxmp() == {} else: assert im.getxmp() == {"xmpmeta": None} diff --git a/Tests/test_file_png.py b/Tests/test_file_png.py index eea9f73d866..40fc595ad52 100644 --- a/Tests/test_file_png.py +++ b/Tests/test_file_png.py @@ -665,7 +665,10 @@ def test_plte_length(self, tmp_path): def test_getxmp(self): with Image.open("Tests/images/color_snakes.png") as im: if ElementTree is None: - with pytest.warns(UserWarning): + with pytest.warns( + UserWarning, + match="XMP data cannot be read without defusedxml dependency", + ): assert im.getxmp() == {} else: xmp = im.getxmp() diff --git a/Tests/test_file_tiff.py b/Tests/test_file_tiff.py index f13436ce868..7362c93cac8 100644 --- a/Tests/test_file_tiff.py +++ b/Tests/test_file_tiff.py @@ -734,7 +734,10 @@ def test_discard_icc_profile(self, tmp_path): def test_getxmp(self): with Image.open("Tests/images/lab.tif") as im: if ElementTree is None: - with pytest.warns(UserWarning): + with pytest.warns( + UserWarning, + match="XMP data cannot be read without defusedxml dependency", + ): assert im.getxmp() == {} else: xmp = im.getxmp() diff --git a/Tests/test_file_webp_metadata.py b/Tests/test_file_webp_metadata.py index 037479f9fbb..dd47be8b21b 100644 --- a/Tests/test_file_webp_metadata.py +++ b/Tests/test_file_webp_metadata.py @@ -118,7 +118,10 @@ def test_getxmp(): with Image.open("Tests/images/flower2.webp") as im: if ElementTree is None: - with pytest.warns(UserWarning): + with pytest.warns( + UserWarning, + match="XMP data cannot be read without defusedxml dependency", + ): assert im.getxmp() == {} else: assert (