#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 System.Diagnostics;
using System.IO;
#if GDI
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
#endif
#if WPF
using System.Windows.Media;
#endif
using PdfSharp.Drawing.Pdf;
using PdfSharp.Pdf;
using PdfSharp.Pdf.Advanced;
using PdfSharp.Pdf.Filters;
namespace PdfSharp.Drawing
{
///
/// Represents a graphical object that can be used to render retained graphics on it.
/// In GDI+ it is represented by a Metafile, in WPF by a DrawingVisual, and in PDF by a Form XObjects.
///
public class XForm : XImage, IContentStream
{
internal enum FormState
{
///
/// The form is an imported PDF page.
///
NotATemplate,
///
/// The template is just created.
///
Created,
///
/// XGraphics.FromForm() was called.
///
UnderConstruction,
///
/// The form was drawn at least once and is 'frozen' now.
///
Finished,
}
///
/// Initializes a new instance of the class.
///
protected XForm()
{ }
#if GDI
///
/// Initializes a new instance of the XForm class such that it can be drawn on the specified graphics
/// object.
///
/// The graphics object that later is used to draw this form.
/// The size in points of the form.
public XForm(XGraphics gfx, XSize size)
{
if (gfx == null)
throw new ArgumentNullException("gfx");
if (size.Width < 1 || size.Height < 1)
throw new ArgumentNullException("size", "The size of the XPdfForm is to small.");
_formState = FormState.Created;
//templateSize = size;
_viewBox.Width = size.Width;
_viewBox.Height = size.Height;
// If gfx belongs to a PdfPage also create the PdfFormXObject
if (gfx.PdfPage != null)
{
_document = gfx.PdfPage.Owner;
_pdfForm = new PdfFormXObject(_document, this);
PdfRectangle rect = new PdfRectangle(new XPoint(), size);
_pdfForm.Elements.SetRectangle(PdfFormXObject.Keys.BBox, rect);
}
}
#endif
#if GDI
///
/// Initializes a new instance of the XForm class such that it can be drawn on the specified graphics
/// object.
///
/// The graphics object that later is used to draw this form.
/// The width of the form.
/// The height of the form.
public XForm(XGraphics gfx, XUnit width, XUnit height)
: this(gfx, new XSize(width, height))
{ }
#endif
///
/// Initializes a new instance of the class that represents a page of a PDF document.
///
/// The PDF document.
/// The view box of the page.
public XForm(PdfDocument document, XRect viewBox)
{
if (viewBox.Width < 1 || viewBox.Height < 1)
throw new ArgumentNullException("viewBox", "The size of the XPdfForm is to small.");
// I must tie the XPdfForm to a document immediately, because otherwise I would have no place where
// to store the resources.
if (document == null)
throw new ArgumentNullException("document", "An XPdfForm template must be associated with a document at creation time.");
_formState = FormState.Created;
_document = document;
_pdfForm = new PdfFormXObject(document, this);
//_templateSize = size;
_viewBox = viewBox;
PdfRectangle rect = new PdfRectangle(viewBox);
_pdfForm.Elements.SetRectangle(PdfFormXObject.Keys.BBox, rect);
}
///
/// Initializes a new instance of the class that represents a page of a PDF document.
///
/// The PDF document.
/// The size of the page.
public XForm(PdfDocument document, XSize size)
: this(document, new XRect(0, 0, size.Width, size.Height))
{
////if (size.width < 1 || size.height < 1)
//// throw new ArgumentNullException("size", "The size of the XPdfForm is to small.");
////// I must tie the XPdfForm to a document immediately, because otherwise I would have no place where
////// to store the resources.
////if (document == null)
//// throw new ArgumentNullException("document", "An XPdfForm template must be associated with a document.");
////_formState = FormState.Created;
////_document = document;
////pdfForm = new PdfFormXObject(document, this);
////templateSize = size;
////PdfRectangle rect = new PdfRectangle(new XPoint(), size);
////pdfForm.Elements.SetRectangle(PdfFormXObject.Keys.BBox, rect);
}
///
/// Initializes a new instance of the class that represents a page of a PDF document.
///
/// The PDF document.
/// The width of the page.
/// The height of the page
public XForm(PdfDocument document, XUnit width, XUnit height)
: this(document, new XRect(0, 0, width, height))
{ }
///
/// This function should be called when drawing the content of this form is finished.
/// The XGraphics object used for drawing the content is disposed by this function and
/// cannot be used for any further drawing operations.
/// PDFsharp automatically calls this function when this form was used the first time
/// in a DrawImage function.
///
public void DrawingFinished()
{
if (_formState == FormState.Finished)
return;
if (_formState == FormState.NotATemplate)
throw new InvalidOperationException("This object is an imported PDF page and you cannot finish drawing on it because you must not draw on it at all.");
Finish();
}
///
/// Called from XGraphics constructor that creates an instance that work on this form.
///
internal void AssociateGraphics(XGraphics gfx)
{
if (_formState == FormState.NotATemplate)
throw new NotImplementedException("The current version of PDFsharp cannot draw on an imported page.");
if (_formState == FormState.UnderConstruction)
throw new InvalidOperationException("An XGraphics object already exists for this form.");
if (_formState == FormState.Finished)
throw new InvalidOperationException("After drawing a form it cannot be modified anymore.");
Debug.Assert(_formState == FormState.Created);
_formState = FormState.UnderConstruction;
Gfx = gfx;
}
internal XGraphics Gfx;
///
/// Disposes this instance.
///
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
}
///
/// Sets the form in the state FormState.Finished.
///
internal virtual void Finish()
{
#if GDI
if (_formState == FormState.NotATemplate || _formState == FormState.Finished)
return;
if (Gfx.Metafile != null)
_gdiImage = Gfx.Metafile;
Debug.Assert(_formState == FormState.Created || _formState == FormState.UnderConstruction);
_formState = FormState.Finished;
Gfx.Dispose();
Gfx = null;
if (PdfRenderer != null)
{
//pdfForm.CreateStream(PdfEncoders.RawEncoding.GetBytes(PdfRenderer.GetContent()));
PdfRenderer.Close();
Debug.Assert(PdfRenderer == null);
if (_document.Options.CompressContentStreams)
{
_pdfForm.Stream.Value = Filtering.FlateDecode.Encode(_pdfForm.Stream.Value, _document.Options.FlateEncodeMode);
_pdfForm.Elements["/Filter"] = new PdfName("/FlateDecode");
}
int length = _pdfForm.Stream.Length;
_pdfForm.Elements.SetInteger("/Length", length);
}
#endif
#if WPF
#endif
}
///
/// Gets the owning document.
///
internal PdfDocument Owner
{
get { return _document; }
}
PdfDocument _document;
///
/// Gets the color model used in the underlying PDF document.
///
internal PdfColorMode ColorMode
{
get
{
if (_document == null)
return PdfColorMode.Undefined;
return _document.Options.ColorMode;
}
}
///
/// Gets a value indicating whether this instance is a template.
///
internal bool IsTemplate
{
get { return _formState != FormState.NotATemplate; }
}
internal FormState _formState;
///
/// Get the width of the page identified by the property PageNumber.
///
[Obsolete("Use either PixelWidth or PointWidth. Temporarily obsolete because of rearrangements for WPF. Currently same as PixelWidth, but will become PointWidth in future releases of PDFsharp.")]
public override double Width
{
//get { return templateSize.width; }
get { return _viewBox.Width; }
}
///
/// Get the width of the page identified by the property PageNumber.
///
[Obsolete("Use either PixelHeight or PointHeight. Temporarily obsolete because of rearrangements for WPF. Currently same as PixelHeight, but will become PointHeight in future releases of PDFsharp.")]
public override double Height
{
//get { return templateSize.height; }
get { return _viewBox.Height; }
}
///
/// Get the width in point of this image.
///
public override double PointWidth
{
//get { return templateSize.width; }
get { return _viewBox.Width; }
}
///
/// Get the height in point of this image.
///
public override double PointHeight
{
//get { return templateSize.height; }
get { return _viewBox.Height; }
}
///
/// Get the width of the page identified by the property PageNumber.
///
public override int PixelWidth
{
//get { return (int)templateSize.width; }
get { return (int)_viewBox.Width; }
}
///
/// Get the height of the page identified by the property PageNumber.
///
public override int PixelHeight
{
//get { return (int)templateSize.height; }
get { return (int)_viewBox.Height; }
}
///
/// Get the size of the page identified by the property PageNumber.
///
public override XSize Size
{
//get { return templateSize; }
get { return _viewBox.Size; }
}
//XSize templateSize;
///
/// Gets the view box of the form.
///
public XRect ViewBox
{
get { return _viewBox; }
}
XRect _viewBox;
///
/// Gets 72, the horizontal resolution by design of a form object.
///
public override double HorizontalResolution
{
get { return 72; }
}
///
/// Gets 72 always, the vertical resolution by design of a form object.
///
public override double VerticalResolution
{
get { return 72; }
}
///
/// Gets or sets the bounding box.
///
public XRect BoundingBox
{
get { return _boundingBox; }
set { _boundingBox = value; } // TODO: pdfForm = null
}
XRect _boundingBox;
///
/// Gets or sets the transformation matrix.
///
public virtual XMatrix Transform
{
get { return _transform; }
set
{
if (_formState == FormState.Finished)
throw new InvalidOperationException("After a XPdfForm was once drawn it must not be modified.");
_transform = value;
}
}
internal XMatrix _transform;
internal PdfResources Resources
{
get
{
Debug.Assert(IsTemplate, "This function is for form templates only.");
return PdfForm.Resources;
//if (resources == null)
// resources = (PdfResources)pdfForm.Elements.GetValue(PdfFormXObject.Keys.Resources, VCF.Create); // VCF.CreateIndirect
//return resources;
}
}
//PdfResources resources;
///
/// Implements the interface because the primary function is internal.
///
PdfResources IContentStream.Resources
{
get { return Resources; }
}
///
/// Gets the resource name of the specified font within this form.
///
internal string GetFontName(XFont font, out PdfFont pdfFont)
{
Debug.Assert(IsTemplate, "This function is for form templates only.");
pdfFont = _document.FontTable.GetFont(font);
Debug.Assert(pdfFont != null);
string name = Resources.AddFont(pdfFont);
return name;
}
string IContentStream.GetFontName(XFont font, out PdfFont pdfFont)
{
return GetFontName(font, out pdfFont);
}
///
/// Tries to get the resource name of the specified font data within this form.
/// Returns null if no such font exists.
///
internal string TryGetFontName(string idName, out PdfFont pdfFont)
{
Debug.Assert(IsTemplate, "This function is for form templates only.");
pdfFont = _document.FontTable.TryGetFont(idName);
string name = null;
if (pdfFont != null)
name = Resources.AddFont(pdfFont);
return name;
}
///
/// Gets the resource name of the specified font data within this form.
///
internal string GetFontName(string idName, byte[] fontData, out PdfFont pdfFont)
{
Debug.Assert(IsTemplate, "This function is for form templates only.");
pdfFont = _document.FontTable.GetFont(idName, fontData);
//pdfFont = new PdfType0Font(Owner, idName, fontData);
//pdfFont.Document = _document;
Debug.Assert(pdfFont != null);
string name = Resources.AddFont(pdfFont);
return name;
}
string IContentStream.GetFontName(string idName, byte[] fontData, out PdfFont pdfFont)
{
return GetFontName(idName, fontData, out pdfFont);
}
///
/// Gets the resource name of the specified image within this form.
///
internal string GetImageName(XImage image)
{
Debug.Assert(IsTemplate, "This function is for form templates only.");
PdfImage pdfImage = _document.ImageTable.GetImage(image);
Debug.Assert(pdfImage != null);
string name = Resources.AddImage(pdfImage);
return name;
}
///
/// Implements the interface because the primary function is internal.
///
string IContentStream.GetImageName(XImage image)
{
return GetImageName(image);
}
internal PdfFormXObject PdfForm
{
get
{
Debug.Assert(IsTemplate, "This function is for form templates only.");
if (_pdfForm.Reference == null)
_document._irefTable.Add(_pdfForm);
return _pdfForm;
}
}
///
/// Gets the resource name of the specified form within this form.
///
internal string GetFormName(XForm form)
{
Debug.Assert(IsTemplate, "This function is for form templates only.");
PdfFormXObject pdfForm = _document.FormTable.GetForm(form);
Debug.Assert(pdfForm != null);
string name = Resources.AddForm(pdfForm);
return name;
}
///
/// Implements the interface because the primary function is internal.
///
string IContentStream.GetFormName(XForm form)
{
return GetFormName(form);
}
///
/// The PdfFormXObject gets invalid when PageNumber or transform changed. This is because a modification
/// of an XPdfForm must not change objects that are already been drawn.
///
internal PdfFormXObject _pdfForm; // TODO: make private
internal XGraphicsPdfRenderer PdfRenderer;
#if WPF && !SILVERLIGHT
///
/// Gets a value indicating whether this image is cmyk.
///
/// true if this image is cmyk; otherwise, false.
internal override bool IsCmyk
{
get { return false; } // not supported and not relevant
}
///
/// Gets a value indicating whether this image is JPEG.
///
/// true if this image is JPEG; otherwise, false.
internal override bool IsJpeg
{
get { return base.IsJpeg; }// not supported and not relevant
}
///
/// Gets the JPEG memory stream (if IsJpeg returns true).
///
/// The memory.
public override MemoryStream Memory
{
get { throw new NotImplementedException(); }
}
#endif
}
}