#region PDFsharp - A .NET library for processing PDF
//
// Authors:
// Stefan Lange
//
// Copyright (c) 2005-2017 empira Software GmbH, Cologne Area (Germany)
//
// http://www.pdfsharp.com
// http://sourceforge.net/projects/pdfsharp
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
#endregion
using System;
using PdfSharp.Pdf.IO;
using PdfSharp.Pdf.Internal;
namespace PdfSharp.Pdf.Annotations
{
///
/// Represents a link annotation.
///
public sealed class PdfLinkAnnotation : PdfAnnotation
{
// Just a hack to make MigraDoc work with this code.
enum LinkType
{
None, Document, Web, File
}
///
/// Initializes a new instance of the class.
///
public PdfLinkAnnotation()
{
_linkType = LinkType.None;
Elements.SetName(PdfAnnotation.Keys.Subtype, "/Link");
}
///
/// Initializes a new instance of the class.
///
public PdfLinkAnnotation(PdfDocument document)
: base(document)
{
_linkType = LinkType.None;
Elements.SetName(PdfAnnotation.Keys.Subtype, "/Link");
}
///
/// Creates a link within the current document.
///
/// The link area in default page coordinates.
/// The one-based destination page number.
public static PdfLinkAnnotation CreateDocumentLink(PdfRectangle rect, int destinationPage)
{
if (destinationPage < 1)
throw new ArgumentException("Invalid destination page in call to CreateDocumentLink: page number is one-based and must be 1 or higher.", "destinationPage");
PdfLinkAnnotation link = new PdfLinkAnnotation();
link._linkType = LinkType.Document;
link.Rectangle = rect;
link._destPage = destinationPage;
return link;
}
int _destPage;
LinkType _linkType;
string _url;
///
/// Creates a link to the web.
///
public static PdfLinkAnnotation CreateWebLink(PdfRectangle rect, string url)
{
PdfLinkAnnotation link = new PdfLinkAnnotation();
link._linkType = PdfLinkAnnotation.LinkType.Web;
link.Rectangle = rect;
link._url = url;
return link;
}
///
/// Creates a link to a file.
///
public static PdfLinkAnnotation CreateFileLink(PdfRectangle rect, string fileName)
{
PdfLinkAnnotation link = new PdfLinkAnnotation();
link._linkType = LinkType.File;
// TODO: Adjust bleed box here (if possible)
link.Rectangle = rect;
link._url = fileName;
return link;
}
internal override void WriteObject(PdfWriter writer)
{
PdfPage dest = null;
//pdf.AppendFormat(CultureInfo.InvariantCulture,
// "{0} 0 obj\n<<\n/Type/Annot\n/Subtype/Link\n" +
// "/Rect[{1} {2} {3} {4}]\n/BS<>\n/Border[0 0 0]\n/C[0 0 0]\n",
// ObjectID.ObjectNumber, rect.X1, rect.Y1, rect.X2, rect.Y2);
// Older Adobe Reader versions uses a border width of 0 as default value if neither Border nor BS are present.
// But the PDF Reference specifies:
// "If neither the Border nor the BS entry is present, the border is drawn as a solid line with a width of 1 point."
// After this issue was fixed in newer Reader versions older PDFsharp created documents show an ugly solid border.
// The following hack fixes this by specifying a 0 width border.
if (Elements[PdfAnnotation.Keys.BS] == null)
Elements[PdfAnnotation.Keys.BS] = new PdfLiteral("<>");
// May be superfluous. See comment above.
if (Elements[PdfAnnotation.Keys.Border] == null)
Elements[PdfAnnotation.Keys.Border] = new PdfLiteral("[0 0 0]");
switch (_linkType)
{
case LinkType.None:
break;
case LinkType.Document:
// destIndex > Owner.PageCount can happen when rendering pages using PDFsharp directly.
int destIndex = _destPage;
if (destIndex > Owner.PageCount)
destIndex = Owner.PageCount;
destIndex--;
dest = Owner.Pages[destIndex];
//pdf.AppendFormat("/Dest[{0} 0 R/XYZ null null 0]\n", dest.ObjectID);
Elements[Keys.Dest] = new PdfLiteral("[{0} 0 R/XYZ null null 0]", dest.ObjectNumber);
break;
case LinkType.Web:
//pdf.AppendFormat("/A<>\n", PdfEncoders.EncodeAsLiteral(url));
Elements[PdfAnnotation.Keys.A] = new PdfLiteral("<>", //PdfEncoders.EncodeAsLiteral(url));
PdfEncoders.ToStringLiteral(_url, PdfStringEncoding.WinAnsiEncoding, writer.SecurityHandler));
break;
case LinkType.File:
//pdf.AppendFormat("/A<> >>\n",
// PdfEncoders.EncodeAsLiteral(url));
Elements[PdfAnnotation.Keys.A] = new PdfLiteral("<> >>",
//PdfEncoders.EncodeAsLiteral(url));
PdfEncoders.ToStringLiteral(_url, PdfStringEncoding.WinAnsiEncoding, writer.SecurityHandler));
break;
}
base.WriteObject(writer);
}
///
/// Predefined keys of this dictionary.
///
internal new class Keys : PdfAnnotation.Keys
{
// ///
// /// (Required) The type of annotation that this dictionary describes;
// /// must be Link for a link annotation.
// ///
// inherited from base class
///
/// (Optional; not permitted if an A entry is present) A destination to be displayed
/// when the annotation is activated.
///
[KeyInfo(KeyType.ArrayOrNameOrString | KeyType.Optional)]
public const string Dest = "/Dest";
///
/// (Optional; PDF 1.2) The annotation’s highlighting mode, the visual effect to be
/// used when the mouse button is pressed or held down inside its active area:
/// N (None) No highlighting.
/// I (Invert) Invert the contents of the annotation rectangle.
/// O (Outline) Invert the annotation’s border.
/// P (Push) Display the annotation as if it were being pushed below the surface of the page.
/// Default value: I.
/// Note: In PDF 1.1, highlighting is always done by inverting colors inside the annotation rectangle.
///
[KeyInfo("1.2", KeyType.Name | KeyType.Optional)]
public const string H = "/H";
///
/// (Optional; PDF 1.3) A URI action formerly associated with this annotation. When Web
/// Capture changes and annotation from a URI to a go-to action, it uses this entry to save
/// the data from the original URI action so that it can be changed back in case the target page for
/// the go-to action is subsequently deleted.
///
[KeyInfo("1.3", KeyType.Dictionary | KeyType.Optional)]
public const string PA = "/PA";
// QuadPoints
///
/// Gets the KeysMeta for these keys.
///
public static DictionaryMeta Meta
{
get { return _meta ?? (_meta = CreateMeta(typeof(Keys))); }
}
static DictionaryMeta _meta;
}
///
/// Gets the KeysMeta of this dictionary type.
///
internal override DictionaryMeta Meta
{
get { return Keys.Meta; }
}
}
}