ในบทความนี้เราก็ยังคงอยู่กับเรื่องการทำภาพลายน้ำอย่างต่อเนื่องจาก EP. ที่แล้วที่พูดถึงการทำข้อความลายน้ำบนภาพที่เราทำการอัพโหลด ถ้าใครยังไม่ได้อ่านสามารถตามไปอ่านกันได้ ที่นี่ นะคะแต่สำหรับ EP. นี้เราจะขอเปลี่ยนบรรยากาศไปทำ ลายน้ำบนไฟล์ PDF โดยใช้เครื่องมือ iTextSharp กันบ้าง เผื่อว่าผู้อ่านบางท่านที่อาจจะกำลังใช้งาน iTextSharp ในการจัดทำไฟล์ PDF อยู่พอดี และอยากจะลองใส่ลายน้ำให้กับงานเอกสารของท่านดูบ้าง จะได้สามารถนำวิธีการนี้ไปประยุกต์ใช้กับงานของตนได้ไม่ทางใดก็ทางหนึ่งนะคะ โดยตัวอย่างที่จะนำมาแนะนำกันจะมีทั้งแบบลายน้ำที่เป็นข้อความ และลายน้ำที่เป็นภาพค่ะ นอกจากนี้ก็ยังมีทั้งแบบที่เป็นการทำภาพลายน้ำทับไฟล์เดิมที่มีอยู่ และแบบที่ทำภาพลายน้ำและบันทึกเป็นไฟล์ใหม่ค่ะ ผู้อ่านจะได้ลองในหลายๆวิธี และสามารถเลือกไปปรับใช้ให้เหมาะกับงานของแต่ละท่านได้เพื่อไม่ให้เป็นการเสียเวลา งั้นเรามาเริ่มทำภาพลายน้ำบนงานเอกสาร PDF ของเรากันเลยดีกว่าค่ะ
แบบที่ 1 : การสร้างลายน้ำแบบข้อความ ซึ่งวิธีการนี้ จะมีการทำ Template ต้นฉบับของลายน้ำแบบข้อความไว้ก่อน และเมื่อต้องการทำไฟล์ลายน้ำ จะต้องทำการอ่านไฟล์ลายน้ำจากต้นแบบมาจัดทำลายน้ำบนไฟล์ที่ต้องการได้ ดังนี้ค่ะ
1.1 ระบุ Library เพิ่มเติม
using iTextSharp.text;
using iTextSharp.text.pdf;
using System.IO;
1.2 สร้างเมธอดในการสร้าง Template ลายน้ำต้นฉบับ เพื่อใช้ในการทำลายน้ำให้กับไฟล์ PDF ที่ต้องการ
////กรณียังไม่เคยสร้างหรือมี Template มาก่อน ให้เรียกใช้งาน CreateTemplate("ข้อความที่ต้องการให้แสดงในเทมเพลต",พาธที่จะสร้างไฟล์เทมเพลตดังกล่าว)
public void CreateTemplate(string watermarkText, string targetFileName)
{
var document = new Document();
////ระบุพาธที่ต้องการสร้างไฟล์เทมเพลต
var pdfWriter = PdfWriter.GetInstance(document, new FileStream(targetFileName, FileMode.Create));
///ระบุค่าต่างๆเกี่ยวกับตัวอักษรที่จะแสดงผลในเทมเพลตลายน้ำที่สร้างขึ้น
var font = new Font(Font.FontFamily.HELVETICA, 60, Font.NORMAL, BaseColor.LIGHT_GRAY);
document.Open();
////ระบุค่าข้อความ และค่าต่างๆให้กับลายน้ำที่ต้องการ
ColumnText.ShowTextAligned(pdfWriter.DirectContent, Element.ALIGN_CENTER, new Phrase(watermarkText, font), 300, 400, 45);
document.Close();
}
ตัวอย่าง ไฟล์ PDF ของ Template ลายน้ำที่ได้จากการเรียกใช้งานเมธอด CreateTemplate ข้างต้น
1.3 สร้างเมธอดในการจัดทำลายน้ำข้อความให้กับไฟล์ PDF จาก template ลายน้ำต้นฉบับ
public void AddTextWatermark(string sourceFilePath, string watermarkTemplatePath, string targetFilePath)
{
///ระบุพาธไฟล์ต้นทางที่ต้องการทำข้อความลายน้ำ
var pdfReaderSource = new PdfReader(sourceFilePath);
///ระบุพาธไฟล์ปลายทางที่ต้องการบันทึกไฟล์แบบมีลายน้ำ
var pdfStamper = new PdfStamper(pdfReaderSource, new FileStream(targetFilePath, FileMode.Create));
///ระบุพาธของไฟล์ต้นแบบลายน้ำที่จัดทำไว้
var pdfReaderTemplate = new PdfReader(watermarkTemplatePath);
var page = pdfStamper.GetImportedPage(pdfReaderTemplate, 1);
///ทำการวนลูปเพื่อทำลายน้ำให้กับไฟล์ PDF ทีละหน้า
for (var i = 0; i < pdfReaderSource.NumberOfPages; i++)
{
///ระบุตำแหน่งในการแสดงผลลายน้ำกับเนื้อหาในไฟล์ PDF กรณีนี้คือวางไว้ใต้เนื้อหา แต่หากต้องการให้อยู่บนเนื้อหาให้เปลี่ยนเป็น GetOverContent แทน
var content = pdfStamper.GetUnderContent(i + 1);
content.AddTemplate(page, 0, 0);
}
pdfStamper.Close();
pdfReaderTemplate.Close();
}
1.4 เรียกใช้งานเมธอดเพื่อทำลายน้ำให้กับไฟล์ PDF ที่ต้องการ(กรณีนี้สมมุติให้เป็นการกดปุ่มเพื่อเรียกใช้งานเมธอดดังกล่าว)
protected void btnGenWatermark_Click(object sender, EventArgs e)
{
////กำหนด Path ของไฟล์ PDF ต้นทางที่ต้องการทำลายน้ำ กรณีที่ gen จาก iTextSharp สามารถนำมาประยุกต์ใช้โดยเอาพาธดังกล่าวมาใช้เป็น strSourcePath ได้เลย
string strSourcePath = HttpContext.Current.Server.MapPath("~/PDF/File/PDFDocument.pdf");
////สร้างตัวแปรชื่อไฟล์ PDF ที่จะบันทึกใหม่ในชื่อตัวแปร genName
string genName = Guid.NewGuid().ToString() + ".pdf";
////กรณียังไม่เคยสร้างหรือมี Template มาก่อนให้เรียกใช้งาน CreateTemplate("ข้อความที่ต้องการให้แสดงในเทมเพลต",templatePath) ทั้งชื่อไฟล์เทมเพลตใหม่ที่จะบันทึก
string templatePath = HttpContext.Current.Server.MapPath("~/PDF/TemplateWatermarkPDF/" + genName);
////ระบุพาธปลายทางที่ต้องการบันทึกไฟล์แบบมีลายน้ำพร้อมทั้งชื่อไฟล์ใหม่ที่จะบันทึก
string targetPath = HttpContext.Current.Server.MapPath("~/PDF/WatermarkPDF/" + genName);
////ตรวจสอบว่ามีไฟล์ดังกล่าวอยู่จริงตามที่อยู่ที่ระบุไว้หรือไม่
if( File.Exists(strSourcePath))
{
////กรณียังไม่เคยสร้างหรือมี Template มาก่อน ให้เรียกใช้งาน CreateTemplate("ข้อความที่ต้องการให้แสดงในเทมเพลต",พาธที่จะสร้างไฟล์เทมเพลตดังกล่าว)
CreateTemplate("Copyrights (c) 2023", templatePath);
////เรียกใช้งานเมธอดในการสร้างข้อความลายน้ำตามเทมเพลตที่มี(ตามพาธที่ระบุ) โดยส่งค่าที่อยู่ของไฟล์ต้นทาง พาธเทมเพลตที่ต้องการทำลายน้ำ และพาธปลายทางที่ต้องการบันทึกไฟล์แบบมีลายน้ำ
AddTextWatermark(strSourcePath, templatePath, targetPath);
}
}
ตัวอย่างผลลัพธ์
หมายเหตุ :
- บางครั้งอาจพบว่าการใช้ GetUnderContent อาจทำให้ข้อความลายน้ำโดนเนื้อหาบดบังได้ในบางกรณี จนอาจจะต้องใช้ GetOverContent แทนดังเช่นตัวอย่างต่อไปนี้
แต่สำหรับเนื้อหาในไฟล์ PDF โดยทั่วไปแล้ว สามารถใช้งาน GetUnderContent ได้ตามปกติ เพื่อไม่ให้ข้อความลายน้ำบดบังเนื้อหาในเอกสาร
แบบที่ 2 การสร้างลายน้ำแบบรูปภาพให้กับเอกสาร PDF โดยจะขอยกตัวอย่างให้ดู 2 แบบนะคะ คือแบบที่สร้างลายน้ำบนไฟล์ PDF ใหม่ และแบบที่สร้างลายน้ำบนไฟล์ต้นทางเดิมค่ะ
2.1 แบบสร้างลายน้ำบนไฟล์ใหม่ โดยการสร้างเมธอด AddImageWatermark
public void AddImageWatermark(string sourceFilePath, string watermarkImagePath, string targetFilePath)
{
///ระบุพาธไฟล์ต้นทางที่ต้องการทำภาพลายน้ำ
var pdfReader = new PdfReader(sourceFilePath);
///ระบุพาธไฟล์ปลายทางที่ต้องการบันทึกไฟล์แบบมีภาพลายน้ำ
var pdfStamper = new PdfStamper(pdfReader, new FileStream(targetFilePath, FileMode.Create));
///ระบุพาธของไฟล์ภาพที่ต้องการนำมาทำภาพลายน้ำ
var image = iTextSharp.text.Image.GetInstance(watermarkImagePath);
image.SetAbsolutePosition(200, 400);
///ทำการวนลูปเพื่อทำภาพลายน้ำให้กับไฟล์ PDF ทีละหน้า
for (var i = 0; i < pdfReader.NumberOfPages; i++)
{
var content = pdfStamper.GetUnderContent(i + 1);
content.AddImage(image);
}
pdfStamper.Close();
}
วิธีเรียกใช้งาน (กรณีนี้สมมุติให้เป็นการกดปุ่มเพื่อเรียกใช้งานเมธอดดังกล่าว)
protected void btnGenWatermark_Click(object sender, EventArgs e)
{
////กำหนด Path ของไฟล์ภาพที่ต้องการทำลายน้ำ
string strWaterMark = HttpContext.Current.Server.MapPath("~/images/clientpreview.png");
////ระบุ Path ของไฟล์ PDF ต้นทางที่ต้องการทำลายน้ำ
string strSourcePath = HttpContext.Current.Server.MapPath("~/PDF/File/job_apply_form.pdf");
////สร้างตัวแปรชื่อไฟล์ PDF ที่จะบันทึกใหม่ในชื่อตัวแปร genName
string genName = Guid.NewGuid().ToString() + ".pdf";
////ระบุพาธปลายทางที่ต้องการบันทึกไฟล์แบบมีลายน้ำพร้อมทั้งชื่อไฟล์ใหม่ที่จะบันทึก
string targetPath = HttpContext.Current.Server.MapPath("~/PDF/WatermarkPDF/" + genName);
////ตรวจสอบว่ามีไฟล์ภาพลายน้ำ และไฟล์ PDF ต้นทางดังกล่าวอยู่จริงตามที่อยู่ที่ระบุไว้หรือไม่
if (File.Exists(strWaterMark) && File.Exists(strSourcePath))
{
AddImageWatermark(strSourcePath, strWaterMark, targetPath);
}
}
2.2 แบบสร้างลายน้ำบนไฟล์เดิม โดยการสร้างเมธอด AddImageWatermarkInExistingFile
private void AddImageWatermarkInExistingFile(string sourceFilePath,string watermarkImagePath )
{
///อ่านค่าจากพาธไฟล์ต้นทางที่ต้องการทำภาพลายน้ำ
byte[] bytes = File.ReadAllBytes(sourceFilePath);
///ระบุพาธของไฟล์ภาพที่ต้องการนำมาทำภาพลายน้ำ
var img = iTextSharp.text.Image.GetInstance(watermarkImagePath);
img.SetAbsolutePosition(200, 400);
PdfContentByte waterMark;
using (MemoryStream stream = new MemoryStream())
{
///ทำภาพลายน้ำในไฟล์ต้นทางที่ต้องการทำภาพลายน้ำ
PdfReader reader = new PdfReader(bytes);
using (PdfStamper stamper = new PdfStamper(reader, stream))
{
///ทำการวนลูปเพื่อทำภาพลายน้ำให้กับไฟล์ PDF ทีละหน้า
int pages = reader.NumberOfPages;
for (int i = 1; i <= pages; i++)
{
waterMark = stamper.GetUnderContent(i);
waterMark.AddImage(img);
}
}
bytes = stream.ToArray();
}
File.WriteAllBytes(sourceFilePath, bytes);
}
วิธีเรียกใช้งาน (กรณีนี้สมมุติให้เป็นการกดปุ่มเพื่อเรียกใช้งานเมธอดดังกล่าว)
protected void btnGenWatermark_Click(object sender, EventArgs e)
{
////กำหนด Path ของไฟล์ภาพที่ต้องการทำลายน้ำ
string strWaterMark = HttpContext.Current.Server.MapPath("~/images/clientpreview.png");
////ระบุ Path ของไฟล์ PDF ต้นทางที่ต้องการทำลายน้ำ
string strSourcePath = HttpContext.Current.Server.MapPath("~/PDF/File/job_apply_form.pdf");
////สร้างตัวแปรชื่อไฟล์ PDF ที่จะบันทึกใหม่ในชื่อตัวแปร genName
string genName = Guid.NewGuid().ToString() + ".pdf";
////ตรวจสอบว่ามีไฟล์ภาพลายน้ำ และไฟล์ PDF ต้นทางดังกล่าวอยู่จริงตามที่อยู่ที่ระบุไว้หรือไม่
if (File.Exists(strWaterMark) && File.Exists(strSourcePath))
{
AddImageWatermarkInExistingFile(strSourcePath,strWaterMark);
}
}
ตัวอย่างผลลัพธ์
หมายเหตุ :
1. ทั้งสองวิธีข้างต้นจะให้ผลลัพธ์ของภาพลายน้ำแบบเดียวกัน แต่ต่างกันตรงที่ไฟล์ที่บันทึกภาพลายน้ำ โดยแบบแรกจะสร้างเป็นไฟล์ใหม่ แต่แบบที่สองจะบันทึกลงบนไฟล์เดิม
2. ในการใช้ภาพทำภาพลายน้ำ อาจจะต้องระวังเกี่ยวกับขนาดภาพที่นำมาใช้ในการแสดงผล และอาจต้องทดสอบการจัดวางตำแหน่งของภาพ เพื่อให้ภาพลายน้ำดังกล่าวออกมาสวยงาม และตรงกับความต้องการในการใช้งาน เพราะหากใช้ภาพที่ใหญ่หรือเล็กเกินไป อาจทำให้ไม่เหมาะกับการนำมาใช้งานได้
ซึ่งทั้งหมดนี้ก็เป็นเพียงวิธีเบื้องต้นในการสร้างภาพลายน้ำด้วย iTextSharp เท่านั้น เราอาจจะต้องลองผิดลองถูก ประยุกต์วิธีการนำไปใช้ไปด้วยกัน และหวังว่าบทความนี้จะเป็นประโยชน์กับผู้อ่านเพื่อให้แต่ละท่านสามารถนำวิธีดังกล่าวไปประยุกต์ใช้เพิ่มเติมกับงานพัฒนาที่ท่านกำลังทำอยู่ หรือหากผู้อ่านท่านใดมีข้อเสนอแนะสามารถให้คำแนะนำมาได้นะคะ ทางเรายินดีรับฟังทุกข้อเสนอแนะ เพื่อเป็นการต่อยอดความรู้ร่วมกันนะคะ แล้วพบกันใหม่ในบทความหน้า และขอบคุณที่ติดตามกันนะคะ ^^
แหล่งอ้างอิง