Example #1
0
 public static void Example()
 {
     using (Xtractor.Xtractor xtractor = new Xtractor.Xtractor(filename: @"..\..\..\Input\Xtractor.Input.pdf"))
     {
         /*
          * PDF documents don't always store the desired reading order of the text.
          * Even if it does, the text is not required to be stored in the reading
          * order for  that language. Some languages even have multiple acceptible
          * reading orders. Thus, Xtractor cannot guarantee getting text back in the
          * desired reading order for a given language.
          *
          * However, if you know what reading order you expect from your document,
          * it is still quite easy to get the desired result using LINQ. The example
          * below sorts the text for English, meaning top -> bottom first,
          * and left -> right second.
          */
         Console.WriteLine("Extracting document text by reading order ...");
         Xtractor.CharAndBox[]             englishText = xtractor.ExtractTextWithLocation(pageNumber: 1, origin: Xtractor.Xtractor.CoordinateOrigin.BottomLeft);
         IEnumerable <Xtractor.CharAndBox> sortedText  = englishText.OrderBy(cab => cab.Box.Y).ThenBy(cab => cab.Box.X);
         StringBuilder stringBuilder = new StringBuilder();
         foreach (Xtractor.CharAndBox character in sortedText)
         {
             stringBuilder.Append(character.Character);
         }
         Console.WriteLine($"Document Text: {stringBuilder.ToString()}");
     }
 }
        public static void Example()
        {
            /*
             * Assume that you have a page with text that looks like this:
             *
             * ---------------------------------
             |                               |
             |             North             |
             |                               |
             |  West       Center      East  |
             |                               |
             |             South             |
             |                               |
             | ---------------------------------
             */

            using (Xtractor.Xtractor xtractor = new Xtractor.Xtractor(filename: @"..\..\..\Input\Xtractor.Text.Location.pdf"))
            {
                //These functions have options to control which page you extract from, how many characters you want to get,
                //how far to the side of the original text in PDF units to search, and which instance on that page to use
                //as the reference point.
                string up = xtractor.ExtractTextAbove(pageNumber: 1, text: "Center", length: int.MaxValue, unitType: Xtractor.Xtractor.UnitType.Character);
                Console.WriteLine($"Text above center: {up.Trim()}");

                string below = xtractor.ExtractTextBelow(pageNumber: 1, text: "Center", length: int.MaxValue, unitType: Xtractor.Xtractor.UnitType.Character);
                Console.WriteLine($"Text below center: {below.Trim()}");

                string right = xtractor.ExtractTextRight(pageNumber: 1, text: "Center", length: int.MaxValue, unitType: Xtractor.Xtractor.UnitType.Character);
                Console.WriteLine($"Text right of center: {right.Trim()}");

                string left = xtractor.ExtractTextLeft(pageNumber: 1, text: "Center", length: int.MaxValue, unitType: Xtractor.Xtractor.UnitType.Character);
                Console.WriteLine($"Text left of center: {left.Trim()}");
            }
        }
Example #3
0
 public static void Example()
 {
     Console.WriteLine($"Counting number of pages in input document ...");
     using (Xtractor.Xtractor xtractor = new Xtractor.Xtractor(filename: @"..\..\..\Input\Xtractor.Input.pdf"))
     {
         Console.WriteLine($"  Number of pages found: {xtractor.PageTotal}.");
     }
 }
        public static void Example()
        {
            // You have a few options, depending on how much detail you want.
            // Note that all of the "Xtractor.Xtractor.CoordinateOrigin" arguments are optional.
            using (Xtractor.Xtractor xtractor = new Xtractor.Xtractor(@"..\..\..\Input\Xtractor.Input.pdf"))
            {
                string searchPhrase = "ActivePDF";

                // Gives back the bounding box of each occurrance of "ActivePDF" on page 1,
                // and results are relative to the top-left corner of the page.
                Console.WriteLine($"Retrieve the bounding box coordinates for all instances of {searchPhrase} on page one.");
                RectangleF[] page1BoundingBoxes = xtractor.FindText(text: searchPhrase, pageNumber: 1, origin: Xtractor.Xtractor.CoordinateOrigin.TopLeft);
                Console.WriteLine($"{page1BoundingBoxes.Length.ToString()} instance(s) of {searchPhrase} found on page 1.");
                foreach (RectangleF boundingBox in page1BoundingBoxes)
                {
                    Console.WriteLine($"  Box: ({boundingBox.X}, {boundingBox.Y}), ({boundingBox.X + boundingBox.Width}, {boundingBox.Y + boundingBox.Height})");
                }
                Console.WriteLine();

                // Gives back the bounding box of each occurrance of "ActivePDF" in the document.
                // Results are relative to the top-left corner of the page.
                // The first dimension of the array is sorted by page number,
                // so wholeDocumentBoundingBoxes[0] contains the same data as page1BoundingBoxes.
                Console.WriteLine($"Retrieve the bounding box coordinates for all instances of {searchPhrase} in the document.");
                RectangleF[][] wholeDocumentBoundingBoxes = xtractor.FindText(text: searchPhrase, origin: Xtractor.Xtractor.CoordinateOrigin.TopLeft);
                for (int i = 0; i < wholeDocumentBoundingBoxes.Length; ++i)
                {
                    Console.WriteLine($"{wholeDocumentBoundingBoxes[i].Length.ToString()} instance(s) of {searchPhrase} found on page {i + 1}.");
                    for (int j = 0; j < wholeDocumentBoundingBoxes[i].Length; ++j)
                    {
                        RectangleF boundingBox = wholeDocumentBoundingBoxes[i][j];
                        Console.WriteLine($"  Box: ({boundingBox.X}, {boundingBox.Y}), ({boundingBox.X + boundingBox.Width}, {boundingBox.Y + boundingBox.Height})");
                    }
                }

                // Uses the regex @"\w+" to find all words on page 1. Gets back each word and location found.
                // Returned coordinates are given relative to the bottom left corner, in PDF units.
                Tuple <string, RectangleF>[] allWordsPage1 = xtractor.FindText(new Regex(@"\w+"), 1, Xtractor.Xtractor.CoordinateOrigin.BottomLeft);

                // Uses the regex @"\w+" to find all words in the document. Gets back each word and location found.
                // Returned coordinates are given relative to the bottom left corner, in PDF units.
                // allWordsWholeDocument[0] contains the same data as allWordsPage1.
                Tuple <string, RectangleF>[][] allWordsWholeDocument = xtractor.FindText(re: new Regex(@"\w+"), origin: Xtractor.Xtractor.CoordinateOrigin.BottomLeft);

                // Extracts the location of each individual character on page 1. Coordinates are relative to the top left corner.
                // The order of characters is in the PDF's order, which may or may not be in natural reading order.
                Xtractor.CharAndBox[] eachCharacterPage1 = xtractor.ExtractTextWithLocation(pageNumber: 1, origin: Xtractor.Xtractor.CoordinateOrigin.TopLeft);

                // Extracts the location of each individual character in the whole document. Coordinates are relative to the bottom left corner.
                // eachCharacterWholeDocument[0] contains the same characters in the same order as eachCharacterPage1, but the
                // coordinates returned will differ because they used different coordinate spaces when they were called.
                // Coordinates will match if they used the same coordinate space.
                // The order of characters is in the PDF's order, which may or may not be in natural reading order.
                Xtractor.CharAndBox[][] eachCharacterWholeDocument = xtractor.ExtractTextWithLocation(origin: Xtractor.Xtractor.CoordinateOrigin.BottomLeft);
            }
        }
Example #5
0
 public static void Example()
 {
     using (Xtractor.Xtractor xtractor = new Xtractor.Xtractor(filename: @"..\..\..\Input\Xtractor.Input.pdf"))
     {
         Xtractor.DocumentInfo xtractorDocInfo = xtractor.GetDocumentInfo();
         WriteMetadata(XtractorDocInfo: xtractorDocInfo);
         Console.WriteLine();
         WritePermissions(XtractorDocInfo: xtractorDocInfo);
     }
 }
Example #6
0
        public static void Example()
        {
            using (Xtractor.Xtractor xtractor = new Xtractor.Xtractor(filename: @"..\..\..\Input\Xtractor.Input.pdf"))
            {
                string searchTerm = "ActivePDF";

                Console.WriteLine($"Counting search term, {searchTerm}, instances ...");

                // Count instances on just the first page.
                int searchResults = xtractor.CountInstances(text: searchTerm, pageNumber: 1);
                Console.WriteLine($" Instances of {searchTerm} found on the first page: {searchResults}");

                // Count instances in the entire document.
                searchResults = xtractor.CountInstances(text: searchTerm);
                Console.WriteLine($" Instances of {searchTerm} found in the document: {searchResults}");
            }
        }
Example #7
0
        public static void Example()
        {
            // You have two options for extracting the page size.
            using (Xtractor.Xtractor xtractor = new Xtractor.Xtractor(filename: @"..\..\..\Input\Xtractor.Input.pdf"))
            {
                Console.WriteLine("Extracting document page dimensions ...");

                // Extract the page size as two floats from page one.
                float width, height;
                xtractor.GetPageSize(pageNumber: 1, width: out width, height: out height);
                Console.WriteLine($"  Page one Width: {width} Height: {height}");

                // Extract the page size from page two as a rectangle.
                RectangleF pageSize = xtractor.GetPageSize(pageNumber: 2);
                Console.WriteLine($"  Page two Width: {pageSize.Width} Height: {pageSize.Height}");
            }
        }
        public static void Example()
        {
            using (Xtractor.Xtractor xtractor = new Xtractor.Xtractor(filename: @"..\..\..\Input\Xtractor.Input.pdf"))
            {
                // This method extracts the text from pages, one page at a time.
                Console.WriteLine("Extract text from each page individually.");
                for (int pageNum = 1; pageNum <= xtractor.PageTotal; ++pageNum)
                {
                    string pageText = xtractor.ExtractText(pageNumber: pageNum);
                    Console.WriteLine($"  Page {Convert.ToString(pageNum)} Text: {xtractor.ExtractText(pageNum)}");
                }

                // This method extracts the text from the whole document at once.
                // The string[] is sorted by page number, where index 'n' is page 'n + 1'.
                string[] allTextArray = xtractor.ExtractText();
            }
        }
Example #9
0
        public static void Example()
        {
            using (Xtractor.Xtractor xtractor = new Xtractor.Xtractor(filename: @"..\..\..\Input\Xtractor.Input.pdf"))
            {
                //Simple regex to search for all words.
                Regex re = new Regex(pattern: "\\w+");

                Console.WriteLine($"Counting regular expression, {re.ToString()}, instances ...");

                //Count instances on just the first page.
                int searchResults = xtractor.CountInstances(re: re, pageNumber: 1);
                Console.WriteLine($"  Instances of {re.ToString()} found on the first page: {searchResults}");

                //Count instances in the entire document.
                searchResults = xtractor.CountInstances(re: re);
                Console.WriteLine($"  Instances of {re.ToString()} found in the document: {searchResults}");
            }
        }
Example #10
0
        public static void Example()
        {
            using (Xtractor.Xtractor xtractor = new Xtractor.Xtractor(filename: @"..\..\..\Input\Xtractor.Input.pdf"))
            {
                //This saves the text from just page 1 to a file.
                xtractor.ExtractTextToFile(filename: @"..\..\..\Output\PageOneText.txt", pageNumber: 1);
                Process.Start(@"PageOneText.txt");

                //This saves the text from the whole document to a file.
                xtractor.ExtractTextToFile(filename: @"WholeDocumentText.txt");
                Process.Start(@"WholeDocumentText.txt");

                //This overload contains an optional parameter for a string to insert
                //between the result of each page. It defaults to "\n". Each page may
                //contain newlines as well, so modify this if you need to be able to
                //tell pages apart.
                xtractor.ExtractTextToFile(filename: @"WholeDocumentTextPageBreak.txt", pageSeparationStr: "This is a page break.");
                Process.Start(@"WholeDocumentTextPageBreak.txt");
            }
        }
        public static void Example()
        {
            // Xtractor supports many image file formats, including jpg, png, tiff, and more.
            using (Xtractor.Xtractor xtractor = new Xtractor.Xtractor(filename: @"..\..\..\Input\Xtractor.Input.pdf"))
            {
                PointF location = new PointF(x: 50f, y: 50f);

                // On page 1, finds the image 50 units from the left edge, 
                // and 50 units from the top, and saves to a jpg file.
                xtractor.ExtractImageToFile(filename: @"..\..\..\Output\ExtractImagesByLocation.jpg", pageNumber: 1, location: location, origin: Xtractor.Xtractor.CoordinateOrigin.TopLeft);

                // On page 1, finds the image 50 units from the left edge, 
                // and 700 units from the bottom, and saves to a png file.
                xtractor.ExtractImageToFile(filename: @"..\..\..\Output\ExtractImagesByLocation.png", pageNumber: 1, location: new PointF(x: 50f, y: 700f), origin: Xtractor.Xtractor.CoordinateOrigin.BottomLeft);

                // Extracts the image 50 units from the left edge and 50 from the top of page 1, and returns it in memory.
                Bitmap imageAtLocation = xtractor.ExtractImage(pageNumber: 1, location: location, origin: Xtractor.Xtractor.CoordinateOrigin.TopLeft);
                imageAtLocation.Dispose();
            }
        }
Example #12
0
        public static void Example()
        {
            using (Xtractor.Xtractor xt = new Xtractor.Xtractor(filename: @"..\..\..\Input\Xtractor.Input.pdf"))
            {
                // Saves all images on page 1 to bmp files.
                // The function will replace #PAGE# with the page number (1) and #NUM# with
                // the order it appeared on the page, starting at 1 and counting up.
                // The literal file names, after the #PAGE# AND #NUM# substitutions were made, are returned.
                // Using both #PAGE# and #NUM# are optional.
                string[] bmpFileNames = xt.ExtractImagesToFile(filenameOrMask: @"..\..\..\Output\#PAGE#_#NUM#.bmp", pageNumber: 1);
                foreach (string bmpFileName in bmpFileNames)
                {
                    Process.Start(fileName: bmpFileName);
                }
                Console.WriteLine("First page BMP image processing complete, press any key to continue.");

                // Saves all images in the entire document to JPG files.
                string[] jpgFileNames = xt.ExtractImagesToFile(filenameOrMask: @"..\..\..\Output\#PAGE#_#NUM#.jpg");
                foreach (string jpgFileName in jpgFileNames)
                {
                    Process.Start(fileName: jpgFileName);
                }
                Console.WriteLine("JPG image processing complete, press any key to continue.");

                // Extracts all images on page 1, and returns them in memory.
                Bitmap[] allImagesPage1 = xt.ExtractImages(pageNumber: 1);

                // Process the images

                DisposeBitmaps(allImagesPage1);

                // Extracts all images in the whole document, and returns them in memory.
                // The first dimension in the array is sorted by page number in ascending order.
                // allImagesWholeDocument
                Bitmap[][] allImagesWholeDocument = xt.ExtractImages();

                // Process the images

                DisposeBitmaps(allImagesWholeDocument);
            }
        }
        public static void Example()
        {
            // When it comes to extracting bookmarks, you have two options.
            using (Xtractor.Xtractor xtractor = new Xtractor.Xtractor(filename: @"..\..\..\Input\Xtractor.Input.pdf"))
            {
                // Extract bookmarks as a JSON string.
                Console.WriteLine($"Extracting bookmarks as a JSON string.");
                string bookmarksJson    = xtractor.GetBookmarksAsJson();
                string bookmarksJonFile = "bookmarks.json";
                using (FileStream outputStream = new FileStream(path: bookmarksJonFile, mode: FileMode.OpenOrCreate, access: FileAccess.ReadWrite))
                {
                    byte[] bookmarksBytes = Encoding.UTF8.GetBytes(s: bookmarksJson);
                    outputStream.Write(array: bookmarksBytes, offset: 0, count: bookmarksBytes.Length);
                }
                Console.WriteLine($"Bookmark JSON data saved to: ${System.IO.Directory.GetCurrentDirectory()}\\{bookmarksJonFile}");
                Console.WriteLine();

                // Extract bookmarks as a tree structure.
                Console.WriteLine($"Extracting bookmarks as a tree structure.");
                Xtractor.DocumentOutline bookmarks = xtractor.GetBookmarksAsTree();
                PrintBookmarks(bookmarks: bookmarks);
            }
        }
Example #14
0
        public static void Example()
        {
            using (Xtractor.Xtractor xtractor = new Xtractor.Xtractor(filename: @"..\..\..\Input\Xtractor.Input.pdf"))
            {
                // If you know where on the page you want to look, you can
                // restrict extractions to just that area. In this example,
                // we'll just a square 100 units  on each side and pull from a
                // corner.
                const float boxWidth = 100, boxHeight = 810;
                for (int pageNum = 1; pageNum <= xtractor.PageTotal; ++pageNum)
                {
                    // PDF allows each page to be a different size, so we should get the
                    // page size for each page rather than once for the whole document.
                    float pageWidth, pageHeight;
                    xtractor.GetPageSize(pageNumber: pageNum, width: out pageWidth, height: out pageHeight);

                    // We use Image Coordinates as the text origin  [top left is (0, 0)]
                    RectangleF topBox = new RectangleF(x: pageWidth - boxWidth,
                                                       y: 0,
                                                       width: boxWidth,
                                                       height: boxHeight);
                    string textTopRight = xtractor.ExtractTextWithin(pageNumber: pageNum, rect: topBox, origin: Xtractor.Xtractor.CoordinateOrigin.TopLeft);
                    Console.WriteLine($"Top Right Text Page {pageNum}: {textTopRight}");
                    Console.WriteLine();

                    // or we can use PDF coordinates  [bottom left is (0, 0)]
                    RectangleF bottomBox = new RectangleF(x: pageWidth - boxWidth,
                                                          y: boxHeight,
                                                          width: boxWidth,
                                                          height: boxHeight);
                    string textBottomLeft = xtractor.ExtractTextWithin(pageNumber: pageNum, rect: bottomBox, origin: Xtractor.Xtractor.CoordinateOrigin.BottomLeft);
                    Console.WriteLine($"Bottom Right Text Page {pageNum}: {textBottomLeft}");
                    Console.WriteLine();
                }
            }
        }
Example #15
0
        public static void Example()
        {
            using (Xtractor.Xtractor xtractor = new Xtractor.Xtractor(@"..\..\..\Input\Xtractor.Input.pdf"))
            {
                // Simple Regex to search for numbers.
                Regex re = new Regex(pattern: "\\d+");

                // Finds all the numbers on page 1.
                Console.WriteLine("Searching first page ...");
                string[] page1Matches = xtractor.FindAllByRegex(re: re, pageNumber: 1);
                Console.WriteLine($"{page1Matches.Length} results found on page one.");
                Console.WriteLine();


                // Finds all numbers in the whole document. The first dimension
                // of the array is sorted by page number.
                Console.WriteLine("Searching entire document ...");
                string[][] wholeDocumentMatches = xtractor.FindAllByRegex(re: re);
                for (int i = 0; i < wholeDocumentMatches.Length; ++i)
                {
                    Console.WriteLine($"{wholeDocumentMatches[i].Length} results found on page {i + 1}.");
                }
            }
        }
Example #16
0
        // This example contains different ways of opening an Xtractor input
        // file and how to handle passwords.
        public static void Example()
        {
            // Open a file from disk.
            using (Xtractor.Xtractor xtractor = new Xtractor.Xtractor(filename: @"..\..\..\Input\Xtractor.Input.pdf"))
            {
                // Perform your extractions here.
                Console.WriteLine("Successfully opened Xtractor.Input.pdf with Xtractor.");
            }

            //Open a file from memory.
            byte[] examplePDF = File.ReadAllBytes(@"..\..\..\Input\Xtractor.Input.pdf");
            using (Xtractor.Xtractor xtractor = new Xtractor.Xtractor(file: examplePDF))
            {
                // Perform your extractions here.
                Console.WriteLine("Successfully opened Xtractor.Input.pdf with Xtractor as a byte array.");
            }

            // Open a file with a password from disk.
            using (SecureString password = new SecureString())
            {
                // We recommend never storing secure data like a password in a
                // 'string', however we will here for simplicity.
                string insecurePassword = "******";
                foreach (char c in insecurePassword)
                {
                    password.AppendChar(c);
                }
                password.MakeReadOnly();
                using (Xtractor.Xtractor xtractor = new Xtractor.Xtractor(filename: @"..\..\..\Input\Xtractor.Input.Secure.pdf", password: password))
                {
                    // Perform your extractions here.
                    Console.WriteLine("Successfully opened Xtractor.Input.Secure.pdf with Xtractor and input password.");
                }
            }

            // Open a file with a password from memory.
            examplePDF = File.ReadAllBytes(@"..\..\..\Input\Xtractor.Input.Secure.pdf");
            using (SecureString password = new SecureString())
            {
                string insecurePassword = "******";
                foreach (char c in insecurePassword)
                {
                    password.AppendChar(c);
                }
                password.MakeReadOnly();

                using (Xtractor.Xtractor xtractor = new Xtractor.Xtractor(file: examplePDF, password: password))
                {
                    // Perform your extractions here.
                    Console.WriteLine("Successfully opened Xtractor.Input.Secure.pdf with Xtractor as a byte array using a password.");
                }
            }

            // Handle an invalid password.
            // We aren't using a 'using' block here, like most other examples.
            // Since the runtime expands 'using' into a try/finally pattern anyway, we'll
            // manually expand it so we can add in a 'catch' as well.
            {
                Xtractor.Xtractor xtractor = null;
                try
                {
                    string       password       = "******";
                    SecureString securePassword = new SecureString();
                    foreach (char c in password)
                    {
                        securePassword.AppendChar(c);
                    }
                    securePassword.MakeReadOnly();

                    xtractor = new Xtractor.Xtractor(filename: @"..\..\..\Input\Xtractor.Input.Secure.pdf", password: securePassword);

                    // Perform your extractions here.
                    Console.WriteLine("Successfully opened Xtractor.Input.pdf with Xtractor.");
                }
                catch (Xtractor.InvalidPasswordException)
                {
                    // Handle the error here.
                    Console.WriteLine("InvalidPasswordException caught opening Xtractor.Input.Secure.pdf");
                }
                finally
                {
                    xtractor?.Dispose();
                }
            }
        }
Example #17
0
        static void Main(string[] args)
        {
            string appPath = System.AppDomain.CurrentDomain.BaseDirectory;
            string newPDF = "GeneratedPDF.pdf";
            int result = -1;

            // Use Toolkit to create a new PDF
            using (APToolkitNET.Toolkit toolkit = new APToolkitNET.Toolkit())
            {
                toolkit.OutputPageHeight = 792.0f;
                toolkit.OutputPageWidth = 612.0f;

                Console.WriteLine($"Toolkit: Generating new PDF using NewPage");

                // Open the output file in memory
                result = toolkit.OpenOutputFile("MEMORY");
                if (result != 0)
                {
                    WriteResult($"Toolkit: Failed to open output file in-memory, error code {result}");
                    return;
                }

                // Each time a new page is required call NewPage
                toolkit.NewPage();

                // Text can be added onto the new page with
                // SetFont, PrintText and PrintMultilineText functions
                toolkit.SetFont("Helvetica", 24);
                toolkit.PrintText(36.0f, 720.0f, $"Toolkit Version: {toolkit.ToolkitVersion}");

                // Images can be added onto the new page with
                // PrintImage, PrintJPEG and PrintTIFF
                toolkit.PrintJPEG($"{appPath}IMG.jpg", 36.0f, 36.0f, 540.0f, 684.0f, true);

                // Close the new file to complete PDF creation
                toolkit.CloseOutputFile();

                // Save the new PDF to the application path
                result = toolkit.SaveMemoryToDisk($"{appPath}{newPDF}");
                if (result != 0)
                {
                    WriteResult($"Toolkit: SaveMemoryToDisk failed, error code {result}");
                    return;
                }
                Console.WriteLine($"Toolkit: New pdf created {appPath}{newPDF}");

                // Use Toolkit Compressor to compress images
                Console.WriteLine("Toolkit.Compressor: Compressing generated PDF");
                toolkit.OpenOutputFile("MEMORY");
                if (result != 0)
                {
                    WriteResult($"Toolkit Compressor: Failed to open output file in-memory, error code {result}");
                    return;
                }

                // Retrieves the entire PDF as a string variable after you call
                // CloseOutputFile and set the output file name to MEMORY.
                toolkit.InputByteStream = toolkit.OutputByteStream;

                // Open the input file
                toolkit.OpenInputFile("MEMORY");
                if (result != 0)
                {
                    WriteResult($"Toolkit Compressor: Failed to open input file in-memory, error code {result}");
                    return;
                }

                // Instantiate the compressor object
                APToolkitNET.Compressor compressor = toolkit.GetCompressor();

                // Compresses images in the output PDF with the default settings.
                compressor.CompressImages = true;

                result = toolkit.CopyForm(0, 0);
                if (result != 1)
                {
                    WriteResult($"Toolkit Compressor: CopyForm failed, error code {result}");
                    return;
                }
                toolkit.CloseOutputFile();

                // Save the compressed PDF to disk
                result = toolkit.SaveMemoryToDisk($"{appPath}Toolkit.Compressed.pdf");
                if (result != 0)
                {
                    WriteResult($"Toolkit Compressor: SaveMemoryToDisk failed, error code {result}");
                    return;
                }
                Console.WriteLine($"Toolkit Compressor: Compressed pdf created {appPath}Toolkit.Compressed.pdf");
            }

            // Use Rasterizer to convert generated PDF to an image
            Console.WriteLine("\nRasterizer: Converting generated PDF to image format");
            using (APRasterizerNET.Rasterizer rasterizer =
                new APRasterizerNET.Rasterizer())
            {
                // Open PDF
                rasterizer.OpenFile($"{appPath}{newPDF}");

                // Get page count of open file
                int pageCount = rasterizer.NumPages();

                for (int currentPage = 1; currentPage <= pageCount; currentPage++)
                {
                    // Image Format
                    rasterizer.ImageFormat = APRasterizerNET.ImageType.ImgJPEG;

                    // Output Type
                    rasterizer.OutputFormat =
                        APRasterizerNET.OutputFormatType.OutFile;

                    // Other settings
                    rasterizer.OutputFileName =
                        $"{appPath}Rasterizer.ConvertPDFToJPEG.Page.{currentPage}.jpg";

                    // Render the current page
                    rasterizer.RenderPage(currentPage);

                    // Check for errors
                    if (rasterizer.LastError != 0)
                    {
                        WriteResult($"Error rendering page {currentPage}: {rasterizer.LastErrorMessage}");
                    }

                    Console.WriteLine($"Rasterizer: JPG image created at {appPath}Rasterizer.ConvertPDFToJPEG.Page.{currentPage}.jpg");
                }
            }

            // Use Xtractor to extract text and images
            Console.WriteLine("\nXtractor: Extracting images and text from the generated PDF");
            using (Xtractor.Xtractor xtractor = new Xtractor.Xtractor(filename: $"{appPath}{newPDF}"))
            {
                // Saves all images in the entire document to JPG files.
                string[] jpgFileNames = xtractor.ExtractImagesToFile(filenameOrMask: $"{appPath}Xtractor.#PAGE#_#NUM#.jpg");
                Console.WriteLine($"Xtractor: Files extracted from \"{newPDF}\"");
                foreach (string file in jpgFileNames)
                {
                    Console.WriteLine($"\tExtracted File: {file}");
                }

                // This method extracts the text from the whole document at once.
                // The string[] is sorted by page number, where index 'n' is page 'n + 1'.
                string[] allTextArray = xtractor.ExtractText();
                Console.WriteLine($"Xtractor: Text extracted from {newPDF}");
                foreach (string text in allTextArray)
                {
                    Console.WriteLine($"\tExtracted Text: {text}");
                }
            }

            // Use Redactor to redact images and text from generated PDF
            Console.WriteLine("\nRedactor: Redacting images and text from the generated PDF");
            using (APRedactor.Redactor redactor = new APRedactor.Redactor(
                filename: $"{appPath}{newPDF}"))
            {
                redactor.PageLiteralText = new string[]
                    {
                    "Version"
                    };
                redactor.TextMode =
                    APRedactor.Redactor.TextRedactionMode.LiteralText;
                redactor.ImageMode =
                    APRedactor.Redactor.ImageRedactionMode.Unconditional;
                int redactionsPerformed = redactor.Redact();
                redactor.Save($"{appPath}RedactImagesAndText.pdf");
                Console.WriteLine($"Redactor: Redacted PDF created {appPath}RedactedImagesAndText.pdf");
            }

            WriteResult("\nSuccess!");
        }