PDF Encrypter

Continuing my adventure of “Going Paperless“, I needed an easy way to encrypt PDF files before I added them to Evernote. To do this, I used the LEADTOOLS PDFFile() class to add a user password to a file. I created a console application with code to register itself into the Windows Explorer shell. Now I can right click any PDF file and encrypt it with a password. The LEADTOOLS code to do this is very easy; it took me longer to figure out how to edit the registry to add the application to the Windows Explorer context menu then it did to use LEADTOOLS to add the password.

One call got it done:

new PDFFile( fileName, password ) {
   SecurityOptions = new PDFSecurityOptions {
      UserPassword = newPassword,
      EncryptionMode = PDFEncryptionMode.RC128Bit
   },
   CompatibilityLevel = PDFCompatibilityLevel.PDF15
}.Convert( 1, -1, null );
Continue reading
Posted in Document Imaging | Tagged , , , , , | Leave a comment

Repurpose Content with ASP.NET Layout Pages

I was recently tasked with updating all of our product descriptions on the MSDN Marketplace site. The requirements were to make sure that all of the product descriptions matched our website exactly and that all of the links included a query string parameter. Manually qualifying and tagging hundreds HREFs and SRCs every quarter is not my idea of a good time; I’d rather write code! Additionally, the MSDN site has some markup quirks that need to be handled consistently.

Manually qualifying and tagging hundreds HREFs and SRCs every quarter is not my idea of a good time…

Fortunately, our website is based on ASP.NET and uses layouts. This means that by changing the layout page and a little code, I was able to reuse the existing content, adjust for the MSDN quirks, and the task became an error-free copy-paste job.

♻ Recycle Content

We use layout pages on our site to ensure the consistency of all of our content pages. Our layout pages hold the page structure as well as specify regions that are required to be defined in the content pages. The body of the content pages are rendered in a layout page when the RenderBody() is called. Basically, RenderBody() renders anything that is in the content page that is not enclosed in a @section{}. This makes it very easy for all of the members of our team to add new and update existing content without having to worry about forgetting required elements or how a certain page type is structured.

You can read more about layout pages on w3schools.com.

The first thing I did was make a copy of our product layout page. Then, I began stripping down all the extra stuff (e.g., Google Analytics script) that was not needed for the MSDN Marketplace product listings. Next, I added the HTML scaffolding that we decided to use.

At this point, I was ready to process the links and fix the marketplace specific quirks, but I was not sure how. The content is rendered directly in the layout page, so I was not exactly sure where I could modify it. I began digging more into the RenderPage() function and noticed that it returns a System.Web.WebPages.HelperResult. Reading the documentation for HelperResult shows that it is just for the framework’s internal use. Since only our team would be using the results, I intrepidly ignored the warnings in the documentation.

I intrepidly ignored the warnings in the documentation

Instead of directly returning the results of RenderBody() into the layout, I returned the results into a variable. With very little trial and error, I was able to render that variable in the layout with a call to Html.Raw().

Here is how:

Layout Page

@{
    var bodyHtmlHelper = RenderBody();
    var bodyHtml = bodyHtmlHelper.ToHtmlString();
}
<td style="padding: 15px; vertical-align: top;">
    @Html.Raw(bodyHtml)
    <p>
        <a href="@GetLinkToPage()">Get more information at @GetLinkToPage(false)</a>
    </p>
</td>

Now that I knew it was possible to get the HTML results from RenderBody() and still render it in the layout, I was ready to try to update the HTML. (By the way, this same idea can be applied to RenderSection(). For example, var bannerHtmlHelper = RenderSection("BannerImage", false); returns the same HtmlHelper type as RenderBody().)

To process the HTML, I decided to install the HtmlAgilityPack NuGet. I created functions to process all of the links and images in the HTML to make them fully qualified. (The functions below only show how to fix root relative hrefs and srcs.)

@using HtmlAgilityPack
@functions {
   static string FixHtml(string htmlString)
   {
     var doc = new HtmlDocument();
     doc.LoadHtml(htmlString);

     doc = FixLinks(doc);
     doc = FixImages(doc);

     htmlString = doc.DocumentNode.OuterHtml;
     return htmlString;
   }

   static HtmlDocument FixImages(HtmlDocument doc)
   {
     foreach (var image in doc.DocumentNode.Descendants("img"))
     {
         var att = image.Attributes["src"];
         if (att == null || !att.Value.StartsWith("/"))
             continue;
         att.Value = "https://www.leadtools.com" + att.Value;
     }
     return doc;
   }

   static HtmlDocument FixLinks(HtmlDocument doc)
   {
     foreach (var link in doc.DocumentNode.Descendants("a"))
     {
         var att = link.Attributes["href"];
         if (att == null || !att.Value.StartsWith("/"))
             continue;
         var href = "https://www.leadtools.com" + att.Value;
         var bookmark = href.IndexOf("#", StringComparison.Ordinal);
         var query = href.IndexOf("?", StringComparison.Ordinal);
         bookmark = bookmark > -1 ? bookmark : href.Length;
         href = query == -1 
            ? href.Insert(bookmark, "?SrcOrigin=VisualStudioGallery") 
            : href.Insert(query + 1, "SrcOrigin=VisualStudioGallery&");

         att.Value = href;
     }
     return doc;
   }    
}

In the code above, the HtmlAgilityPack HtmlDocument is populated by passing the return of the bodyHtmlHelper.ToHtmlString() method. Once the links and images have been fixed, the HtmlDocument.DocumentNode.OuterHtml property is returned and rendered back to the client with a call to Html.Raw().

This is slightly off topic, but I still think worth mentioning. To streamline copying and pasting the HTML markup, I added a div to wrap the part of the page I wanted to copy, a button, and a little JavaScript to the layout. Thanks StackOverflow! Here is the JavaScript:

function CopyClipboard() {
    // creating new textarea element and giveing it id 't'
    const t = document.createElement('textarea');
    t.id = 't';
    t.style.height = 0;
    document.body.appendChild(t);
    // Copy contentDiv HTML into the text area
    t.value = document.getElementById("contentDiv").innerHTML;
    // Now copy whatever inside the textarea to clipboard
    const selector = document.querySelector('#t');
    selector.select();
    document.execCommand('copy');
    // Remove the textarea
    document.body.removeChild(t);
}

Content Pages

The content pages only required one change so that the new layout is used instead of our standard layout.

This:

@{
    Layout = "~/layouts/_Product.cshtml";
}

Became this:

@{
    Layout = "~/layouts/_Product.cshtml";
    if (HttpContext.Current.IsDebuggingEnabled)
    {
        if (HttpContext.Current.Request.QueryString["VSG"] != null)
        {
            Layout = "~/layouts/_ProductVSG.cshtml";
        }
    }
}

Because this is only for internal usage, the code checks to see if the current context is debug (web.config on production servers is always release) and also checks to see if there is a specific query string parameter present before changing the layout.

Same Content, Different Layout

Since the process is streamlined, we have added a tickler to update the content on the MSDN marketplace on a regular basis. Check out an example of the results:

Thanks to ASP.NET and layout pages, what once took days of tedious and error prone HTML editing now takes less than 15 minutes of copy and paste.

Posted in General | Tagged | Leave a comment

Faster OCR for Apple and Android – Plus Some Exciting Platform-Specific Updates

The LEADTOOLS Imaging SDK for iOS, macOS, and Android had a significant update recently! Across the board, the OCR engine has been made 3-6x faster and the demo UI was given a significant redesign. In addition, each platform has its own set of platform-specific updates.

Android

  • Barcode demo code was rewritten, resulting in a much faster implementation
  • Added support for android.hardware.camera2, which means live capture support for all modern devices

Apple

  • ALL libraries are now dynamic
  • Updated interface for better Swift compatibility

If you want to try the latest version, you can download from here. Additionally, we have various sample applications on the App Store and Google Play available as well.

Finally, if you have any questions or would like a consult on your project, feel free to leave a comment here or contact support.

Posted in News | Tagged , , , , , , , , | Leave a comment

Evernote Backup Automation

As I mentioned in a previous post, I am in the process of "Going Paperless." I have decided to use Evernote as my digital repository. (I love the tags!!) One important requirement of my new information repository system is that there has to be a way to back up my data. Unfortunately, Evernote does not include a built-in backup option; however, there is a command line utility to export notes. Since I am semi-dangerous with scripting, I decided to write a batch file to create a consistent and automatic backup system.

Continue reading
Posted in General | Tagged , , , | 2 Comments

My Paperless Journey Begins

After more than 20 years of working for a company that produces the leading document imaging SDK and a card carrying member of AIIM, I finally decided that it was time to personally go paperless. There are many motivations behind this decision, including reducing clutter, better protection for my data, and better access to information when and where I need it.

One of the things that was holding me back in the past was finding a system that I trusted to store my data. My definition of a trusted system is a system where I know my data is secure, safe, and available. Additionally, I need to be able capture data from anywhere, including Internet, e-mail, snail mail, and out in the real world. I was trying a combination of OneNote and OneDrive, but I was not completely happy with it and never totally dove in. Then, I discovered Evernote. I had heard about Evernote in the past, but thought of it as just a non-Microsoft replacement of OneNote. However, once I did begin considering it, I found that there are specific features in Evernote that I have not been able to find or use as easily in OneNote that can make it my trusted system.

Continue reading
Posted in Document Imaging | Tagged , , | 5 Comments

Protect Personal Information with LEADTOOLS

The protection of privacy is at the forefront of concerns for many organizations that need to distribute information. One way to do this is to redact private information from an image or document before releasing it. Recently we had a customer ask how to do this with LEADTOOLS.

Using LEADTOOLS, a user would load an image or a document as an image, use the redaction annotation object to “black-out” the text, and then burn the redaction into the image. Once the protected information is redacted, the image can then be saved as a text searchable PDF so the remaining text can be indexed or searched.

Continue reading
Posted in Document Imaging | Tagged , , , , | Leave a comment

Credit Card Reader SDK – Support for More Platforms Coming Q1 2017

Coming soon in v19

We told you this upcoming release was big, didn’t we? Well today is the last post in our blog series introduction of the upcoming updates to LEADTOOLS V19 Document and Medical technologies. These updates will include a market-first DICOM Hanging Protocol implementation as well as the fastest Form Recognition and Processing engine in the world! Additionally, the upcoming update includes new features for the HTML5 Zero-footprint Medical Web Viewer, DICOM Storage Server, Recognition Engines, Document Viewer, Document Formats, Linux, and Credit Card Reader.

Here we’ll focus on the new availability of the LEADTOOLS Credit Carder Reader SDK for .NET and C:

Continue reading
Posted in News | Tagged , , , | Leave a comment