PDF 合并和保护工具






4.97/5 (12投票s)
PDF MERGER and PROTECTOR 是最佳的 PDF 合并软件,它以快速而强大的方式合并(Merge)PDF 文件,并提供密码保护,同时您还可以使用任何类型的图片或文本印章。使用此实用程序,您无需安装 Adobe Acrobat。听起来很棒???

密码保护的 PDF | 内容受到文本保护 | 内容受到图片保护 |
![]() | ![]() | ![]() |
简介
PDF Merger and Protector 是一款免费工具,用于合并和保护您的 PDF 文件,包括密码和印章功能。该工具具有以下多项功能:
- 将任意数量的 PDF 文件合并成一个 PDF 文件。
- 为所有页面重新生成页码。
- 无需安装“Adobe Acrobat and Reader”。
- 使用简单,外观和感觉专业。
- 您可以为内容设置密码,以防止未经授权的打开、复制或打印。
- 您可以使用文本或任何图片来保护您的内容,使其免受版权、商标、许可或水印的侵害。
背景
此工具可用于任何领域或场景,例如:
- 如果您是读者,可以按作者管理所有教程。
- 如果您是员工,可以将每月的工资单按财政年度保存。
- 如果您是付费者,可以按类别记录手机账单、电费账单。
- 用于归档或统一目的。
- 通过电子邮件发送文件,而不是发送一堆文件。
- 打印。
- 按时间顺序查看。
使用代码
此应用程序是借助 iTextSharp 库开发的。我在 软件开发公司 网站上撰写了完整的 使用指南 和 技术使用指南。
在此,我将通过代码和流程为您提供 PDF Merger and Protector 的一般性介绍。在开始阅读本文之前,您应该了解以下内容。
先决条件:
变量声明
//this is the notify file merging process at specified interval private NotifyProgress m_clsNotifyDelegate; //Declaration of thread private Thread m_clsThread; //Provides a way to synchronously or asynchronously execute a delegate private ISynchronizeInvoke m_clsSynchronizingObject; //this is the definition of the progress delegate - it defines the "signature" of the routine... //NotifyProgress has four arguments TotalFiles: total number of files to merge ProcessFileIndex: currently merging file index TotalPages: total number of pages of all files PageIndex: currently merging file page index. public delegate void NotifyProgress(int TotalFiles, int ProcessFileIndex, int TotalPages, int PageIndex);
属性
//Gets or Sets the Destination File Path. Where save generated file.
public string DestinationFile { get;set; }
//Processing or current File Index,File Name and Total Pages and Process Page Index.
public int ProcessFileIndex { get;set; }
public string ProcessFileName { get;set; }
public int ProcessFilePages { get;set; }
public int ProcessFilePageIndex { get;set; }
//Total Files and Total Pages to be merged in a single file (pdf).
public int TotalFiles { get;set; }
public int TotalPages { get;set; }
public int PageIndex { get;set; }
构造函数
- 此类的对象需要传递两个参数:“同步对象”,它告诉类“通知委托”在哪个上下文中运行。
public PDFManager(ISynchronizeInvoke SynchronizingObject, NotifyProgress NotifyDelegate)
{
m_clsSynchronizingObject = SynchronizingObject;
m_clsNotifyDelegate = NotifyDelegate;
}
公共方法
- AddFile 此方法会将文件列表添加到文件列表中。文件列表包含所有将被合并成单个文件的文件。
public void AddFile(string pathnname)
{
fileList.Add(pathnname);
}
- Execute Execute 方法会将所有文件合并成一个(pdf)文件。
public void Execute()
{
//Method will execute in background thread, it will continuous call “MeregDocs” method to update or notify to the users screen.
m_clsThread = new System.Threading.Thread(MergeDocs);
m_clsThread.Name = "PDF Mereger Background Thread";
m_clsThread.IsBackground = true;
m_clsThread.Start();
}
私有方法
- MergeDocs 此方法是整个合并过程的核心。它会将所有文件合并成一个,并将生成的文件保存在目标位置。此方法非常直观,因此无需在此赘述。
private void MergeDocs() { string value = ""; setting = new SettingManager(Path.Combine(Application.StartupPath, "settings.ini")); //------------------------------------------------------------------------------------ //Step 1: Create a Docuement-Object //------------------------------------------------------------------------------------ Document document = new Document(); try { //------------------------------------------------------------------------------------ //Step 2: we create a writer that listens to the document //------------------------------------------------------------------------------------ PdfWriter writer = PdfWriter.GetInstance(document, new FileStream(destinationfile, FileMode.Create)); //------------------------------------------------------------------------------------ //Step 3: Set Password Protection if you are set for it //------------------------------------------------------------------------------------ SetPasswordProtection(writer); //------------------------------------------------------------------------------------ //Step 4: Open the document //------------------------------------------------------------------------------------ document.Open(); PdfContentByte cb = writer.DirectContent; PdfImportedPage page; PdfReader reader; int rotation = 0; ProcessFileIndex = 0; TotalFiles = fileList.Count; TotalPages = 0; PageIndex = 0; foreach (string filename in fileList) { reader = new PdfReader(filename); //Gets the number of pages to process TotalPages += reader.NumberOfPages; } //Loops for each file that has been listed foreach (string filename in fileList) { //Create a reader for the document reader = new PdfReader(filename); ProcessFileIndex++; ProcessFileName = filename; //Gets the number of pages to process ProcessFilePages = reader.NumberOfPages; ProcessFilePageIndex = 0; while (ProcessFilePageIndex < ProcessFilePages) { ProcessFilePageIndex++; PageIndex++; NotifyUI(TotalFiles, ProcessFileIndex, TotalPages, PageIndex); Thread.Sleep(1); document.SetPageSize(reader.GetPageSizeWithRotation(1)); document.NewPage(); //Insert to Destination on the first page if (ProcessFilePageIndex == 1) { Chunk fileRef = new Chunk(" "); fileRef.SetLocalDestination(filename); document.Add(fileRef); } page = writer.GetImportedPage(reader, ProcessFilePageIndex); rotation = reader.GetPageRotation(ProcessFilePageIndex); if (rotation == 90 || rotation == 270) cb.AddTemplate(page, 0, -1f, 1f, 0, 0, reader.GetPageSizeWithRotation(ProcessFilePageIndex).Height); else cb.AddTemplate(page, 1f, 0, 0, 1f, 0, 0); //------------------------------------------------------------------------------------ //Step 4: Set Page Number and Formatting if you are set for it //------------------------------------------------------------------------------------ value = setting.Read("Page Number and Formatting", "AollowPageFormatting"); if (!string.IsNullOrEmpty(value) && Convert.ToBoolean(value) == true) { // we tell the ContentByte we're ready to draw text cb.BeginText(); // we draw some text on a perticular position BaseFont bf = BaseFont.CreateFont(BaseFont.TIMES_ROMAN, BaseFont.CP1252, false); cb.SetFontAndSize(bf, 12); value = setting.Read("Page Number and Formatting", "PageText"); string PageNumberText = ""; if (!string.IsNullOrEmpty(value)) PageNumberText = value; string isPageNumber = setting.Read("Page Number and Formatting", "PageNumber"); string isTotalPageNumber = setting.Read("Page Number and Formatting", "TotalPage"); if (!string.IsNullOrEmpty(isPageNumber) && Convert.ToBoolean(isPageNumber) == true && !string.IsNullOrEmpty(isTotalPageNumber) && Convert.ToBoolean(isTotalPageNumber) == true) { PageNumberText = string.Format("{0} {1} of {2}", PageNumberText, PageIndex, TotalPages); } else if (!string.IsNullOrEmpty(isPageNumber) && Convert.ToBoolean(isPageNumber) == true) { PageNumberText = string.Format("{0} {1}", PageNumberText, PageIndex); } else if (!string.IsNullOrEmpty(isTotalPageNumber) && Convert.ToBoolean(isTotalPageNumber) == true) { PageNumberText = string.Format("{0} {1}", PageNumberText, TotalPages); } Coordinates Coordinates = GetPageAlignment(PageNumberText, document); cb.SetTextMatrix(Coordinates.X, Coordinates.Y); cb.ShowText(PageNumberText); // we tell the contentByte, we've finished drawing text cb.EndText(); } } } } catch (Exception e) { MessageBox.Show(e.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); } finally { //------------------------------------------------------------------------------------ //Step 5: Close the merged pdf document //------------------------------------------------------------------------------------ document.Close(); //------------------------------------------------------------------------------------ //Step 6: Applying watermark Image of Text on PDF //------------------------------------------------------------------------------------ bool isWatermarkEnabled = Convert.ToBoolean(setting.Read("Watermark Image or Write Text", "IsWatermarkEnabled")); if (isWatermarkEnabled) { bool isImagePath = Convert.ToBoolean(setting.Read("Watermark Image or Write Text", "IsImagePath")); string filePath = setting.Read("Merege PDF Location", "PDFLocation"); if (string.IsNullOrEmpty(filePath) || !Directory.Exists(filePath)) { string newFilePath = Path.Combine(Path.GetDirectoryName(Application.ExecutablePath), "MergedFiles"); setting.Write("Merege PDF Location", "PDFLocation", newFilePath); MessageBox.Show(string.Format("Directory does not exists at {0}\n Default path is {1}", filePath, newFilePath), "Directory Not Found", MessageBoxButtons.OK); filePath = newFilePath; } //Step 6.1: Applying watermark Image if image option was selected filePath = Path.Combine(filePath, DateTime.Now.Ticks + ".pdf"); if (isImagePath) { string imagePath = setting.Read("Watermark Image or Write Text", "ImagePath"); if (imagePath != null && imagePath != "") { if (File.Exists(imagePath)) { AddWatermarkImage(DestinationFile, filePath, imagePath); File.Delete(DestinationFile); File.Copy(filePath, DestinationFile); File.Delete(filePath); } else { MessageBox.Show(string.Format("File could not be found at {0}", imagePath), "File Not Found", MessageBoxButtons.OK); } } } else { //Step 6.2: Applying watermark text if text option was selected string watermarkText = setting.Read("Watermark Image or Write Text", "WatermarkText"); string watermarkFont = setting.Read("Watermark Image or Write Text", "WatermarkFont"); string watermarkColor = setting.Read("Watermark Image or Write Text", "WatermarkColor"); iTextSharp.text.pdf.BaseFont font = ConvertStringToFont(watermarkFont); BaseColor color = ConvertStringToColor(watermarkColor); AddWatermarkText(sourceFile: DestinationFile, outputFile: filePath, watermarkText: watermarkText, watermarkFont: font, watermarkFontColor: color); File.Delete(DestinationFile); File.Copy(filePath, DestinationFile); File.Delete(filePath); } } //Step 7: Destroy PDF Merger object from the memory and release all the objects. m_clsNotifyDelegate = null; m_clsThread = null; m_clsSynchronizingObject = null; fileList.Clear(); } }
- SetPasswordProtection 此方法将使用用户名和密码来保护您的文档,没有用户名和密码,没有人可以打开它。
private PdfWriter SetPasswordProtection(PdfWriter writer)
{
try
{
string value = setting.Read("File Protection", "AllowFileProtection");
if (!string.IsNullOrEmpty(value) && Convert.ToBoolean(value) == true)
{
string password = setting.Read("File Protection", "Password");
string ownerPassword = "imdadhusen";
if (!string.IsNullOrEmpty(password))
{
int Permission = 0;
bool Strength = false;
value = setting.Read("File Protection", "AllowCopy");
if (!string.IsNullOrEmpty(value)) Permission = 16;
value = setting.Read("File Protection", "AllowPrinting");
if (!string.IsNullOrEmpty(value)) Permission += 2052;
value = setting.Read("File Protection", "EncryptionStrength");
if (!string.IsNullOrEmpty(value) && value == "strength128bits") Strength = true;
writer.SetEncryption(Strength, password, ownerPassword, Permission);
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
return writer;
}
- ConvertStringToFont 此方法将根据您的选择设置水印文本的字体。
private BaseFont ConvertStringToFont(string fontName) { iTextSharp.text.pdf.BaseFont font = null; try { if (string.IsNullOrEmpty(fontName) == false) { switch (fontName.ToUpper()) { case "COURIER": case "HELVETICA": font = BaseFont.CreateFont(CultureInfo.CurrentCulture.TextInfo.ToTitleCase(fontName), BaseFont.CP1252, BaseFont.NOT_EMBEDDED); break; case "TIMES": font = BaseFont.CreateFont(BaseFont.TIMES_BOLD, BaseFont.CP1252, BaseFont.NOT_EMBEDDED); break; } } } catch (Exception ex) { MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); } return font; }
- ConvertStringToColor 此方法将设置您水印文本的字体颜色。
private BaseColor ConvertStringToColor(string colorName) BaseColor color = null; if (string.IsNullOrEmpty(colorName.ToLower()) == false) { Color c = Color.FromName(colorName.ToLower()); color = new BaseColor(c.R, c.G, c.B); } return color; }
- NotifyUI 此方法决定如何与调用线程进行交互,无论是通过委托还是事件。它将在用户屏幕上更新合并过程的状态。
private void NotifyUI(int TotalFiles, int ProcessFileIndex, int TotalPages, int PageIndex)
{
try
{
object[] args = { TotalFiles, ProcessFileIndex, TotalPages, PageIndex };
//call the delegate, specifying the context in which to run...
m_clsSynchronizingObject.Invoke(m_clsNotifyDelegate, args);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
private Coordinates GetPageAlignment(string PageNumberText, Document document) { Coordinates Coordinates = new PDFLibrary.Coordinates(); try { frmSettings frmsetting = new frmSettings(); PageNumberSize PageNumberSize = frmsetting.GetPageNumberSize(PageNumberText); float TMargin = document.TopMargin; float RMargin = document.RightMargin; float BMargin = document.BottomMargin; float LMargin = document.LeftMargin; setting = new SettingManager(Path.Combine(Application.StartupPath, "settings.ini")); iTextSharp.text.Rectangle pageSize = document.PageSize; string value = setting.Read("Page Number and Formatting", "VerticalAlignment"); switch (value) { case "top": Coordinates.Y = pageSize.Height - (PageNumberSize.Height + TMargin); break; case "middle": Coordinates.Y = (pageSize.Height - (PageNumberSize.Height + TMargin)) / 2; break; case "bottom": Coordinates.Y = BMargin - PageNumberSize.Height; break; } value = setting.Read("Page Number and Formatting", "HorizontalAlignment"); switch (value) { case "left": Coordinates.X = LMargin; break; case "center": Coordinates.X = (pageSize.Width - (PageNumberSize.Width + RMargin)) / 2; break; case "right": Coordinates.X = pageSize.Width - (PageNumberSize.Width + RMargin); break; } } catch (Exception ex) { MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); } return Coordinates; }
private void AddWatermarkImage(string sourceFile, string outputFile, string watermarkImage) { try { using (Stream inputPdfStream = new FileStream(sourceFile, FileMode.Open, FileAccess.Read, FileShare.Read)) using (Stream inputImageStream = new FileStream(watermarkImage, FileMode.Open, FileAccess.Read, FileShare.Read)) using (Stream outputPdfStream = new FileStream(outputFile, FileMode.Create, FileAccess.Write, FileShare.None)) { PdfReader reader; string userPassword = "imdadhusen"; //Imdadhusen is a master Password but you can unlock with User Password also. string ownerPassword = "imdadhusen"; try { reader = new PdfReader(sourceFile); } catch (BadPasswordException) { System.Text.Encoding enc = System.Text.Encoding.ASCII; Byte[] myByteArray = enc.GetBytes(userPassword); reader = new PdfReader(sourceFile, myByteArray); } var stamper = new PdfStamper(reader, outputPdfStream); string value = setting.Read("File Protection", "AllowFileProtection"); if (!string.IsNullOrEmpty(value) && Convert.ToBoolean(value) == true) { userPassword = setting.Read("File Protection", "Password"); if (!string.IsNullOrEmpty(userPassword)) { int Permission = 0; bool Strength = false; value = setting.Read("File Protection", "AllowCopy"); if (!string.IsNullOrEmpty(value)) Permission = 16; value = setting.Read("File Protection", "AllowPrinting"); if (!string.IsNullOrEmpty(value)) Permission += 2052; value = setting.Read("File Protection", "EncryptionStrength"); if (!string.IsNullOrEmpty(value) && value == "strength128bits") Strength = true; stamper.SetEncryption(Strength, userPassword, ownerPassword, Permission); } } iTextSharp.text.Rectangle rect = null; float X = 0; float Y = 0; int pageCount = 0; PdfContentByte underContent = null; rect = reader.GetPageSizeWithRotation(1); pageCount = reader.NumberOfPages; reader.Close(); iTextSharp.text.Image img = iTextSharp.text.Image.GetInstance(watermarkImage); if (img.Width > rect.Width || img.Height > rect.Height) { img.ScaleToFit(rect.Width, rect.Height); X = (rect.Width - img.ScaledWidth) / 2; Y = (rect.Height - img.ScaledHeight) / 2; } else { X = (rect.Width - img.Width) / 2; Y = (rect.Height - img.Height) / 2; } img.SetAbsolutePosition(X, Y); for (int i = 1; i <= pageCount; i++) { underContent = stamper.GetUnderContent(i); underContent.AddImage(img); } stamper.Close(); inputPdfStream.Close(); } } catch (Exception ex) { MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); } }
private void AddWatermarkText(string sourceFile, string outputFile, string watermarkText, iTextSharp.text.pdf.BaseFont watermarkFont = null, float watermarkFontSize = 48, BaseColor watermarkFontColor = null, float watermarkFontOpacity = 0.3f, float watermarkRotation = 45f) { using (Stream inputPdfStream = new FileStream(sourceFile, FileMode.Open, FileAccess.Read, FileShare.Read)) using (Stream outputPdfStream = new FileStream(outputFile, FileMode.Create, FileAccess.Write, FileShare.None)) { PdfReader reader; string userPassword = "imdadhusen"; //Imdadhusen is a master Password but you can unlock with User Password also. string ownerPassword = "imdadhusen"; try { reader = new PdfReader(sourceFile); } catch (BadPasswordException) { System.Text.Encoding enc = System.Text.Encoding.ASCII; Byte[] myByteArray = enc.GetBytes(userPassword); reader = new PdfReader(sourceFile, myByteArray); } var stamper = new PdfStamper(reader, outputPdfStream); string value = setting.Read("File Protection", "AllowFileProtection"); if (!string.IsNullOrEmpty(value) && Convert.ToBoolean(value) == true) { userPassword = setting.Read("File Protection", "Password"); if (!string.IsNullOrEmpty(userPassword)) { int Permission = 0; bool Strength = false; value = setting.Read("File Protection", "AllowCopy"); if (!string.IsNullOrEmpty(value)) Permission = 16; value = setting.Read("File Protection", "AllowPrinting"); if (!string.IsNullOrEmpty(value)) Permission += 2052; value = setting.Read("File Protection", "EncryptionStrength"); if (!string.IsNullOrEmpty(value) && value == "strength128bits") Strength = true; stamper.SetEncryption(Strength, userPassword, ownerPassword, Permission); } } iTextSharp.text.Rectangle rect = null; PdfGState gstate = null; int pageCount = 0; PdfContentByte underContent = null; rect = reader.GetPageSizeWithRotation(1); if (watermarkFont == null) watermarkFont = BaseFont.CreateFont(BaseFont.HELVETICA, BaseFont.CP1252, BaseFont.NOT_EMBEDDED); if (watermarkFontColor == null) watermarkFontColor = BaseColor.BLUE; gstate = new PdfGState(); gstate.FillOpacity = watermarkFontOpacity; gstate.StrokeOpacity = watermarkFontOpacity; pageCount = reader.NumberOfPages; for (int i = 1; i <= pageCount; i++) { underContent = stamper.GetUnderContent(i); var _with1 = underContent; _with1.SaveState(); _with1.SetGState(gstate); _with1.SetColorFill(watermarkFontColor); _with1.BeginText(); _with1.SetFontAndSize(watermarkFont, watermarkFontSize); _with1.SetTextMatrix(30, 30); _with1.ShowTextAligned(Element.ALIGN_CENTER, watermarkText, rect.Width / 2, rect.Height / 2, watermarkRotation); _with1.EndText(); _with1.RestoreState(); } stamper.Close(); inputPdfStream.Close(); } }
public class Coordinates
{
public float X { get; set; }
public float Y { get; set; }
}
- 用法
- 密码保护。
- 防止复制和打印。
- 自定义页码和对齐方式。
- 水印内容保护。
- Image
- 文本
- 向您的项目添加命名空间。
using PDFMerger;
PDFLibrary.PDFManager merge;
merge = new PDFLibrary.PDFManager(this, new PDFLibrary.PDFManager.NotifyProgress(DelegateProgress));
private void DelegateProgress(int TotalFiles, int ProcessFileIndex, int TotalPages, int PageIndex) { try { if (merge != null && merge.TotalPages > 0) { this.Invoke((MethodInvoker)delegate { int pagepercent = merge.ProcessFilePageIndex * 100 / merge.ProcessFilePages; TextProgressBar pb = (TextProgressBar)lstFiles.GetEmbeddedControl(3, merge.ProcessFileIndex - 1); pb.Text = string.Format("{0:00} %", pagepercent); pb.Value = pagepercent; int percent = merge.PageIndex * 100 / merge.TotalPages; ProgressStripItem statusProgrss = (ProgressStripItem)tsStatus.Items[1]; statusProgrss.TextProgressBar.Value = percent; statusProgrss.TextProgressBar.Text = string.Format("{0:00}%", percent); DisplayStatusMessage(string.Format("File Name:{0}, File {1:00} of {2:00}, Page {3:00} of {4:00}", Path.GetFileName(merge.ProcessFileName), merge.ProcessFileIndex, merge.TotalFiles, merge.ProcessFilePageIndex, merge.ProcessFilePages)); if (percent >= 100) { DisplayStatusMessage(string.Format("File merged successfully at {0}", merge.DestinationFile)); for (int i = 0; i < lstFiles.Items.Count; i++) { lstFiles.RemoveEmbeddedControl(lstFiles.GetEmbeddedControl(3, i)); } ClearList(); merge = null; } }); } else { ((ProgressStripItem)tsStatus.Items[1]).TextProgressBar.Text = string.Format("{0:00}%", 0); DisplayStatusMessage(string.Format("File {0:00} of {1:00}, Page {2:00} of {3:00}", 0, 0, 0, 0)); } } catch (Exception ex) { MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); } }
merge.DestinationFile = “D:/MergedFiles/”;
merge.Execute();
- 文件保护设置
- 加密强度
- 密码
- 允许复制
- 允许打印
- 页码和格式
- 垂直对齐
- 水平对齐
- 页码格式
- 水印图像或文本
- 水印图像路径
- 水印文本值
- 字体名称
- 字体颜色
- 合并后的 PDF 位置 使用以下代码,您可以获取和设置(.ini)文件中的全局设置。
- 声明
SettingManager setting = new SettingManager(Path.Combine(Application.StartupPath, "settings.ini"));
string value = setting.Read("Page Number and Formatting", "AollowPageFormatting");
setting.Write("File Protection", "Password", “imdadhusen”);
评论和反馈
创建和维护 PDFMerger 库需要(并且仍然需要)大量的工作和努力。PDFMerger 是免费的,我希望您觉得它有用。如果您想支持未来的开发和新产品功能,请通过评论、邮件、消息或评分留下您宝贵的评论、反馈、建议或赞赏。
这些努力用于覆盖和提高产品效率。