年末将至,又到了一年一度的收集发票时间,平时零零碎碎的花钱都是不在意开发票,现在好了,到处找发票来报销,简直头大,

东拼西凑,终于搞定了全部发票,大伙多余的发票,麻烦艾特我一下啊,不限日期,能开发票的都可以,谢谢啦。文章后有彩蛋~

这么多的发票,一张一张打印,要浪费我多少时间,就想着合并这些PDF文件(发票)一起打印,节省时间。

还寻思这网上找一个软件来使使,都很(méi)委(līang)婉(xīn)的想收费,在线转PDF的还给我打水印,恰巧今天公司网速不行。

来吧,自己搞!程序猿没有什么不可能!

Spire.PDF

  NPOI、DocX、Epplus……这些开源且免费的优秀组件,大家应该是耳熟能详的,而Spire是一款企业级的收费组件,Spire.PDF for .NET

是一个专业的PDF组件,用于在.NET应用程序中创建,编写,编辑,处理和阅读PDF文件,功能十分丰富…………

提取关键词:收费、稳定、高效

具体我不再过多的啰嗦了,详细我推荐看这篇《 高效而稳定的企业级.NET Office 组件Spire(.NET组件介绍之二)

合并PDF

  回到今天的问题,合并发票,合并PDF,然后一次性打印。其实吧,主要代码就两行:

  var doc = PdfDocument.MergeFiles(allFiles.ToArray());
doc.Save(DateTime.Now.ToString("yyyyMMddHHmmss") + ".pdf", FileFormat.PDF);

然后,你们输出之后会发现,很(méi)漂(līang)亮(xīn)的水印:

“Evaluation Warning:The document was created with Spire.PDF for .NET”

简直玷污我心爱的发票!!!!

解决

  既然隐藏不了,那合并的第一页加入一个空页不就行了?!生成PDF后,然后从第二页开始打印或是删去第一页不就行了?!就这么干!

             var first = new PdfDocument();
first.AppendPage(); //加入一个空页
for (int idx = ; idx < allFiles.Count; idx++)
{
var next = new PdfDocument(allFiles[idx]);
first.AppendPage(next);
}
first.SaveToFile(DateTime.Now.ToString("yyyyMMddHHmmss")+".pdf", FileFormat.PDF);

工具很简单,就不放到Git上去了,源码:

界面:

namespace 合并PDF
{
partial class mainForm
{
/// <summary>
/// 必需的设计器变量。
/// </summary>
private System.ComponentModel.IContainer components = null; /// <summary>
/// 清理所有正在使用的资源。
/// </summary>
/// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
} #region Windows 窗体设计器生成的代码 /// <summary>
/// 设计器支持所需的方法 - 不要修改
/// 使用代码编辑器修改此方法的内容。
/// </summary>
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
this.btnAdd = new System.Windows.Forms.Button();
this.btnMerge = new System.Windows.Forms.Button();
this.bgw = new System.ComponentModel.BackgroundWorker();
this.listView1 = new System.Windows.Forms.ListView();
this.columnHeader1 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
this.contextMenuStrip1 = new System.Windows.Forms.ContextMenuStrip(this.components);
this.btnRemove = new System.Windows.Forms.ToolStripMenuItem();
this.statusStrip1 = new System.Windows.Forms.StatusStrip();
this.progressBar = new System.Windows.Forms.ToolStripProgressBar();
this.tipStatu = new System.Windows.Forms.ToolStripStatusLabel();
this.btnSplit = new System.Windows.Forms.Button();
this.contextMenuStrip1.SuspendLayout();
this.statusStrip1.SuspendLayout();
this.SuspendLayout();
//
// btnAdd
//
this.btnAdd.Location = new System.Drawing.Point(, );
this.btnAdd.Name = "btnAdd";
this.btnAdd.Size = new System.Drawing.Size(, );
this.btnAdd.TabIndex = ;
this.btnAdd.Text = "添加文件";
this.btnAdd.UseVisualStyleBackColor = true;
this.btnAdd.Click += new System.EventHandler(this.btnSearch_Click);
//
// btnMerge
//
this.btnMerge.Font = new System.Drawing.Font("宋体", 9F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)()));
this.btnMerge.Location = new System.Drawing.Point(, );
this.btnMerge.Name = "btnMerge";
this.btnMerge.Size = new System.Drawing.Size(, );
this.btnMerge.TabIndex = ;
this.btnMerge.Text = "开始合并";
this.btnMerge.UseVisualStyleBackColor = true;
this.btnMerge.Click += new System.EventHandler(this.btnMerge_Click);
//
// bgw
//
this.bgw.WorkerReportsProgress = true;
this.bgw.DoWork += new System.ComponentModel.DoWorkEventHandler(this.bgw_DoWork);
this.bgw.ProgressChanged += new System.ComponentModel.ProgressChangedEventHandler(this.bgw_ProgressChanged);
this.bgw.RunWorkerCompleted += new System.ComponentModel.RunWorkerCompletedEventHandler(this.bgw_RunWorkerCompleted);
//
// listView1
//
this.listView1.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
this.columnHeader1});
this.listView1.ContextMenuStrip = this.contextMenuStrip1;
this.listView1.FullRowSelect = true;
this.listView1.GridLines = true;
this.listView1.Location = new System.Drawing.Point(, );
this.listView1.MultiSelect = false;
this.listView1.Name = "listView1";
this.listView1.Size = new System.Drawing.Size(, );
this.listView1.TabIndex = ;
this.listView1.UseCompatibleStateImageBehavior = false;
this.listView1.View = System.Windows.Forms.View.Details;
//
// columnHeader1
//
this.columnHeader1.Text = "文件";
this.columnHeader1.Width = ;
//
// contextMenuStrip1
//
this.contextMenuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.btnRemove});
this.contextMenuStrip1.Name = "contextMenuStrip1";
this.contextMenuStrip1.Size = new System.Drawing.Size(, );
//
// btnRemove
//
this.btnRemove.Name = "btnRemove";
this.btnRemove.Size = new System.Drawing.Size(, );
this.btnRemove.Text = "移除";
this.btnRemove.Click += new System.EventHandler(this.btnRemove_Click);
//
// statusStrip1
//
this.statusStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.progressBar,
this.tipStatu});
this.statusStrip1.Location = new System.Drawing.Point(, );
this.statusStrip1.Name = "statusStrip1";
this.statusStrip1.Size = new System.Drawing.Size(, );
this.statusStrip1.TabIndex = ;
this.statusStrip1.Text = "statusStrip1";
//
// progressBar
//
this.progressBar.Name = "progressBar";
this.progressBar.Size = new System.Drawing.Size(, );
//
// tipStatu
//
this.tipStatu.Name = "tipStatu";
this.tipStatu.Size = new System.Drawing.Size(, );
this.tipStatu.Text = "0/0";
//
// btnSplit
//
this.btnSplit.Font = new System.Drawing.Font("宋体", 9F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)()));
this.btnSplit.Location = new System.Drawing.Point(, );
this.btnSplit.Name = "btnSplit";
this.btnSplit.Size = new System.Drawing.Size(, );
this.btnSplit.TabIndex = ;
this.btnSplit.Text = "开始拆分";
this.btnSplit.UseVisualStyleBackColor = true;
this.btnSplit.Click += new System.EventHandler(this.btnSplit_Click);
//
// mainForm
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(, );
this.Controls.Add(this.btnSplit);
this.Controls.Add(this.statusStrip1);
this.Controls.Add(this.listView1);
this.Controls.Add(this.btnMerge);
this.Controls.Add(this.btnAdd);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
this.MaximizeBox = false;
this.MaximumSize = new System.Drawing.Size(, );
this.MinimumSize = new System.Drawing.Size(, );
this.Name = "mainForm";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.Text = "PDF Merge";
this.contextMenuStrip1.ResumeLayout(false);
this.statusStrip1.ResumeLayout(false);
this.statusStrip1.PerformLayout();
this.ResumeLayout(false);
this.PerformLayout(); } #endregion
private System.Windows.Forms.Button btnAdd;
private System.Windows.Forms.Button btnMerge;
private System.ComponentModel.BackgroundWorker bgw;
private System.Windows.Forms.ListView listView1;
private System.Windows.Forms.ColumnHeader columnHeader1;
private System.Windows.Forms.StatusStrip statusStrip1;
private System.Windows.Forms.ToolStripProgressBar progressBar;
private System.Windows.Forms.ToolStripStatusLabel tipStatu;
private System.Windows.Forms.ContextMenuStrip contextMenuStrip1;
private System.Windows.Forms.ToolStripMenuItem btnRemove;
private System.Windows.Forms.Button btnSplit;
}
}

后台:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows.Forms;
using Spire.Pdf;
using System.Threading;
using Spire.Pdf.Graphics;
using System.Drawing;
using System.IO; namespace 合并PDF
{
public partial class mainForm : Form
{
public mainForm()
{
InitializeComponent();
} List<string> allFiles = new List<string>();
private void btnSearch_Click(object sender, EventArgs e)
{
OpenFileDialog openFile = new OpenFileDialog();
openFile.Filter = "PDF文件|*.pdf";
openFile.Multiselect = true;
if (openFile.ShowDialog() == DialogResult.OK)
{
foreach (var fi in openFile.FileNames)
{
if (allFiles.Contains(fi))
continue;
this.listView1.Items.Add(new ListViewItem(fi));
allFiles.Add(fi);
}
progressBar.Minimum = ;
progressBar.Maximum = allFiles.Count;
}
} bool bMerge = false;
private void btnMerge_Click(object sender, EventArgs e)
{
if (!bgw.IsBusy)
{
if (allFiles.Count <= )
{
MessageBox.Show("请至少选择 2 个PDF文件");
return;
}
CtrlStatu(false);
bMerge = true;
bgw.RunWorkerAsync();
}
} void Merge()
{
var first = new PdfDocument();
first.AppendPage(); //加入一个空页
for (int idx = ; idx < allFiles.Count; idx++)
{
var next = new PdfDocument(allFiles[idx]);
first.AppendPage(next);
ReportInfo(idx + , allFiles.Count);
Thread.Sleep();
}
first.SaveToFile(DateTime.Now.ToString("yyyyMMddHHmmss") + ".pdf", FileFormat.PDF);
} private void CtrlStatu(bool b)
{
listView1.Enabled = b;
btnMerge.Enabled = b;
btnAdd.Enabled = b;
} private void bgw_DoWork(object sender, DoWorkEventArgs e)
{
if (bMerge)
{
Merge();
}
if (bSplit)
{
Split();
}
} /// <summary>
/// 输出消息
/// </summary>
public void ReportInfo(int idx, int count)
{
bgw.ReportProgress(, idx + "/" + count);
} private void bgw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
var userState = e.UserState.ToString();
tipStatu.Text = userState;
progressBar.Value = Convert.ToInt32(userState.Split('/')[]);
} private void bgw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
tipStatu.Text = "完成...";
CtrlStatu(true);
bMerge = bSplit = false;
} private void btnRemove_Click(object sender, EventArgs e)
{
if (this.listView1.SelectedItems.Count > )
{
int idx = this.listView1.SelectedItems[].Index;
allFiles.Remove(this.listView1.SelectedItems[].Text);
this.listView1.Items[idx].Remove();
}
} bool bSplit = false;
private void btnSplit_Click(object sender, EventArgs e)
{
if (!bgw.IsBusy)
{
if (allFiles.Count < )
{
MessageBox.Show("请至少选择 1 个PDF文件");
return;
}
CtrlStatu(false);
bSplit = true;
bgw.RunWorkerAsync();
}
}
void Split()
{
var dir = System.Windows.Forms.Application.StartupPath + "\\拆分";
if (!Directory.Exists(dir))
{
Directory.CreateDirectory(dir);
}
string path = "";
PdfTextLayout format = new PdfTextLayout();
format.Break = PdfLayoutBreakType.FitPage;
format.Layout = PdfLayoutType.Paginate; string curTime = DateTime.Now.ToString("yyyyMMddHHmmss");
for (int idx = ; idx < allFiles.Count; idx++)
{
PdfDocument pdf = new PdfDocument();
FileInfo file = new FileInfo(allFiles[idx]);
string fileName = file.Name.Replace(file.Extension, "");
pdf.LoadFromFile(allFiles[idx]); path = string.Format("{0}\\{1}_",dir, fileName) + "第{0}页_"+curTime+".pdf";
pdf.Split(path);
pdf.Close();
ReportInfo(idx + , allFiles.Count);
Thread.Sleep();
}
}
}
}

本文已独家授权给脚本之家(ID:jb51net)公众号发布

Spire高效稳定的.NET组件的更多相关文章

  1. 你要是还学不会,请提刀来见 Typora+PicGo+Gitee + node.js 打造个人高效稳定优雅图床

    你要是还学不会,请提刀来见 Typora+PicGo+Gitee + node.js 打造个人高效稳定优雅图床 经过前面两弹的介绍,相信大家对图床都不陌生了吧, 但是小魔童觉得这样做法还是不方便,使用 ...

  2. DIOCP开源项目-高效稳定的服务端解决方案(DIOCP + 无锁队列 + ZeroMQ + QWorkers) 出炉了

    [概述] 自从上次发布了[DIOCP开源项目-利用队列+0MQ+多进程逻辑处理,搭建稳定,高效,分布式的服务端]文章后,得到了很多朋友的支持和肯定.这加大了我的开发动力,经过几个晚上的熬夜,终于在昨天 ...

  3. 使用Windows Server 2012+ 搭建VPN 简单 高效 稳定

    前几天,在机缘巧合之下,买到了一台性能配置一般的腾讯云服务器(香港的),因为性能比较差,没啥太大用途,就想着试试搭建一个VPN,后来,经过多次尝试和查资料,总结出了一套几乎100%成功的教程,现在拿来 ...

  4. K8s 如何提供更高效稳定的编排能力?K8s Watch 实现机制浅析

    关于我们 更多关于云原生的案例和知识,可关注同名[腾讯云原生]公众号~ 福利: ①公众号后台回复[手册],可获得<腾讯云原生路线图手册>&<腾讯云原生最佳实践>~ ②公 ...

  5. C#组件系列——又一款Excel处理神器Spire.XLS,你值得拥有

    前言:最近项目里面有一些对Excel操作的需求,博主想都没想,NPOI呗,简单.开源.免费,大家都喜欢!确实,对于一些简单的Excel导入.导出.合并单元格等,它都没啥太大的问题,但是这次的需求有两点 ...

  6. 高效的TCP消息发送组件

    目前的.net 架构下缺乏高效的TCP消息发送组件,而这种组件是构建高性能分布式应用所必需的.为此我结合多年的底层开发经验开发了一个.net 下的高效TCP消息发送组件.这个组件在异步发送时可以达到每 ...

  7. chunkupload 文件上传断点续传组件(java) - 正式发布

    chunkupload简介 chunkupload是一款基于java语言的断点续传组件,针对文件上传,非文件下载,集成方便,使用简单. chunkupload实现如下功能: ·  实现断点续传 ·  ...

  8. 轻量级C#网络通信组件StriveEngine —— C/S通信开源demo(附源码)

    前段时间,有几个研究ESFramework网络通讯框架的朋友对我说,ESFramework有点庞大,对于他们目前的项目来说有点“杀鸡用牛刀”的意思,因为他们的项目不需要文件传送.不需要P2P.不存在好 ...

  9. SNFAutoupdater通用自动升级组件V2.0

    1.组件介绍 C/S构的特点是能充分发挥客户端的处理能力,很多工作可以由客户端处理后再提交给服务器,对应的优点就是客户端响应速度快模式客户端以其强大的功能,丰富的表现力受到相当大部分用户的青睐,但是客 ...

随机推荐

  1. 会话机器人Chatbot的相关资料

    Chatbot简介 竹间智能简仁贤:打破千篇一律的聊天机器人 | Chatbot的潮流 重点关注其中关于情感会话机器人的介绍 当你对我不满的时候我应该怎么应对,当你无聊,跟我说你很烦的时候,我应该怎么 ...

  2. 用户注册登录系统 V2.0

    # 准备空列表 users = [] # 准备当前在线用户 online_user = {} while True: # 打印系统提示 print("欢迎使用 用户注册登录系统V2.0&qu ...

  3. Cocos2d-x 实战

    跨平台商业项目实战:攻城大作战游戏创意触发点:做什么样的游戏?分析当前主流的游戏:经典游戏(俄罗斯方块).大众化的游戏(卡牌游戏.休闲游戏).重口味游戏. 游戏创意:生活当中 游戏开发流程:1.策划方 ...

  4. SSM博客

    最近在写基于SSM 的博客,用的是spring+springmvc+mybatis搭建的,用的maven+github管理项目,目前完成了登录注册以及用户管理员的增删改查,后续的功能还需要完善,如何建 ...

  5. Flask入门之flask-wtf表单处理

    参考文章 1. 使用 WTForms 进行表单验证  第11集 #Sample.py # coding:utf-8 from flask import Flask,render_template,re ...

  6. __new__()方法的使用和实例化

    Python中__new__()方法的使用和实例化 1 2 new()是在新式类中新出现的方法,它作用在构造方法init()建造实例之前,可以这么理解,在Python 中存在于类里面的构造方法init ...

  7. JVM GC-----垃圾回收算法

    说到Java,一定绕不开GC,尽管不是Java首创的,但Java一定是使用GC的代表.GC就是垃圾回收,更直接点说就是内存回收.是对内存进行整理,从而使内存的使用尽可能大的被复用. 一直想好好写一篇关 ...

  8. JAVAEE——Mybatis第一天:入门、jdbc存在的问题、架构介绍、入门程序、Dao的开发方法、接口的动态代理方式、SqlMapConfig.xml文件说明

    1. 学习计划 第一天: 1.Mybatis的介绍 2.Mybatis的入门 a) 使用jdbc操作数据库存在的问题 b) Mybatis的架构 c) Mybatis的入门程序 3.Dao的开发方法 ...

  9. Unity3D学习(七):Unity多重采样抗锯齿设置无效的解决办法

    前言 学习Shader的过程中发现模型锯齿严重,于是去Edit--Project Settings--Quality选项下将反锯齿设置为了8X Multi Sampling.结果没有任何改变,如图: ...

  10. java中的取整(/)和求余(%)

    1.取整运算符取整从字面意思理解就是被除数到底包含几个除数,也就是能被整除多少次,那么它有哪些需要注意的地方呢?先看下面的两端代码: int a = 10; int b = 3; double c= ...