Password Protected PDF | Content Protected with Text | Content Protected with Image |
| | |
Introduction
PDF Merger and Protector is a free tool for merge and protect your PDF with password and stamping. this tools has several features like:
- Merge any number of PDF files into single PDF file.
- Regenerate page number for every pages.
- No need to install "Adobe Acrobat and Reader".
- It is very simple to use and professional look and feel.
- You can protect your content with password to prevent unauthorized opening, copying or printing.
- You can protect your content with Copyright, Trademark, License or Watermark using text or any image.
Background
This tool you can use any area or field like :
- If you are reader, you can manage every tutorials with different Author Wise.
- If your are employee, You can keep your monthly salary sleep into Financial Year Wise.
- If you are payer, you can keep record of Mobile Bill, Electricity Bill into Category Wise.
- Filing or Unification Purposes.
- Send File via Email instead of list of files.
- Taking Print.
- View in Chronological Order.
Using the code
This application is developed with help of iTextSharp library. I have written complete guide line for How to Use and Technical Usage Guide at Software Development Company site.
Here i am giving you general idea behind PDF Merger and Protector with code and flow. Before starting go-through article, you should have knowledge about following.
Variable Declaration
private NotifyProgress m_clsNotifyDelegate;
private Thread m_clsThread;
private ISynchronizeInvoke m_clsSynchronizingObject;
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);
Properties
public string DestinationFile { get;set; }
public int ProcessFileIndex { get;set; }
public string ProcessFileName { get;set; }
public int ProcessFilePages { get;set; }
public int ProcessFilePageIndex { get;set; }
public int TotalFiles { get;set; }
public int TotalPages { get;set; }
public int PageIndex { get;set; }
Constructor
You can create object of PDFMerger with default value like Synchronize Object and Notify Progress parameters
This class object will requires two parameter “synchronizing object” be passed to it – this tells the class what context “notify delegates” should run in
public PDFManager(ISynchronizeInvoke SynchronizingObject, NotifyProgress NotifyDelegate)
{
m_clsSynchronizingObject = SynchronizingObject;
m_clsNotifyDelegate = NotifyDelegate;
}
Public Methods
- AddFile
This method will add list of files into file list. File list contain all those files to be merged into single.
public void AddFile(string pathnname)
{
fileList.Add(pathnname);
}
- Execute
Execute method will combine all files into single (pdf) file.
public void Execute()
{
m_clsThread = new System.Threading.Thread(MergeDocs);
m_clsThread.Name = "PDF Mereger Background Thread";
m_clsThread.IsBackground = true;
m_clsThread.Start();
}
Private Methods
- MergeDocs
This method is a heart of the entire merging process. It will merge all the files into single and save generated file at destination location. This method is very explanatory so no need write more for that.
private void MergeDocs()
{
string value = "";
setting = new SettingManager(Path.Combine(Application.StartupPath, "settings.ini"));
Document document = new Document();
try
{
PdfWriter writer = PdfWriter.GetInstance(document, new FileStream(destinationfile, FileMode.Create));
SetPasswordProtection(writer);
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);
TotalPages += reader.NumberOfPages;
}
foreach (string filename in fileList)
{
reader = new PdfReader(filename);
ProcessFileIndex++;
ProcessFileName = filename;
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();
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);
value = setting.Read("Page Number and Formatting", "AollowPageFormatting");
if (!string.IsNullOrEmpty(value) && Convert.ToBoolean(value) == true)
{
cb.BeginText();
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);
cb.EndText();
}
}
}
}
catch (Exception e)
{
MessageBox.Show(e.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
finally
{
document.Close();
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;
}
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
{
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);
}
}
m_clsNotifyDelegate = null;
m_clsThread = null;
m_clsSynchronizingObject = null;
fileList.Clear();
}
}
- SetPasswordProtection
This method will protect your document with user name and password, without user name and password nobody can open it.
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
This method will set Watermark Text font as per selected by you.
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
This method will set font color of your Watermark Text
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
This is the method that determines how to interact with the calling thread, whether by delegate or event. It will update status of merging process on the users screen.
private void NotifyUI(int TotalFiles, int ProcessFileIndex, int TotalPages, int PageIndex)
{
try
{
object[] args = { TotalFiles, ProcessFileIndex, TotalPages, PageIndex };
m_clsSynchronizingObject.Invoke(m_clsNotifyDelegate, args);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
GetPageAlignmentThis method will display Custom Page Number at specific position or alignment (top, middle, bottom) or (left, center and right)
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;
}
AddWatermarkImageUsing this method you may add water mark Image on every pages. So it will protect your data from theft.
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";
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);
}
}
AddWatermarkTextUsing this method you may add water mark Text on every pages. So it will protect your data from theft.
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";
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();
}
}
Classes This class has only two properties which can hold information about X and Y co-ordinates for displaying page number.
public class Coordinates
{
public float X { get; set; }
public float Y { get; set; }
}
Usage of PDF Merger PDF Merger is a command line utility, that will combine multiple files (.pdf) into single file (.pdf). Using this utility you can protect your document (.pdf) with several features like.
- Usage
- Password protection.
- Protect from copy and print.
- Custom page number and alignment.
- Watermark content protection.
- Image
- Text
- Add name space to your project
using PDFMerger;
Declare PDF Merger object
PDFLibrary.PDFManager merge;
Assign Isynchronize object and Notify delegate object within constructor.
merge = new PDFLibrary.PDFManager(this, new PDFLibrary.PDFManager.NotifyProgress(DelegateProgress));
Create delegate progress function to notify UI at specific intervalThis method contains four parameters TotalFiles (which contain total number of (pdf) files, ProcessFileIndex (will contain curruntly processing file number), TotalPages (total number of pages of all files (.pdf) and PageIndex (page number of currently processing file).
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);
}
}
Setting up destination folder path, where store generated or merged file (.pdf). If destination path does not exists then it will automatically created.
merge.DestinationFile = "D:/MergedFiles/";
Execute merge proces.
merge.Execute();
SettingsIn the above code you will get SettingManager object in the several methods. This is a class (.ini) which store information about users setting for example.
- File Protection Setting
- Encryption Strength
- Password
- Allow Copy
- Allow Printing
- Page Number and Formatting
- Vertical Alignment
- Horizontal Alignment
- Page Number Format
- Watermark Image or Text
- Watermark Image Path
- Watermark Text Value
- Font Name
- Font Color
- Merged PDF Location
Using following code you can Get and Set of your global settings in (.ini) file.
- Declaration
SettingManager setting = new SettingManager(Path.Combine(Application.StartupPath, "settings.ini"));
Read Setting
string value = setting.Read("Page Number and Formatting", "AollowPageFormatting");
Save Setting
setting.Write("File Protection", "Password", "imdadhusen");
Comments and Feedback
Creating and maintaining PDFMerger library has required – and still does – a considerable amount of work and effort.
PDFMerger is free, and I hope that you find it useful. If you’d like to support future development and new product features, please make a your valuable comments, feedback, suggestions or appreciation via Comments, mail, messages or rating.
These efforts are used to cover and improve product efficiency.