From 42bedda0a74209cb0a4e834b3b1ad42e0f8d2de8 Mon Sep 17 00:00:00 2001 From: treeform Date: Fri, 18 Mar 2022 19:24:56 -0700 Subject: [PATCH 1/3] Fix #372 - Add negative spread. --- src/pixie/masks.nim | 11 +++++++++-- tests/masks/drawPolygon.png | Bin 853 -> 737 bytes tests/masks/negativeSpread.png | Bin 0 -> 180 bytes tests/masks/strokePolygon.png | Bin 1400 -> 1273 bytes tests/test_masks.nim | 11 +++++++++++ 5 files changed, 20 insertions(+), 2 deletions(-) create mode 100644 tests/masks/negativeSpread.png diff --git a/src/pixie/masks.nim b/src/pixie/masks.nim index ea7b718..465dd86 100644 --- a/src/pixie/masks.nim +++ b/src/pixie/masks.nim @@ -234,14 +234,21 @@ proc getValueSmooth*(mask: Mask, x, y: float32): uint8 {.raises: [].} = else: topMix +proc invert(mask: Mask) {.raises: [].} = + ## Makes inverts all values - creates a negative of the mask. + for i in 0 ..< mask.data.len: + mask.data[i] = 255 - mask.data[i] + proc spread*(mask: Mask, spread: float32) {.raises: [PixieError].} = ## Grows the mask by spread. let spread = round(spread).int if spread == 0: return if spread < 0: - raise newException(PixieError, "Cannot apply negative spread") - + mask.invert() + spread(mask, -spread.float32) + mask.invert() + return # Spread in the X direction. Store with dimensions swapped for reading later. let spreadX = newMask(mask.height, mask.width) for y in 0 ..< mask.height: diff --git a/tests/masks/drawPolygon.png b/tests/masks/drawPolygon.png index abd187e6caf02634e38bf9f260ef5d7adab20646..c16c400c321c54864ad69538edd9ebfd4b4e45d3 100644 GIT binary patch delta 714 zcmV;*0yX{B2H^#eBYy&@NklI#UaDQARI4%+^Gp?H6!-LbL za{%=u_A9+xYEG<;&XY8xxK{a|?9~9YCg02liiIL^hkfP7-sR1nvA8i*L0wWEyynR7 z=s33Z{cL_JM^&=AGqj^{r&_;lAXRt?Ls4=h++1qjqI8cpF>1ajL`hQDciJvmZEra+ zG9|iULP6rVaeuSQv}%c}6TO47z!C}^7YUAw1jj{! z<08Rvk>I#Ua9kufE)pv=u4r8)=@>Z*5VciL wmn;WjT+4$cBseY-92W_Wiv-6-;{S>34~sR%jC|_ZMgRZ+07*qoM6N<$f_8LH3;+NC delta 831 zcmV-F1Hk;@1=R+SBYy)NNkl zGsGk#S{nLf5Iq!8Jp>UH5mESuFta~cwDnR{MD&m~1FcLDTtXT`3r2=1vYhdAu-|rn z=bU@*7QJ*oFS>KS=l8wm?8kn;d$ZU-K$|F`$EAcGmlAqhN`L5aDWS)ugdUd?|JArE zKcAuK8xxLBJgy}^2YD4|N0iJnCSlTY(9q#HzW3wF7{X5M5A$M56nEz=nu{Scxv(uJ z#L3Hlf+rUdnUr;AF6t;Y`9f4${GIfa(DeqHCAW+}ID$@gpTJ8^ia(5)9{^~R9KRi? zu~ObPZw;EzCV$6jO(li>*J~2rD_v!bxkLH;vr40xOq87?utiPN^p0TU(GNi zQfzoUiR-9N?ib;8JQ-y-_>c)WMPi~Zg%^p)x0?7;WN3k(B?fpWY-mTJp^&8SC@v&S*vG^2 zuc^_R6kk&(S3B|5adchh0*O$aut1aS*5T)#lz+Dl(+k@Z7esLSDUqZ*Vej_IZRdgw zX>8}_C+esb#_Q&z!k)AbaAs$ACaucK@mJPZGQv*SfQLR*`_%Xs4%MQ;hU9f|><@AQE8N)555 zCK9o7&;!GZT4z4)kLgmDusgrRxN2!DyfhX z+JIbo^13s#4|aCg*PKaX%zpl0e=|EX-<==3bMyPnJh%y%B7anv?xMnU7Zs+vsQ7QX zE9$ud-!#=cfO;kyyc^bSxpIL{h0a~spFNYnKz#YyuB$XMG$M&_dzM&&764|kYvGRp z<1)rYBDS;lG5}17L4R$vfzF^&8N(ul-ijzRC=+7P1)>Vee(U2beGH0ZHttCl2IDmV zAi2WcaSa)|7=IFpd%ba~(ny)L@nlLZQjkwan?jfR1LRBQ? zy${o*W;}!2whba{aDRVZEHW_CY8JKmu`-T|i1pbcd3ZC#-}}ma=!)p^fIR{k7&)$B z#|&1MP!@4`%dAoxo}-SVle~qPY-vu*LI#HQflULwSa}vDk-M8;Oq^{X@YBY9qk<_g zdiaNx3x5P#BynTGxnZ#&p(HYJhjgFk`qMT2yoGbwGqffeuKetXkj*`f3qH_BE zk~1NBH=am(8kN95vTbtB>cN{oEc zVN1epgdy_ROI3>R3(h6?Xuk9=(u?db{?5Q}Y=5xzKtir4OD|%(A@x1R}m$=UA6nQsGTj6j-0FpMZ?$p}WFa3D;?4~}*ged}$ zQGc7%surN!wznZunq!b*49{dI5!YH)*Nk;3g<6)Hng|&~p_WpEf$8v}9y=NSE~vW4Cl7y@9N0?+zwmqYP6Z9cRT!Yx?a#yB z7>+DgOuH1w-&)s{%~fNJ*H!+46(y9GdVc_zIn$7ogA9y_f~t`op(cDVk)rm2j!yLisItv2O$Q}33x@@+Ix z?o2T8?dR#(IylQ$#hSAyv01#~R#IF>O9D<%lPU-(Hi(eQQ0SKI6?^?`tJmok@aS%i$0&unQXL|zlJD;aI z(xMarxZn=7RA{Blm7sAK$Mosbw8xC}BH=(ilW;Ias4(3{h3PIT{y*;e2bD8=?_(F& Q?*IS*07*qoM6N<$f(oB!761SM delta 1382 zcmV-s1)2K!3HS<-BYy=yNkl>u;GLN*kKGkZ>$?_yRvPt=uwQ zE6JY{6Nxe~$lgZF)heAPtGSxh)Ykand?7I>Ovt6J8nd=aKtzISG;|UMTV(F1As{cm zU%QvzdCtA(o^$TKs8dC1l5i|q)!4v&uur0rn(SUA$utl>6RlA?h2RhHG+f1#Ny!I*F?cUVmIYXk>hTRXZA?SJP3Ef+sD{^M6Y{Em;ZV zG(71D34e9)Ojhimg4|0q77_S;19r_ma}i^NV-j%!-!G{80F@FtQ&X`wqs;u~a!g*z z$BaRb4`Ufk#Sx@C{+|XCB4(2*H8|(N&f_SQ;&VNS{fqYvU>wA3vg?6h7eIIJ5XN%O zJ`+O(u8Ai}NHCeqEe|7o@M05&77X>SLB#@7L4Rp7IXVl~^$wQCww2RKURcT@5(Z&S zJg;N%5XkNhitNy~5fc+znQ5Cbah-?@Ku}%riJglRx)bRFbvP7*N0F=3sqL4+Yo`FrL-^6eX z)&!c1#zqSOreA1P54L#f6_kyxX20%CCcOz6D9`lTomTFw#c2h~4&ViXm`tF)2q(xG zaZ$*yl`f7xkBtd(VBk@_g8PWQsXnn1r+<2Q<2y_zn4bjB<=~2H zqUGn1TJNWo0ChEXjHc+oC3ZuU^beVbYVQlNoc7IT& z-t=W*VtSRl;7&O}Z?xnLrs<&q11(wj=@34PR}@kX(Q@iDHw#>`U#ealK3al}m)DJBvtanIwRnMr zqHRdJAptM&zZX@+PXcW#=!$C1Pp^tK5)){pMWH4Bwd351>bYmW<;4jHKP3?d*^@v+ zk=^aV>z;9M5B3F?bMA{Jpa5)>&Z5#MfwQ@Gwrmx+kpDlnY)3DzWAEFH0$)(@o4Hws z{7ImFNs>-1;@d5vo-r&;;5;oTg^a9WOGXAOlipJP=A)ic3lB?^TY}Y-+!8`2jtC8x oBSORFh|q93A~al%xGlr=ADUKO`h0S~wEzGB07*qoM6N<$g1n@r5&!@I diff --git a/tests/test_masks.nim b/tests/test_masks.nim index f0ae841..0b9d105 100644 --- a/tests/test_masks.nim +++ b/tests/test_masks.nim @@ -92,6 +92,17 @@ block: a.writeFile("tests/masks/spread.png") +block: + let path = newPath() + path.rect(40, 40, 20, 20) + + let a = newMask(100, 100) + a.fillPath(path) + + a.spread(-5) + + a.writeFile("tests/masks/negativeSpread.png") + block: let mask = newMask(100, 100) From 6068a923633d948efe9669c98a6d1544f0d62215 Mon Sep 17 00:00:00 2001 From: treeform Date: Fri, 18 Mar 2022 22:24:46 -0700 Subject: [PATCH 2/3] Split invert out. --- src/pixie/images.nim | 42 +++++++++++---------------------- src/pixie/masks.nim | 21 +++++++++++++---- tests/images/drawPolygon.png | Bin 1442 -> 1357 bytes tests/images/strokePolygon.png | Bin 2448 -> 2271 bytes 4 files changed, 30 insertions(+), 33 deletions(-) diff --git a/src/pixie/images.nim b/src/pixie/images.nim index 90e760c..b3b4cf8 100644 --- a/src/pixie/images.nim +++ b/src/pixie/images.nim @@ -434,45 +434,31 @@ proc applyOpacity*(target: Image | Mask, opacity: float32) {.raises: [].} = for j in i ..< target.data.len: target.data[j] = ((target.data[j] * opacity) div 255).uint8 -proc invert*(target: Image | Mask) {.raises: [].} = +proc invert*(target: Image) {.raises: [].} = ## Inverts all of the colors and alpha. var i: int when defined(amd64) and not defined(pixieNoSimd): let vec255 = mm_set1_epi8(cast[int8](255)) - - when type(target) is Image: - let byteLen = target.data.len * 4 - else: - let byteLen = target.data.len - + let byteLen = target.data.len * 4 for _ in 0 ..< byteLen div 16: - when type(target) is Image: - let index = i div 4 - else: - let index = i - + let index = i div 4 var values = mm_loadu_si128(target.data[index].addr) values = mm_sub_epi8(vec255, values) mm_storeu_si128(target.data[index].addr, values) - i += 16 - when type(target) is Image: - for j in i div 4 ..< target.data.len: - var rgba = target.data[j] - rgba.r = 255 - rgba.r - rgba.g = 255 - rgba.g - rgba.b = 255 - rgba.b - rgba.a = 255 - rgba.a - target.data[j] = rgba + for j in i div 4 ..< target.data.len: + var rgba = target.data[j] + rgba.r = 255 - rgba.r + rgba.g = 255 - rgba.g + rgba.b = 255 - rgba.b + rgba.a = 255 - rgba.a + target.data[j] = rgba - # Inverting rgbx(50, 100, 150, 200) becomes rgbx(205, 155, 105, 55). This - # is not a valid premultiplied alpha color. - # We need to convert back to premultiplied alpha after inverting. - target.data.toPremultipliedAlpha() - else: - for j in i ..< target.data.len: - target.data[j] = (255 - target.data[j]).uint8 + # Inverting rgbx(50, 100, 150, 200) becomes rgbx(205, 155, 105, 55). This + # is not a valid premultiplied alpha color. + # We need to convert back to premultiplied alpha after inverting. + target.data.toPremultipliedAlpha() proc blur*( image: Image, radius: float32, outOfBounds: SomeColor = color(0, 0, 0, 0) diff --git a/src/pixie/masks.nim b/src/pixie/masks.nim index 465dd86..e2eb151 100644 --- a/src/pixie/masks.nim +++ b/src/pixie/masks.nim @@ -234,17 +234,28 @@ proc getValueSmooth*(mask: Mask, x, y: float32): uint8 {.raises: [].} = else: topMix -proc invert(mask: Mask) {.raises: [].} = - ## Makes inverts all values - creates a negative of the mask. - for i in 0 ..< mask.data.len: - mask.data[i] = 255 - mask.data[i] +proc invert*(mask: Mask) {.raises: [].} = + ## Inverts all of the values - creates a negative of the mask. + var i: int + when defined(amd64) and not defined(pixieNoSimd): + let vec255 = mm_set1_epi8(cast[int8](255)) + let byteLen = mask.data.len + for _ in 0 ..< byteLen div 16: + let index = i + var values = mm_loadu_si128(mask.data[index].addr) + values = mm_sub_epi8(vec255, values) + mm_storeu_si128(mask.data[index].addr, values) + i += 16 + + for j in i ..< mask.data.len: + mask.data[j] = (255 - mask.data[j]).uint8 proc spread*(mask: Mask, spread: float32) {.raises: [PixieError].} = ## Grows the mask by spread. let spread = round(spread).int if spread == 0: return - if spread < 0: + elif spread < 0: mask.invert() spread(mask, -spread.float32) mask.invert() diff --git a/tests/images/drawPolygon.png b/tests/images/drawPolygon.png index f68adc116acf383d0d213996aa90ecfdf1ac2ad0..b117fed8b248b2b722b5c782cef81798d9a0a701 100644 GIT binary patch literal 1357 zcmeAS@N?(olHy`uVBq!ia0vp^DImQYSV8$9Czi^)W})6=JV#?S$OHmt9O>qEkD&HDBRgyUH81^;hTHi`_-Lv z#FV9aZ}sfaxdy(4LsJQk?c5Sqr#~OfmEFiBYeU>FPeK2_)pJt)GReI z?u(aP@M1fTb!awI!b*+3*y6(w(x%KO9!cP1axp*MY z?Xq80|M{zGB950V9dxJeITO?NsrbFCc_{XV>G9k2a+~ z>XYY+*Y>(??)J*^c&c*y#AA`^@n5nleRC(g-19omzcpup{{L^ktWIS6BpIi!d0^oD zW7fvKb-wy5xF;PhyH;$!Ir7atPu1CbtY;spQrkQ+Y}1d<#FKU|>sN3pegA#*%(Kum z!#T}+tya36FqB(9t>o6tQx*S~)GO_Ow(~&qiP~Ddt813Fe9Za!r{(-qSM8}+F1d1@ zeRAn!>T|oJ;f-vX%jU6lX(sBf{PXyA=X}q;TJ`w`y;HXoGw1f$d`^sK6-wc`AKQq8P8KNN-+lXr z0N+IqJM|aSd#3w#=sPNvd{Xhg^VZWYce#LfMxo;*(`T2S*zK2DZh!lvqFdK#tbiB}b|AAB6fpsr}w@^7GQ_eX@=x&MD7apzzp`t)M3->JFdkS*y+u zQvN$CHD}L!a_%7iK9M`d{UaX^} z^+}cKY1@B?Hvdi85q-HvY?mpU;sk}lP4au%yv$u4+t^OjeN>Q1W;p+8&hN#0yA2(6 z7Dg{{Z1M5?G3j=sn`QHlv%X;;Cd-7gN#vw#iuS(1#4n`2*)3)JJ2o!K)8TnyoztJZ z-O)0^{!USj?iHYmUfSe;kodi0rp>mUFKthjOn7)EiPL}M30ZIHQpZOr^QP|cowj{` zrOD39@Vy_+|5i+_^hus7&9q?ZEd?jF{k6wr_Z&XV^Vr>7@?FxJg)K=^E1uhZpEYYG zAJ9^v>mL>72RVpY-^p3)vSpGdXZDI`nct-n1-cXpjbcOclI;ujO0#QUcK?4~KjySd zTw$>nUrUD4N{-M8mw#Pw>ib>iW4FC$@y_a?BbvW9by()L#4Gmnt#q&x!qq^}aanX??HcvN-U5e^ylrk%bC8 cY5e5BzhfJl>#uj^z+#fY)78&qol`;+0I$Dw5C8xG literal 1442 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 literal 2448 zcmbW3`9BkmAIFK52{|VDmSdrP#G*OJ2V-Hi<=7z_%B?>580ABh&pu{3axF}bY|Ctt za^%RBdxqRTj!B23G#^@y7V6{sFMNJ@zn;Im95d>~hIb7N7Hq&ZEVZw{zt6#niAlR75pe7u;;V%+&+#~5@7=s7uf&8dU3OaV2rwc>`W_y8_&DHz zohIn4IMN7RGdld_NP58WU&sjugxR*@NPR=cP!~z@EXQ}YB!)k@%N}V<7lp6Oz4`O@ z7cb2lh))D)^RijgCS7r33vIJ$UU5d%6!F@lur9E zaKdGN_2}Ix?2G5yD{QlVh;*3wj?s0P(WyZ%Iyvwb|g)c6AI> z*Kk}m99cQ{Ss3nFJ-Xn0!#l{T)12FAboU#}j@38)P? zti%~8%PMnmgdw!f3X7a(N7271U(M5*4E>e>c6Y! zhi!$6VG6;m!-lnFsj!Y~bm`A?b32etgC&bBnr2GjYv%ua7A2^DLti9Pz~`oWk^^00 zgUx)IpK1p^1`$aO4epBCy4boKIbeGhhM5AZ<1ecFN2Rf&mb*S+k`@Ru=cfju8 zLNBH8^@LS-8P;_AboaR#LmCnr;Ip7JKB7m=?2bySH8@ixLxdF2csE(IKKvegPGaLl zhFle8h0tE3(*}b)l(Io;+#;?-v<>A<9n4a_KYdjgWHQ+Br=tbxAT@rpf@R@#`K_Cz z>&F0o8LPZcnEyQA`Yb-C!YQjIZ#(BD72U^OGzEpDH^wT^%_CcUrsW(LX|7 z?yA~<)4-v&N)=Ky0U2>rol>tdRbbENHI+l`%e!~Ags`WdhOp%|W~0B}?7~d-+rb=X z9J1;)(H{MXB)4{2ZcCQUOD(Oa@oRM$%0C0p#u<_sfgNlaL=!k8-jD_u^0F~Ih~=M( z&qlU_C)ZO+1l&B6yUf4K}aTjI~Vs@CD(Y63N(tD&s zQ8Z}G{%#(&9B+?TemE5Vo-p}4{6WZ3LjRGlB?ao)nTrgx6X)!a#e_Ol@Ja|>w%;ox zQ+-1Vb3bDaI;03wNcnatFjMX;Xw4E4e6X?!af1pTx6PSv=0-D7m;h~N1BtAwk&eCc zTK;qc8(e0c_thOEu~AZp^f`u;RWOjmg>p`0kRN?Hftyd@^DKwJ z9q_&dTwg(HA`Yr3Yqb;`DwmDMUSLBx1}g1&;(hIE0@lfkXxST`=iJXcdC4~B^g;5H>XdoOMtq)r z>}Nx~Z<~E0s~w=l?l=qB6U#Aw1%jQ=*X8Z;`?k}ib90lG8tE zMv{0WtY3i?Zv!1z5<&yk8zz+!Dmtf-3vvqO7anMqt7O>W5@e?Zle!@#wKx3Uob&oF z`w&_f;W#Gyg-X-pWmJ?U7cj33|40K87Fe&XKMmOZ^UnLL4sh-c&tVe)cY zyUpC|Q!)mZ7gYiPPrupDj@NRy)ihwur*3;btFy}qd$g+16tc(ZainWFM9?4iEN2JL zH)sE*vgJyyw6brU-{45G0qe6pdba2P+FX)c%|>UBiG~+p`r@wi>la(x^gj(!g?Ka@A5?qOxS!o+9~EeZYJW4Uvr}XeUx6_dJ31Y_+b;3a&`M{$g%LR zWOul-lT|@9-+N8?N?FP<{hhbhrry0_32#?iOO=6ttvGffxBTTsax{G0cF_i=T94kb z%Od-wQfp&QE7LT^e?_$pSl15 From 87397c8bf8cc0dc75222d16d3ee165243a5db0ac Mon Sep 17 00:00:00 2001 From: treeform Date: Sun, 20 Mar 2022 08:54:06 -0700 Subject: [PATCH 3/3] Negative spread without inverts. --- src/pixie/masks.nim | 81 +++++++++++++++++++++++++++++---------------- 1 file changed, 53 insertions(+), 28 deletions(-) diff --git a/src/pixie/masks.nim b/src/pixie/masks.nim index e2eb151..3bf80be 100644 --- a/src/pixie/masks.nim +++ b/src/pixie/masks.nim @@ -255,35 +255,60 @@ proc spread*(mask: Mask, spread: float32) {.raises: [PixieError].} = let spread = round(spread).int if spread == 0: return - elif spread < 0: - mask.invert() - spread(mask, -spread.float32) - mask.invert() - return - # Spread in the X direction. Store with dimensions swapped for reading later. - let spreadX = newMask(mask.height, mask.width) - for y in 0 ..< mask.height: - for x in 0 ..< mask.width: - var maxValue: uint8 - for xx in max(x - spread, 0) .. min(x + spread, mask.width - 1): - let value = mask.unsafe[xx, y] - if value > maxValue: - maxValue = value - if maxValue == 255: - break - spreadX.unsafe[y, x] = maxValue + elif spread > 0: - # Spread in the Y direction and modify mask. - for y in 0 ..< mask.height: - for x in 0 ..< mask.width: - var maxValue: uint8 - for yy in max(y - spread, 0) .. min(y + spread, mask.height - 1): - let value = spreadX.unsafe[yy, x] - if value > maxValue: - maxValue = value - if maxValue == 255: - break - mask.unsafe[x, y] = maxValue + # Spread in the X direction. Store with dimensions swapped for reading later. + let spreadX = newMask(mask.height, mask.width) + for y in 0 ..< mask.height: + for x in 0 ..< mask.width: + var maxValue: uint8 + for xx in max(x - spread, 0) .. min(x + spread, mask.width - 1): + let value = mask.unsafe[xx, y] + if value > maxValue: + maxValue = value + if maxValue == 255: + break + spreadX.unsafe[y, x] = maxValue + + # Spread in the Y direction and modify mask. + for y in 0 ..< mask.height: + for x in 0 ..< mask.width: + var maxValue: uint8 + for yy in max(y - spread, 0) .. min(y + spread, mask.height - 1): + let value = spreadX.unsafe[yy, x] + if value > maxValue: + maxValue = value + if maxValue == 255: + break + mask.unsafe[x, y] = maxValue + + elif spread < 0: + + # Spread in the X direction. Store with dimensions swapped for reading later. + let spread = -spread + let spreadX = newMask(mask.height, mask.width) + for y in 0 ..< mask.height: + for x in 0 ..< mask.width: + var maxValue: uint8 = 255 + for xx in max(x - spread, 0) .. min(x + spread, mask.width - 1): + let value = mask.unsafe[xx, y] + if value < maxValue: + maxValue = value + if maxValue == 0: + break + spreadX.unsafe[y, x] = maxValue + + # Spread in the Y direction and modify mask. + for y in 0 ..< mask.height: + for x in 0 ..< mask.width: + var maxValue: uint8 = 255 + for yy in max(y - spread, 0) .. min(y + spread, mask.height - 1): + let value = spreadX.unsafe[yy, x] + if value < maxValue: + maxValue = value + if maxValue == 0: + break + mask.unsafe[x, y] = maxValue proc ceil*(mask: Mask) {.raises: [].} = ## A value of 0 stays 0. Anything else turns into 255.