C# Camera API for Getting Video Frame

If you have a USB camera, how can you build a simple C# camera application on Windows 10? There are three options:  WIA (Windows Imaging Acquisition), DirectShow and MediaCapture. After trying some sample code that downloaded from CodeProject and GitHub, I got the conclusion: 1. WIA is not good because it does not support my webcam.  2. DirectShow can work well, but there is no C# API provided by Microsoft. You need to create a wrapper for C++ API. 3. MediaCapture class that designed for UWP apps provides C# APIs which provide low-level control over the capture pipeline and enable advanced capture scenarios. In this article, I want to share how to create a simple C# webcam app in which I can handle every preview frame myself.

Read more

How to Bridge C Code to Create Swift Barcode Reader on Mac

Have you implemented any barcode reader software in Swift on Mac OS X? Since Dynamsoft released the 1D/2D barcode SDK for Mac, I was wondering how I can bridge the C dylib with Swift. Why Swift, not Objective-C? Because Apple is encouraging developers to migrate to the new programming language, it is important to master the new tool if you want to create more excellent apps for Mac and iOS in the future. Swift is totally new to me, and thus I spent two days googling relevant resources and finally figured out the solution.

Read more

How to Make Java Barcode Reader with Dynamsoft Barcode SDK

Last week, Dynamsoft released Barcode Reader (DBR) SDK v2.0, which is available for Windows and Mac. The Windows installer contains Barcode libraries for ActiveX, C/C++, and .NET. If you are a Java developer, you have to use JNI to link native C/C++ libraries. In this tutorial, I’ll demonstrate how to invoke the native methods of Dynamsoft Barcode SDK via JNI to create a Java Barcode Reader.

Read more

Wrapping C++ OCR Library in Java

Dynamsoft OCR SDK is totally implemented in C++, which means it is easy to be wrapped in high-level programming languages, such as C#, Java, Python and so on. As a proprietary development SDK, so far, only .NET OCR library is available for commercial use. Because some of developers and users are hoping that Dynamsoft could provide a Java OCR library, I wrapped the C++ OCR library for test. Anyone can feel free to use the sample, and I’d like to receive feedbacks from you.

Read more

Java TWAIN with Dynamic .NET TWAIN and jni4net

Dynamic .NET TWAIN is one of the excellent TWAIN-compliant SDKs for document scanning and image capture. In this tutorial, I would like to share how to create a bridge to convert .NET TWAIN C# methods to Java methods in order to help Java developers easily implement TWAIN scanner software.

Source Code

JavaTwain

How to Make Demo Work

  1. Download Dynamic .NET TWAIN
  2. Download and learn jni4net to understand how JVM and CLR work together
  3. Correctly configure the paths of JAVA_HOME and  C:\Windows\Microsoft.NET\Framework\v3.5\csc.exe in the system environment
  4. Unzip the sample code, and launch JavaTwain.sln to build JavaTwain.dll
  5. Copy bin and lib folders from jni4net package to your project directory
  6. Run generateProxies.cmd
  7. Run run.cmd

Java TWAIN

How to Make a Java TWAIN Scanner App based on .NET TWAIN with jni4net

To invoke the Dynamic .NET TWAIN instance, we need to create a bridge in C#.

  1. Add DynamicDotNetTWAIN.dll as a reference.TWAIN reference
  2. Create a class named DotNetScanner, and initialize the .NET TWAIN component in the constructor.
            public DotNetScanner()
            {
                // initialize TWAIN Component
                try
                {
                    dynamicDotNetTwain = new Dynamsoft.DotNet.TWAIN.DynamicDotNetTwain();
                    dynamicDotNetTwain.OnPostAllTransfers += new Dynamsoft.DotNet.TWAIN.Delegate.OnPostAllTransfersHandler(this.dynamicDotNetTwain_OnPostAllTransfers);
                    dynamicDotNetTwain.MaxImagesInBuffer = 64;
                    dynamicDotNetTwain.IfAppendImage = true;
                    dynamicDotNetTwain.IfThrowException = true;
                    dynamicDotNetTwain.IfShowUI = false;
                    dynamicDotNetTwain.IfThrowException = true;
                    dynamicDotNetTwain.ScanInNewProcess = true;
                }
                catch 
                {
                    MessageBox.Show(dynamicDotNetTwain.ErrorString);
                }
    
            }
  3. Create interfaces for data transmission between JVM and CLR.
        public interface IJavaProxy
        {
            bool AcquireImage(int iIndex);
            String[] GetSources();
            bool RegisterListener(INativeProxy proxy);
            void CloseSource();
        }
    
        public interface INativeProxy
        {
            bool Notify(String message, String value);
        }
  4. Capture an image and notify the Java layer to load it.
            public bool AcquireImage(int iIndex)
            {
                try
                {
                    //dynamicDotNetTwain.CloseSource();
                    bool success = dynamicDotNetTwain.SelectSourceByIndex(Convert.ToInt16(iIndex));
                    dynamicDotNetTwain.OpenSource();
                    dynamicDotNetTwain.AcquireImage();
                }
                catch (Dynamsoft.DotNet.TWAIN.TwainException exp)
                {
                    String errorstr = "";
                    errorstr += "Error " + exp.Code + "\r\n" + "Description: " + exp.Message + "\r\nPosition: " + exp.TargetSite + "\r\nHelp: " + exp.HelpLink + "\r\n";
                    MessageBox.Show(errorstr);
                }
                catch (Exception exp)
                {
                    String errorstr = "";
                    errorstr += "ErrorMessage: " + exp.Message + "\r\n";
                    MessageBox.Show(errorstr);
                }
    
                return true;
            }
    
            private void dynamicDotNetTwain_OnPostAllTransfers()
            {
                //MessageBox.Show("dynamicDotNetTwain_OnPostAllTransfers");
    
                if (dynamicDotNetTwain.MaxImagesInBuffer < 1)
                {
                    return;
                }
    
                Image img = dynamicDotNetTwain.GetImage(0);
                img = resizeImage(img, new Size(480, 640));
                img.Save("twain.png");
    
                if (listener != null)
                {
                    listener.Notify("data ready", "twain.png");
                }
            }

To make the C# interfaces work in Java:

  1. Load the JavaTwain.j4n.dll which is generated by proxygen.exe.
            private void initTWAIN() {
    		try {
    			Bridge.init();
    			Bridge.LoadAndRegisterAssemblyFrom(new java.io.File("JavaTwain.j4n.dll"));
    		}
    		catch (Exception e) {
                e.printStackTrace();
            }
    
    		mScanner = new DotNetScanner();
    		mScanner.RegisterListener(this);
    	}
  2. Create Swing UI to interact with the C# bridge.
       public ScanDocuments() {
            super(new BorderLayout());
    		initTWAIN();
    
            //Create a file chooser
            mFileChooser = new JFileChooser();
            FileNameExtensionFilter filter = new FileNameExtensionFilter(
                    ".png", "png");
            mFileChooser.setFileFilter(filter);
            mLoad = new JButton("Load");
            mLoad.addActionListener(this);
    
            mScan = new JButton("Scan");
            mScan.addActionListener(this);
    
    		// get sources
    		mSources = mScanner.GetSources();
    
    		if (mSources != null) {
    			mSourceList = new JComboBox(mSources);
    		}
    		else {
    			mSourceList = new JComboBox(new String[]{"N/A"});
    		}
            mSourceList.setSelectedIndex(0);
    
            // button panel
            JPanel buttonPanel = new JPanel(); 
    		buttonPanel.add(mSourceList);
    		buttonPanel.add(mScan);
    		buttonPanel.add(mLoad);
            add(buttonPanel, BorderLayout.PAGE_START);
    
            // image panel
    		JPanel imageViewer = new JPanel();
    		mImage = new JLabel();
    		mImage.setSize(480, 640);
    		imageViewer.add(mImage);
    		add(imageViewer, BorderLayout.CENTER);
        }

Try it yourself and have fun with Dynamic .NET TWAIN in Java.

Barcode Generator with HTML5 WebSocket

Last week, I shared how to transmit an image between a WebSocket server and a Web client. Based on that, we can make a little bit of improvement. Today, I would like to share how to generate barcode on .Net server side and display it on web browser.

websocket barcode

Prerequisites

Remote Barcode Generator

  • In your WinForms project, add DynamicBarcode.dll and set its property Copy to Output Directory as Copy always. As so, the Dynamic .NET TWAIN component is able to automatically load the barcode library.

barcode library

  • Encode the received message, and draw generated barcode onto a background image:
            float scale = 3;
            short sImageIndex = 0;
            dynamicDotNetTwain.MaxImagesInBuffer = 1;
            bool isLoaded = dynamicDotNetTwain.LoadImage("test.png");
            dynamicDotNetTwain.AddBarcode(sImageIndex, Dynamsoft.DotNet.TWAIN.Enums.Barcode.BarcodeFormat.QR_CODE, message, "", 0, 0, scale);
  • Send image width, height and data to web client:
            Image img = dynamicDotNetTwain.GetImage(sImageIndex);

            ImageData imageData = load_image(img);
            session.Send(imageData.Width + "," + imageData.Height);
            session.Send(imageData.Data, 0, imageData.Data.Length);
            imageData = null;
  • Display the barcode image on JavaScript web client:
               ws.onmessage = function (evt) {
                    var data = evt.data;
                    if (!data)
                        return;

                    if (data instanceof ArrayBuffer) {
                        drawImage(evt.data);
                    }
                    else {
                        var len = data.length;
                        var index = data.indexOf(",");
                        var w = data.substring(0, index);
                        var h = data.substring(index + 1, len);
                        imageWidth = parseInt(w);
                        imageHeight = parseInt(h);
                    }
                };

Now, you can have fun with the remote barcode generator via all browsers (Chrome, Firefox, IE etc.) which support HTML5 WebSocket.

Source Code

WebSocketBarcodeGenerator

 

Image Transmission between a HTML5 WebSocket Server and a Web Client

HTML5 WebSocket facilitates the communication between web browsers and local/remote servers. If you want to learn a simple websocket example, creating a WebSocket Server in C# and a Web client in JavaScript, you can refer to SuperWebSocket, which is a .NET implementation of Web Socket Server.

In this article, I would like to share how I implemented a simple WebSocket solution for image transmission based on the basic sample code of SuperWebSocket and Dynamic .NET TWAIN, especially what problem I have solved.

Here is a quick look of the WebSocket server and the HTML5 & JavaScript client.

WebSocket ServerWebSocket Client

Prerequisites

Create a .NET WebSocket Server

Create a new WinForms project, and add the following references which are located at the folder of SuperWebSocket.

WebSocket References

Add the required namespaces:

using Dynamsoft.DotNet.TWAIN;

using SuperSocket.SocketBase;
using SuperWebSocket;

In the sample code, the server is launched with port 2012, no IP specified by default. You can specify the IP address for remote access. For example:

if (!appServer.Setup("192.168.8.84", 2012)) //Setup with listening port
{
     MessageBox.Show("Failed to setup!");
     return;
}

You can use Dynamic Web TWAIN component to do some image operation. With two lines of code, I can load an image file:

bool isLoad = dynamicDotNetTwain.LoadImage("dynamsoft_logo_black.png"); // load an image
Image img = dynamicDotNetTwain.GetImage(0);

Be careful of the image format. It is PNG. If you want to display it in a Web browser, you need to convert the format from PNG to BMP:

            byte[] result;
            using (System.IO.MemoryStream stream = new System.IO.MemoryStream())
            {
                img.Save(stream, System.Drawing.Imaging.ImageFormat.Bmp);   // convert png to bmp
                result = stream.GetBuffer();
            }

It’s not done yet. The byte array contains some extra image information, which is 54 bytes in length. So the actual data length is:

int iRealLen = result.Length - 54;
byte[] image = new byte[iRealLen];

Here are some tricky things that if you just send the subset of the byte array to your Web browser, you will find the displayed image is upside-down, and the color is also incorrect.

To fix the position issue, you need to sort the bytes of original data array from bottom to top. As to the color, exchange the position of blue and red. See the code:

            int iIndex = 0;
            int iRowIndex = 0;
            int iWidth = width * 4;
            for (int i = height - 1; i >= 0; --i)
            {
                iRowIndex = i * iWidth;
                for (int j = 0; j < iWidth; j += 4)
                {
                    // RGB to BGR
                    image[iIndex++] = result[iRowIndex + j + 2 + 54]; // B
                    image[iIndex++] = result[iRowIndex + j + 1 + 54]; // G
                    image[iIndex++] = result[iRowIndex + j + 54];     // R
                    image[iIndex++] = result[iRowIndex + j + 3 + 54]; // A
                }   
            }

Now, you can send the data via:

session.Send(imageData.Data, 0, imageData.Data.Length);

Create a JavaScript Client

To receive the image as ArrayBuffer on the client side, you have to specify the binaryType after creating a WebSocket:

ws.binaryType = "arraybuffer";

Once the image data is received, draw all bytes onto a new canvas, and finally create an image element to display the canvas data:

                var imageWidth = 73, imageHeight = 73; // hardcoded width & height. 
                var byteArray = new Uint8Array(data);

                var canvas = document.createElement('canvas');
                canvas.height = imageWidth;
                canvas.width = imageHeight;
                var ctx = canvas.getContext('2d');

                var imageData = ctx.getImageData(0, 0, imageWidth, imageHeight); // total size: imageWidth * imageHeight * 4; color format BGRA
                var dataLen = imageData.data.length;
                for (var i = 0; i < dataLen; i++)
                {
                    imageData.data[i] = byteArray[i];
                }
                ctx.putImageData(imageData, 0, 0);

                // create a new element and add it to div
                var image = document.createElement('img');
                image.width = imageWidth;
                image.height = imageHeight;
                image.src = canvas.toDataURL();

                var div = document.getElementById('img');
                div.appendChild(image);

Download Sample

WebSocketImageSendSource

How to Use C# to Read resx Files in Visual Studio

If you ever developed some iOS or Android apps, you should know that for localization, the strings should be stored in some resource files and dynamically loaded in apps. What about Windows applications?

When I tried to store strings in a resource file in Visual Studio, I met some problems and finally found out the solution. In this tutorial, I would like to share my experience about how to dynamically load strings from a resx file.

How to create a resx File?

Create a new project. Notice that there is a default resx file named Form1.resx, which is auto-generated by Visual Studio. I ever made a mistake that I created all strings in this resx file. What happened later? As I edited some elements on viewer designer, and saved the Form, the resx file was totally cleaned up. So you have to remember that do not put strings in the Form1.resx.

Right-click on the project root, and add a new resource file named strings.resx.

Open the properties of the resx file. Set the Build Action as Content. Set Copy to Output Directory as Copy if newer.

build action

As such, when you build the project, the resx file will be automatically copied to the output directory.

How to Read resx File?

string resxFile = @".\strings.resx"; // relative directory to the executable file
using (ResXResourceSet resxSet = new ResXResourceSet(resxFile))
{
   this.Text = resxSet.GetString("app_title");
}