From f26d138a05f8cf0b486fa56155b8354f2154e5bd Mon Sep 17 00:00:00 2001 From: "byte[]" Date: Sun, 1 Aug 2021 23:19:20 -0400 Subject: [PATCH] Add initial handling of ICC color profiles --- lib/philomena/processors/jpeg.ex | 37 +++++++++++++++++++++++++------ priv/icc/sRGB.icc | Bin 0 -> 20272 bytes 2 files changed, 30 insertions(+), 7 deletions(-) create mode 100644 priv/icc/sRGB.icc diff --git a/lib/philomena/processors/jpeg.ex b/lib/philomena/processors/jpeg.ex index 8cbff441..e4dde2ff 100644 --- a/lib/philomena/processors/jpeg.ex +++ b/lib/philomena/processors/jpeg.ex @@ -23,19 +23,38 @@ defmodule Philomena.Processors.Jpeg do intensities end + defp requires_lossy_transformation?(file) do + with {output, 0} <- + System.cmd("identify", ["-format", "%[orientation]\t%[profile:icc]", file]), + [orientation, profile] <- String.split(output, "\t") do + orientation != "Undefined" or profile != "" + else + _ -> + true + end + end + defp strip(file) do stripped = Briefly.create!(extname: ".jpg") # ImageMagick always reencodes the image, resulting in quality loss, so # be more clever - case System.cmd("identify", ["-format", "%[orientation]", file]) do - {"Undefined", 0} -> - # Strip EXIF without touching orientation - {_output, 0} = System.cmd("jpegtran", ["-copy", "none", "-outfile", stripped, file]) + case requires_lossy_transformation?(file) do + true -> + # Transcode: strip EXIF, embedded profile and reorient image + {_output, 0} = + System.cmd("convert", [ + file, + "-profile", + srgb_profile(), + "-auto-orient", + "-strip", + stripped + ]) - {_output, 0} -> - # Strip EXIF and reorient image - {_output, 0} = System.cmd("convert", [file, "-auto-orient", "-strip", stripped]) + _ -> + # Transmux only: Strip EXIF without touching orientation + {_output, 0} = System.cmd("jpegtran", ["-copy", "none", "-outfile", stripped, file]) end stripped @@ -85,4 +104,8 @@ defmodule Philomena.Processors.Jpeg do scaled end + + defp srgb_profile do + Path.join(File.cwd!(), "priv/icc/sRGB.icc") + end end diff --git a/priv/icc/sRGB.icc b/priv/icc/sRGB.icc new file mode 100644 index 0000000000000000000000000000000000000000..832579f4225099f80e6d519280a9bf9cb71d03f1 GIT binary patch literal 20272 zcmd6ueRSManaA&B#szCYSltzngX1m&a!8$)*4Dn!rmsjzUs6kJv(_Y&w|6y2kz6kF)hVk<4B4dqmU8?P}*W`6hH=RR-uxzBy>bAQ*lWtpz#?m{Z#Tz9T7zjASHdd=Dorq4U&67DkR z{~DVMz4MkYUuvaF->07!wElir1ForW`||O}9=zm{=f3yFO^d&OeRHKAvAPSgEd{|O z(yF_%xi{aZ=LODP*t@Z>SI=*LO!aSVZg0%$`58T5mluP2{tfj_{`sQwd2X}k%X!YP zS~=gjizJmxx5b{DV$aR(`EJ217tEF2Eq#r8hW4UtcUH76-sjxxzV5F6z&{dJx8y!h zuV3h0?h0KEA-Uq9$va%D@G zf8L?zV=V^1*}2qUYlpADP0y!W^Zxl`&b=YmX7Igw{`YpP*Y}?^wD)_MoSvWS5EcEY z{=8WohVynk@92=U`WuiqnGMFzb$b4KXOFL!?#}-~m%(gx?u}KsCSNbQZ@i<|=t{;3 zDMm?u!a1RyQ?J`3hz{2#JbkJIx}YcOn)TZun4D_nxm#U-u?<=+f-qX?V(p9S z-KGBy!GR_1vi`diWAiA+(4O_seO`vFyV^CXf1jx4iyY>JrOnqB+;Y|TCq5<|eePwo z1J|xksr3CS(<|p;dR(`j2Yp$P>U~0-<=pG4?-1mmo=@mGlm{e3qt`)B?ak6yXhFj# zWGkD*M_kwF5`Cnl5%k8d@!#pGX2mD^K-=xYJs|981(}=l+osY#i;IFj9s0DXF7FoT znX%xLE}@wAy$WjY6Zec7bm$2cFm{ScPXEw_yZN4We58RYNV;}WIw_b=Y1k;|lJ_JJ zC!bCpb7_4)sqX{HgUKh8N0N^uzpc`4{q9fhOzze5PPOe!ep~-LlaD6%B_CD`J*Y4C z7p|vN^Qc;mCJ%uz`CVUgK$s3D_o~eIA@z=0_N(o%YIX{KZ}N%cbIJX}@tA)WWntQv z+^)8xs$VEMOuv<^@`R+vCY!v*gUwa8Nz=4hZKb(E9kT};&UzbJCEa!F6SqI+A2z^< zq{SQa@TBUxJY1jGGb7cf|9-bYc(7x}tV1QnqDN1RXuo>q)xN>k0Nv^FHEKK=>G+Hf zvv7QAqd9FJ06Vdn9kj!YgopAu2}gNxFjnI)OS-fh(dTTsHh5coLgc$k6Da7+>o1qR4pTY4UC`u|gV5`>|{DPr$T^)@i|w2#yi&6I55(+-4rr zlNs718m6sA;iMKD@Amb`hwRL6yh^8j(OGX%@=d<2O|@CoVo&sF*BExVpZbz%$h^)k z1!q1C?}z0f&46HOX%v^#C+(7JKb>@hL};`4Y=Sm}k9khsG7mZ{I=GB0Fa&J1TB%siC& zw@gpV&o-XQEqn3Zoyq0OptR0g4!>K(D!wZJyy7V({=$?n~*6-!R z4MVf`H03(YWu4i_gOng{08LPO(SPgy`TS9}>U|~Qq?~oQP7ZR%R zHjM1ulmr!4!VX`?OVHm+jh+&otw&bY;rlG`nzDHj=fhS38{e^O)P|UTS)t0G z{SQ7j@;?LKE`pDV+sI4qKg0{VHUER1(2lR`iPcA%4?eP8P?1Lp955eBSDg{npsPQG zhlsk_%UB-7YpNzyo0^lVb?MX%skwSukeZ&FnOdsyywqfsC+RaKH8nL`H3l~$l}XJI z)IwJy$mu|+ZF*{&;HRorZEAMvCbfbwqmuf@>gJ@b7oCjirl%JBw&|(&6~}z+EVc-& zN7jjt!s}pVX5sj2vr*ddi&^hAu@vS>BtK*RdeKs_2}NJ2E5vOkwZ?NfDz{2&Qd9Lk zM{>+8O24uw{S7Kl6W_>$^gxx$@7uJ@Z}Ar%$boe&%`ats3KpzNe-0Hust+W%*8BC2hS=S_sy(x@b+4Q~t@1JG!Gh zMZc4zttqm%n$)sUZTU87a8^;zrFIl_KS}LVQ}6XQw6rtZ{Jqcpa>KoC*Ve!ASHIqP z3SZng;lAZ7-+R}odv5-CuH{p8r&ruu_gUHow&s_#&8Ln1x%NQ%i}u}x*6Szxszmks zwHN&PnKQ3mt3BQqoqPRLXU_cRSI(Sy{j1tj{@A$#_eTAD?sabZFI2xRs=M-UwYUDH zbN}$2sIKX2&ON@(xl4Z9+n8_kbdvh6YHfAy*MF})+FIw{a$I}9b+)Hg8}06^FF3dA zBhD@Tu5*8LzjId!{>=^9j%M32YI7=}i}cZ+&;7YR+AI3mFZ4O45A8qG zr&=HJ>@L*jHGPC5QKet)2@~wUwKq>(rC-4(X6bi=taqN~>O8kzR;E3aM!i|K!}^Oi z#zwJ&`R-=7NHEwLmY(;1I_qi#jh`f{YEda}|1G1vtTrp`>>P=fyYvC?QsILhHV*uJ zmvQx;pE}RkN`1pwuP7K_dD&*uDCPn6BJ#8qev+H$rsy+O`I;yFS#?8 zcSuSX$)_yuQ1vCL>e;Lxy{cW>!?#-Ap-Q=w>Psx|kjzM}`Ig+`S`F@If;29--<9=dL|wxr5}Ob2WEZzMyK2bDG!#lGIhnUantb`GTrD zoSXWLg?3v* zZLPLg(CGHb&%p=lcdM}Vix!b;sYMc3n13|r8&$$`^PXGa!w#L;lsV9*f7YS2<+Jn~ z*>9nYH=<*MWtJfG0%>%$EYf7S*-Hf#ur~`k(y#-y`2!Uq59}Skyvb`64Ix>hAT5Jq zt7<7EaTGcOyJd8OM&kT}g(#ENBEko^#$hpQ=dSbg&>&fqe(8XH5GA-9t5vII#8|b7 zv$pZLEI4vHgYmzN$LQurcC57?+F& zV+F)S)h_jI?C6N?8M6ROY-{6^ThUmHiw{W8i`vxHSl4(GSes{boLDAh?fD%SONQZVpx-mIgWnd z*7$}$M&2|UEW~WUAec8;H5jmI^u9_ZG+MqNrayjC9yalI?GST5&%#`bXF~D5SR=e> z?;*G#H<02-*$>7C&tZAb@|j?x68F@VX9BYJCe{k$$CO_kP)tsigB*bEWi4JO3qyw1 zcn`C~G*vziqBs|yhMzp4-kp*t^2TIC$jRU{Z6^j!R+bU(Yf34B5kCE%LlTdOS0Eyt z1^Br4PP^5Kw<{-u-!x9~F=!sU=IU&&I+1wV$TrKq9ty{HfOsfe@?g}dGHeKn`DuR9&ZO=e_i;@BUH38$;|lo zi5}|!R*uz>Tj-ZI8ti~i?q+v3k4Rje~L-Xi@Rcc^V;}fOL`02@NU+U8A+bFK^ z8gYJzYKeMHdN{VI?%a{AWi=~Xr_G6t!o(?=*;jzyC|)cUW)-Lu6(A!kSG}aPc$o3X zmhs%`_wE*BqB&rRV$E`boi0*sUY1wN1Le5=*{YWJ+95s%8cPyi?MT>^7FHxJ0wM(1?tbP6|dPMp3Mf463rsJ?Q^7+aZbk`)ydUYI(#{gyTK2v%YXrNMBC#!b#sT;Vb1J$O`1+(%N1@KPi|e^~71^(?wkzLX&Zi zn*2L2aX4o@q`t=l&8g#V&(l7%m)zw!1EtD@Vlj!Q%5icqw9iBDq6P!DgP+=u-|hfGtCRx3`b)YJ52D zecZ>jVK-^sp1FmGBVzeuhFLp5%Jhb24u-_-%WZmjlKQzaxh;2fH2&$a-Ko=Q^Eyyq!EGt=g{7P?D zQE-!u#loU2gGHj|LyR^!SpDOf24YL32>m&gWQFfgJZ0JdtF5H*h&IY2Y!YR#7%vu~ z*ch-MrZ+8U0&59%mGcP(PgDx8|I>Veaq_b0SSBHos$45J;%J*V{#^M4#?16)C-da4 zZA3zJU21)%b!IMHoGotv#%S!~83W6LgJq&%#qV zM;3}`6B{FHwLTU(vd=Q^qijKqb^@Hq0nOSIaRVl7%+BVJ1KKC`4@|J#8Aa|Us_p}N z22ZyiC-f4Jd&zM!erS(3_C2k4)#t%FYN1oDTA?fz2o|F?(&kfr~79$T@JPPt2Q>b)D_a8|`uv=LyF0P2E20 zL0oTs60fj9{fYdI62673!g#jI=vJ~+)hm;M7J)zm%r9nFe18PRxGmy4ZH}3&k^R97 zT+)sOkiEhKn`a9C(B7;-Dx+$-P^eNyON?J+H#I6@Gpm&wJ5Ml`b4aEYcqP|PehDoF zUl1}j%mv=sA!CH)Kv6sLB3`H(cgRqhFEYG91WST1EQma=W$8j*tkPRm=J71=MI0f^ zPbZ)JOM0;+kA2J+U&r!+eI5ZfO(jK?io0R3oUcYe(C5z7HneRz=fT+B|*m zpX~Zi3%*I^xPJl?>){&@htAvlY^4|P$MOameMY1aTbC-pcvvhDiOcC>Wwm+-yk?YN zbc%M_M;rd2f#AuIh@7a&9Y&{I_hh z@?OE=O~?V034?lkzF4FZKkbCKu~un$8GBFEPHI_i(O>Xr(K~^76!;+H0k+7Kn(W3s zExdaT7VHX%=w)^rc|L5hepCYd43O9_r&2_I;OESP_`q7v&P&{a8QZ`S(Gc?l3x%VA zFK`y=uo4HHTnBx`X|pQO6Is!f={ERIW-9bpNqM&tU6hXw^A{e?L%@xVa9go2xg~fH ze3};U)8(3I5+u-!3Y5ZFGB?@hg|&))6UTXn(&UK8>dd(E9S&>QzvyFYY5eqwoe*9W zozoAQ#dlmFws&n{ZhJck_kc~j#o)L}jau}O10~qO? zyaBSr=NK5F0;W>CUg}|q?Z~bYdso`Yw8^faV<$gwfM3TOSu|F@M>p6Ikr`F)0fgP9 zjh^M~@lm$hf^R$5U>0GS=jIA3(Y}Tfcv-=r%&x}b^&ofL>aj8Mw`c{erDNx#LI1&< zQVx>Z7@Ob0o}mPW52t>x=kW1^m%H@AE4M#A{OO@tPspDh|H+Pp!)uNnaOuPE z=l$KG+rFRKIZbqnc5vY6frC)kk=gg#Kxa>b-tX-j+CIEy`-^^sF75{m`|}M)zA@av zo4%~PkGlO^_HP~1TZsF9^UR;cDeZpiQx6SS?>QeShQ9XP8hY=#SI;UJ-zV17_SEz5 zgR6s2A3iRsiQ$eoj)Upr|2WjQ{ehzg_8#+`gmFn9NgRF|su6u88Cu}dKWcbBHT+?h ze(Dn8{j|N4EKXNR&tp9nCoivREQm&IugY8?1|q&7f59^r!dT%q{0Jp#eaYTD=B;C5 z8D<^6m37zVl;PpM4_44_Uq9Y@+2J0j;5RI4eL(Lr>TSrxW{)X4YbNd$_QX0bNuVBV zk`?fQvdE1Sc`P}r9!Q3SEy5B>jkSh%lZlnt7v-g^je-t71YRw2lC*KYOEwSpE(bVbjMta?+1*g-u98)@VwDW3O)R?`1d$f9z&;`@8bSI zaGWOx>CjHFEA(umZhegks}ORIwI4|!lUU`=-wkS{HtE^(EB}J_xUqoF@e)~; zS>J-(SQtAAupwn>ro?hY>|p83iex)Vd#4DUn-7N{{EE>4hmG%eRtLq(t5x6x56djE zH<|FIynhv1Lp~9|g=9bXZRYRBu4O>MzxibJLcAKR3LlG}A`Q@L8h~zqrx!5TGW1zl zY=mtE8&NMb7PMhlZ6t|aZB2>r83ioTJac?SeW@ssy%P}fBl3TK=Yei)Jq(c(mJle} zbFPS?bp0ci0J0EkMLT$oNa_~dkF+(471vfrJDo&J=+bN^V2f)hzRvNMie;~Cm4dEm z-RvH1hB!6S25~PE!cW*$@(gSxTV?#<(|WNspHPYS0fH8z@sDTo3dK7Kf5vqBz1r-J+bcEZSMelgvqmC3a;%m? zr362b9b@_B77H$T>he1i=2#f{FyEk9YP&xd%*1otMd2RGje67ndVkl1I~aBoBitZa z=5G?*l$xnuZkJ5+-`riPRf)SRGyHu5ZW3_wWEpo0#Kkxk?O`f-cIy32myD;#eUKaU zSuET)rDmyZvObrn#O;^4`kl&Cv7Y-g@Xbvb-Iy80G+Xx|GJ@v*3^z--RTFMea3=>D zr`T`N@6?FqG{H{t(%MZ3ZqtZ2eV{tWW0>l1@XSoDP+j0~5wt~Xj(&~jIIXEj;jWS0 zv3s=Lf$hD*I%6Y@Jrvx#MGcJy=ND-iO!H49oyX`?)Dh{a4Ts_kv}*P59(pu zLU|JUQ4Mwz>6IHlOI3?KA=47wS*cTbv8ccqZ83ckYfCQf5Y-Cu25|cOLZT&YjjkD~ zg`N)Mdb6jexVU7*!HaBIgKWcN&7c!KNlJas@s>2(a{xA^MIW@ym2}fYAC8#?wO%qt z8C~C?R`^G+6VG}Z3j0|i7_-vJ>buZCN4KQ7qr+XP>E2%7g+^79W$8xGJA|K+nCox) zK=pE!)~F6X(f0x`i}7Rnnxl5g^kX!sMFW%dZE*DUx75@sPoVGenKoZ_(|n7~fw-?g zl62}Vsf+c?c$y?e5&a>Jw>A9&3$D1mP7{Q2i1nJa0*4*L6?VSJ!%Ss|m-! zMA6V! zS;uoH7NwG><1H!T4^|R(6ukR6j;Gf8VLP7+-g>mn;#P~Vh+kPpS+ALuMCAP9?T8L( zDScNi>|jm_j!X;DTR4eiCvjS(5Qp<-C#P<<*RX6Ac#(!2FlSJPFTj;*B1i)?=XY>~ zF4(KYqZ0HBZ6q_^i525JL)+`1OQhr6mA$mZ6(N&ou{^7?!Ik1O{RcixW?+NPEN^D_ z@!>D#;Y2OSY5E0!u!mBK?QGn1pY~i5m5@1vt5cE?yP#y}j*-TRlh}=R%HHg@W3aR? zL9?T5RP5a4Z#2efY7UHRRTigKvMKC@_^h?$HYByS2f)5_dUtwKV!ci;CJ7dL7K7R? zdMuq&p|GN2iM$WVSaNE|XuqV7tR|7scii4==fHcA-d=^jyMlyv#%+AE3rBN$4^}+A z1FrR9v_|i43WsH4Sn0{RSfm$O+|@<<;567~FgQ5*A}b9iS(WqnJ&gnyUh>vhdYXhK z8U;Hu>sIbzy{`*rn2`+yiev!0d^Cbq?e=(FSJa7C;vF8QU!^w9N84ecSIbaZ1Z_4B zM&i-vEQj$Sqd!=b!la6gf@I_@{x!jY5B-4gC4KBXj{SwCKkFS>tw~zRiAIesMl*?FdmF z5yM=+;=!rOU=T%4(wC;{{8~9zcY7!M)$eS#fmvg9A6ir`c4mE_?jz^3J!!c3DE6&ZP)+-)ZY0u~Mys&gJp)E z#ifTc+IBBlQMKx#)qhUv7L~cZZ0jyJ_=ryJzVj0O!WDdmRdlB6h}lDA8tAgl8g0`c z>#Fgmdi7@|CN3hXW39G0WwP*>%RAk#@bE+nyoPbj_%T|lK8ibKzopTrB0|A0l75K4 zO{WV?5|zQl*q}9@OCppQN0L*mQ^aM6Uo4iU&)BHcqB^?`?jvg7cdmNR(8x~g%x=4^ z{~Ej9-H*pwq7&Hk?PNm7+Hrctt*ff1N(VD0`h|<`tg-T$>bg_)&wA>% z14-9S7}&b(Y3_W-@B!{GdnoZ=xw{~L(^N|Q{TICT5IjV);72P?rpba zhcZ>sZT9|2AAYelx9aZoJ3iNQ*LUuE@Jx08HFcjA<@4_P*1*