/*
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.documents.contents;
using it.stefanochizzolini.clown.documents.interaction.forms;
using it.stefanochizzolini.clown.documents.interaction.navigation.document;
using it.stefanochizzolini.clown.documents.interchange.metadata;
using it.stefanochizzolini.clown.documents.interaction.viewer;
using it.stefanochizzolini.clown.files;
using it.stefanochizzolini.clown.objects;
using it.stefanochizzolini.clown.tokens;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Printing;
namespace it.stefanochizzolini.clown.documents{
/**
<summary>PDF document [PDF:1.6::3.6.1].</summary>
*/
public class Document
: PdfObjectWrapper<PdfDictionary>
{
#region dynamic
#region fields
internal Dictionary<PdfReference,object> Cache = new Dictionary<PdfReference,object>();
#endregion
#region constructors
internal Document(
File context
) : base(
context,
new PdfDictionary(
new PdfName[1]{PdfName.Type},
new PdfDirectObject[1]{PdfName.Catalog}
) // Document catalog [PDF:1.6:3.6.1].
)
{
/*
NOTE: Here is just a minimal initialization.
Any further customization is upon client's responsibility.
*/
// Link the document to the file!
// NOTE: Attach a catalog reference to the file trailer.
context.Trailer[PdfName.Root] = BaseObject;
// Initialize the pages collection (page-tree root node)!
/*
NOTE: The page-tree root node is required [PDF:1.6:3.6.1].
*/
this.Pages = new Pages(this);
// Default page size.
PageSize = PageFormat.GetSize();
// Default resources collection.
Resources = new Resources(this);
}
internal Document(
PdfDirectObject baseObject
) : base(
baseObject,
null // NO container (the document catalog MUST be an indirect object [PDF:1.6:3.4.4]).
)
{}
#endregion
#region interface
#region public
/**
<summary>Gets/Sets the document's behavior in response to trigger events.</summary>
*/
public DocumentActions Actions
{
get
{
PdfDirectObject actionsObject = BaseDataObject[PdfName.AA];
if(actionsObject == null)
return null;
return new DocumentActions(actionsObject,Container);
}
set
{BaseDataObject[PdfName.AA] = value.BaseObject;}
}
/**
<summary>Gets/Sets the bookmark collection [PDF:1.6:8.2.2].</summary>
*/
public Bookmarks Bookmarks
{
get
{
PdfDirectObject bookmarksObject = BaseDataObject[PdfName.Outlines];
if(bookmarksObject == null)
return null;
return new Bookmarks(bookmarksObject);
}
set
{BaseDataObject[PdfName.Outlines] = value.BaseObject;}
}
public override object Clone(
Document context
)
{throw new NotImplementedException();}
/**
<summary>Forces the object to belong to the document context.</summary>
*/
public PdfObjectWrapper Contextualize(
PdfObjectWrapper obj
)
{
if(obj.File == File)
return obj;
return (PdfObjectWrapper)obj.Clone(this);
}
/**
<summary>Forces the collection's objects to belong to the document context.</summary>
*/
public ICollection<T> Contextualize<T>(
ICollection<T> objs
)
where T : PdfObjectWrapper
{
List<T> contextualizedObjects = new List<T>(objs.Count);
foreach(T obj in objs)
{contextualizedObjects.Add((T)Contextualize(obj));}
return (ICollection<T>)contextualizedObjects;
}
/**
<summary>Forces the object to be dropped from the document context.</summary>
*/
public void Decontextualize(
PdfObjectWrapper obj
)
{
if(obj.File != File)
return;
obj.Delete();
}
/**
<summary>Forces the collection's objects to be dropped from the document context.</summary>
*/
public void Decontextualize<T>(
ICollection<T> objs
)
where T : PdfObjectWrapper
{
foreach(T obj in objs)
{Decontextualize(obj);}
}
/**
<summary>Gets/Sets the interactive form (AcroForm) [PDF:1.6:8.6.1].</summary>
*/
public Form Form
{
get
{
PdfDirectObject formObject = BaseDataObject[PdfName.AcroForm];
if(formObject == null)
return null;
return new Form(formObject,Container);
}
set
{BaseDataObject[PdfName.AcroForm] = value.BaseObject;}
}
/**
<summary>Gets the document size, that is the maximum page dimensions across
the whole document.</summary>
*/
public Size GetSize(
)
{
int height = 0, width = 0;
foreach(Page page in Pages)
{
Size? pageSize = page.Size;
if(!pageSize.HasValue)
continue;
height = Math.Max(height,pageSize.Value.Height);
width = Math.Max(width,pageSize.Value.Width);
}
return new Size(width,height);
}
/**
<summary>Gets/Sets the document information dictionary [PDF:1.6:10.2.1].</summary>
*/
public Information Information
{
get
{
PdfDirectObject informationObject = File.Trailer[PdfName.Info];
if(informationObject == null)
return null;
return new Information(informationObject);
}
set
{File.Trailer[PdfName.Info] = value.BaseObject;}
}
/**
<summary>Gets/Sets the name dictionary [PDF:1.6:3.6.3].</summary>
*/
public Names Names
{
get
{
PdfDirectObject namesObject = BaseDataObject[PdfName.Names];
if(namesObject == null)
return null;
return new Names(
namesObject,
((PdfReference)BaseObject).IndirectObject
);
}
set
{BaseDataObject[PdfName.Names] = value.BaseObject;}
}
/**
<summary>Gets the page layout to be used when the document is opened.</summary>
*/
public PageLayoutEnum PageLayout
{
get
{
PdfName value = (PdfName)BaseDataObject[PdfName.PageLayout];
if(value.Equals(PdfName.OneColumn))
return PageLayoutEnum.OneColumn;
else if(value.Equals(PdfName.TwoColumnLeft))
return PageLayoutEnum.TwoColumns;
else
return PageLayoutEnum.SinglePage;
}
set
{
switch(value)
{
case PageLayoutEnum.SinglePage:
BaseDataObject[PdfName.PageLayout] = PdfName.SinglePage;
break;
case PageLayoutEnum.OneColumn:
BaseDataObject[PdfName.PageLayout] = PdfName.OneColumn;
break;
case PageLayoutEnum.TwoColumns:
BaseDataObject[PdfName.PageLayout] = PdfName.TwoColumnLeft;
break;
}
}
}
/**
<summary>Gets the page mode, that is how the document should be displayed when is opened.</summary>
*/
public PageModeEnum PageMode
{
get
{
PdfName value = (PdfName)BaseDataObject[PdfName.PageMode];
if(value.Equals(PdfName.UseOutlines))
return PageModeEnum.Outlines;
else if(value.Equals(PdfName.UseThumbs))
return PageModeEnum.Thumbnails;
else if(value.Equals(PdfName.FullScreen))
return PageModeEnum.FullScreen;
else
return PageModeEnum.Simple;
}
set
{
switch(value)
{
case PageModeEnum.Simple:
BaseDataObject[PdfName.PageMode] = PdfName.UseNone;
break;
case PageModeEnum.Outlines:
BaseDataObject[PdfName.PageMode] = PdfName.UseOutlines;
break;
case PageModeEnum.Thumbnails:
BaseDataObject[PdfName.PageMode] = PdfName.UseThumbs;
break;
case PageModeEnum.FullScreen:
BaseDataObject[PdfName.PageMode] = PdfName.FullScreen;
break;
}
}
}
/**
<summary>Gets/Sets the page collection [PDF:1.6:3.6.2].</summary>
*/
public Pages Pages
{
get
{return new Pages(BaseDataObject[PdfName.Pages]); /* NOTE: Required. */}
set
{BaseDataObject[PdfName.Pages] = value.BaseObject;}
}
/**
<summary>Gets/Sets the default page size [PDF:1.6:3.6.2].</summary>
*/
public Size? PageSize
{
get
{
/*
NOTE: Due to the contract,
we cannot force the existence of the default media box at document level.
*/
PdfArray box = MediaBox;
if(box == null)
return null;
return new Size(
(int)((IPdfNumber)box[2]).RawValue,
(int)((IPdfNumber)box[3]).RawValue
);
}
set
{
PdfArray mediaBox = MediaBox;
if(mediaBox == null)
{
// Create default media box!
mediaBox = new PdfRectangle(0,0,0,0);
// Assign the media box to the document!
((PdfDictionary)File.Resolve(
BaseDataObject[PdfName.Pages]
))[PdfName.MediaBox] = mediaBox;
}
mediaBox[2] = new PdfReal(value.Value.Width);
mediaBox[3] = new PdfReal(value.Value.Height);
}
}
/**
<summary>Gets/Sets the default resource collection [PDF:1.6:3.6.2].</summary>
<remarks>The default resource collection is used as last resort by every page
that doesn't reference one explicitly (and doesn't reference an intermediate one
implicitly).</remarks>
*/
public Resources Resources
{
get
{
PdfReference pages = (PdfReference)BaseDataObject[PdfName.Pages];
PdfDirectObject resources = ((PdfDictionary)File.Resolve(pages))[PdfName.Resources];
if(resources == null)
return null;
return new Resources(
resources,
pages.IndirectObject
);
}
set
{
PdfReference pages = (PdfReference)BaseDataObject[PdfName.Pages];
((PdfDictionary)File.Resolve(pages))[PdfName.Resources] = value.BaseObject;
value.Container = pages.IndirectObject; // Resources object could be directly inside a container.
}
}
/**
<summary>Gets/Sets the version of the PDF specification to which the document conforms.</summary>
*/
public string Version
{
get
{
string fileVersion = File.Version;
/*
NOTE: 'Version' entry may be undefined.
*/
PdfName versionObject = (PdfName)BaseDataObject[PdfName.Version];
if(versionObject == null)
return fileVersion;
string version = versionObject.RawValue;
string[] fileVersionDigits;
string[] versionDigits;
try
{
fileVersionDigits = fileVersion.Split('.');
versionDigits = version.Split('.');
}
catch(Exception exception)
{throw new Exception("Version decomposition failed.",exception);}
try
{
if(Convert.ToInt32(versionDigits[0]) > Convert.ToInt32(fileVersionDigits[0])
|| (Convert.ToInt32(versionDigits[0]) == Convert.ToInt32(fileVersionDigits[0])
&& Convert.ToInt32(versionDigits[1]) > Convert.ToInt32(fileVersionDigits[1])))
return version;
return fileVersion;
}
catch(Exception exception)
{throw new Exception("Wrong version format.",exception);}
}
set
{BaseDataObject[PdfName.Version] = new PdfName(value);}
}
/**
<summary>Gets the way the document is to be presented [PDF:1.6:8.1].</summary>
*/
public ViewerPreferences ViewerPreferences
{
get
{
PdfDirectObject viewerPreferences = BaseDataObject[PdfName.ViewerPreferences];
if(viewerPreferences == null)
return null;
return new ViewerPreferences(
viewerPreferences,
((PdfReference)BaseObject).IndirectObject //TODO: Container?
);
}
set
{
BaseDataObject[PdfName.ViewerPreferences] = value.BaseObject;
value.Container = ((PdfReference)BaseObject).IndirectObject; // ViewerPreferences object could be directly inside a container.
}
}
#endregion
#region private
/**
<summary>Gets the default media box.</summary>
*/
private PdfArray MediaBox
{
get
{
/*
NOTE: Document media box MUST be associated with the page-tree root node
in order to be inheritable by all the pages.
*/
return (PdfArray)((PdfDictionary)File.Resolve(BaseDataObject[PdfName.Pages]))[PdfName.MediaBox];
}
}
#endregion
#endregion
#endregion
}
}
|