/// <summary>
        /// Adds the image to the pdf document
        /// </summary>
        /// <param name="document">The document to annotate</param>
        /// <param name="imageDocument">The image document</param>
        public void AddImageToPdfDocument(Document document, Document imageDocument)
        {
            // Get image information
            var documentTypeImageCoOrdinates = document.Type.DocumentTypeImageCoOrdinates.FirstOrDefault(e => e.ImageDocumentType.Id == imageDocument.Type.Id);

            if (documentTypeImageCoOrdinates == null)
            {
                return;
            }

            // Create a pdf reader to read the document content, and a pdf stamper to modify it and output to a memory stream
            var reader  = new PdfReader(document.LatestRevision.Content.Content);
            var oStream = new MemoryStream();
            var stamper = new PdfStamper(reader, oStream);

            // Get the image page of the PDF document object
            var pdfContentByte = stamper.GetOverContent(documentTypeImageCoOrdinates.PageNumber);

            // Create a white rectangle bitmap for the background image
            var bitmap = new Bitmap(documentTypeImageCoOrdinates.MaxWidth, documentTypeImageCoOrdinates.MaxHeight);

            using (var graphics = Graphics.FromImage(bitmap))
            {
                var rectangle = new System.Drawing.Rectangle(0, 0, documentTypeImageCoOrdinates.MaxWidth, documentTypeImageCoOrdinates.MaxHeight);
                graphics.FillRectangle(Brushes.White, rectangle);
            }

            // Draw the background image onto the pdf to clear any previous image
            var image = Image.GetInstance(bitmap, ImageFormat.Bmp);

            image.SetAbsolutePosition(documentTypeImageCoOrdinates.OriginX, documentTypeImageCoOrdinates.OriginY);
            pdfContentByte.AddImage(image);

            // Draw the image onto the pdf
            image = Image.GetInstance(imageDocument.LatestRevision.Content.Content);
            image.ScaleToFit(documentTypeImageCoOrdinates.MaxWidth, documentTypeImageCoOrdinates.MaxHeight);
            var differenceX = documentTypeImageCoOrdinates.MaxWidth - image.ScaledWidth;
            var differenceY = documentTypeImageCoOrdinates.MaxHeight - image.ScaledHeight;

            image.SetAbsolutePosition(
                differenceX > 0 ? documentTypeImageCoOrdinates.OriginX + (differenceX / 2) : documentTypeImageCoOrdinates.OriginX,
                differenceY > 0 ? documentTypeImageCoOrdinates.OriginY + (differenceY / 2) : documentTypeImageCoOrdinates.OriginY
                );
            pdfContentByte.AddImage(image);

            // Close the pdf stamper to flush the output memory stream
            stamper.Writer.CloseStream = false;
            stamper.Close();

            // Move the stream position to the beginning
            oStream.Seek(0, SeekOrigin.Begin);

            // Update content, length and checksum
            var content = oStream.ToArray();

            document.LatestRevision.Content.Content      = content;
            document.LatestRevision.Content.FileChecksum = GenerateFileChecksum(content);
            document.LatestRevision.Bytes = content.Length;
        }
        /// <summary>
        /// Sets the value of the specified form field in the pdf document
        /// </summary>
        /// <param name="document">The document in which to set the form field</param>
        /// <param name="fieldName">The name of the field to set</param>
        /// <param name="value">The value to set the field to</param>
        /// <returns>The content of the annotated document as a byte array</returns>
        public void SetPdfFormField(Document document, string fieldName, string value)
        {
            // Update content, length and checksum
            var content = SetPdfFormField(document.LatestRevision.Content.Content, fieldName, value);

            document.LatestRevision.Content.Content      = content;
            document.LatestRevision.Content.FileChecksum = GenerateFileChecksum(content);
            document.LatestRevision.Bytes = content.Length;
        }
        /// <summary>
        /// Converts the Word document located at the specified file path to its pdf equivalent
        /// </summary>
        /// <param name="document">The Word document to be converted</param>
        /// <param name="workingDirectory">The directory to temporarily save the word and pdf documents to during the conversion process</param>
        /// <param name="domain">The domain of the network credentials to use when connecting to the <paramref name="workingDirectory"/></param>
        /// <param name="userName">The username of the network credentials to use when connecting to the <paramref name="workingDirectory"/></param>
        /// <param name="password">The password of the network credentials to use when connecting to the <paramref name="workingDirectory"/></param>
        /// <returns>The converted pdf document</returns>
        public Document ConvertWordToPdf(Document document, string workingDirectory, string domain, string userName, string password)
        {
            var impersonationContext = CreateImpersonationContext(domain, userName, password);

            // If the working directory does not exist, attempt to create it
            if (!Directory.Exists(workingDirectory))
            {
                Directory.CreateDirectory(workingDirectory);
            }

            // Create a new Microsoft Word application object
            var application = new Application {
                Visible = false, ScreenUpdating = false
            };

            // C# doesn't have optional arguments, so we create a dummy value to pass in for these
            object oMissing = System.Reflection.Missing.Value;

            // Ideally this would be done in memory and would not touch the file system,
            // however because we have to use the Microsoft.Word.Interop library we have no choice

            // Construct the full file paths for the temporary Word and pdf documents in the working directory
            var filePathWord = Path.Combine(workingDirectory, document.LatestRevision.FileName);
            var filePathPdf  = Path.ChangeExtension(filePathWord, "pdf");
            // Cast the file paths to an object for the Word application Open and SaveAs methods
            var filePathWordObject = (object)filePathWord;
            var filePathPdfObject  = (object)filePathPdf;

            // Write the temporary Word document to the working directory
            var tmpFileStream = File.OpenWrite(filePathWord);

            tmpFileStream.Write(document.LatestRevision.Content.Content, 0, document.LatestRevision.Content.Content.Length);
            tmpFileStream.Close();

            // Create the document object in memory by loading the file from the file system
            // Use the dummy value as a placeholder for optional arguments
            var wordDocumentObject = application.Documents.Open(ref filePathWordObject, ref oMissing,
                                                                ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing,
                                                                ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing,
                                                                ref oMissing, ref oMissing, ref oMissing, ref oMissing);

            wordDocumentObject.Activate();

            // Save the document in pdf format
            object fileFormat = WdSaveFormat.wdFormatPDF;

            wordDocumentObject.SaveAs(ref filePathPdfObject,
                                      ref fileFormat, ref oMissing, ref oMissing,
                                      ref oMissing, ref oMissing, ref oMissing, ref oMissing,
                                      ref oMissing, ref oMissing, ref oMissing, ref oMissing,
                                      ref oMissing, ref oMissing, ref oMissing, ref oMissing);

            // Close the Word document, but leave the Word application open
            // The document object has to be cast to type _Document so that it will find the correct Close method
            object saveChanges = WdSaveOptions.wdDoNotSaveChanges;

            ((_Document)wordDocumentObject).Close(ref saveChanges, ref oMissing, ref oMissing);
            wordDocumentObject = null;

            // The Microsoft Word application object has to be cast to type _Application so that it will find the correct Quit method
            ((_Application)application).Quit(ref oMissing, ref oMissing, ref oMissing);
            application = null;

            // Read the converted pdf document data into memory
            byte[] fileData;
            using (var memoryStream = new MemoryStream())
                using (var fileStream = new FileStream(filePathPdf, FileMode.Open, FileAccess.Read))
                {
                    fileData = new byte[fileStream.Length];
                    fileStream.Read(fileData, 0, (int)fileStream.Length);
                    memoryStream.Write(fileData, 0, (int)fileStream.Length);
                }

            // Form the pdf Document domain object to return
            var documentReturn = new Document
            {
                Type        = document.Type,
                Description = Path.GetFileNameWithoutExtension(filePathPdf),
                Revisions   = new HashSet <DocumentRevisionMetaData>()
            };
            var documentMetaData = new DocumentRevisionMetaData(documentReturn)
            {
                DisplayName      = Path.GetFileNameWithoutExtension(filePathPdf),
                FileName         = Path.GetFileName(filePathPdf),
                MimeType         = "application/pdf",
                CreatedDateUtc   = SystemTime.UtcNow(),
                PublishedDateUtc = SystemTime.UtcNow(),
                Bytes            = fileData.Length,
                Content          = new DocumentRevisionContent {
                    Content = fileData
                },
            };

            documentReturn.Revisions.Add(documentMetaData);

            // Finally, clean up any temporary files created in the conversion process
            DeleteFile(filePathWord, domain, userName, password);
            DeleteFile(filePathPdf, domain, userName, password);

            UndoImpersonationContext(impersonationContext);

            return(documentReturn);
        }