/*
Copyright 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;
using it.stefanochizzolini.clown.files;
using it.stefanochizzolini.clown.objects;
using System;
using System.Drawing;
namespace it.stefanochizzolini.clown.documents.interaction.annotations{
/**
<summary>Annotation [PDF:1.6:8.4].</summary>
*/
public class Annotation
: PdfObjectWrapper<PdfDictionary>
{
#region types
/**
<summary>Field flags [PDF:1.6:8.4.2].</summary>
*/
public enum FlagsEnum
{
/**
<summary>Hide the annotation, both on screen and on print,
if it does not belong to one of the standard annotation types
and no annotation handler is available.</summary>
*/
Invisible = 0x1,
/**
<summary>Hide the annotation, both on screen and on print
(regardless of its annotation type or whether an annotation handler is available).</summary>
*/
Hidden = 0x2,
/**
<summary>Print the annotation when the page is printed.</summary>
*/
Print = 0x4,
/**
<summary>Do not scale the annotation's appearance to match the magnification of the page.</summary>
*/
NoZoom = 0x8,
/**
<summary>Do not rotate the annotation's appearance to match the rotation of the page.</summary>
*/
NoRotate = 0x10,
/**
<summary>Hide the annotation on the screen.</summary>
*/
NoView = 0x20,
/**
<summary>Do not allow the annotation to interact with the user.</summary>
*/
ReadOnly = 0x40,
/**
<summary>Do not allow the annotation to be deleted or its properties to be modified by the user.</summary>
*/
Locked = 0x80,
/**
<summary>Invert the interpretation of the NoView flag.</summary>
*/
ToggleNoView = 0x100
};
#endregion
#region static
#region interface
#region public
/**
<summary>Wraps an annotation reference into an annotation object.</summary>
<param name="reference">Reference to an annotation object.</param>
<returns>Annotation object associated to the reference.</returns>
*/
public static Annotation Wrap(
PdfReference reference
)
{return Wrap(reference,null);}
/**
<summary>Wraps an annotation base object into an annotation object.</summary>
<param name="baseObject">Annotation base object.</param>
<param name="container">Annotation base object container.</param>
<returns>Annotation object associated to the base object.</returns>
*/
public static Annotation Wrap(
PdfDirectObject baseObject,
PdfIndirectObject container
)
{
/*
NOTE: This is a factory method for any annotation-derived object.
*/
if(baseObject == null)
return null;
PdfDictionary dataObject = (PdfDictionary)File.Resolve(baseObject);
if(!dataObject[PdfName.Type].Equals(PdfName.Annot))
return null;
PdfName annotationType = (PdfName)dataObject[PdfName.Subtype];
if(annotationType.Equals(PdfName.Text)) return new Note(baseObject,container);
if(annotationType.Equals(PdfName.Link)) return new Link(baseObject,container);
if(annotationType.Equals(PdfName.FreeText)) return new CalloutNote(baseObject,container);
if(annotationType.Equals(PdfName.Line)) return new Line(baseObject,container);
if(annotationType.Equals(PdfName.Square)) return new Rectangle(baseObject,container);
if(annotationType.Equals(PdfName.Circle)) return new Ellipse(baseObject,container);
if(annotationType.Equals(PdfName.Polygon)) return new Polygon(baseObject,container);
if(annotationType.Equals(PdfName.PolyLine)) return new Polyline(baseObject,container);
if(annotationType.Equals(PdfName.Highlight)
|| annotationType.Equals(PdfName.Underline)
|| annotationType.Equals(PdfName.Squiggly)
|| annotationType.Equals(PdfName.StrikeOut))
return new TextMarkup(baseObject,container);
if(annotationType.Equals(PdfName.Stamp)) return new RubberStamp(baseObject,container);
if(annotationType.Equals(PdfName.Caret)) return new Caret(baseObject,container);
if(annotationType.Equals(PdfName.Ink)) return new Scribble(baseObject,container);
if(annotationType.Equals(PdfName.Popup)) return new Popup(baseObject,container);
if(annotationType.Equals(PdfName.FileAttachment)) return new FileAttachment(baseObject,container);
if(annotationType.Equals(PdfName.Sound)) return new SoundAnnotation(baseObject,container);
if(annotationType.Equals(PdfName.Movie)) return new MovieAnnotation(baseObject,container);
if(annotationType.Equals(PdfName.Widget)) return new Widget(baseObject,container);
//TODO
// if(annotationType.Equals(PdfName.Screen)) return new Screen(baseObject,container);
// if(annotationType.Equals(PdfName.PrinterMark)) return new PrinterMark(baseObject,container);
// if(annotationType.Equals(PdfName.TrapNet)) return new TrapNet(baseObject,container);
// if(annotationType.Equals(PdfName.Watermark)) return new Watermark(baseObject,container);
// if(annotationType.Equals(PdfName.3DAnnotation)) return new 3DAnnotation(baseObject,container);
// Other annotation type.
return new Annotation(baseObject,container);
}
#endregion
#endregion
#endregion
#region dynamic
#region constructors
protected Annotation(
Document context,
PdfName subtype,
RectangleF box,
Page page
) : base(
context.File,
new PdfDictionary(
new PdfName[]
{
PdfName.Type,
PdfName.Subtype,
PdfName.P,
PdfName.Border
},
new PdfDirectObject[]
{
PdfName.Annot,
subtype,
page.BaseObject,
new PdfArray(new PdfDirectObject[]{new PdfInteger(0),new PdfInteger(0),new PdfInteger(0)}) // NOTE: Hide border by default.
}
)
)
{
Box = box;
PdfArray pageAnnotsObject = (PdfArray)File.Resolve(page.BaseDataObject[PdfName.Annots]);
if(pageAnnotsObject == null)
{page.BaseDataObject[PdfName.Annots] = pageAnnotsObject = new PdfArray();}
pageAnnotsObject.Add(BaseObject);
}
protected Annotation(
PdfDirectObject baseObject,
PdfIndirectObject container
) : base(baseObject,container)
{}
#endregion
#region interface
#region public
/**
<summary>Gets/Sets the annotation's behavior in response to various trigger events.</summary>
*/
public virtual AnnotationActions Actions
{
get
{
PdfDirectObject actionsObject = BaseDataObject[PdfName.AA];
if(actionsObject == null)
return null;
return new AnnotationActions(this,actionsObject,Container);
}
set
{
if(value == null)
{BaseDataObject.Remove(PdfName.AA);}
else
{BaseDataObject[PdfName.AA] = value.BaseObject;}
}
}
/**
<summary>Gets/Sets the appearance specifying how the annotation is presented visually on the page.</summary>
*/
public Appearance Appearance
{
get
{
/*
NOTE: 'AP' entry may be undefined.
*/
PdfDirectObject appearanceObject = BaseDataObject[PdfName.AP];
if(appearanceObject == null)
return null;
return new Appearance(appearanceObject,Container);
}
set
{
if(value == null)
{BaseDataObject.Remove(PdfName.AP);}
else
{BaseDataObject[PdfName.AP] = value.BaseObject;}
}
}
/**
<summary>Gets/Sets the border style.</summary>
*/
public Border Border
{
get
{
/*
NOTE: 'BS' entry may be undefined.
*/
PdfDirectObject borderObject = BaseDataObject[PdfName.BS];
if(borderObject == null)
return null;
return new Border(borderObject,Container);
}
set
{
if(value == null)
{BaseDataObject.Remove(PdfName.BS);}
else
{
BaseDataObject[PdfName.BS] = value.BaseObject;
BaseDataObject.Remove(PdfName.Border);
}
}
}
/**
<summary>Gets/Sets the annotation rectangle.</summary>
*/
public RectangleF Box
{
get
{
/*
NOTE: 'Rect' entry MUST be defined.
*/
PdfArray box = (PdfArray)File.Resolve(BaseDataObject[PdfName.Rect]);
double x = ((IPdfNumber)box[0]).RawValue;
double y = ((IPdfNumber)box[1]).RawValue;
return new RectangleF(
(float)x,
(float)(((IPdfNumber)Page.Box[3]).RawValue - y),
(float)(((IPdfNumber)box[2]).RawValue - x),
(float)(y - ((IPdfNumber)box[3]).RawValue)
);
}
set
{
double pageHeight = ((IPdfNumber)Page.Box[3]).RawValue;
BaseDataObject[PdfName.Rect] = new PdfRectangle(
value.X,
pageHeight - value.Y - value.Height,
value.X + value.Width,
pageHeight - value.Y
);
}
}
public override object Clone(
Document context
)
{throw new NotImplementedException();}
/**
<summary>Gets/Sets the annotation flags.</summary>
*/
public FlagsEnum Flags
{
get
{
PdfInteger flagsObject = (PdfInteger)BaseDataObject[PdfName.F];
if(flagsObject == null)
return 0;
return (FlagsEnum)Enum.ToObject(
typeof(FlagsEnum),
flagsObject.RawValue
);
}
set
{BaseDataObject[PdfName.F] = new PdfInteger((int)value);}
}
/**
<summary>Gets/Sets the date and time when the annotation was most recently modified.</summary>
*/
public DateTime? ModificationDate
{
get
{
/*
NOTE: 'M' entry may be undefined.
*/
PdfDirectObject modificationDateObject = BaseDataObject[PdfName.M];
if(modificationDateObject == null
|| !(modificationDateObject is PdfDate)) // NOTE: Non-well-formed dates are ignored.
return null;
return (DateTime)((PdfDate)modificationDateObject).Value;
}
set
{
if(value.HasValue)
{BaseDataObject[PdfName.M] = new PdfDate(value.Value);}
else
{BaseDataObject.Remove(PdfName.M);}
}
}
/**
<summary>Gets/Sets the annotation name.</summary>
<remarks>The annotation name uniquely identify the annotation among all the annotations on its page.</remarks>
*/
public string Name
{
get
{
/*
NOTE: 'NM' entry may be undefined.
*/
PdfTextString nameObject = (PdfTextString)BaseDataObject[PdfName.NM];
if(nameObject == null)
return null;
return (string)nameObject.Value;
}
set
{BaseDataObject[PdfName.NM] = new PdfTextString(value);}
}
/**
<summary>Gets/Sets the associated page.</summary>
*/
public Page Page
{
get
{
/*
NOTE: 'P' entry may be undefined.
*/
PdfDirectObject pageObject = BaseDataObject[PdfName.P];
if(pageObject == null)
return null;
return new Page(pageObject);
}
set
{BaseDataObject[PdfName.P] = value.BaseObject;}
}
/**
<summary>Gets/Sets the annotation size.</summary>
*/
public SizeF Size
{
get
{
/*
NOTE: Rectangle entry MUST be defined.
*/
PdfArray box = (PdfArray)File.Resolve(BaseDataObject[PdfName.Rect]);
return new SizeF(
(float)(((IPdfNumber)box[2]).RawValue - ((IPdfNumber)box[0]).RawValue),
(float)(((IPdfNumber)box[3]).RawValue - ((IPdfNumber)box[1]).RawValue)
);
}
set
{
PdfArray box = (PdfArray)File.Resolve(BaseDataObject[PdfName.Rect]);
((IPdfNumber)box[2]).Value = value.Width;
((IPdfNumber)box[3]).Value = value.Height;
}
}
/**
<summary>Gets/Sets the annotation text.</summary>
<remarks>Depending on the annotation type, the text may be either directly displayed
or (in case of non-textual annotations) used as alternate description.</remarks>
*/
public string Text
{
get
{
/*
NOTE: 'Contents' entry may be undefined.
*/
PdfTextString textObject = (PdfTextString)BaseDataObject[PdfName.Contents];
if(textObject == null)
return null;
return (string)textObject.Value;
}
set
{
if(value == null)
{BaseDataObject.Remove(PdfName.Contents);}
else
{BaseDataObject[PdfName.Contents] = new PdfTextString(value);}
}
}
/**
<summary>Gets/Sets whether to print the annotation when the page is printed.</summary>
*/
public bool Printable
{
get
{return (Flags & FlagsEnum.Print) == FlagsEnum.Print;}
set
{
FlagsEnum flags = Flags;
if(value)
{flags |= FlagsEnum.Print;}
else
{flags ^= FlagsEnum.Print;}
Flags = flags;
}
}
/**
<summary>Gets/Sets whether the annotation is visible.</summary>
*/
public bool Visible
{
get
{return (Flags & FlagsEnum.Hidden == 0);}
set
{
FlagsEnum flags = Flags;
if(value)
{flags ^= FlagsEnum.Hidden;}
else
{flags |= FlagsEnum.Hidden;}
Flags = flags;
}
}
#endregion
#endregion
#endregion
}
}
|