Create WPF Browser Application to Scan a Document from Scanner(ADF and Flatbed) Using WIA

Let's Start with step by step instructions to create the WPF browser application for scanning the documents.
 
Step 1: First open the visual studio and select the project type WPF Browser based Application.
 
Check in this Image how to create WPF browser application,

 
Step 2: In the second step design your page as you want to view in browser accordingly.   
 
Step 3:  Now you have to add the Interop.WIA.dll and itextsharp.dll in your project reference.
 
Step 4:  Now you have to add System.Drawing and System.Web Assemblies. 
 
Step 5:  Now Generate the click event to start the scanning. 

Step 6:
  Here I have given all the code, just go through that and you can change the code according to your requirement or just copy and paste into your cs page.
  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Text;  
  5. using System.Threading.Tasks;  
  6. using System.Windows;  
  7. using System.Windows.Controls;  
  8. using System.Windows.Data;  
  9. using System.Windows.Documents;  
  10. using System.Windows.Input;  
  11. using System.Windows.Media;  
  12. using System.Windows.Media.Imaging;  
  13. using System.Windows.Navigation;  
  14. using System.Windows.Shapes;  
  15.   
  16. using WIA;  
  17. using System.Deployment.Application;  
  18. using System.Runtime.InteropServices;  
  19. using System.Windows.Interop;  
  20. using System.Collections.Specialized;  
  21. using System.Web;  
  22. using System.Security.Cryptography;  
  23. using System.Reflection;  
  24. using System.Configuration;  
  25. using System.IO;  
  26. using System.Drawing.Imaging;  
  27.   
  28. namespace WpfBrowserApplication1  
  29. {  
  30.    /// <summary>  
  31.     /// Interaction logic for Page1.xaml  
  32.     /// </summary>  
  33.     public partial class Page1 : Page  
  34.     {  
  35.         List<System.Drawing.Image> obj = new List<System.Drawing.Image>();  
  36.         List<Scannerdata> objListSD = new List<Scannerdata>();  
  37.         int GlobalSquence = 1;  
  38.         int count = 0;  
  39.         int SequenceTotal = 1;  
  40.   
  41.   
  42.   
  43.         public Page1()  
  44.         {  
  45.             InitializeComponent();  
  46.             _deviceId = GetDefaultDeviceID();  
  47.             _deviceInfo = FindDevice(_deviceId);  
  48.             _device = _deviceInfo.Connect();  
  49.   
  50.             btnPreview.IsEnabled = false;  
  51.             btnNext.IsEnabled = false;  
  52.         }  
  53.  
  54.  
  55.  
  56.        
  57.  
  58.         #region WIA constants  
  59.         public const int WIA_DPS_DOCUMENT_HANDLING_CAPABILITIES = 3086;  
  60.         public const int WIA_DPS_DOCUMENT_HANDLING_STATUS = 3087;  
  61.         public const int WIA_DPS_DOCUMENT_HANDLING_SELECT = 3088;  
  62.   
  63.         public const string WIA_FORMAT_JPEG = "{B96B3CAE-0728-11D3-9D7B-0000F81EF32E}";  
  64.   
  65.         public const int FEED_READY = 0x00000001;  
  66.         public const int FLATBED_READY = 0x00000002;  
  67.   
  68.         public const uint BASE_VAL_WIA_ERROR = 0x80210000;  
  69.         public const uint WIA_ERROR_PAPER_EMPTY = BASE_VAL_WIA_ERROR + 3;  
  70.         #endregion  
  71.   
  72.         private string _deviceId;  
  73.         private DeviceInfo _deviceInfo;  
  74.         private Device _device;  
  75.   
  76.   
  77.         private DeviceInfo FindDevice(string deviceId)  
  78.         {  
  79.             DeviceManager manager = new DeviceManager();  
  80.             foreach (DeviceInfo info in manager.DeviceInfos)  
  81.                 if (info.DeviceID == deviceId)  
  82.                     return info;  
  83.   
  84.             return null;  
  85.         }  
  86.   
  87.         private string GetDefaultDeviceID()  
  88.         {  
  89.             string deviceId = string.Empty;  
  90.   
  91.             //string deviceId = Properties.Settings.Default.ScannerDeviceID;  
  92.   
  93.             //if (String.IsNullOrEmpty(deviceId))  
  94.             //{  
  95.             Device d = null;  
  96.             WIA.CommonDialog wiaDiag = new WIA.CommonDialog();  
  97.             try  
  98.             {  
  99.                 d = wiaDiag.ShowSelectDevice(WiaDeviceType.ScannerDeviceType, truefalse);  
  100.                 if (d != null)  
  101.                 {  
  102.                     deviceId = d.DeviceID;  
  103.                     Properties.Settings.Default.ScannerDeviceID = deviceId;  
  104.                     Properties.Settings.Default.Save();  
  105.                 }  
  106.                 else  
  107.                 {  
  108.                     MessageBox.Show("Check the Device Connection \n or \n Change the Scanner Device""Device Not Found!", MessageBoxButton.OKCancel, MessageBoxImage.Exclamation);  
  109.                     var hostScript = BrowserInteropHelper.HostScript;  
  110.                     hostScript.document.ResponseData("");  
  111.                 }  
  112.             }  
  113.             catch (Exception err)  
  114.             {  
  115.                  
  116.                 MessageBox.Show("Scaner device not found in your system""Devic Not Found!", MessageBoxButton.OKCancel, MessageBoxImage.Error);  
  117.                 var hostScript = BrowserInteropHelper.HostScript;  
  118.                 hostScript.document.ResponseData("");  
  119.             }  
  120.             return deviceId;  
  121.         }  
  122.   
  123.         public List<System.Drawing.Image> ScanPages(int dpi = 150, double width = 8.27, double height = 11.69)  
  124.         {  
  125.             Item item = _device.Items[1];  
  126.   
  127.             // configure item  
  128.             SetDeviceItemProperty(ref item, 6146, 2); // greyscale  
  129.             SetDeviceItemProperty(ref item, 6147, dpi); // 150 dpi  
  130.             SetDeviceItemProperty(ref item, 6148, dpi); // 150 dpi  
  131.             SetDeviceItemProperty(ref item, 6151, (int)(dpi * width)); // scan width  
  132.             SetDeviceItemProperty(ref item, 6152, (int)(dpi * height)); // scan height  
  133.             SetDeviceItemProperty(ref item, 4104, 8); // bit depth  
  134.   
  135.             // TODO: Detect if the ADF is loaded, if not use the flatbed  
  136.   
  137.             List<System.Drawing.Image> images = GetPagesFromScanner(ScanSource.DocumentFeeder, item);  
  138.             if (images.Count == 0)  
  139.             {  
  140.                 // Try from flatbed  
  141.                 // DialogResult dialogResult;  
  142.                 MessageBoxResult dialogResult;  
  143.                 do  
  144.                 {  
  145.                     List<System.Drawing.Image> singlePage = GetPagesFromScanner(ScanSource.Flatbed, item);  
  146.                     images.AddRange(singlePage);  
  147.                     dialogResult = MessageBox.Show("Do you want to scan another page?""ScanToEvernote", MessageBoxButton.YesNo, MessageBoxImage.Question);  
  148.                 }  
  149.                 while (dialogResult == MessageBoxResult.Yes);  
  150.             }  
  151.             return images;  
  152.         }  
  153.   
  154.         private List<System.Drawing.Image> GetPagesFromScanner(ScanSource source, Item item)  
  155.         {  
  156.             SetDeviceProperty(ref _device, 3088, (int)source);  
  157.   
  158.             List<System.Drawing.Image> images = new List<System.Drawing.Image>();  
  159.   
  160.             int handlingStatus = GetDeviceProperty(ref _device, WIA_DPS_DOCUMENT_HANDLING_STATUS);  
  161.             if ((source == ScanSource.DocumentFeeder && handlingStatus == FEED_READY) || (source == ScanSource.Flatbed && handlingStatus == FLATBED_READY))  
  162.             {  
  163.                 do  
  164.                 {  
  165.                     ImageFile wiaImage = null;  
  166.                     try  
  167.                     {  
  168.                         wiaImage = item.Transfer(WIA_FORMAT_JPEG);  
  169.                     }  
  170.                     catch (COMException ex)  
  171.                     {  
  172.                         if ((uint)ex.ErrorCode == WIA_ERROR_PAPER_EMPTY)  
  173.                             break;  
  174.                         else  
  175.                             throw;  
  176.                     }  
  177.   
  178.                     if (wiaImage != null)  
  179.                     {  
  180.   
  181.                         System.Diagnostics.Trace.WriteLine(String.Format("Image is {0} x {1} pixels", (float)wiaImage.Width / 150, (float)wiaImage.Height / 150));  
  182.                         System.Drawing.Image image = ConvertToImage(wiaImage);  
  183.                         images.Add(image);  
  184.                     }  
  185.                 }  
  186.                 while (source == ScanSource.DocumentFeeder);  
  187.             }  
  188.             return images;  
  189.         }  
  190.   
  191.         private static System.Drawing.Image ConvertToImage(ImageFile wiaImage)  
  192.         {  
  193.             byte[] imageBytes = (byte[])wiaImage.FileData.get_BinaryData();  
  194.             MemoryStream ms = new MemoryStream(imageBytes);  
  195.   
  196.             System.Drawing.Image image = System.Drawing.Image.FromStream(ms);  
  197.             //  Image image = Image.FromStream(ms);  
  198.             return image;  
  199.         }  
  200.  
  201.         #region Get/set device properties  
  202.   
  203.         private void SetDeviceProperty(ref Device device, int propertyID, int propertyValue)  
  204.         {  
  205.             foreach (Property p in device.Properties)  
  206.             {  
  207.                 if (p.PropertyID == propertyID)  
  208.                 {  
  209.                     object value = propertyValue;  
  210.                     p.set_Value(ref value);  
  211.                     break;  
  212.                 }  
  213.             }  
  214.         }  
  215.   
  216.         private int GetDeviceProperty(ref Device device, int propertyID)  
  217.         {  
  218.             int ret = -1;  
  219.   
  220.             foreach (Property p in device.Properties)  
  221.             {  
  222.                 if (p.PropertyID == propertyID)  
  223.                 {  
  224.                     ret = (int)p.get_Value();  
  225.                     break;  
  226.                 }  
  227.             }  
  228.   
  229.             return ret;  
  230.         }  
  231.   
  232.         private void SetDeviceItemProperty(ref Item item, int propertyID, int propertyValue)  
  233.         {  
  234.             foreach (Property p in item.Properties)  
  235.             {  
  236.                 if (p.PropertyID == propertyID)  
  237.                 {  
  238.                     object value = propertyValue;  
  239.                     p.set_Value(ref value);  
  240.                     break;  
  241.                 }  
  242.             }  
  243.         }  
  244.   
  245.         private int GetDeviceItemProperty(ref Item item, int propertyID)  
  246.         {  
  247.             int ret = -1;  
  248.   
  249.             foreach (Property p in item.Properties)  
  250.             {  
  251.                 if (p.PropertyID == propertyID)  
  252.                 {  
  253.                     ret = (int)p.get_Value();  
  254.                     break;  
  255.                 }  
  256.             }  
  257.   
  258.             return ret;  
  259.         }  
  260.  
  261.         #endregion  
  262.   
  263.         private delegate void UpdateProgressBarDelegate(System.Windows.DependencyProperty dp, Object value);  
  264.   
  265.         /// <summary>  
  266.         /// Button_Click Used for start the sacnning  
  267.         /// </summary>  
  268.         /// <param name="sender"></param>  
  269.         /// <param name="e"></param>  
  270.         private void Button_Click(object sender, RoutedEventArgs e)  
  271.         {  
  272.             //Make butone enable false   
  273.             btnAttach.IsEnabled = false;  
  274.             btnScan.IsEnabled = false;  
  275.             pic_scan.Source = null;  
  276.             lbl_message.Content = string.Empty;  
  277.   
  278.             //Configure the ProgressBar  
  279.             ProgressBar1.Minimum = 0;  
  280.             ProgressBar1.Maximum = 1000;  
  281.             ProgressBar1.Value = 0;  
  282.   
  283.             //Stores the value of the ProgressBar  
  284.             double value = 0;  
  285.   
  286.             //Create a new instance of our ProgressBar Delegate that points  
  287.             //  to the ProgressBar's SetValue method.  
  288.             UpdateProgressBarDelegate updatePbDelegate = new UpdateProgressBarDelegate(ProgressBar1.SetValue);  
  289.   
  290.             //Tight Loop:  Loop until the ProgressBar.Value reaches the max  
  291.             do  
  292.             {  
  293.                 value += 1;  
  294.   
  295.                 /*Update the Value of the ProgressBar: 
  296.                   1)  Pass the "updatePbDelegate" delegate that points to the ProgressBar1.SetValue method 
  297.                   2)  Set the DispatcherPriority to "Background" 
  298.                   3)  Pass an Object() Array containing the property to update (ProgressBar.ValueProperty) and the new value */  
  299.                 Dispatcher.Invoke(updatePbDelegate,  
  300.                     System.Windows.Threading.DispatcherPriority.Background,  
  301.                     new object[] { ProgressBar.ValueProperty, value });  
  302.   
  303.             }  
  304.             while (ProgressBar1.Value != ProgressBar1.Maximum);  
  305.             if (ProgressBar1.Value == ProgressBar1.Maximum)  
  306.             {  
  307.                 ProgressBar1.IsEnabled = true;  
  308.   
  309.                 obj = ScanPages();//start scan method  
  310.   
  311.                 foreach (System.Drawing.Image aa in obj)  
  312.                 {  
  313.                     Scannerdata objSD = new Scannerdata();  
  314.                     objSD.Sequence = SequenceTotal;  
  315.                     objSD.ImageObj = aa;  
  316.   
  317.                     objListSD.Add(objSD);  
  318.                     SequenceTotal++;  
  319.                 }  
  320.   
  321.                 Scannerdata first = (from row in objListSD where row.Sequence == GlobalSquence select row).FirstOrDefault();  
  322.   
  323.                 LoadImage(first.ImageObj);  
  324.   
  325.   
  326.                 // Application.Current.Properties["Objliost"] = obj.ToList();  
  327.             }  
  328.             if (obj.Count == 1)  
  329.             {  
  330.                 btnPreview.IsEnabled = false;  
  331.                 btnNext.IsEnabled = false;  
  332.                 lbl_message.Visibility = Visibility.Visible;  
  333.                 lbl_message.Content = "Single page scaning Completed.";  
  334.             }  
  335.             else if (obj.Count > 1)  
  336.             {  
  337.                 //btnPreview.IsEnabled = true;  
  338.                 btnNext.IsEnabled = true;  
  339.                 lbl_message.Visibility = Visibility.Visible;  
  340.                 lbl_message.Content = "Multiple page scaning Completed.";  
  341.             }  
  342.             btnAttach.IsEnabled = true;  
  343.             btnScan.IsEnabled = true;  
  344.             ProgressBar1.Value = 0;  
  345.   
  346.         }  
  347.   
  348.         /// <summary>  
  349.         /// Use for Load the Image in Image Box  
  350.         /// </summary>  
  351.         /// <param name="loaddata"></param>  
  352.         /// <returns></returns>  
  353.         public byte[] LoadImage(System.Drawing.Image loaddata)  
  354.         {  
  355.             BitmapImage bi = new BitmapImage();  
  356.   
  357.             bi.BeginInit();  
  358.   
  359.             MemoryStream ms = new MemoryStream();  
  360.   
  361.             // Save to a memory stream...  
  362.   
  363.             loaddata.Save(ms, ImageFormat.Jpeg);  
  364.   
  365.             //  Rewind the stream...  
  366.   
  367.             ms.Seek(0, SeekOrigin.Begin);  
  368.   
  369.             // cache the image  
  370.             bi.CacheOption = BitmapCacheOption.OnLoad;  
  371.   
  372.             // Tell the WPF image to use this stream...  
  373.             bi.StreamSource = ms;  
  374.   
  375.             bi.EndInit();  
  376.             pic_scan.Source = bi;  
  377.             bi.Freeze();  
  378.   
  379.   
  380.             return ms.ToArray();  
  381.         }  
  382.   
  383.         /// <summary>  
  384.         /// Button_Click_3 used for saved the scanned documents in pdf.  
  385.         /// </summary>  
  386.   
  387.         private void Button_Click_3(object sender, RoutedEventArgs e)  
  388.         {  
  389.             using (var ms = new MemoryStream())  
  390.             {  
  391.                 var document = new iTextSharp.text.Document(iTextSharp.text.PageSize.LETTER.Rotate(), 0, 0, 0, 0);  
  392.                 iTextSharp.text.pdf.PdfWriter.GetInstance(document, ms).SetFullCompression();  
  393.                 document.Open();  
  394.   
  395.                 foreach (System.Drawing.Image aa in obj)  
  396.                 {  
  397.                     MemoryStream msimage = new MemoryStream();  
  398.   
  399.                     aa.Save(msimage, ImageFormat.Jpeg);  
  400.   
  401.                     var image = iTextSharp.text.Image.GetInstance(msimage.ToArray());  
  402.                     image.ScaleToFit(document.PageSize.Width, document.PageSize.Height);  
  403.                     document.Add(image);  
  404.                 }  
  405.                 document.Close();  
  406.   
  407.                 //Path will come from App config  
  408.                 string Path = ConfigurationManager.AppSettings["uploadfolderpath"].ToString();//confige path  
  409.   
  410.   
  411.                 string filename = "C3kycDMS" + DateTime.Now.ToString("yyyy-MM-dd HHmmss") + ".pdf";  
  412.   
  413.                 //Save using drive name  
  414.   
  415.                 File.WriteAllBytes(Path + filename, ms.ToArray());  
  416.                 byte[] test = ms.ToArray();  
  417.   
  418.   
  419.   
  420.   
  421.                 MessageBox.Show("File Uploaded Successfully""Success!", MessageBoxButton.OKCancel);  
  422.                 pic_scan.Source = null;  
  423.   
  424.   
  425.                 
  426.             }  
  427.   
  428.   
  429.         }  
  430.   
  431.         /// <summary>  
  432.         /// Used for Next button to see the images  
  433.         /// </summary>  
  434.         /// <param name="sender"></param>  
  435.         /// <param name="e"></param>  
  436.         private void Button_Click_2(object sender, RoutedEventArgs e)  
  437.         {  
  438.             btnPreview.IsEnabled = true;  
  439.             if (GlobalSquence < SequenceTotal)  
  440.             {  
  441.                 GlobalSquence++;  
  442.             }  
  443.             Scannerdata first = (from row in objListSD where row.Sequence == GlobalSquence select row).FirstOrDefault();  
  444.             LoadImage(first.ImageObj);  
  445.             if (GlobalSquence == SequenceTotal - 1)  
  446.             {  
  447.                 btnNext.IsEnabled = false;  
  448.             }  
  449.   
  450.         }  
  451.         /// <summary>  
  452.         /// Used for Preview the page  
  453.         /// </summary>  
  454.         /// <param name="sender"></param>  
  455.         /// <param name="e"></param>  
  456.         private void Button_Click_1(object sender, RoutedEventArgs e)  
  457.         {  
  458.             btnNext.IsEnabled = true;  
  459.             if (GlobalSquence < SequenceTotal)  
  460.             {  
  461.                 GlobalSquence--;  
  462.             }  
  463.             Scannerdata first = (from row in objListSD where row.Sequence == GlobalSquence select row).FirstOrDefault();  
  464.             LoadImage(first.ImageObj);  
  465.             if (GlobalSquence == 1)  
  466.             {  
  467.                 btnPreview.IsEnabled = false;  
  468.             }  
  469.   
  470.         }  
  471.   
  472.         
  473.     }  
  474.   
  475.     enum ScanSource  
  476.     {  
  477.         DocumentFeeder = 1,  
  478.         Flatbed = 2,  
  479.     }  
  480. }  
  481. public class Scannerdata  
  482. {  
  483.     public int Sequence { getset; }  
  484.   
  485.     public System.Drawing.Image ImageObj { getset; }  
  486. }  
Step 7:  This is important you have to set device Id as seen in the below Image.

 
Step 8: If you are running WPF browser application make sure your site is a fuly trusted site if it is not you have to make this a fully trusted site.

To make it a fully trusted site follow this steps.

Goto SoluationExplorer -> Rightclick -> goto Properties -> select Security option -> now select Radio button Full trusted application -> Save and run.
 
Check in this Image,

 
I think this will help you but if you have any doubts or queries you can reach me any time. 
 
Note: Same solution you can find with WINDOWS FORM  -- to check this click on below link and check in my blogs,