logo
Welcome Guest! To enable all features please Login or Register.

Notification

Icon
Error

Options
Go to last post Go to first unread
Bazi  
#1 Posted : Friday, September 20, 2019 3:51:06 AM(UTC)
Bazi

Rank: Member

Groups: Registered
Joined: 9/19/2019(UTC)
Posts: 16
Germany
Location: Landshut

Thanks: 1 times
Hi,
With my program, I read PDF files as a background in the PdfViewer and draw graphic elements about it.
At the end I would like to save my work in the read in PDF.
For this I would like to create my own layer (optional content group), and save the shapes I have drawn in it.
How can I create these layers and write lines, rectangles etc. in these new layers?

Christian
Paul Rayman  
#2 Posted : Wednesday, September 25, 2019 6:20:19 AM(UTC)
Paul Rayman

Rank: Administration

Groups: Administrators
Joined: 1/5/2016(UTC)
Posts: 840

Thanks: 2 times
Was thanked: 103 time(s) in 101 post(s)
Hi,

Version 4.17.2704 has just been released
https://forum.patagames....n-Sep--25--2019#post1790

In this version you can write the following:
Code:

private static void OptionalContent()
{
    using (var doc = PdfDocument.CreateNew())
    {
        var list = PdfIndirectList.FromPdfDocument(doc);
        var page = doc.Pages.InsertPageAt(0, 500, 900);

        //Creating optional content groups (ocg)
        var ocg1 = PdfTypeDictionary.Create();
        ocg1["Type"] = PdfTypeName.Create("OCG");
        ocg1["Name"] = PdfTypeString.Create("Group 1");

        var ocg2 = PdfTypeDictionary.Create();
        ocg2["Type"] = PdfTypeName.Create("OCG");
        ocg2["Name"] = PdfTypeString.Create("Group 2");

        //Add optional content gropus to the list of indirect objects
        list.Add(ocg1); 
        list.Add(ocg2);

        //Creating the default viewing optional content configuration dictionary
        var defView = PdfTypeDictionary.Create();
        defView["Order"] = PdfTypeArray.Create(); //An array specifying the recommended order for presentation of optional content groups in a user interface. 
        defView["Order"].As<PdfTypeArray>().AddIndirect(list, ocg2);
        defView["Order"].As<PdfTypeArray>().AddIndirect(list, ocg1);
        defView["OFF"] = PdfTypeArray.Create(); //An array of optional content groups whose state should be set to OFF
        defView["OFF"].As<PdfTypeArray>().AddIndirect(list, ocg1);

        //Creating document's optional content properties dictionary;
        doc.Root["OCProperties"] = PdfTypeDictionary.Create();
        doc.Root["OCProperties"].As<PdfTypeDictionary>()["OCGs"] = PdfTypeArray.Create();
        doc.Root["OCProperties"].As<PdfTypeDictionary>()["OCGs"].As<PdfTypeArray>().AddIndirect(list, ocg1);
        doc.Root["OCProperties"].As<PdfTypeDictionary>()["OCGs"].As<PdfTypeArray>().AddIndirect(list, ocg2);
        doc.Root["OCProperties"].As<PdfTypeDictionary>()["D"] = defView;
                               

        //Creating text objects
        var textObj1 = PdfTextObject.Create("Optional text 1", 40, 50, PdfFont.CreateStock(doc, FontStockNames.Arial), 40);
        var textObj2 = PdfTextObject.Create("Optional text 2", 40, 90, PdfFont.CreateStock(doc, FontStockNames.Arial), 40);
        var textObj3 = PdfTextObject.Create("Optional text 3", 40, 120, PdfFont.CreateStock(doc, FontStockNames.Arial), 40);

        //Mark page objects as optional content
        textObj1.MarkedContent.Add(new PdfMarkedContent("OC", false, PropertyListTypes.PropertiesDict, ocg1));
        textObj2.MarkedContent.Add(new PdfMarkedContent("OC", false, PropertyListTypes.PropertiesDict, ocg1));
        textObj3.MarkedContent.Add(new PdfMarkedContent("OC", false, PropertyListTypes.PropertiesDict, ocg2));


        //Add page(text) obhects to page
        page.PageObjects.Add(textObj1);
        page.PageObjects.Add(textObj2);
        page.PageObjects.Add(textObj3);
        page.GenerateContent();

        doc.Save(@"e:\18\optional.pdf", SaveFlags.NoIncremental);
    }

}


More details about dictionary entries can be found int the PDF specification
https://www.adobe.com/co...ve/pdf_reference_1-7.pdf

On a page 364 (4.10 Optional Content)

Edited by user Wednesday, September 25, 2019 6:20:57 AM(UTC)  | Reason: Not specified

thanks 1 user thanked Paul Rayman for this useful post.
Bazi on 9/30/2019(UTC)
Bazi  
#3 Posted : Monday, September 30, 2019 10:12:47 PM(UTC)
Bazi

Rank: Member

Groups: Registered
Joined: 9/19/2019(UTC)
Posts: 16
Germany
Location: Landshut

Thanks: 1 times
Fantastic, thanks for the answer.
Bazi  
#4 Posted : Friday, October 4, 2019 12:39:44 PM(UTC)
Bazi

Rank: Member

Groups: Registered
Joined: 9/19/2019(UTC)
Posts: 16
Germany
Location: Landshut

Thanks: 1 times
I was too optimistic.
It works great on a new file, but changing an existing file takes too long.
How can I bypass the Page.GenerateContent?
I do not change the existing data, so it would not have to generate it again.
Paul Rayman  
#5 Posted : Saturday, October 5, 2019 9:23:52 PM(UTC)
Paul Rayman

Rank: Administration

Groups: Administrators
Joined: 1/5/2016(UTC)
Posts: 840

Thanks: 2 times
Was thanked: 103 time(s) in 101 post(s)
if you only add new objects, then you can try solution described in this post (solution #3)
https://forum.patagames....Content-is-SLOW#post1667

with remarks in post #8 in the same thread..
Bazi  
#6 Posted : Sunday, October 6, 2019 3:07:12 PM(UTC)
Bazi

Rank: Member

Groups: Registered
Joined: 9/19/2019(UTC)
Posts: 16
Germany
Location: Landshut

Thanks: 1 times
I am doing something wrong.
I am getting an error (Fatal Error, Number 1002)
b = Patagames.Pdf.Pdfium.FPDF_GenerateContentToStream (doc.Handle, ocg2.Handle, stream.Handle, page.Dictionary ("Resources"). Handle)
An attempt was made to read in the protected memory.

Code:
private void OptionalContent1()
{
    string FileName = "";
    using (OpenFileDialog ofd = new OpenFileDialog())
    {
        {
            var withBlock = ofd;
            withBlock.Title = "Datei öffnen";
            withBlock.Filter = "Portable Document Format (PDF) | *.pdf";
            withBlock.Multiselect = false;
            if (withBlock.ShowDialog == Windows.Forms.DialogResult.OK)
                FileName = withBlock.FileName;
        }
    }
    if (FileName.Length == 0 || !System.IO.File.Exists(FileName))
        return;

    using (var doc = Patagames.Pdf.Net.PdfDocument.Load(FileName))
    {
        var page = doc.Pages(0);
        var contentsArray = ConvertContentsToArray(page);

        var ocg1 = Patagames.Pdf.Net.BasicTypes.PdfTypeDictionary.Create();
        ocg1("Type") = Patagames.Pdf.Net.BasicTypes.PdfTypeName.Create("OCG");
        ocg1("Name") = Patagames.Pdf.Net.BasicTypes.PdfTypeString.Create("Group 1");
        var ocg2 = Patagames.Pdf.Net.BasicTypes.PdfTypeDictionary.Create();
        ocg2("Type") = Patagames.Pdf.Net.BasicTypes.PdfTypeName.Create("OCG");
        ocg2("Name") = Patagames.Pdf.Net.BasicTypes.PdfTypeString.Create("Group 2");

        var textObj1 = Patagames.Pdf.Net.PdfTextObject.Create("Optional text 1", 40, 50, Patagames.Pdf.Net.PdfFont.CreateStock(doc, Patagames.Pdf.Enums.FontStockNames.Arial), 40);
        var textObj2 = Patagames.Pdf.Net.PdfTextObject.Create("Optional text 2", 40, 90, Patagames.Pdf.Net.PdfFont.CreateStock(doc, Patagames.Pdf.Enums.FontStockNames.Arial), 40);
        var textObj3 = Patagames.Pdf.Net.PdfTextObject.Create("Optional text 3", 40, 120, Patagames.Pdf.Net.PdfFont.CreateStock(doc, Patagames.Pdf.Enums.FontStockNames.Arial), 40);

        textObj1.MarkedContent.Add(new Patagames.Pdf.Net.PdfMarkedContent("OC", false, Patagames.Pdf.Enums.PropertyListTypes.PropertiesDict, ocg1));
        textObj2.MarkedContent.Add(new Patagames.Pdf.Net.PdfMarkedContent("OC", false, Patagames.Pdf.Enums.PropertyListTypes.PropertiesDict, ocg1));
        textObj3.MarkedContent.Add(new Patagames.Pdf.Net.PdfMarkedContent("OC", false, Patagames.Pdf.Enums.PropertyListTypes.PropertiesDict, ocg2));

        var lineObj1 = InsertLine(new PointF(10, 10), new PointF(100, 100), Patagames.Pdf.FS_COLOR.Blue);
        lineObj1.MarkedContent.Add(new Patagames.Pdf.Net.PdfMarkedContent("OC", false, Patagames.Pdf.Enums.PropertyListTypes.PropertiesDict, ocg2));

        Patagames.Pdf.Net.PdfPathObject pathObject = Patagames.Pdf.Net.PdfPathObject.Create(Patagames.Pdf.Enums.FillModes.Alternate, false);
        var rectObj = InsertRect(pathObject, new PointF(40, 150), new PointF(100, 200), Patagames.Pdf.FS_COLOR.RosyBrown);
        rectObj.MarkedContent.Add(new Patagames.Pdf.Net.PdfMarkedContent("OC", false, Patagames.Pdf.Enums.PropertyListTypes.PropertiesDict, ocg2));

        var list = Patagames.Pdf.Net.BasicTypes.PdfIndirectList.FromPdfDocument(doc);
        var stream = Patagames.Pdf.Net.BasicTypes.PdfTypeStream.Create;
        list.Add(stream);
        if (!page.Dictionary.ContainsKey("Resources"))
            page.Dictionary("Resources") = Patagames.Pdf.Net.BasicTypes.PdfTypeDictionary.Create();
        bool b = Patagames.Pdf.Pdfium.FPDF_GenerateContentToStream(doc.Handle, ocg1.Handle, stream.Handle, page.Dictionary("Resources").Handle);
        b = Patagames.Pdf.Pdfium.FPDF_GenerateContentToStream(doc.Handle, ocg2.Handle, stream.Handle, page.Dictionary("Resources").Handle);
        b = Patagames.Pdf.Pdfium.FPDF_GenerateContentToStream(doc.Handle, textObj1.Handle, stream.Handle, page.Dictionary("Resources").Handle);
        b = Patagames.Pdf.Pdfium.FPDF_GenerateContentToStream(doc.Handle, textObj2.Handle, stream.Handle, page.Dictionary("Resources").Handle);
        b = Patagames.Pdf.Pdfium.FPDF_GenerateContentToStream(doc.Handle, textObj3.Handle, stream.Handle, page.Dictionary("Resources").Handle);
        contentsArray.AddIndirect(list, stream);

        using (SaveFileDialog sfd = new SaveFileDialog())
        {
            sfd.Title = "Testdatei speichern unter";
            sfd.Filter = "Portable Document Format (PDF) | *.pdf";
            if (sfd.ShowDialog == Windows.Forms.DialogResult.OK)
                doc.Save(sfd.FileName, Patagames.Pdf.Enums.SaveFlags.NoIncremental);
        }
    }
}


Christian

Edited by moderator Sunday, October 6, 2019 8:10:53 PM(UTC)  | Reason: Not specified

Paul Rayman  
#7 Posted : Sunday, October 6, 2019 8:14:57 PM(UTC)
Paul Rayman

Rank: Administration

Groups: Administrators
Joined: 1/5/2016(UTC)
Posts: 840

Thanks: 2 times
Was thanked: 103 time(s) in 101 post(s)
Originally Posted by: Bazi Go to Quoted Post

I am getting an error (Fatal Error, Number 1002)
b = Patagames.Pdf.Pdfium.FPDF_GenerateContentToStream


You are using this completely wrong.
You must add page objects to the collection of page objects, and then generate this collection to the stream.
Please study the example that I gave earlier.

You may use form.PageObjects or annot.NormalAppearance (normal appearance is PdfPageObjectsCollection too)

Edited by user Sunday, October 6, 2019 8:17:46 PM(UTC)  | Reason: Not specified

Bazi  
#8 Posted : Thursday, October 10, 2019 3:51:22 PM(UTC)
Bazi

Rank: Member

Groups: Registered
Joined: 9/19/2019(UTC)
Posts: 16
Germany
Location: Landshut

Thanks: 1 times
Thanks for the hint.
Now I am getting no more error message, but the objects I add are upside down.
The OCG´s I add do not appear.
Code:

private void OptionalContent1()
{
    string FileName = "";
    using (OpenFileDialog ofd = new OpenFileDialog())
    {
        {
            var withBlock = ofd;
            withBlock.Title = "Datei öffnen";
            withBlock.Filter = "Portable Document Format (PDF) | *.pdf";
            withBlock.Multiselect = false;
            if (withBlock.ShowDialog == Windows.Forms.DialogResult.OK)
                FileName = withBlock.FileName;
        }
    }
    if (FileName.Length == 0 || !System.IO.File.Exists(FileName))
        return;

    using (var doc = Patagames.Pdf.Net.PdfDocument.Load(FileName))
    {
        var page = doc.Pages(0);
        var contentsArray = ConvertContentsToArray(page);
        Patagames.Pdf.Net.BasicTypes.PdfTypeDictionary OCG = GetDictionary(doc.Root, "OCProperties", null/* TODO Change to default(_) if this is not a reference type */, false);
        var ocg1 = Patagames.Pdf.Net.BasicTypes.PdfTypeDictionary.Create();
        ocg1("Type") = Patagames.Pdf.Net.BasicTypes.PdfTypeName.Create("OCG");
        ocg1("Name") = Patagames.Pdf.Net.BasicTypes.PdfTypeString.Create("Group 1");
        var ocg2 = Patagames.Pdf.Net.BasicTypes.PdfTypeDictionary.Create();
        ocg2("Type") = Patagames.Pdf.Net.BasicTypes.PdfTypeName.Create("OCG");
        ocg2("Name") = Patagames.Pdf.Net.BasicTypes.PdfTypeString.Create("Group 2");
        OCG.Add("Group 1", (Patagames.Pdf.Net.BasicTypes.PdfTypeBase)ocg1);
        OCG.Add("Group 2", (Patagames.Pdf.Net.BasicTypes.PdfTypeBase)ocg2);
        var textObj1 = Patagames.Pdf.Net.PdfTextObject.Create("Optional text 1", 40, 50, Patagames.Pdf.Net.PdfFont.CreateStock(doc, Patagames.Pdf.Enums.FontStockNames.Arial), 40);
        var textObj2 = Patagames.Pdf.Net.PdfTextObject.Create("Optional text 2", 40, 90, Patagames.Pdf.Net.PdfFont.CreateStock(doc, Patagames.Pdf.Enums.FontStockNames.Arial), 40);
        var textObj3 = Patagames.Pdf.Net.PdfTextObject.Create("Optional text 3", 40, 120, Patagames.Pdf.Net.PdfFont.CreateStock(doc, Patagames.Pdf.Enums.FontStockNames.Arial), 40);

        textObj1.MarkedContent.Add(new Patagames.Pdf.Net.PdfMarkedContent("OC", false, Patagames.Pdf.Enums.PropertyListTypes.PropertiesDict, ocg1));
        textObj2.MarkedContent.Add(new Patagames.Pdf.Net.PdfMarkedContent("OC", false, Patagames.Pdf.Enums.PropertyListTypes.PropertiesDict, ocg1));
        textObj3.MarkedContent.Add(new Patagames.Pdf.Net.PdfMarkedContent("OC", false, Patagames.Pdf.Enums.PropertyListTypes.PropertiesDict, ocg2));

        var lineObj1 = InsertLine(new PointF(10, 10), new PointF(100, 100), Patagames.Pdf.FS_COLOR.Blue);
        lineObj1.MarkedContent.Add(new Patagames.Pdf.Net.PdfMarkedContent("OC", false, Patagames.Pdf.Enums.PropertyListTypes.PropertiesDict, ocg2));

        Patagames.Pdf.Net.PdfPathObject pathObject = Patagames.Pdf.Net.PdfPathObject.Create(Patagames.Pdf.Enums.FillModes.Alternate, false);
        var rectObj = InsertRect(pathObject, new PointF(40, 150), new PointF(100, 200), Patagames.Pdf.FS_COLOR.RosyBrown);
        rectObj.MarkedContent.Add(new Patagames.Pdf.Net.PdfMarkedContent("OC", false, Patagames.Pdf.Enums.PropertyListTypes.PropertiesDict, ocg2));

        using (var form = Patagames.Pdf.Net.PdfFormObject.Create(page))
        {
            form.PageObjects.Add(textObj1);
            form.PageObjects.Add(textObj2);
            form.PageObjects.Add(textObj3);
            form.PageObjects.Add(lineObj1);
            var stream = Patagames.Pdf.Net.BasicTypes.PdfTypeStream.Create;
            var list = Patagames.Pdf.Net.BasicTypes.PdfIndirectList.FromPdfDocument(doc);
            list.Add(stream);
            bool b = Patagames.Pdf.Pdfium.FPDF_GenerateContentToStream(doc.Handle, form.PageObjects.Handle, stream.Handle, IntPtr.Zero);
            contentsArray.AddIndirect(list, stream);
        }

        using (SaveFileDialog sfd = new SaveFileDialog())
        {
            sfd.Title = "Testdatei speichern unter";
            sfd.Filter = "Portable Document Format (PDF) | *.pdf";
            if (sfd.ShowDialog == Windows.Forms.DialogResult.OK)
                doc.Save(sfd.FileName, Patagames.Pdf.Enums.SaveFlags.NoIncremental);
        }
    }
}

Edited by moderator Friday, October 11, 2019 6:27:52 AM(UTC)  | Reason: Not specified

Paul Rayman  
#9 Posted : Friday, October 11, 2019 6:29:25 AM(UTC)
Paul Rayman

Rank: Administration

Groups: Administrators
Joined: 1/5/2016(UTC)
Posts: 840

Thanks: 2 times
Was thanked: 103 time(s) in 101 post(s)
I'm guessing you should pass page resource to the GenerateContentToStream method.
Like described here:
https://forum.patagames....Content-is-SLOW#post1674
Bazi  
#10 Posted : Friday, October 11, 2019 7:46:06 AM(UTC)
Bazi

Rank: Member

Groups: Registered
Joined: 9/19/2019(UTC)
Posts: 16
Germany
Location: Landshut

Thanks: 1 times
This will give me the error message again, in Line 13.

Code:

using (var form = Patagames.Pdf.Net.PdfFormObject.Create(page))
        {
            form.PageObjects.Add(textObj1);
            form.PageObjects.Add(textObj2);
            form.PageObjects.Add(textObj3);
            form.PageObjects.Add(lineObj1);
            var stream = Patagames.Pdf.Net.BasicTypes.PdfTypeStream.Create;
            var list = Patagames.Pdf.Net.BasicTypes.PdfIndirectList.FromPdfDocument(doc);
            list.Add(stream);
            if (!page.Dictionary.ContainsKey("Resources"))
                page.Dictionary("Resources") = Patagames.Pdf.Net.BasicTypes.PdfTypeDictionary.Create();
            bool b = Patagames.Pdf.Pdfium.FPDF_GenerateContentToStream(doc.Handle, form.PageObjects.Handle, stream.Handle, page.Dictionary("Resources").Handle);
            // Dim b As Boolean = Patagames.Pdf.Pdfium.FPDF_GenerateContentToStream(doc.Handle, form.PageObjects.Handle, stream.Handle, IntPtr.Zero)
            contentsArray.AddIndirect(list, stream);
        }


{"Fatal runtime error."}
" bei Patagames.Pdf.Pdfium.FPDF_GenerateContentToStream_native(IntPtr doc, IntPtr objList, IntPtr stream, IntPtr resDict, GenerateContentCallback callback, IntPtr userData) bei Patagames.Pdf.Pdfium.FPDF_GenerateContentToStream(IntPtr doc, IntPtr objList, IntPtr stream, IntPtr resDict, GenerateContentCallback callback, IntPtr userData)"

Edited by moderator Friday, October 11, 2019 8:31:52 AM(UTC)  | Reason: Not specified

Paul Rayman  
#11 Posted : Friday, October 11, 2019 9:17:58 AM(UTC)
Paul Rayman

Rank: Administration

Groups: Administrators
Joined: 1/5/2016(UTC)
Posts: 840

Thanks: 2 times
Was thanked: 103 time(s) in 101 post(s)
Resource dictionary should be obtained in this way
Code:
page.Dictionary["Resources"].As<PdfTypeDictionary>().Handle


I checked the following code. It seems to be working fine. Please use this one

Code:
private static void Main(string[] args)
{
    OptionalContent2();
}

private static void OptionalContent2()
{
    using (var doc = PdfDocument.Load(@"e:\19\sample.pdf"))
    {
        var list = PdfIndirectList.FromPdfDocument(doc);

        //Creating optional content groups
        var ocg1 = PdfTypeDictionary.Create();
        ocg1["Type"] = PdfTypeName.Create("OCG");
        ocg1["Name"] = PdfTypeString.Create("Group 1");

        var ocg2 = PdfTypeDictionary.Create();
        ocg2["Type"] = PdfTypeName.Create("OCG");
        ocg2["Name"] = PdfTypeString.Create("Group 2");

        //Add optional content gropus to the list of indirect objects
        list.Add(ocg1);
        list.Add(ocg2);

        //Creating the default viewing optional content configuration dictionary
        var defView = PdfTypeDictionary.Create();
        defView["Order"] = PdfTypeArray.Create();
        defView["Order"].As<PdfTypeArray>().AddIndirect(list, ocg2);
        defView["Order"].As<PdfTypeArray>().AddIndirect(list, ocg1);
        defView["OFF"] = PdfTypeArray.Create();
        defView["OFF"].As<PdfTypeArray>().AddIndirect(list, ocg1);

        //Creating document's optional content properties dictionary;
        doc.Root["OCProperties"] = PdfTypeDictionary.Create();
        doc.Root["OCProperties"].As<PdfTypeDictionary>()["OCGs"] = PdfTypeArray.Create();
        doc.Root["OCProperties"].As<PdfTypeDictionary>()["OCGs"].As<PdfTypeArray>().AddIndirect(list, ocg1);
        doc.Root["OCProperties"].As<PdfTypeDictionary>()["OCGs"].As<PdfTypeArray>().AddIndirect(list, ocg2);
        doc.Root["OCProperties"].As<PdfTypeDictionary>()["D"] = defView;


        //Creating text objects
        var textObj1 = PdfTextObject.Create("Optional text 1", 40, 50, PdfFont.CreateStock(doc, FontStockNames.Arial), 40);
        var textObj2 = PdfTextObject.Create("Optional text 2", 40, 90, PdfFont.CreateStock(doc, FontStockNames.Arial), 40);
        var textObj3 = PdfTextObject.Create("Optional text 3", 40, 120, PdfFont.CreateStock(doc, FontStockNames.Arial), 40);

        //Mark page objects as optional content
        textObj1.MarkedContent.Add(new PdfMarkedContent("OC", false, PropertyListTypes.PropertiesDict, ocg1));
        textObj2.MarkedContent.Add(new PdfMarkedContent("OC", false, PropertyListTypes.PropertiesDict, ocg1));
        textObj3.MarkedContent.Add(new PdfMarkedContent("OC", false, PropertyListTypes.PropertiesDict, ocg2));


        var page = doc.Pages[0];
        var contentsArray = ConvertContentsToArray(page);

        using (var tmpAnnot = new PdfTextAnnotation(page))
        {
            tmpAnnot.CreateEmptyAppearance(AppearanceStreamModes.Normal);
            //Add page(text) obhects to page
            tmpAnnot.NormalAppearance.Add(textObj1);
            tmpAnnot.NormalAppearance.Add(textObj2);
            tmpAnnot.NormalAppearance.Add(textObj3);
            //Create empty stream and add it to the list of indirect objects
            var stream = PdfTypeStream.Create();
            list.Add(stream);
            //Generate content of form object to that stream
            if (!page.Dictionary.ContainsKey("Resources"))
                page.Dictionary["Resources"] = PdfTypeDictionary.Create();
            bool b = Pdfium.FPDF_GenerateContentToStream(doc.Handle, tmpAnnot.NormalAppearance.Handle, stream.Handle, page.Dictionary["Resources"].As<PdfTypeDictionary>().Handle);

            //Add stream to the contentsArray
            contentsArray.AddIndirect(list, stream);
        }

        doc.Save(@"e:\19\optional.pdf", SaveFlags.NoIncremental);
        Process.Start(@"e:\19\optional.pdf");
    }

}

public static PdfTypeArray ConvertContentsToArray(PdfPage page)
{
    var pageDict = page.Dictionary;
    var list = PdfIndirectList.FromPdfDocument(page.Document);

    if (!pageDict.ContainsKey("Contents"))
    {
        var array = PdfTypeArray.Create();
        //Add array into list of indirect objects
        list.Add(array);
        //And set it as a contents of the page
        pageDict.SetIndirectAt("Contents", list, array);
        return array;
    }

    var contents = pageDict["Contents"];

    //check the original content whether it's an array
    if (contents is PdfTypeArray)
        return contents as PdfTypeArray;  //if contents is a array just return it
    else if (contents is PdfTypeIndirect)
    {
        if ((contents as PdfTypeIndirect).Direct is PdfTypeArray)
            return (contents as PdfTypeIndirect).Direct as PdfTypeArray; //if contents is a reference to array then return that array
        else if ((contents as PdfTypeIndirect).Direct is PdfTypeStream)
        {
            //if contents is a reference to a stream then create a new array and insert stream as a first element of array
            var array = PdfTypeArray.Create();
            array.AddIndirect(list, (contents as PdfTypeIndirect).Direct);
            //Add array into list of indirect objects
            list.Add(array);
            //And set it as a contents of the page
            pageDict.SetIndirectAt("Contents", list, array);
            return array;
        }
        else
            throw new Exception("Unexpected content type");
    }
    else if (contents is PdfTypeStream)
    {
        //if contents is a stream instead of reference to a stream then try to convert it to a reference then create a new array and insert stream as a first element of array
        list.Add(contents);
        var array = PdfTypeArray.Create();
        array.AddIndirect(list, contents);
        //Add array into list of indirect objects
        list.Add(array);
        //And set it as a contents of the page
        pageDict.SetIndirectAt("Contents", list, array);
        return array;
    }
    else
        throw new Exception("Unexpected content type");
}
Bazi  
#12 Posted : Saturday, October 12, 2019 1:34:00 PM(UTC)
Bazi

Rank: Member

Groups: Registered
Joined: 9/19/2019(UTC)
Posts: 16
Germany
Location: Landshut

Thanks: 1 times
Hello Paul,
thanks for your support.
This code also works without an error message, but the result does not match my expectations.
The 2 new OCGs are created, but the existing ones disappear.
The inserted texts are upside down and upper left on the output.
I try to attach 2 sample files, original and modified.

T21_GSP_5_BTX_W2_GR_O1_013_02_V.pdf (763kb) downloaded 1 time(s).
T21_GSP_5_BTX_W2_GR_O1_013_02_V-OCG.pdf (797kb) downloaded 0 time(s).

Edited by user Saturday, October 12, 2019 1:34:45 PM(UTC)  | Reason: Not specified

Paul Rayman  
#13 Posted : Sunday, October 13, 2019 1:50:55 AM(UTC)
Paul Rayman

Rank: Administration

Groups: Administrators
Joined: 1/5/2016(UTC)
Posts: 840

Thanks: 2 times
Was thanked: 103 time(s) in 101 post(s)
Please study the relevant section of the documentation that I cited in the first post. In order to qualitatively solve your task, you will need to understand the structure of dictionaries of the optional contents of an PDF document.

In this case, you are working with a document that already contains OCGs dictionary, therefore you do not need to create this one, but instead add your layers to existing dictionary.

those. in my example you need to replace the lines 34 and 35
with following
Code:
if(!doc.Root.ContainsKey("OCProperties"))
    doc.Root["OCProperties"] = PdfTypeDictionary.Create();
if(!doc.Root["OCProperties"].As<PdfTypeDictionary>().ContainsKey("OCGs"))
    doc.Root["OCProperties"].As<PdfTypeDictionary>()["OCGs"] = PdfTypeArray.Create();


And similarly, on line 38, you should not replace dictionary D with your own newly created dictionary, but you must modify the existing one
Code:
//doc.Root["OCProperties"].As<PdfTypeDictionary>()["D"] = defView;
doc.Root["OCProperties"].As<PdfTypeDictionary>()["D"].As<PdfTypeDictionary>()["Order"].As<PdfTypeArray>().AddIndirect(list, ocg1);
doc.Root["OCProperties"].As<PdfTypeDictionary>()["D"].As<PdfTypeDictionary>()["Order"].As<PdfTypeArray>().AddIndirect(list, ocg2);


Concerning the second part of the question ...

Since you are invading the space of someone else’s document and don’t want to regenerate the content, you should be aware that this document can impose various third-party effects on its content.

In this case, this document was generated in such a way that an uncompensated transformation matrix is ​​applied to its content. Therefore, the same matrix applies to your newly created content. In order for your content to display as you need, you must apply the same matrix to it.

Read more about transformation matrices here:
https://forum.patagames....Matrix-and-How-to-Use-It

In your document the matrix is
1 0 0 -1 0 2383.94 cm

So you can write the following for example
Code:

textObj1.Matrix = new FS_MATRIX(1, 0, 0, -1, 0, 2300);
textObj2.Matrix = new FS_MATRIX(1, 0, 0, -1, 0, 2200);
textObj3.Matrix = new FS_MATRIX(1, 0, 0, -1, 0, 2100);

Edited by user Sunday, October 13, 2019 1:52:02 AM(UTC)  | Reason: Not specified

Bazi  
#14 Posted : Sunday, October 13, 2019 9:17:27 AM(UTC)
Bazi

Rank: Member

Groups: Registered
Joined: 9/19/2019(UTC)
Posts: 16
Germany
Location: Landshut

Thanks: 1 times
I have adopted the changed code, but the existing OCGs are still not displayed.

Using the matrix, the text is no longer upside down, but the X coordinate appears to be set to 0.

Code:
    Private Shared Sub OptionalContent2()
        Dim FileName As String = ""
        Using ofd As New OpenFileDialog
            With ofd
                .Title = "Datei öffnen"
                .Filter = "Portable Document Format (PDF) | *.pdf"
                .Multiselect = False
                If .ShowDialog = Windows.Forms.DialogResult.OK Then FileName = .FileName
            End With
        End Using
        If FileName.Length = 0 OrElse Not IO.File.Exists(FileName) Then Return

        Using doc = Patagames.Pdf.Net.PdfDocument.Load(FileName)
            Dim page = doc.Pages(0)
            Dim pageContent As String = page.Dictionary("Contents").As(Of Patagames.Pdf.Net.BasicTypes.PdfTypeStream).DecodedText
            'Dim MediaBox = page.Dictionary("MediaBox").As(Of Patagames.Pdf.Net.BasicTypes.PdfTypeArray)()
            'Dim cmMatrices = ExtractMatrices(pageContent, "cm")
            'Dim tmMatrices = ExtractMatrices(pageContent, "Tm")


            Dim list = Patagames.Pdf.Net.BasicTypes.PdfIndirectList.FromPdfDocument(doc)
            Dim ocg1 = Patagames.Pdf.Net.BasicTypes.PdfTypeDictionary.Create()
            ocg1("Type") = Patagames.Pdf.Net.BasicTypes.PdfTypeName.Create("OCG")
            ocg1("Name") = Patagames.Pdf.Net.BasicTypes.PdfTypeString.Create("Group 1")
            Dim ocg2 = Patagames.Pdf.Net.BasicTypes.PdfTypeDictionary.Create()
            ocg2("Type") = Patagames.Pdf.Net.BasicTypes.PdfTypeName.Create("OCG")
            ocg2("Name") = Patagames.Pdf.Net.BasicTypes.PdfTypeString.Create("Group 2")
            list.Add(ocg1)
            list.Add(ocg2)

            Dim defView = Patagames.Pdf.Net.BasicTypes.PdfTypeDictionary.Create()
            defView("Order") = Patagames.Pdf.Net.BasicTypes.PdfTypeArray.Create()
            defView("Order").[As](Of Patagames.Pdf.Net.BasicTypes.PdfTypeArray)().AddIndirect(list, ocg2)
            defView("Order").[As](Of Patagames.Pdf.Net.BasicTypes.PdfTypeArray)().AddIndirect(list, ocg1)
            defView("OFF") = Patagames.Pdf.Net.BasicTypes.PdfTypeArray.Create()
            defView("OFF").[As](Of Patagames.Pdf.Net.BasicTypes.PdfTypeArray)().AddIndirect(list, ocg1)

            If Not doc.Root.ContainsKey("OCProperties") Then doc.Root("OCProperties") = Patagames.Pdf.Net.BasicTypes.PdfTypeDictionary.Create()
            If Not doc.Root("OCProperties").[As](Of Patagames.Pdf.Net.BasicTypes.PdfTypeDictionary).ContainsKey("OCGs") Then doc.Root("OCProperties").[As](Of Patagames.Pdf.Net.BasicTypes.PdfTypeDictionary)()("OCGs") = Patagames.Pdf.Net.BasicTypes.PdfTypeArray.Create()
            'doc.Root("OCProperties") = Patagames.Pdf.Net.BasicTypes.PdfTypeDictionary.Create()
            'doc.Root("OCProperties").[As](Of Patagames.Pdf.Net.BasicTypes.PdfTypeDictionary)()("OCGs") = Patagames.Pdf.Net.BasicTypes.PdfTypeArray.Create()
            doc.Root("OCProperties").[As](Of Patagames.Pdf.Net.BasicTypes.PdfTypeDictionary)()("OCGs").[As](Of Patagames.Pdf.Net.BasicTypes.PdfTypeArray)().AddIndirect(list, ocg1)
            doc.Root("OCProperties").[As](Of Patagames.Pdf.Net.BasicTypes.PdfTypeDictionary)()("OCGs").[As](Of Patagames.Pdf.Net.BasicTypes.PdfTypeArray)().AddIndirect(list, ocg2)
            doc.Root("OCProperties").[As](Of Patagames.Pdf.Net.BasicTypes.PdfTypeDictionary)()("D") = defView

            Dim textObj1 = Patagames.Pdf.Net.PdfTextObject.Create("Optional text 1", 40, 50, Patagames.Pdf.Net.PdfFont.CreateStock(doc, Patagames.Pdf.Enums.FontStockNames.Arial), 40)
            textObj1.Matrix = New Patagames.Pdf.FS_MATRIX(1, 0, 0, -1, 0, page.Height - 50)

            Dim textObj2 = Patagames.Pdf.Net.PdfTextObject.Create("Optional text 2", 40, 90, Patagames.Pdf.Net.PdfFont.CreateStock(doc, Patagames.Pdf.Enums.FontStockNames.Arial), 40)
            textObj2.Matrix = New Patagames.Pdf.FS_MATRIX(1, 0, 0, -1, 0, page.Height - 90)

            Dim textObj3 = Patagames.Pdf.Net.PdfTextObject.Create("Optional text 3", 100, 120, Patagames.Pdf.Net.PdfFont.CreateStock(doc, Patagames.Pdf.Enums.FontStockNames.Arial), 40)
            textObj3.Matrix = New Patagames.Pdf.FS_MATRIX(1, 0, 0, -1, 0, page.Height - 120)

            textObj1.MarkedContent.Add(New Patagames.Pdf.Net.PdfMarkedContent("OC", False, Patagames.Pdf.Enums.PropertyListTypes.PropertiesDict, ocg1))
            textObj2.MarkedContent.Add(New Patagames.Pdf.Net.PdfMarkedContent("OC", False, Patagames.Pdf.Enums.PropertyListTypes.PropertiesDict, ocg1))
            textObj3.MarkedContent.Add(New Patagames.Pdf.Net.PdfMarkedContent("OC", False, Patagames.Pdf.Enums.PropertyListTypes.PropertiesDict, ocg2))
            'Dim page = doc.Pages(0)
            Dim contentsArray = ConvertContentsToArray(page)

            Using tmpAnnot = New Patagames.Pdf.Net.Annotations.PdfTextAnnotation(page)
                tmpAnnot.CreateEmptyAppearance(Patagames.Pdf.Enums.AppearanceStreamModes.Normal)
                tmpAnnot.NormalAppearance.Add(textObj1)
                tmpAnnot.NormalAppearance.Add(textObj2)
                tmpAnnot.NormalAppearance.Add(textObj3)
                Dim stream = Patagames.Pdf.Net.BasicTypes.PdfTypeStream.Create()
                list.Add(stream)
                If Not page.Dictionary.ContainsKey("Resources") Then page.Dictionary("Resources") = Patagames.Pdf.Net.BasicTypes.PdfTypeDictionary.Create()
                Dim b As Boolean = Patagames.Pdf.Pdfium.FPDF_GenerateContentToStream(doc.Handle, tmpAnnot.NormalAppearance.Handle, stream.Handle, page.Dictionary("Resources").[As](Of Patagames.Pdf.Net.BasicTypes.PdfTypeDictionary)().Handle)
                contentsArray.AddIndirect(list, stream)
            End Using

            Using sfd As New SaveFileDialog
                sfd.Title = "Testdatei speichern unter"
                sfd.Filter = "Portable Document Format (PDF) | *.pdf"
                If sfd.ShowDialog = Windows.Forms.DialogResult.OK Then
                    doc.Save(sfd.FileName, Patagames.Pdf.Enums.SaveFlags.NoIncremental)
                    Process.Start(sfd.FileName)
                End If
            End Using

        End Using
    End Sub

Edited by moderator Monday, October 14, 2019 9:03:02 AM(UTC)  | Reason: Not specified

Paul Rayman  
#15 Posted : Monday, October 14, 2019 9:01:21 AM(UTC)
Paul Rayman

Rank: Administration

Groups: Administrators
Joined: 1/5/2016(UTC)
Posts: 840

Thanks: 2 times
Was thanked: 103 time(s) in 101 post(s)
I checked the code on your document before posting it.
Both the text position and the OCG layers work fine.

Please check your code carefully again.

Quote:
Using the matrix, the text is no longer upside down, but the X coordinate appears to be set to 0.


Because you set it to 0.
Please read about the matrices at the link I provided.
e and f - location.

Edited by user Monday, October 14, 2019 9:07:00 AM(UTC)  | Reason: Not specified

Bazi  
#16 Posted : Thursday, October 17, 2019 12:40:10 PM(UTC)
Bazi

Rank: Member

Groups: Registered
Joined: 9/19/2019(UTC)
Posts: 16
Germany
Location: Landshut

Thanks: 1 times
I found the mistake.
Now it's working.
Thanks for your help.
Bazi  
#17 Posted : Friday, October 18, 2019 2:34:33 AM(UTC)
Bazi

Rank: Member

Groups: Registered
Joined: 9/19/2019(UTC)
Posts: 16
Germany
Location: Landshut

Thanks: 1 times
Quote:
In this case, this document was generated in such a way that an uncompensated transformation matrix is ​​applied to its content.


Is this the first line in page.Dictionary("Contents").DecodedText ?
Paul Rayman  
#18 Posted : Tuesday, October 22, 2019 11:45:12 PM(UTC)
Paul Rayman

Rank: Administration

Groups: Administrators
Joined: 1/5/2016(UTC)
Posts: 840

Thanks: 2 times
Was thanked: 103 time(s) in 101 post(s)
Usually it is, but this is not the rule. Unfortunately, I cannot determine a formal rule suitable for the automatic processing of this situation.
Bazi  
#19 Posted : Wednesday, October 23, 2019 9:38:44 AM(UTC)
Bazi

Rank: Member

Groups: Registered
Joined: 9/19/2019(UTC)
Posts: 16
Germany
Location: Landshut

Thanks: 1 times
Thanks, the statement is enough for me.
Then I check if the first line starts numerically, if no I try it without matrix. This will apply to the majority of files.

Christian
Users browsing this topic
Forum Jump  
You cannot post new topics in this forum.
You cannot reply to topics in this forum.
You cannot delete your posts in this forum.
You cannot edit your posts in this forum.
You cannot create polls in this forum.
You cannot vote in polls in this forum.