From 36b86ddaf38bd95bdad0f6e69a8b096a7865c861 Mon Sep 17 00:00:00 2001 From: Oliver Duis Date: Sat, 31 Mar 2012 19:02:42 +0200 Subject: [PATCH] Clipless and fast DCP color profile engine see issue #1295 --- rtdata/CMakeLists.txt | 2 + rtdata/dcpprofiles/Canon EOS 20D.dcp | Bin 0 -> 1506 bytes rtdata/dcpprofiles/Canon EOS 40D.dcp | Bin 0 -> 1506 bytes rtdata/dcpprofiles/Canon EOS 450D.dcp | Bin 0 -> 1510 bytes rtdata/dcpprofiles/Canon EOS 5D.dcp | Bin 0 -> 1506 bytes rtdata/dcpprofiles/Canon EOS-1D Mark III.dcp | Bin 0 -> 1522 bytes rtdata/dcpprofiles/Canon PowerShot G10.dcp | Bin 0 -> 1518 bytes rtdata/dcpprofiles/Canon PowerShot G12.dcp | Bin 0 -> 1518 bytes rtdata/dcpprofiles/Nikon D200.dcp | Bin 0 -> 1502 bytes rtdata/dcpprofiles/Nikon D3000.dcp | Bin 0 -> 1502 bytes rtdata/dcpprofiles/Nikon D3100.dcp | Bin 0 -> 1502 bytes rtdata/dcpprofiles/Nikon D3S.dcp | Bin 0 -> 1498 bytes rtdata/dcpprofiles/Nikon D700.dcp | Bin 0 -> 1496 bytes rtdata/dcpprofiles/Olympus E-P2.dcp | Bin 0 -> 1506 bytes rtdata/dcpprofiles/Panasonic DMC-FZ150.dcp | Bin 0 -> 1518 bytes rtdata/dcpprofiles/Panasonic DMC-FZ38.dcp | Bin 0 -> 1518 bytes rtdata/dcpprofiles/Panasonic DMC-G1.dcp | Bin 0 -> 1514 bytes rtdata/dcpprofiles/Panasonic DMC-G3.dcp | Bin 0 -> 1514 bytes rtdata/dcpprofiles/Panasonic DMC-GH1.dcp | Bin 0 -> 1514 bytes rtdata/dcpprofiles/Panasonic DMC-GH2.dcp | Bin 0 -> 1514 bytes rtdata/dcpprofiles/Pentax K200D.dcp | Bin 0 -> 1506 bytes rtdata/dcpprofiles/Sony DSLR-A700.dcp | Bin 0 -> 1510 bytes rtdata/dcpprofiles/Sony DSLR-A900.dcp | Bin 0 -> 1510 bytes rtdata/dcpprofiles/Sony NEX-5N.dcp | Bin 0 -> 1502 bytes rtdata/dcpprofiles/Sony SLT-A55V.dcp | Bin 0 -> 55294 bytes rtdata/languages/Deutsch | 10 +- rtdata/languages/default | 10 +- rtengine/CMakeLists.txt | 2 +- rtengine/dcp.cc | 458 +++++++++++++++++++ rtengine/dcp.h | 76 +++ rtengine/improcfun.cc | 2 +- rtengine/improcfun.h | 4 +- rtengine/init.cc | 3 + rtengine/rawimagesource.cc | 37 +- rtengine/rawimagesource.h | 5 +- rtexif/rtexif.cc | 21 +- rtexif/rtexif.h | 6 +- rtgui/icmpanel.cc | 5 +- 38 files changed, 605 insertions(+), 36 deletions(-) create mode 100644 rtdata/dcpprofiles/Canon EOS 20D.dcp create mode 100644 rtdata/dcpprofiles/Canon EOS 40D.dcp create mode 100644 rtdata/dcpprofiles/Canon EOS 450D.dcp create mode 100644 rtdata/dcpprofiles/Canon EOS 5D.dcp create mode 100644 rtdata/dcpprofiles/Canon EOS-1D Mark III.dcp create mode 100644 rtdata/dcpprofiles/Canon PowerShot G10.dcp create mode 100644 rtdata/dcpprofiles/Canon PowerShot G12.dcp create mode 100644 rtdata/dcpprofiles/Nikon D200.dcp create mode 100644 rtdata/dcpprofiles/Nikon D3000.dcp create mode 100644 rtdata/dcpprofiles/Nikon D3100.dcp create mode 100644 rtdata/dcpprofiles/Nikon D3S.dcp create mode 100644 rtdata/dcpprofiles/Nikon D700.dcp create mode 100644 rtdata/dcpprofiles/Olympus E-P2.dcp create mode 100644 rtdata/dcpprofiles/Panasonic DMC-FZ150.dcp create mode 100644 rtdata/dcpprofiles/Panasonic DMC-FZ38.dcp create mode 100644 rtdata/dcpprofiles/Panasonic DMC-G1.dcp create mode 100644 rtdata/dcpprofiles/Panasonic DMC-G3.dcp create mode 100644 rtdata/dcpprofiles/Panasonic DMC-GH1.dcp create mode 100644 rtdata/dcpprofiles/Panasonic DMC-GH2.dcp create mode 100644 rtdata/dcpprofiles/Pentax K200D.dcp create mode 100644 rtdata/dcpprofiles/Sony DSLR-A700.dcp create mode 100644 rtdata/dcpprofiles/Sony DSLR-A900.dcp create mode 100644 rtdata/dcpprofiles/Sony NEX-5N.dcp create mode 100644 rtdata/dcpprofiles/Sony SLT-A55V.dcp create mode 100644 rtengine/dcp.cc create mode 100644 rtengine/dcp.h diff --git a/rtdata/CMakeLists.txt b/rtdata/CMakeLists.txt index 2a87a74d4..b104fb3a3 100644 --- a/rtdata/CMakeLists.txt +++ b/rtdata/CMakeLists.txt @@ -4,6 +4,7 @@ file (GLOB LANGUAGEFILES "languages/*") file (GLOB SOUNDFILES "sounds/*") file (GLOB INPUTICCFILES "iccprofiles/input/*") file (GLOB OUTPUTICCFILES "iccprofiles/output/*") +file (GLOB DCPFILES "dcpprofiles/*") # THEMEDIR includes subfolders for image resources for some themes; doing the normal glob won't work. set (THEMEDIR "themes") set (IMAGESDIR "images") @@ -33,6 +34,7 @@ install (FILES ${PROFILEFILES} DESTINATION ${DATADIR}/profiles) install (FILES ${SOUNDFILES} DESTINATION ${DATADIR}/sounds) install (FILES ${INPUTICCFILES} DESTINATION ${DATADIR}/iccprofiles/input) install (FILES ${OUTPUTICCFILES} DESTINATION ${DATADIR}/iccprofiles/output) +install (FILES ${DCPFILES} DESTINATION ${DATADIR}/dcpprofiles) install (DIRECTORY ${THEMEDIR} DESTINATION ${DATADIR}) install (DIRECTORY ${IMAGESDIR} DESTINATION ${DATADIR} FILES_MATCHING PATTERN "index.theme") install (DIRECTORY ${IMAGESDIR} DESTINATION ${DATADIR} FILES_MATCHING PATTERN "*.png") diff --git a/rtdata/dcpprofiles/Canon EOS 20D.dcp b/rtdata/dcpprofiles/Canon EOS 20D.dcp new file mode 100644 index 0000000000000000000000000000000000000000..0dfc1c80b26d5219628e39e545d692c65c11983a GIT binary patch literal 1506 zcmeH`{ZABE6o#*WEQN%&YBZMC@S*VsZR2q7ji!yiJT8Es)1=Z_@MFfC%a$sbClFrCHn(bJk{#-si)63W!i za?Bq^Rw0QPS8kEM z9ucW)<_^^Avs6S0Q%D zpmPN@OudWWEi#5Xd2D{{v9vA}kUYlYdsC*`5lZpdnNl3H9#Kc0xPv|hAFmP6CjP3n zuX_(g%^YTjnAP#q%=3#9*ie{wCWj(=q8PiBWF>q;K=(XW-xs01$;m+Wo_ceIm#xlrYEak;Kc1!JX%X~)ZK#=_N@*$)|4w1B@~T2D6TAa zC$0_A=VS2885HL|VM(3CE+h;Hct5EMZDSN8XPwBnYOy?2ctj^~2&s(WxfQ#^(LFK!n3*(w5DZ(6ydN{Hz+Q_X7J){T$F(XFZfa z(f%zDE<8_Jn0af22u0hrGOU|&!}`mRfbDZ!_;8@m z61Q7G?{pazGrd~MO)2PO@E=Js(vn4OxV{>QujQ#HvnZziCL#al Nz1G}50i)d#{svuw-)jH> literal 0 HcmV?d00001 diff --git a/rtdata/dcpprofiles/Canon EOS 40D.dcp b/rtdata/dcpprofiles/Canon EOS 40D.dcp new file mode 100644 index 0000000000000000000000000000000000000000..98cf8ce0985b8bdacbb9fa5efcd368bb22c599b8 GIT binary patch literal 1506 zcmeH`|4-C)9LGO+aeOfk3q!N2O_S<_&h&!$EIF>!<8t}_r+X9AlEVEzI@)F zcgRT|9N0CtyouV>oXspzjNRw`VaqF>QFF3xEo*LNF@i|L(G9To-SzpwKcTJn_T2OF z{<7!$wfF1uS--x*k}3#7iZCxcOE7VIg)1+dE~Ig<=h_)I2ua-Mb4~txrjPUA;Rgf* z_b^v9JX^5xL)SP@^Yz$yeOO+ud#f(DeDk*4H3e4TJdc^XOb|w=@7;^JZz|!g;e>B4 zPVCR-*T?n^(ZqUIdSc#{lkodfjr_8hV)Z133_*w~HvZ@T$~#P2S4hbpzl%VIf|1lK zVvU)?I@N+s-(l4vQ>>`5BWYtPGp%|D4TE)9-fd%Igy7RAC(O|`+QCRyyze@1Urq66 zSqbya?8T4AWqi2qoZ4SZv3sZmgBOmn&%TkdN_N0IV$gz%JUH9y#I@21Z7kOx&(S$F zLoj}DsaE(w8}>DMkX>*~Jl-H9kne!MA|KhGctBrk#7JSE8jZN|&~FqrZ_2>;i<;v( zI?wnO$Oi zjw1)+_2^uALqSG+7P~68Vs{cjNlz7p;hhf%-HgRwD+ z^0l>6$E{uQdUP)1-%S5N9}Ei!K2IiC`(+U>nJ6M#2p;Pp;`BL!(i0vmZcxQ<=gU~y z=SE}7MQM3AjpyiWe1T$Ru#-*vK(MY_!D!_)+fkt4hFQVewJ)*fpCKS;xU6>E$(J!1 Gr1%GcX3mEI literal 0 HcmV?d00001 diff --git a/rtdata/dcpprofiles/Canon EOS 450D.dcp b/rtdata/dcpprofiles/Canon EOS 450D.dcp new file mode 100644 index 0000000000000000000000000000000000000000..1db7ee1cdf27877a6e4b6a0fc518f82228465cfa GIT binary patch literal 1510 zcmeH`{Zmv`7{?E=3kWI%IMCbVOK6dRCREz&{hGUI3=D7CP{|Kq$V3g$q_~T5_nvz% zYs=(FV9+lmT3P~*I#^01_uO@I#~MpQd2#Fyn{z#I*X+76Ge;k>?{VlFn{81!=dn(t|y_`YL(|!wy;{Gky z-~M>w;7R8=-{tQ^`DWOw>Kp3k<`us%Hz#+AgOHjuLJ}7d5_>xs4Ef|;!!xfNp0~vK z9yQbO$$NS8VvOg#4;lXNy3u^WkV1Phf`X8cLh(QUSLX2a=#R|SMv?XfMbcANHnyAM z`ghH^UHUkSTdd%hT}>z)Uct_Oq`u_jO}awy)2M`t6H5hOraOG@Cf9yNalYDt zOZ#P1EO)~{W{34l85=HdK@XiH9OY}}O*s)~%Vv#VOBngyjhg$~wNpK6xQ@xY(nTB? zU&Jo8c<{;IMnpGS*}6#umg0>_In$}BCn?^!0p5Ca7rGT*`L%D1QD;!JZWt1&crtSrnQ}D2%@T zJQ0nteG+aBP~;Z(+9LmO!+S$SXL~$Lo+YEo$LDMhYWwXnRv&IgM8vG2Ks?2cTQXYX z#s%dAW6mbO8K7`{wiN|4RkY|5b{=^iCkH8(kBT_h(=JTN5~3ez#&rKaEs>wsV*<~~ zTBtiZyy3n~F1gW+vEScj8G#nezv;xWHOblnuMFEJCxU4S+H>g?i%UeTdZR)s=jZj> zlM4EJpVj9)AcyOi+rjBKG$q24b5QDE~p!N zk@r=VAtJrMhB^3s2+hdkmAr>#G4HcqpHOiAQ;M3E$F((wDGp4_$SCU;wtFR9OKw5- z!_~sbUlKff6!gYa>fKJGj>&a>6t5SR>EZ>7i5!Z)h7mT*D0&z2e_(CBR@cD!Lki30 NVPS9vMSF^Ze*g_A*aiRq literal 0 HcmV?d00001 diff --git a/rtdata/dcpprofiles/Canon EOS 5D.dcp b/rtdata/dcpprofiles/Canon EOS 5D.dcp new file mode 100644 index 0000000000000000000000000000000000000000..11fab1900f942ab57ab117dae03236c1fed6eed3 GIT binary patch literal 1506 zcmeH`jc*i17{*81B9s6U)SeKLD*aGXb3t0<(%Yxl4-17JaA~21Dy>F9Di#gU?)7eG z_O^Q-O`#!B^iXUAtxDUVjbcA+#8rh=4(`?DLIfx=4xJ}sXP!z?$SI-)9t@|dNuw%5KrPX z4`{j*m`C!orf)P3YxB{5qjD?vy|Qn4zRkWoGmnt-CPMB>Bjl$)B9W;3!n)gj)_vJ3 zeZ419_v17Ae9~-v{K!MP|2tJ%BvD2GM=uIOqKel4{9ieT+QoTl;fxa#!wiv%P5$mr z>(RN(g}}94ith)8fzu9LjB8Q0X1TG3@ko8qtX%Xmto+D{ZfV>qy;K{!cY~=}#FDRj zusU6YoXL=|q6^_?L^Ku%xV-!J(8lK}sx5W6OBuSd z`jjL=M&C*&?0kcwPK&rwbr7Du%l^6!ikz_nSn<8bS~x18^Mn(-7gXcyDi+Hzcn?Gr zHJa3ABMjTNQz##ID|a#|j(lE^(e{3Syj{SC@j9$6dw|Pn6>w_8f$2~d_6A>%X>;MLG^&)$VtA+70bq~v$pk~$ume)F=x;hsap|TDx!E>6 zIilwnJZTa!7@U`r@SYpxZ!+8*Xh-&Gip?(wFl{R4c8t4FnaabLI_WpJ3&<|#aisrS zr6nxK_GR$Yd5Y4}66N7@5{44$k^D<=aPcCBO4}h!wJfkEB~#?DuY>n`tF_~*fW#^% z= JpW=QC!(TKR*%|-< literal 0 HcmV?d00001 diff --git a/rtdata/dcpprofiles/Canon EOS-1D Mark III.dcp b/rtdata/dcpprofiles/Canon EOS-1D Mark III.dcp new file mode 100644 index 0000000000000000000000000000000000000000..0bbaceb2cda33660acbd0c9ba93ce240f61dd986 GIT binary patch literal 1522 zcmeH`|4-C)9LGN%DhF1OLnZkV&X_@C;l|i4 z;MKl*te^ja^h`T2YN$n_L`YJ$fZfs6*cLcNo;@$ZU0j9FN;Z%i?E)HW9SB)6m5~;E zWbPU-&EwGf_c`|Gtpe8Va$xG~4Ty^q@k_4_sp%{!u=BX^krn;%he*j{9%C=;!}RcV z)_hoqHDJ-Ac9v`B z(CCpcV$pqj+0-1#(fD4-iP5&(%2>w%JU2&`Z&i-CMVuIL!GGc$F{BFUoRm;(Tnb|u zkKR2JeLh_3KlSF(mlRV45BsC7F_NS4%w`FRwa1mpQVHYfP6SG_lysYb^zTG8 W99%eC6s_jG6LgDFvOG07xchv& z&%y0jCX~vu8ChBCEpp3P-rf5H#mO+AwLSNI zd|sc|UZ2ZgjBKZ+P;iJA6}&(EuV z^`7R93C$1DoSF}3Xx?yN%U7jp&u`E{)%X9_o0c%D)Y-J)!7!@S_@DnP`>=TI4rvIu zkUuQpL}3pMZ#vQB;t(*cBrn)_7+!A2mmfsP#%&U^EbaLE^(~|)Ea3ciRF4jjS3cLy zTIbv=9?YjCu(t`+d1FB@pzKH- z`(`_m^XRZ1}SUZ1_-O@|fG3-O6aTLY-1st#Nfi0e52aP<;1`n*y zGJ|6UUCBN=-~7D;DN|{K)u&|y4L)?ub}6wN5^6^~aHHr7$@)mdvNA84UbV1`HVLpF z_Wa{c?b*H>_lXk)l`O6gRB?drsh`EHF=Qzvy76s4ROweOuGl)*c_yE+=<5>5_(1kh-~IC z%}9v#wJ5e}ZCyI2Z}p(A)K9LKdU5n_w;IaEH#h0f6P zYS_u6FZHytc2Y>rqw|UfWHA7&j5YChN&WKz-rnFr PLtYxY!pURe7ZHB~B=X}s literal 0 HcmV?d00001 diff --git a/rtdata/dcpprofiles/Canon PowerShot G12.dcp b/rtdata/dcpprofiles/Canon PowerShot G12.dcp new file mode 100644 index 0000000000000000000000000000000000000000..aa7d680f72b80cb5ddd97ce2904eb60f2ad184b5 GIT binary patch literal 1518 zcmeH`@lO+H7{^b_7&=9qY%00{cEe2Gw%@XjO@r2o+aijR)hv|Fv{s>OY3aRp zZ2?hnaST)lW<!{Ohzi*tMGP`aCi zSv%PE+5#SV11@MAX9=1=c%02~;H4Qigw#WRbQ*Tywlhhb@Nm#y^CGoAB;D!#IJS3{ z`%NsGEN_d+vuiQD#*OxyeAmLB0ED!?nAedYWtw>O=Gt(tX}RPp^*0;p?F z4Y$8s9jl{q@Rk=Btqa4s!aIUF_@7wKJ2 zf<4c3^uBD$KlRSluf&U8`?0FVhxz5l#H$uR?nc}wC_5t-Zw#QB&iVNEkf?F_p$|H- zvUrOyyNtk8=tuF$C27$nWnU_HT&lv;hM&dXmQ|xd>qh2rt@Kb?}a^V2KYo20x4^mWTQ2%A8e}#yl9kGA&#b+=n0Py?FgZgP5_=kE}!& z8eW(}ULJ>ds}I}Ur_d8eP;#0ep)%j_E}XG`R37qF;_lbkVziTBg6{pz6=7kwgU7Ki zSezL?*Cnmsa5S4kD8EhrR|>)SO@jN^pD`R=5Qx=LdEOj?UFox=xBv&&d4kbgjkHw9 bfzbV$Cx(TRFA1y~4y_|PG|}&eVR`%mcJ$%i literal 0 HcmV?d00001 diff --git a/rtdata/dcpprofiles/Nikon D200.dcp b/rtdata/dcpprofiles/Nikon D200.dcp new file mode 100644 index 0000000000000000000000000000000000000000..3a31735d32afb377dc098d32601db80d070dd26b GIT binary patch literal 1502 zcmeH`{Zmv`7{|}L>kBcBB4X);_zELs5TjWM_v?r_2qUJ$peBfr?*vS5utK}%p1pT> z!5u6nmmf3l(8I)NLx>Gn=V{bE!4FQVM(%HS;nf`@ldS;&ae(pKv ze(y8qdG5-UYcnShLdKIRfiWanP^rjSfd@#G&kXmH$$`1jQz(% zA>sWyBgXn7oAG=h!O(wujuRgWXSfz4WDpY0aQx5zm3t_f`=FkEdpDX>6l^KpAf0)* z7E^~DcxLG;Zhf3#>+g0f3^nnzUtK61uEIc93@^%H7`udGP4h_S%}{lu?cJh_h3!s!`xM0vZ<&1XiA zU+0^myb&LhSJbMQR_fpbEeiAj8MkIsYB64lT-AYbqy3$iUvT0((Qn_#cCDv_qTSB0 z;*l&pdB4#wlV@LcV_%h|PqQk>u`9TA?Nz?_X&Ga0%CI%WBR!TPzfjb0_#J6@3dOa} z3`0lv^KEmC`7wF^E-wx}-@w04Vign}KlWmJ9Mw0;GP1fo*s}UIpIIT}n~;jESFUPvcgn~Yjva%CrPn8l IxvFvDZvzC>;{X5v literal 0 HcmV?d00001 diff --git a/rtdata/dcpprofiles/Nikon D3000.dcp b/rtdata/dcpprofiles/Nikon D3000.dcp new file mode 100644 index 0000000000000000000000000000000000000000..7a6d79fa5501738689e9c52af05d0c264005af9a GIT binary patch literal 1502 zcmeH`k580!9LFDpfr8wa-qgtong}d5J3N9S?s*@GIy7BUF0v#==P)Odjsx`WdA`q& zyADBe6Io8NvP~%6a3RRf?!FHomt#f|X?ppCNx2o~%BGQeUe7&G&(^=t)@S?d{d&IN z&-eZP?DO4IT3WVr2E#D%j5#=+nWa*tn$H9in3<|ptGPZH!%S1vtmf1|HN7hT6^vzK zR2@+BVK9*?QHw@Y4y)_YdL!0s+rG0pt;A}vSeQo(874WCVKN^?B2oSAk*=TK*7ZWZ zzQ10*Ji2cR>+6-V`uC<(UH|PFr(P7zXfJvYFibR~@jw4p=8*f%7<<&?K~lXNcUw2p z>Oq1pUJx;Byo=877P0(}6N}HErmKb|G+c9FqA#6pa|&qwnxMnipi~{*uf4m$Ikj&1 zi+S3#S%zp55$u~wUwt58_-PkzUW->M?-8U=Ik0RXMVURo;p8VA+K>5_Gcy`BAA>^| z1w6mwEFGDbQ+Hv`)l9}6$Q$NIk-pO#mJY({dpxEF07QnZ#bq{x72Gs z2Df&IsLHh{8EF!Ve{{j>G_!A+1lTL;k=QHlV=n9c{WSn&=N=ZL3IaOl%b^OOeNd;N2a^_%E1vl5f7B zxpU^sxo76)r$@x#d9?v&o`G!rUj;9vcX3m&FW~LJ|Hj@zh?S~KJ{^SGQTL*Nv+w}WW zN9rDp>FecY{ks2Y-Tz%PnZGEmcrSWT5E55B{^$S79A2zX);?eTE`s$GSAVS)$}&Z` zE?1!Mh=Yk%8Ry>+(NcVX6%11`KU+j#u9Zb|W#Ev6wn=Nz>ZnS5cZ2h4Wh`^`Bh{`V z8l=eU4rA9>3a;#TPBDbA5elm?MSWn^ab)jVY%242}1aF;;>`NVNy{07U7`%9sj48!_ zO}M8*Sw&Gdb-X4vP&_VH;T_j%W;^S~3#pap%7|V#!`$eRCHSV;1!QtYw}=lw2Y#Qjp#j3aVg-&-rY^1o(4DCY!&!G+`wWz5`Nh2M#{41 zwZ>9^VqXTEpQT9ejj*5Fy-15xAY)oz=)yIMj4l^ObxaEVwpc>hD^>VuoIO;aN!VT_ zW3zLk<~yt=>KI(tPBEfnvo?RJiY?!}(X#X~b25sJ_6lSMj|mx#5;B{sFg;QxI2{t+ zZpZEKoA%w51--TM%iwJ{kgS`w(JYepA@!Kg4e_q^vE z?(N=-xrRS(3>oSoh5Ug@E|PoRPDRTVSkb~(Tm_Wgb5Cde4Q+k5@1D35<5KUZy2*@k}dOmuRtE4Ac3nAN;eYm+?c*!o@OG zSWjwCa(Qgi0OLn&UEgn3;oB9}RZH`18@b|VI4*HH$F=@7Go$N?$A-53YUr(1#(R~; z(BG#|8td<{fckS^s-gcn&SoFcThCz>0mtdB*Z=%qnL{|sN3Yu7Mf|q}>Wyp29pv$9 z&->8sN}+B03H}_a!xwQI=uJ(+!8^5>Oq@;EED(`dBfv6w&#~m^#^}A99Cu$tUDYYr zev$F{Ap+;`A7NsXjIlBv*}_7)eJ?@ZnR-~Z25FKiAaIzVshZkoit=eHLCtUj{%CDh_U#w&T#k%n{zdvwb7OqMjdc+*RQ8n{^bvvQUV}Y5;*0v2Ts-PU zaC10Rw@b!Ug&)V}O*zWaL>yST7lkRE*uoQh-5h{zUWa4+f&l9x58n7;@x{*Xnxj4@ zSLA+xs^XZ7TVC;?*XBq1G*J(qkq{a2qCC<=r>jNecQ>I;@jCYHAvk+PX6N-X{;3B8 zaXI6ed$2Ps;#~G+I4c@4tnqkOTSG@O2^J^TqhMq+mA8sGQr>{l`<sD9NLFk z;VNm0<}rDlUB>B|-%!}-!C9AtbW0kXK7#lrf-lR*l!OKz3&UjO$gpMXOh z5>`Cbsuo-_@|c{wN=B{6uV#EAV}V725;H)r&k>Q9&+=GX9OGdDn+6HAlpIHYrGRrU ziJ0oWO}k1BACqma(pS8)mOFT$(^{SQq1QEvm)w${|m7pjj!*#WoitLV@0SSYVJVzJvpCwE9 E8+4)G^Z)<= literal 0 HcmV?d00001 diff --git a/rtdata/dcpprofiles/Nikon D700.dcp b/rtdata/dcpprofiles/Nikon D700.dcp new file mode 100644 index 0000000000000000000000000000000000000000..969c6b9643835954e758a2ddd928a6f5043dc969 GIT binary patch literal 1496 zcmeH`|8G-O7{>29nPU}1<^~aoo4^<`PGZ73iM@}Zg}5O@7MIN}&Zz;M%uSYkD{Fht z{nFZ@3zUEZ1~`n>ADlKD24$>0cj)SvvLJC2V>O_Q)7Hf72go+U>bbqSe}su|^5*&6 zbKX4nz2`l*xVX%g&T-tm+=CGlXJ+&&%iKr?x0q=I%c@8!m%?-f%UM>F#`HYPxyU_S zD$^mB^AR&=XGNoo@3M8R-iXq=eT@w{cFV?%9M_k_am&_o+*7v`2~B$!bbV=B*Reu< ze~7(Y+dpzgU;lHF{v3To*UGZG=H1Cov~IL6^dR6kEw%Wc|10N^$f;Bd9&5)>F&7YD zLU;5#@LHf1%Dj_$OGTV5Z^ES5L*IHqhBob)mH zlb_wFt5Rvvuooqj4vc@U(CMWzuJtv+mA5DCun|l@+k&+E)bO&01Z=u1VJ>71yKAMS zkHPV41V8kbsur7!3w{Cb4o=bul_0*a12-S;34hovV9w+KDQM(3=d*rR2`HW~_&6!?2?&?BcM*yA!LADFN%%n@A5*3Lx> z{hzuTJjTzECis4Hp>-g^W32<#>)NsCpFK2mlpwpU8C?w`eI+V_{@#YRyw%~u+X$vO z377rXF+}upHh5%)z-_+ona52Yn5zih$n@d)Eh282Tu8T^53O8qBRboTU@V_Dmk0=m zF3h?%sC(BQOn#Tau_6KE!(Y0@xgF@h7ziQ2VG#+_<6KC9`a>t7V%tajkZnp^}Wg67pu{2ji+ z@BM|%vrfQ!-}g~e>OKbNCPe&oPNu;Mb`QHHOx;T7GX#Rv_hoECDaz~F{kf!|Z2Sa2 zu#{j|jfBjxm>O_;lKmL`W{L!F#(-*hN5bkcj6c&lFMfcN^auF3Q+xk!P L@=k)mZ4&+kQdQa& literal 0 HcmV?d00001 diff --git a/rtdata/dcpprofiles/Olympus E-P2.dcp b/rtdata/dcpprofiles/Olympus E-P2.dcp new file mode 100644 index 0000000000000000000000000000000000000000..bdc25cb0c9e6cbec79634185814fd68a96858f0b GIT binary patch literal 1506 zcmeH`|4&tQ7{@<^v$${t5%SBGyp@8M*d`5VlkdOCu4n1V8s4&ky|xZ9Ut2&+9y& z=e$2>&$E-A{Z{5Pgpj96jQ=TO<&?+uyx&5?crNC8#~(^Uc#h$E@TBJy=W+iO63Vlm z>!ClKyuq7#IX~j{K))HQ3U_TQE-SHTCFU$8WOY0tQ3-^c7@eF9bQ?m)+-hVmSFz$uPTTM8 z40ktCY)!Cf^R6rSaBn4Q?&N9F_Y|x@>A-lhXeIS^48tDn9_(YJmleyp6SH#JC@%_P`Yd-Zj5J_-7md^1nR zBcM?sd5=8%BqGQ@~;g?INz=$c??y9OE2Bw4*Hl} zyFo={(j*GERHNgRis@1VG8?K8eqV)cNurhL{u+75f*Fn*l*eqD1s)9Zy zukgCjG`dkw`^ST;P7g|Y{?z6dG3*`To;?H?P$`FJRacEu&)VkaqNrgcm17d>o&ukMr4l5a-0k$_RblK0fCn7hdW0 z>HSBHeVIJ-=`ukNk-wf6zbXV^jw)Db^*iJ$+bu+cVYaB zj6ZU+(pw*t2Ip+@fpZGVS|ZWdNs$_%!aDMqFr{6_ks$>|!y!U^J%!ZCaHT$3=ntc4 z4U>_fZBHM}m4iMe&uH`D@{DPkcU(kOu^Y9^7i*VP7i@_tz8F}wEG>hgF@_;DYE(El Jn|bf9$DkjxQ$EG z^qiJ|#V2zmTGOD$W7@smZ^er0`s&6_^&4yEl$5&)mbjl=;NZTQ$8itmbKKTDsg$mc zF;gf1Y3ih>%zBnKnqJRMn)lI%%=2=)ssHA!wQzdsvzbA`aeC_UKmS+uaK7iZayCoA zr^iJ^1HJhC1i_m_KD1W7$X8yWsC(c=pKVxPTPk38ssU9qyX4^?C@w1jWOg^ILpRK~ zw)hPa#MDE5(T2qgnJoeikB;!c0}PKxC`x}hsMy^UcVDLHxOqU?n?rCmTR>x>7YkC% z_&*kR>=y9H*Z_Yn5(K}HU~AnDCALh2qx(IqvnS=m28ztvK7>DeHQLn@z=t`K*5h?f z_%>wtSbS`K5EB}TFn)70u6YEE&c7%}Z!(mR5cp`W^7UzgS5kg##wYT`SO5`1(ROR5 zv$|=!;bU<$5JuykmGTNEVQ^au+8tM;vkMred0KEU)(Wzo;O;RI>i$RY@gj;X4j<%^ zjF_u^r{QDqjZI;cxNNaAr9m{m6-KA4MomT-@>WZDw&IqYc9mjJ4@IPtVO}f6+#~v4 z^f32abkU>yG$5eqg&?k<>f|rY4`BIg3@1<4DwX#szO47*%$-7|2n?^!@?(ng+E;J? zMv(9exUzGH>OLVE^H{tj5yH_2xk@rkz@l9er2bmvLK(r~ArYgIUS(W|A4m3ykna(t zU^c}Ob= zzJ@Ab z_Eneo@A9d(OM=qG@9G@q2ZoQuZ9g}IJl(HeKP{pv8Nw=Wg&J})V2Xst>`y35Jrs;F P{J3y{SMwrWh27{<>oL>3U~TBB9d2&7tSBW+zNjk-J#2zAA_bgiMg+6y-Op~Wp4E|GTG zIdj`f!K{RG5!*ycQLMyT6%(<$GaGf=pjN7>M5s+bO51n^#nw{5*%`+#{skt!$&=?d zXWsMVopUlao4v?H2uUKh#f)UJLeDD7jHQrd#p@I~V+q8d_#KL_{oNB$_|I4(Nl^SN zMb~4gq*!UXpzxfs9`DzytYU9Pb=BV8yE2M56g^PlwB!;pw33iT%L%#j*M)_+-!-rK z&a0ZQzE69ks? zEFO1D*j4SpAg#v=M`3ty2Srm)4YIC0FCCrXP&7~tgZ*}Cdm)QQcCrX&4o21`zo_23 z&X+_E?H`VVnHFH5rSL|FP-_zqqF#6%`=#Ec6ruM$u(VH0Eo&KcjtX$inC0y96;&^pXHxPrdUjQ-11{- z)c8tB&C$7hYXE6q=R_au5m9Rn;^*%Mn6*UCWm#_dymi^@f9(vIB}eednV6Rwc7LYZxK9)ppR;&9bB z4EkRdA#Bgdzx<|_qjORkkI8XkK}wnro!uOa5hIQyQrz6m;@&Y)`h0Rf(hqYuRB%ix zeT+f&TOtZtMft$fE$VmaocRL>|I&NpP1Z()uCh3PW;AkPC5uxXEOIax-e_;YR48@ld>C}~lc%oLtx7Afsn(Zu!f^QQlB)v$=BUw)IPpQ1?b7jbA!P_~sT_iGmM4&Nua V)>8C*A>ajvJHNGyL06@KzX0P)-HHGJ literal 0 HcmV?d00001 diff --git a/rtdata/dcpprofiles/Panasonic DMC-G1.dcp b/rtdata/dcpprofiles/Panasonic DMC-G1.dcp new file mode 100644 index 0000000000000000000000000000000000000000..aee19766ba90fc66251187f91592e531d8fcdbbc GIT binary patch literal 1514 zcmeH``%e^C6vrAVCRcKp=t%HqWDNbXxg+EDvw$U?mTyQ z)}`$N3N}&tkVVki07gwTg&F)|fm*4tkR}>Ln+CN;EeZiaV(-o}KlLwY(vzHgKQs5- z@0{FoXZ`xksUd`rV6weqie2horE($|+i1Q6m&U;NMim2-G7H!6AXnutWk22*AM zd)UpP_=beiY^Yw7guF%p0a2V<9xvmG*^2%{;p**l5zB`K+%?_7os4RI?gn4al<}6+ zgDc~9q~;6A`t~-f(Y<5qKF7J7A(c%N@qI@bu8l=#%9k8gsRvNFvrfZ_I^D<`dsK9`3xsdn^mDsLUd9QzJBR`=h_=Qc3Vm?aLHvc#c>#aD5K+YWcL$~Q};2r zX_<`9yaDZ6l`JAuRGP4BnT^@l8%w3h)0(P90 zurZQL_SC!eehfYnV@Gc$llX!O8GRS#vZM5zYbGSr z#`Lm*K?2h0yzV}-puXol-N)dJtqwR{p&Ivb1%7ucxYE(9;(aS3wm9IiIJ;UKdAMyd PD#jLLz{#Uwzl?tXdwklN literal 0 HcmV?d00001 diff --git a/rtdata/dcpprofiles/Panasonic DMC-G3.dcp b/rtdata/dcpprofiles/Panasonic DMC-G3.dcp new file mode 100644 index 0000000000000000000000000000000000000000..9247f6df721d058553c352e1b839d6a0fa42c185 GIT binary patch literal 1514 zcmeH``%e^C6vwYZM7k>hfzkj*TE#ZB6vT?nR_41!tswGP%_dqBQt$y7g{%-k7iR7} zT%c)LR5lH@NTNtBHd?fZ!FA_u(k>-!@fo!?X-cZbDzvFdU$z@NyVLO(|AHnx$;tOK zcg}q8$vK(A!gVWV6GEa$LSQC|)2K?zX9G`>XiXcnd@~S1W@wtAX9$UXo)Gr%(W8(i26eSh z=_+LF?>kMpUin==|IVyGS10NEr1LE8(olx_(u0DKP=?}v{;$j-YC}2t-|oQTE*X}I zcy#Yq;3}cG>^|rnS)<@gh7(ak@#>^q!RGuX{CF=(9o{WMQFugd+02TP-VN{F;GCl} zG96ph2kTuBJ1Gi0Y3gS^G7iT$ao&{3PUnlT&uPN?;y9L<%A=6Az&`U1E30>heGE?Q zmN0VJ#wxrWsMtv{FzNCAGK<2J-VE=_>)f$A9^RN;xa}S1Vt?i_P%UBKk!XL-6d(36 z_|pLyy|;pl)GOfT$q-(DjTLVc(RZGr_lG&CDxk<7#X z!P~FO$eH*ac^|c5bVxxU*^M@P8`7n{cxCHFF1}5|JGlyMduq7k7z$yVh#O>)>Ugg` z>|^lUZxs0FxmezU4(wRx!bsL^c5Y1T%dMd2X0CdxS48<)3FY-)bN6d08X6?+`%vir zRQafgWgYE^Gs*bM;_>}tm*8Jbu`$)7247H+((Hu!w*mE&92t&UC#DxJ^)=Zj)Nv6f zR#DcqUEi0%o>#TId8*!vS5UE!B5TV7b@aFZe`+gAXIR*=ms*j&YYz^Y&8#qm$DyuP zd@vYfZ#{Mfen0Qx&rBX&li92tsPr$hY6d4Piv(7zEQF~j$*wFxz z4+^-}BVp~Z#aiTYgnbNNeqTgUK?KY$0qP|Qv2T3LZ8$8V(k)|ZX&HCYPw{@5to5{) zvqe)ho)NL8rNO$eDl~8Un7^D5~&no}` literal 0 HcmV?d00001 diff --git a/rtdata/dcpprofiles/Panasonic DMC-GH1.dcp b/rtdata/dcpprofiles/Panasonic DMC-GH1.dcp new file mode 100644 index 0000000000000000000000000000000000000000..c7aa00ef1ceb6a3ac1028be7b4bbbc20463daf74 GIT binary patch literal 1514 zcmeH`|5Fro7{`~+OFZus=%Ao3Kw|uYFv+BjQTHZ~5pd3iFM~Mh_=T=Pr|Bp_$b-B6 z?B3oNi8BM70(CSB&j^yS7$-e%SISFF8>dFf#G%m`Yf`b121<%Pcgz0NU(ig?%ro!T ze)ie-KA&gzQ&?DHie?yQHlq(c#KcjmpqU!dFmtHZ(%cwQF;P_GX->}61StOzn#HK7 zeogbw&|D^u7X3i^FS;JCSE6XUb$d;fb>~YddFxD>`31`u{}T)ovyfp1CZ?yuIyoh4 z-uz{M^5tAEqx2XSgpp2pA@u;rO5bD{~nCqTP5jReT0pO#D|O;}ZI$F*ZNDYi#Id(3WB1q#FkRu0`AbtqpS50!@CsoRav zy_1!D#w0|16y8zEW5WI(T=Tu~-rzBqUxD-^9u)UGF)C~}sx)*y6HZ{>a^rxGV9G;K zd~Qt4vB>=>to>2I<~0W;+mIX5Cmwuf$&jKOIOsQdu%S#4xBkjPz1xN3Vvg~x_gQ$( z^R$m}$Y;uZhv3~?JUU`|EW9%wtW0yDGl4^}x=+l#$>G*2g3+dS@k$1di>Fwa?==P! z_Y&y7qI+xR#LC`1k$oxb)e`))lf#%h)n57VXOA_ux2e*;U8 zYNU~FJ9<~xalYfYG?LjC@liP8lpRsOw21fgZj5N_5u?^2xs=5R_p4Ex9u)}XJ8;`= z!)MDLMce`w1E)FY_GX_wsrJfqo?-LH1fkXk(zOCFKJ9d%$T}+eZ9FWqY^d0}A5UH) zIPt6k(Ft2D3;vIyn$&`XfBzE`G{=2F-URV8M zruzP1tm?;R)b&ZD`W$9aBK!V5`5ty?M3G!-@gO9kNd3?Mm3vs7*QqR-Zo`#M8IP|Y z__Eb1!?8xdLV7nak|yKixE%}DysVg$WSly%4<8I|Qu-$a3~c5R(|ePCz5Uhbch~ra zC?lnN1--w^h1015GX5A*-cOd`dE*rvF_h7sg*;Mk+fXvvNE3@4_^V1lLixPlBc9gi z9F2EQ@~EjVrI+Gb;M3dT|H5fXTV%to!A5-bZWZ>pY-rH!Mp1=3uheJ9@H!E$+)rs& z$Ij>+jei&t(7HTCpKq72tcpj+{5qvR#3RdSM@CI1m)XtZ1{JW}W9IUIb71vBC(a~| zaYt&@JQ|NxNjU$Vkvo2@70HZylXzU&>qbtKgw572(~q$dVxMCfT(6nVB=UH1V>3oR z8x4GPxjmXkz%`nC=9(O*P#)(9Y@mDEjb(D`^6I=!?oW-luB0!B|X z(9eq;czP+z_xhY*@30)5qwy9Kk6`)vKuBytU9ue)tf^c}d=q-Q_rQ8$Hyp6xS7je^ z4(FJ>*$$*1<#8+TV`^EsJvv9@B^3g)%v)*FQ_ZlX2{_;`<2r8h&?^$A7WZ`X*12= zDqzJe5f9e&nM&h$JfIUWs9VYTD)vX`XuSVPC*mu^N`hHN_GKrY8JkCso)dBL2^Yvj Xt+Mt_0eyZM`BU-Owv@-!;}ZS`p+DO{ literal 0 HcmV?d00001 diff --git a/rtdata/dcpprofiles/Pentax K200D.dcp b/rtdata/dcpprofiles/Pentax K200D.dcp new file mode 100644 index 0000000000000000000000000000000000000000..c1a5b79337dbd771851fa54e0b4eeeb10ec23919 GIT binary patch literal 1506 zcmeH_|4&tA9LFE7P7x}#E@r6#ZY{}?W?G>a-Z-u;6+x6r(&3lFnK~`<63{(go_p>& zUa#)b7)`-7iGme!A1I<(AM z?@Y0@=l=RSew0~nWLWxd*J=DPGtGXikU@xFe?U$EDQP>F`EC$gCE9!2u!Dm=|8c&9-|Po=rv3~SEU&pYy$ z9Q5J}Q}K89Xx_}e8vL=BV$r!4*4ZZ`{;PnTY0WHhi{gBVfS&%>!XCGbR~sodJ{iJT zsnw6ot}@=|Y)8I7sNmuaKN@=b^2+&4J{h9;sjQB5?-a3mv5YH`7S`P-;k#23=GU~c zyT1hz_p-Uy<;OVfaMfPo^VbDT8t%N>fDH9w6)p{z8OO_RTLQ_ z)o(Xi{n+e$LBqG9M|4-3is1u3c+`)>?j00In!G5Aetp>Q?WSvL^xh4ffe}i z@_vsV@_G|KHdl^oAa5%AazVzyfQsa7qSHAP`RRUi>>drzipogOP+%0KB9ggVY-xHoWZjl>fJcQefV_Eo2;mj``FaZ`k| zM}-kP!_1);Sg$Tork?l1P~D7=>bsR(Qvjxqo8d4ODkVJ(U)`0k?aMMeHPsl~cb$)g zDW<-o*pnxt<8dFxZ?47-kBrwEn$Wh%plp1V!cw&t?`NJ=X77rqNuy{y9t__~m18+N zPbN?dbQsk9{2CSy%C8n@@Sj0Bw#pOK@3WK>4F6?K>O@B9BTft&E zI`5ojC~xqnuh%os42COqqdHVAp(vTc`$4>7v5H7dlwdQZV%;wy`i?Plb(w5$)C6NW zI(y@SxVV%G#t=o%A0bSam14)V59V|2a6cNxlgmX+UVR&DvxkJg7EvS}kx}Wqq&k|~ zV>vpHJQhS=7gG~n2*B?Tq3T|nvSyKt>}4Sg8E1vBH#3Z12;#l`8f-pDk!5e=&qqr; zQ*+a9+m_4*{B%viLS_ccXvMIx1-nw1k_Lv6`6i6rIiS?=xvSUvQ1Y2GY|RwBd8 z#ZTBhN3|TC^V|%dPOPvGf9S{0wGwvJ4dTi-5*&%Gxc#djxLRBB!$dQB%_WL+M#SDS ziZk*xrT=^=HkZ!kLWW(Q>vMTh~$8IvDO4Ucqdq zgx}W6IMUg#SVy%Sojb4lQB?ela_I{R1D^+w^>DXv_>d1r(}Qq~c(A)yg#1tlp15U# zSg&u7oGQ(0M4o@8Qjk51(cI8yqt7=xgYAq}z#GXOO;uVC{&&FbLe}7*0ta07_ zMf&@m6x}=K^!2-m`g327?*Gm;s~?OjK9gP)gv1rE|M|ai4u|K@Lv;Aj9rfT&+tb|W z_Y5(!8-MH{lXveE@YW*%Ep&zQ)QEuQ`xN88E3!3-VOJZEGlBZ>%!!Y+dpG#CUnD$s zii&8JuzWLx^P3dqT9ts5*>JPE72zrrcv!|lf+x)L(bbwPkPC}90dChpQB9*I9NjIK+w$>VM< z$Ka$oFS@ET!z1$&x)=FyAh$zVcAR0^5f3(2x16B3zIIgkZNG@G1Fg6{Fg)b8Q@A>JAhv1t%on*77kk>V^LZ=B4)Wl$ z8Qxny5%yke*K!QD3=23rVGr|^A#b1qMRjZBSNbTT)vd5jSK@<{6rV^=B!1b;6<8?} zup7DEjkay+JGC5xEyqQ4di|(wU|6+L#FBR{D1K8wRj+`P3yyImlj_;Z3=bNzx#!fg z{ZnEH9Xe$z&(iPR;Dg(Im^``=jiEi5>+|5p)%VKoeY+Q@f0dAWE66p?@W_8C;L`>Z L27^5Iwh8zfl|9>A literal 0 HcmV?d00001 diff --git a/rtdata/dcpprofiles/Sony NEX-5N.dcp b/rtdata/dcpprofiles/Sony NEX-5N.dcp new file mode 100644 index 0000000000000000000000000000000000000000..263733b044a176cb70626d297491b9d50d8dd675 GIT binary patch literal 1502 zcmeH`k580!9LK+U{0i^D+lQSZUyd_#Z2#F|C|MP!k4|%SOQsH6?(o9Z#wdE`|7xVb! zdmf%sN9d(80S^c!oGb6APfZJG<949mx}5G3YlUjIZO+6}IB0VWIR;iVX>ycOdhUM%vfUAsBDQx{23yrI&3=j>?;E3y440 zL2qppkh{!`2_L1^J_ptW-$c>sJUW?U!}0N2RC-g21}ZpYR`7U2+pJ@Ma4R_~_pb8d zqu%wj>319KX$}m1n?#3`c${Bp#q4?GndxmDUV66#=C&Wm|u|ZM=JVH zg{ISoM>oBJcY2#KY0yjCN6bi{Y{cgUiPFAOJM^#afj^^*zIDZpfln>SpJT-zn|Yl2 zi9=OKw~pL4D(_KQzq=jcfgsX4YfuyN;DZ%u)OgH<*eN>>Yc*1rmPNu13*z_?J>JLR zV4MYOex1?neaxZcsH}b4i>bwB$iAOL_In(9>Re)uyxTIvPUKwOFNVP5=e;Hj1y(Sj z2@Y)+tl+aw>L%BddnX+5rXyQEyPUCB`yG4G?Q;6CZVHV4Lv+fZ;OnJyY<@!du*!rEJmSkEHy9v8xE zN0^VVb9ge=g;8I{@ZkrYN{-46qn+rqoRGGJSsco50k4^%t*>#Id(Me3nPjo2gonXn Q$KcdThWx_e@p3!<23=gzmH+?% literal 0 HcmV?d00001 diff --git a/rtdata/dcpprofiles/Sony SLT-A55V.dcp b/rtdata/dcpprofiles/Sony SLT-A55V.dcp new file mode 100644 index 0000000000000000000000000000000000000000..ce07b30f6e2002ea3a489aeea7173e3ff61c17d5 GIT binary patch literal 55294 zcmeIb`Cm=n8~m^Q!@Fmfb=JPF*M6XKa z`HiIitEilp{+Q)AQ_+-u=1G4#GH$M_qB1GJv5NFVrM2{DGGkqdze}%eCjA^I{pBx- z+e$o5;+lLlmBtb;k@$DMmddpDDk^Iw{=>L>zKY6UiAAZ+qEZ!=TB*JC*Y*FkEkF*7 z?yIQiGCnV{;y-u4MJr9+UB_7t?Av#O$_{-Ml~(2|D$Q%^>J&dm)!}DI6@K=yz~5`M zz)!7zi2JJH_s|abX~Fuj_>I4x&Dz;k;`dr>wCkpYpB-uu|K0?@yGzw6jz7!K*UHP= zZ|3a(cb=vL>tmCo{M$)?{#U1p%6fu7iprF%P(i7K!Uswnl;c9_0i_3&9#DEf=>eq& zlpaueKeq&lpaueKeq&lpaueKeq&lpaueKeq&lpaueKeq&lpaueKgv`J&lx+&-&u(J zR-GY_`-83D-6X$TgMY4jO@6#vTi@q_)bAuU6I}Y|H+j4meD7T~nNk~6-)3LdTVm4> zta0Kd$*EjjAOE9vnsk1>vYw~j+)bM51lF_vfsLfAM?gJ$E!{wB)4-0lAw>Jks`~i& zq>V)FKK?zaOoI)?!Dd5!{Ozt_^5Ac9Jr~5SC%SXN-4_Ru=+|gJ;X@#)4*&1JMP(rm zmO1=JjWJcBoW)!49K?`ub5e;3@ca|juo1-_zt zk#tN1hn{#(jz>ZV-K)*`dz%qA{cgnPZv>l7w&V>$!81(l`GN?rMNU8dC2O<1wGE%m z{5dwjkk1_t-S$VS@P}eh``Cm+67K}v_B~7>7GW#u^(3`>$%`BCUNe7-TeYKIMj>iu<^L$#xBzR7UH@k*GYf~HjP*1CuV|c_IKcqoCAl%*z!*6aSd5dUg{*se%2!Y;sGg~`cH7-1sR#iJht5~js!5>f@Ec6 z;zP927}%U2z`PfHw>z&*+mH>C=f9#&v-_`!MHPH*xm1V0%zUD@$d^wHq>ciqwGAs7)503J@z|CQ7-`s_)Wo&DfL~y$Xmn^H`Jlw}?R( z#2<&fBhOoc1>p<1)fBqr%zi}9vACU)obYYYrlD4jEl$e>ro+16i`>yhXj78xLOL}8 z%bO;VGO166_l#D)C$Y`InRnarWzE5#ZrbuqTY%ekapUK*_G6R$_*cwt$DVBB15@CE zt&1Y~K5Xm05Qrt%f+nl486=l?gK?3C;AntnLegVxpLCi8=4 zMKMt^Mm*n3Bx$VP%D-31T$bmHxs{}2W3<_L`w!W`YQHl3A!#ke74v}Cj||d@aYL;R zn5W5xGH;yE$mDX=&`D#gQ$M#QzeXSNsQW#6tq$P1 zO^5K?*u4EJVJcs0iukRTi}^Cbd*GQgW(W&*9opK{?Vejy%V zY01Ah0lu23&9CwTH`RJiGOfYaQgetF8=LKXPmt;VtEF`!`M|FAqgtIK!Y`b!cPj{7@JX>L*Y;kgh)2EPF})GE(9MOMhPijPd^vea>0-&W3KndB3NCMJdl$r^T! z>M9kHK1Vb;;^-@S{Y1vg#SwJ9Q|Td;>gnt~aS<>+ptJo!XKl8_C99mourH zTmv~Qk8&VuT7!ARy(F+bbkoVXNs>AuUgN65>-7LP&e!EP_X5|RH0NbZpUC}v`SwE) zf0)McEj_@x!a#mKn{Ru5mGQpo5Z4-G%TL+_UUau3KW7%tqkfOp;K$rq0Yul2L!180D@6n5vk&t>rnQ@-77aGPa1 z{86TDv*nHWT!Q$kNl!@t%g4zpgWRrx4u#VqNb(u*l%j#;U?6Jm;$Fs;FGM`ZyDNA8 zIO3bHbl_GULj38bGu$u&4))d{k@>&it%`O;6-wk%{gyPUXmQ9Pe4o~-bKeC8!E1Z8=9{>qeU+ykKZT8>KHv5EGUgfU=em3-i+69*inm~M zn#TflKA4T)lC-bn3)8AJrG&JR<^;ugY}W4-nfMBt1Z0L1KRyzGnOE{}S zXj1TAoqN81O?_@^absmw&9QFTo;{HpUyJy+?Im1!HQG1SNXHTq1>jz;|5Vm1Du@zY%K+ShackoVFUROoNKx{O?u=1B$9 zFXzcUc0E$@-$5*+nN|l!kh7)m#@E_%ZpCTT9(+NQJ24abB&Lp(jjY9<#vqR=oc29v zW!e7$x8mV{wGszxk)2>#ZS>p96|woeY^NSc>V!N$?(rwP`+|idi6m+ec)_siB$w%v z__~73WcAMQYs|Ntf;JBpYV)4|TR*qe=T9;2Yh}c5X6wo5A13_z$!K3}Zp=GL8Y*!N1?IXl;XJPL^k^TrXK3ev<2Z9d#p<9o9C*=nMpzA2cyDz+FCopk7voNh^m|N5_1 zzh|tLJ!V>!djxZH_0az#jpjtv68tK47Rhx+K6>c~$Wb=8=tt#~9<26Uy^mz(LbQK> zq$ywQ2k!E~fd9M*ue~v;2X8qa@l+E>e&kH>+JUb8M&_l1$Hwz%{~NzGWB5i&I0&!vOrF}0I%tJh%9{zzPU1jxL*M84htk5*l|DD z&LA0W(f{?_@uY~|*H@@aAotncNW=N6ZmXXxnE5s+B9MD$fIc-IsgurZJutZGRC0t} z_s8svC3!Q@#=IntoM)Q2n^h9G6^P4LHsgP;0z0~x@I`^($)oJ}cu6-!z1N+`@N=1G zH1;mwE2RDvnrL{h=g%-doY=6QKgprJXf>06H48l4)tXN}0ruDWOO`aoI)CSfSH(PrEkj`s@yr>>dK4`<`&PZs)PB7380ne?O>8wn$YAXa_5DoC+e}7(MVsn1JBWNU*hF(D z@zDq8d2S_VbJ6Eo>o9U-JGh}%R$a%-1g2G>>ol&w2yGTl`N6re{7(*cB^xIr=hzv$ zNXjy>`LS#=I1KIgzIjV-MS^F|XvQyy0&^;oRy)A8sf0hW9(>JXCZEjawBYa%zCecf z%t!n9C+zwX=yZ@js)l$=ehdGM2Op{#%D2A=cGPLi_jE?Ri4RVYv@2kpts$g+YwTCJ z{tYAh*#6#xl-=ZN0@`@b+DnEH24~ESA}eap=V)#h;q$-^weoWwBAcs$`1RD$+#FNz z#i%!2=|Hf>uz|#d%}XX5!^v97CyMia^u;+68;v%t1D_G&1aL$~6Mk9}d+kgk-bacn z+PC~;&+laIqXQ=J5$n)q_O(DhgIyoj8in)KOgGiGTlqQcd|7w~@Do>}{YGyG{?b$M zq`OV|8m86MMfv1Y4BH3pA5XflebM=s_Y>>O&}78DgT#M3_|Ne}WYs9J&%HQO)E0cx za39&q=DLPjHEv=jYp;pp4)G(LWhZdJ*}L4uq2O12`jCsh;MvlC$t202irVLUC6i6Z zSo`V{aw7x0x5HmjkqyqCtiub8!!o<`-&h;%Jf2^{<{U?E0>3U6?OVN{#cS;bpG%(3 zA7=fN;Y0Z7XNaq*cj4a|B_*?p$fm35X}r>7`qxo{2f=ZoKw@Vnrfr_}igkHGzR81SSF?2_J%pU$`{ zwh!OzIpW0w`tcLKg0FV8;X4>2f1AlBypJb57Ub{iY>0g{&#^YG5aRiuvT z6K4H@L`NXLXnZ~i2?94UyhLKzp4iQ@(_|OZYVf(^B;OMK=V=@v)veLKp;ml;D_KG_ zFWCOf3P}PHkokaYn!FJO9I^whDohISzdVTQDZ8GLF z+Dtk6g*5*Sju_aKuT@13GrqRrgPJ3^%Bpt!C27w};Z+}<_WTiPOexr~rVYQ8)!4XF zgEwd6=*6W*e0e4Mu_~$~zHh^OGF%aXxsoJcH=F zfgi6tNh14$Pb`QhN14YOYIQE;r{g*;)IzQ{=5j2+<{P3ot0~}~lU2wAc3l|R%aItf zF*T!$^d1!RL&)>}#6i+TQKKyFBFU6=P@L;;(RYcz^j?yJrwsT+dYXgp7OC)CrT6U= z?PHSEc~9y6l=|0}Hs#Mr*LOwxv47Qgwew)FL8^SjPjFCO9ocV;dHXN@N2ay`cTlM& zgI=S}@Y>hp0efwvYblu;iTKjV(mH1uc*leD#9=BpVd_cJZ7BHkf+NI=U0WM!^=#iY zNB`!~q*nEzYzw>ZbJ1SGjb-zB@~wMZ8)@7rYI*kBnE2fUe`z|NysgG-f8~Y{bzL0m z(v-tQ-UA%$cad~=0Dpddi?kR4emJ?DoM!XP*~BVxG63-><9?E7`@qiPZ!)eBY$^Xs zv}?f6=l>&Jbg>@LH~UN0G>29T$XC+&J=)wkR!)LM=wBOso5UPIe6*NDRs@6BeoZGv z%wuzOj+6J}5x;svnp+0pwGFk(OpA3~#rDa!nJ39;AJpE)ZXoBw=JUs^PjIi3q0hp8 z|F|FJXtVj21qo<{{@>S5CNaIi0sBHoPc{!6ULHp**tzr1IYUeqqK)<5JaTq5`1jCK zGK$T;2aY`_mM0KDWb}b}F|CaMd?x+gAii1mJNZ%#9-{t*Ol51Q663dI=3~V5ga;&t zf{w1XRe_HvJ5yJ;)A2jM2 z>Gd4#JHC5NhCM+%_i!n3D+Vv$TS%_U(MI1Pi+p1GyV;#0|Dw^R$(VSO9s*9x-b>mp z2kZH6C;z1RUr~EQt@d5Wb@as&g&Lpx1RHBT zNj$e_H2Pl>^^6<9e6qc38EK2+2grQMV~X<|_;)waVY;<{7fvF=5Fc}O1F2!PG}Nm9{mSAbp5IB|`W!A{}P+}E;p;j7e+hp6aeVC5h+Q@gY{g#RMqUB$XKr8*e&*fF@S|9mbO}IV<{gia9 zlQ(9^n(Uk*SAB{2tYf{HXZDs=F+DHPOMK7H;L3vS(!|NSYs!Zc6t9pl47;{fpW zcz0pOI`D(^J#yQ%;F6GovT3Z%?$8C?ve}4#N)kA)abVZ#znq~n_{<4C65ks<+{>KU zbOI;Z_af14!HWa?k_dIM>xsVP`7h*rxUVhQB>7X3zp9-z+42;8bWsn|v;^E^Y8TQv zAKXx@4@VznZ_tN61q0v6$4v*vzF8-{D*|7Rx+8Gxx|ZwShCaQ5ettBvrS{AlV^X zXCDUF9nO(W4h2W0&EPV9!SCnBa~(avReA;7At&(HKF_&VEVr+nK67!>dQ9QfuLEni z&20bS=k8i=RUK-1f8rlE=?ggiXf0>_3gfY%R<4G6@^0;+NwKY&;Jg4_)Z@HR^A7Cn z*N%2ygMPYZcv8z2IBv*|&2(u5a?2F=(;=V0y&R9xUA^&qLgw~kRAVA|;Lro~w>Q|T z?N)ktGM*n(e=whRbq3F9*NF6(rr?}+MUPWLpt9V+qAG~b*2AVV%+&gF( zozw@s?ok{1T@BpJ`kHX=5$cL_2oi)0@bmeNg(H%N3NJkk)sm+&4R3evB(wHHn~04C zvQQUr`?%JebwBVPm%iMUuHc4RY4`=mSDL~)@(Kk;0r4&~1_@C%j~1p~vleaw1&|6?4}fr%v*Vlffw#BONad1vk{nar7R! zMrUXhzvGy&H5P2pXfT~V4f^a0Po)Fh@Y=b5>S*#9~I$qPoZ%N?F&7;N3OTgO-`iXmt!Jk!3#8Rg1mVr&gJ(JL15_nKfS5fsLv?`0x6n$sIZ$_oh=~*_GTU+5Hf94$c)Gm_;&Xqtry)b7FVQfT#krMEc69Ql7JjTJp^p~mw&NfU8jh9XW+&d$0)Kj$o-Zs|WryExVfoI3BV7*&8aDV{e(@5f>F{u~f{N_==7{ZxL~DV}9x zc98KRac(7!Wx2>%^mhP1(l-;Qra>RQi%rCD1Ht32JfodIB2VMAY})uZxToD=`gJkb z<$f4lC#_Eu=i=T|X{}-eo;hL!)tA;Mig>RSE82)X8{cpY#vQ7b*D$TgVX`qXvWD7L+VoO^#x7dL02#tNUO;tcOC^|dD)tPv0ShS&4s(RHFl zBD5+Q_gO470DI_`ifMY#P1`43toed|J}%lL`jo?0^5Ugp-#Q$tMe;CF)dd_sxvMyz zLLcg=CEj!gZ}YC8mMR#h4{sJyJpnnJC#TS3Vc>*CQPgb;cx`Pk-ERjTuQiKiv*+P+ z%ZAWZzy9m1GZU)iBbZiK`?sPin6J!7o~1KdqJ4;aXE8?l9D+jgb#X!Bm`LQ@^KOc` zXEACVRaq)7Y=YX0i$96lO`wTa+;`E313!EEMtmipjciVl7*d2Wm>-!czRE;DBS-HP z=St7JD30}Q=OXbXoAXnv2aDJGN$ER7IVn8Wd~_LfAHWP5!8Mp>WaFsoDQ`FYo3}!JzIer`pS9OC;3P=Uv=}-q`GXr zGH#bdBc(k7#T?#cj=uP39$u^cWwzM1EpoPsjuppepsr!Zv&9GTQpo8V+ z2V%4h^m*RorZ}tw@%w=n#L+Fmx(NrxC*7gdxA+io>sa(T{@Zl1H5>2U);o%yo8!3c zZB0epL(t^(X-)CV2=G*gDms^Gb@}{lT3m{p4|l#u^-h52jZLK98^IQHBk6N5@W|U6 zs0SOH)O9}9Fh{(hR&?!i`8akR?EI`&NR_UG3Vlx2MbrHP)>o0&nuxPB@Y+r9hlmA> zkXtanQJk5F{14O|5SKkgjeDl0i5XF-{nPq$;`7_!1tF>8$QbbZvIAoK)|=~(HOnnr zG@Xan{ygm~?#yTYv2qce9l>9hTZxf3aolNr^u(G-_$qMl&w81N1BVTbJ0(W!JcB|ZRA#}zg~PQtvMAs&-=MmoaTVq zYr5?c{n>SG^4qOqcFEM0%Bh|z=BwWwZqTIXY^>E?q^m9?=h4rO(`82y zU%NPl8cNqnMb7D)BIsaW@R;vGv}){swR%2IF8{{fKV6z#B#elGR_{CbP~ritc7DvI zb7h#jMz_=w-Izbe8`+4BYS3q|K_f+fHZFEvnl8F(quxKJb40y?&|ye#FR>8^o>A;B zuG9rD`#DgoD?`0YoUO%}c(8+tu^74p?A5xZxNju5&x}T5_g>(`H$G8WJ8)^QGP;ee zQKws8rIr=QO=Hdly0ipro`0PBT>!TnA4``W0QWWAM!y6@E1M3%bm$y#LtkAhJt?;_ zg+7(7f)6>e!EUUotJ{%kYxrvvy#dp*(43f%OxmUy5mI3l8vc&!sS zUHne}ckjs$e@%-zAU^QTUAnLp_?lNf9WLDyDf|}y`#cSJ4{m9AoQ^97x9Sp0&7`rZ zXrn!58!ce>o4wBl)2h{oH`MCvr~UF+L+CUA*Ad~yGVt)f)^zee@YE^W>2J1w?xk^= z2C}`)>lGiVeG2^6OIKZN(SjX!Q%mvV81TIwI-<@R@RE*gM2Bdcug#j;Vh1+g<{Z%w zH_Fjw*XYKg?gQ|m1+_HxC)#(C{h-yl7+ig}>TU`-k9BBbHN3Pk3y~&qV5a1DxQRPbXVqy_$dY3AI@c-I4<;D0dQkWy%-2 z?GAY0oiB78TelcwS5ci#$Y=V^O1fndGzrMBr2HYoU&K_=-OLZ)ExyoXrq563D%#f* z`rL?mOS9)e6XRizsERju{j#f6cQkn2p-kGbH&`=P+FNT4KIy)fMpxlj-&%#!em7V? zi-YK&WN<^R)Xg`@P4uA2e)Ek2=Lz0ksYzAYvkF;-9#r2L`YdzZPVLzH5oxi(rXvzk8m(Nv|D8eEWk^8p-Z$7oL1ZS27=F ztA3&mwaD4A#UJ`)0cvdWv5r1C1+C1&eo+?@@#UA_(C$)PF{V1J7t_b=S}>vKMQS$_ zaj)V;YQ*+NG;?>;XKc*wC<~!S*?DocTt*kN>sLdqYG(P#2e9`hz%89#+$ zHqZCzKxpuL#ILMgLG^oL-IZgri%y>i4F@egNL#b_B{w7g_C0dwtt5C)Q||#)nGSu5?p9M3OVn80wVC+$5qR;HR$}MAxGpT| zt0j)I$92T>g-)(EKo6=7snky=~Nv`EB{MAi9IC zH>%gprFYnRqoGz!zfF|~w}K8w9VQDS3Am;G3*k->`1RqQG>ducj@1;Z^%8NNj3C;( z1{}O1jHXKSo8tOwTDX;J{zd%ErtQ?C4m`nO7wv8YtxnC4p}tGNA6BQ((hl%ghl{sp z1>3tLWvZg(4AhnM+fd9~2pu-9?=BWR1wZ|6Eaqf^+h0)^H_QO{NhqUrn&5}2>2yUd zwCa)*P2aJ7$gmw7=y+-Ep~!hhvw3tVo8La$ji*;W|91>(To^6?!rr5AblXKxW$)29 z+IdUZJqtCOuQjA);m|?bX$Va`h`5@G7uA!Vb5NYe8UK7~Z3x)Lb1}7IuWdfsmoDTH zKW?~?+S!4%CIr&U>{-*KPCIBb_Do2e_9fas7`mnDsfzy6wNg<_!LuHsX(?(ar#P|a zbga$ZUA7QyTZ2uTX^L;7&}K=@ZQ4olp5nE|4-@F;577KV^HAz>671wOhvqH@FYY~x z`m?baAI;I9YKS-V)fDGJ@=z`0|KmInrm<&=epcrQPe&l`Uek&uP6xj|+Lu0=3f}GJ zLN7UiU!}UyZ|uGP2R@_d^euQU`klWMJ#`1qKM#G^hd%ENK6t@~cC5tnFY-H zHG3ZTdFPIF7JCl7dPQ$)I|llEO0lIDo1ssxc~?4^eYU;%8BMzD4)i%NOD_0t!1n{J z+TT|&-M+m3T<7VFeDvvYKGg*koC_B_=}deGimQ2W)_ z8uY3&JhsLwPgvs!4xJV&gq169?|BDBhkzAV)Ffk1;9Vz}vd=BfPBNx@Rzsh-dDe9G z1L)(I*o$8H1^?Xd-GxrMiO;;el{{%?3$4cIr3+?{phJiBMuK77vU;sLPidCjYu?g& zKKi#*-f1Ylv!dx?Lt*kL;b|87oSCs&&|U=I@Frfk&F&W(YE|UkL%y^z z@-c2qRnPOlZ?%PCckx#a$BYEPf^TQD~Gh; zdR0P`=7+asTPA_;8MP5?r(@jds|5=G*gaZ9t;#C8%0H??tKy{2!u9$wx}JzFjtleI z_b_PQs1}1^ZXG%38iPPVCv=(3lKL9YOnyV>%=EA4H0vbkODLdQhviR& ziLM@?VSdW6vF>6_k&v1M)D-~Jqh>!8VmBb&}Y%>61bzBC zn+xrez$2w+gmnGD4aea5$?fIa+4rJ+axxTFOP_~TT>Fk29TiNEBF|xxR&OM&6uLc& zwWgzY!B<7jo>X=oS{<=oOP5DOt7Z|A^tK+x!it^8X+TSi!Sye5Xh%PcyZ)LF>4XPM z>yP!Q&10&bfa_qwglxL?3w*V1aTwjW0mlj*(S*|!GX!4!e6$BJaxfQq5A)_ z-){LzSAL&;&x1VJKG(-D3yi6V@rBv())VQ?R{V#t?mxL9XwP(=d!g#&MuMmjK^zdcRokI zbjNY+pC6=;v@ssz+N`31*0?@Ct+t^vzGGfGr&BFtyJK%>;_Pg}c0P14dLzxfQ^7VB z#|0nhJqU${>J!fi>g?Y0{Nh~U2YY`obY6)t{~r2m=&RVyt>lZCR@oDE1S_W1?!p5? z)04=v*sNAKHX7{P&XV%%bHtTbrM(&%bc?&amWFSGRsm;s(X{LE*s<;jba*rHtb}x$ zwF)};Ke|j0tzKQ9vr$|LUF3&0i#NWdnmy6y?hmyz=_-!<#;A_wuzg6qVNYnIme6f* zPBQh*!oJ4>hamcL5HuVUH;~TT1Gc_zOas{S9;41Qr*Z5#x{K4)D3=ONO59cH$-QXb zDo=%u3;M5C?JjG|ZT{yg-xk7irj&KB$tGOP_UAoa>?QTZk#s za4fB}UBx+4Oc75WWhu_>fa|qmR|C;)F4)cV6OCq{-wAq`PG7KR>YAPpr@Nm)&nvTL zP-kgBO)-ZoJWFU|FX&KI){`c%=hnP3OsI|IRmHI?KkCy+Q?zgBtFmj2$fCVEfy;j1r;mcc+(Z>o%?y23=opHpD7f2Rd(oJ!{bs2U(UfuizwY9op6vcK zOhZiH4&6Mrl+s_d;NqMlx{ekU;T~TtR~dSb=bX3Shon_1pAJWzgn*ZgLP`A zs5fmz0KIbwS~*2;r;(B1GY=BzCCPh=^L4XXHeGfcY~TG6UCLfN>%59+H5+~Y+hib$ zMPPZ9rFdHMg2E57(%#|`c8}l7yOX%SE8?psXo`x@Tr2u7zVnP8JB7H}@Ju@53*!EB zV(3cg*Z& z^VNs=jlx3q{WE1_9tuxGkbjX$J9=<9c*CMWbaX55W%EV!!VBp3F)e~xTmetjIYKYw zfPbc5ph=Ix>pGQEGd;XEYSeeidtr#e+81No#LTLx_uXO*V&@HZa z8!^lXJiAs!)ENj(3XGmm3--B~h`ZVJ$3C<R;CA|%J%`}*bq!r4>8a@R z>+D%{vR*wUo$v;T*l_Jk`#mj{US;%wsq#J_aX2dmK zw5Hmlz=n~IG@5;Wf0_OqYEuav8ij49y>5dGXT;GzY@E8dpQZeL#NU)(r2&87F}=g( z^sY6IW%r|o_Lv9m?bt-L*^gscw`nRS=YWqNQx(nFIgK0liH0!^pC7qPpRqlq;V0x& z<_I04Mjxjo?0p2;rzq;P6!B77C@qopFcn($+3)}V>|vVBnnb@ce>T+WZ$xf(Ec@;n z@y880Vc*SCK5n+~<^pnlxLy<*Zv@}^tx1mz1OI$rOFuDRP5e29a+0qUI**_m=mI%3 zDgPTy`$^+Ykx#kLNh(VKw|+*c^C_@=;~hFLA8fMV6%}5Cjm0W@Qw_)3{o^Y=Y77ov zQAsn|dauOj1`q%;0@Rv5Snd@xRxK4kON z@k2dmQ+7>!w91|8UPg`E8?B+SJHU3GB5A)l;KR+1(exqUa+iy=Q!j9_>UFx6?UydQ z_K@B&hUVH@ujmjXv^l-@9TlXwLi6t88|nF5@ILQnv_n6%|B!fx{+ooj@s~V0ljU&v z*g2ZOe17v?0?q1xTApm%O%KflcQM^WQ`mJs|IPyX^&8?1wJN(3mpy`MwI|@Xy!tWP z43fTnOpoouyiHCNKKUYk@4y!!wJZ2k3p1+r1i5)M8$m7hfS<2gO4pABw~F6RhiZb$ zLlWrd0<06NzGYIM&0tagI{h>p+)FH@n_7WM=sVi@8P;8UbUssyY<%BKS>PA?@HF^Y z;77WK-LtPb|AK1Qp#9Ux61tD|dGWGHqf*dkb$Kd1p^tn{_1;g%vHOD5;4QS|4dUO{ zEuqbw{;So5!p+%X?0eW$yX=vlX8SO)1A7WXk79msToWY>oDQz4dMb?82CHc6({XIi zq2E!Sda-?DO`V0*vlh8+O5aMav$dAiphTK)!E#=dO+RO%F1n_anmd5s8CKA5Sy-?3 z8}^TO9t!?+u8DZ}^Q!uBaZ5`>+(O-F0#=^<#JUjCkrx(@#RsDyTz zjsAbCXVLYIkV9CjMEZ6wxT<_RooxcGw&w)WyV3A!LtnX;%*@WMhKAjqtdWnn2ktjq zSI{^B9<381L`v&+#rQpY@|w`$JNjHXusKcM4!&JzM|DlXjz+WT@?*%M;7tV8GX}T5 zkVMC9K+ab>dM6RaBqFWa3iSoiaipy4m zvwj$hMQPZ_7$7~@dSMvaugY#BRvV$8du1PJwmSNEeRqvcd<$-JD3$&`gM3QG-PC3# z@?3X8x`&eXc>lli)!g*n+3HNIYvm*5wI$G}`0#J}&plv^&$ER-JotX2bHdU`(4AR zeX(NzbhvF`EgD+jK02ZAKyiCd+;@ir4ioe8uosc+;UvZwBmQJ;FR`m`V111@v)hZt zlhBXVgvR2u<16dqOOBLL*M~Unsfp+5pl8UZ@$YD=dkN#ZN#RObvIzM%^p%fRZPrA# zzt?6%dwK0G_~+}cEAr%R(C1`dnXs@o*x`GOkeCat+$+n42hQM`yb+yu2L0P*j-_YS z!4W&d=&S+Is?Ifyej~{3%!8*?QxiE?kmlmSaMWcJYbkcShT3m6A0rx6V-F|&`U3If zD(ppgR4f!SUsLMPF24*F?yx}A700{+}3twSuwL95$GFVPeM`FMrxqDE!NbMn|(v`X@r zqV|SbwTXLo(UWO)Yj^YPBiEsc+_|NEI$Kly7@IE7HbMM_jpVAwK(8{AuSNz)twPbn>5syCz zsP{wmhBe}RJNRcVPcy* z@Yu?fc4BjD^e-!UM>b>CxTDr!5JggD)aa8aJHA9Kd*Ns8zLUfI~~B)gTv5 z$KY$wWO-`g0Igt*$B4ggvwIpM&W|}SUvUKbI7D+oZyj7OGK6D79UJ3GgVktxDzv)% zYA~IZhaBdf-%ba_Bez$t3+brd$obrnW@6uIsKqK}fEZ#3Klr{{EbiTl+WpLSiUo5P z*J~nti4o7Ng>L&Sc8a5X;IU<1{^H1kXs_MEQ9R#+`P03Hcwq^AyL!@Xx^6g*o6g13 zzvq!p)V!IrtQdLveeX!DA}oyIaMX{9)K zQx~T>bWDU+Nv}7_S|(via(iq1e(B{q(baPx}u=|MH9zbi^|pcbNZDddLj9eS6T8_Ax@vzPmpP+U5V% z>cb09$HvT8-mcEFB&O9(-E`T`4bbXL_B+`~Y0pHV6fVos0I$cJzR53Er2o zir8A^GN&PMUvR8d8;=OvZNLLtx1!}EvA_5E;Y?~f5W2-|Jxb3uLH;goFKG|<-b6?9 zHsbjHsP}4;h4`U8eDb`)P7FE=4Od_9DPHM^_d9BCw-Vz5(SC5i3mW6P#x3oLBOZfsWAshM(yEvcAV%NctIXw45K>rsjOJrMmf@kjfnEfUMIka{4 z6xv>cR_A?R3AI0vvsPmVYSkRvr*9}dZGgJwbv{Lx+rtk_<`&UGdr|wJihFd(LNMol zmHONSKP@~#-^ZhUa_t8CEe-v&On0C=Mf7iZvPO{JW5!&1FiHqz>%IPCS_z%IA?Nq5 z*R$W9{I6EaPZc;GU|O~G$dNr{*TEsa&Rl#1^jUBqk~`A}yj1l9x4IbPZe`VVuKz6P zCe~i(HcQXFD7^P+MkaUB7hGPujdOnit(>b&xzj_yTI0VDNI3}I{tJ_$ir5$E~7u>g^nUhx5AImJ-lnywJxVg6~-QwQn zjL;_~6zt!{fXrt5;Xk|$$UGO+b#kl$QJDg6=&S6uy=8^$9_RGfKAg$}v{~&;xv|o{ zvto_ppQTT%=72wTb0xQ>d0r83Q5{Ggm*Kemk8CB{Y@b0hXD^vP6!AGj4-nta&?kJv z0rFVdTTqPC#l!cJooa}W3)w;1Play7Y(mJ+2xwKUvw}R>i~D81$3oIUntv3p?e%&# z888szZf5ulGUquPr|l<^E{E~jPLIZsV;9l?{9a>8JGSSRIejGQtcE?S&V|Fs683(_ zfG^G@pf%!)#uDPh-d}F0)xx18WsliD!{6UyxtnZHX8irDQ_cX}22s47w3O zqS$yG>mN;My7p-R)%`{5dpdaSWbip##JEtA>p@sQ2?l`O0D43?=rdm^K6qh)EAH8`ogtWilv z&b!HF8EGQp?DpK3Sq}2xG&)tvqL%w}Qa_x@%?xIg+Dq^*DQ^RE}+Ps1lyEwU&96vsa{T_w~T!F`IyrzB+~oZ<=ikACo+z{<@B=$ z5lIKGu>DXX5BS<2yCwq`yCE7$~*+i+X*2LLnGI`y%E&1_SdgJ7+9+|s(8i|c*M=G^u zNOc-Y-{s~-M%5aVRcf=Odd)~TUvJXbt242^I$NsSoKzajC7F5M$%!dGQvDX>(w=!_ zVK-~CBxk;)Lod?liHoM6q>CdlY_yncaVKQsm&KAk zPUOygf5K%BBGWRKNIDHA%fpwFZ|z5r#nQirC7nl-DBVvatsPAQA1#w~b0e<1mXj&v z<4EYhKuJFjvZW%Bv>GyrT->oj(s2q2v|357oS05}6t0x?oJo35T}4*5m`#3Eu99?} zOYTbVD_i-`C-!P +* +* RawTherapee is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* RawTherapee is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with RawTherapee. If not, see . +*/ + +#include "dcp.h" +#include +#include "safegtk.h" +#include "iccmatrices.h" +#include "iccstore.h" +#include "rawimagesource.h" +#include "improcfun.h" + +using namespace rtengine; +using namespace rtexif; + +#undef CLIP +#define MAXVAL 0xffff +#define CLIP(a) ((a)>0?((a)getTag(TagCalibrationIlluminant2); + bool use2nd = (tag!=NULL && tag->toInt(0,SHORT)>=20 && tag->toInt(0,SHORT)<=23); + + // Color Matrix + tag = tagDir->getTag( use2nd ? TagColorMatrix2 : TagColorMatrix1); + + for (int row=0;row<3;row++) { + for (int col=0;col<3;col++) { + mColorMatrix[col][row]=(float)tag->toDouble((col+row*3)*8); + } + } + + // LUT profile? Divisions counts + bool useSimpleLookup=false; + tag = tagDir->getTag(TagProfileHueSatMapDims); + if (tag==NULL) { + tag=tagDir->getTag(TagProfileLookTableDims); + useSimpleLookup=true; + } + + if (tag!=NULL) { + iHueDivisions=tag->toInt(0); iSatDivisions=tag->toInt(4); iValDivisions=tag->toInt(8); + + // Saturation maps. Need to be unwinded. + tag = tagDir->getTag(useSimpleLookup ? TagProfileLookTableData : ( use2nd ? TagProfileHueSatMapData2 : TagProfileHueSatMapData1)); + iArrayCount = tag->getCount()/3; + + aDeltas=new HSBModify[iArrayCount]; + + const int TIFFFloatSize=4; + for (int i=0;itoDouble((i*3)*TIFFFloatSize); + aDeltas[i].fSatScale=tag->toDouble((i*3+1)*TIFFFloatSize); + aDeltas[i].fValScale=tag->toDouble((i*3+2)*TIFFFloatSize); + } + } + + if (pFile!=NULL) fclose(pFile); + delete tagDir; + + if (iArrayCount>0) { + // Convert DNG color matrix to xyz_cam compatible matrix + int i,j,k; + + double cam_xyz[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}; + for (i=0; i<3; i++) + for (j=0; j<3; j++) + for (k=0; k<3; k++) + cam_xyz[i][j] += mColorMatrix[j][k] * (i==k); + + + // Multiply out XYZ colorspace + double cam_rgb[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}; + for (i=0; i < 3; i++) + for (j=0; j < 3; j++) + for (k=0; k < 3; k++) + cam_rgb[i][j] += cam_xyz[i][k] * xyz_sRGB[k][j]; + + // Normalize cam_rgb so that: cam_rgb * (1,1,1) is (1,1,1,1) + double num; + for (i=0; i<3; i++) { + for (num=j=0; j<3; j++) num += cam_rgb[i][j]; + for (j=0; j<3; j++) cam_rgb[i][j] /= num; + } + + double rgb_cam[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}; + RawImageSource::inverse33 (cam_rgb, rgb_cam); + + memset(mXYZCAM,0,sizeof(mXYZCAM)); + for (i=0; i<3; i++) + for (j=0; j<3; j++) + for (k=0; k<3; k++) + mXYZCAM[i][j] += xyz_sRGB[i][k] * rgb_cam[k][j]; + } +} + +DCPProfile::~DCPProfile() { + delete[] aDeltas; +} + +void DCPProfile::Apply(Imagefloat *pImg, Glib::ustring workingSpace) const { + TMatrix mWork = iccStore->workingSpaceInverseMatrix (workingSpace); + + if (iArrayCount==0) { + //===== No LUT- Calculate matrix for direct conversion raw>working space + double mat[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}; + for (int i=0; i<3; i++) + for (int j=0; j<3; j++) + for (int k=0; k<3; k++) + mat[i][j] += mWork[i][k] * mXYZCAM[k][j]; + + // Apply the matrix part +#pragma omp parallel for + for (int y=0; yheight; y++) { + float newr, newg, newb; + for (int x=0; xwidth; x++) { + newr = mat[0][0]*pImg->r[y][x] + mat[0][1]*pImg->g[y][x] + mat[0][2]*pImg->b[y][x]; + newg = mat[1][0]*pImg->r[y][x] + mat[1][1]*pImg->g[y][x] + mat[1][2]*pImg->b[y][x]; + newb = mat[2][0]*pImg->r[y][x] + mat[2][1]*pImg->g[y][x] + mat[2][2]*pImg->b[y][x]; + + pImg->r[y][x] = newr; pImg->g[y][x] = newg; pImg->b[y][x] = newb; + } + } + } + else { + //===== LUT available- Calculate matrix for conversion raw>ProPhoto + double m2ProPhoto[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}; + for (int i=0; i<3; i++) + for (int j=0; j<3; j++) + for (int k=0; k<3; k++) + m2ProPhoto[i][j] += prophoto_xyz[i][k] * mXYZCAM[k][j]; + + double m2Work[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}; + for (int i=0; i<3; i++) + for (int j=0; j<3; j++) + for (int k=0; k<3; k++) + m2Work[i][j] += mWork[i][k] * xyz_prophoto[k][j]; + + // Preperations for LUT + float hScale = (iHueDivisions < 2) ? 0.0f : (iHueDivisions * (1.0f / 6.0f)); + float sScale = (float) (iSatDivisions - 1); + float vScale = (float) (iValDivisions - 1); + + int maxHueIndex0 = iHueDivisions - 1; + int maxSatIndex0 = iSatDivisions - 2; + int maxValIndex0 = iValDivisions - 2; + + const HSBModify *tableBase = aDeltas; + + int hueStep = iSatDivisions; + int valStep = iHueDivisions * hueStep; + + // Convert to prophoto and apply LUT +#pragma omp parallel for + for (int y=0; yheight; y++) { + float newr, newg, newb, h,s,v; + for (int x=0; xwidth; x++) { + newr = m2ProPhoto[0][0]*pImg->r[y][x] + m2ProPhoto[0][1]*pImg->g[y][x] + m2ProPhoto[0][2]*pImg->b[y][x]; + newg = m2ProPhoto[1][0]*pImg->r[y][x] + m2ProPhoto[1][1]*pImg->g[y][x] + m2ProPhoto[1][2]*pImg->b[y][x]; + newb = m2ProPhoto[2][0]*pImg->r[y][x] + m2ProPhoto[2][1]*pImg->g[y][x] + m2ProPhoto[2][2]*pImg->b[y][x]; + + ImProcFunctions::rgb2hsv(newr, newg, newb, h , s, v); + h*=6.f; // RT calculates in [0,1] + + // Apply the HueSatMap. Ported from Adobes reference implementation + float hueShift, satScale, valScale; + + if (iValDivisions < 2) // Optimize most common case of "2.5D" table. + { + float hScaled = h * hScale; + float sScaled = s * sScale; + + int hIndex0 = (int) hScaled; + int sIndex0 = (int) sScaled; + + sIndex0 = MIN (sIndex0, maxSatIndex0); + + int hIndex1 = hIndex0 + 1; + + if (hIndex0 >= maxHueIndex0) + { + hIndex0 = maxHueIndex0; + hIndex1 = 0; + } + + float hFract1 = hScaled - (float) hIndex0; + float sFract1 = sScaled - (float) sIndex0; + + float hFract0 = 1.0f - hFract1; + float sFract0 = 1.0f - sFract1; + + const HSBModify *entry00 = tableBase + hIndex0 * hueStep + + sIndex0; + + const HSBModify *entry01 = entry00 + (hIndex1 - hIndex0) * hueStep; + + float hueShift0 = hFract0 * entry00->fHueShift + + hFract1 * entry01->fHueShift; + + float satScale0 = hFract0 * entry00->fSatScale + + hFract1 * entry01->fSatScale; + + float valScale0 = hFract0 * entry00->fValScale + + hFract1 * entry01->fValScale; + + entry00++; + entry01++; + + float hueShift1 = hFract0 * entry00->fHueShift + + hFract1 * entry01->fHueShift; + + float satScale1 = hFract0 * entry00->fSatScale + + hFract1 * entry01->fSatScale; + + float valScale1 = hFract0 * entry00->fValScale + + hFract1 * entry01->fValScale; + + hueShift = sFract0 * hueShift0 + sFract1 * hueShift1; + satScale = sFract0 * satScale0 + sFract1 * satScale1; + valScale = sFract0 * valScale0 + sFract1 * valScale1; + + } else { + + float hScaled = h * hScale; + float sScaled = s * sScale; + float vScaled = v * vScale; + + int hIndex0 = (int) hScaled; + int sIndex0 = (int) sScaled; + int vIndex0 = (int) vScaled; + + sIndex0 = MIN (sIndex0, maxSatIndex0); + vIndex0 = MIN (vIndex0, maxValIndex0); + + int hIndex1 = hIndex0 + 1; + + if (hIndex0 >= maxHueIndex0) + { + hIndex0 = maxHueIndex0; + hIndex1 = 0; + } + + float hFract1 = hScaled - (float) hIndex0; + float sFract1 = sScaled - (float) sIndex0; + float vFract1 = vScaled - (float) vIndex0; + + float hFract0 = 1.0f - hFract1; + float sFract0 = 1.0f - sFract1; + float vFract0 = 1.0f - vFract1; + + const HSBModify *entry00 = tableBase + vIndex0 * valStep + + hIndex0 * hueStep + + sIndex0; + + const HSBModify *entry01 = entry00 + (hIndex1 - hIndex0) * hueStep; + + const HSBModify *entry10 = entry00 + valStep; + const HSBModify *entry11 = entry01 + valStep; + + float hueShift0 = vFract0 * (hFract0 * entry00->fHueShift + + hFract1 * entry01->fHueShift) + + vFract1 * (hFract0 * entry10->fHueShift + + hFract1 * entry11->fHueShift); + + float satScale0 = vFract0 * (hFract0 * entry00->fSatScale + + hFract1 * entry01->fSatScale) + + vFract1 * (hFract0 * entry10->fSatScale + + hFract1 * entry11->fSatScale); + + float valScale0 = vFract0 * (hFract0 * entry00->fValScale + + hFract1 * entry01->fValScale) + + vFract1 * (hFract0 * entry10->fValScale + + hFract1 * entry11->fValScale); + + entry00++; + entry01++; + entry10++; + entry11++; + + float hueShift1 = vFract0 * (hFract0 * entry00->fHueShift + + hFract1 * entry01->fHueShift) + + vFract1 * (hFract0 * entry10->fHueShift + + hFract1 * entry11->fHueShift); + + float satScale1 = vFract0 * (hFract0 * entry00->fSatScale + + hFract1 * entry01->fSatScale) + + vFract1 * (hFract0 * entry10->fSatScale + + hFract1 * entry11->fSatScale); + + float valScale1 = vFract0 * (hFract0 * entry00->fValScale + + hFract1 * entry01->fValScale) + + vFract1 * (hFract0 * entry10->fValScale + + hFract1 * entry11->fValScale); + + hueShift = sFract0 * hueShift0 + sFract1 * hueShift1; + satScale = sFract0 * satScale0 + sFract1 * satScale1; + valScale = sFract0 * valScale0 + sFract1 * valScale1; + } + + hueShift *= (6.0f / 360.0f); // Convert to internal hue range. + + h += hueShift; + s *= satScale; // no clipping here, we are RT float :-) + v *= valScale; + + // RT range correction + if (h < 0.0f) h += 6.0f; + if (h >= 6.0f) h -= 6.0f; + h/=6.f; + ImProcFunctions::hsv2rgb( h, s, v, newr, newg, newb); + + pImg->r[y][x] = m2Work[0][0]*newr + m2Work[0][1]*newg + m2Work[0][2]*newb; + pImg->g[y][x] = m2Work[1][0]*newr + m2Work[1][1]*newg + m2Work[1][2]*newb; + pImg->b[y][x] = m2Work[2][0]*newr + m2Work[2][1]*newg + m2Work[2][2]*newb; + } + } + } +} + + +// Integer variant is legacy, only used for thumbs. Simply take the matrix here +void DCPProfile::Apply(Image16 *pImg, Glib::ustring workingSpace) const { + TMatrix mWork = iccStore->workingSpaceInverseMatrix (workingSpace); + + // Calculate matrix for direct conversion raw>working space + double mat[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}; + for (int i=0; i<3; i++) + for (int j=0; j<3; j++) + for (int k=0; k<3; k++) + mat[i][j] += mWork[i][k] * mXYZCAM[k][j]; + + // Apply the matrix part +#pragma omp parallel for + for (int y=0; yheight; y++) { + float newr, newg, newb; + for (int x=0; xwidth; x++) { + newr = mat[0][0]*pImg->r[y][x] + mat[0][1]*pImg->g[y][x] + mat[0][2]*pImg->b[y][x]; + newg = mat[1][0]*pImg->r[y][x] + mat[1][1]*pImg->g[y][x] + mat[1][2]*pImg->b[y][x]; + newb = mat[2][0]*pImg->r[y][x] + mat[2][1]*pImg->g[y][x] + mat[2][2]*pImg->b[y][x]; + + pImg->r[y][x] = CLIP((int)newr); pImg->g[y][x] = CLIP((int)newg); pImg->b[y][x] = CLIP((int)newb); + } + } +} + + +// Generates as singleton +DCPStore* DCPStore::getInstance() +{ + static DCPStore* instance_ = 0; + if ( instance_ == 0 ) + { + static Glib::Mutex smutex_; + Glib::Mutex::Lock lock(smutex_); + if ( instance_ == 0 ) + { + instance_ = new DCPStore(); + } + } + return instance_; +} + +// Reads all profiles from the given profiles dir +void DCPStore::init (Glib::ustring rtProfileDir) { + Glib::Mutex::Lock lock(mtx); + + fileStdProfiles.clear(); + + Glib::ustring rootDirName=rtProfileDir; + + if (rootDirName!="") { + std::deque qDirs; + + qDirs.push_front(rootDirName); + + while (qDirs.size()) { + // process directory + Glib::ustring dirname = qDirs.back(); + qDirs.pop_back(); + + Glib::Dir* dir = NULL; + try { + if (!safe_file_test (dirname, Glib::FILE_TEST_IS_DIR)) return; + dir = new Glib::Dir (dirname); + } + catch (Glib::Exception& fe) { + return; + } + dirname = dirname + "/"; + for (Glib::DirIterator i = dir->begin(); i!=dir->end(); ++i) { + Glib::ustring fname = dirname + *i; + Glib::ustring sname = *i; + // ignore directories + if (!safe_file_test (fname, Glib::FILE_TEST_IS_DIR)) { + int lastdot = sname.find_last_of ('.'); + if (lastdot!=Glib::ustring::npos && lastdot<=(int)sname.size()-4 && (!sname.casefold().compare (lastdot, 4, ".dcp"))) { + Glib::ustring camShortName = sname.substr(0,lastdot).uppercase(); + fileStdProfiles[camShortName]=fname; // they will be loaded and cached on demand + } + } else qDirs.push_front(fname); // for later scanning + } + delete dir; + } + } +} + +DCPProfile* DCPStore::getProfile (Glib::ustring filename) { + Glib::Mutex::Lock lock(mtx); + + std::map::iterator r = profileCache.find (filename); + if (r!=profileCache.end()) return r->second; + + // Add profile + profileCache[filename]=new DCPProfile(filename); + + return profileCache[filename]; +} + +DCPProfile* DCPStore::getStdProfile(Glib::ustring camShortName) { + std::map::iterator r = fileStdProfiles.find (camShortName); + if (r==fileStdProfiles.end()) return NULL; + + return getProfile(r->second); +} + +bool DCPStore::isValidDCPFileName(Glib::ustring filename) const { + return safe_file_test (filename, Glib::FILE_TEST_EXISTS) + && !filename.casefold().compare (filename.find_last_of ('.'), 4, ".dcp"); +} \ No newline at end of file diff --git a/rtengine/dcp.h b/rtengine/dcp.h new file mode 100644 index 000000000..7ff047228 --- /dev/null +++ b/rtengine/dcp.h @@ -0,0 +1,76 @@ +/* +* This file is part of RawTherapee. +* +* Copyright (c) 2012 Oliver Duis +* +* RawTherapee is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* RawTherapee is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with RawTherapee. If not, see . +*/ + +#ifndef _DCP_ +#define _DCP_ + +#include "imagefloat.h" +#include +#include +#include + +namespace rtengine { + + class DCPProfile { + struct HSBModify + { + float fHueShift; + float fSatScale; + float fValScale; + }; + + double mColorMatrix[3][3]; + double mXYZCAM[3][3]; // compatible to RTs xyz_cam + HSBModify *aDeltas; + + int iHueDivisions, iSatDivisions, iValDivisions; + + int iHueStep, iValStep, iArrayCount; + + public: + DCPProfile(Glib::ustring fname); + ~DCPProfile(); + + void Apply(Imagefloat *pImg, Glib::ustring workingSpace) const; + void Apply(Image16 *pImg, Glib::ustring workingSpace) const; + }; + + class DCPStore { + Glib::Mutex mtx; + + // these contain standard profiles from RT. keys are all in uppercase, file path is value + std::map fileStdProfiles; + + // Maps file name to profile as cache + std::map profileCache; + + public: + void init(Glib::ustring rtProfileDir); + + bool isValidDCPFileName(Glib::ustring filename) const; + + DCPProfile* getProfile(Glib::ustring filename); + DCPProfile* getStdProfile(Glib::ustring camShortName); + + static DCPStore* getInstance(); + }; + + #define dcpStore DCPStore::getInstance() +}; +#endif diff --git a/rtengine/improcfun.cc b/rtengine/improcfun.cc index 9211da117..7f9c005e2 100644 --- a/rtengine/improcfun.cc +++ b/rtengine/improcfun.cc @@ -944,7 +944,7 @@ fclose(f);*/ void ImProcFunctions::hsv2rgb (float h, float s, float v, float &r, float &g, float &b) { float h1 = h*6; // sector 0 to 5 - int i = floor( h1 ); + int i = (int)h1; // floor() is very slow, and h1 is always >0 float f = h1 - i; // fractional part of h float p = v * ( 1 - s ); diff --git a/rtengine/improcfun.h b/rtengine/improcfun.h index 7affea848..7f1650c69 100644 --- a/rtengine/improcfun.h +++ b/rtengine/improcfun.h @@ -162,8 +162,8 @@ class ImProcFunctions { static double getAutoDistor (const Glib::ustring& fname, int thumb_size); double getTransformAutoFill (int oW, int oH); - void rgb2hsv (float r, float g, float b, float &h, float &s, float &v); - void hsv2rgb (float h, float s, float v, float &r, float &g, float &b); + static void rgb2hsv (float r, float g, float b, float &h, float &s, float &v); + static void hsv2rgb (float h, float s, float v, float &r, float &g, float &b); void xyz2srgb (float x, float y, float z, float &r, float &g, float &b); void xyz2rgb (float x, float y, float z, float &r, float &g, float &b, float rgb_xyz[3][3]); void Lab2XYZ(float L, float a, float b, float &x, float &y, float &z); diff --git a/rtengine/init.cc b/rtengine/init.cc index 597acb075..ced941921 100644 --- a/rtengine/init.cc +++ b/rtengine/init.cc @@ -18,6 +18,7 @@ */ #include "rtengine.h" #include "iccstore.h" +#include "dcp.h" #include "improcfun.h" #include "improccoordinator.h" #include "curves.h" @@ -37,6 +38,8 @@ int init (const Settings* s, Glib::ustring baseDir) { iccStore->init (s->iccDirectory, baseDir + "/iccprofiles"); iccStore->findDefaultMonitorProfile(); + dcpStore->init (baseDir + "/dcpprofiles"); + ProcParams::init (); CurveFactory::init (); ImProcFunctions::initMunsell(); diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index f915231ba..c7652e211 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -31,6 +31,7 @@ #include "slicer.h" #include #include "../rtgui/options.h" +#include "dcp.h" @@ -1680,10 +1681,16 @@ void RawImageSource::colorSpaceConversion (Imagefloat* im, ColorManagementParams //MyTime t1, t2, t3; //t1.set (); cmsHPROFILE in; - if (!findInputProfile(cmp.input, embedded, camName, in)) return; + DCPProfile *dcpProf; + + if (!findInputProfile(cmp.input, embedded, camName, &dcpProf, in)) return; + + if (dcpProf!=NULL) { + dcpProf->Apply(im, cmp.working); + } else { // Calculate matrix for direct conversion raw>working space TMatrix work = iccStore->workingSpaceInverseMatrix (cmp.working); - float mat[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}; + double mat[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}; for (int i=0; i<3; i++) for (int j=0; j<3; j++) for (int k=0; k<3; k++) @@ -1887,7 +1894,7 @@ void RawImageSource::colorSpaceConversion (Imagefloat* im, ColorManagementParams if (imgPreLCMS!=NULL) delete imgPreLCMS; } - + } //t3.set (); // printf ("ICM TIME: %d\n", t3.etime(t1)); } @@ -1897,8 +1904,13 @@ void RawImageSource::colorSpaceConversion (Imagefloat* im, ColorManagementParams // Converts raw image including ICC input profile to working space - 16bit int version void RawImageSource::colorSpaceConversion16 (Image16* im, ColorManagementParams cmp, cmsHPROFILE embedded, cmsHPROFILE camprofile, double camMatrix[3][3], std::string camName, double& defgain) { cmsHPROFILE in; - if (!findInputProfile(cmp.input, embedded, camName, in)) return; + DCPProfile *dcpProf; + if (!findInputProfile(cmp.input, embedded, camName, &dcpProf, in)) return; + + if (dcpProf!=NULL) { + dcpProf->Apply(im, cmp.working); + } else { if (in==NULL) { // Take camprofile from DCRAW // in this case we avoid using the slllllooooooowwww lcms @@ -1970,23 +1982,30 @@ TMatrix work = iccStore->workingSpaceInverseMatrix (cmp.working); cmsDeleteTransform(hTransform); } - + } //t3.set (); // printf ("ICM TIME: %d\n", t3.etime(t1)); } // Determine RAW input and output profiles. Returns TRUE on success -bool RawImageSource::findInputProfile(Glib::ustring inProfile, cmsHPROFILE embedded, std::string camName, cmsHPROFILE& in) { +bool RawImageSource::findInputProfile(Glib::ustring inProfile, cmsHPROFILE embedded, std::string camName, DCPProfile **dcpProf, cmsHPROFILE& in) { in=NULL; // cam will be taken on NULL + *dcpProf=NULL; if (inProfile == "(none)") return false; if (inProfile == "(embedded)" && embedded) { in = embedded; } else if (inProfile=="(cameraICC)") { - in = iccStore->getStdProfile(camName); + // DCPs have higher quality, so use them first + *dcpProf=dcpStore->getStdProfile(camName); + if (*dcpProf==NULL) in = iccStore->getStdProfile(camName); } else if (inProfile!="(camera)" && inProfile!="") { - in = iccStore->getProfile (inProfile); + Glib::ustring normalName=inProfile; + if (!inProfile.compare (0, 5, "file:")) normalName=inProfile.substr(5); + + if (dcpStore->isValidDCPFileName(normalName)) *dcpProf=dcpStore->getProfile(normalName); + if (*dcpProf==NULL) in = iccStore->getProfile (inProfile); } // "in" might be NULL because of "not found". That's ok, we take the cam profile then @@ -2561,7 +2580,7 @@ void RawImageSource::transformPosition (int x, int y, int tran, int& ttx, int& t //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -void RawImageSource::inverse33 (double (*rgb_cam)[3], double (*cam_rgb)[3]) { +void RawImageSource::inverse33 (const double (*rgb_cam)[3], double (*cam_rgb)[3]) { double nom = (rgb_cam[0][2]*rgb_cam[1][1]*rgb_cam[2][0] - rgb_cam[0][1]*rgb_cam[1][2]*rgb_cam[2][0] - rgb_cam[0][2]*rgb_cam[1][0]*rgb_cam[2][1] + rgb_cam[0][0]*rgb_cam[1][2]*rgb_cam[2][1] + rgb_cam[0][1]*rgb_cam[1][0]*rgb_cam[2][2] - rgb_cam[0][0]*rgb_cam[1][1]*rgb_cam[2][2] ); diff --git a/rtengine/rawimagesource.h b/rtengine/rawimagesource.h index 57b9d3a6a..764651883 100644 --- a/rtengine/rawimagesource.h +++ b/rtengine/rawimagesource.h @@ -21,6 +21,7 @@ #include "imagesource.h" #include +#include "dcp.h" #include "array2D.h" #include "curves.h" #include "../rtgui/cacheimagedata.h" @@ -60,7 +61,7 @@ class RawImageSource : public ImageSource { private: static LUTf invGrad; // for fast_demosaic static LUTf initInvGrad (); - static bool findInputProfile(Glib::ustring inProfile, cmsHPROFILE embedded, std::string camName, cmsHPROFILE& in); + static bool findInputProfile(Glib::ustring inProfile, cmsHPROFILE embedded, std::string camName, DCPProfile **dcpProf, cmsHPROFILE& in); protected: Glib::Mutex getImageMutex; // locks getImage @@ -167,7 +168,7 @@ class RawImageSource : public ImageSource { static void colorSpaceConversion16 (Image16* im, ColorManagementParams cmp, cmsHPROFILE embedded, cmsHPROFILE camprofile, double cam[3][3], std::string camName, double& defgain); static void colorSpaceConversion (Imagefloat* im, ColorManagementParams cmp, cmsHPROFILE embedded, cmsHPROFILE camprofile, double cam[3][3], std::string camName, double& defgain); - static void inverse33 (double (*coeff)[3], double (*icoeff)[3]); + static void inverse33 (const double (*coeff)[3], double (*icoeff)[3]); void boxblur2(float** src, float** dst, int H, int W, int box ); void boxblur_resamp(float **src, float **dst, float & max, int H, int W, int box, int samp ); diff --git a/rtexif/rtexif.cc b/rtexif/rtexif.cc index bc8c7e095..96e5a90db 100644 --- a/rtexif/rtexif.cc +++ b/rtexif/rtexif.cc @@ -24,6 +24,7 @@ #include #include #include +#include #include "rtexif.h" @@ -45,7 +46,7 @@ TagDirectory::TagDirectory () TagDirectory::TagDirectory (TagDirectory* p, const TagAttrib* ta, ByteOrder border) : attribs(ta), order(border), parent(p) {} -TagDirectory::TagDirectory (TagDirectory* p, FILE* f, int base, const TagAttrib* ta, ByteOrder border) { +TagDirectory::TagDirectory (TagDirectory* p, FILE* f, int base, const TagAttrib* ta, ByteOrder border, bool skipIgnored) { attribs = ta; order = border; @@ -66,6 +67,7 @@ TagDirectory::TagDirectory (TagDirectory* p, FILE* f, int base, const TagAttrib* continue; } + if (skipIgnored) { int id = newTag->getID(); // detect and possibly ignore tags of directories belonging to the embedded thumbnail image @@ -78,6 +80,7 @@ TagDirectory::TagDirectory (TagDirectory* p, FILE* f, int base, const TagAttrib* delete newTag; else addTag (newTag); + } else addTag (newTag); } } @@ -759,7 +762,7 @@ int Tag::toInt (int ofs, TagType astype) { case LONG: return (int)sget4 (value+ofs, getOrder()); case SRATIONAL: case RATIONAL: a = (int)sget4 (value+ofs+4, getOrder()); return a==0 ? 0 : (int)sget4 (value+ofs, getOrder()) / a; - case FLOAT: return (int)((float) sget4 (value+ofs, getOrder())); + case FLOAT: return (int)toDouble(ofs); case UNDEFINED: return 0; default: return 0; // Quick fix for missing cases (INVALID, DOUBLE, OLYUNDEF, SUBDIR) } @@ -767,6 +770,7 @@ int Tag::toInt (int ofs, TagType astype) { } double Tag::toDouble (int ofs) { + union IntFloat { uint32_t i; float f; } conv; double ud, dd; switch (type) { @@ -778,7 +782,10 @@ double Tag::toDouble (int ofs) { case LONG: return (double)((int)sget4 (value+ofs, getOrder())); case SRATIONAL: case RATIONAL: ud = (int)sget4 (value+ofs, getOrder()); dd = (int)sget4 (value+ofs+4, getOrder()); return dd==0. ? 0. : (double)ud / (double)dd; - case FLOAT: return (float) sget4 (value+ofs, getOrder()); + case FLOAT: + conv.i=sget4 (value+ofs, getOrder()); + return conv.f; // IEEE FLOATs are already C format, they just need a recast + case UNDEFINED: return 0.; default: return 0.; // Quick fix for missing cases (INVALID, DOUBLE, OLYUNDEF, SUBDIR) } @@ -1302,7 +1309,7 @@ void ExifManager::parseCIFF (FILE* f, int base, int length, TagDirectory* root) } } -TagDirectory* ExifManager::parse (FILE* f, int base) { +TagDirectory* ExifManager::parse (FILE* f, int base, bool skipIgnored) { setlocale(LC_NUMERIC, "C"); // to set decimal point in sscanf // read tiff header fseek (f, base, SEEK_SET); @@ -1316,7 +1323,7 @@ TagDirectory* ExifManager::parse (FILE* f, int base) { fseek (f, base+firstifd, SEEK_SET); // first read the IFD directory - TagDirectory* root = new TagDirectory (NULL, f, base, ifdAttribs, order); + TagDirectory* root = new TagDirectory (NULL, f, base, ifdAttribs, order, skipIgnored); // fix ISO issue with nikon and panasonic cameras Tag* exif = root->getTag ("Exif"); @@ -1373,9 +1380,9 @@ TagDirectory* ExifManager::parseJPEG (FILE* f) { return NULL; } -TagDirectory* ExifManager::parseTIFF (FILE* f) { +TagDirectory* ExifManager::parseTIFF (FILE* f, bool skipIgnored) { - return parse (f, 0); + return parse (f, 0, skipIgnored); } std::vector ExifManager::defTags; diff --git a/rtexif/rtexif.h b/rtexif/rtexif.h index 58c1bbc8c..d77f4ec0d 100644 --- a/rtexif/rtexif.h +++ b/rtexif/rtexif.h @@ -69,7 +69,7 @@ class TagDirectory { public: TagDirectory (); - TagDirectory (TagDirectory* p, FILE* f, int base, const TagAttrib* ta, ByteOrder border); + TagDirectory (TagDirectory* p, FILE* f, int base, const TagAttrib* ta, ByteOrder border, bool skipIgnored=true); TagDirectory (TagDirectory* p, const TagAttrib* ta, ByteOrder border); virtual ~TagDirectory (); @@ -197,9 +197,9 @@ class ExifManager { static Tag* saveCIFFMNTag (FILE* f, TagDirectory* root, int len, const char* name); public: - static TagDirectory* parse (FILE*f, int base); + static TagDirectory* parse (FILE*f, int base, bool skipIgnored=true); static TagDirectory* parseJPEG (FILE*f); - static TagDirectory* parseTIFF (FILE*f); + static TagDirectory* parseTIFF (FILE*f, bool skipIgnored=true); static TagDirectory* parseCIFF (FILE* f, int base, int length); static void parseCIFF (FILE* f, int base, int length, TagDirectory* root); diff --git a/rtgui/icmpanel.cc b/rtgui/icmpanel.cc index a8a651c02..c4a77825f 100644 --- a/rtgui/icmpanel.cc +++ b/rtgui/icmpanel.cc @@ -22,6 +22,7 @@ #include "guiutils.h" #include "../rtengine/safegtk.h" #include "../rtengine/iccstore.h" +#include "../rtengine/dcp.h" #include "rtimage.h" using namespace rtengine; @@ -160,6 +161,8 @@ ICMPanel::ICMPanel () : Gtk::VBox(), FoldableToolPanel(this), iunchanged(NULL), Gtk::FileFilter filter_icc; filter_icc.set_name(M("TP_ICM_FILEDLGFILTERICM")); + filter_icc.add_pattern("*.dcp"); + filter_icc.add_pattern("*.DCP"); filter_icc.add_pattern("*.icc"); filter_icc.add_pattern("*.icm"); filter_icc.add_pattern("*.ICC"); @@ -437,7 +440,7 @@ void ICMPanel::setRawMeta (bool raw, const rtengine::ImageData* pMeta) { icamera->set_active (raw); iembedded->set_active (!raw); icamera->set_sensitive (raw); - icameraICC->set_sensitive (raw && iccStore->getStdProfile(pMeta->getCamera()) != NULL); + icameraICC->set_sensitive (raw && (iccStore->getStdProfile(pMeta->getCamera()) != NULL || dcpStore->getStdProfile(pMeta->getCamera()) != NULL)); iembedded->set_sensitive (!raw); enableListener ();