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

Notification

Icon
Error

Options
Go to last post Go to first unread
darren  
#1 Posted : Monday, June 19, 2017 10:00:40 PM(UTC)
darren

Rank: Newbie

Groups: Registered
Joined: 6/16/2017(UTC)
Posts: 4
Australia

Thanks: 1 times
My understanding is that PDF files do not support "layers" in the same way that CAD files do, but they do support "optional content" which enables a similar result. I need to be able to select which PDF layers are displayed by the PdfViewer.

I have managed to read the layers from the PDF using the following code:

Code:
   PdfTypeDictionary root = pdfViewer1.Document.Root;
   PdfTypeDictionary oc_prop = root["OCProperties"] as PdfTypeDictionary;
   PdfTypeArray ocgs = oc_prop["OCGs"] as PdfTypeArray;
   foreach (PdfTypeBase ocg_indirect in ocgs)
   {
      PdfTypeBase ocg = (ocg_indirect as PdfTypeIndirect).Direct;
      PdfTypeString name = (ocg as PdfTypeDictionary)["Name"] as PdfTypeString;
      System.Diagnostics.Debug.WriteLine(name.UnicodeString);
   }



My question is how do I control which are visible?
Paul Rayman  
#2 Posted : Thursday, June 22, 2017 8:59:31 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)
Hi,
some quotes from PDF Reference ver. 1.7. page 365.
I hope it can help you

http://www.adobe.com/content/dam/Adobe/en/devnet/acrobat/pdfs/pdf_reference_1-7.pdf
Page
Quote:

Optional Content Membership Dictionaries

As mentioned above, content typically belongs to a single optional content group
and is visible when the group is ON and invisible when it is OFF. To express more
complex visibility policies, content should declare itself not to belong directly to
an optional content group but rather to an optional content membership dictionary, whose entries are shown in Table 4.49. (Section 4.10.2 describes how content declares its membership in a group or membership dictionary.)

TABLE 4.49 Entries in an optional content membership dictionary

Key: Type
Type: name
Value: (Required) The type of PDF object that this dictionary describes; must be OCMD for an optional content membership dictionary.

Key: OCGs
Type: dictionary or array
Name: (Optional) A dictionary or array of dictionaries specifying the optional content groups whose states determine the visibility of content controlled by this member ship dictionary.

Key: P
Type: name
Name: (Optional) A name specifying the visibility policy for content belonging to this membership dictionary. Valid values are:
    AllOn: visible only if all of the entries in OCGs are ON
  • AnyOn: visible if any of the entries in OCGs are ON
  • AnyOff: visible if any of the entries in OCGs are OFF
  • AllOff: visible only if all of the entries in OCGs are OFF
Default value: AnyOn

Key: VE
Type: array
Name: (Optional; PDF 1.6) An array specifying a visibility expression, used to compute visibility of content based on a set of optional content groups; see discussion below.




An optional content membership dictionary can express its visibility policy in two ways:

  • The P entry specifies a simple boolean expression indicating how the optional content groups specified by the OCGs entry determine the visibility of content controlled by the membership dictionary.
  • PDF 1.6 introduces the VE entry, which is a visibility expression that can specify an arbitrary boolean expression for computing the visibility of content from the states of optional content groups.


Note: Since the VE entry is more general, if it is present and supported by the PDF
consumer software, it should be used in preference to OCGs and P. However, for
compatibility purposes, PDF creators should use OCGs and P entries where possible.
When the use of VE is necessary to express the intended behavior, OCGs and P entries should also be provided to approximate the behavior in older consumer software.

A visibility expression is an array with the following characteristics:
  • ts first element is a name representing a boolean operator (And, Or, or Not)
  • Subsequent elements are either optional content groups or other visibility expressions.
  • If the first element is Not, it should have only one subsequent element. If the first element is And or Or, it may have one or more subsequent elements.
  • In evaluating a visibility expression, the ON state of an optional content group is
    equated to the boolean value true; OFF is equated to false.


Membership dictionaries are useful in cases such as these:
  • Some content may choose to be invisible when a group is ON and visible when it is OFF. In this case, the content would belong to a membership dictionary whose OCGs entry consists of a single optional content group and whose P entry is AnyOff or AllOff.

    Note: It is legal to have an OCGs entry consisting of a single group and a P entry that is AnyOn or AllOn. However, in this case it is preferable to use an optional content group directly because it uses fewer objects.
  • Some content may belong to more than one group and must specify its policy when the groups are in conflicting states. In this case, the content would belong to a membership dictionary whose OCGs entry consists of an array of optional content groups and whose P entry specifies the visibility policy, as illustrated in Example 4.32 below. (Example 4.33 shows the equivalent policy using visibility expressions.)

darren  
#3 Posted : Monday, June 26, 2017 3:37:36 AM(UTC)
darren

Rank: Newbie

Groups: Registered
Joined: 6/16/2017(UTC)
Posts: 4
Australia

Thanks: 1 times
Hi Paul,

thanks for directing me to the PDF Reference.

The document I am using as a test was generated by a CAD tool. It contains Optional Content Groups (OCG), but no Optional Content Membership Dictionaries (OCMD). I have opened it in Adobe Acrobat Reader DC and I can switch the layers off and on, and I need to work out how to do the same with PDFIUM.

In section 4.10.1 of the PDF Reference, it says

Quote:
A group is assigned a state, which is either ON or OFF. States are not themselves part of the PDF document but can be set programmatically or through the viewer user interface to change the visibility of content. When a document is first opened, the groups’ states are initialized based on the document’s default configuration dictionary...


The problem I have is that I have been unable to find how to programmatically set the OCG states to ON or OFF using PDFIUM. Is it possible to do this?
Paul Rayman  
#4 Posted : Monday, June 26, 2017 4:21:35 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)
could you please provide pdf document?
darren  
#5 Posted : Monday, June 26, 2017 9:16:47 PM(UTC)
darren

Rank: Newbie

Groups: Registered
Joined: 6/16/2017(UTC)
Posts: 4
Australia

Thanks: 1 times
I have tried many PDF files that contain layers, and they are all essentially the same.

Typical PDF files with layers can be found here(axf-layer-1.pdf) or here(Layers.pdf) or here(House_Plan_Final.pdf).

Edited by moderator Tuesday, June 27, 2017 9:38:01 PM(UTC)  | Reason: Not specified

Paul Rayman  
#6 Posted : Tuesday, June 27, 2017 9:58:13 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)
Please study the following code.
It hides all document optional contents.
Briefly, you should change the value in the View dictionary.

I have checked the code with documents were provided and it works fine.

Please Note. If the page with optional content is already displayed in the viewer, then it must be reloaded.
This can be done by calling the page.Dispose method and initiating the redrawing of the pdfViewer next. In this case, the disposed page will be automatically loaded.

Code:

public PdfTypeDictionary GetDictionary(PdfTypeDictionary parent, string entry, PdfIndirectList list = null, bool is_create = true)
{
    PdfTypeDictionary ret = null;
    if (!parent.ContainsKey(entry))
    {
        if(!is_create)
            throw new Exception(string.Format("The document does not have {0} entry", entry));

        ret = PdfTypeDictionary.Create();
        if (list != null)
        {
            list.Add(ret);
            parent.SetIndirectAt(entry, list, ret);
        }
        else
            parent.SetAt(entry, ret);
    }
    else if (parent[entry] is PdfTypeIndirect)
        ret = (parent[entry] as PdfTypeIndirect).Direct as PdfTypeDictionary;
    else if (parent[entry] is PdfTypeDictionary)
        ret = parent[entry] as PdfTypeDictionary;
    else
        throw new Exception(string.Format("'{0}' entry has unknown type", entry));

    return ret;
}

public Form1()
{
    InitializeComponent();
    PdfCommon.Initialize();

    pdfViewer1.LoadDocument(@"d:\10\axf-layer-1.pdf");
    //pdfViewer1.LoadDocument(@"d:\10\House_Plan_Final.pdf");
    //pdfViewer1.LoadDocument(@"d:\10\Layers.pdf");

    //The catalog dictionary for the PDF document contained in the file
    var root = pdfViewer1.Document.Root;

    //The document’s optional content properties dictionary (see Section 4.10.3,
    //“Configuring Optional Content”).
    //(Optional; PDF 1.5; required if a document contains optional content)
    var oc_prop = GetDictionary(root, "OCProperties", null, false);

    //dictionary or array of dictionaries specifying the optional content
    //groups whose states determine the visibility of content controlled by this membership dictionary.
    //Note: Null values or references to deleted objects are ignored. If this entry is not
    //present, is an empty array, or contains references only to null or deleted objects, the
    //membership dictionary has no effect on the visibility of any content.

    //It may be a dictionary not an array. Please check it for other documents. 
    //All provided documents contains an array in that entry.
    var ocgs = oc_prop["OCGs"] as PdfTypeArray;

    var list = PdfIndirectList.FromPdfDocument(pdfViewer1.Document);
    foreach (var item in ocgs)
    {
        var ocg = (item as PdfTypeIndirect).Direct as PdfTypeDictionary;

        //A usage dictionary describing the nature of the content controlled by
        //the group. It may be used by features that automatically control the state of the
        //group based on outside factors. See “Usage and Usage Application Dictionaries”
        //on page 380 for more information.
        var usage = GetDictionary(ocg, "Usage", list);

        //A dictionary that has a single entry, ViewState, a name that may have a
        //value of ON or OFF, indicating that the group should be set to that state when the
        //document is opened in a viewer application.
        var view = GetDictionary(usage, "View");

        PdfTypeName viewState = null;
        if (!view.ContainsKey("ViewState"))
        {
            viewState = PdfTypeName.Create("OFF");
            view.Add("ViewState", viewState);
        }
        else
            viewState = view["ViewState"] as PdfTypeName;

        viewState.Value = "OFF";
    }
    pdfViewer1.ClearRenderBuffer();
    pdfViewer1.Invalidate();
}

Edited by user Tuesday, October 15, 2019 7:17:10 PM(UTC)  | Reason: Not specified

thanks 1 user thanked Paul Rayman for this useful post.
darren on 6/28/2017(UTC)
darren  
#7 Posted : Wednesday, June 28, 2017 4:17:56 AM(UTC)
darren

Rank: Newbie

Groups: Registered
Joined: 6/16/2017(UTC)
Posts: 4
Australia

Thanks: 1 times
Thanks Paul.

That has given me the information that I need.
Bazi  
#8 Posted : Sunday, October 13, 2019 1:03:42 PM(UTC)
Bazi

Rank: Member

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

Thanks: 1 times
Hello Paul,
was that changed?

I get the value of viewState = OFF in Line 79 from your Code for all OCGs, even though they are visible.

Christian
Paul Rayman  
#9 Posted : Tuesday, October 15, 2019 7:22:16 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)
I assume that you should call the following after changing the dictionaries.
Code:
pdfViewer1.ClearRenderBuffer();
pdfViewer1.Invalidate();


I just added this to the code in a previous post.
Bazi  
#10 Posted : Wednesday, October 16, 2019 5:18:27 AM(UTC)
Bazi

Rank: Member

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

Thanks: 1 times
Hello Paul,
Thank you for your reply.
I do the following:
After displaying a PDF in the viewer, I start by button the code that reads out the OCG's and saves all ViewStates in a list (of viewstate).
The ViewState .Value of all OCGs is already "OFF". Although these are displayed in the PdfViewer.

If I switch the ViewState.Value of the list from "OFF" to "ON" or vice versa and the page dispose and invalidate the viewer the display flickers, but otherwise nothing changes.

Code behind the Button:
Code:
 internal void LoadOCGs()
{
    this.CheckedListBox1.Items.Clear();
    ViewStates.Clear();
    if (!pdfOCGs == null)
        pdfOCGs.Clear();
    pdfOCGs = new List<Patagames.Pdf.Net.BasicTypes.PdfTypeDictionary>();
    pdfRoot = PdfViewer1.Document.Root;
    // (Optional; PDF 1.5; required if a document contains optional content)
    // dictionary or array of dictionaries specifying the optional content
    // groups whose states determine the visibility of content controlled by this membership dictionary.

    // Note: Null values or references to deleted objects are ignored. If this entry is not
    // present, is an empty array, or contains references only to null or deleted objects, the
    // membership dictionary has no effect on the visibility of any content.

    // It may be a dictionary not an array. Please check it for other documents. 
    // All provided documents contains an array in that entry.
    var oc_prop = GetDictionary(pdfRoot, "OCProperties", null/* TODO Change to default(_) if this is not a reference type */, false);
    var ocgs = oc_prop("OCGs") as Patagames.Pdf.Net.BasicTypes.PdfTypeArray;
    var list = Patagames.Pdf.Net.BasicTypes.PdfIndirectList.FromPdfDocument(PdfViewer1.Document);
    foreach (object Item in ocgs)
    {
        var ocg = Item as Patagames.Pdf.Net.BasicTypes.PdfTypeIndirect.Direct as Patagames.Pdf.Net.BasicTypes.PdfTypeDictionary;
        // A usage dictionary describing the nature of the content controlled by
        // the group. It may be used by features that automatically control the state of the
        // group based on outside factors. See “Usage and Usage Application Dictionaries”
        // on page 380 for more information.
        var usage = GetDictionary(ocg, "Usage", list);
        // A dictionary that has a single entry, ViewState, a name that may have a
        // value of ON or OFF, indicating that the group should be set to that state when the
        // document is opened in a viewer application.
        var view = GetDictionary(usage, "view");
        Patagames.Pdf.Net.BasicTypes.PdfTypeName viewState = null/* TODO Change to default(_) if this is not a reference type */;
        if (!view.ContainsKey("viewState"))
        {
            viewState = Patagames.Pdf.Net.BasicTypes.PdfTypeName.Create("OFF");
            view.Add("viewState", viewState);
        }
        else
        {
            var t = view("viewState");
            var V = (Patagames.Pdf.Net.BasicTypes.PdfTypeName)t;
            viewState = view("viewState") as Patagames.Pdf.Net.BasicTypes.PdfTypeName;
        }
        var Name = ocg.GetStringBy("Name");
        var ni = CheckedListBox1.Items.Add(Name, viewState.Value.ToString == "OFF" ? false : true);
        ViewStates.Add(viewState);
        pdfOCGs.Add(ocg);
    }
}

Code in CheckedListbox:

Code:
private void CheckedListBox1_ItemCheck(object sender, System.Windows.Forms.ItemCheckEventArgs e)
{
    var Test = e.CurrentValue;
    var Index = e.Index;
    var ViewState = ViewStates(Index);
    ViewStates(Index).Value = Test == CheckState.Checked ? "ON" : "OFF";
    PdfViewer1.CurrentPage.Dispose();
    PdfViewer1.ClearRenderBuffer();
    PdfViewer1.Invalidate();
}


Christian

Edited by moderator Tuesday, October 22, 2019 11:46:47 PM(UTC)  | Reason: Not specified

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.