From 6e97da02603fcd1fe2e16f6164f737200107d924 Mon Sep 17 00:00:00 2001 From: Alexander Piskun Date: Tue, 26 Jul 2022 00:30:32 +0300 Subject: [PATCH 1/5] fixing xmp tag orientation generated by exiftool --- Tests/images/xmp_orientation_exifool.png | Bin 0 -> 1935 bytes Tests/test_imageops.py | 7 +++++++ src/PIL/Image.py | 6 ++++++ src/PIL/ImageOps.py | 5 +++++ 4 files changed, 18 insertions(+) create mode 100644 Tests/images/xmp_orientation_exifool.png diff --git a/Tests/images/xmp_orientation_exifool.png b/Tests/images/xmp_orientation_exifool.png new file mode 100644 index 0000000000000000000000000000000000000000..fb30199c86acbc8953d1cf16ddfa9e3ec41ece19 GIT binary patch literal 1935 zcmY+F2{hZ;9>@QxtxWn1Gu2jWOXx_a$WnUdQ2t5V` z06@{v!PW(w`C!LG_JE_;L6P4`et*gwlVAAXEGzg8a;B2x}{-B@YV%Lg*YS zj29Bj48!tph+QrgT<^G12-t22CkTgd450?lu~<7E!=J)p1;a3>kcMak2nnV6V_j_R zzaT&hhX~|w*jN;b%jF`uhDcUu019JnZjM5qLY+Eg07e*ug)=!+o&hsV2P8mYy9`@; zm|rM^&0(;ZupK7VmvxncLm;5AFK7?GmO$a< z&F8iKbD6B(wdmL!K_T9S2q}c`15?RJXrp<;mb@oa+pNAZ5oVT{7IZ}6esn!{T`N9% ze`nFJoi55XkKts6B| z2Pdr~l<<_(Gx(5BY`|M;*F#uEFcj%G(&WlJ9@6LRsrRNDa{5Z^^#nw;4nBTC4q7F0am|R}D?90? z#r)z{Ho&Yi=oKapG8f_Z2$U0$pZVzW(er*>6`FTZ>B$)M?OuBIa7|5(Q<3o9#>bBz zU%ysS+!Jvq$TcAU)9!(IKDtq%_s*fzEyU{h++1*Ycs8l6s>-E=5~$Aq%XE|}*M1cG z=Oip$uDwv!_lI%7XQH$P4>8PsHaV#S-wQV~F>wl9Q8LT5vf$7E9!b^h?70 zW;7xap)6k7Y7-zBlH`e+(uC2!MH_O(g8adL8s}DZLqkJbn-cI;whTUzya9JlPa{%w zU*NOn&vDk)dWq4PsO#6eRJ$e!c=>B3W26XyGZt0(6I*)429nlIGs$hKuOAmVB4jd| zg@uKxA2I$N#rU#P^glW_XSr&Uxjw;*;hQ&aG6o3}8_2-dffKgc=T4}U4$SuSBtCiv zA5Z|)H8rDI-t+C2w1U?UhC%OPYG&489AQ~M0F}<61x#k#Lyp5=#1_d1e z*lhNA*$Z5^Y&qHf-f-|oYsg-dxH-4kuXAtf7B4c=Rpq;U^5Vk6VQ8$g?mdP_jfaMY zhL?v&zmX!`)~3*<1aiL3T|esDHPtw{$wl&}9Uwb9lRApYlm4uWEox|NoXz~SxoHXD z2d{2RL#tX_M}tkSdI{*N%7^71Zlt8-c4`v8A(l{}px{pTB?tsUb5A9dW&w z36=}C`i1y}1fbTMYAvZ=T&XK5b%Na8e&L%(N2063z> zsy^KO80ALcUA;3;(9V*=JHtxFjAL={KYcPcHa5oLS}H2o;o-y8=>r3<@EUrFTUk!= z7OwDc7o1=Y>9T};Zql*0c+VX3$b7rR&+i;z06?O!!q|kArtBgb6r`jS6cjL-Oe0cL zV`GnO+0f8%ZEa0;(!aW-^m3)UB@VahDk~_I%#4g&tPKC4bHo?ed>E^G#_^5mquUnD zgC3cyA3hLIL$H=UNqQO3EuVl`46|;e$OXKJ9FW*49Ls5{s;EF)SzQthHW`S8qX%x~ zUcs<_>z<#!)1X00HKqBs>e#2&9e)Cwqu6GJtf1H0HDqxAfPk;y4W5rEC*^*c&Y0w@ zh5dQu!SHi|kMM`>dR(dN`ktx548kjEhL#UsPhRhV_f%ziR_cE7vtJ^e;R`vN*zMM;q%9liD=p7U(yl0Y zNPLQ>sGN4tQB6EC*;zifuRm^S@3pIylfE-C-s0xwk<|RhHx#^ctNxOcCIL^^)jI}u P{!vFevh5?HPxOBPc@S?M literal 0 HcmV?d00001 diff --git a/Tests/test_imageops.py b/Tests/test_imageops.py index 87fffa7b724..855b6bccd6a 100644 --- a/Tests/test_imageops.py +++ b/Tests/test_imageops.py @@ -351,6 +351,13 @@ def check(orientation_im): transposed_im = ImageOps.exif_transpose(im) assert 0x0112 not in transposed_im.getexif() + # Orientation from "XML:com.adobe.xmp" info key (from exiftool) + with Image.open("Tests/images/xmp_orientation_exiftool.png") as im: + assert im.getexif()[0x0112] == 8 + + transposed_im = ImageOps.exif_transpose(im) + assert 0x0112 not in transposed_im.getexif() + # Orientation from "Raw profile type exif" info key # This test image has been manually hexedited from exif_imagemagick.png # to have a different orientation diff --git a/src/PIL/Image.py b/src/PIL/Image.py index 6abb1249166..816ea94db8d 100644 --- a/src/PIL/Image.py +++ b/src/PIL/Image.py @@ -1407,6 +1407,12 @@ def getexif(self): match = re.search(r'tiff:Orientation="([0-9])"', xmp_tags) if match: self._exif[0x0112] = int(match[1]) + else: + match = re.search( + r"([0-9])", xmp_tags + ) + if match: + self._exif[0x0112] = int(match[1]) return self._exif diff --git a/src/PIL/ImageOps.py b/src/PIL/ImageOps.py index f0d4545badf..b26b1858b93 100644 --- a/src/PIL/ImageOps.py +++ b/src/PIL/ImageOps.py @@ -606,5 +606,10 @@ def exif_transpose(image): "", transposed_image.info["XML:com.adobe.xmp"], ) + transposed_image.info["XML:com.adobe.xmp"] = re.sub( + r"([0-9])", + "", + transposed_image.info["XML:com.adobe.xmp"], + ) return transposed_image return image.copy() From db20d0f8feaf2928ef68791e7e1fdffc8658cd9e Mon Sep 17 00:00:00 2001 From: Alexander Piskun Date: Tue, 26 Jul 2022 00:45:23 +0300 Subject: [PATCH 2/5] fixing typo in filetest name --- ...xifool.png => xmp_tags_orientation_exiftool.png} | Bin Tests/test_imageops.py | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename Tests/images/{xmp_orientation_exifool.png => xmp_tags_orientation_exiftool.png} (100%) diff --git a/Tests/images/xmp_orientation_exifool.png b/Tests/images/xmp_tags_orientation_exiftool.png similarity index 100% rename from Tests/images/xmp_orientation_exifool.png rename to Tests/images/xmp_tags_orientation_exiftool.png diff --git a/Tests/test_imageops.py b/Tests/test_imageops.py index 855b6bccd6a..95b49596e79 100644 --- a/Tests/test_imageops.py +++ b/Tests/test_imageops.py @@ -352,7 +352,7 @@ def check(orientation_im): assert 0x0112 not in transposed_im.getexif() # Orientation from "XML:com.adobe.xmp" info key (from exiftool) - with Image.open("Tests/images/xmp_orientation_exiftool.png") as im: + with Image.open("Tests/images/xmp_tags_orientation_exiftool.png") as im: assert im.getexif()[0x0112] == 8 transposed_im = ImageOps.exif_transpose(im) From f42e2552068dd3d6a02e1b544ff07abf08e77036 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Tue, 26 Jul 2022 11:58:44 +1000 Subject: [PATCH 3/5] Simplified code --- src/PIL/Image.py | 10 ++-------- src/PIL/ImageOps.py | 13 +++++-------- 2 files changed, 7 insertions(+), 16 deletions(-) diff --git a/src/PIL/Image.py b/src/PIL/Image.py index 816ea94db8d..4eb2dead655 100644 --- a/src/PIL/Image.py +++ b/src/PIL/Image.py @@ -1404,15 +1404,9 @@ def getexif(self): if 0x0112 not in self._exif: xmp_tags = self.info.get("XML:com.adobe.xmp") if xmp_tags: - match = re.search(r'tiff:Orientation="([0-9])"', xmp_tags) + match = re.search(r'tiff:Orientation(="|>)([0-9])', xmp_tags) if match: - self._exif[0x0112] = int(match[1]) - else: - match = re.search( - r"([0-9])", xmp_tags - ) - if match: - self._exif[0x0112] = int(match[1]) + self._exif[0x0112] = int(match[2]) return self._exif diff --git a/src/PIL/ImageOps.py b/src/PIL/ImageOps.py index b26b1858b93..48b41d87fda 100644 --- a/src/PIL/ImageOps.py +++ b/src/PIL/ImageOps.py @@ -601,15 +601,12 @@ def exif_transpose(image): "Raw profile type exif" ] = transposed_exif.tobytes().hex() elif "XML:com.adobe.xmp" in transposed_image.info: - transposed_image.info["XML:com.adobe.xmp"] = re.sub( + for pattern in ( r'tiff:Orientation="([0-9])"', - "", - transposed_image.info["XML:com.adobe.xmp"], - ) - transposed_image.info["XML:com.adobe.xmp"] = re.sub( r"([0-9])", - "", - transposed_image.info["XML:com.adobe.xmp"], - ) + ): + transposed_image.info["XML:com.adobe.xmp"] = re.sub( + pattern, "", transposed_image.info["XML:com.adobe.xmp"] + ) return transposed_image return image.copy() From 7e1261c6a0001c2302d391da24a44e2b5d669b57 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Wed, 27 Jul 2022 22:18:39 +1000 Subject: [PATCH 4/5] Simplified test code --- .../images/xmp_tags_orientation_exiftool.png | Bin 1935 -> 1258 bytes Tests/test_imageops.py | 16 +++++----------- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/Tests/images/xmp_tags_orientation_exiftool.png b/Tests/images/xmp_tags_orientation_exiftool.png index fb30199c86acbc8953d1cf16ddfa9e3ec41ece19..10f0f44009ae9237c1a5712ae8b0c7269b527711 100644 GIT binary patch literal 1258 zcmbtUO=uHA6rN($novXq`-gO`;GVjFO|jV~DKV)grKy@mnu=s}AL+KVR@ylDkNREki%i75Ie4RNh42p)E4-uJ%wX1=%ccJlDR z!FpG-3n5e=jfCSclDVsH6THt0&mY22n+?W-2+dt^f0s5wOr;|67(%7J2u++t=o>&2 zpAZ`75Ly~RNW6+rgFf@%hz}B5^vJM@kb4JtYS8pdBSIUN>hyjw(_Xi(;=WXA+v0r+9(!cxVtY(it%xK2VW> z$WM=1mM*evp-^B79gJpVS>EgQvYfyQLOU?p&7x{acDris0R#cAkz!yu5IE?+fSxe5WW0qtbW=ROn6y3mP*+Hj|{R<<9 zFN22+8AItwkpmqSq7$nUlV9m7e^a2<#IoWG7f<4zI;@g8x-E zxX)`}5nIw7MFW}`GO%Q62D!|E^2b(4NOdp*18!F{$oUBt)6#OL7?vy?5IEi=@|?(Z zQCugPbakz)b8yx)vvMtl)CbuW$7~h5p9Ta4^x>bn4=17usDH zT3r0`vte^Cb2518`jfjiw?`gvp35)47H2=-Ug&G7ZR_g`-q`iNd)u*RCw8(;^K;YQ zd#Q!D?rR@Ed}*yunypi9$0x50ox9&W*uV6q``sOWs(rcjMGfBC(%^no^pHPFw09sp IyMN@&FNzYMoB#j- delta 1598 zcmV-E2EqC236BpYiBL{Q4GJ0x0000DNk~Le0001h0000$2m$~A09~}`C;$KfiIH}Y z0y8j^2mx)AVgfFcxdIFjI6NP zABchm#igLdQV_MYhS1}}ceuxJ-!x4x$)%}}_nNA`++E-A``oWw@&`f)xKR{^Kk=`{ zvMm0@L!9ZP^!!k*e>iREVSv;jQ4VMt0J7gTwve#}S%Vup7iHfX4->MK1VB%+#xrehZ4r zj6pG=Z=(0CK%bq6(}37Tccsrx#9%;lx_4XC_}U+~q4kW~e}?`U5QXlXt4KDPUo)b% zA#wwR>+UUj&)E*=F0pI2QP}Wjcz9TNrWAqF_iX8GS&E`S2oXYtVc3#Uxm^|X<%Dn# zB3TKmsv2H>g@Lmynwb7+SynEW8yOjyn3zBa(M((`*0TslalU_vCxRnDi0%OjvaeEA zm3n{>N+y$pe~?zI)o!;f%c70fZto$ZK~yLRi-0h#-dAIH6l7nesw#vqm&;|d*|oK` zN~NOf`u6tr)YKFW0(uo|RcD>~qd`USH{?9q?T*@uURY1cv1LkQIl zXyQa7Q79Cu)#}R1imvM+)dv6^9v*^kU+uv>WS+k89RWP`^XP3H!zKU#LO3}&S+CdG zc9h9vYPA|6#QrC>VQXs(0B~?{;H%C($>;Npe@3I(Z1z701TVzAo4jMi1it-veSK9F zC7n+1?(P-}g-j-+Xo}O-QZZu81y1L5e^D{Fu_xJZ0<7Ts|s%o)VJUu=2 zRp*|h)9KsWTd{faBNt)-{H%o-Pf6A{u9rJ*6Izz_^72AQ2s%7qj4PE2{a|N>e=%;i z+oe*eR;vL3ip8Sen!B>FurNM8Ua!}?EySYU3zD00F>l7n?dYGm9ZiupWMaM}Mv=E9 z!yxQbM3`;#F!#Y7=OJciX9*#>T&`3q0RWDVkIUthZ1v2W@Fc`U`j z4?dPcVP~1a@R-7O7R1hI?e2wYe~mFtr_-%gE0s#oeLyyiYpdsP_yV_1<GKjeejT)4{Q*OfugXxfz@V1O$F zE2v-Ov6PsR2E@#eeM}+ln*2KczOsz{L)y?ETwdD8ej#m$jvlYAWD`jn#Ny+{t?UKT whVTS@b+O}O>4aazyu90yowR`mUz@W30osfJ$oL$>)c^nh07*qoM6N<$f|I@g`~Uy| diff --git a/Tests/test_imageops.py b/Tests/test_imageops.py index 95b49596e79..bd5f44e5008 100644 --- a/Tests/test_imageops.py +++ b/Tests/test_imageops.py @@ -345,18 +345,12 @@ def check(orientation_im): check(orientation_im) # Orientation from "XML:com.adobe.xmp" info key - with Image.open("Tests/images/xmp_tags_orientation.png") as im: - assert im.getexif()[0x0112] == 3 - - transposed_im = ImageOps.exif_transpose(im) - assert 0x0112 not in transposed_im.getexif() + for suffix in ("", "_exiftool"): + with Image.open("Tests/images/xmp_tags_orientation" + suffix + ".png") as im: + assert im.getexif()[0x0112] == 3 - # Orientation from "XML:com.adobe.xmp" info key (from exiftool) - with Image.open("Tests/images/xmp_tags_orientation_exiftool.png") as im: - assert im.getexif()[0x0112] == 8 - - transposed_im = ImageOps.exif_transpose(im) - assert 0x0112 not in transposed_im.getexif() + transposed_im = ImageOps.exif_transpose(im) + assert 0x0112 not in transposed_im.getexif() # Orientation from "Raw profile type exif" info key # This test image has been manually hexedited from exif_imagemagick.png From bac83f7dd3ac738f8bc16a6647f69f373916ae2b Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Wed, 27 Jul 2022 22:27:43 +1000 Subject: [PATCH 5/5] Check that orientation is still absent after reloading Exif --- Tests/test_imageops.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Tests/test_imageops.py b/Tests/test_imageops.py index bd5f44e5008..01e40e6d4d5 100644 --- a/Tests/test_imageops.py +++ b/Tests/test_imageops.py @@ -352,6 +352,9 @@ def check(orientation_im): transposed_im = ImageOps.exif_transpose(im) assert 0x0112 not in transposed_im.getexif() + transposed_im._reload_exif() + assert 0x0112 not in transposed_im.getexif() + # Orientation from "Raw profile type exif" info key # This test image has been manually hexedited from exif_imagemagick.png # to have a different orientation