public PdfDocumentWriter(Stream stream, PdfDocumentOptions options = null)
        {
            // Initialize collections and object references:
            this.Xref         = new List <long>();
            this.Fonts        = new Dictionary <string, PdfObjectRef>();
            this.XObjects     = new Dictionary <string, PdfObjectRef>();
            this.XObjectsRev  = new Dictionary <PdfObjectRef, string>();
            this.ImageRatios  = new Dictionary <PdfObjectRef, double>();
            this.CatalogRef   = NewObjectRef();
            this.PagesRef     = NewObjectRef();
            this.ResourcesRef = NewObjectRef();
            this.InfoRef      = NewObjectRef();

            // Wrap the given stream in a Position-logging stream and build a StreamWriter:
            this.InnerWriter = new StreamWriter(new PositionStream(stream), Encoding.ASCII);

            // Make sure options are set:
            this.Options = options ?? new PdfDocumentOptions();

            // Write document introduction:
            this.WriteIntro();
        }
        /// <summary>
        /// Adds a PdfScriptObject to the page that draws an XObject.
        /// </summary>
        public static PdfObjectRef DrawXObjectRef(this PdfPageWriter page, double x, double y, PdfObjectRef xObjRef, double width)
        {
            var obj = new PdfScriptObject();

            obj.DrawExternalObject(page.DocumentWriter.GetNameOfXObject(xObjRef));
            return(page.WriteObject(obj));
        }
        /// <summary>
        /// Adds a PdfScriptObject to the page that draws an image previously added to the DocumentWriter,
        /// stretched to the given width and height.
        /// </summary>
        public static PdfObjectRef DrawImageRef(this PdfPageWriter page, double x, double y, PdfObjectRef imageRef, double width, double leftRotationDegrees = 0.0)
        {
            var obj = new PdfScriptObject();

            obj.DrawImageByName(x, y, width, page.DocumentWriter.GetImageHeight(imageRef, width), page.DocumentWriter.GetNameOfXObject(imageRef), leftRotationDegrees);
            return(page.WriteObject(obj));
        }
        /// <summary>
        /// Adds a PdfScriptObject to the page that draws an image previously added to the DocumentWriter,
        /// scaled to the given width and height.
        /// </summary>
        public static PdfObjectRef DrawImageRef(this PdfPageWriter page, double x, double y, PdfObjectRef imageRef, double width, double height, PdfImagePlacement imagePlacement, PdfImageRotation rotation = PdfImageRotation.None)
        {
            var width2  = width;
            var height2 = height;
            var xdelta  = 0.0;
            var ydelta  = 0.0;

            // Fix for rotations:
            if (rotation == PdfImageRotation.Left || rotation == PdfImageRotation.Right)
            {
                Swap(ref width2, ref height2);
            }
            imagePlacement = imagePlacement.Rotated(rotation);

            if (imagePlacement != PdfImagePlacement.Stretch)
            {
                // Calculate box aspect ratio and image aspect ratio:
                var boxar = height2 / width2;
                var imgar = page.DocumentWriter.GetImageHeight(imageRef, 1.0);

                if (imgar < boxar)
                {
                    var imgh = height2 / boxar * imgar;
                    switch (imagePlacement)
                    {
                    case PdfImagePlacement.LeftOrTop:
                    case PdfImagePlacement.RightOrTop:
                        ydelta = (height2 - imgh);
                        break;

                    case PdfImagePlacement.Center:
                        ydelta = (height2 - imgh) / 2.0;
                        break;
                    }
                    height2 = imgh;
                }
                else
                {
                    var imgw = width2 * boxar / imgar;
                    switch (imagePlacement)
                    {
                    case PdfImagePlacement.RightOrBottom:
                        xdelta = (width2 - imgw);
                        break;

                    case PdfImagePlacement.RightOrTop:
                        xdelta = (width2 - imgw);
                        break;

                    case PdfImagePlacement.Center:
                        xdelta = (width2 - imgw) / 2.0;
                        break;
                    }
                    width2 = imgw;
                }
            }

            // Correct for rotations:
            switch (rotation)
            {
            case PdfImageRotation.None: break;

            case PdfImageRotation.Left:
                Swap(ref xdelta, ref ydelta);
                xdelta = width - xdelta;
                break;

            case PdfImageRotation.Right:
                Swap(ref xdelta, ref ydelta);
                ydelta = height - ydelta;
                break;

            case PdfImageRotation.UpsideDown:
                xdelta = width - xdelta;
                ydelta = height - ydelta;
                break;
            }

            var obj = new PdfScriptObject();

            obj.DrawImageByName(x + xdelta, y + ydelta, width2, height2, page.DocumentWriter.GetNameOfXObject(imageRef), ((int)rotation) * 90.0);
            return(page.WriteObject(obj));
        }
        /// <summary>
        /// Writes a PdfObject to this document given its object reference.
        /// </summary>
        public virtual void WriteObject(PdfObject obj, PdfObjectRef objRef)
        {
            if (obj is PdfScriptObject)
            {
                foreach (var font in ((PdfScriptObject)obj).ReferencedFonts)
                {
                    RegisterFont(font);
                }
            }

            Xref[objRef.ObjectId - 1] = this.Position;

            var builder = new StringBuilder();

            builder.Append(objRef.ObjectId + " " + objRef.GenerationId + " obj\n");
            if (obj.Data != null || obj.Stream != null)
            {
                builder.Append("<<\n");
                if (obj.Data != null)
                {
                    foreach (var pair in obj.Data)
                    {
                        builder.Append('/');
                        builder.Append(pair.Key);
                        builder.Append(' ');
                        builder.Append(pair.Value.ToString());
                        builder.Append('\n');
                    }
                }
                if (obj.Stream == null)
                {
                    builder.Append(">>\n");
                }
                else if (obj.Stream is PdfBinaryStream)
                {
                    var s = ((PdfBinaryStream)obj.Stream);
                    builder.Append("/Length ");
                    builder.Append(s.Length);
                    builder.Append("\n/Filter [");
                    builder.Append(s.Filter);
                    builder.Append("]\n>>\n");
                    builder.Append("stream\n");

                    this.WriteRaw(builder.ToString());
                    builder.Length = 0;
                    this.WriteRaw(s.Content, 0, s.Content.Length);

                    builder.Append("\nendstream\n");
                }
                else
                {
                    byte[] bytes;
                    if ((obj.Stream is PdfTextStream) && (this.Options.TextFilter != null))
                    {
                        bytes = this.Options.TextFilter.EncodeString(((PdfTextStream)obj.Stream).Content.ToString());
                        builder.Append("/Filter [");
                        builder.Append(this.Options.TextFilter.Name);
                        builder.Append("]\n");
                    }
                    else
                    {
                        bytes = Encoding.Default.GetBytes(((PdfTextStream)obj.Stream).Content.ToString());
                    }
                    builder.Append("/Length ");
                    builder.Append(bytes.Length);
                    builder.Append('\n');

                    builder.Append(">>\n");

                    builder.Append("stream\n");

                    this.WriteRaw(builder.ToString());
                    builder.Length = 0;
                    this.WriteRaw(bytes, 0, bytes.Length);

                    builder.Append("\nendstream\n");
                }
            }
            builder.Append("endobj\n");

            this.WriteRaw(builder.ToString());
        }
 /// <summary>
 /// Returns the height the previoulsy added image should have, when rendered with the given width, in order to have
 /// the same aspect ration.
 /// </summary>
 /// <param name="imageRef">Reference to the image previoulsy added.</param>
 /// <param name="forWidth">Width to render the image with.</param>
 public double GetImageHeight(PdfObjectRef imageRef, double forWidth)
 {
     return(this.ImageRatios[imageRef] * forWidth);
 }
 public double GetImageAspectRatio(PdfObjectRef imageRef)
 {
     return(this.ImageRatios[imageRef]);
 }
 /// <summary>
 /// Retrieves the name of a previously added XObject.
 /// </summary>
 public string GetNameOfXObject(PdfObjectRef objRef)
 {
     return(this.XObjectsRev[objRef]);
 }
 protected void RegisterXObject(PdfObjectRef objRef, string name)
 {
     XObjects[name]      = objRef;
     XObjectsRev[objRef] = name;
 }
 /// <summary>
 /// Draws an image (convenience method).
 /// Assumes default naming of object references is used.
 /// </summary>
 public void DrawImageByRef2(double x1, double y1, double x2, double y2, PdfObjectRef imageRef)
 {
     this.DrawImageByName2(x1, y1, x2, y2, imageRef.ToDefaultName());
 }
 /// <summary>
 /// Draws an image (convenience method).
 /// Assumes default naming of object references is used.
 /// </summary>
 public void DrawImageByRef(double x, double y, double width, double height, PdfObjectRef imageRef)
 {
     this.DrawImageByName(x, y, width, height, imageRef.ToDefaultName());
 }
 /// <summary>
 /// Adds the object referenced by the given object reference to this page.
 /// </summary>
 public virtual void WriteObjectRef(PdfObjectRef objRef)
 {
     Content.Add(objRef);
 }