diff --git a/itext.tests/itext.kernel.tests/itext/kernel/pdf/PdfDocumentTest.cs b/itext.tests/itext.kernel.tests/itext/kernel/pdf/PdfDocumentTest.cs index ffe06e8fef..f96bf55bac 100644 --- a/itext.tests/itext.kernel.tests/itext/kernel/pdf/PdfDocumentTest.cs +++ b/itext.tests/itext.kernel.tests/itext/kernel/pdf/PdfDocumentTest.cs @@ -21,6 +21,7 @@ You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ using System; +using System.Collections.Generic; using System.IO; using iText.Commons.Utils; using iText.IO.Image; @@ -32,6 +33,7 @@ You should have received a copy of the GNU Affero General Public License using iText.Kernel.Pdf.Annot; using iText.Kernel.Pdf.Canvas; using iText.Kernel.Pdf.Filespec; +using iText.Kernel.Pdf.Layer; using iText.Kernel.Pdf.Navigation; using iText.Kernel.Pdf.Tagging; using iText.Kernel.Pdf.Xobject; @@ -530,60 +532,13 @@ public virtual void GetDefaultConformanceLevelTest() { NUnit.Framework.Assert.IsFalse(document.GetConformance().IsPdfAOrUa()); } - //TODO DEVSIX-8490 remove this test when implemented [NUnit.Framework.Test] - [LogMessage(KernelLogMessageConstant.DUPLICATE_ENTRIES_IN_ORDER_ARRAY_REMOVED)] - public virtual void RemoveDuplicatesInOrderArrayTest() { - String inputPdf = "removeDuplicatesInOrderArray.pdf"; - String outputPdf = "removedDuplicateInOrderArray.pdf"; - PdfDocument doc = new PdfDocument(new PdfReader(SOURCE_FOLDER + inputPdf), CompareTool.CreateTestPdfWriter - (DESTINATION_FOLDER + outputPdf)); - //Need to update OCProperties - doc.GetCatalog().GetOCProperties(false); + public virtual void OcgWithTwoParentsTest() { + String inputPdf = "ocgWithTwoParents.pdf"; + PdfDocument doc = new PdfDocument(new PdfReader(SOURCE_FOLDER + inputPdf)); + IList layerList = doc.GetCatalog().GetOCProperties(false).GetLayers(); + NUnit.Framework.Assert.AreEqual(2, layerList[4].GetParents().Count); doc.Close(); - NUnit.Framework.Assert.IsNull(new CompareTool().CompareByContent(DESTINATION_FOLDER + outputPdf, SOURCE_FOLDER - + "cmp_" + outputPdf, DESTINATION_FOLDER)); - } - - //TODO DEVSIX-8490 remove this test when implemented - [NUnit.Framework.Test] - [LogMessage(KernelLogMessageConstant.DUPLICATE_ENTRIES_IN_ORDER_ARRAY_REMOVED)] - public virtual void RemoveNestedDuplicatesInOrderArrayTest() { - String inputPdf = "removeNestedDuplicatesInOrderArray.pdf"; - String outputPdf = "removedNestedDuplicatesInOrderArray.pdf"; - PdfDocument doc = new PdfDocument(new PdfReader(SOURCE_FOLDER + inputPdf), new PdfWriter(DESTINATION_FOLDER - + outputPdf)); - //Need to update OCProperties - doc.GetCatalog().GetOCProperties(false); - doc.Close(); - NUnit.Framework.Assert.IsNull(new CompareTool().CompareByContent(DESTINATION_FOLDER + outputPdf, SOURCE_FOLDER - + "cmp_" + outputPdf, DESTINATION_FOLDER)); - } - - //TODO DEVSIX-8490 remove this test when implemented - [NUnit.Framework.Test] - public virtual void RemoveDuplicatesHasChildInOrderArrayTest() { - String inputPdf = "removeDuplicatesHasChildInOrderArray.pdf"; - String outputPdf = "removedDuplicatesHasChildInOrderArray.pdf"; - PdfDocument doc = new PdfDocument(new PdfReader(SOURCE_FOLDER + inputPdf), CompareTool.CreateTestPdfWriter - (DESTINATION_FOLDER + outputPdf)); - PdfCatalog catalog = doc.GetCatalog(); - Exception e = NUnit.Framework.Assert.Catch(typeof(PdfException), () => catalog.GetOCProperties(false)); - NUnit.Framework.Assert.AreEqual(MessageFormatUtil.Format(KernelExceptionMessageConstant.UNABLE_TO_REMOVE_DUPLICATE_LAYER - , "4 0 R"), e.Message); - } - - //TODO DEVSIX-8490 remove this test when implemented - [NUnit.Framework.Test] - public virtual void RemoveNestedDuplicatesHasChildInOrderArrayTest() { - String inputPdf = "removeNestedDuplicatesHasChildInOrderArray.pdf"; - String outputPdf = "removedNestedDuplicatesHasChildInOrderArray.pdf"; - PdfDocument doc = new PdfDocument(new PdfReader(SOURCE_FOLDER + inputPdf), CompareTool.CreateTestPdfWriter - (DESTINATION_FOLDER + outputPdf)); - PdfCatalog catalog = doc.GetCatalog(); - Exception e = NUnit.Framework.Assert.Catch(typeof(PdfException), () => catalog.GetOCProperties(false)); - NUnit.Framework.Assert.AreEqual(MessageFormatUtil.Format(KernelExceptionMessageConstant.UNABLE_TO_REMOVE_DUPLICATE_LAYER - , "27 0 R"), e.Message); } [NUnit.Framework.Test] diff --git a/itext.tests/itext.kernel.tests/itext/kernel/pdf/layer/PdfLayerTest.cs b/itext.tests/itext.kernel.tests/itext/kernel/pdf/layer/PdfLayerTest.cs index 7f532ececb..bfe62bf799 100644 --- a/itext.tests/itext.kernel.tests/itext/kernel/pdf/layer/PdfLayerTest.cs +++ b/itext.tests/itext.kernel.tests/itext/kernel/pdf/layer/PdfLayerTest.cs @@ -25,7 +25,6 @@ You should have received a copy of the GNU Affero General Public License using iText.Commons.Utils; using iText.IO.Font.Constants; using iText.IO.Source; -using iText.Kernel.Exceptions; using iText.Kernel.Font; using iText.Kernel.Geom; using iText.Kernel.Pdf; @@ -466,21 +465,69 @@ public virtual void TestReadOcgFromApAnnotation() { } } - //TODO DEVSIX-8490 remove this test when implemented [NUnit.Framework.Test] - public virtual void AddSecondParentlayerTest() { - using (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) { - using (PdfDocument doc = new PdfDocument(new PdfWriter(outputStream))) { - PdfLayer childLayer = new PdfLayer("childLayer", doc); - PdfLayer parentLayer1 = new PdfLayer("firstParentLayer", doc); - PdfLayer parentLayer2 = new PdfLayer("secondParentLayer", doc); - parentLayer1.AddChild(childLayer); - PdfIndirectReference @ref = childLayer.GetIndirectReference(); - Exception e = NUnit.Framework.Assert.Catch(typeof(PdfException), () => parentLayer2.AddChild(childLayer)); - NUnit.Framework.Assert.AreEqual(MessageFormatUtil.Format(KernelExceptionMessageConstant.UNABLE_TO_ADD_SECOND_PARENT_LAYER - , @ref.ToString()), e.Message); - } - } + public virtual void NestedLayerTwoParentsTest() { + String outPdf = destinationFolder + "nestedLayerTwoParents.pdf"; + String cmpPdf = sourceFolder + "cmp_nestedLayerTwoParents.pdf"; + PdfDocument pdfDoc = new PdfDocument(CompareTool.CreateTestPdfWriter(outPdf)); + PdfFont font = PdfFontFactory.CreateFont(); + PdfLayer parentLayer1 = new PdfLayer("Parent layer 1", pdfDoc); + PdfLayer parentLayer2 = new PdfLayer("Parent layer 2", pdfDoc); + PdfLayer nestedLayer = new PdfLayer("Nested layer 1", pdfDoc); + parentLayer1.AddChild(nestedLayer); + parentLayer2.AddChild(nestedLayer); + PdfCanvas canvas = new PdfCanvas(pdfDoc.AddNewPage()); + canvas.SetFontAndSize(font, 12); + PdfLayerTestUtils.AddTextInsideLayer(parentLayer1, canvas, "Parent layer 1 text", 50, 750); + PdfLayerTestUtils.AddTextInsideLayer(parentLayer2, canvas, "Parent layer 2 text", 50, 700); + PdfLayerTestUtils.AddTextInsideLayer(nestedLayer, canvas, "Nested layer 1 text", 100, 650); + canvas.Release(); + pdfDoc.Close(); + PdfLayerTestUtils.CompareLayers(outPdf, cmpPdf); + } + + [NUnit.Framework.Test] + public virtual void NestedLayerTwoParentsWithOneParentTest() { + String outPdf = destinationFolder + "nestedLayerTwoParentsWithOneParent.pdf"; + String cmpPdf = sourceFolder + "cmp_nestedLayerTwoParentsWithOneParent.pdf"; + PdfDocument pdfDoc = new PdfDocument(CompareTool.CreateTestPdfWriter(outPdf)); + PdfFont font = PdfFontFactory.CreateFont(); + PdfLayer parentLayer = new PdfLayer("Parent layer", pdfDoc); + PdfLayer layer1 = new PdfLayer("Layer 1", pdfDoc); + PdfLayer layer2 = new PdfLayer("Layer 2", pdfDoc); + PdfLayer nestedLayer = new PdfLayer("Nested layer 1", pdfDoc); + layer1.AddChild(nestedLayer); + layer2.AddChild(nestedLayer); + parentLayer.AddChild(layer1); + parentLayer.AddChild(layer2); + PdfCanvas canvas = new PdfCanvas(pdfDoc.AddNewPage()); + canvas.SetFontAndSize(font, 12); + PdfLayerTestUtils.AddTextInsideLayer(parentLayer, canvas, "Parent layer text", 50, 750); + PdfLayerTestUtils.AddTextInsideLayer(layer1, canvas, "layer 1 text", 100, 700); + PdfLayerTestUtils.AddTextInsideLayer(layer2, canvas, "layer 2 text", 100, 650); + PdfLayerTestUtils.AddTextInsideLayer(nestedLayer, canvas, "Nested layer text", 150, 600); + canvas.Release(); + pdfDoc.Close(); + PdfLayerTestUtils.CompareLayers(outPdf, cmpPdf); + } + + [NUnit.Framework.Test] + public virtual void DuplicatedNestedLayersTest() { + String outPdf = destinationFolder + "duplicatedNestedLayers.pdf"; + String cmpPdf = sourceFolder + "cmp_duplicatedNestedLayers.pdf"; + PdfDocument pdfDoc = new PdfDocument(CompareTool.CreateTestPdfWriter(outPdf)); + PdfFont font = PdfFontFactory.CreateFont(); + PdfLayer parentLayer = new PdfLayer("Parent layer", pdfDoc); + PdfLayer nestedLayer1 = new PdfLayer("Nested layer", pdfDoc); + parentLayer.AddChild(nestedLayer1); + parentLayer.AddChild(nestedLayer1); + PdfCanvas canvas = new PdfCanvas(pdfDoc.AddNewPage()); + canvas.SetFontAndSize(font, 12); + PdfLayerTestUtils.AddTextInsideLayer(parentLayer, canvas, "Parent layer text", 50, 750); + PdfLayerTestUtils.AddTextInsideLayer(nestedLayer1, canvas, "Nested layer text", 100, 700); + canvas.Release(); + pdfDoc.Close(); + PdfLayerTestUtils.CompareLayers(outPdf, cmpPdf); } } } diff --git a/itext.tests/itext.kernel.tests/itext/kernel/pdf/layer/PdfOCPropertiesUnitTest.cs b/itext.tests/itext.kernel.tests/itext/kernel/pdf/layer/PdfOCPropertiesUnitTest.cs index f2a257799f..7c9fc229fc 100644 --- a/itext.tests/itext.kernel.tests/itext/kernel/pdf/layer/PdfOCPropertiesUnitTest.cs +++ b/itext.tests/itext.kernel.tests/itext/kernel/pdf/layer/PdfOCPropertiesUnitTest.cs @@ -20,90 +20,226 @@ 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 System.Collections.Generic; using System.IO; -using iText.Commons.Utils; using iText.IO.Source; -using iText.Kernel.Exceptions; using iText.Kernel.Pdf; namespace iText.Kernel.Pdf.Layer { [NUnit.Framework.Category("UnitTest")] public class PdfOCPropertiesUnitTest { - //TODO DEVSIX-8490 remove this test when implemented [NUnit.Framework.Test] - public virtual void RemoveOrderDuplicatesTest() { + public virtual void OrderArrayOcgWithTwoParentsTest() { byte[] docBytes; using (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) { using (PdfDocument document = new PdfDocument(new PdfWriter(outputStream))) { - PdfDictionary ocgDic = new PdfDictionary(); - ocgDic.MakeIndirect(document); + PdfDictionary parentOcg1 = new PdfDictionary(); + parentOcg1.Put(PdfName.Name, new PdfString("Parent1")); + parentOcg1.Put(PdfName.Type, PdfName.OCG); + parentOcg1.MakeIndirect(document); PdfArray orderArray = new PdfArray(); - for (int i = 0; i < 3; i++) { - orderArray.Add(ocgDic); - } - PdfDictionary ocgDic2 = new PdfDictionary(); - ocgDic.MakeIndirect(document); - for (int i = 0; i < 3; i++) { - PdfArray layerArray = new PdfArray(); - layerArray.Add(new PdfString("layerName" + i)); - layerArray.Add(ocgDic2); - orderArray.Add(layerArray); - } + orderArray.Add(parentOcg1); + PdfDictionary childOcg = new PdfDictionary(); + childOcg.Put(PdfName.Name, new PdfString("child")); + childOcg.Put(PdfName.Type, PdfName.OCG); + childOcg.MakeIndirect(document); + PdfArray childArray = new PdfArray(); + childArray.Add(childOcg); + orderArray.Add(childArray); + PdfDictionary parentOcg2 = new PdfDictionary(); + parentOcg2.Put(PdfName.Name, new PdfString("Parent2")); + parentOcg2.Put(PdfName.Type, PdfName.OCG); + parentOcg2.MakeIndirect(document); + orderArray.Add(parentOcg2); + orderArray.Add(new PdfArray(childArray)); PdfDictionary DDictionary = new PdfDictionary(); DDictionary.Put(PdfName.Order, orderArray); - PdfArray OCGsArray = new PdfArray(); - OCGsArray.Add(ocgDic); - OCGsArray.Add(ocgDic2); + PdfArray ocgArray = new PdfArray(); + ocgArray.Add(parentOcg1); + ocgArray.Add(parentOcg2); + ocgArray.Add(childOcg); PdfDictionary OCPropertiesDic = new PdfDictionary(); OCPropertiesDic.Put(PdfName.D, DDictionary); - OCPropertiesDic.Put(PdfName.OCGs, OCGsArray); + OCPropertiesDic.Put(PdfName.OCGs, ocgArray); + OCPropertiesDic.MakeIndirect(document); document.GetCatalog().GetPdfObject().Put(PdfName.OCProperties, OCPropertiesDic); - document.GetCatalog().GetOCProperties(false); } docBytes = outputStream.ToArray(); } using (PdfDocument docReopen = new PdfDocument(new PdfReader(new MemoryStream(docBytes)))) { - PdfArray resultArray = docReopen.GetCatalog().GetPdfObject().GetAsDictionary(PdfName.OCProperties).GetAsDictionary - (PdfName.D).GetAsArray(PdfName.Order); - NUnit.Framework.Assert.AreEqual(2, resultArray.Size()); + IList layers = docReopen.GetCatalog().GetOCProperties(false).GetLayers(); + NUnit.Framework.Assert.AreEqual(3, layers.Count); + NUnit.Framework.Assert.AreEqual(1, layers[0].GetChildren().Count); + NUnit.Framework.Assert.AreEqual(2, layers[1].GetParents().Count); + NUnit.Framework.Assert.AreEqual(1, layers[2].GetChildren().Count); } } - //TODO DEVSIX-8490 remove this test when implemented [NUnit.Framework.Test] - public virtual void RemoveOrderDuplicateHasChildTest() { + public virtual void OrderArrayOcgWithTwoTitleParentsTest() { + byte[] docBytes; using (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) { using (PdfDocument document = new PdfDocument(new PdfWriter(outputStream))) { - PdfDictionary ocgDic = new PdfDictionary(); - PdfDictionary ocgDicChild1 = new PdfDictionary(); - PdfDictionary ocgDicChild2 = new PdfDictionary(); - ocgDic.MakeIndirect(document); + PdfDictionary childOcg = new PdfDictionary(); + childOcg.Put(PdfName.Name, new PdfString("child")); + childOcg.Put(PdfName.Type, PdfName.OCG); + childOcg.MakeIndirect(document); + PdfArray childArray = new PdfArray(); + childArray.Add(childOcg); + PdfArray titleOcg1 = new PdfArray(); + titleOcg1.Add(new PdfString("parent title layer 1")); + titleOcg1.Add(childArray); PdfArray orderArray = new PdfArray(); - PdfArray childArray1 = new PdfArray(); - childArray1.Add(ocgDicChild1); - PdfArray childArray2 = new PdfArray(); - childArray2.Add(ocgDicChild2); - orderArray.Add(ocgDic); - orderArray.Add(childArray1); - orderArray.Add(ocgDic); - orderArray.Add(childArray2); + orderArray.Add(titleOcg1); + PdfArray titleOcg2 = new PdfArray(); + titleOcg2.Add(new PdfString("parent title 2")); + titleOcg2.Add(childArray); + orderArray.Add(titleOcg2); PdfDictionary DDictionary = new PdfDictionary(); DDictionary.Put(PdfName.Order, orderArray); - PdfArray OCGsArray = new PdfArray(); - OCGsArray.Add(ocgDic); - OCGsArray.Add(ocgDicChild1); - OCGsArray.Add(ocgDicChild2); - PdfDictionary OCPropertiesDic = new PdfDictionary(); - OCPropertiesDic.Put(PdfName.D, DDictionary); - OCPropertiesDic.Put(PdfName.OCGs, OCGsArray); - document.GetCatalog().GetPdfObject().Put(PdfName.OCProperties, OCPropertiesDic); - PdfIndirectReference @ref = ocgDic.GetIndirectReference(); - PdfCatalog catalog = document.GetCatalog(); - Exception e = NUnit.Framework.Assert.Catch(typeof(PdfException), () => catalog.GetOCProperties(false)); - NUnit.Framework.Assert.AreEqual(MessageFormatUtil.Format(KernelExceptionMessageConstant.UNABLE_TO_REMOVE_DUPLICATE_LAYER - , @ref.ToString()), e.Message); + PdfArray ocgArray = new PdfArray(); + ocgArray.Add(childOcg); + PdfDictionary ocPropertiesDic = new PdfDictionary(); + ocPropertiesDic.Put(PdfName.D, DDictionary); + ocPropertiesDic.Put(PdfName.OCGs, ocgArray); + ocPropertiesDic.MakeIndirect(document); + document.GetCatalog().GetPdfObject().Put(PdfName.OCProperties, ocPropertiesDic); } + docBytes = outputStream.ToArray(); + } + using (PdfDocument docReopen = new PdfDocument(new PdfReader(new MemoryStream(docBytes)), new PdfWriter(new + ByteArrayOutputStream()))) { + IList layers = docReopen.GetCatalog().GetOCProperties(false).GetLayers(); + NUnit.Framework.Assert.AreEqual(3, layers.Count); + NUnit.Framework.Assert.AreEqual(1, layers[0].GetChildren().Count); + NUnit.Framework.Assert.AreEqual(2, layers[1].GetParents().Count); + NUnit.Framework.Assert.AreEqual(1, layers[2].GetChildren().Count); + } + } + + [NUnit.Framework.Test] + public virtual void OrderArrayTitleOcgWithTwoParentsTest() { + byte[] docBytes; + using (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) { + using (PdfDocument document = new PdfDocument(new PdfWriter(outputStream))) { + PdfDictionary parentOcg1 = new PdfDictionary(); + parentOcg1.Put(PdfName.Name, new PdfString("Parent1")); + parentOcg1.Put(PdfName.Type, PdfName.OCG); + parentOcg1.MakeIndirect(document); + PdfArray orderArray = new PdfArray(); + orderArray.Add(parentOcg1); + PdfArray titleChildOcg = new PdfArray(); + titleChildOcg.Add(new PdfString("child title layer")); + PdfArray childArray = new PdfArray(); + childArray.Add(titleChildOcg); + orderArray.Add(childArray); + PdfDictionary parentOcg2 = new PdfDictionary(); + parentOcg2.Put(PdfName.Name, new PdfString("Parent2")); + parentOcg2.Put(PdfName.Type, PdfName.OCG); + parentOcg2.MakeIndirect(document); + orderArray.Add(parentOcg2); + orderArray.Add(new PdfArray(childArray)); + PdfDictionary DDictionary = new PdfDictionary(); + DDictionary.Put(PdfName.Order, orderArray); + PdfArray ocgArray = new PdfArray(); + ocgArray.Add(parentOcg1); + ocgArray.Add(parentOcg2); + PdfDictionary ocPropertiesDic = new PdfDictionary(); + ocPropertiesDic.Put(PdfName.D, DDictionary); + ocPropertiesDic.Put(PdfName.OCGs, ocgArray); + ocPropertiesDic.MakeIndirect(document); + document.GetCatalog().GetPdfObject().Put(PdfName.OCProperties, ocPropertiesDic); + } + docBytes = outputStream.ToArray(); + } + using (PdfDocument docReopen = new PdfDocument(new PdfReader(new MemoryStream(docBytes)), new PdfWriter(new + ByteArrayOutputStream()))) { + IList layers = docReopen.GetCatalog().GetOCProperties(false).GetLayers(); + NUnit.Framework.Assert.AreEqual(3, layers.Count); + NUnit.Framework.Assert.AreEqual(1, layers[0].GetChildren().Count); + NUnit.Framework.Assert.AreEqual(2, layers[1].GetParents().Count); + NUnit.Framework.Assert.AreEqual(1, layers[2].GetChildren().Count); + } + } + + [NUnit.Framework.Test] + public virtual void OrderArrayDuplicatedOcgTest() { + byte[] docBytes; + using (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) { + using (PdfDocument document = new PdfDocument(new PdfWriter(outputStream))) { + PdfDictionary ocg = new PdfDictionary(); + ocg.Put(PdfName.Name, new PdfString("ocg")); + ocg.Put(PdfName.Type, PdfName.OCG); + ocg.MakeIndirect(document); + PdfArray orderArray = new PdfArray(); + orderArray.Add(ocg); + orderArray.Add(ocg); + orderArray.Add(ocg); + PdfDictionary parentOcg = new PdfDictionary(); + parentOcg.Put(PdfName.Name, new PdfString("Parent")); + parentOcg.Put(PdfName.Type, PdfName.OCG); + parentOcg.MakeIndirect(document); + orderArray.Add(parentOcg); + orderArray.Add(new PdfArray(ocg)); + PdfDictionary DDictionary = new PdfDictionary(); + DDictionary.Put(PdfName.Order, orderArray); + PdfArray ocgArray = new PdfArray(); + ocgArray.Add(ocg); + ocgArray.Add(parentOcg); + PdfDictionary ocPropertiesDic = new PdfDictionary(); + ocPropertiesDic.Put(PdfName.D, DDictionary); + ocPropertiesDic.Put(PdfName.OCGs, ocgArray); + ocPropertiesDic.MakeIndirect(document); + document.GetCatalog().GetPdfObject().Put(PdfName.OCProperties, ocPropertiesDic); + } + docBytes = outputStream.ToArray(); + } + using (PdfDocument docReopen = new PdfDocument(new PdfReader(new MemoryStream(docBytes)), new PdfWriter(new + ByteArrayOutputStream()))) { + IList layers = docReopen.GetCatalog().GetOCProperties(false).GetLayers(); + NUnit.Framework.Assert.AreEqual(2, layers.Count); + NUnit.Framework.Assert.AreEqual(1, layers[0].GetParents().Count); + NUnit.Framework.Assert.AreEqual(1, layers[1].GetChildren().Count); + } + } + + [NUnit.Framework.Test] + public virtual void OrderArrayDuplicatedTitleOcgTest() { + byte[] docBytes; + using (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) { + using (PdfDocument document = new PdfDocument(new PdfWriter(outputStream))) { + PdfArray orderArray = new PdfArray(); + PdfArray titleOcg = new PdfArray(); + titleOcg.Add(new PdfString("title layer")); + orderArray.Add(titleOcg); + PdfDictionary parentOcg = new PdfDictionary(); + parentOcg.Put(PdfName.Name, new PdfString("Parent")); + parentOcg.Put(PdfName.Type, PdfName.OCG); + parentOcg.MakeIndirect(document); + orderArray.Add(parentOcg); + PdfArray nestedOcg = new PdfArray(); + nestedOcg.Add(titleOcg); + orderArray.Add(nestedOcg); + orderArray.Add(titleOcg); + PdfDictionary DDictionary = new PdfDictionary(); + DDictionary.Put(PdfName.Order, orderArray); + PdfArray ocgArray = new PdfArray(); + ocgArray.Add(parentOcg); + PdfDictionary ocPropertiesDic = new PdfDictionary(); + ocPropertiesDic.Put(PdfName.D, DDictionary); + ocPropertiesDic.Put(PdfName.OCGs, ocgArray); + ocPropertiesDic.MakeIndirect(document); + document.GetCatalog().GetPdfObject().Put(PdfName.OCProperties, ocPropertiesDic); + } + docBytes = outputStream.ToArray(); + } + using (PdfDocument docReopen = new PdfDocument(new PdfReader(new MemoryStream(docBytes)), new PdfWriter(new + ByteArrayOutputStream()))) { + IList layers = docReopen.GetCatalog().GetOCProperties(false).GetLayers(); + NUnit.Framework.Assert.AreEqual(2, layers.Count); + NUnit.Framework.Assert.AreEqual("title layer", layers[0].GetTitle()); + NUnit.Framework.Assert.AreEqual(1, layers[0].GetParents().Count); + NUnit.Framework.Assert.AreEqual(1, layers[1].GetChildren().Count); } } } diff --git a/itext.tests/itext.kernel.tests/resources/itext/kernel/pdf/PdfDocumentTest/cmp_removedDuplicateInOrderArray.pdf b/itext.tests/itext.kernel.tests/resources/itext/kernel/pdf/PdfDocumentTest/cmp_removedDuplicateInOrderArray.pdf deleted file mode 100644 index 602e3a4c81..0000000000 Binary files a/itext.tests/itext.kernel.tests/resources/itext/kernel/pdf/PdfDocumentTest/cmp_removedDuplicateInOrderArray.pdf and /dev/null differ diff --git a/itext.tests/itext.kernel.tests/resources/itext/kernel/pdf/PdfDocumentTest/cmp_removedNestedDuplicatesInOrderArray.pdf b/itext.tests/itext.kernel.tests/resources/itext/kernel/pdf/PdfDocumentTest/cmp_removedNestedDuplicatesInOrderArray.pdf deleted file mode 100644 index 9da2248dfa..0000000000 Binary files a/itext.tests/itext.kernel.tests/resources/itext/kernel/pdf/PdfDocumentTest/cmp_removedNestedDuplicatesInOrderArray.pdf and /dev/null differ diff --git a/itext.tests/itext.kernel.tests/resources/itext/kernel/pdf/PdfDocumentTest/removeDuplicatesInOrderArray.pdf b/itext.tests/itext.kernel.tests/resources/itext/kernel/pdf/PdfDocumentTest/ocgWithTwoParents.pdf similarity index 75% rename from itext.tests/itext.kernel.tests/resources/itext/kernel/pdf/PdfDocumentTest/removeDuplicatesInOrderArray.pdf rename to itext.tests/itext.kernel.tests/resources/itext/kernel/pdf/PdfDocumentTest/ocgWithTwoParents.pdf index 5afded545d..d5307b79dd 100644 Binary files a/itext.tests/itext.kernel.tests/resources/itext/kernel/pdf/PdfDocumentTest/removeDuplicatesInOrderArray.pdf and b/itext.tests/itext.kernel.tests/resources/itext/kernel/pdf/PdfDocumentTest/ocgWithTwoParents.pdf differ diff --git a/itext.tests/itext.kernel.tests/resources/itext/kernel/pdf/PdfDocumentTest/removeDuplicatesHasChildInOrderArray.pdf b/itext.tests/itext.kernel.tests/resources/itext/kernel/pdf/PdfDocumentTest/removeDuplicatesHasChildInOrderArray.pdf deleted file mode 100644 index 2fa10d0386..0000000000 Binary files a/itext.tests/itext.kernel.tests/resources/itext/kernel/pdf/PdfDocumentTest/removeDuplicatesHasChildInOrderArray.pdf and /dev/null differ diff --git a/itext.tests/itext.kernel.tests/resources/itext/kernel/pdf/PdfDocumentTest/removeNestedDuplicatesHasChildInOrderArray.pdf b/itext.tests/itext.kernel.tests/resources/itext/kernel/pdf/PdfDocumentTest/removeNestedDuplicatesHasChildInOrderArray.pdf deleted file mode 100644 index 754950dda9..0000000000 Binary files a/itext.tests/itext.kernel.tests/resources/itext/kernel/pdf/PdfDocumentTest/removeNestedDuplicatesHasChildInOrderArray.pdf and /dev/null differ diff --git a/itext.tests/itext.kernel.tests/resources/itext/kernel/pdf/PdfDocumentTest/removeNestedDuplicatesInOrderArray.pdf b/itext.tests/itext.kernel.tests/resources/itext/kernel/pdf/PdfDocumentTest/removeNestedDuplicatesInOrderArray.pdf deleted file mode 100644 index 1f43c432c2..0000000000 Binary files a/itext.tests/itext.kernel.tests/resources/itext/kernel/pdf/PdfDocumentTest/removeNestedDuplicatesInOrderArray.pdf and /dev/null differ diff --git a/itext.tests/itext.kernel.tests/resources/itext/kernel/pdf/layer/PdfLayerTest/cmp_duplicatedNestedLayers.pdf b/itext.tests/itext.kernel.tests/resources/itext/kernel/pdf/layer/PdfLayerTest/cmp_duplicatedNestedLayers.pdf new file mode 100644 index 0000000000..a47f384cd3 Binary files /dev/null and b/itext.tests/itext.kernel.tests/resources/itext/kernel/pdf/layer/PdfLayerTest/cmp_duplicatedNestedLayers.pdf differ diff --git a/itext.tests/itext.kernel.tests/resources/itext/kernel/pdf/layer/PdfLayerTest/cmp_nestedLayerTwoParents.pdf b/itext.tests/itext.kernel.tests/resources/itext/kernel/pdf/layer/PdfLayerTest/cmp_nestedLayerTwoParents.pdf new file mode 100644 index 0000000000..528c3b9e2f Binary files /dev/null and b/itext.tests/itext.kernel.tests/resources/itext/kernel/pdf/layer/PdfLayerTest/cmp_nestedLayerTwoParents.pdf differ diff --git a/itext.tests/itext.kernel.tests/resources/itext/kernel/pdf/layer/PdfLayerTest/cmp_nestedLayerTwoParentsWithOneParent.pdf b/itext.tests/itext.kernel.tests/resources/itext/kernel/pdf/layer/PdfLayerTest/cmp_nestedLayerTwoParentsWithOneParent.pdf new file mode 100644 index 0000000000..d90b760317 Binary files /dev/null and b/itext.tests/itext.kernel.tests/resources/itext/kernel/pdf/layer/PdfLayerTest/cmp_nestedLayerTwoParentsWithOneParent.pdf differ diff --git a/itext/itext.kernel/itext/kernel/exceptions/KernelExceptionMessageConstant.cs b/itext/itext.kernel/itext/kernel/exceptions/KernelExceptionMessageConstant.cs index b61ae47368..572efa886e 100644 --- a/itext/itext.kernel/itext/kernel/exceptions/KernelExceptionMessageConstant.cs +++ b/itext/itext.kernel/itext/kernel/exceptions/KernelExceptionMessageConstant.cs @@ -655,10 +655,10 @@ public const String WHEN_ADDING_OBJECT_REFERENCE_TO_THE_TAG_TREE_IT_MUST_BE_CONN public const String INVALID_OBJECT_STREAM_NUMBER = "Unable to read object {0} with object stream " + "number {1} and index {2} from object stream."; - //TODO DEVSIX-8490 remove this exception message when implemented + [Obsolete] public const String UNABLE_TO_ADD_SECOND_PARENT_LAYER = "Unable to add second parent layer to " + "{0} ocg layer"; - //TODO DEVSIX-8490 remove this exception message when implemented + [Obsolete] public const String UNABLE_TO_REMOVE_DUPLICATE_LAYER = "Unable to remove duplicated layer {0} " + "because it has child layers."; public const String TYPE_SHOULD_NOT_BE_NULL = "ClassArgument type should not be null"; diff --git a/itext/itext.kernel/itext/kernel/logs/KernelLogMessageConstant.cs b/itext/itext.kernel/itext/kernel/logs/KernelLogMessageConstant.cs index b5f35fe1c1..c9c54f6f7c 100644 --- a/itext/itext.kernel/itext/kernel/logs/KernelLogMessageConstant.cs +++ b/itext/itext.kernel/itext/kernel/logs/KernelLogMessageConstant.cs @@ -90,7 +90,7 @@ public sealed class KernelLogMessageConstant { public const String XOBJECT_STRUCT_PARENT_INDEX_MISSED_AND_RECREATED = "XObject has no StructParents index in its stream, so index is recreated"; - //TODO DEVSIX-8490 remove this log message when implemented + [Obsolete] public const String DUPLICATE_ENTRIES_IN_ORDER_ARRAY_REMOVED = "Duplicated entries in order array are " + "removed"; diff --git a/itext/itext.kernel/itext/kernel/pdf/canvas/PdfCanvas.cs b/itext/itext.kernel/itext/kernel/pdf/canvas/PdfCanvas.cs index 057d1e4272..fbc5fd86f7 100644 --- a/itext/itext.kernel/itext/kernel/pdf/canvas/PdfCanvas.cs +++ b/itext/itext.kernel/itext/kernel/pdf/canvas/PdfCanvas.cs @@ -1636,16 +1636,10 @@ public virtual iText.Kernel.Pdf.Canvas.PdfCanvas BeginLayer(IPdfOCG layer) { } else { if (layer is PdfLayer) { - int num = 0; PdfLayer la = (PdfLayer)layer; - while (la != null) { - if (la.GetTitle() == null) { - AddToPropertiesAndBeginLayer(la); - num++; - } - la = la.GetParent(); - } - layerDepth.Add(num); + ICollection layers = new HashSet(); + int depth = BeginLayerTree(la, layers); + layerDepth.Add(depth); } else { throw new NotSupportedException("Unsupported type for operand: layer"); @@ -2488,6 +2482,30 @@ private static bool IsIdentityMatrix(float a, float b, float c, float d, float e && Math.Abs(1 - d) < IDENTITY_MATRIX_EPS && Math.Abs(e) < IDENTITY_MATRIX_EPS && Math.Abs(f) < IDENTITY_MATRIX_EPS; } + /// This method is used to traverse parent tree and begin all layers in it. + /// + /// This method is used to traverse parent tree and begin all layers in it. + /// If layer was already begun during method call, it will not be processed again. + /// + private int BeginLayerTree(PdfLayer layer, ICollection layers) { + if (layer == null || layers.Contains(layer)) { + return 0; + } + layers.Add(layer); + int depth = 0; + if (layer.GetTitle() == null) { + AddToPropertiesAndBeginLayer(layer); + depth++; + } + IList parentLayers = layer.GetParents(); + if (parentLayers != null) { + foreach (PdfLayer parentLayer in parentLayers) { + depth += BeginLayerTree(parentLayer, layers); + } + } + return depth; + } + private enum CheckColorMode { NONE, FILL, diff --git a/itext/itext.kernel/itext/kernel/pdf/layer/PdfLayer.cs b/itext/itext.kernel/itext/kernel/pdf/layer/PdfLayer.cs index de5a67994a..45d2b8cbad 100644 --- a/itext/itext.kernel/itext/kernel/pdf/layer/PdfLayer.cs +++ b/itext/itext.kernel/itext/kernel/pdf/layer/PdfLayer.cs @@ -24,7 +24,6 @@ You should have received a copy of the GNU Affero General Public License using System.Collections.Generic; using iText.Commons.Utils; using iText.IO.Font; -using iText.Kernel.Exceptions; using iText.Kernel.Pdf; namespace iText.Kernel.Pdf.Layer { @@ -53,10 +52,18 @@ public class PdfLayer : PdfObjectWrapper, IPdfOCG { protected internal bool locked = false; + [Obsolete] protected internal iText.Kernel.Pdf.Layer.PdfLayer parent; + // After removing deprecated parent rename to parents + protected internal ICollection parentLayers; + + [Obsolete] protected internal IList children; + // After removing deprecated children rename to children + protected internal ICollection childLayers; + /// Creates a new layer by existing dictionary, which must be an indirect object. /// the layer dictionary, must have an indirect reference. public PdfLayer(PdfDictionary layerDictionary) @@ -115,23 +122,26 @@ public static void AddOCGRadioGroup(PdfDocument document, IListAdds a child layer. Nested layers can only have one parent. /// the child layer public virtual void AddChild(iText.Kernel.Pdf.Layer.PdfLayer childLayer) { - //TODO DEVSIX-8490 implement multiple parent support - if (childLayer.parent != null) { - PdfIndirectReference @ref = childLayer.GetIndirectReference(); - throw new PdfException(MessageFormatUtil.Format(KernelExceptionMessageConstant.UNABLE_TO_ADD_SECOND_PARENT_LAYER - , @ref.ToString())); + if (childLayer.parentLayers == null) { + childLayer.parentLayers = new LinkedHashSet(); } - childLayer.parent = this; - if (children == null) { - children = new List(); + childLayer.parentLayers.Add(this); + if (childLayers == null) { + childLayers = new LinkedHashSet(); } - children.Add(childLayer); + childLayers.Add(childLayer); } - /// Gets the parent of this layer, be it a title layer, or a usual one. - /// the parent of the layer, or null if it has no parent + /// Gets the first parent of this layer, be it a title layer, or a usual one. + /// the first parent of the layer, or null if it has no parent public virtual iText.Kernel.Pdf.Layer.PdfLayer GetParent() { - return parent; + return parentLayers == null ? null : new List(parentLayers)[0]; + } + + /// Gets all parents of this layer. + /// list of parents of the layer, or null if it has no parent + public virtual IList GetParents() { + return parentLayers == null ? null : new List(parentLayers); } /// Sets the name of the layer to be displayed in the Layers panel. @@ -439,7 +449,7 @@ public virtual String GetTitle() { /// /// the list of the current child layers, null if the layer has no children. public virtual IList GetChildren() { - return children == null ? null : new List(children); + return childLayers == null ? null : new List(childLayers); } protected internal override bool IsWrappedObjectMustBeIndirect() { diff --git a/itext/itext.kernel/itext/kernel/pdf/layer/PdfOCProperties.cs b/itext/itext.kernel/itext/kernel/pdf/layer/PdfOCProperties.cs index f61c976b11..5b455506dc 100644 --- a/itext/itext.kernel/itext/kernel/pdf/layer/PdfOCProperties.cs +++ b/itext/itext.kernel/itext/kernel/pdf/layer/PdfOCProperties.cs @@ -26,7 +26,6 @@ You should have received a copy of the GNU Affero General Public License using iText.Commons; using iText.Commons.Utils; using iText.IO.Font; -using iText.Kernel.Exceptions; using iText.Kernel.Logs; using iText.Kernel.Pdf; @@ -52,12 +51,6 @@ public class PdfOCProperties : PdfObjectWrapper { private IList layers = new List(); - //TODO DEVSIX-8490 remove this field when implemented - private ICollection references; - - //TODO DEVSIX-8490 remove this field when implemented - private bool isDuplicateRemoved; - /// Creates a new PdfOCProperties instance. /// the document the optional content belongs to public PdfOCProperties(PdfDocument document) @@ -165,7 +158,7 @@ public virtual PdfObject FillDictionary(bool removeNonDocumentOcgs) { IList docOrder = new List(layers); for (int i = 0; i < docOrder.Count; i++) { PdfLayer layer = docOrder[i]; - if (layer.GetParent() != null) { + if (layer.GetParents() != null) { docOrder.Remove(layer); i--; } @@ -413,14 +406,9 @@ private void ReadLayersFromDictionary() { } PdfArray orderArray = d.GetAsArray(PdfName.Order); if (orderArray != null && !orderArray.IsEmpty()) { - references = new HashSet(); - isDuplicateRemoved = false; - ReadOrderFromDictionary(null, orderArray, layerMap); - //TODO DEVSIX-8490 remove this check when implemented - if (isDuplicateRemoved) { - ILogger logger = ITextLogManager.GetLogger(typeof(iText.Kernel.Pdf.Layer.PdfOCProperties)); - logger.LogWarning(KernelLogMessageConstant.DUPLICATE_ENTRIES_IN_ORDER_ARRAY_REMOVED); - } + ICollection layerReferences = new HashSet(); + IDictionary titleLayers = new Dictionary(); + ReadOrderFromDictionary(null, orderArray, layerMap, layerReferences, titleLayers); } } // Add the layers which should not be displayed on the panel to the order list @@ -433,7 +421,8 @@ private void ReadLayersFromDictionary() { /// Reads the /Order in the /D entry and initialized the parent-child hierarchy. private void ReadOrderFromDictionary(PdfLayer parent, PdfArray orderArray, IDictionary layerMap) { + , PdfLayer> layerMap, ICollection layerReferences, IDictionary titleLayers) { for (int i = 0; i < orderArray.Size(); i++) { PdfObject item = orderArray.Get(i); if (item.GetObjectType() == PdfObject.DICTIONARY) { @@ -441,33 +430,19 @@ private void ReadOrderFromDictionary(PdfLayer parent, PdfArray orderArray, IDict if (layer == null) { continue; } - //TODO DEVSIX-8490 remove this check and it statement when implemented - if (references.Contains(layer.GetIndirectReference())) { - //We want to check if this duplicate layer has childLayers, if it has - throw an exception, - // else just don't add this layer. - if (i + 1 < orderArray.Size() && orderArray.Get(i + 1).GetObjectType() == PdfObject.ARRAY) { - PdfArray nextArray = orderArray.GetAsArray(i + 1); - if (nextArray.Size() > 0 && nextArray.Get(0).GetObjectType() != PdfObject.STRING) { - PdfIndirectReference @ref = layer.GetIndirectReference(); - throw new PdfException(MessageFormatUtil.Format(KernelExceptionMessageConstant.UNABLE_TO_REMOVE_DUPLICATE_LAYER - , @ref.ToString())); - } - } - isDuplicateRemoved = true; - } - else { - references.Add(layer.GetIndirectReference()); + if (!layerReferences.Contains(layer.GetIndirectReference())) { + layerReferences.Add(layer.GetIndirectReference()); layers.Add(layer); layer.onPanel = true; - if (parent != null) { - parent.AddChild(layer); - } - if (i + 1 < orderArray.Size() && orderArray.Get(i + 1).GetObjectType() == PdfObject.ARRAY) { - PdfArray nextArray = orderArray.GetAsArray(i + 1); - if (nextArray.Size() > 0 && nextArray.Get(0).GetObjectType() != PdfObject.STRING) { - ReadOrderFromDictionary(layer, orderArray.GetAsArray(i + 1), layerMap); - i++; - } + } + if (parent != null) { + parent.AddChild(layer); + } + if (i + 1 < orderArray.Size() && orderArray.Get(i + 1).GetObjectType() == PdfObject.ARRAY) { + PdfArray nextArray = orderArray.GetAsArray(i + 1); + if (nextArray.Size() > 0 && nextArray.Get(0).GetObjectType() != PdfObject.STRING) { + ReadOrderFromDictionary(layer, orderArray.GetAsArray(i + 1), layerMap, layerReferences, titleLayers); + i++; } } } @@ -479,16 +454,22 @@ private void ReadOrderFromDictionary(PdfLayer parent, PdfArray orderArray, IDict } PdfObject firstObj = subArray.Get(0); if (firstObj.GetObjectType() == PdfObject.STRING) { - PdfLayer titleLayer = PdfLayer.CreateTitleSilent(((PdfString)firstObj).ToUnicodeString(), GetDocument()); - titleLayer.onPanel = true; - layers.Add(titleLayer); + PdfString title = (PdfString)firstObj; + PdfLayer titleLayer = titleLayers.Get(title); + if (titleLayer == null) { + titleLayer = PdfLayer.CreateTitleSilent(title.ToUnicodeString(), GetDocument()); + titleLayer.onPanel = true; + layers.Add(titleLayer); + titleLayers.Put(title, titleLayer); + } if (parent != null) { parent.AddChild(titleLayer); } - ReadOrderFromDictionary(titleLayer, new PdfArray(subArray.SubList(1, subArray.Size())), layerMap); + ReadOrderFromDictionary(titleLayer, new PdfArray(subArray.SubList(1, subArray.Size())), layerMap, layerReferences + , titleLayers); } else { - ReadOrderFromDictionary(parent, subArray, layerMap); + ReadOrderFromDictionary(parent, subArray, layerMap, layerReferences, titleLayers); } } } diff --git a/port-hash b/port-hash index 54fa537fa1..1c918581c7 100644 --- a/port-hash +++ b/port-hash @@ -1 +1 @@ -028c9c8e959e6073cf53bfa6932a6ef882d4b82f +a390afa1f077eb736e61e6d66d74a7f35354e0e4