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 0000000000..5be5733210 Binary files /dev/null and b/itext.tests/itext.svg.tests/resources/itext/svg/css/AttributesRelativeUnitTest/cmp_absWidthViewBoxNoneRatioTest.pdf differ diff --git a/itext.tests/itext.svg.tests/resources/itext/svg/css/AttributesRelativeUnitTest/cmp_absoluteHeightViewBoxMissWidthTest.pdf b/itext.tests/itext.svg.tests/resources/itext/svg/css/AttributesRelativeUnitTest/cmp_absoluteHeightViewBoxMissWidthTest.pdf new file mode 100644 index 0000000000..7988c7b2dd Binary files /dev/null and b/itext.tests/itext.svg.tests/resources/itext/svg/css/AttributesRelativeUnitTest/cmp_absoluteHeightViewBoxMissWidthTest.pdf differ 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 0000000000..88cb03005c Binary files /dev/null and b/itext.tests/itext.svg.tests/resources/itext/svg/css/AttributesRelativeUnitTest/cmp_absoluteWidthHeightViewBoxTest.pdf differ 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 0000000000..337d66f436 Binary files /dev/null and b/itext.tests/itext.svg.tests/resources/itext/svg/css/AttributesRelativeUnitTest/cmp_absoluteWidthNoHeightNoViewBoxTest.pdf differ diff --git a/itext.tests/itext.svg.tests/resources/itext/svg/css/AttributesRelativeUnitTest/cmp_absoluteWidthViewBoxNoHeightTest.pdf b/itext.tests/itext.svg.tests/resources/itext/svg/css/AttributesRelativeUnitTest/cmp_absoluteWidthViewBoxNoHeightTest.pdf new file mode 100644 index 0000000000..c45bfa13aa Binary files /dev/null and b/itext.tests/itext.svg.tests/resources/itext/svg/css/AttributesRelativeUnitTest/cmp_absoluteWidthViewBoxNoHeightTest.pdf differ diff --git a/itext.tests/itext.svg.tests/resources/itext/svg/css/AttributesRelativeUnitTest/cmp_percentHeightMissWidthViewBoxTest.pdf b/itext.tests/itext.svg.tests/resources/itext/svg/css/AttributesRelativeUnitTest/cmp_percentHeightMissWidthViewBoxTest.pdf new file mode 100644 index 0000000000..181881f1ab Binary files /dev/null and b/itext.tests/itext.svg.tests/resources/itext/svg/css/AttributesRelativeUnitTest/cmp_percentHeightMissWidthViewBoxTest.pdf differ 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 f2a94a4907..a3e8e56677 100644 Binary files a/itext.tests/itext.svg.tests/resources/itext/svg/css/AttributesRelativeUnitTest/cmp_svgHeightPercentTest.pdf and b/itext.tests/itext.svg.tests/resources/itext/svg/css/AttributesRelativeUnitTest/cmp_svgHeightPercentTest.pdf differ 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 0000000000..31f7cb4a83 Binary files /dev/null and b/itext.tests/itext.svg.tests/resources/itext/svg/css/AttributesRelativeUnitTest/cmp_svgRelativeSizeWithViewBox1.pdf differ diff --git a/itext.tests/itext.svg.tests/resources/itext/svg/css/AttributesRelativeUnitTest/cmp_svgViewboxWidthPercentTest.pdf b/itext.tests/itext.svg.tests/resources/itext/svg/css/AttributesRelativeUnitTest/cmp_svgViewboxWidthPercentTest.pdf index 081a52bfd8..da76fa8100 100644 Binary files a/itext.tests/itext.svg.tests/resources/itext/svg/css/AttributesRelativeUnitTest/cmp_svgViewboxWidthPercentTest.pdf and b/itext.tests/itext.svg.tests/resources/itext/svg/css/AttributesRelativeUnitTest/cmp_svgViewboxWidthPercentTest.pdf differ 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 95176cc9f5..ef74fed25b 100644 Binary files a/itext.tests/itext.svg.tests/resources/itext/svg/css/AttributesRelativeUnitTest/cmp_svgWidthPercentTest.pdf and b/itext.tests/itext.svg.tests/resources/itext/svg/css/AttributesRelativeUnitTest/cmp_svgWidthPercentTest.pdf differ diff --git a/itext.tests/itext.svg.tests/resources/itext/svg/css/AttributesRelativeUnitTest/cmp_viewBoxMissWidthHeightTest.pdf b/itext.tests/itext.svg.tests/resources/itext/svg/css/AttributesRelativeUnitTest/cmp_viewBoxMissWidthHeightTest.pdf new file mode 100644 index 0000000000..73374e5586 Binary files /dev/null and b/itext.tests/itext.svg.tests/resources/itext/svg/css/AttributesRelativeUnitTest/cmp_viewBoxMissWidthHeightTest.pdf differ 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 c255769b3a..16f21a4464 100644 Binary files a/itext.tests/itext.svg.tests/resources/itext/svg/css/AttributesRelativeUnitTest/cmp_viewportFromConverterPropertiesTest.pdf and b/itext.tests/itext.svg.tests/resources/itext/svg/css/AttributesRelativeUnitTest/cmp_viewportFromConverterPropertiesTest.pdf differ diff --git a/itext.tests/itext.svg.tests/resources/itext/svg/css/AttributesRelativeUnitTest/percentHeightMissWidthViewBoxTest.svg b/itext.tests/itext.svg.tests/resources/itext/svg/css/AttributesRelativeUnitTest/percentHeightMissWidthViewBoxTest.svg new file mode 100644 index 0000000000..7837d06cc0 --- /dev/null +++ b/itext.tests/itext.svg.tests/resources/itext/svg/css/AttributesRelativeUnitTest/percentHeightMissWidthViewBoxTest.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/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 0000000000..7cf415ef87 Binary files /dev/null and b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/SvgImageRendererTest/cmp_fixed_height_percent_width.pdf differ diff --git a/itext.tests/itext.svg.tests/resources/itext/svg/renderers/SvgImageRendererTest/cmp_percent_height_fixed_width.pdf b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/SvgImageRendererTest/cmp_percent_height_fixed_width.pdf new file mode 100644 index 0000000000..9656091c82 Binary files /dev/null and b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/SvgImageRendererTest/cmp_percent_height_fixed_width.pdf differ 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 0000000000..03bbdde00a Binary files /dev/null and b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/SvgImageRendererTest/cmp_percent_height_fixed_width_prRatio_none.pdf differ 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 0000000000..ac73e52171 Binary files /dev/null and b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/SvgImageRendererTest/cmp_viewbox_fixed_height_percent_width.pdf differ 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 0000000000..5feb433496 Binary files /dev/null and b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/SvgImageRendererTest/cmp_viewbox_fixed_height_prRatio_none.pdf differ 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 0000000000..b7c63d4c55 Binary files /dev/null and b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/SvgImageRendererTest/cmp_viewbox_percent_height_percent_width.pdf differ 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 0000000000..0fc50ee8ed Binary files /dev/null and b/itext.tests/itext.svg.tests/resources/itext/svg/renderers/SvgImageRendererTest/cmp_viewbox_percent_height_percent_width_prRatio_none.pdf differ 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