Page.cs :  » PDF » PDF-Clown » it » stefanochizzolini » clown » documents » C# / CSharp Open Source

Home
C# / CSharp Open Source
1.2.6.4 mono .net core
2.2.6.4 mono core
3.Aspect Oriented Frameworks
4.Bloggers
5.Build Systems
6.Business Application
7.Charting Reporting Tools
8.Chat Servers
9.Code Coverage Tools
10.Content Management Systems CMS
11.CRM ERP
12.Database
13.Development
14.Email
15.Forum
16.Game
17.GIS
18.GUI
19.IDEs
20.Installers Generators
21.Inversion of Control Dependency Injection
22.Issue Tracking
23.Logging Tools
24.Message
25.Mobile
26.Network Clients
27.Network Servers
28.Office
29.PDF
30.Persistence Frameworks
31.Portals
32.Profilers
33.Project Management
34.RSS RDF
35.Rule Engines
36.Script
37.Search Engines
38.Sound Audio
39.Source Control
40.SQL Clients
41.Template Engines
42.Testing
43.UML
44.Web Frameworks
45.Web Service
46.Web Testing
47.Wiki Engines
48.Windows Presentation Foundation
49.Workflows
50.XML Parsers
C# / C Sharp
C# / C Sharp by API
C# / CSharp Tutorial
C# / CSharp Open Source » PDF » PDF Clown 
PDF Clown » it » stefanochizzolini » clown » documents » Page.cs
/*
  Copyright 2006,2007,2008 Stefano Chizzolini. http://clown.stefanochizzolini.it

  Contributors:
    * Stefano Chizzolini (original code developer, http://www.stefanochizzolini.it)

  This file should be part of the source code distribution of "PDF Clown library"
  (the Program): see the accompanying README files for more info.

  This Program is free software; you can redistribute it and/or modify it under
  the terms of the GNU General Public License as published by the Free Software
  Foundation; either version 2 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, either expressed or implied; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the License for more details.

  You should have received a copy of the GNU General Public License along with this
  Program (see README files); if not, go to the GNU website (http://www.gnu.org/).

  Redistribution and use, with or without modification, are permitted provided that such
  redistributions retain the above copyright notice, license and disclaimer, along with
  this list of conditions.
*/

using it.stefanochizzolini.clown.bytes;
using it.stefanochizzolini.clown.documents.contents;
using it.stefanochizzolini.clown.documents.contents.composition;
using it.stefanochizzolini.clown.documents.contents.objects;
using xObjectsit.stefanochizzolini.clown.documents.contents.xObjects;
using it.stefanochizzolini.clown.documents.interaction.navigation.page;
using it.stefanochizzolini.clown.files;
using it.stefanochizzolini.clown.objects;

using System;
using System.Collections.Generic;
using System.Drawing;

namespace it.stefanochizzolini.clown.documents{
  /**
    <summary>Document page [PDF:1.6:3.6.2].</summary>
  */
  public class Page
    : PdfObjectWrapper<PdfDictionary>,
      IContentContext
  {
    /*
      NOTE: Inheritable attributes are NOT early-collected, as they are NOT part
      of the explicit representation of a page. They are retrieved everytime
      clients call.
    */
    #region types
    /**
      <summary>Annotations tab order [PDF:1.6:3.6.2].</summary>
    */
    public enum TabOrderEnum
    {
      /**
        <summary>Row order.</summary>
      */
      Row,
      /**
        <summary>Column order.</summary>
      */
      Column,
      /**
        <summary>Structure order.</summary>
      */
      Structure
    };
    #endregion

    #region static
    #region fields
    private static readonly Dictionary<TabOrderEnum,PdfName> TabOrderEnumCodes;
    #endregion

    #region constructors
    static Page()
    {
      TabOrderEnumCodes = new Dictionary<TabOrderEnum,PdfName>();
      TabOrderEnumCodes[TabOrderEnum.Row] = PdfName.R;
      TabOrderEnumCodes[TabOrderEnum.Column] = PdfName.C;
      TabOrderEnumCodes[TabOrderEnum.Structure] = PdfName.S;
    }
    #endregion

    #region interface
    #region public
    public static Page Wrap(
      PdfReference reference
      )
    {return new Page(reference);}
    #endregion

    #region private
    /**
      <summary>Gets the code corresponding to the given value.</summary>
    */
    private static PdfName ToCode(
      TabOrderEnum value
      )
    {return TabOrderEnumCodes[value];}

    /**
      <summary>Gets the tab order corresponding to the given value.</summary>
    */
    private static TabOrderEnum ToTabOrderEnum(
      PdfName value
      )
    {
      foreach(KeyValuePair<TabOrderEnum,PdfName> tabOrder in TabOrderEnumCodes)
      {
        if(tabOrder.Value.Equals(value))
          return tabOrder.Key;
      }
      return TabOrderEnum.Row;
    }
    #endregion
    #endregion
    #endregion

    #region dynamic
    #region constructors
    /**
      <summary>Creates a new page within the given document context, using default resources.</summary>
    */
    public Page(
      Document context
      ) : base(
        context.File,
        new PdfDictionary(
          new PdfName[2]
          {
            PdfName.Type,
            PdfName.Contents
          },
          new PdfDirectObject[2]
          {
            PdfName.Page,
            context.File.Register(
              new PdfStream()
              )
          }
          )
        )
    {}

    /**
      <summary>Creates a new page within the given document context, using custom resources.</summary>
    */
    public Page(
      Document context,
      Size size,
      Resources resources
      ) : base(
        context.File,
        new PdfDictionary(
          new PdfName[4]
          {
            PdfName.Type,
            PdfName.MediaBox,
            PdfName.Contents,
            PdfName.Resources
          },
          new PdfDirectObject[4]
          {
            PdfName.Page,
            new PdfRectangle(0,0,size.Width,size.Height),
            context.File.Register(
              new PdfStream()
              ),
            resources.BaseObject
          }
          )
        )
    {}

    internal Page(
      PdfDirectObject baseObject
      ) : base(
        baseObject,
        null // NO container. NOTE: this is a simplification (the spec [PDF:1.6] doesn't apparently prescribe the use of an indirect object for page dictionary, whilst the general practice is as such. If an exception occur, you'll need to specify the proper container).
        )
    {}
    #endregion

    #region interface
    #region public
    /**
      <summary>Gets/Sets the page's behavior in response to trigger events.</summary>
    */
    public PageActions Actions
    {
      get
      {
        PdfDirectObject actionsObject = BaseDataObject[PdfName.AA];
        if(actionsObject == null)
          return null;

        return new PageActions(actionsObject,Container);
      }
      set
      {BaseDataObject[PdfName.AA] = value.BaseObject;}
    }

    /**
      <summary>Gets/Sets the annotations associated to the page.</summary>
    */
    public PageAnnotations Annotations
    {
      get
      {
        PdfDirectObject annotationsObject = BaseDataObject[PdfName.Annots];
        if(annotationsObject == null)
          return null;

        return new PageAnnotations(annotationsObject,Container,this);
      }
      set
      {BaseDataObject[PdfName.Annots] = value.BaseObject;}
    }

    public override object Clone(
      Document context
      )
    {
      /*
        NOTE: We cannot just delegate the cloning to the base object, as it would
        involve some unwanted objects like those in 'Parent' and 'Annots' entries that may
        cause infinite loops (due to circular references) and may include exceeding contents
        (due to copy propagations to the whole page-tree which this page belongs to).
        TODO: 'Annots' entry must be finely treated to include any non-circular reference.
      */
      // TODO:IMPL deal with inheritable attributes!!!

      File contextFile = context.File;
      PdfDictionary clone = new PdfDictionary(BaseDataObject.Count);
      foreach(
        KeyValuePair<PdfName,PdfDirectObject> entry in BaseDataObject
        )
      {
        PdfName key = entry.Key;
        // Is the entry unwanted?
        if(key.Equals(PdfName.Parent)
          || key.Equals(PdfName.Annots))
          continue;

        // Insert the clone of the entry into the clone of the page dictionary!
        clone[key] = (PdfDirectObject)entry.Value.Clone(contextFile);
      }

      return new Page(
        contextFile.IndirectObjects.Add(clone).Reference
        );
    }

    /**
      <summary>Gets/Sets the page's display duration.</summary>
      <remarks>
        <para>The page's display duration (also called its advance timing)
        is the maximum length of time, in seconds, that the page is displayed
        during presentations before the viewer application automatically advances
        to the next page.</para>
        <para>By default, the viewer does not advance automatically.</para>
      </remarks>
    */
    public double Duration
    {
      get
      {
        IPdfNumber durationObject = (IPdfNumber)BaseDataObject[PdfName.Dur];
        if(durationObject == null)
          return 0;

        return durationObject.RawValue;
      }
      set
      {BaseDataObject[PdfName.Dur] = new PdfReal(value);}
    }

    /**
      <summary>Gets the index of the page.</summary>
      <remarks>The page index is not an explicit datum, therefore it needs
      to be inferred from the position of the page object inside the page tree,
      requiring a significant amount of computation: invoke it sparingly!</remarks>
    */
    public int Index
    {
      get
      {
        /*
          NOTE: We'll scan sequentially each page-tree level above this page object
          collecting page counts. At each level we'll scan the kids array from the
          lower-indexed item to the ancestor of this page object at that level.
        */
        PdfReference ancestorKidReference = (PdfReference)BaseObject;
        PdfReference parentReference = (PdfReference)BaseDataObject[PdfName.Parent];
        PdfDictionary parent = (PdfDictionary)File.Resolve(parentReference);
        PdfArray kids = (PdfArray)File.Resolve(parent[PdfName.Kids]);
        int index = 0;
        for(
          int i = 0;
          true;
          i++
          )
        {
          PdfReference kidReference = (PdfReference)kids[i];
          // Is the current-level counting complete?
          // NOTE: It's complete when it reaches the ancestor at this level.
          if(kidReference.Equals(ancestorKidReference)) // Ancestor node.
          {
            // Does the current level correspond to the page-tree root node?
            if(!parent.ContainsKey(PdfName.Parent))
            {
              // We reached the top: counting's finished.
              return index;
            }
            // Set the ancestor at the next level!
            ancestorKidReference = parentReference;
            // Move up one level!
            parentReference = (PdfReference)parent[PdfName.Parent];
            parent = (PdfDictionary)File.Resolve(parentReference);
            kids = (PdfArray)File.Resolve(parent[PdfName.Kids]);
            i = -1;
          }
          else // Intermediate node.
          {
            PdfDictionary kid = (PdfDictionary)File.Resolve(kidReference);
            if(kid[PdfName.Type].Equals(PdfName.Page))
              index++;
            else
              index += ((PdfInteger)kid[PdfName.Count]).RawValue;
          }
        }
      }
    }

    /**
      <summary>Gets/Sets the page size.</summary>
    */
    public Size? Size
    {
      get
      {
        PdfArray box = (PdfArray)File.Resolve(
          GetInheritableAttribute(PdfName.MediaBox)
          );
        if(box == null)
          return null;

        return new Size(
          (int)((IPdfNumber)box[2]).RawValue,
          (int)((IPdfNumber)box[3]).RawValue
          );
      }
      set
      {
        /*
          NOTE: When page size is about to be modified, we MUST ensure that the change will affect just
          the mediaBox of this page; so, if such a mediaBox is implicit (inherited), it MUST be cloned
          and explicitly assigned to this page in order to apply changes.
        */
        PdfDictionary dictionary = BaseDataObject;
        PdfDirectObject entry = dictionary[PdfName.MediaBox];
        if(entry == null)
        {
          // Clone the inherited attribute in order to restrict its change to this page's scope only!
          entry = (PdfDirectObject)GetInheritableAttribute(PdfName.MediaBox).Clone(File);
          // Associate the cloned attribute to this page's dictionary!
          dictionary[PdfName.MediaBox] = entry;
        }

        PdfArray box = (PdfArray)File.Resolve(entry);
        ((IPdfNumber)box[2]).RawValue = value.Value.Width;
        ((IPdfNumber)box[3]).RawValue = value.Value.Height;
      }
    }

    /**
      <summary>Gets/Sets the tab order to be used for annotations on the page.</summary>
    */
    public TabOrderEnum TabOrder
    {
      get
      {return ToTabOrderEnum((PdfName)BaseDataObject[PdfName.Tabs]);}
      set
      {BaseDataObject[PdfName.Tabs] = ToCode(value);}
    }

    /**
      <summary>Gets the transition effect to be used
      when displaying the page during presentations.</summary>
    */
    public Transition Transition
    {
      get
      {
        PdfDirectObject transitionObject = BaseDataObject[PdfName.Trans];
        if(transitionObject == null)
          return null;

        return new Transition(transitionObject,Container);
      }
      set
      {BaseDataObject[PdfName.Trans] = value.BaseObject;}
    }

    #region IContentContext
    public PdfArray Box
    {get{return (PdfArray)File.Resolve(GetInheritableAttribute(PdfName.MediaBox));}}

    public Contents Contents
    {
      get
      {
        return new Contents(
          BaseDataObject[PdfName.Contents],
          ((PdfReference)BaseObject).IndirectObject,
          this
          );
      }
    }

    public Resources Resources
    {
      get
      {
        return new Resources(
          GetInheritableAttribute(PdfName.Resources),
          ((PdfReference)BaseObject).IndirectObject
          );
      }
    }

    #region IContentEntity
    public ContentObject ToInlineObject(
      PrimitiveFilter context
      )
    {throw new NotImplementedException();}

    public xObjects::XObject ToXObject(
      Document context
      )
    {
      File contextFile = context.File;

      xObjects::FormXObject form = new xObjects::FormXObject(context);
      PdfStream formStream = form.BaseDataObject;

      // Header.
      {
        PdfDictionary formHeader = formStream.Header;
        // Bounding box.
        formHeader[PdfName.BBox] = (PdfDirectObject)GetInheritableAttribute(PdfName.MediaBox).Clone(contextFile);
        // Resources.
        {
          PdfDirectObject resourcesObject = GetInheritableAttribute(PdfName.Resources);
          // Same document?
          /* NOTE: Try to reuse the resource dictionary whenever possible. */
          formHeader[PdfName.Resources] = (context.Equals(Document) ?
            resourcesObject
            : (PdfDirectObject)resourcesObject.Clone(contextFile));
        }
      }

      // Body (contents).
      {
        IBuffer formBody = formStream.Body;
        PdfDataObject contentsDataObject = File.Resolve(BaseDataObject[PdfName.Contents]);
        if(contentsDataObject is PdfStream)
        {formBody.Append(((PdfStream)contentsDataObject).Body);}
        else
        {
          foreach(PdfDirectObject contentStreamObject in (PdfArray)contentsDataObject)
          {formBody.Append(((PdfStream)File.Resolve(contentStreamObject)).Body);}
        }
      }

      return form;
    }
    #endregion
    #endregion
    #endregion

    #region protected
    protected PdfDirectObject GetInheritableAttribute(
      PdfName key
      )
    {
      /*
        NOTE: It moves upward until it finds the inherited attribute.
      */
      PdfDictionary dictionary = BaseDataObject;
      while(true)
      {
        PdfDirectObject entry = dictionary[key];
        if(entry != null)
          return entry;

        dictionary = (PdfDictionary)File.Resolve(
          dictionary[PdfName.Parent]
          );
        if(dictionary == null)
        {
          // Isn't the page attached to the page tree?
          /* NOTE: This condition is illegal. */
          if(BaseDataObject[PdfName.Parent] == null)
            throw new Exception("Inheritable attributes unreachable: Page objects MUST be inserted into their document's Pages collection before being used.");

          return null;
        }
      }
    }
    #endregion
    #endregion
    #endregion
  }
}
www.java2v.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.