Develop a simple scanning application with the NAPS2 SDK
Digital Docs
A simple command-line application that scans one or more documents and saves them as images (JPEG, PNG, TIFF) and PDFs uses an SDK provided by the Not Another PDF Scanner 2 (NAPS2) developers, the C# language, and the .NET framework. NAPS2 is a free, open source, document-scanning application that allows users to scan, organize, and save documents [1].
NAPS2 supports various scanners and offers optical character recognition (OCR), batch scanning, and easy document editing, all with a simple, user-friendly interface. Although the NAPS2 application and SDK are cross-platform, the drivers and libraries related to the system's graphical interface vary depending on the operating system. Therefore, the application in this article will be specific to Linux. However, you can adapt the code to a different environment by making a few simple modifications.
Setting Up the Environment
I recommend setting up an integrated development environment like Visual Studio Code (VSCode) [2] for C# and .NET programming and having a basic understanding of the language and the framework. On Ubuntu, an easy way to install VSCode is by downloading the .deb package, right-clicking the file, and selecting the Install
option.
Alternatively, you can search for vscode in the App Center and click the Install button. If you prefer the terminal, you can find detailed instructions for any Linux distribution online [3]. I also suggest adding C# and .NET development extensions, including .NET Install Tool , C# , C# Dev Kit , and Code Runner to manage and run the project.
The .NET framework is necessary, and it is officially supported on various distributions. On Ubuntu, the easiest way is to proceed through the App Center. The .NET website [4] provides more detailed information about the installation and configuration of the framework.
Creating the Project Solution
Once the VSCode extensions are installed, you create a new project by selecting File | New File | .NET New Project
(Figure 1). Alternatively, you could proceed in the terminal with the dotnet new command; however, VSCode and its extensions greatly simplify project management at every stage.
The project folder will contain subfolders named .vscode, bin, and obj, as well as files with the extensions .csproj, .cs, and .sln. The .csproj file contains the list of installed NuGet packages and other project properties, such as the version of the .NET library being used. A NuGet package is an archive that contains compiled code, metadata, and dependencies for reusable .NET libraries or tools; it simplifies adding, updating, and managing dependencies in .NET projects.
The .cs file contains the application code, and the .sln file serves as a container for multiple related projects and configurations, specifying the relationships between projects, their build configurations (e.g., Debug
or Release
), and target platforms (e.g., Any CPU
or x64
). The file also stores global solution settings, including the build order and dependencies and may include logical groupings of projects or files for better organization.
To add NuGet packages, just press Ctrl+Shift+P and enter the name of the desired package (Figure 2). A list of entries matching the search appears. Simply select the correct package from the list and the most recent available version. The packages needed for this project are NAPS2.Images
, NAPS2.Images.Gtk
, and NAPS2.Sdk
. After adding them, the .csproj file should look similar to Listing 1.
Listing 1
myScan.csproj
<PackageReference Include="NAPS2.Images" Version="1.1.3" /> <PackageReference Include="NAPS2.Images.Gtk" Version="1.1.3" /> <PackageReference Include="NAPS2.Sdk" Version="1.1.3" />
Developing the Application
The SDK provides good encapsulation of scanning functions, and the resulting code is quite straightforward (Listing 2). This code demonstrates how you can use the NAPS2 library to build a simple application for scanning documents and exporting them as a PDF.
Listing 2
Program.cs
01 using NAPS2.Images;
02 using NAPS2.Images.Gtk;
03 using NAPS2.Scan;
04 using NAPS2.Pdf;
05
06 public class HelloWorldSample
07 {
08 static async Task Main(string [] args)
09 {
10 await HelloWorldSample.Run();
11 }
12
13 public static async Task Run()
14 {
15 using var scanningContext = newScanningContext(new GtkImageContext());
16 var controller = new ScanController(scanningContext);
17
18 ScanDevice device = (await controller.GetDeviceList()).First();
19
20 var options = new ScanOptions
21 {
22 Device = device,
23 PaperSource = PaperSource.Feeder,
24 PageSize = PageSize.A4,
25 Dpi = 300
26 };
27
28 var images = new List<NAPS2.Images.ProcessedImage>();
29
30 int i=1;
31 Console.WriteLine("Scan in process..");
32 await foreach (var image incontroller.Scan(options))
33 {
34 image.Save($"page{i++}.jpg");
35 images.Add(image);
36 }
37 Console.WriteLine("Scanning complete!");
38
39 var pdfExporter = new PdfExporter(scanningContext);
40 await pdfExporter.Export("doc.pdf",images);
41 }
42 }
To start, you import the necessary namespaces from the library (e.g., NAPS2.Images, NAPS2.Scan, and NAPS2.Pdf), which provide all the functionality needed to manage images, control the scanner, and handle PDF exports. For the GTK-based image-handling context, also include NAPS2.Images.Gtk
. To ensure the application works on Windows, you should use the NAPS2.Images.Gdi
library instead.
The program begins with the definition of the HelloWorldSample class, which contains the Main method entry point, where you invoke the Run method asynchronously. This design ensures that the program can handle time-consuming operations like scanning and file export without blocking the main thread.
In the Run method, you first establish a scanning environment by creating a ScanningContext object, which is configured to use a GtkImageContext that provides the necessary tools to process scanned images in a GTK-based graphical environment. Next, you initialize a ScanController object in this scanning context, which acts as the main interface for interacting with the scanner.
Next, retrieve the list of available scanning devices by calling the GetDeviceList method on the controller. From this list you select the first device to proceed with the scan. With the device selected, the ScanOptions object sets up the scanning options. Here, you specify that the feeder tray will be the paper source, the page size will be A4, and the scan resolution will be 300DPI. The scanner parameters are highly customizable. For instance, to change the document source from the feeder to the scanner's flatbed, you simply need to set the PaperSource option to Flatbed. You can find complete documentation for the available APIs online [5].
Once the scanning options are configured, you begin the scanning process by creating an empty list to store the scanned images and an await foreach loop to process each image as it is produced by the scanner. As each page is scanned, you save it as a JPEG file, naming the files sequentially (e.g., page1.jpg, page2.jpg, etc.). Also, each processed image is added to the list, ensuring you have all the scanned pages ready for the final PDF export.
During the scanning process, you print messages to the console to indicate progress, letting the user know that the scan is underway and when it is complete. This basic feedback provides a better user experience. After all the pages have been scanned, you move on to the final step: creating a PDF by initializing a PdfExporter object in the same scanning context used earlier. The Export method of the PdfExporter combines all the scanned images into a single PDF file named doc.pdf, completing the process. The program ends after successfully generating the PDF.
The primary drawback of the NAPS2 SDK is its limited adoption, which makes it challenging to find support information when needed.
Buy this article as PDF
(incl. VAT)
Buy ADMIN Magazine
Subscribe to our ADMIN Newsletters
Subscribe to our Linux Newsletters
Find Linux and Open Source Jobs
Most Popular
Support Our Work
ADMIN content is made possible with support from readers like you. Please consider contributing when you've found an article to be beneficial.

