C# Winform 从扫描仪获取图片 并导出为PDF

      最近在做一个科研档案管理系统的项目,需要能够直接调用扫描仪进行扫描。扫描仪又分为是否有进稿器(批量扫描和一张一张扫描),进稿器模式使用twain协议就可以做,直接可以得到PDF文件,这个网上有很多案例我也没做什么创新,就不写了。另外一种方式因为扫描仪没有进稿器,一次只能扫描一张图像,所以可以是利用WIA获取图像,保存在临时文件夹下,然后最后再转为PDF导出。这篇文章说的就是这种方法。

利用WIA从扫描仪获取图像

1.添加引用

如图,为winform项目添加引用。网上看到有提问说找不到这个引用,据说是安装office2007以上版本可以解决,我没试过,因为大部分电脑都装了office,如果有解决这个问题经验的欢迎交流。

然后,在CS文件中添加USING,如下:

using WIA;

从扫描仪获取图像

1、先new 一个WIA.CommonDialogClass对象

CommonDialogClass cdc = new WIA.CommonDialogClass();

2、调用CommonDialogClass对象的ShowAcquireImage方法可以获取扫描仪图像

这个方法的说明可以看微软的官方文档,就不多做解释了

https://docs.microsoft.com/zh-cn/previous-versions/windows/desktop/wiaaut/-wiaaut-icommondialog-showacquireimage

我们只要知道返回的是一个ImageFile对象,这个对象有一个SaveFile方法可以把获取到的图像存为文件。

var imageFile = cdc.ShowAcquireImage(WIA.WiaDeviceType.ScannerDeviceType,WIA.WiaImageIntent.TextIntent,WIA.WiaImageBias.MaximizeQuality,"{00000000-0000-0000-0000-000000000000}",true,true,false);

这样就得到了imageFile对象了。

当然,这个方法不一定可靠,如果获取失败他会抛出一个异常,我们可以用 try catch捕获异常,我暂时捕获的是System.Runtime.InteropServices.COMException异常

接下来,用

imageFile.SaveFile("你设置的存储路径,以jpg,bmp,png结尾都行,我试过了可用");

在picturebox中显示扫描的图像

在界面上画一个picturebox控件。由于picturebox不能直接给路径,得给一个Image对象,Image提供了一个FromStream方法从图像文件流构造Image对象,因此,需要先读图像文件并获取文件流

这里当然是先using 

using System.IO;

然后通过他的构找函数new一个FileStream 对象,因为涉及到释放资源的问题,建议使用using把它包裹起来。

using (FileStream stream = new FileStream("刚才存储的图片地址", FileMode.Open,
                    FileAccess.Read, FileShare.Read))

这样stream就是我们要的图像文件流了。

之后我们构造获取Image对象

var img=Image.FromStream(stream);;

然后就是

pictureBox1.Image = img;

这样picturebox1里面就会显示图像了。

 

图像转为PDF

一份文件可能由多页构成,一次上传好多图片可能并不利于阅读,因此我的设计是你只要按顺序进行扫描,之后就可以一键导出,将本次打开这个软件并扫描的多张图像转为一个pdf,挺方便的。

这里用到一个类库iTextSharp,可以在nuget上安装这个类库或者自己去下载一个iTextSharp.dll来添加引用。

经验:因为iTextSharp也存在一个Image类,和我们前面用的Image重名,这样就需要在写的时候标注具体指的是哪个image,所以我干脆就不using iTextSharp的命名空间。把代码写长点毕竟只用写那么几句,方便的很。

在这之前要先读取到已经扫描的文件,我的设计思路是读取本次的临时文件夹(每次打开软件第一次扫描会生成一个临时文件夹),列出该文件夹下所有的文件,这样万一扫描错了你直接在文件夹中删除文件就ok了,我的软件就不用负责管理。

private List<string> GetImageFileList()
        {
            
            List<string> res = new List<string>();
            if (!Directory.Exists(path))
            {
                Directory.CreateDirectory(path);
                return res;
            }
            DirectoryInfo root = new DirectoryInfo(path);
            FileInfo[] files=root.GetFiles();
            foreach (var file in files)
            {
                if (file.FullName.Substring(file.FullName.LastIndexOf(".")+1).ToLower() == "pdf")
                    continue;
                res.Add(file.FullName);
            }
            return res;
        }

 

正式开始,先创建一个iTestSahrp.text.Document对象,也就相当于新建一个空文档,设置好它的纸张大小、页边距,代码入下:

iTextSharp.text.Document document = new iTextSharp.text.Document(iTextSharp.text.PageSize.A4, 25, 25, 25, 25);

然后,需要获取到一个pdfWriter对象,类库中这个类使用了单例模式,所以用GetInstance来创建对象。后面我发现由于它采用了单一实例,得到的对象甚至后面用不到,所以就不给他变量名了。

iTextSharp.text.pdf.PdfWriter.GetInstance(document, new FileStream("PDF存储路径,以.pdf结尾", FileMode.Create, FileAccess.ReadWrite));

打开这个空文档

 document.Open();

然后就是把一张一张图片插入到文档里(插入之前用NewPage方法插入个新的页,然后用Add方法插如图片)

                    foreach (var imgfile in imglist)
                    {
                        if (string.IsNullOrEmpty(imgfile))
                            break;
                        var image = iTextSharp.text.Image.GetInstance(imgfile);
                        if (image.Height > iTextSharp.text.PageSize.A4.Height - 25)
                        {
                            image.ScaleToFit(iTextSharp.text.PageSize.A4.Width - 25, iTextSharp.text.PageSize.A4.Height - 25);
                        }
                        else if (image.Width > iTextSharp.text.PageSize.A4.Width - 25)
                        {
                            image.ScaleToFit(iTextSharp.text.PageSize.A4.Width - 25, iTextSharp.text.PageSize.A4.Height - 25);
                        }
                        image.Alignment = iTextSharp.text.Image.ALIGN_MIDDLE;
                        document.NewPage();//创建一个新的页
                        document.Add(image);//插入图片
                    }

 

最后都做完了记得关闭document,这几步我用的try cache finally来做的,这样可以保证出错也能关闭

document.Close();

提醒:

如果图片多,生成PDF会耗费时间,造成UI假死,所以要用多线程来做,创建个线程实现后台运行。

            ThreadStart threadStart = new ThreadStart(ImagetoPDF);//ImagetoPDF为要执行的方法,无参数,返回类型VOID,这是个委托
            Thread thread = new Thread(threadStart);
            thread.IsBackground = true;
            thread.Start();//启动新线程
            Image2PDF.CheckForIllegalCrossThreadCalls=false;

 

详细代码:

扫描并在pictureBox上显示

private void 开始扫描ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ImageFile imageFile = null;
            CommonDialogClass cdc = new WIA.CommonDialogClass();

            try
            {
                imageFile = cdc.ShowAcquireImage(WIA.WiaDeviceType.ScannerDeviceType,
                                                 WIA.WiaImageIntent.TextIntent,
                                                 WIA.WiaImageBias.MaximizeQuality,
                                                 "{00000000-0000-0000-0000-000000000000}",
                                                 true,
                                                 true,
                                                 false);
            }
            catch (System.Runtime.InteropServices.COMException)
            {
                imageFile = null;
            }
            if (imageFile != null)
            {
                nowfile=path+"\\page_"+(++page)+".jpg";
                if (!Directory.Exists(path))
                {
                    Directory.CreateDirectory(path);
                }
                imageFile.SaveFile(nowfile);
                using (FileStream stream = new FileStream(nowfile, FileMode.Open,
                    FileAccess.Read, FileShare.Read))
                {
                    var img=Image.FromStream(stream);;
                    pictureBox1.SizeMode = PictureBoxSizeMode.Zoom;
                    pictureBox1.Width = img.Width;
                    pictureBox1.Height = img.Height;
                    pictureBox1.Image = img;
                } 
            }
        }

导出PDF按钮被点击(我另外弹出一个窗体叫做Image2PDF,做了个等待的效果)

private void 转存pdfToolStripMenuItem_Click(object sender, EventArgs e)
        {
            try
            {
                string localFilePath;
                SaveFileDialog sfd = new SaveFileDialog();
                //设置文件类型 
                sfd.Filter = "PDF文档(*.pdf)|*.pdf";

                //设置默认文件类型显示顺序 
                sfd.FilterIndex = 1;

                //保存对话框是否记忆上次打开的目录 
                sfd.RestoreDirectory = true;

                //点了保存按钮进入 
                if (sfd.ShowDialog() == DialogResult.OK)
                {
                    localFilePath = sfd.FileName.ToString(); //获得文件路径 
                    string fileNameExt = localFilePath.Substring(localFilePath.LastIndexOf("\\") + 1); //获取文件名,不带路径

                    var imgList = GetImageFileList();
                    if (imgList == null || imgList.Count == 0)
                    {
                        MessageBox.Show("本次未扫描任何文件");
                        return;
                    }

                    if (File.Exists(localFilePath))
                    {
                        DialogResult dr = MessageBox.Show("文件已存在,是否覆盖?", "警告", MessageBoxButtons.OKCancel);
                        if (dr == DialogResult.Cancel)
                            return;
                        File.Delete(localFilePath);
                    }
                    var form = new Image2PDF(imgList, localFilePath);
                    form.Show();
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show("导出失败");
            }
        }
public Image2PDF(List<string> imgList,string savepath)
        {
            ImgList = imgList;
            SavePath = savepath;
            InitializeComponent();
            ThreadStart threadStart = new ThreadStart(ImagetoPDF);
            Thread thread = new Thread(threadStart);
            thread.IsBackground = true;
            thread.Start();//启动新线程
            Image2PDF.CheckForIllegalCrossThreadCalls=false;
        }
 private void ImagetoPDF()
        {
            try
            {
                var imglist = ImgList;
                if (imglist == null || imglist.Count == 0)
                {
                    MessageBox.Show("本次未扫描任何文件", "系统提示", MessageBoxButtons.OK, MessageBoxIcon.None, MessageBoxDefaultButton.Button1, MessageBoxOptions.ServiceNotification);
                    return;
                }
                string pdfpath = SavePath;
                while (File.Exists(pdfpath))
                {
                    pdfpath = SavePath;
                }
                iTextSharp.text.Document document = new iTextSharp.text.Document(iTextSharp.text.PageSize.A4, 25, 25, 25, 25);
                try
                {
                    iTextSharp.text.pdf.PdfWriter.GetInstance(document, new FileStream(pdfpath, FileMode.Create, FileAccess.ReadWrite));
                    document.Open();
                    iTextSharp.text.Image image;
                    foreach (var imgfile in imglist)
                    {
                        if (string.IsNullOrEmpty(imgfile))
                            break;
                        image = iTextSharp.text.Image.GetInstance(imgfile);
                        if (image.Height > iTextSharp.text.PageSize.A4.Height - 25)
                        {
                            image.ScaleToFit(iTextSharp.text.PageSize.A4.Width - 25, iTextSharp.text.PageSize.A4.Height - 25);
                        }
                        else if (image.Width > iTextSharp.text.PageSize.A4.Width - 25)
                        {
                            image.ScaleToFit(iTextSharp.text.PageSize.A4.Width - 25, iTextSharp.text.PageSize.A4.Height - 25);
                        }
                        image.Alignment = iTextSharp.text.Image.ALIGN_MIDDLE;
                        document.NewPage();
                        document.Add(image);
                    }

                }
                catch (Exception ex)
                {

                    throw;
                }
                finally
                {
                    document.Close();

                }
                MessageBox.Show("转换完成", "系统提示", MessageBoxButtons.OK, MessageBoxIcon.None, MessageBoxDefaultButton.Button1, MessageBoxOptions.ServiceNotification);

                
            }
            catch (Exception)
            {
                MessageBox.Show("转换失败", "系统提示", MessageBoxButtons.OK, MessageBoxIcon.None, MessageBoxDefaultButton.Button1, MessageBoxOptions.ServiceNotification);
            }
            finally
            {
                CloseForm();
            }
        }

 

 

public void CloseForm()
        {
            this.Close();
            this.Dispose();
        }

 

文章中部分代码来源于网络,我自己进行加工和组合,供大家参考,如侵权请告知,我将会及时删除。

 

 

 

  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值