internal PdfFormXObject(PdfDocument thisDocument, PdfImportedObjectTable importedObjectTable, XPdfForm form) : base(thisDocument) { Debug.Assert(importedObjectTable != null); Debug.Assert(ReferenceEquals(thisDocument, importedObjectTable.Owner)); Elements.SetName(Keys.Type, "/XObject"); Elements.SetName(Keys.Subtype, "/Form"); if (form.IsTemplate) { Debug.Assert(importedObjectTable == null); // TODO more initialization here??? return; } XPdfForm pdfForm = form; // Get import page PdfPages importPages = importedObjectTable.ExternalDocument.Pages; if (pdfForm.PageNumber < 1 || pdfForm.PageNumber > importPages.Count) { PSSR.ImportPageNumberOutOfRange(pdfForm.PageNumber, importPages.Count, form._path); } PdfPage importPage = importPages[pdfForm.PageNumber - 1]; // Import resources PdfItem res = importPage.Elements["/Resources"]; if (res != null) // unlikely but possible { #if true // Get root object PdfObject root; if (res is PdfReference) { root = ((PdfReference)res).Value; } else { root = (PdfDictionary)res; } root = ImportClosure(importedObjectTable, thisDocument, root); // If the root was a direct object, make it indirect. if (root.Reference == null) { thisDocument._irefTable.Add(root); } Debug.Assert(root.Reference != null); Elements["/Resources"] = root.Reference; #else // Get transitive closure PdfObject[] resources = importPage.Owner.Internals.GetClosure(resourcesRoot); int count = resources.Length; #if DEBUG_ for (int idx = 0; idx < count; idx++) { Debug.Assert(resources[idx].XRef != null); Debug.Assert(resources[idx].XRef.Document != null); Debug.Assert(resources[idx].Document != null); if (resources[idx].ObjectID.ObjectNumber == 12) { GetType(); } } #endif // 1st step. Already imported objects are reused and new ones are cloned. for (int idx = 0; idx < count; idx++) { PdfObject obj = resources[idx]; if (importedObjectTable.Contains(obj.ObjectID)) { // external object was already imported PdfReference iref = importedObjectTable[obj.ObjectID]; Debug.Assert(iref != null); Debug.Assert(iref.Value != null); Debug.Assert(iref.Document == Owner); // replace external object by the already clone counterpart resources[idx] = iref.Value; } else { // External object was not imported ealier and must be cloned PdfObject clone = obj.Clone(); Debug.Assert(clone.Reference == null); clone.Document = Owner; if (obj.Reference != null) { // add it to this (the importer) document Owner.irefTable.Add(clone); Debug.Assert(clone.Reference != null); // save old object identifier importedObjectTable.Add(obj.ObjectID, clone.Reference); //Debug.WriteLine("Cloned: " + obj.ObjectID.ToString()); } else { // The root object (the /Resources value) is not an indirect object Debug.Assert(idx == 0); // add it to this (the importer) document Owner.irefTable.Add(clone); Debug.Assert(clone.Reference != null); } // replace external object by its clone resources[idx] = clone; } } #if DEBUG_ for (int idx = 0; idx < count; idx++) { Debug.Assert(resources[idx].XRef != null); Debug.Assert(resources[idx].XRef.Document != null); Debug.Assert(resources[idx].Document != null); if (resources[idx].ObjectID.ObjectNumber == 12) { GetType(); } } #endif // 2nd step. Fix up indirect references that still refers to the import document. for (int idx = 0; idx < count; idx++) { PdfObject obj = resources[idx]; Debug.Assert(obj.Owner != null); FixUpObject(importedObjectTable, importedObjectTable.Owner, obj); } // Set resources key to the root of the clones Elements["/Resources"] = resources[0].Reference; #endif } // Take /Rotate into account PdfRectangle rect = importPage.Elements.GetRectangle(PdfPage.Keys.MediaBox); int rotate = importPage.Elements.GetInteger(PdfPage.Keys.Rotate); //rotate = 0; if (rotate == 0) { // Set bounding box to media box Elements["/BBox"] = rect; } else { // TODO: Have to adjust bounding box? (I think not, but I'm not sure -> wait for problem) Elements["/BBox"] = rect; // Rotate the image such that it is upright XMatrix matrix = new XMatrix(); double width = rect.Width; double height = rect.Height; matrix.RotateAtPrepend(-rotate, new XPoint(width / 2, height / 2)); if (rotate != 180) { // Translate the image such that its center lies on the center of the rotated bounding box double offset = (height - width) / 2; if (height > width) { matrix.TranslatePrepend(offset, offset); } else { matrix.TranslatePrepend(-offset, -offset); } } //string item = "[" + PdfEncoders.ToString(matrix) + "]"; //Elements[Keys.Matrix] = new PdfLiteral(item); Elements.SetMatrix(Keys.Matrix, matrix); } // Preserve filter because the content keeps unmodified PdfContent content = importPage.Contents.CreateSingleContent(); #if !DEBUG content.Compressed = true; #endif PdfItem filter = content.Elements["/Filter"]; if (filter != null) { Elements["/Filter"] = filter.Clone(); } // (no cloning needed because the bytes keep untouched) Stream = content.Stream; // new PdfStream(bytes, this); Elements.SetInteger("/Length", content.Stream.Value.Length); }
/// <summary> /// Opens an existing PDF document. /// </summary> public static PdfDocument Open(Stream stream, string password, PdfDocumentOpenMode openmode, PdfPasswordProvider passwordProvider) { PdfDocument document = null; try { Lexer lexer = new Lexer(stream); document = new PdfDocument(lexer); document.state |= DocumentState.Imported; document.openMode = openmode; document.fileSize = stream.Length; // Get file version byte[] header = new byte[1024]; stream.Position = 0; stream.Read(header, 0, 1024); document.version = GetPdfFileVersion(header); if (document.version == 0) { throw new InvalidOperationException(PSSR.InvalidPdf); } // Read all trailers document.irefTable.IsUnderConstruction = true; Parser parser = new Parser(document); document.trailer = parser.ReadTrailer(); document.irefTable.IsUnderConstruction = false; // Is document encrypted? PdfReference xrefEncrypt = document.trailer.Elements[PdfTrailer.Keys.Encrypt] as PdfReference; if (xrefEncrypt != null) { //xrefEncrypt.Value = parser.ReadObject(null, xrefEncrypt.ObjectID, false); PdfObject encrypt = parser.ReadObject(null, xrefEncrypt.ObjectID, false); encrypt.Reference = xrefEncrypt; xrefEncrypt.Value = encrypt; PdfStandardSecurityHandler securityHandler = document.SecurityHandler; TryAgain: PasswordValidity validity = securityHandler.ValidatePassword(password); if (validity == PasswordValidity.Invalid) { if (passwordProvider != null) { PdfPasswordProviderArgs args = new PdfPasswordProviderArgs(); passwordProvider(args); if (args.Abort) { return(null); } password = args.Password; goto TryAgain; } else { if (password == null) { throw new PdfReaderException(PSSR.PasswordRequired); } else { throw new PdfReaderException(PSSR.InvalidPassword); } } } else if (validity == PasswordValidity.UserPassword && openmode == PdfDocumentOpenMode.Modify) { if (passwordProvider != null) { PdfPasswordProviderArgs args = new PdfPasswordProviderArgs(); passwordProvider(args); if (args.Abort) { return(null); } password = args.Password; goto TryAgain; } else { throw new PdfReaderException(PSSR.OwnerPasswordRequired); } } } else { if (password != null) { // Password specified but document is not encrypted. // ignore } } PdfReference[] irefs = document.irefTable.AllReferences; int count = irefs.Length; // Read all indirect objects for (int idx = 0; idx < count; idx++) { PdfReference iref = irefs[idx]; if (iref.Value == null) { try { Debug.Assert(document.irefTable.Contains(iref.ObjectID)); PdfObject pdfObject = parser.ReadObject(null, iref.ObjectID, false); Debug.Assert(pdfObject.Reference == iref); pdfObject.Reference = iref; Debug.Assert(pdfObject.Reference.Value != null, "something got wrong"); } catch (Exception ex) { Debug.WriteLine(ex.Message); } } else { Debug.Assert(document.irefTable.Contains(iref.ObjectID)); iref.GetType(); } // Set maximum object number document.irefTable.maxObjectNumber = Math.Max(document.irefTable.maxObjectNumber, iref.ObjectNumber); } // Encrypt all objects if (xrefEncrypt != null) { document.SecurityHandler.EncryptDocument(); } // Fix references of trailer values and then objects and irefs are consistent. document.trailer.Finish(); #if DEBUG_ // Some tests... PdfReference[] reachables = document.xrefTable.TransitiveClosure(document.trailer); reachables.GetType(); reachables = document.xrefTable.AllXRefs; document.xrefTable.CheckConsistence(); #endif if (openmode == PdfDocumentOpenMode.Modify) { // Create new or change existing document IDs if (document.Internals.SecondDocumentID == "") { document.trailer.CreateNewDocumentIDs(); } else { byte[] agTemp = Guid.NewGuid().ToByteArray(); document.Internals.SecondDocumentID = PdfEncoders.RawEncoding.GetString(agTemp, 0, agTemp.Length); } // Change modification date document.Info.ModificationDate = DateTime.Now; // Remove all unreachable objects int removed = document.irefTable.Compact(); if (removed != 0) { Debug.WriteLine("Number of deleted unreachable objects: " + removed.ToString()); } // Force flattening of page tree PdfPages pages = document.Pages; //bool b = document.irefTable.Contains(new PdfObjectID(1108)); //b.GetType(); document.irefTable.CheckConsistence(); document.irefTable.Renumber(); document.irefTable.CheckConsistence(); } } finally { //if (filestream != null) // filestream.Close(); } return(document); }
/// <summary> /// Opens an existing PDF document. /// </summary> public static PdfDocument Open(Stream stream, string password, PdfDocumentOpenMode openmode, PdfPasswordProvider passwordProvider) { PdfDocument document; try { Lexer lexer = new Lexer(stream); document = new PdfDocument(lexer); document._state |= DocumentState.Imported; document._openMode = openmode; document._fileSize = stream.Length; // Get file version. byte[] header = new byte[1024]; stream.Position = 0; stream.Read(header, 0, 1024); document._version = GetPdfFileVersion(header); if (document._version == 0) { throw new InvalidOperationException(PSSR.InvalidPdf); } document._irefTable.IsUnderConstruction = true; Parser parser = new Parser(document); // Read all trailers or cross-reference streams, but no objects. document._trailer = parser.ReadTrailer(); if (document._trailer == null) { ParserDiagnostics.ThrowParserException("Invalid PDF file: no trailer found."); // TODO L10N using PSSR. } Debug.Assert(document._irefTable.IsUnderConstruction); document._irefTable.IsUnderConstruction = false; // Is document encrypted? PdfReference xrefEncrypt = document._trailer.Elements[PdfTrailer.Keys.Encrypt] as PdfReference; if (xrefEncrypt != null) { //xrefEncrypt.Value = parser.ReadObject(null, xrefEncrypt.ObjectID, false); PdfObject encrypt = parser.ReadObject(null, xrefEncrypt.ObjectID, false, false); encrypt.Reference = xrefEncrypt; xrefEncrypt.Value = encrypt; PdfStandardSecurityHandler securityHandler = document.SecurityHandler; TryAgain: PasswordValidity validity = securityHandler.ValidatePassword(password); if (validity == PasswordValidity.Invalid) { if (passwordProvider != null) { PdfPasswordProviderArgs args = new PdfPasswordProviderArgs(); passwordProvider(args); if (args.Abort) { return(null); } password = args.Password; goto TryAgain; } else { if (password == null) { throw new PdfReaderException(PSSR.PasswordRequired); } else { throw new PdfReaderException(PSSR.InvalidPassword); } } } else if (validity == PasswordValidity.UserPassword && openmode == PdfDocumentOpenMode.Modify) { if (passwordProvider != null) { PdfPasswordProviderArgs args = new PdfPasswordProviderArgs(); passwordProvider(args); if (args.Abort) { return(null); } password = args.Password; goto TryAgain; } else { throw new PdfReaderException(PSSR.OwnerPasswordRequired); } } } else { if (password != null) { // Password specified but document is not encrypted. // ignore } } PdfReference[] irefs2 = document._irefTable.AllReferences; int count2 = irefs2.Length; // 3rd: Create iRefs for all compressed objects. Dictionary <int, object> objectStreams = new Dictionary <int, object>(); for (int idx = 0; idx < count2; idx++) { PdfReference iref = irefs2[idx]; PdfCrossReferenceStream xrefStream = iref.Value as PdfCrossReferenceStream; if (xrefStream != null) { for (int idx2 = 0; idx2 < xrefStream.Entries.Count; idx2++) { PdfCrossReferenceStream.CrossReferenceStreamEntry item = xrefStream.Entries[idx2]; // Is type xref to compressed object? if (item.Type == 2) { //PdfReference irefNew = parser.ReadCompressedObject(new PdfObjectID((int)item.Field2), (int)item.Field3); //document._irefTable.Add(irefNew); int objectNumber = (int)item.Field2; if (!objectStreams.ContainsKey(objectNumber)) { objectStreams.Add(objectNumber, null); PdfObjectID objectID = new PdfObjectID((int)item.Field2); parser.ReadIRefsFromCompressedObject(objectID); } } } } } // 4th: Read compressed objects. for (int idx = 0; idx < count2; idx++) { PdfReference iref = irefs2[idx]; PdfCrossReferenceStream xrefStream = iref.Value as PdfCrossReferenceStream; if (xrefStream != null) { for (int idx2 = 0; idx2 < xrefStream.Entries.Count; idx2++) { PdfCrossReferenceStream.CrossReferenceStreamEntry item = xrefStream.Entries[idx2]; // Is type xref to compressed object? if (item.Type == 2) { PdfReference irefNew = parser.ReadCompressedObject(new PdfObjectID((int)item.Field2), (int)item.Field3); Debug.Assert(document._irefTable.Contains(iref.ObjectID)); //document._irefTable.Add(irefNew); } } } } PdfReference[] irefs = document._irefTable.AllReferences; int count = irefs.Length; // Read all indirect objects. for (int idx = 0; idx < count; idx++) { PdfReference iref = irefs[idx]; if (iref.Value == null) { #if DEBUG_ if (iref.ObjectNumber == 1074) { iref.GetType(); } #endif try { Debug.Assert(document._irefTable.Contains(iref.ObjectID)); PdfObject pdfObject = parser.ReadObject(null, iref.ObjectID, false, false); Debug.Assert(pdfObject.Reference == iref); pdfObject.Reference = iref; Debug.Assert(pdfObject.Reference.Value != null, "Something went wrong."); } catch (Exception ex) { Debug.WriteLine(ex.Message); // 4STLA rethrow exception to notify caller. throw; } } else { Debug.Assert(document._irefTable.Contains(iref.ObjectID)); //iref.GetType(); } // Set maximum object number. document._irefTable._maxObjectNumber = Math.Max(document._irefTable._maxObjectNumber, iref.ObjectNumber); } // Encrypt all objects. if (xrefEncrypt != null) { document.SecurityHandler.EncryptDocument(); } // Fix references of trailer values and then objects and irefs are consistent. document._trailer.Finish(); #if DEBUG_ // Some tests... PdfReference[] reachables = document.xrefTable.TransitiveClosure(document.trailer); reachables.GetType(); reachables = document.xrefTable.AllXRefs; document.xrefTable.CheckConsistence(); #endif if (openmode == PdfDocumentOpenMode.Modify) { // Create new or change existing document IDs. if (document.Internals.SecondDocumentID == "") { document._trailer.CreateNewDocumentIDs(); } else { byte[] agTemp = Guid.NewGuid().ToByteArray(); document.Internals.SecondDocumentID = PdfEncoders.RawEncoding.GetString(agTemp, 0, agTemp.Length); } // Change modification date document.Info.ModificationDate = DateTime.Now; // Remove all unreachable objects int removed = document._irefTable.Compact(); if (removed != 0) { Debug.WriteLine("Number of deleted unreachable objects: " + removed); } // Force flattening of page tree PdfPages pages = document.Pages; Debug.Assert(pages != null); //bool b = document.irefTable.Contains(new PdfObjectID(1108)); //b.GetType(); document._irefTable.CheckConsistence(); document._irefTable.Renumber(); document._irefTable.CheckConsistence(); } } catch (Exception ex) { Debug.WriteLine(ex.Message); throw; } return(document); }
// The end goal is to have a user select the path of a PDf in need of watermarks. // Submit the file and press GO. Once they press Go, it grabs the pdf and watermarks it, then saves it in the network folder. public void markPDF(string filepath, string watermark, string userfile, int fontSize, string destination) { string userWatermark = watermark; // If the watermark field is empty. if (string.IsNullOrEmpty(userWatermark)) { MessageBox.Show("Enter text for the watermark.", "WaterPDF"); // Alert the user. } // If the path field is empty. else if (string.IsNullOrEmpty(filepath)) { MessageBox.Show("Select a file.", "WaterPDF");// Alert the user } // If the new filename is empty. else if (string.IsNullOrWhiteSpace(userfile)) { MessageBox.Show("Enter a filename", "WaterPDF"); // Alert the user. } else if (string.IsNullOrWhiteSpace(destination)) { MessageBox.Show("Select a save destination"); // Alert the user. } else { if (File.Exists(filepath)) { // Creates a new file path to save the watermarked PDF. string newFileName = destination + @"\" + userfile + ".pdf"; //PdfPasswordProvider provider; // Opens the file from the path provided. PdfDocument document = PdfReader.Open(filepath, PdfDocumentOpenMode.Modify); // Counts the amount of pages in the PDF. PdfPages pages = document.Pages; // foreach page in pdf // Paint the pdf and then move onto the next one? foreach (PdfPage pager in pages) { // Creating the font variable. XFont font = new XFont("Arial", fontSize, XFontStyle.Regular); // Creating the graphics. XGraphics gfx = XGraphics.FromPdfPage(pager, XGraphicsPdfPageOptions.Append); var size = gfx.MeasureString(watermark, font); // Creating the coordinates. gfx.TranslateTransform(pager.Width / 2, pager.Height / 2); gfx.RotateTransform(-Math.Atan(pager.Height / pager.Width) * 180 / Math.PI); gfx.TranslateTransform(-pager.Width / 2, -pager.Height / 2); var format = new XStringFormat(); format.Alignment = XStringAlignment.Near; format.LineAlignment = XLineAlignment.Near; // Creating the brush to paint with. XBrush brush = new XSolidBrush(XColor.FromKnownColor(XKnownColor.DimGray)); gfx.DrawString(watermark, font, brush, new XPoint((pager.Width - size.Width) / 2, (pager.Height - size.Height) / 2), format); gfx.DrawString(watermark, font, brush, new XPoint((pager.Width - size.Width) / 2, (pager.Height - size.Height) / 2), format); } // Sets the first page as the page to work on. // PdfPage page = document.Pages[0]; // Saves it in the provided location. document.Save(newFileName); if (MessageBox.Show("Your PDF has been watered.", "WaterPDF") == DialogResult.OK) { // Alerts the user that the file was saved and creates an explorer window of the destination. System.Diagnostics.Process.Start("explorer.exe", destination); } } else { MessageBox.Show("File Incorrect. Choose new file"); } } }