Technical FAQs

Question

How can I enable content encryption in PrizmDoc Viewer?

Answer

First, you need to enable content encryption on the PrizmDoc Server in the central configuration file. To do this, find the viewing.contentEncryption.enabled section and change the value to true. Save the changes to the file and restart the PrizmDoc services for the change to take effect.

The file paths for the central configuration file are:

Linux: /usr/share/prizm/prizm-services-config.yml
Windows: C:\Prizm\prizm-services-config.yml

Next, you need to enable content encryption in the Viewer. To do this, in the index page of your viewer (Default.aspx in C#, index.php in the PHP sample, index.html, etc.), provide the encryption option in the viewer options parameter as follows so that the Viewer can handle encrypted data:

function buildViewerOptions() {
    ...
    var optionsOverride = args.pop(); // always last arg
    var options = {
        ...
        encryption: true
    };
    var combinedOptions = _.extend(optionsOverride, options);
    embedViewer(combinedOptions);
}

For more in-depth information on enabling content encryption in PrizmDoc, please refer to our documentation here.

Today’s organizations are inundated with a variety of document and image formats on a regular basis. By integrating comprehensive PDF functionality into their applications, developers can provide the tools to manage those files much more easily. Converting files into PDFs makes them easier to share, modify, and annotate without having to worry about compatibility issues across applications.

Simply converting documents or images into searchable PDF files is easy enough, but in many cases, several files need to be merged into a single document or one large file must be split into multiple documents. Accusoft’s ImageGear SDK gives applications the ability to process PDFs programmatically, allowing users to quickly prepare documents for viewing and collaboration.

How to Merge PDF Files with ImageGear Using C#

ImageGear can merge two multi-page PDF documents into a single document. This is especially useful for organizations that have multiple files associated with the same workflow or account, such as loan applications or medical records. The following steps will walk you through the merge PDF process using ImageGear.NET in C#.

Step 1: Initialize PDF Support

Before getting started, you’ll need to initialize PDF support within ImageGear.NET (if you haven’t done so already during deployment). This initialization will allow your application to load, save, and process PDF files.

After creating a new “Console Application” and adding the required assembly reference and resources, you can use the following code snippet to load and save PDF files.

 

using System.IO;
using ImageGear.Formats;
using ImageGear.Formats.PDF;
using ImageGear.Evaluation;
namespace MyPDFProject
{
    class Program
    {
        public void Initialize()
        {
            // Initialize evaluation license.
            ImGearEvaluationManager.Initialize();
            ImGearEvaluationManager.Mode = ImGearEvaluationMode.Watermark;
            // Initialize common formats.
            ImGearCommonFormats.Initialize();
            // Add support for PDF files.
            ImGearFileFormats.Filters.Insert(0, ImGearPDF.CreatePDFFormat());
            ImGearPDF.Initialize();
        }
        public void Terminate()
        {
            // Dispose of support for PDF files.
            ImGearPDF.Terminate();
        }
        public void LoadAndSave(string fileIn, string fileOut)
        {
            ImGearPDFDocument igPDFDocument = null;
            try
            {
                // Load the PDF document.
                using (FileStream inStream = new FileStream(fileIn, FileMode.Open))
                    igPDFDocument = (ImGearPDFDocument)ImGearFileFormats.LoadDocument(inStream, 0, (int)ImGearPDFPageRange.ALL_PAGES);
                // Save the PDF document to a new file.
                ImGearPDFSaveOptions pdfOptions = new ImGearPDFSaveOptions();
                using (FileStream outStream = new FileStream(fileOut, FileMode.Create))
                    ImGearFileFormats.SaveDocument(igPDFDocument, outStream, 0, ImGearSavingModes.OVERWRITE, ImGearSavingFormats.PDF, pdfOptions);
            }
            finally
            {
                igPDFDocument?.Dispose();
            }
        }
        static void Main(string[] args)
        {
            Program myProgram = new Program();
            myProgram.Initialize();
            myProgram.LoadAndSave(@"C:\PATHTOPDF\FILENAME.pdf", @"C:\PATHTOPDF\NEWNAME.pdf");
            myProgram.Terminate();
        }
    }
}

       

 

Step 2: Set the Merge PDF Parameters

You will need to determine what order the documents will be combined in and set the page numeration for the new document.

Step 3: Merge the PDF Documents

Once you’ve identified the files you want to merge and the order they should go in, you can use the “MergePdfDocuments” command to assemble the new PDF file. Here’s what the code snippet looks like in C#:

 

        // Merges two PDF document into a third PDF document.
        public void Merge(string fileInFirst, string fileInSecond, string fileOut)
        {
            // ImageGear uses zero-based page numbers.
            const int FIRST_PAGE_INDEX = 0;
            ImGearPDFDocument igPDFDocumentFirst = null;
            ImGearPDFDocument igPDFDocumentSecond = null;
            ImGearPDFDocument igPDFDocumentResult = null;
            try
            {
                // Load the source PDF documents.
                using (FileStream inStream = new FileStream(fileInFirst, FileMode.Open))
                    igPDFDocumentFirst = (ImGearPDFDocument)ImGearFileFormats.LoadDocument(inStream, 0, (int)ImGearPDFPageRange.ALL_PAGES);
                using (FileStream inStream = new FileStream(fileInSecond, FileMode.Open))
                    igPDFDocumentSecond = (ImGearPDFDocument)ImGearFileFormats.LoadDocument(inStream, 0, (int)ImGearPDFPageRange.ALL_PAGES);
                // Create the resulting PDF document.
                igPDFDocumentResult = new ImGearPDFDocument();
                // Copy all pages of first document into resulting PDF document.
                for (int pageIndex = FIRST_PAGE_INDEX; pageIndex < igPDFDocumentFirst.Pages.Count; pageIndex++)
                    igPDFDocumentResult.Pages.Add(igPDFDocumentFirst.Pages[pageIndex].Clone());
                // Copy all pages of second document into resulting PDF document.
                for (int pageIndex = FIRST_PAGE_INDEX; pageIndex < igPDFDocumentSecond.Pages.Count; pageIndex++)
                    igPDFDocumentResult.Pages.Add(igPDFDocumentSecond.Pages[pageIndex].Clone());
                // Save the resulting PDF document to a new file.
                ImGearPDFSaveOptions pdfOptions = new ImGearPDFSaveOptions();
                using (FileStream outStream = new FileStream(fileOut, FileMode.Create))
                    ImGearFileFormats.SaveDocument(igPDFDocumentResult, outStream, 0, ImGearSavingModes.OVERWRITE, ImGearSavingFormats.PDF, pdfOptions);
            }
            finally
            {
                igPDFDocumentFirst?.Dispose();
                igPDFDocumentSecond?.Dispose();
                igPDFDocumentResult?.Dispose();
            }
        }
        static void Main(string[] args)
        {
            Program myProgram = new Program();
            myProgram.Initialize();
            myProgram.Merge(@"C:\PATHTOPDF\FIRSTFILENAME.pdf", @"C:\PATHTOPDF\SECONDFILENAME.pdf", @"C:\PATHTOPDF\NEWNAME.pdf");
            myProgram.Terminate();
        }

 

After merging your files into a new document, you can begin working with the resulting PDF using ImageGear’s other PDF features:

How to Split PDF Files with ImageGear Using C#

While the merge PDF command is used to combine multiple documents into a new, single PDF file, the split PDF command saves pages from an existing document as a separate document. A three-page PDF file, for instance, can be broken into three, single-page PDF documents.

Once you’ve initialized PDF support for ImageGear.NET, you can split a PDF document by following a few simple steps:

Step 1: Read the PDF into a System.IO.Stream Object

This allows ImageGear to read the stream using ImGearFileFormats.LoadDocument(FILE NAME) command.

Step 2: Determine PDF Page Count

The ImGearPDFDocument.Pages property provides access to the document’s page array, which can then be used to assemble a new document.

Step 3: Create a New PDF Document

The ImGearPDFDocument object can be used to create an empty PDF document that will serve as the destination file for the split pages.

Step 4: Insert Pages into the New Document

The InsertPages command takes specific pages from the source document (the PDF you’re splitting), and inserts them into the destination document. After the pages are inserted, you can save the new PDF to disk or memory. Keep in mind that the original document will still contain all pages, so splitting it into two documents will require you to create two new documents.

Here is a what splitting a single PDF document into several single-page PDF documents looks like in C#:

 

public void Split(string fileIn, string directoryOut)
        {
            // ImageGear uses zero-based page numbers.
            const int FIRST_PAGE = 0;
            // Ensure output directory exists.
            if (!System.IO.Directory.Exists(directoryOut))
                Directory.CreateDirectory(directoryOut);
            // Load the source PDF document.
            using (FileStream inStream = new FileStream(fileIn, FileMode.Open))
            {
                using (ImGearPDFDocument igPDFDocument = ImGearFileFormats.LoadDocument(inStream, FIRST_PAGE, (int)ImGearPDFPageRange.ALL_PAGES) as ImGearPDFDocument)
                {
                    // Write each page in source PDF document to a separate PDF file.
                    for (int pageIndex = FIRST_PAGE; pageIndex < igPDFDocument.Pages.Count; pageIndex++)
                    {
                        // Construct the output filepath.
                        string outputFileName = string.Format("{0}_{1}.pdf", Path.GetFileNameWithoutExtension(fileIn), pageIndex + 1);
                        string outputPath = System.IO.Path.Combine(directoryOut, outputFileName);
                        // Create a new empty PDF document.
                        using (ImGearPDFDocument igPDFDocumentResult = new ImGearPDFDocument())
                        {
                            // Insert page into new PDF document.
                            igPDFDocumentResult.InsertPages((int)ImGearPDFPageNumber.BEFORE_FIRST_PAGE, igPDFDocument, pageIndex, 1, ImGearPDFInsertFlags.DEFAULT);
                            // Save new PDF document to file.
                            igPDFDocumentResult.Save(outputPath, ImGearSavingFormats.PDF, FIRST_PAGE, FIRST_PAGE, 1, ImGearSavingModes.OVERWRITE);
                        }
                    }
                }
            }
        }
        static void Main(string[] args)
        {
            Program myProgram = new Program();
            myProgram.Initialize();
            myProgram.Split(@"C:\PATHTOPDF\FILENAME.pdf", @"C:\PATHTOPDF\OUTPUTDIRECTORY");
            myProgram.Terminate();
        }

 

Enhance Your PDF Capabilities with ImageGear

Accusoft’s ImageGear SDK provides a broad range of document and image processing functions beyond the ability to split and merge PDFs. Whether you need powerful file conversion capabilities, multi-language OCR support, or image cleanup, correction, and transformation functions, ImageGear integrations can enhance your application’s performance and versatility. 

Learn more about the ImageGear collection of SDKs and see how they can help you shorten your development cycle and get your innovative products to market faster.

Question

I want to load an HTML document in PrizmDoc with UTF-8 encoding. Can this be done automatically in the product?

Answer

Currently, no. We have a parameter for .txt files which does that (detailed here), but this “textFileEncoding” intentionally only works for .txt, not .html files. There is a feature request for this:

https://ideas.accusoft.com/ideas/PDV-I-546

In the meantime, this can be fixed manually by adding charset = “utf-8” to the meta tag of the HTML document. One POC way this might be done programmatically is below in Python 3.7 (need obvious polishing like checking for the tag already existing, multiple “meta” tags, etc):

with open(filename, "r") as file:
    content = file.read()

index = content.find("meta") + len("meta")

new_content = content[:index] + " charset=\"utf-8\" " + content[index:]

with open(filename, "w") as file:
    file.write(new_content)
Question

I am combining multiple PDF documents together, and I need to create a new bookmark collection, placed at the beginning of the new document. Each bookmark should go to a specific page or section of the new document.
Example structure:

  • Section 1
    • Document 1
  • Section 2
    • Document 2

How might I do this using ImageGear .NET?

Answer

You are adding section dividers to the result document. So, for example, if you are to merge two documents, you might have, say, two sections, each with a single document, like so…

  • Section 1
    • Document 1
  • Section 2
    • Document 2

…The first page will be the first header page, and then the pages of Document 1, then another header page, then the pages of Document 2. So, the first header page is at index 0, the first page of Document 1 is at index 1, the second header is at 1 + firstDocumentPageCount, etc.

The following code demonstrates adding some blank pages to igResultDocument, inserting pages from other ImGearPDFDocuments, and modifying the bookmark tree such that it matches the outline above, with "Section X" pointing to the corresponding divider page and "Document X" pointing to the appropriate starting page number…

// Create new document, add pages
ImGearPDFDocument igResultDocument = new ImGearPDFDocument();
igResultDocument.CreateNewPage((int)ImGearPDFPageNumber.BEFORE_FIRST_PAGE, new ImGearPDFFixedRect(0, 0, 300, 300));
igResultDocument.InsertPages((int)ImGearPDFPageNumber.LAST_PAGE, igFirstDocument, 0, (int)ImGearPDFPageRange.ALL_PAGES, ImGearPDFInsertFlags.DEFAULT);
igResultDocument.CreateNewPage(igFirstDocument.Pages.Count, new ImGearPDFFixedRect(0, 0, 300, 300));
igResultDocument.InsertPages((int)ImGearPDFPageNumber.LAST_PAGE, igSecondDocument, 0, (int)ImGearPDFPageRange.ALL_PAGES, ImGearPDFInsertFlags.DEFAULT);

// Add first Section
ImGearPDFBookmark resultBookmarkTree = igResultDocument.GetBookmark();
resultBookmarkTree.AddNewChild("Section 1");
var child = resultBookmarkTree.GetLastChild();
int targetPageNumber = 0;
setNewDestination(igResultDocument, targetPageNumber, child);

// Add first Document
child.AddNewChild("Document 1");
child = child.GetLastChild();
targetPageNumber = 1;
setNewDestination(igResultDocument, targetPageNumber, child);

// Add second Section
resultBookmarkTree.AddNewChild("Section 2");
child = resultBookmarkTree.GetLastChild();
targetPageNumber = 1 + igFirstDocument.Pages.Count;
setNewDestination(igResultDocument, targetPageNumber, child);

// Add second Document
child.AddNewChild("Document 2");
child = child.GetLastChild();
targetPageNumber = 2 + igFirstDocument.Pages.Count;
setNewDestination(igResultDocument, targetPageNumber, child);

// Save
using (FileStream stream = File.OpenWrite(@"C:\path\here\test.pdf"))
{
    igResultDocument.Save(stream, ImGearSavingFormats.PDF, 0, 0, igResultDocument.Pages.Count, ImGearSavingModes.OVERWRITE);
}

...

private ImGearPDFDestination setNewDestination(ImGearPDFDocument igPdfDocument, int targetPageNumber, ImGearPDFBookmark targetNode)
{
    ImGearPDFAction action = targetNode.GetAction();
    if (action == null)
    {
        action = new ImGearPDFAction(
            igPdfDocument,
            new ImGearPDFDestination(
                igPdfDocument,
                igPdfDocument.Pages[targetPageNumber] as ImGearPDFPage,
                new ImGearPDFAtom("XYZ"),
                new ImGearPDFFixedRect(), 0, targetPageNumber));
        targetNode.SetAction(action);
    }
    return action.GetDestination();
}

(The setNewDestination method is a custom method that abstracts the details of adding the new destination.)

Essentially, the GetBookmark() method will allow you to get an instance representing the root of the bookmark tree, with its children being subtrees themselves. Thus, we can add a new child to an empty tree, then get the last child with GetLastChild(). Then, we can set the action for that node to be a new "GoTo" action that will navigate to the specified destination. Upon save to the file system, this should produce a PDF with the below bookmark structure…

Bookmarks example

Note that you may need to use the native Save method (NOT SaveDocument) described in the product documentation here in order to save a PDF file with the bookmark tree included. Also, you can read more about Actions in the PDF Specification.

Question

In some other viewers, there are highlights or markers that appear on the UI to indicate that annotations are available for a given page or document. Is there a way to implement this in PrizmDoc?

Answer

Sure can, you just need to make a MarkupLayerRecords request to determine if there are marks that pertain to the given Viewing Session. Keep in mind that documents don’t really have a specific set of annotations associated with them though — Markup IDs do, and you can specify any Markup ID you want when you create a viewing session:

// Add rules to your CSS for the following classes.
// The actual style information can be whatever you like.
//
// .mark-indicator {
//     background-color: gold !important;
// }
//
// .marked-page-indicator {
//     background-color: gold !important;
// }

let pasUrl = "http://localhost/pas-service"; // Example PAS proxy URL
let viewingSessionId = <%= viewingSessionId %>; // Example viewingSessionId
let thumbnailButton = $(".pcc-icon-thumbnails");
let pageIndicatorsAdded = false;
let thumbnailsClicked = false;
let marksRetrieved = false;
let markedPages = {};

async function addPageIndicators() {
    console.log("Attempting to add page indicators...");
    if (thumbnailsClicked && marksRetrieved && !pageIndicatorsAdded) {
        console.log("Conditions met.");

        let wrappers = $(".pccThumbnailWrapper");

        wrappers.each(function(index, wrapper) {
            if (markedPages[index]) {
                $(wrapper).addClass("marked-page-indicator");
            }
        });

        pageIndicatorsAdded = true;
    } else {
        console.log("Conditions not met");
    }
}

thumbnailButton.click(function() {
    console.log("Thumbnails button clicked.");

    thumbnailsClicked = true;

    addPageIndicators();
});

async function apiCall(type, url, body = {}) {
    return await $.ajax({
        "type": type,
        "url": url,
        "contentType": "application/json",
        "data": JSON.stringify(body)
    });
}

async function createMarkIndicators() {
    let output = await apiCall("GET", `${pasUrl}/MarkupLayers/u${viewingSessionId}`);

    if (output.length > 0) {
        console.log("Found layers.");

        thumbnailButton.addClass("mark-indicator");

        let layers = await Promise.all(output.map(function(element) {
            return apiCall("GET", `${pasUrl}/MarkupLayers/u${viewingSessionId}/${element.layerRecordId}`);
        }));

        layers.forEach(function(layer) {
            layer.marks.forEach(function(mark) {
                markedPages[mark.pageNumber - 1] = true;
            });
        });

        marksRetrieved = true;

        console.log("Marks retrieved.");

        addPageIndicators();
    } else {
        console.log("No layers found.");
    }
}

createMarkIndicators(); 
Question

How can I change the PrizmDoc Viewer so that the TextSelection tool is selected by default instead of the Pan tool?

Answer

In order to select the TextSelection tool by default in PrizmDoc Viewer there are a few things you need to take into account. First, you have to click the button inside the embedViewer() function found in the index page of the sample. Second, the button for the text selection tool is actually disabled initially, so in order to be able to click it, the button has to be enabled first by removing the pcc-disabled class.

Use the following code to do this:

function embedViewer(options) {
    var viewer = $('#viewer1').pccViewer(options);
    viewer.viewerControl.on(PCCViewer.EventType.ViewerReady, function(viewer) {
        $("[data-pcc-mouse-tool=\"AccusoftSelectText\"]").removeClass('pcc-disabled');
        $("[data-pcc-mouse-tool=\"AccusoftSelectText\"]").click();            
    });
}
Question

We want to use one PAS instance for multiple customers while ensuring their calls and data are separated so that other customers cannot access them. Is there a way PrizmDoc can accomplish this?

Answer

How To:

Use the following steps to set up the multi-tenancy feature:

  1. Add a new line inside of /usr/share/prizm/pas/pcc.nix.yml (Linux) or C:\Prizm\pas\pcc.win.yml (Windows) in the following format:

undocumentedFeature.multiTenancy: “enabled”

  1. After enabling this feature, all requests to PAS must include the header accusoft-tenant-id. The following shows an example request for creating a new viewing session:
POST /ViewingSession HTTP/1.1
Host: localhost:3000
Content-Type: application/json
accusoft-tenant-id: myUniqueTenantId
cache-control: no-cache
Postman-Token: 5edd698a-5e4f-46d2-b93a-42cc57371dce
  {
  "source": {
  "type": "document",
  "fileName": "1040ez.pdf"
   }
  }

NOTE: All Tenant Ids are converted to lowercase and must be unique between tenants. This means that in terms of the application both “MyTenant” and “mytenant” are equivalent and would be able to see the same files. Tenant Ids are not generated for the application and must be generated and handled by the integration components. Tenant Ids are also strictly alphanumeric at this time.

File storage including Documents, markupXml, formDefinitions and markupLayerRecords will now be appended with the
{tenantId} as shown in the above example with a Documents configuration of /usr/share/prizm/Samples/Documents. The request would attempt to create a viewing session from the following file: /usr/share/prizm/Samples/Documents/myuniquetenantid/1040ez.pdf

Viewing Package data stored in the database will have the tenantId included in the composite index as well as include an accusoftTenantId column.

Question

Is it possible to automatically annotate a document, similar to the Auto-Redaction feature, using PrizmDoc?

Answer

An auto-annotation feature isn’t an out-of-the-box feature but with some work, it can be done. This would involve creating a searchTask and using the information from it to programmatically create XML markup that can be used in the MarkupBurner.

To do this you would need to create a searchTask for the pattern you would like to annotate. You can then get the results of the searchTask as JSON which will contain all occurrences of that pattern/search. Each search result will include the selected text, the page on which it occurs, the starting index of the result, and the dimensions and coordinates of the bounding rectangles for that search result.

All this information can be used to construct the markup XML to add the annotations with the markup burner.

Once you have constructed the XML you would post to the MarkupBurner with the XML as the body to burn the document.