From 95dfd7d22d15af74a27b82adbdf7056e0357c9c8 Mon Sep 17 00:00:00 2001 From: Alexey Subach Date: Fri, 12 Aug 2022 18:55:32 +0300 Subject: [PATCH] SVG: Initial implementation of stroke-dasharray attribute For now only absolute values are supported. Percents are not supported --- .../svg/css/SvgStrokeParameterConverter.java | 94 ++++++++++++++++++ .../svg/logs/SvgLogMessageConstant.java | 3 + .../impl/AbstractSvgNodeRenderer.java | 93 +++++++++-------- .../SvgStrokeParameterConverterUnitTest.java | 36 +++++++ .../itextpdf/svg/renderers/StrokeTest.java | 5 + .../cmp_usingJFreeSvgBarChartFromFileTest.pdf | Bin 57069 -> 57195 bytes ...mp_usingJFreeSvgBarChartFromStringTest.pdf | Bin 57069 -> 57195 bytes ...cmp_usingJFreeSvgLineChartFromFileTest.pdf | Bin 13520 -> 13646 bytes ...p_usingJFreeSvgLineChartFromStringTest.pdf | Bin 13520 -> 13646 bytes .../cmp_usingJFreeSvgXYChartFromFileTest.pdf | Bin 11239 -> 11464 bytes ...cmp_usingJFreeSvgXYChartFromStringTest.pdf | Bin 11239 -> 11464 bytes .../impl/StrokeTest/cmp_strokeAdvanced.pdf | Bin 2410 -> 2446 bytes .../impl/StrokeTest/cmp_strokeWithDashes.pdf | Bin 0 -> 1204 bytes .../impl/StrokeTest/strokeWithDashes.svg | 3 + 14 files changed, 193 insertions(+), 41 deletions(-) create mode 100644 svg/src/main/java/com/itextpdf/svg/css/SvgStrokeParameterConverter.java create mode 100644 svg/src/test/java/com/itextpdf/svg/css/SvgStrokeParameterConverterUnitTest.java create mode 100644 svg/src/test/resources/com/itextpdf/svg/renderers/impl/StrokeTest/cmp_strokeWithDashes.pdf create mode 100644 svg/src/test/resources/com/itextpdf/svg/renderers/impl/StrokeTest/strokeWithDashes.svg diff --git a/svg/src/main/java/com/itextpdf/svg/css/SvgStrokeParameterConverter.java b/svg/src/main/java/com/itextpdf/svg/css/SvgStrokeParameterConverter.java new file mode 100644 index 0000000000..57fc1d05e5 --- /dev/null +++ b/svg/src/main/java/com/itextpdf/svg/css/SvgStrokeParameterConverter.java @@ -0,0 +1,94 @@ +package com.itextpdf.svg.css; + +import com.itextpdf.styledxmlparser.css.util.CssDimensionParsingUtils; +import com.itextpdf.styledxmlparser.css.util.CssTypesValidationUtils; +import com.itextpdf.svg.SvgConstants; +import com.itextpdf.svg.logs.SvgLogMessageConstant; +import com.itextpdf.svg.utils.SvgCssUtils; + +import java.util.Arrays; +import java.util.List; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * This class converts stroke-related SVG parameters and attributes into those from PDF specification + */ +public class SvgStrokeParameterConverter { + + private SvgStrokeParameterConverter() { + } + + private static Logger LOGGER = LoggerFactory.getLogger(SvgStrokeParameterConverter.class); + + public static PdfLineDashParameters convertStrokeDashArray(String strokeDashArray) { + if (!SvgConstants.Values.NONE.equalsIgnoreCase(strokeDashArray)) { + List dashArray = SvgCssUtils.splitValueList(strokeDashArray); + + for (String dashArrayItem : dashArray) { + if (CssTypesValidationUtils.isPercentageValue(dashArrayItem)) { + LOGGER.error(SvgLogMessageConstant.PERCENTAGE_VALUES_IN_STROKE_DASHARRAY_ARE_NOT_SUPPORTED); + return null; + } + } + + if (dashArray.size() > 0) { + if (dashArray.size() % 2 == 1) { + // If an odd number of values is provided, then the list of values is repeated to yield an even + // number of values. Thus, 5,3,2 is equivalent to 5,3,2,5,3,2. + dashArray.addAll(dashArray); + } + float[] dashArrayFloat = new float[dashArray.size()]; + for (int i = 0; i < dashArray.size(); i++) { + dashArrayFloat[i] = CssDimensionParsingUtils.parseAbsoluteLength(dashArray.get(i)); + } + return new PdfLineDashParameters(dashArrayFloat, 0); + } + } + return null; + } + + public static class PdfLineDashParameters { + private float[] lengths; + private float phase; + + public PdfLineDashParameters(float[] lengths, float phase) { + this.lengths = lengths; + this.phase = phase; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + PdfLineDashParameters that = (PdfLineDashParameters) o; + + if (Float.compare(that.phase, phase) != 0) { + return false; + } + return Arrays.equals(lengths, that.lengths); + } + + @Override + public int hashCode() { + int result = Arrays.hashCode(lengths); + result = 31 * result + (phase != +0.0f ? Float.floatToIntBits(phase) : 0); + return result; + } + + + public float[] getLengths() { + return lengths; + } + + public float getPhase() { + return phase; + } + } + +} diff --git a/svg/src/main/java/com/itextpdf/svg/logs/SvgLogMessageConstant.java b/svg/src/main/java/com/itextpdf/svg/logs/SvgLogMessageConstant.java index c8da4d187e..c56d1ca1ad 100644 --- a/svg/src/main/java/com/itextpdf/svg/logs/SvgLogMessageConstant.java +++ b/svg/src/main/java/com/itextpdf/svg/logs/SvgLogMessageConstant.java @@ -81,6 +81,9 @@ public final class SvgLogMessageConstant { public static final String PATTERN_WIDTH_OR_HEIGHT_IS_NEGATIVE = "Pattern width or height is negative value. This pattern will not be rendered."; + public static final String PERCENTAGE_VALUES_IN_STROKE_DASHARRAY_ARE_NOT_SUPPORTED = + "Percentage values in 'stroke-dasharray' attribute are not supported. Attribute will be ignored completely"; + public static final String MISSING_WIDTH = "Top Svg tag has no defined width attribute and viewbox width is not present, so browser default of 300px " + "is used"; diff --git a/svg/src/main/java/com/itextpdf/svg/renderers/impl/AbstractSvgNodeRenderer.java b/svg/src/main/java/com/itextpdf/svg/renderers/impl/AbstractSvgNodeRenderer.java index 746454defe..09426ffa1b 100644 --- a/svg/src/main/java/com/itextpdf/svg/renderers/impl/AbstractSvgNodeRenderer.java +++ b/svg/src/main/java/com/itextpdf/svg/renderers/impl/AbstractSvgNodeRenderer.java @@ -45,7 +45,6 @@ This file is part of the iText (R) project. import com.itextpdf.kernel.colors.Color; import com.itextpdf.kernel.colors.ColorConstants; import com.itextpdf.kernel.colors.DeviceRgb; -import com.itextpdf.kernel.colors.WebColors; import com.itextpdf.kernel.geom.AffineTransform; import com.itextpdf.kernel.geom.Rectangle; import com.itextpdf.kernel.pdf.canvas.PdfCanvas; @@ -62,6 +61,8 @@ This file is part of the iText (R) project. import com.itextpdf.styledxmlparser.css.validate.CssDeclarationValidationMaster; import com.itextpdf.svg.MarkerVertexType; import com.itextpdf.svg.SvgConstants; +import com.itextpdf.svg.SvgConstants.Attributes; +import com.itextpdf.svg.css.SvgStrokeParameterConverter; import com.itextpdf.svg.css.impl.SvgNodeRendererInheritanceResolver; import com.itextpdf.svg.renderers.IMarkerCapable; import com.itextpdf.svg.renderers.ISvgNodeRenderer; @@ -320,9 +321,9 @@ void preDraw(SvgDrawContext context) { PdfExtGState opacityGraphicsState = new PdfExtGState(); if (!partOfClipPath) { - float generalOpacity = getOpacity(); // fill { + float generalOpacity = getOpacity(); String fillRawValue = getAttributeOrDefault(SvgConstants.Attributes.FILL, "black"); this.doFill = !SvgConstants.Values.NONE.equalsIgnoreCase(fillRawValue); @@ -349,47 +350,9 @@ void preDraw(SvgDrawContext context) { currentCanvas.setFillColor(fillColor); } } - // stroke - { - String strokeRawValue = getAttributeOrDefault(SvgConstants.Attributes.STROKE, - SvgConstants.Values.NONE); - - if (!SvgConstants.Values.NONE.equalsIgnoreCase(strokeRawValue)) { - String strokeWidthRawValue = getAttribute(SvgConstants.Attributes.STROKE_WIDTH); - - // 1 px = 0,75 pt - float strokeWidth = 0.75f; - - if (strokeWidthRawValue != null) { - strokeWidth = CssDimensionParsingUtils.parseAbsoluteLength(strokeWidthRawValue); - } - float strokeOpacity = getOpacityByAttributeName(SvgConstants.Attributes.STROKE_OPACITY, - generalOpacity); - - Color strokeColor = null; - TransparentColor transparentColor = getColorFromAttributeValue( - context, strokeRawValue, (float) ((double) strokeWidth / 2.0), strokeOpacity); - if (transparentColor != null) { - strokeColor = transparentColor.getColor(); - strokeOpacity = transparentColor.getOpacity(); - } + applyStrokeProperties(context, currentCanvas, opacityGraphicsState); - if (!CssUtils.compareFloats(strokeOpacity, 1f)) { - opacityGraphicsState.setStrokeOpacity(strokeOpacity); - } - - // as default value for stroke is 'none' we should not set - // it in case when value obtaining fails - if (strokeColor != null) { - currentCanvas.setStrokeColor(strokeColor); - } - - currentCanvas.setLineWidth(strokeWidth); - - doStroke = true; - } - } // opacity { if (!opacityGraphicsState.getPdfObject().isEmpty()) { @@ -507,4 +470,52 @@ private float getOpacity() { return result; } + + private void applyStrokeProperties(SvgDrawContext context, PdfCanvas currentCanvas, PdfExtGState opacityGraphicsState) { + String strokeRawValue = getAttributeOrDefault(SvgConstants.Attributes.STROKE, + SvgConstants.Values.NONE); + if (!SvgConstants.Values.NONE.equalsIgnoreCase(strokeRawValue)) { + String strokeWidthRawValue = getAttribute(SvgConstants.Attributes.STROKE_WIDTH); + + // 1 px = 0,75 pt + float strokeWidth = 0.75f; + + if (strokeWidthRawValue != null) { + strokeWidth = CssDimensionParsingUtils.parseAbsoluteLength(strokeWidthRawValue); + } + + float generalOpacity = getOpacity(); + float strokeOpacity = getOpacityByAttributeName(SvgConstants.Attributes.STROKE_OPACITY, + generalOpacity); + + Color strokeColor = null; + TransparentColor transparentColor = getColorFromAttributeValue( + context, strokeRawValue, (float) ((double) strokeWidth / 2.0), strokeOpacity); + if (transparentColor != null) { + strokeColor = transparentColor.getColor(); + strokeOpacity = transparentColor.getOpacity(); + } + + if (!CssUtils.compareFloats(strokeOpacity, 1f)) { + opacityGraphicsState.setStrokeOpacity(strokeOpacity); + } + + String strokeDashArrayRawValue = getAttribute(Attributes.STROKE_DASHARRAY); + SvgStrokeParameterConverter.PdfLineDashParameters lineDashParameters = + SvgStrokeParameterConverter.convertStrokeDashArray(strokeDashArrayRawValue); + if (lineDashParameters != null) { + currentCanvas.setLineDash(lineDashParameters.getLengths(), lineDashParameters.getPhase()); + } + + // as default value for stroke is 'none' we should not set + // it in case when value obtaining fails + if (strokeColor != null) { + currentCanvas.setStrokeColor(strokeColor); + } + + currentCanvas.setLineWidth(strokeWidth); + + doStroke = true; + } + } } diff --git a/svg/src/test/java/com/itextpdf/svg/css/SvgStrokeParameterConverterUnitTest.java b/svg/src/test/java/com/itextpdf/svg/css/SvgStrokeParameterConverterUnitTest.java new file mode 100644 index 0000000000..c39b963a55 --- /dev/null +++ b/svg/src/test/java/com/itextpdf/svg/css/SvgStrokeParameterConverterUnitTest.java @@ -0,0 +1,36 @@ +package com.itextpdf.svg.css; + +import com.itextpdf.svg.css.SvgStrokeParameterConverter.PdfLineDashParameters; +import com.itextpdf.svg.logs.SvgLogMessageConstant; +import com.itextpdf.test.ExtendedITextTest; +import com.itextpdf.test.annotations.LogMessage; +import com.itextpdf.test.annotations.LogMessages; + +import org.junit.Assert; +import org.junit.Test; + +public class SvgStrokeParameterConverterUnitTest extends ExtendedITextTest { + + @Test + @LogMessages(messages = { + @LogMessage(messageTemplate = + SvgLogMessageConstant.PERCENTAGE_VALUES_IN_STROKE_DASHARRAY_ARE_NOT_SUPPORTED)}) + public void testStrokeDashArrayPercentsAreNotSupported() { + Assert.assertNull(SvgStrokeParameterConverter.convertStrokeDashArray("5,3%")); + } + + @Test + public void testStrokeDashArrayOddNumberOfValues() { + PdfLineDashParameters result = SvgStrokeParameterConverter.convertStrokeDashArray("5pt"); + Assert.assertNotNull(result); + Assert.assertEquals(0, result.getPhase(), 0); + Assert.assertArrayEquals(new float[] {5, 5}, result.getLengths(), 1e-5f); + } + + @Test + public void testEmptyStrokeDashArray() { + PdfLineDashParameters result = SvgStrokeParameterConverter.convertStrokeDashArray(""); + Assert.assertNull(result); + } + +} diff --git a/svg/src/test/java/com/itextpdf/svg/renderers/StrokeTest.java b/svg/src/test/java/com/itextpdf/svg/renderers/StrokeTest.java index 5e16f9d900..aa699aae59 100644 --- a/svg/src/test/java/com/itextpdf/svg/renderers/StrokeTest.java +++ b/svg/src/test/java/com/itextpdf/svg/renderers/StrokeTest.java @@ -80,6 +80,11 @@ public void noLineStrokeWidthTest() throws IOException, InterruptedException { convertAndCompare(SOURCE_FOLDER, DESTINATION_FOLDER, "noLineStrokeWidth"); } + @Test + public void strokeWithDashesTest() throws IOException, InterruptedException { + convertAndCompare(SOURCE_FOLDER, DESTINATION_FOLDER, "strokeWithDashes"); + } + @Test //TODO: update cmp-file after DEVSIX-2258 public void advancedStrokeTest() throws IOException, InterruptedException { diff --git a/svg/src/test/resources/com/itextpdf/svg/JFreeSvgTest/cmp_usingJFreeSvgBarChartFromFileTest.pdf b/svg/src/test/resources/com/itextpdf/svg/JFreeSvgTest/cmp_usingJFreeSvgBarChartFromFileTest.pdf index a8a1031784afdbfc464005292a59339b6506f8ec..5fa8bb839d28ea483026572f2604330b8cd07d36 100644 GIT binary patch delta 6542 zcmai2O^aPc5altr84;BM7a@TcaWWB&c6U{EcWDrmC@N@#hzcTR;>@f>$rrft{sy@l z7b5-xm4G|lxy&Lc_yOh*hztLL=e_&hynFi$_`*Oa`ri6DRi{qhe}3Hh`=_n%&di=p zp~e(bQmIb`*$ZLs$!FjA^x)F|t;6$|o=YK(4)m|h9-nFd@$89Ny7R^Cui2K>aOe8g z=Vu>!KR#n~{CzMF^Mn5C?wS6<-FL`(n=EJge|O(I!FqU(t*86n&%H}$Pxr6ywbpO; zt~ci%Ie)XUT-`l==j-#|e%0Up`G?NtVey-PGT&bQCrQYaY*7;1Jd-WuKsHIrwz~4s zjU2176N~HwrKcBWWhW(YBBe}ybRi_E!cH7DX)EKIoM=eoM1xPAz=uX7ABqm^S|^$+ zI}v3k8rg{!c4A72Xbx*1-7)T(8Fwv=yB5Y>E90)txT~*mU&G#oWPx$F$hcc%+$}Ng zCXBmDgF7HG1?<2dzjZV)8sl!pxLao2Ei>*`7@9uQDFw(g)(%Bj5?2L2? zJm4iV&?PQ`Ui8GKBT8bVOJbypFw#XgNUwn|%0L$z13mO)D*1#LmP}J$Dg#)YJEDe4 zWM8Al7OdJOC%UO1H9BaKZCR)zD#}35R^?}X=qBX9DZht85&8*C;HlCJT^VCHo*&O? z>|qchJMT#qE7TB z7CAdhaa6*=iLqD}=!BNO#HOn1)G|WI1j5t$M}OVvtn%!e7do8-?Mcaz_O5_rDRk^- zqK&M}noZj?8_z|~nOYVY&|KuoKtuIVM-;H#rkhsniIq!zjM1k|3QJ%q__ulC09H|2 zhEmKZkJGHR<18&RkR&{0!h4OZI7HDKE492yt4$)svv z%?lYO6naF|?F%D*WJ{!n7IZ#ppJ7rpN})_5NSR)Us}b36 zm@LUoC6X|}UQ&W&p%z+51gVe>E0Jv<5gX%@Om`hcdvJh!4NK!?PSg} zRuef<5-FOE2RCP0IN&J~DGK2-4zU05&j&g*_6U-p2hj=Ra|@$Fx6pi-6Q~rrg%XBt zp14Ha_P8R9h zyo@|gD12Fe(1%dQKHMsi>hX6FTxu9&Ty)xI#pg?sKo%k?c?;<=8e@E9zfRW_tP~g`|;X=>tV(|DEh+1|2xrtd0)@!g)48q_|}zIFTcHg^Va^2Tc6!H SJleJZJ+QsI`|{;iw*Lct+5S-g delta 6445 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 TV{vU4AB<&pfB)snuk8K@M1KB5 delta 6445 zcmai2O^aMb6r~w(G24JaqahI|A84?u?nl)X6_hBt&fAR7nKmKm<=VDJyA3xap_VV)4 zl^2%J9elR>{QlsJ)#rsPVO=Ovd*Y5ckL z<)!`AAEijO<&$538@&IIq?+hi7UgHr=vi@!BvLqr#5%^X-I4$-z0fiTvBp7MIY`Y6 zq}F+iA*CWsI7lQ85>7!h2?fy<^B{OW{LErd7gA*s-M!3 z5qe)+m(Q>>aaySL3*(H|kL>iqC`@ArH%w^EVvN;Q!Wl_`TiQ%3m7az4n~{_Vh@@=& zcLmiv^l~goDlde5c7Y`sbsGjV6}Z4#a15mD^nKgu3Qd&0N+f5c&E!IbD_NYs3rEv$ zI$Kvq$iL)D>6hFxr8Nh2hm=G*BqdYpOM#g8n*rs*n{xt$=q#Idof60;4Tlj%&_R z?;dRnWIbJ_CKiy&j#w)Cv*);q5KWk*1f&|b;!r&ilIlT)RL|&=+L)3vX05cOL<#h5 z1TyA-V{QbtkB~IUgrq4eX46huAySPGLYRqlhmzC&lZG_(X>E8TJ;O}xpWz%tltiZK zDN$G*V_;_lt3d`tLbZ zQi70(a8-+vR4c|^FI+0lHG@O;e1ph84%uhyFu3gm{n@7<%mzNALd> zri6+{b!!;bV^$TzoHjF)RuBSkFe+5kx*ho&|EG{|T4;&JF_eNiw!*@NOAgwgA%*iz z-+=Te3xoAO9Z1aU^3fmX29_#oG=SBDNp&P-9zNlsi7brb5J_8ytvMxsS25tRsO%iH zQV^qYr0!&4aKSb8#bzkr*<9>bis5a?!<=3apeyL$ru7Uhg{|pGNEmKPh$|Yh2ZHut z#i(pQQFUa-#!95j)XI&ED+FE_lZfvqM#CWNci8x9bG+H+b%i;`r2wzfu5m}jK>yGV zaluIa)7Ylskig>H+MMIDaa)iH)JV0GV!$*IcTt$*fJpY)!i@)sco;W$c%A@n6(jfv zs=+oD!-&isu35%ETguOfrX)wp^=e^iKVuIvAThQx~9Hweu_(CNvej6m63rFLcwGYMrB5m z$vKQFj7FO$GTvomHnKF`T*&-Sl{eZ@&r|`3V-*Y(QYJspl%3qI8HOQRiXkF9xlk(t zi|A9VqLJE|X39)Hr5%oDf`U#ln#co9naS&P(A5D&H!J8$vpX6Zrlgu0B$=8fnx`dN vnphZ{Sel!pB%3FvB$*qVnA_PH5Ku9>#>5yHG#gCBxQxsVxKveL{oS|#FM(hZ delta 233 zcmX??bs=+uETguep`n3=p}C2Lp{2HgvAThQx~9Hweu_(CNvej6m63rFLcwGYMrB6B z$vKQFjE0*hGTvomHZ-%`T*&-Sbuy#2%;cGxVPINPD*{Z<2Gb>A_Iz!Sob+Tlop3Nc z4@%4Fg87^0=}NOZCZ(iWm?WhoC#EH*8m6WtCnp*kB%7Kir5PI=0Vz8h0|F{0|1vQK UI#AD4jLXo(giBS`)!&T^013lFM*si- diff --git a/svg/src/test/resources/com/itextpdf/svg/JFreeSvgTest/cmp_usingJFreeSvgLineChartFromStringTest.pdf b/svg/src/test/resources/com/itextpdf/svg/JFreeSvgTest/cmp_usingJFreeSvgLineChartFromStringTest.pdf index 7a4db32aea40884241dc6c1d97f612fc71f66fb6..ca6fa935c3c9acc92a3fe166a8b9961819123505 100644 GIT binary patch delta 357 zcmcbRc`j>%ETfK*frX)wp^=e^iHWv>vAThQx~9Hweu_(CNvej6m63rFl7h*ej7p3q zlXDnV7>zbhWW3ABY-DM=xsdsvDsQx*o~Z&5$0`^oq)dLGDLc7aGYmtt6hlOIa-miP z7SX3zMI*H_&6JsZN;@3Q1O=U9G?53IGLzTopsNFlZdTBhVt2BzNKP|0GB-{$Ft-G< ul1!6Q%*;(pQ%#H#%?vFJEbVLvshC`2VhjwM4JKk-M&<@ws;aL3Zd?G#DPSf5 delta 235 zcmX??bs=+uETfL0p`n3=p}C2Lp_#UUvAThQx~9Hweu_(CNvej6m63rFl7h*ej7p4# zlXDnV7!5a1WW3ABY-nb=xsdsv>SRW3naMLX!@#tpRs@)y4W>)L?D^UtIqAuAI^ke? z9+Z~T1@kx0)0JX(N-|1GG_XuIvrJ7)wKOy`G_W)zbhWW3GDYG`0+XuP?AIZlQ*+EC9_0f=K23=~o(8!AdpekLD>MKneMQ&ej5 zWrcVQwUrnml9LZ9Mqv>(QA)rfx(2JLiZV8}b1+07s>n{3Pzggb7bM!H5`iIFiXkF9 zxkwdLoy_E?s^J)FWhRHKVG-SYQmuo<$v7=B&BD^qDB0N9B+0_UFeNoLHQ6%RG|j@? zBFQYp($0pEipi6;jTKFFgZ&%>f<630xQa^>i%KerQq#B$4GkR`8<4sETfL0p`n3=p}C2Lp_#UUvAThQx~9Hweu_(CNvej6m63rFl7h*ej7p4# zlXDnV7!5a1WW3GDVrgMvxw()zPG)kVg2d#n@^L`A49xzkkN~Ee6%!_ZR4kfYs8j)@ zB_|6g$AiVEDnsO@RUq_2l_;>dqG}A7UJRvG)gb)kY7lvKbuhhoxq3H?lVP%PN|JeE zN}@qB(50!VX{kwuiDo7S#z`rO7RIKgb~c1mOfJzeRy5QN_Hzsf_V5qkDlSPZDyb++ SP2&OvizbhWW3GDYG`0+XuP?AIZlQ*+EC9_0f=K23=~o(8!AdpekLD>MKneMQ&ej5 zWrcVQwUrnml9LZ9Mqv>(QA)rfx(2JLiZV8}b1+07s>n{3Pzggb7bM!H5`iIFiXkF9 zxkwdLoy_E?s^J)FWhRHKVG-SYQmuof<630xQa^>i%KerQq#B$4GkR`8<4sETfL0p`n3=p}C2Lk%6{>vAThQx~9Hweu_(CNvej6m63rFl7h*ej7p4# zlXDnV7!5a1WW3GDVrgMvxw()zPG)kVg2d#n@^L`A49xzkkN~Ee6%!_ZR4kfYs8j)@ zB_|6g$AiVEDnsO@RUq_2l_;>dqG}A7UJRvG)gb)kY7lvKbuhhoxq3H?Q;NA+nyF!$ zi5bw9MrJ97W`@ZImX=9|$%ba8NhSs{KHRn=Qb@g}S0sx!fEe-$x diff --git a/svg/src/test/resources/com/itextpdf/svg/renderers/impl/StrokeTest/cmp_strokeWithDashes.pdf b/svg/src/test/resources/com/itextpdf/svg/renderers/impl/StrokeTest/cmp_strokeWithDashes.pdf new file mode 100644 index 0000000000000000000000000000000000000000..5b8530e1a22cd442d97d0b1f9e077f05a70fc3d0 GIT binary patch literal 1204 zcmah}-EPw`6u$RUoSSN!P!s>eNs6XQTT92peo9&aQrC;5aZ9E)9*#Q-Z^R9+!Ub;t zFT!z~t)qj@Q5^gHpU-UeJL;?k!U6aE@|4fxL`wZ-gTB%Ea-z(BF;px29Xi@5 zh&=8E&B4V{fAIQp2v_?@C;cT)aEjmg3<(Mo;1FG8@7_BXGXQSTCsC$Y^F6(n;Gb$g}jr@4NLRVkiJ{U#blM?G1 zF;9Yfofe-lPC40Zk`qF`fJ+v`XY6KPl!}Nb^5O_MkG;4B3nE&$=fDHu2?295_~-3d z88yYAF~M`L2ZT}z2~)U}afax)0p-0c;0VT!j7vP%9T|;~2D>tbP3_2nD1Iah!v}e- zNsGBM?hkOG7Qz5cAoW$+tEyn(7Io05A$ k{6XLUaO(B&{ja`EmN1QYouP%G!4|*Cx#sB~S literal 0 HcmV?d00001 diff --git a/svg/src/test/resources/com/itextpdf/svg/renderers/impl/StrokeTest/strokeWithDashes.svg b/svg/src/test/resources/com/itextpdf/svg/renderers/impl/StrokeTest/strokeWithDashes.svg new file mode 100644 index 0000000000..babad53183 --- /dev/null +++ b/svg/src/test/resources/com/itextpdf/svg/renderers/impl/StrokeTest/strokeWithDashes.svg @@ -0,0 +1,3 @@ + + +