From 5655d6a54c5797ea5ae15a29a74bc2eec06463a2 Mon Sep 17 00:00:00 2001 From: Dmitry Chubrick Date: Mon, 30 Dec 2024 19:19:14 +0000 Subject: [PATCH] Support percent width&height resolving for svg tag and background svg image in html * Fix rem resolving DEVSIX-8809 Autoported commit. Original commit hash: [fad2fb257] --- .../layout/properties/BackgroundImageTest.cs | 58 +++++- .../BackgroundSizeCalculationUtilUnitTest.cs | 89 ---------- .../svg/css/AttributesRelativeUnitTest.cs | 41 +++++ .../svg/renderers/SvgImageRendererTest.cs | 99 +++++++++++ .../absWidthViewBoxNoneRatioTest.svg | 5 + .../absoluteHeightViewBoxMissWidthTest.svg | 12 ++ .../absoluteWidthHeightViewBoxTest.svg | 12 ++ .../absoluteWidthNoHeightNoViewBoxTest.svg | 6 + .../absoluteWidthViewBoxNoHeightTest.svg | 7 + .../cmp_absWidthViewBoxNoneRatioTest.pdf | Bin 0 -> 1525 bytes ...cmp_absoluteHeightViewBoxMissWidthTest.pdf | Bin 0 -> 1560 bytes .../cmp_absoluteWidthHeightViewBoxTest.pdf | Bin 0 -> 1556 bytes ...cmp_absoluteWidthNoHeightNoViewBoxTest.pdf | Bin 0 -> 1551 bytes .../cmp_absoluteWidthViewBoxNoHeightTest.pdf | Bin 0 -> 1656 bytes .../cmp_percentHeightMissWidthViewBoxTest.pdf | Bin 0 -> 1520 bytes .../cmp_svgHeightPercentTest.pdf | Bin 1616 -> 1610 bytes .../cmp_svgRelativeSizeWithViewBox1.pdf | Bin 0 -> 1716 bytes .../cmp_svgViewboxWidthPercentTest.pdf | Bin 1678 -> 1671 bytes .../cmp_svgWidthPercentTest.pdf | Bin 1621 -> 1618 bytes .../cmp_viewBoxMissWidthHeightTest.pdf | Bin 0 -> 1560 bytes ...mp_viewportFromConverterPropertiesTest.pdf | Bin 1663 -> 1652 bytes .../percentHeightMissWidthViewBoxTest.svg | 12 ++ .../svgRelativeSizeWithViewBox1.svg | 8 + .../viewBoxMissWidthHeightTest.svg | 12 ++ .../cmp_fixed_height_percent_width.pdf | Bin 0 -> 1539 bytes .../cmp_percent_height_fixed_width.pdf | Bin 0 -> 1551 bytes ...ercent_height_fixed_width_prRatio_none.pdf | Bin 0 -> 1555 bytes ...cmp_viewbox_fixed_height_percent_width.pdf | Bin 0 -> 1575 bytes .../cmp_viewbox_fixed_height_prRatio_none.pdf | Bin 0 -> 1555 bytes ...p_viewbox_percent_height_percent_width.pdf | Bin 0 -> 1555 bytes ...cent_height_percent_width_prRatio_none.pdf | Bin 0 -> 1548 bytes .../fixed_height_percent_width.svg | 5 + .../percent_height_fixed_width.svg | 5 + .../viewbox_fixed_height_percent_width.svg | 5 + .../viewbox_percent_height_percent_width.svg | 5 + ...cent_height_percent_width_prRatio_none.svg | 5 + .../layout/properties/BackgroundImage.cs | 90 ++++++++++ .../itext/layout/renderer/AbstractRenderer.cs | 4 +- .../renderer/BackgroundSizeCalculationUtil.cs | 165 ------------------ itext/itext.svg/itext/svg/SvgConstants.cs | 12 +- .../itext.svg/itext/svg/css/SvgCssContext.cs | 6 + itext/itext.svg/itext/svg/element/SvgImage.cs | 15 ++ .../itext/svg/renderers/SvgImageRenderer.cs | 53 +++++- .../impl/AbstractContainerSvgNodeRenderer.cs | 6 +- .../itext.svg/itext/svg/utils/SvgCssUtils.cs | 6 +- .../itext/svg/xobject/SvgImageXObject.cs | 117 ++++++++++++- port-hash | 2 +- 47 files changed, 582 insertions(+), 280 deletions(-) delete mode 100644 itext.tests/itext.layout.tests/itext/layout/renderer/BackgroundSizeCalculationUtilUnitTest.cs create mode 100644 itext.tests/itext.svg.tests/resources/itext/svg/css/AttributesRelativeUnitTest/absWidthViewBoxNoneRatioTest.svg create mode 100644 itext.tests/itext.svg.tests/resources/itext/svg/css/AttributesRelativeUnitTest/absoluteHeightViewBoxMissWidthTest.svg create mode 100644 itext.tests/itext.svg.tests/resources/itext/svg/css/AttributesRelativeUnitTest/absoluteWidthHeightViewBoxTest.svg create mode 100644 itext.tests/itext.svg.tests/resources/itext/svg/css/AttributesRelativeUnitTest/absoluteWidthNoHeightNoViewBoxTest.svg create mode 100644 itext.tests/itext.svg.tests/resources/itext/svg/css/AttributesRelativeUnitTest/absoluteWidthViewBoxNoHeightTest.svg create mode 100644 itext.tests/itext.svg.tests/resources/itext/svg/css/AttributesRelativeUnitTest/cmp_absWidthViewBoxNoneRatioTest.pdf create mode 100644 itext.tests/itext.svg.tests/resources/itext/svg/css/AttributesRelativeUnitTest/cmp_absoluteHeightViewBoxMissWidthTest.pdf create mode 100644 itext.tests/itext.svg.tests/resources/itext/svg/css/AttributesRelativeUnitTest/cmp_absoluteWidthHeightViewBoxTest.pdf create mode 100644 itext.tests/itext.svg.tests/resources/itext/svg/css/AttributesRelativeUnitTest/cmp_absoluteWidthNoHeightNoViewBoxTest.pdf create mode 100644 itext.tests/itext.svg.tests/resources/itext/svg/css/AttributesRelativeUnitTest/cmp_absoluteWidthViewBoxNoHeightTest.pdf create mode 100644 itext.tests/itext.svg.tests/resources/itext/svg/css/AttributesRelativeUnitTest/cmp_percentHeightMissWidthViewBoxTest.pdf create mode 100644 itext.tests/itext.svg.tests/resources/itext/svg/css/AttributesRelativeUnitTest/cmp_svgRelativeSizeWithViewBox1.pdf create mode 100644 itext.tests/itext.svg.tests/resources/itext/svg/css/AttributesRelativeUnitTest/cmp_viewBoxMissWidthHeightTest.pdf create mode 100644 itext.tests/itext.svg.tests/resources/itext/svg/css/AttributesRelativeUnitTest/percentHeightMissWidthViewBoxTest.svg create mode 100644 itext.tests/itext.svg.tests/resources/itext/svg/css/AttributesRelativeUnitTest/svgRelativeSizeWithViewBox1.svg create mode 100644 itext.tests/itext.svg.tests/resources/itext/svg/css/AttributesRelativeUnitTest/viewBoxMissWidthHeightTest.svg create mode 100644 itext.tests/itext.svg.tests/resources/itext/svg/renderers/SvgImageRendererTest/cmp_fixed_height_percent_width.pdf create mode 100644 itext.tests/itext.svg.tests/resources/itext/svg/renderers/SvgImageRendererTest/cmp_percent_height_fixed_width.pdf create mode 100644 itext.tests/itext.svg.tests/resources/itext/svg/renderers/SvgImageRendererTest/cmp_percent_height_fixed_width_prRatio_none.pdf create mode 100644 itext.tests/itext.svg.tests/resources/itext/svg/renderers/SvgImageRendererTest/cmp_viewbox_fixed_height_percent_width.pdf create mode 100644 itext.tests/itext.svg.tests/resources/itext/svg/renderers/SvgImageRendererTest/cmp_viewbox_fixed_height_prRatio_none.pdf create mode 100644 itext.tests/itext.svg.tests/resources/itext/svg/renderers/SvgImageRendererTest/cmp_viewbox_percent_height_percent_width.pdf create mode 100644 itext.tests/itext.svg.tests/resources/itext/svg/renderers/SvgImageRendererTest/cmp_viewbox_percent_height_percent_width_prRatio_none.pdf create mode 100644 itext.tests/itext.svg.tests/resources/itext/svg/renderers/SvgImageRendererTest/fixed_height_percent_width.svg create mode 100644 itext.tests/itext.svg.tests/resources/itext/svg/renderers/SvgImageRendererTest/percent_height_fixed_width.svg create mode 100644 itext.tests/itext.svg.tests/resources/itext/svg/renderers/SvgImageRendererTest/viewbox_fixed_height_percent_width.svg create mode 100644 itext.tests/itext.svg.tests/resources/itext/svg/renderers/SvgImageRendererTest/viewbox_percent_height_percent_width.svg create mode 100644 itext.tests/itext.svg.tests/resources/itext/svg/renderers/SvgImageRendererTest/viewbox_percent_height_percent_width_prRatio_none.svg delete mode 100644 itext/itext.layout/itext/layout/renderer/BackgroundSizeCalculationUtil.cs diff --git a/itext.tests/itext.layout.tests/itext/layout/properties/BackgroundImageTest.cs b/itext.tests/itext.layout.tests/itext/layout/properties/BackgroundImageTest.cs index e0a1a44816..213a55e157 100644 --- a/itext.tests/itext.layout.tests/itext/layout/properties/BackgroundImageTest.cs +++ b/itext.tests/itext.layout.tests/itext/layout/properties/BackgroundImageTest.cs @@ -41,10 +41,12 @@ You should have received a copy of the GNU Affero General Public License namespace iText.Layout.Properties { [NUnit.Framework.Category("IntegrationTest")] public class BackgroundImageTest : ExtendedITextTest { - public static readonly String SOURCE_FOLDER = iText.Test.TestUtil.GetParentProjectDirectory(NUnit.Framework.TestContext + private const float DELTA = 0.0001f; + + private static readonly String SOURCE_FOLDER = iText.Test.TestUtil.GetParentProjectDirectory(NUnit.Framework.TestContext .CurrentContext.TestDirectory) + "/resources/itext/layout/BackgroundImageTest/"; - public static readonly String DESTINATION_FOLDER = NUnit.Framework.TestContext.CurrentContext.TestDirectory + private static readonly String DESTINATION_FOLDER = NUnit.Framework.TestContext.CurrentContext.TestDirectory + "/test/itext/layout/BackgroundImageTest/"; [NUnit.Framework.OneTimeSetUp] @@ -623,6 +625,58 @@ public virtual void BackgroundImageWithLinearGradientAndLuminosityBlendModeTest( BlendModeTest(BlendMode.LUMINOSITY); } + [NUnit.Framework.Test] + public virtual void CalculateImageSizeTest() { + PdfImageXObject xObject = new PdfImageXObject(ImageDataFactory.Create(SOURCE_FOLDER + "pattern-grg-rrg-rgg.png" + )); + iText.Layout.Properties.BackgroundImage backgroundImage = new BackgroundImage.Builder().SetImage(xObject). + Build(); + float[] widthAndHeight = backgroundImage.CalculateBackgroundImageSize(200f, 300f); + iText.Test.TestUtil.AreEqual(new float[] { 45f, 45f }, widthAndHeight, DELTA); + } + + [NUnit.Framework.Test] + public virtual void CalculateImageSizeWithCoverPropertyTest() { + PdfImageXObject xObject = new PdfImageXObject(ImageDataFactory.Create(SOURCE_FOLDER + "pattern-grg-rrg-rgg.png" + )); + iText.Layout.Properties.BackgroundImage backgroundImage = new BackgroundImage.Builder().SetImage(xObject). + Build(); + backgroundImage.GetBackgroundSize().SetBackgroundSizeToCover(); + float[] widthAndHeight = backgroundImage.CalculateBackgroundImageSize(200f, 300f); + iText.Test.TestUtil.AreEqual(new float[] { 300f, 300f }, widthAndHeight, DELTA); + } + + [NUnit.Framework.Test] + public virtual void CalculateSizeWithContainPropertyTest() { + PdfImageXObject xObject = new PdfImageXObject(ImageDataFactory.Create(SOURCE_FOLDER + "pattern-grg-rrg-rgg.png" + )); + iText.Layout.Properties.BackgroundImage backgroundImage = new BackgroundImage.Builder().SetImage(xObject). + Build(); + backgroundImage.GetBackgroundSize().SetBackgroundSizeToContain(); + float[] widthAndHeight = backgroundImage.CalculateBackgroundImageSize(200f, 300f); + iText.Test.TestUtil.AreEqual(new float[] { 200f, 200.000015f }, widthAndHeight, DELTA); + } + + [NUnit.Framework.Test] + public virtual void CalculateSizeWithContainAndImageWeightMoreThatHeightTest() { + PdfImageXObject xObject = new PdfImageXObject(ImageDataFactory.Create(SOURCE_FOLDER + "itis.jpg")); + iText.Layout.Properties.BackgroundImage backgroundImage = new BackgroundImage.Builder().SetImage(xObject). + Build(); + backgroundImage.GetBackgroundSize().SetBackgroundSizeToContain(); + float[] widthAndHeight = backgroundImage.CalculateBackgroundImageSize(200f, 300f); + iText.Test.TestUtil.AreEqual(new float[] { 200f, 112.5f }, widthAndHeight, DELTA); + } + + [NUnit.Framework.Test] + public virtual void CalculateSizeWithCoverAndImageWeightMoreThatHeightTest() { + PdfImageXObject xObject = new PdfImageXObject(ImageDataFactory.Create(SOURCE_FOLDER + "itis.jpg")); + iText.Layout.Properties.BackgroundImage backgroundImage = new BackgroundImage.Builder().SetImage(xObject). + Build(); + backgroundImage.GetBackgroundSize().SetBackgroundSizeToCover(); + float[] widthAndHeight = backgroundImage.CalculateBackgroundImageSize(200f, 300f); + iText.Test.TestUtil.AreEqual(new float[] { 533.3333f, 300f }, widthAndHeight, DELTA); + } + private void BlendModeTest(BlendMode blendMode) { AbstractLinearGradientBuilder gradientBuilder = new StrategyBasedLinearGradientBuilder().AddColorStop(new GradientColorStop(ColorConstants.BLACK.GetColorValue())).AddColorStop(new GradientColorStop(ColorConstants diff --git a/itext.tests/itext.layout.tests/itext/layout/renderer/BackgroundSizeCalculationUtilUnitTest.cs b/itext.tests/itext.layout.tests/itext/layout/renderer/BackgroundSizeCalculationUtilUnitTest.cs deleted file mode 100644 index b12400d284..0000000000 --- a/itext.tests/itext.layout.tests/itext/layout/renderer/BackgroundSizeCalculationUtilUnitTest.cs +++ /dev/null @@ -1,89 +0,0 @@ -/* -This file is part of the iText (R) project. -Copyright (c) 1998-2024 Apryse Group NV -Authors: Apryse Software. - -This program is offered under a commercial and under the AGPL license. -For commercial licensing, contact us at https://itextpdf.com/sales. For AGPL licensing, see below. - -AGPL licensing: -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program 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 Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ -using System; -using iText.IO.Image; -using iText.Kernel.Pdf.Xobject; -using iText.Layout.Properties; -using iText.Test; - -namespace iText.Layout.Renderer { - [NUnit.Framework.Category("UnitTest")] - public class BackgroundSizeCalculationUtilUnitTest : ExtendedITextTest { - private static readonly String SOURCE_FOLDER = iText.Test.TestUtil.GetParentProjectDirectory(NUnit.Framework.TestContext - .CurrentContext.TestDirectory) + "/resources/itext/layout/BackgroundImageTest/"; - - private const float delta = 0.0001f; - - [NUnit.Framework.Test] - public virtual void CalculateImageSizeTest() { - PdfImageXObject xObject = new PdfImageXObject(ImageDataFactory.Create(SOURCE_FOLDER + "pattern-grg-rrg-rgg.png" - )); - BackgroundImage backgroundImage = new BackgroundImage.Builder().SetImage(xObject).Build(); - float[] widthAndHeight = BackgroundSizeCalculationUtil.CalculateBackgroundImageSize(backgroundImage, 200f, - 300f); - iText.Test.TestUtil.AreEqual(new float[] { 45f, 45f }, widthAndHeight, delta); - } - - [NUnit.Framework.Test] - public virtual void CalculateImageSizeWithCoverPropertyTest() { - PdfImageXObject xObject = new PdfImageXObject(ImageDataFactory.Create(SOURCE_FOLDER + "pattern-grg-rrg-rgg.png" - )); - BackgroundImage backgroundImage = new BackgroundImage.Builder().SetImage(xObject).Build(); - backgroundImage.GetBackgroundSize().SetBackgroundSizeToCover(); - float[] widthAndHeight = BackgroundSizeCalculationUtil.CalculateBackgroundImageSize(backgroundImage, 200f, - 300f); - iText.Test.TestUtil.AreEqual(new float[] { 300f, 300f }, widthAndHeight, delta); - } - - [NUnit.Framework.Test] - public virtual void CalculateSizeWithContainPropertyTest() { - PdfImageXObject xObject = new PdfImageXObject(ImageDataFactory.Create(SOURCE_FOLDER + "pattern-grg-rrg-rgg.png" - )); - BackgroundImage backgroundImage = new BackgroundImage.Builder().SetImage(xObject).Build(); - backgroundImage.GetBackgroundSize().SetBackgroundSizeToContain(); - float[] widthAndHeight = BackgroundSizeCalculationUtil.CalculateBackgroundImageSize(backgroundImage, 200f, - 300f); - iText.Test.TestUtil.AreEqual(new float[] { 200f, 200.000015f }, widthAndHeight, delta); - } - - [NUnit.Framework.Test] - public virtual void CalculateSizeWithContainAndImageWeightMoreThatHeightTest() { - PdfImageXObject xObject = new PdfImageXObject(ImageDataFactory.Create(SOURCE_FOLDER + "itis.jpg")); - BackgroundImage backgroundImage = new BackgroundImage.Builder().SetImage(xObject).Build(); - backgroundImage.GetBackgroundSize().SetBackgroundSizeToContain(); - float[] widthAndHeight = BackgroundSizeCalculationUtil.CalculateBackgroundImageSize(backgroundImage, 200f, - 300f); - iText.Test.TestUtil.AreEqual(new float[] { 200f, 112.5f }, widthAndHeight, delta); - } - - [NUnit.Framework.Test] - public virtual void CalculateSizeWithCoverAndImageWeightMoreThatHeightTest() { - PdfImageXObject xObject = new PdfImageXObject(ImageDataFactory.Create(SOURCE_FOLDER + "itis.jpg")); - BackgroundImage backgroundImage = new BackgroundImage.Builder().SetImage(xObject).Build(); - backgroundImage.GetBackgroundSize().SetBackgroundSizeToCover(); - float[] widthAndHeight = BackgroundSizeCalculationUtil.CalculateBackgroundImageSize(backgroundImage, 200f, - 300f); - iText.Test.TestUtil.AreEqual(new float[] { 533.3333f, 300f }, widthAndHeight, delta); - } - } -} diff --git a/itext.tests/itext.svg.tests/itext/svg/css/AttributesRelativeUnitTest.cs b/itext.tests/itext.svg.tests/itext/svg/css/AttributesRelativeUnitTest.cs index 0b8e35711d..07042e1418 100644 --- a/itext.tests/itext.svg.tests/itext/svg/css/AttributesRelativeUnitTest.cs +++ b/itext.tests/itext.svg.tests/itext/svg/css/AttributesRelativeUnitTest.cs @@ -121,6 +121,11 @@ public virtual void SvgWidthAndHeightEmAndRemTest() { ConvertAndCompare(SOURCE_FOLDER, DESTINATION_FOLDER, "svgWidthAndHeightEmAndRemTest"); } + [NUnit.Framework.Test] + public virtual void SvgRelativeSizeWithViewBox1() { + ConvertAndCompare(SOURCE_FOLDER, DESTINATION_FOLDER, "svgRelativeSizeWithViewBox1"); + } + //-------------- use [NUnit.Framework.Test] public virtual void UseXPercentTest() { @@ -169,6 +174,32 @@ public virtual void SymbolWidthAndHeightEmAndRemTest() { ConvertAndCompare(SOURCE_FOLDER, DESTINATION_FOLDER, "symbolWidthAndHeightEmAndRemTest"); } + //-------------- SVGs with absolute or missing size, but with viewBox and or preserveAspectRatio="none" + [NUnit.Framework.Test] + public virtual void AbsoluteWidthHeightViewBoxTest() { + ConvertAndCompare(SOURCE_FOLDER, DESTINATION_FOLDER, "absoluteWidthHeightViewBoxTest"); + } + + [NUnit.Framework.Test] + public virtual void AbsoluteHeightViewBoxMissWidthTest() { + ConvertAndCompare(SOURCE_FOLDER, DESTINATION_FOLDER, "absoluteHeightViewBoxMissWidthTest"); + } + + [NUnit.Framework.Test] + public virtual void AbsoluteWidthNoHeightNoViewBoxTest() { + ConvertAndCompare(SOURCE_FOLDER, DESTINATION_FOLDER, "absoluteWidthNoHeightNoViewBoxTest"); + } + + [NUnit.Framework.Test] + public virtual void AbsoluteWidthViewBoxNoHeightTest() { + ConvertAndCompare(SOURCE_FOLDER, DESTINATION_FOLDER, "absoluteWidthViewBoxNoHeightTest"); + } + + [NUnit.Framework.Test] + public virtual void AbsWidthViewBoxNoneRatioTest() { + ConvertAndCompare(SOURCE_FOLDER, DESTINATION_FOLDER, "absWidthViewBoxNoneRatioTest"); + } + //-------------- misc [NUnit.Framework.Test] public virtual void LinePercentTest() { @@ -203,5 +234,15 @@ public virtual void ViewportFromConverterPropertiesTest() { // browsers the result should be bigger but with the same proportions ConvertAndCompare(SOURCE_FOLDER, DESTINATION_FOLDER, "viewportFromConverterPropertiesTest", properties); } + + [NUnit.Framework.Test] + public virtual void ViewBoxMissWidthHeightTest() { + ConvertAndCompare(SOURCE_FOLDER, DESTINATION_FOLDER, "viewBoxMissWidthHeightTest"); + } + + [NUnit.Framework.Test] + public virtual void PercentHeightMissWidthViewBoxTest() { + ConvertAndCompare(SOURCE_FOLDER, DESTINATION_FOLDER, "percentHeightMissWidthViewBoxTest"); + } } } diff --git a/itext.tests/itext.svg.tests/itext/svg/renderers/SvgImageRendererTest.cs b/itext.tests/itext.svg.tests/itext/svg/renderers/SvgImageRendererTest.cs index 357417f446..dfb1b09b66 100644 --- a/itext.tests/itext.svg.tests/itext/svg/renderers/SvgImageRendererTest.cs +++ b/itext.tests/itext.svg.tests/itext/svg/renderers/SvgImageRendererTest.cs @@ -26,6 +26,9 @@ You should have received a copy of the GNU Affero General Public License using iText.Kernel.Pdf; using iText.Kernel.Utils; using iText.Layout; +using iText.Layout.Element; +using iText.Layout.Logs; +using iText.Layout.Properties; using iText.StyledXmlParser.Node; using iText.StyledXmlParser.Resolver.Resource; using iText.Svg.Converter; @@ -34,6 +37,7 @@ You should have received a copy of the GNU Affero General Public License using iText.Svg.Processors.Impl; using iText.Svg.Utils; using iText.Svg.Xobject; +using iText.Test.Attributes; namespace iText.Svg.Renderers { [NUnit.Framework.Category("IntegrationTest")] @@ -107,5 +111,100 @@ public virtual void NoSpecifiedWidthHeightImageTest() { NUnit.Framework.Assert.IsNull(new CompareTool().CompareByContent(outFileName, cmpFileName, DESTINATION_FOLDER , "diff")); } + + [NUnit.Framework.Test] + public virtual void RelativeSizedSvg1Test() { + String svgName = "fixed_height_percent_width"; + String svgFileName = SOURCE_FOLDER + svgName + ".svg"; + String cmpFileName = SOURCE_FOLDER + "cmp_" + svgName + ".pdf"; + String outFileName = DESTINATION_FOLDER + svgName + ".pdf"; + using (Document document = new Document(new PdfDocument(new PdfWriter(outFileName, new WriterProperties(). + SetCompressionLevel(0))))) { + INode parsedSvg = SvgConverter.Parse(FileUtil.GetInputStreamForFile(svgFileName)); + ISvgProcessorResult result = new DefaultSvgProcessor().Process(parsedSvg, new SvgConverterProperties().SetBaseUri + (svgFileName)); + SvgDrawContext svgDrawContext = new SvgDrawContext(new ResourceResolver(SOURCE_FOLDER), null); + SvgImageXObject svgImageXObject = new SvgImageXObject(result, svgDrawContext, 12, document.GetPdfDocument( + )); + SvgImage svgImage = new SvgImage(svgImageXObject); + svgImage.SetWidth(100); + svgImage.SetHeight(300); + document.Add(svgImage); + } + NUnit.Framework.Assert.IsNull(new CompareTool().CompareByContent(outFileName, cmpFileName, DESTINATION_FOLDER + , "diff")); + } + + [NUnit.Framework.Test] + public virtual void RelativeSizedSvg3Test() { + String svgName = "viewbox_fixed_height_percent_width"; + String svgFileName = SOURCE_FOLDER + svgName + ".svg"; + String cmpFileName = SOURCE_FOLDER + "cmp_" + svgName + ".pdf"; + String outFileName = DESTINATION_FOLDER + svgName + ".pdf"; + using (Document document = new Document(new PdfDocument(new PdfWriter(outFileName, new WriterProperties(). + SetCompressionLevel(0))))) { + INode parsedSvg = SvgConverter.Parse(FileUtil.GetInputStreamForFile(svgFileName)); + ISvgProcessorResult result = new DefaultSvgProcessor().Process(parsedSvg, new SvgConverterProperties().SetBaseUri + (svgFileName)); + SvgDrawContext svgDrawContext = new SvgDrawContext(new ResourceResolver(SOURCE_FOLDER), null); + SvgImageXObject svgImageXObject = new SvgImageXObject(result, svgDrawContext, 12, document.GetPdfDocument( + )); + SvgImage svgImage = new SvgImage(svgImageXObject); + svgImage.SetWidth(100); + svgImage.SetHeight(300); + document.Add(svgImage); + } + NUnit.Framework.Assert.IsNull(new CompareTool().CompareByContent(outFileName, cmpFileName, DESTINATION_FOLDER + , "diff")); + } + + [NUnit.Framework.Test] + [LogMessage(LayoutLogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA)] + public virtual void RelativeSizedSvg4Test() { + String svgName = "viewbox_percent_height_percent_width"; + String svgFileName = SOURCE_FOLDER + svgName + ".svg"; + String cmpFileName = SOURCE_FOLDER + "cmp_" + svgName + ".pdf"; + String outFileName = DESTINATION_FOLDER + svgName + ".pdf"; + using (Document document = new Document(new PdfDocument(new PdfWriter(outFileName, new WriterProperties(). + SetCompressionLevel(0))))) { + INode parsedSvg = SvgConverter.Parse(FileUtil.GetInputStreamForFile(svgFileName)); + ISvgProcessorResult result = new DefaultSvgProcessor().Process(parsedSvg, new SvgConverterProperties().SetBaseUri + (svgFileName)); + SvgDrawContext svgDrawContext = new SvgDrawContext(new ResourceResolver(SOURCE_FOLDER), null); + SvgImageXObject svgImageXObject = new SvgImageXObject(result, svgDrawContext, 12, document.GetPdfDocument( + )); + SvgImage svgImage = new SvgImage(svgImageXObject); + document.Add(svgImage); + } + NUnit.Framework.Assert.IsNull(new CompareTool().CompareByContent(outFileName, cmpFileName, DESTINATION_FOLDER + , "diff")); + } + + [NUnit.Framework.Test] + public virtual void RelativeSizedSvg5Test() { + String svgName = "viewbox_percent_height_percent_width_prRatio_none"; + String svgFileName = SOURCE_FOLDER + svgName + ".svg"; + String cmpFileName = SOURCE_FOLDER + "cmp_" + svgName + ".pdf"; + String outFileName = DESTINATION_FOLDER + svgName + ".pdf"; + using (Document document = new Document(new PdfDocument(new PdfWriter(outFileName, new WriterProperties(). + SetCompressionLevel(0))))) { + INode parsedSvg = SvgConverter.Parse(FileUtil.GetInputStreamForFile(svgFileName)); + ISvgProcessorResult result = new DefaultSvgProcessor().Process(parsedSvg, new SvgConverterProperties().SetBaseUri + (svgFileName)); + SvgDrawContext svgDrawContext = new SvgDrawContext(new ResourceResolver(SOURCE_FOLDER), null); + SvgImageXObject svgImageXObject = new SvgImageXObject(result, svgDrawContext, 12, document.GetPdfDocument( + )); + Div div = new Div(); + div.SetWidth(100); + div.SetHeight(300); + SvgImage svgImage = new SvgImage(svgImageXObject); + svgImage.SetWidth(UnitValue.CreatePercentValue(100)); + svgImage.SetHeight(UnitValue.CreatePercentValue(100)); + div.Add(svgImage); + document.Add(div); + } + NUnit.Framework.Assert.IsNull(new CompareTool().CompareByContent(outFileName, cmpFileName, DESTINATION_FOLDER + , "diff")); + } } } diff --git a/itext.tests/itext.svg.tests/resources/itext/svg/css/AttributesRelativeUnitTest/absWidthViewBoxNoneRatioTest.svg b/itext.tests/itext.svg.tests/resources/itext/svg/css/AttributesRelativeUnitTest/absWidthViewBoxNoneRatioTest.svg new file mode 100644 index 0000000000..218b0dd7b6 --- /dev/null +++ b/itext.tests/itext.svg.tests/resources/itext/svg/css/AttributesRelativeUnitTest/absWidthViewBoxNoneRatioTest.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/itext.tests/itext.svg.tests/resources/itext/svg/css/AttributesRelativeUnitTest/absoluteHeightViewBoxMissWidthTest.svg b/itext.tests/itext.svg.tests/resources/itext/svg/css/AttributesRelativeUnitTest/absoluteHeightViewBoxMissWidthTest.svg new file mode 100644 index 0000000000..68d7c43432 --- /dev/null +++ b/itext.tests/itext.svg.tests/resources/itext/svg/css/AttributesRelativeUnitTest/absoluteHeightViewBoxMissWidthTest.svg @@ -0,0 +1,12 @@ + + + Image with non-percent width, percent height, viewbox + + + + diff --git a/itext.tests/itext.svg.tests/resources/itext/svg/css/AttributesRelativeUnitTest/absoluteWidthHeightViewBoxTest.svg b/itext.tests/itext.svg.tests/resources/itext/svg/css/AttributesRelativeUnitTest/absoluteWidthHeightViewBoxTest.svg new file mode 100644 index 0000000000..39468156bf --- /dev/null +++ b/itext.tests/itext.svg.tests/resources/itext/svg/css/AttributesRelativeUnitTest/absoluteWidthHeightViewBoxTest.svg @@ -0,0 +1,12 @@ + + + Image with non-percent width, percent height, viewbox + + + + diff --git a/itext.tests/itext.svg.tests/resources/itext/svg/css/AttributesRelativeUnitTest/absoluteWidthNoHeightNoViewBoxTest.svg b/itext.tests/itext.svg.tests/resources/itext/svg/css/AttributesRelativeUnitTest/absoluteWidthNoHeightNoViewBoxTest.svg new file mode 100644 index 0000000000..9f3a5bfa0b --- /dev/null +++ b/itext.tests/itext.svg.tests/resources/itext/svg/css/AttributesRelativeUnitTest/absoluteWidthNoHeightNoViewBoxTest.svg @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/itext.tests/itext.svg.tests/resources/itext/svg/css/AttributesRelativeUnitTest/absoluteWidthViewBoxNoHeightTest.svg b/itext.tests/itext.svg.tests/resources/itext/svg/css/AttributesRelativeUnitTest/absoluteWidthViewBoxNoHeightTest.svg new file mode 100644 index 0000000000..3736203aa1 --- /dev/null +++ b/itext.tests/itext.svg.tests/resources/itext/svg/css/AttributesRelativeUnitTest/absoluteWidthViewBoxNoHeightTest.svg @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/itext.tests/itext.svg.tests/resources/itext/svg/css/AttributesRelativeUnitTest/cmp_absWidthViewBoxNoneRatioTest.pdf b/itext.tests/itext.svg.tests/resources/itext/svg/css/AttributesRelativeUnitTest/cmp_absWidthViewBoxNoneRatioTest.pdf new file mode 100644 index 0000000000000000000000000000000000000000..5be5733210631502052ef37750212e6ba8b38e34 GIT binary patch literal 1525 zcmc&!OK#gR5Z&_>voVsOutid$NELyB#ID<*`M9>x7D&9%hjtyU-!$Kc+UvtVm#<^sYbK$};gSw_B`w^_J7Mc7COQU0*4jzl$$z?(6kfQ7vcqJKz=_3lVt_5)G0985|%8r-n+6;Xj~g!YA#D;_Z%*G zYP@b!&eYR$V7vUAu_a=IfYIa=Ns&>-#!QjA!4|}Si@>5FVuD>?As9SGp!YeXI#3DG z^Z9IiY#vv8HZHKOc5qZ;VRvl|@Bfa?lfj-8e*6D37&~X_ xBrDrv;0*9Om3L;~3};_8D7@^A@~LUsm!|prr6G9{nxZT|!%C1w+!#qvSRyIvR|EzUyKaN#QbvpTnj9Y5r;yL9FO-X3udFmg zOL9Z(;gZuqK|T-yxoX6CGA43s+As17@~WhUZfu`{%A(`q?vmlJ8@e=*VrGvbjTkCw z$Qa6EtrIBG@#l;98j=c6#+zsKJzVxwXUk_S)B6=5)f{>~6OsvpqeYX0QIw5~8rhGk zXi?0!U}p>NW0F-?CsBxmq6d@V!fj09}l*% zno>21^@}yuj@$1uRbHCPk7ssUigIgWs@IqtKdznQyR(NI4yFC~^81FnF8^d5SEks* zLN7PInu}`t!xWy;uK6H8O_roX%iB5CMN!qa!YHSl8xZPzE7%yc2Nd44xCZr7$C=n3 zC)efDVgU+0VZJhGQxw8^oFg{Vzq4uCe9z(@vQZ7>6Ui|~lLw=Ej`?ZqRQzW~kC%s# z6ko>%!k<7;yMx)JU(>*1k*!J~4pO^xX}-d-1aj8q{$EkK(gbuyrrhpvbqRZ*NW5%>X9K^m#pOH!2x6-eLlLQepT z8Hm^oeUbVi_P7_tGKn~VQZm7Z9!APdL+L4=LJBGk699~uJAsF!9&$q(Fvkf*;;}%2 z;%=fqx`A|h|38A6eUhgIHPdWtkMX_L9Xhrr*;k+e&Vx=pjk;zSb)OC+QdW_!>dWWM MaY?81=3+?x0N@;&_y7O^ literal 0 HcmV?d00001 diff --git a/itext.tests/itext.svg.tests/resources/itext/svg/css/AttributesRelativeUnitTest/cmp_absoluteWidthHeightViewBoxTest.pdf b/itext.tests/itext.svg.tests/resources/itext/svg/css/AttributesRelativeUnitTest/cmp_absoluteWidthHeightViewBoxTest.pdf new file mode 100644 index 0000000000000000000000000000000000000000..88cb03005c14ba0550856b9548d8fa382273fcbf GIT binary patch literal 1556 zcmc&!-EP`26u$RU_y)Dr1o2NCCsT#g!q}?yhXL9qwOr)qgi%34olv!VquuOPcCk0u zUS!81Knq%TIfESgobUX7K6azu?KOEzlg6*#KYkKL8O@_xa(wKZLpCYDP%hf-qBIcB z$sKWeb56TC`9KI{NiD{eHF3A5ojfZcD+_Af4V()|rr~M+aLsV50!4jSjGcaH5JN=; z893q-2=y3t)Y69)HP01$0(W0)wDvCNph3tf7 zILjwnu-t+>SY$cPvu;?zVfVFQ!sS9pu7q;gD<%&ZJ2-MK^5kVe-{i?M26H$a!9)3- zc5(wWXz>ktkY9hP=RoA!ed;yG#1;(kI+o|n~;Fv=;n5LB_2hr@cu-;*_}?l#~W`%=$Y z4^PW$a@%nj-c_3d@d%$*h>i5`T2_8sg?^|3@`+@amo0!%Gr__P_9yO9qNot93Y6ll zSb_L6P^I6)t=OuZ!E82N6hJU-gw5?&$d>Tyc_qdm_#WZ(iLSfhK;F!iH-IZZJ zyE0b?dosq7D9|pCL;U+J)sc2X!BP%spaU*^5ySzco{AGGB?j_9f=qnv zN4SgH|38DVbC#t!wJ+Jg8Q^uR`gGt7r(c2k_!cy(m#AqUqUQ65h!kaL%Iferlbkdf IZ?1ae4@}{hzyJUM literal 0 HcmV?d00001 diff --git a/itext.tests/itext.svg.tests/resources/itext/svg/css/AttributesRelativeUnitTest/cmp_absoluteWidthNoHeightNoViewBoxTest.pdf b/itext.tests/itext.svg.tests/resources/itext/svg/css/AttributesRelativeUnitTest/cmp_absoluteWidthNoHeightNoViewBoxTest.pdf new file mode 100644 index 0000000000000000000000000000000000000000..337d66f4360dc835fb5032937a8ea7187d3cbdd2 GIT binary patch literal 1551 zcmc&!&2rN)5Wedvbjh?GCblG7{$Vr8c?|!@c>CS2aZIpIKB2=y_e>SD>LaGC*DEWd z!~%Ur?r=fzK%=(^sUmI7u(BckCbX}MN)=U!ZMw00uF_l_>-#GLzdYtR^4X0$5(Y4s z)sV3&_0mXHLg5dW$tNW%SlMcU_4nX$rzT(QWSKtPDo8a`y`H6HiBO1W_h21mTcSqx zMJ48XwgGz^a33~V<+>P%O6?C`GQxbym`4LfJ@SHhdxY#AxaT^38Za_CT}oy4^QpS8 zzT>_&3dat0NOy8^G@87=oZ{>Kqm$7YzEh@zg4YN58zY2tZApA|YaU94PmEsP;){0& z8?IKWc4K|L1nsE%CQr*NtNi%JT}x4JLacgi$ni=$%1Ltq?FsY1{kQy~&0WhsStgYg zd#KH#sns6Tx<9P&1b6KRP8iDt>frKjhK<%0G*9Dh-r#$xmu%JNXfq!D%^Mozd4`r> zyM1gFdXEa=1xAMx8e6T*3^=R#Jijd!vdEC*MZKUja9~rbPvf!(i9FBYQJojEH?TTT zLh8oXylbNkSc7c*CK_reyIbn*&Cx|#;{Q{)sd7&&-pc4~{kd(UFd4RNei-lA zf&hAcg{zFn=gQdGbUMIShl&OEdZsLqN$L}i3X%pgVj&@liY!ahfD1vXiUJXFKaL|X zghY~nag~HjdV)qlOjr=7JeCkbV?q;9jmppuX_kf=q=tl4aUv66N*<9o78!VD!h8Rp z!Hs)bWE$HcHg?Bw&7f)Qa*}^lID#?IsfSS4&YQoBiu{=~I|?gD8Jl1RBKY$>JWHr+ScOJAjj zeS__bbVmM5V{CdX4Vcu-H-F!d)0>RX`eLA2@4xTg{$+{-ud@&AOkGp2eC`?y{MSYH!R0NUC|XSVA+F%km&*e$mtSrix|+M;kW!*V1X^rrAVsqY z(IH1^n=b149vtq$BP_Bl>uQ{~?r8jn1Q`h_LlLV4#A65_0X#YmUe)$tz{J;fl{^?37X&V60CU0Z;YE;QjlkroCbj$?{|zdL7C zeY}GQ!aj8M$ivT7_GJiyCjeY(C9b!ZITYe}@ghC8y>r{%(V z8iLQq{OUvs<-nLMOmQF>qjjkA!bX`+GstX_gf<0J*jyII0>mQE3mGR_7Kd86R0$_d zk%I&LvPr0;C@Io3(UEp}YBiwWEHk-{wE&}?mMV89$*oDOwI+!#qv*di&Bl8V4UV%KTVd|caT3nX6XGjbK!rc22|(i?Ttt8~#D zv=`}6lH=4tlV!P}sF^o2kHbf{hW$aCcYMy~OIVf#wdqFAIiz`XtnaQE{>o6&z!Otv7#YM+ zQ9(vf=(S0pz`~y{;~PjyT-j>M`nx!siOCmFvP|w*fT?EC?OIBf2*-$K57tpMB`Rbu zDx zx!P7W8|&#c_KrL6^0c_JogYn|hgKBZ5Zk>b&N}^kEy%Xxn};KTQ^-MT^@RHCmS_p4wf{=zC5}w(3i?g$N$=MuEJ{a3erV z&j9&ImdJ}y%gM};twG)4f2~r%Sw~t}hI+4I81)EN1FWETp!FUrD9q>issQ3*6-gKN zE8LCz75gy*h$25!n9cXyI1vd`JY%T}JRS=0J>LEQ45rTMGSk#PQzK`D7pW5K m$QkEffd+WdTh%kuwy#Y4?^lKtWn{|g@WW7%R_o2>fcybU5s)DO literal 0 HcmV?d00001 diff --git a/itext.tests/itext.svg.tests/resources/itext/svg/css/AttributesRelativeUnitTest/cmp_svgHeightPercentTest.pdf b/itext.tests/itext.svg.tests/resources/itext/svg/css/AttributesRelativeUnitTest/cmp_svgHeightPercentTest.pdf index f2a94a4907ff0f60b94023b3ef372e0112b2ce85..a3e8e56677e3f3c8b062e6ccee3f2c081d7c80c3 100644 GIT binary patch delta 364 zcmc(ZJxW7S5QTY(7KVUZ&>}p=;?3NdxpS|GRU!%ruE65{YNbv3EaGiM$O7!OaYKq% zT!htuk8=*+=lp&CdfN3Kg;n4Js0ZlJhs{e~hHW`pUK%ir2LB5C+pc!UZ17=Nm*>ar z(+Q!DZxcUlZ2X!Gzq!ZhN4LY6H5Ukmt0t5ff+JuGQ6VTRR*3}8S1;fsqDriVF!+=> z`dT8S60>C_(6$d^k*$_ua$uiJkZMxuKk%ul`fvpgFkl`|$3_ M$!xJ$-QUc90Hg?G8UO$Q delta 381 zcmc(Zu}T9$5QaHp3XemuO%;o9O2EwQ-pt;LSVd7#EUhedZ)UWLAnEfE_aZ`SUqBll z$I>G{gysMJU-5lb-_`qZQ3D2I4|DJ}Kz+Knf0bog>&f!mfoss=pRm0ttT-Ch89goT zboIP`nR{W4Y>aH0dX!!|@Jo=cBJ;(|IM)7N`MFs2FlmmX1Usn3oO| za#jS+nUesRnGAR26hIQR<}5Z$#K9Bf7P_36B(Z7Juvi4gBHm*nvesAwYE+*&hhW_D ZhAuDuGhu&dp#Eokdl0dl&8{A<%U@wfXXpR` diff --git a/itext.tests/itext.svg.tests/resources/itext/svg/css/AttributesRelativeUnitTest/cmp_svgRelativeSizeWithViewBox1.pdf b/itext.tests/itext.svg.tests/resources/itext/svg/css/AttributesRelativeUnitTest/cmp_svgRelativeSizeWithViewBox1.pdf new file mode 100644 index 0000000000000000000000000000000000000000..31f7cb4a83c8e7d42c7e440b331fde9b7d4c921f GIT binary patch literal 1716 zcmc&!&2HO95WeqI%teTeLgfC6WMBxerP?)`*s5eS1soribjd6gXU z2I-4*c18UpYLa6JkQ~l@GxN>Na(a{Td7lLl>3#b5!$+ckLY>}|lauh3spjpU!1!?3 zwASb)c}K$YC4+HIej~(Gd8bCnxyYUCsIFR5wGFs%)9|&)OMO;9-BSEiiGo=2yKtf{ zVt{+d)HLG0fl7I!YKf5}e%znAPfwxDe7n4`;Xl#QC-yXw1oKo6%DdF_NJ~sv~Y`uDb ztKW}zTwSZW!bbH9d&k0G%e=XDouA%?+g3C?7uUVc2|1II|2A#}VNh z0hRCepwywhb?zL!&r9s{D3A&S9yTXzs}zygFB6Z{_Y1;ew$Wnb$iN!%hE&KASqF+T z&)?3mP_tN+4~-!r3KTHkW+VUTPAL7*@;0nCMTHJW7=lwq( ztb^nGJ6J?e42>_Ov&J4SmnUlq*9(HbNq50ODWRZ%jgDiBy$!0ZPV)Fb#}%G9ckSV5 zgg?=jI>+n_os5zLT}1cdwN{r4W8DJ19K-F2HmcwW&uLC0ZE`^inHQ;wGgSyilY}N} zpmjnsu45L*DoYC)>jWj4ra}rnU?NM5!aGaSEZ1D8Ce=LGkxb*9nT)ccNLea4<2vH8 z5^)miT!^BG^MVh5JcGONvMOqDn|2ybaS`|xFb!wr-v(mbRXx8c`)*P8KVOujX|-+r P@ELAm((C`y=cz5-~H2g`7l0+swn5f+J7h3lE4OB@33~0wxoKi-;vBh)Jv-a>7hO pcyQ5-Lob7X=LB|qkyuLPHC`|N6Jd8`z`EF99U9wCr?-!H?FLitX_5c{ delta 453 zcmcJJy-Gtt5QRwsiVG?1L=e_O5)qP_o!Os}AQn+fA(knucK7ZDL9YFtux^SXaF!c9$!CJ)3_|d>8Sz3Xz&MUXPx&R z0=3)S=789Z9O?X^U?hUhYuNOAx6j?HU1Awo)@VVqY-an}J>UEFhBW{|FN&J0rfqur zZ}Z+qXN5+?Cc4pTxrlf7WuYdM@ocJZC$%x;j6<>^R5m#dB9MJdRD_Ya=ERiikZb28 z*eJl9DHk8an7VjdLaIc(V8s+NBE`roDXvMfhzY`~pkW`Vc)$!;icO_NU}KOVo&CFl VUOW7$(AurpjwN+;ba8X3z5uR=ae4p% diff --git a/itext.tests/itext.svg.tests/resources/itext/svg/css/AttributesRelativeUnitTest/cmp_svgWidthPercentTest.pdf b/itext.tests/itext.svg.tests/resources/itext/svg/css/AttributesRelativeUnitTest/cmp_svgWidthPercentTest.pdf index 95176cc9f56e6e12c61005bc30dea43ab46f99c9..ef74fed25b6dbd5beac9b7e78a798faaf9228d08 100644 GIT binary patch delta 357 zcmc)EF-k*05XN!#JrN11yn#hXM9|sUotYgGt3(hHui)`?syF7 zr?-I)Q00938XkXRm&X^k)e;OKbyM}pFt8Gof>eQWg(MwPwh|djq`=mNGkET#Q8KjJ z3+5KNVaAq|QBiG{+I~VMF^d>=U=J3x8gU@WE&K?(ujFxS*H`~Z825&0IJ`Rwv&CZb Ha5MV`k7r+t delta 374 zcmc(ZJ4!=Q6h(On0ST#7$08&mnDf2&ToJ285F?I2@&2Ax+N94Q-UJ+ikP$cq!O7TY zQ0HK`U@tc7ee^MUJ#6NHULD~v@C;yfw77mQ%eblYLB=F99!_z zvN$jetpK#@%}OM&%*@4<9lDy(6C^aXQoO~&A@csrwXq~nVKWXKilt=Re17(y3H^OT Q_cgdWaKq_zb#pQN1|<| zlImeF1Qh3(KJ?U7z1pj*(eL(}tQC;P&tKnv5DzHmUlnF;VCrj2RjVuj5MHln1Io`thz$M$`}_d&q^6@+0ZSgCXji*g`^hs(#+ZD{!FhK zwIUzf5WE11@p_6m=i5o*H2pgrOl57%M`HqvBp=BfBV6TSCYYbWNyUF^U1IYPqVRRB zAPlx4DBZ!V>Q!Onbeb;;Nd%hqU}nEqC5|?$d&R~(C4MX5fYcgLDWn)eC8(~7Ww9$| zYT;`&w4PQW?mys1BNf^S365fY!1p}ifr2%UGYr}um_PGe40D&qJ)FE991XDByF83% zm*)o29xtFc{A=CP#Q9VjyQI#$aC7XlgvY7KD2-IY{J_r=DtH`-l~^2aEAF82_f!-MzxKab{XMRZ!aTKl(8wR<})fh K(rCQ7?vdX?@0!K{ literal 0 HcmV?d00001 diff --git a/itext.tests/itext.svg.tests/resources/itext/svg/css/AttributesRelativeUnitTest/cmp_viewportFromConverterPropertiesTest.pdf b/itext.tests/itext.svg.tests/resources/itext/svg/css/AttributesRelativeUnitTest/cmp_viewportFromConverterPropertiesTest.pdf index c255769b3aca3b6d2c4c3ab1457077e20a71a1d0..16f21a44649b9d4d2da185a11a4781303978c1c2 100644 GIT binary patch delta 405 zcmc(Zy-EW?6h_%qgDz=Au&`Q-kcdCI_s+d{c0{bA7*Koyi0rJ?wi=DD?ysv~AvbAG delta 437 zcmcJJy-Gtt5QRxZA(!+P7H)))h>*GHRief4{%>Zu=9EJ z4ea#>wYBq{=D_)i@1y(KeeSh}T6-q#kAMaMgTwLVqMF8)45!Bk$QtzzP|sSgTN<$5 zZZGz{8yS@z3mAE7qF~eST|c$YcM*-!1{67SGro}d?dnbuLjB(6&hKYmdRuR;bx^R0 znyX^9jQ0<+EGCojY^ts&QK~B2nAkA}pAi#F@Di&;*$A)!YJ@C7LK7%k7c3*Q@g~_| zy!Qx#wiFjLiK`5im?Mc`VAN&e$|PPBW^tv(;5 + + Image with non-percent width, percent height, viewbox + + + + diff --git a/itext.tests/itext.svg.tests/resources/itext/svg/css/AttributesRelativeUnitTest/svgRelativeSizeWithViewBox1.svg b/itext.tests/itext.svg.tests/resources/itext/svg/css/AttributesRelativeUnitTest/svgRelativeSizeWithViewBox1.svg new file mode 100644 index 0000000000..a105d0c2c1 --- /dev/null +++ b/itext.tests/itext.svg.tests/resources/itext/svg/css/AttributesRelativeUnitTest/svgRelativeSizeWithViewBox1.svg @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/itext.tests/itext.svg.tests/resources/itext/svg/css/AttributesRelativeUnitTest/viewBoxMissWidthHeightTest.svg b/itext.tests/itext.svg.tests/resources/itext/svg/css/AttributesRelativeUnitTest/viewBoxMissWidthHeightTest.svg new file mode 100644 index 0000000000..f656df1ec8 --- /dev/null +++ b/itext.tests/itext.svg.tests/resources/itext/svg/css/AttributesRelativeUnitTest/viewBoxMissWidthHeightTest.svg @@ -0,0 +1,12 @@ + + + Image with non-percent width, percent height, viewbox + + + + diff --git a/itext.tests/itext.svg.tests/resources/itext/svg/renderers/SvgImageRendererTest/cmp_fixed_height_percent_width.pdf b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/SvgImageRendererTest/cmp_fixed_height_percent_width.pdf new file mode 100644 index 0000000000000000000000000000000000000000..7cf415ef8743bec662dfcb3f267b37f0a335a983 GIT binary patch literal 1539 zcmc&!OK#gR5Z&_>voVsOu*HukiA7)_vFkKwKCW%F1rjgxpN5!1?Ut3% z;evc248s%{2oEInAYKq>uwc+H$a_L`o-{=KvPs-+vR;u_I>Q0eCiBCgB;*BWu(huX<}WXluwt@jgBk)vei5r@8aW3OtyHIW%6*VG1W|WyH=7F zVr4h0vVpQGQ8RmC70!#a(74rmh{Z~}%QMz~FoEOQz z2}4sP%UGNJY@+Y0@6aoZ2GwC5+8$pV4aaXUCvd%gbTT}HJ8eoVczpohIHk00OTy8u zc_=lUm|}Sg7atC`T5YSEh4qRh_KrF4vZTDSogYn|O)JXn6x+RK%JI5)j8fcZI$iI% z^qjx9-?zEz_K%lQWt%-H%wkom*{F?UR(@&Q0rOkGw4l73fhmgWk)5myUhtBw`jTwU zgU7njATKMd{k&Q}7)?Hs9CcZXQ!q1BYtVQ29}y%miKr$ix_w1rPe?ZWjJ9e)olDQ> z*=?zb0M?PPz>#-E^RvPP#DsP{pGhCA59>H4MLGsx9omd_1bassBF@>&UQM!EpP$To zqf^Wm5cF8{fG4Gpkir^6qeC5oe1o|z+Q&YRFz%zWcK#T0Y7^0^<1Fb+bhQ<1njaWSJOlQflKz=Y4-K=DZN0FOKKJgRx*cmKbF zsdJjAMQx9fGs1&Zn|0)jv#%NgJm{_ZnrYixrv3DmA!QYss@{A?nM+!&H|$@Q zy~ykkpapHcoG)-V{?0j{KYwD4-+1r;Nn_tss3}opQR?j#3UR^7v?d z>|FSN*I&5emHvZeTspP8xtXn+)hD$v&B`)OH@ODRF%2m0$6)fjd}1l*gBRT7+P+Af zGX9jg^~lQ{UGKF5U^M!O=9ZZ=ItDYge2w*<{l7vH=~=ZbEVG_p!N@b%3g8OvKv!B+ z74>vFSri&EAXb!_ovFv_pH+-Og0L3~!UZ@-R_m6N)6j9Lmo{^?Vl_lH(B^EiS4ocV z{vCZVIAV9s$7zbWlnIv+k7A*T1t&sesU|eaFbfi{f>1J*kW?`daKe);5?s?b z&SV-jd-VOjy-<~9`~G0^RYPR2e4~1Bn(n=6K7VgeQ7ThbhfgpKQKRwZx{Lk*B*2%( literal 0 HcmV?d00001 diff --git a/itext.tests/itext.svg.tests/resources/itext/svg/renderers/SvgImageRendererTest/cmp_percent_height_fixed_width_prRatio_none.pdf b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/SvgImageRendererTest/cmp_percent_height_fixed_width_prRatio_none.pdf new file mode 100644 index 0000000000000000000000000000000000000000..03bbdde00a36889fb05e89bcaec1a084cafc159c GIT binary patch literal 1555 zcmc&!OK#gR5Z&_>voVsOu*8ojiA7)_vFkKwKCW%F1rjgxpSQoPe}`{r>TjNT86%H{|fpJ=4o+`56T7bc)jG zXhFUZhHeTBgb%(Fj)Y`E-2Q?=FDLH_(aW@f;+IY1ZPIn~WvQ2C0k*`@J=f_hI?nH} zY(l9dgdU%`gUBETcm)~iB43$A7f9yQWqhNP62ELU-}*ba+_9N0cCw5gZZ)Qw>Q2W} zvP3NL=3LfMG$krzH!7ofKHY%D2HeGim$Q7?i%PxUd(A2L80U)lED*sfD)uPdJ8;kQ z^xuGi$r9T-nYKC+@lx#U{jduL(JR>>cM47~_td zJl?wu-M?QzV6#^jFj~c>ZFfI6i@I8KRcqDMnrYjus$ezKg5qupCeOpK?c;yv))TUpE1aCLhTXxmmGOFjHh~P=ENphDqPSjv*{V-PbVo3|0ed#w}>w zjw+*`&u6!VCIT3a(gJtxh~}rZ2}lTa{D8>-tST!%atBg5}!gdEt(Y2Pm*D995{tZ5zXvV9VwywPW+c zC;3Vf&F0$J_vy3;SBD}EJ?e24L=p9qlx0H6ETbOt;xvx9FB8o<^Qn)1o+T=YL%}5F zEXy<%Or>7RxXKvUXcu7+cq$3BiZEX3L~6wpO|&P1ltx^I5oI)GEKqT%g!E#s^Zyx4 z+|y;2SMnITLma6}vO{+?`>G+tv2Rt6PTRgY?dNX}Day!{)#WoPC~39cT=vNyF~*fh literal 0 HcmV?d00001 diff --git a/itext.tests/itext.svg.tests/resources/itext/svg/renderers/SvgImageRendererTest/cmp_viewbox_fixed_height_percent_width.pdf b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/SvgImageRendererTest/cmp_viewbox_fixed_height_percent_width.pdf new file mode 100644 index 0000000000000000000000000000000000000000..ac73e521711cb3b20a5a2fb2d70ef86d662d5f44 GIT binary patch literal 1575 zcmc&!OK#gR5Z&_>voVsOutic7B^7~z#IDnz`M9>x7D&9HD9UwUTPY<6NpI9muhKKX5Kuq(eL(}tQC^Ruirm@k^m^=$qhL?^v=v;Qho-Xw%bK% zjhd4$grS=P17AWwCFnWvdUFQdoV+K*EYdmftTmtf$Xn{=v<^ZP3Y z7sLTXf{(qvvKRxr3K^IpUs`PnEalT>a$|IfJC{v5e;b!KveWr9l+nYjL8ysow_QoD z5Lb5Hm2(tziYl_BN;S(T+hBhi+`+cXX};*H((HF%bIJwdJZ91tRKBAA9;JH+-g%z> zJD_j#bg7NqpN`CZ`5ijBH4wL0i#CTBNB!a3%Mo1fAD#5i;Lg|r6J8&{H%=*Sx|DEq zYaa>&CpKT+!o`P!ZLN-~y0K2aMDCdPZkiTXj`_jZ+fY$#e{t;9zZ|c*W0c~Y>3BW! zSbBe_KXlj?{ljHaIZ~1B$x|*gP*cViL3^9qH(mE$#$D zVY5NwR(8(wg63RxkK1d?mP3s3DWXk-ob$&WqLg0lrAA^BfxsH_ku0z@cN!?z2{vX? zqWF!i0uBu$GCUQl2=*iby-!0{G*uvGHk;lShWNm+;Q0jS&%xg$k$=sbJQ znCOUSR3%y~%`(bTrX|mGrb7{iLUP*v{}qhA(?yn7@)&pnJZzOp2i|b{)j))oL8H2g bn(iiQKD~)ZQ7T(j!)G+0q|tbD*&}}dLb{)~ literal 0 HcmV?d00001 diff --git a/itext.tests/itext.svg.tests/resources/itext/svg/renderers/SvgImageRendererTest/cmp_viewbox_fixed_height_prRatio_none.pdf b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/SvgImageRendererTest/cmp_viewbox_fixed_height_prRatio_none.pdf new file mode 100644 index 0000000000000000000000000000000000000000..5feb43349600edf27791e484ef826b8d637fd05e GIT binary patch literal 1555 zcmc&!OKuuL5Z(7FYJ+Smg6Z#kA`8ie;8^j807@d+EQanLf(4AzGgx+RlufRZMQ)H> zB-O*u#!9?QFX*A_P1UQ{Z@SiPcj~MWk=n1{KYkJg6!OsxIXn!`?0j5)2Em)nqI5Q$ zkuQW{ngRn6LOoI;2R$P}XU3qNllO$!xmiK+$(NDaa;Z34AU#{;3#V;?WIkPvZmcfx$#)BVzKJUsxXJ8UmBGWU#ZqJ2Y|Y4_W&IpvaZp0JR`jK88{kJ7z^;5;|~ z26SC+7TUV~$-v&1-=UQ|3rT}DXuW@N)a}2$9KiMd(Mk6V?yM`Y;q?K0dh7tA*?iSq2mc!UPq!O;Z$xEo`5 z6YRufl01t=^iiyI>11l1zn@OqaCMl8P-v6dG#hC-8X22N9+}9fl<`apNu{<_3Ql#R zA|t6VhACrg$|9|-8HHJ#2+9(zBALW-q`5ZAaGAv!OXE1yTo{#cWn!vQ9_m=KOiLbe zX*rFkZ2o@+!{BtD<&`~pK@UHw%B8)aKly4Q#?QW1T{?At=hUCxIix64S5}A5sGy`) Jdvn<#e*ge&m{b4& literal 0 HcmV?d00001 diff --git a/itext.tests/itext.svg.tests/resources/itext/svg/renderers/SvgImageRendererTest/cmp_viewbox_percent_height_percent_width.pdf b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/SvgImageRendererTest/cmp_viewbox_percent_height_percent_width.pdf new file mode 100644 index 0000000000000000000000000000000000000000..b7c63d4c5546a24a83e0501e183849bb0d68ad2d GIT binary patch literal 1555 zcmc&!OK#gR5Z&_>voVsOu*HukQAJ=NvFkKwKCW%F1rjf0igFd$R!Yf1(i?Ttt8~#D zv=`}6{wQ(KW?3yvdFE;6&Eq2*{cf+xS|Mrt`u*c4kw77z+>paV@60Tw0SD89KeeqFAUFG{m03vew4-nmJ#_&C46 zas_21LHT^_^<#?|;1y(GihOCcDUi&k%gK$=CBC_Cfy=k?@kTbAKdUl&xHVX6YT9i_ z$q{kH*K@fD$@@WkgHMoO=ms!5(#--WszUGwsjPr;EOmXpwiakpA4!rX` z`8S|%^JJ-w-OonmzWffI+!}~ltVNr{i=+PV?d1rr_m58cXK-h1feo(@;2WouHeE|N zy0s65ffJiAZ{gy@LCw`kwH~aKFHt+@y~~o~$|*k>ds``r`V*(#`jg|Wc3glGff{eN zU2*U4`iHJ~rT=g_DV^HA+|F0c);qN|&B`)Ox3~t*F%2m0reO2DBrNn>!s(5!s$UUP zd(Guuu$kktJCOjto`y5^cpNm&%fww@R|KpfAISn4Ip4K%Wexp1hAHbIj-D^QT?o90yLqmAY?McGIW(f8VJV(Y*O2`%Aj1N zs^QpeQmcBp;`#iX-dmGmJw?!Q>jwfUg@hC~F)on0dtkAR`6$nBjE88j9UP6&kGnC3 zH^ENKkD_O>kUol)HqK_oy8G$03s;AJqT?t{ls17-(on59mx^mmh2kunOeO)1f>d)Y z62<~eQ>LVf44z_N#i0n3hzVaMG%+dFu@)>10%4Sqp=5!Iag9uzhOvwzDS|{#B7_KG zkd=~j(*FMp#@^{7%`1Bhya67n%B2Hun0+;%@Ypx1OQ-4XoaWOzhZJRO%WCr(6_hj@ IZ!UY}4{d3e761SM literal 0 HcmV?d00001 diff --git a/itext.tests/itext.svg.tests/resources/itext/svg/renderers/SvgImageRendererTest/cmp_viewbox_percent_height_percent_width_prRatio_none.pdf b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/SvgImageRendererTest/cmp_viewbox_percent_height_percent_width_prRatio_none.pdf new file mode 100644 index 0000000000000000000000000000000000000000..0fc50ee8ed2818d5a31ac9918119f6be3e5edc73 GIT binary patch literal 1548 zcmc&!OK#gR5Z&_>voVsOur(w_eTu+9VmE2fd|caT3nW=c6y-XIt(203q&MoOSLvcR zXfM*C{EHnlT~-TAo_TyTeDlaguY1(wt&lZ-{r>TjDL^RF8@9jioto*W`V11=?Xt2a znXoU6QyPJT3_xK3dcwS;35RaM-ZN&V*#bykj>KP+b&6?ard0{9K;Jtv**G~Y9xff7 ziWNk@xb}L9B@Bof(l=!>v)Yu@%BPF;#^{Q^T(!XE+w^!tJDxma89v?_q8gcY+qL8x zacwVlK-}UjY!1#3dV{wYL%7;KIPRUoy|E<~yxN0r0uh_8Bplq? z$I`&DEoOIc{$X$3tCMQ6u}(1~?YQ@DoRybO`Tn)HlA>HMaq2CW94@uvh%{%sUd}v> zyuZsII__Hj!7Qzu*hht(%xf(MwQ|hdFHQF%e&?44l=maBMNu&+ThfV*5VVBzMGaV+ zY!P_LVXl|$%}DU0)lLN8*a~^(-%Y!^js&b>AK8>_?<|jCN7TI~AJTt^pve#-C+p7< zd;>w*O~_n}n#A1Rj_*ptB=DAk3B84rqW+o3Bxr`MAml0}8l0!74T4hwmZ{ad&X9hr z=5XCDQ*%CD_xb#YK3J0zU&P34iw6Rwq=FolF>*ZAIhd|uzE3`K&y$!4$#z>YjLD+g zF;2tYiuo~(aw`_%leLvi#<#}0i|M2bm-|vn?n@B`I?phQbsEHBVwBX033#M5(n(EI z5la;YX{vQD5{0N#$bFqDKj5(pqA<;*(IMt3fw}aBh;nVhfLIMGnTD~^NsL)2xbc0I zdCmhBVU9uA{{J0ZdnePpsO{1B`gEddm-fBE_^W}4PJE-jZ<_A9X>MLOtgI4S)x+l~ LBx^L@TpY1K51^DE literal 0 HcmV?d00001 diff --git a/itext.tests/itext.svg.tests/resources/itext/svg/renderers/SvgImageRendererTest/fixed_height_percent_width.svg b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/SvgImageRendererTest/fixed_height_percent_width.svg new file mode 100644 index 0000000000..f7d6e75912 --- /dev/null +++ b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/SvgImageRendererTest/fixed_height_percent_width.svg @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/itext.tests/itext.svg.tests/resources/itext/svg/renderers/SvgImageRendererTest/percent_height_fixed_width.svg b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/SvgImageRendererTest/percent_height_fixed_width.svg new file mode 100644 index 0000000000..68cae23f3b --- /dev/null +++ b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/SvgImageRendererTest/percent_height_fixed_width.svg @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/itext.tests/itext.svg.tests/resources/itext/svg/renderers/SvgImageRendererTest/viewbox_fixed_height_percent_width.svg b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/SvgImageRendererTest/viewbox_fixed_height_percent_width.svg new file mode 100644 index 0000000000..b1115708aa --- /dev/null +++ b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/SvgImageRendererTest/viewbox_fixed_height_percent_width.svg @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/itext.tests/itext.svg.tests/resources/itext/svg/renderers/SvgImageRendererTest/viewbox_percent_height_percent_width.svg b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/SvgImageRendererTest/viewbox_percent_height_percent_width.svg new file mode 100644 index 0000000000..1d1c9682a3 --- /dev/null +++ b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/SvgImageRendererTest/viewbox_percent_height_percent_width.svg @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/itext.tests/itext.svg.tests/resources/itext/svg/renderers/SvgImageRendererTest/viewbox_percent_height_percent_width_prRatio_none.svg b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/SvgImageRendererTest/viewbox_percent_height_percent_width_prRatio_none.svg new file mode 100644 index 0000000000..78c6b131a1 --- /dev/null +++ b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/SvgImageRendererTest/viewbox_percent_height_percent_width_prRatio_none.svg @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/itext/itext.layout/itext/layout/properties/BackgroundImage.cs b/itext/itext.layout/itext/layout/properties/BackgroundImage.cs index 01d005e1cb..ef45b4f21b 100644 --- a/itext/itext.layout/itext/layout/properties/BackgroundImage.cs +++ b/itext/itext.layout/itext/layout/properties/BackgroundImage.cs @@ -26,6 +26,10 @@ You should have received a copy of the GNU Affero General Public License namespace iText.Layout.Properties { /// Class to hold background-image property. public class BackgroundImage { + private static readonly UnitValue PERCENT_VALUE_100 = UnitValue.CreatePercentValue(100F); + + private const float EPS = 1e-4F; + private static readonly BlendMode DEFAULT_BLEND_MODE = BlendMode.NORMAL; protected internal PdfXObject image; @@ -147,6 +151,31 @@ private BackgroundImage(PdfXObject image, BackgroundRepeat repeat, BackgroundPos this.backgroundOrigin = origin; } + /// Calculates width and height values for background image with a given area params. + /// width of the area of this images + /// height of the area of this images + /// array of two float values. NOTE that first value defines width, second defines height + public virtual float[] CalculateBackgroundImageSize(float areaWidth, float areaHeight) { + BackgroundSize size; + if (GetLinearGradientBuilder() == null && GetBackgroundSize().IsSpecificSize()) { + size = CalculateBackgroundSizeForArea(this, areaWidth, areaHeight); + } + else { + size = GetBackgroundSize(); + } + UnitValue widthUV = size.GetBackgroundWidthSize(); + UnitValue heightUV = size.GetBackgroundHeightSize(); + if (widthUV != null && widthUV.IsPercentValue()) { + widthUV = UnitValue.CreatePointValue(areaWidth * widthUV.GetValue() / PERCENT_VALUE_100.GetValue()); + } + if (heightUV != null && heightUV.IsPercentValue()) { + heightUV = UnitValue.CreatePointValue(areaHeight * heightUV.GetValue() / PERCENT_VALUE_100.GetValue()); + } + float? width = widthUV != null && widthUV.GetValue() >= 0 ? (float?)widthUV.GetValue() : null; + float? height = heightUV != null && heightUV.GetValue() >= 0 ? (float?)heightUV.GetValue() : null; + return ResolveWidthAndHeight(width, height, areaWidth, areaHeight); + } + /// Gets background-position. /// /// @@ -235,6 +264,67 @@ public virtual BackgroundBox GetBackgroundOrigin() { return backgroundOrigin; } + /// Resolves the final size of the background image in specified area. + /// the intrinsic background image width + /// the intrinsic background image height + /// the area width in which background will be placed + /// the area height in which background will be placed + /// the final size of the background image + protected internal virtual float[] ResolveWidthAndHeight(float? width, float? height, float areaWidth, float + areaHeight) { + bool isGradient = GetLinearGradientBuilder() != null; + float?[] widthAndHeight = new float?[2]; + if (width != null) { + widthAndHeight[0] = width; + if (!isGradient && height == null) { + float difference = GetImageWidth() < EPS ? 1F : (float)width / GetImageWidth(); + widthAndHeight[1] = GetImageHeight() * difference; + } + } + if (height != null) { + widthAndHeight[1] = height; + if (!isGradient && width == null) { + float difference = GetImageHeight() < EPS ? 1F : (float)height / GetImageHeight(); + widthAndHeight[0] = GetImageWidth() * difference; + } + } + if (widthAndHeight[0] == null) { + widthAndHeight[0] = isGradient ? areaWidth : GetImageWidth(); + } + if (widthAndHeight[1] == null) { + widthAndHeight[1] = isGradient ? areaHeight : GetImageHeight(); + } + return new float[] { (float)widthAndHeight[0], (float)widthAndHeight[1] }; + } + + private static BackgroundSize CalculateBackgroundSizeForArea(iText.Layout.Properties.BackgroundImage image + , float areaWidth, float areaHeight) { + double widthDifference = areaWidth / image.GetImageWidth(); + double heightDifference = areaHeight / image.GetImageHeight(); + if (image.GetBackgroundSize().IsCover()) { + return CreateBackgroundSizeWithMaxValueSide(widthDifference > heightDifference); + } + else { + if (image.GetBackgroundSize().IsContain()) { + return CreateBackgroundSizeWithMaxValueSide(widthDifference < heightDifference); + } + else { + return new BackgroundSize(); + } + } + } + + private static BackgroundSize CreateBackgroundSizeWithMaxValueSide(bool maxWidth) { + BackgroundSize size = new BackgroundSize(); + if (maxWidth) { + size.SetBackgroundSizeToValues(PERCENT_VALUE_100, null); + } + else { + size.SetBackgroundSizeToValues(null, PERCENT_VALUE_100); + } + return size; + } + /// /// /// builder class. diff --git a/itext/itext.layout/itext/layout/renderer/AbstractRenderer.cs b/itext/itext.layout/itext/layout/renderer/AbstractRenderer.cs index a4ca490d57..f55c5f8ccc 100644 --- a/itext/itext.layout/itext/layout/renderer/AbstractRenderer.cs +++ b/itext/itext.layout/itext/layout/renderer/AbstractRenderer.cs @@ -592,8 +592,8 @@ private void DrawBackgroundImage(BackgroundImage backgroundImage, DrawContext dr ) { Rectangle originBackgroundArea = ApplyBackgroundBoxProperty(backgroundArea.Clone(), backgroundImage.GetBackgroundOrigin ()); - float[] imageWidthAndHeight = BackgroundSizeCalculationUtil.CalculateBackgroundImageSize(backgroundImage, - originBackgroundArea.GetWidth(), originBackgroundArea.GetHeight()); + float[] imageWidthAndHeight = backgroundImage.CalculateBackgroundImageSize(originBackgroundArea.GetWidth() + , originBackgroundArea.GetHeight()); PdfXObject backgroundXObject = backgroundImage.GetImage(); if (backgroundXObject == null) { backgroundXObject = backgroundImage.GetForm(); diff --git a/itext/itext.layout/itext/layout/renderer/BackgroundSizeCalculationUtil.cs b/itext/itext.layout/itext/layout/renderer/BackgroundSizeCalculationUtil.cs deleted file mode 100644 index 2c1cb8d419..0000000000 --- a/itext/itext.layout/itext/layout/renderer/BackgroundSizeCalculationUtil.cs +++ /dev/null @@ -1,165 +0,0 @@ -/* -This file is part of the iText (R) project. -Copyright (c) 1998-2024 Apryse Group NV -Authors: Apryse Software. - -This program is offered under a commercial and under the AGPL license. -For commercial licensing, contact us at https://itextpdf.com/sales. For AGPL licensing, see below. - -AGPL licensing: -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program 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 Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ -using iText.Layout.Properties; - -namespace iText.Layout.Renderer { -//\cond DO_NOT_DOCUMENT - /// Utility class for calculate background image width and height. - internal sealed class BackgroundSizeCalculationUtil { - private const int PERCENT_100 = 100; - - private static readonly UnitValue PERCENT_VALUE_100 = UnitValue.CreatePercentValue(100); - - private BackgroundSizeCalculationUtil() { - } - - //no instance required - /// Calculates width and height values for image with a given area params. - /// - /// the - /// - /// width and height of which you want to calculate - /// - /// width of the area of this images - /// height of the area of this images - /// array of two Float values. NOTE that first value defines width, second defines height. - /// - public static float[] CalculateBackgroundImageSize(BackgroundImage image, float areaWidth, float areaHeight - ) { - bool isGradient = image.GetLinearGradientBuilder() != null; - BackgroundSize size; - if (!isGradient && image.GetBackgroundSize().IsSpecificSize()) { - size = CalculateBackgroundSizeForArea(image, areaWidth, areaHeight); - } - else { - size = image.GetBackgroundSize(); - } - UnitValue width = size.GetBackgroundWidthSize(); - UnitValue height = size.GetBackgroundHeightSize(); - float?[] widthAndHeight = new float?[2]; - if (width != null && width.GetValue() >= 0) { - bool needScale = !isGradient && height == null; - CalculateBackgroundWidth(width, areaWidth, needScale, image, widthAndHeight); - } - if (height != null && height.GetValue() >= 0) { - bool needScale = !isGradient && width == null; - CalculateBackgroundHeight(height, areaHeight, needScale, image, widthAndHeight); - } - SetDefaultSizeIfNull(widthAndHeight, areaWidth, areaHeight, image, isGradient); - return new float[] { (float)widthAndHeight[0], (float)widthAndHeight[1] }; - } - - private static BackgroundSize CalculateBackgroundSizeForArea(BackgroundImage image, float areaWidth, float - areaHeight) { - double widthDifference = areaWidth / image.GetImageWidth(); - double heightDifference = areaHeight / image.GetImageHeight(); - if (image.GetBackgroundSize().IsCover()) { - return CreateSizeWithMaxValueSide(widthDifference > heightDifference); - } - else { - if (image.GetBackgroundSize().IsContain()) { - return CreateSizeWithMaxValueSide(widthDifference < heightDifference); - } - else { - return new BackgroundSize(); - } - } - } - - private static BackgroundSize CreateSizeWithMaxValueSide(bool maxWidth) { - BackgroundSize size = new BackgroundSize(); - if (maxWidth) { - size.SetBackgroundSizeToValues(PERCENT_VALUE_100, null); - } - else { - size.SetBackgroundSizeToValues(null, PERCENT_VALUE_100); - } - return size; - } - - private static void CalculateBackgroundWidth(UnitValue width, float areaWidth, bool scale, BackgroundImage - image, float?[] widthAndHeight) { - if (scale) { - if (width.IsPercentValue()) { - ScaleWidth(areaWidth * width.GetValue() / PERCENT_100, image, widthAndHeight); - } - else { - ScaleWidth(width.GetValue(), image, widthAndHeight); - } - } - else { - if (width.IsPercentValue()) { - widthAndHeight[0] = areaWidth * width.GetValue() / PERCENT_100; - } - else { - widthAndHeight[0] = width.GetValue(); - } - } - } - - private static void CalculateBackgroundHeight(UnitValue height, float areaHeight, bool scale, BackgroundImage - image, float?[] widthAndHeight) { - if (scale) { - if (height.IsPercentValue()) { - ScaleHeight(areaHeight * height.GetValue() / PERCENT_100, image, widthAndHeight); - } - else { - ScaleHeight(height.GetValue(), image, widthAndHeight); - } - } - else { - if (height.IsPercentValue()) { - widthAndHeight[1] = areaHeight * height.GetValue() / PERCENT_100; - } - else { - widthAndHeight[1] = height.GetValue(); - } - } - } - - private static void ScaleWidth(float newWidth, BackgroundImage image, float?[] imageWidthAndHeight) { - float difference = image.GetImageWidth() == 0f ? 1f : newWidth / image.GetImageWidth(); - imageWidthAndHeight[0] = newWidth; - imageWidthAndHeight[1] = image.GetImageHeight() * difference; - } - - private static void ScaleHeight(float newHeight, BackgroundImage image, float?[] imageWidthAndHeight) { - float difference = image.GetImageHeight() == 0f ? 1f : newHeight / image.GetImageHeight(); - imageWidthAndHeight[0] = image.GetImageWidth() * difference; - imageWidthAndHeight[1] = newHeight; - } - - private static void SetDefaultSizeIfNull(float?[] widthAndHeight, float areaWidth, float areaHeight, BackgroundImage - image, bool isGradient) { - if (isGradient) { - widthAndHeight[0] = widthAndHeight[0] == null ? areaWidth : widthAndHeight[0]; - widthAndHeight[1] = widthAndHeight[1] == null ? areaHeight : widthAndHeight[1]; - } - else { - widthAndHeight[0] = widthAndHeight[0] == null ? image.GetImageWidth() : widthAndHeight[0]; - widthAndHeight[1] = widthAndHeight[1] == null ? image.GetImageHeight() : widthAndHeight[1]; - } - } - } -//\endcond -} diff --git a/itext/itext.svg/itext/svg/SvgConstants.cs b/itext/itext.svg/itext/svg/SvgConstants.cs index 455f75b9e1..29826cdee9 100644 --- a/itext/itext.svg/itext/svg/SvgConstants.cs +++ b/itext/itext.svg/itext/svg/SvgConstants.cs @@ -615,19 +615,19 @@ public sealed class Values { /// Value representing the default aspect ratio: xmidymid. public const String DEFAULT_ASPECT_RATIO = SvgConstants.Values.XMID_YMID; - /// Default svg view port width value. + /// Default svg view port width value (300px * 0.75 = 225). /// - /// Default svg view port width value. + /// Default svg view port width value (300px * 0.75 = 225). /// See SVG specification. /// - public const String DEFAULT_VIEWPORT_WIDTH = "300px"; + public const float DEFAULT_VIEWPORT_WIDTH = 225F; - /// Default svg view port height value. + /// Default svg view port height value (150px * 0.75 = 112.5). /// - /// Default svg view port height value. + /// Default svg view port height value (150px * 0.75 = 112.5). /// See SVG specification. /// - public const String DEFAULT_VIEWPORT_HEIGHT = "150px"; + public const float DEFAULT_VIEWPORT_HEIGHT = 112.5F; /// Default width and height value. /// diff --git a/itext/itext.svg/itext/svg/css/SvgCssContext.cs b/itext/itext.svg/itext/svg/css/SvgCssContext.cs index 30f6f0cb03..8f0dac44b4 100644 --- a/itext/itext.svg/itext/svg/css/SvgCssContext.cs +++ b/itext/itext.svg/itext/svg/css/SvgCssContext.cs @@ -45,5 +45,11 @@ public virtual float GetRootFontSize() { public virtual void SetRootFontSize(String fontSizeStr) { this.rootFontSize = CssDimensionParsingUtils.ParseAbsoluteFontSize(fontSizeStr); } + + /// Sets the root font size. + /// the new root font size + public virtual void SetRootFontSize(float rootFontSize) { + this.rootFontSize = rootFontSize; + } } } diff --git a/itext/itext.svg/itext/svg/element/SvgImage.cs b/itext/itext.svg/itext/svg/element/SvgImage.cs index 9583446d3b..0b89824ac2 100644 --- a/itext/itext.svg/itext/svg/element/SvgImage.cs +++ b/itext/itext.svg/itext/svg/element/SvgImage.cs @@ -20,6 +20,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ +using System; using iText.Kernel.Pdf; using iText.Layout.Element; using iText.Layout.Renderer; @@ -45,11 +46,25 @@ public SvgImage(SvgImageXObject xObject) : base(xObject) { } + /// + /// Gets the + /// + /// contained in this image object. + /// + /// + /// a + /// + /// + public virtual SvgImageXObject GetSvgImageXObject() { + return (SvgImageXObject)GetXObject(); + } + /// /// Draws SVG image to a canvas-like object maintained in the /// . /// /// pdf that shall contain the SVG image. + [System.ObsoleteAttribute(@"was replaced by getSvgImageXObject().generate(PdfDocument)")] public virtual void Generate(PdfDocument document) { ((SvgImageXObject)xObject).Generate(document); } diff --git a/itext/itext.svg/itext/svg/renderers/SvgImageRenderer.cs b/itext/itext.svg/itext/svg/renderers/SvgImageRenderer.cs index 8e0b0c2e2b..bc6003e7e4 100644 --- a/itext/itext.svg/itext/svg/renderers/SvgImageRenderer.cs +++ b/itext/itext.svg/itext/svg/renderers/SvgImageRenderer.cs @@ -20,8 +20,13 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ +using iText.Kernel.Geom; +using iText.Layout.Layout; using iText.Layout.Renderer; +using iText.Svg; using iText.Svg.Element; +using iText.Svg.Utils; +using iText.Svg.Xobject; namespace iText.Svg.Renderers { /// @@ -40,10 +45,56 @@ public SvgImageRenderer(SvgImage image) : base(image) { } + public override LayoutResult Layout(LayoutContext layoutContext) { + SvgImage svgImage = (SvgImage)modelElement; + if (svgImage.GetSvgImageXObject().IsRelativeSized()) { + CalculateRelativeSizedSvgSize(svgImage, layoutContext.GetArea().GetBBox()); + } + return base.Layout(layoutContext); + } + /// public override void Draw(DrawContext drawContext) { - ((SvgImage)modelElement).Generate(drawContext.GetDocument()); + ((SvgImage)modelElement).GetSvgImageXObject().Generate(drawContext.GetDocument()); base.Draw(drawContext); } + + private void CalculateRelativeSizedSvgSize(SvgImage svgImage, Rectangle layoutBox) { + SvgImageXObject svgImageXObject = svgImage.GetSvgImageXObject(); + ISvgNodeRenderer svgRootRenderer = svgImageXObject.GetResult().GetRootRenderer(); + float? aspectRatio = null; + float[] viewBoxValues = SvgCssUtils.ParseViewBox(svgRootRenderer); + if (viewBoxValues != null && viewBoxValues.Length == SvgConstants.Values.VIEWBOX_VALUES_NUMBER) { + // aspectRatio can also be specified by absolute height and width, + // but in that case SVG isn't relative and processed as usual image + aspectRatio = viewBoxValues[2] / viewBoxValues[3]; + } + float? retrievedAreaWidth = RetrieveWidth(layoutBox.GetWidth()); + float? retrievedAreaHeight = RetrieveHeight(); + float areaWidth = retrievedAreaWidth == null ? (aspectRatio == null ? SvgConstants.Values.DEFAULT_VIEWPORT_WIDTH + : layoutBox.GetWidth()) : (float)retrievedAreaWidth; + float areaHeight = retrievedAreaHeight == null ? SvgConstants.Values.DEFAULT_VIEWPORT_HEIGHT : (float)retrievedAreaHeight; + float finalWidth; + float finalHeight; + if (aspectRatio != null && (retrievedAreaHeight == null || retrievedAreaWidth == null)) { + if (retrievedAreaWidth == null && retrievedAreaHeight != null) { + finalHeight = areaHeight; + finalWidth = (float)(finalHeight * aspectRatio); + } + else { + finalWidth = areaWidth; + finalHeight = (float)(finalWidth / aspectRatio); + } + } + else { + finalWidth = areaWidth; + finalHeight = areaHeight; + } + svgRootRenderer.SetAttribute(SvgConstants.Attributes.WIDTH, null); + svgRootRenderer.SetAttribute(SvgConstants.Attributes.HEIGHT, null); + svgImageXObject.UpdateBBox(finalWidth, finalHeight); + imageWidth = svgImage.GetImageWidth(); + imageHeight = svgImage.GetImageHeight(); + } } } diff --git a/itext/itext.svg/itext/svg/renderers/impl/AbstractContainerSvgNodeRenderer.cs b/itext/itext.svg/itext/svg/renderers/impl/AbstractContainerSvgNodeRenderer.cs index 2deb87ed58..3db6e43c8c 100644 --- a/itext/itext.svg/itext/svg/renderers/impl/AbstractContainerSvgNodeRenderer.cs +++ b/itext/itext.svg/itext/svg/renderers/impl/AbstractContainerSvgNodeRenderer.cs @@ -48,8 +48,10 @@ protected internal override void DoDraw(SvgDrawContext context) { internal virtual Rectangle CalculateViewPort(SvgDrawContext context) { Rectangle percentBaseBox; if (GetParent() is PdfRootSvgNodeRenderer || !(GetParent() is AbstractSvgNodeRenderer)) { - // If the current container is a top level SVG, take a current view port as a percent base - percentBaseBox = context.GetCurrentViewPort(); + // If the current container is a top level SVG, make a copy of the current viewport. + // It is needed to avoid double percent resolving. For absolute sized viewport we + // will get the same viewport, so save resources and just make a copy. + return context.GetCurrentViewPort().Clone(); } else { // If the current container is nested container, take a view box as a percent base diff --git a/itext/itext.svg/itext/svg/utils/SvgCssUtils.cs b/itext/itext.svg/itext/svg/utils/SvgCssUtils.cs index dcc0b62e3b..615709176f 100644 --- a/itext/itext.svg/itext/svg/utils/SvgCssUtils.cs +++ b/itext/itext.svg/itext/svg/utils/SvgCssUtils.cs @@ -213,10 +213,8 @@ public static Rectangle ExtractWidthAndHeight(ISvgNodeRenderer svgRenderer, floa if (context.GetCustomViewport() == null) { float[] viewBox = iText.Svg.Utils.SvgCssUtils.ParseViewBox(svgRenderer); if (viewBox == null) { - percentHorizontalBase = CssDimensionParsingUtils.ParseAbsoluteLength(SvgConstants.Values.DEFAULT_VIEWPORT_WIDTH - ); - percentVerticalBase = CssDimensionParsingUtils.ParseAbsoluteLength(SvgConstants.Values.DEFAULT_VIEWPORT_HEIGHT - ); + percentHorizontalBase = SvgConstants.Values.DEFAULT_VIEWPORT_WIDTH; + percentVerticalBase = SvgConstants.Values.DEFAULT_VIEWPORT_HEIGHT; } else { percentHorizontalBase = viewBox[2]; diff --git a/itext/itext.svg/itext/svg/xobject/SvgImageXObject.cs b/itext/itext.svg/itext/svg/xobject/SvgImageXObject.cs index 392835999e..b12245c905 100644 --- a/itext/itext.svg/itext/svg/xobject/SvgImageXObject.cs +++ b/itext/itext.svg/itext/svg/xobject/SvgImageXObject.cs @@ -20,15 +20,20 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ +using System; using iText.Kernel.Geom; using iText.Kernel.Pdf; using iText.Kernel.Pdf.Canvas; using iText.Kernel.Pdf.Xobject; +using iText.Layout.Properties; +using iText.StyledXmlParser.Css.Util; using iText.StyledXmlParser.Resolver.Resource; +using iText.Svg; using iText.Svg.Processors; using iText.Svg.Processors.Impl; using iText.Svg.Renderers; using iText.Svg.Renderers.Impl; +using iText.Svg.Utils; namespace iText.Svg.Xobject { /// A wrapper for Form XObject for SVG images. @@ -39,6 +44,12 @@ public class SvgImageXObject : PdfFormXObject { private bool isGenerated = false; + private float em; + + private SvgDrawContext svgDrawContext; + + private bool isRelativeSized = false; + /// Creates a new instance of Form XObject for the SVG image. /// the form XObject’s bounding box. /// processor result containing the SVG information. @@ -51,6 +62,62 @@ public SvgImageXObject(Rectangle bBox, ISvgProcessorResult result, ResourceResol : base(bBox) { this.result = result; this.resourceResolver = resourceResolver; + this.svgDrawContext = new SvgDrawContext(resourceResolver, result.GetFontProvider()); + } + + /// Creates a new instance of Form XObject for the relative sized SVG image. + /// processor result containing the SVG information + /// the svg draw context + /// em value in pt + /// pdf that shall contain the SVG image, can be null + public SvgImageXObject(ISvgProcessorResult result, SvgDrawContext svgContext, float em, PdfDocument pdfDocument + ) + : this(null, result, svgContext.GetResourceResolver()) { + if (pdfDocument != null) { + svgContext.PushCanvas(new PdfCanvas(this, pdfDocument)); + } + this.em = em; + this.isRelativeSized = true; + this.svgDrawContext = svgContext; + } + + /// If the SVG image is relative sized. + /// + /// If the SVG image is relative sized. This information + /// is used during image layouting to resolve it's relative size. + /// + /// + /// + /// + /// if the SVG image is relative sized, + /// + /// otherwise + /// + /// + /// + public virtual bool IsRelativeSized() { + return isRelativeSized; + } + + /// Sets if the SVG image is relative sized. + /// + /// Sets if the SVG image is relative sized. This information + /// is used during image layouting to resolve it's relative size. + /// + /// + /// + /// + /// if the SVG image is relative sized, + /// + /// otherwise + /// + /// + /// + public virtual void SetRelativeSized(bool relativeSized) { + // TODO DEVSIX-8829 remove/deprecate this method after ticket will be done + isRelativeSized = relativeSized; } /// Returns processor result containing the SVG information. @@ -65,6 +132,7 @@ public virtual ISvgProcessorResult GetResult() { /// /// instance /// + [System.ObsoleteAttribute(@"not used anymore")] public virtual ResourceResolver GetResourceResolver() { return resourceResolver; } @@ -74,21 +142,54 @@ public virtual ResourceResolver GetResourceResolver() { /// Processes xObject before first image generation to avoid drawing it twice or more. It allows to reuse the same /// Form XObject multiple times. /// - /// pdf that shall contain the SVG image. + /// + /// pdf that shall contain the SVG image, can be null if constructor + /// + /// was used + /// public virtual void Generate(PdfDocument document) { if (!isGenerated) { - PdfCanvas canvas = new PdfCanvas(this, document); - SvgDrawContext context = new SvgDrawContext(resourceResolver, result.GetFontProvider()); if (result is SvgProcessorResult) { - context.SetCssContext(((SvgProcessorResult)result).GetContext().GetCssContext()); + svgDrawContext.SetCssContext(((SvgProcessorResult)result).GetContext().GetCssContext()); + } + svgDrawContext.SetTempFonts(result.GetTempFonts()); + svgDrawContext.AddNamedObjects(result.GetNamedObjects()); + if (svgDrawContext.Size() == 0) { + svgDrawContext.PushCanvas(new PdfCanvas(this, document)); } - context.SetTempFonts(result.GetTempFonts()); - context.AddNamedObjects(result.GetNamedObjects()); - context.PushCanvas(canvas); ISvgNodeRenderer root = new PdfRootSvgNodeRenderer(result.GetRootRenderer()); - root.Draw(context); + root.Draw(svgDrawContext); isGenerated = true; } } + + /// Updated XObject BBox for relative sized SVG image. + /// the area width where SVG image will be drawn + /// the area height where SVG image will be drawn + public virtual void UpdateBBox(float? areaWidth, float? areaHeight) { + // TODO DEVSIX-8829 change parameters to float, not Float + if (areaWidth != null && areaHeight != null) { + svgDrawContext.SetCustomViewport(new Rectangle((float)areaWidth, (float)areaHeight)); + } + Rectangle bbox = SvgCssUtils.ExtractWidthAndHeight(result.GetRootRenderer(), em, svgDrawContext); + SetBBox(new PdfArray(bbox)); + } + + /// Gets the SVG element width. + /// the SVG element width + public virtual UnitValue GetElementWidth() { + String widthStr = result.GetRootRenderer().GetAttribute(SvgConstants.Attributes.WIDTH); + return CssDimensionParsingUtils.ParseLengthValueToPt(widthStr, em, svgDrawContext.GetCssContext().GetRootFontSize + ()); + } + + /// Gets the SVG element height. + /// the SVG element height + public virtual UnitValue GetElementHeight() { + String heightStr = result.GetRootRenderer().GetAttribute(SvgConstants.Attributes.HEIGHT); + return CssDimensionParsingUtils.ParseLengthValueToPt(heightStr, em, svgDrawContext.GetCssContext().GetRootFontSize + ()); + } } } diff --git a/port-hash b/port-hash index 9fa91479eb..d06f69a49e 100644 --- a/port-hash +++ b/port-hash @@ -1 +1 @@ -8bb3a645256a2b07cf12bb1b8d159ccb397b64e6 +fad2fb2571e1aed7f01fc39fdf33081cdd6a3893