HotPDF พิมพ์เอกสาร PDF ที่โหลดเข้ามาไปยังเครื่องพิมพ์จริง, บริบทอุปกรณ์ (device context) ใดๆ ของ Windows หรือคลิปบอร์ดผ่านการเรียกใช้งานสามคำสั่ง ได้แก่: PrintLoadedDocument ทำหน้าที่ควบคุม VCL TPrinter, RenderLoadedPageToDC วาดหน้ากระดาษลงใน HDC ใดๆ โดยตรง และ RenderLoadedPageToClipboard คัดลอกหน้ากระดาษในรูปแบบบิตแมปหรือเวกเตอร์เมตาไฟล์ HotPDF เป็นส่วนประกอบ VCL PDF ดั้งเดิมสำหรับ Delphi และ C++Builder และได้เพิ่มพาธการพิมพ์ระดับเฟิร์สคลาสนี้ในเวอร์ชัน v2.331.0 และปรับปรุงใน v2.348.0 เพื่อให้คุณไม่ต้องเขียนลูป TPrinter รอบตัวเรนเดอร์บิตแมปด้วยตนเองอีกต่อไป การเรียกทั้งสามคำสั่งนี้จะวาดเนื้อหาเวกเตอร์ของหน้ากระดาษโดยตรงไปยังอุปกรณ์เป้าหมาย ช่วยให้งานพิมพ์มีความคมชัดสูงสุดเท่าที่เครื่องพิมพ์จะสามารถเรนเดอร์ได้
เหตุใดจึงควรวาดหน้า PDF ลงในเครื่องพิมพ์โดยตรงแทนที่จะใช้บิตแมป?
หน้ากระดาษ PDF คือโปรแกรมของตัวดำเนินการวาดรูปเวกเตอร์ — เช่น พาธ, ข้อความ และรูปภาพที่ประมวลผลเทียบกับแบบจำลองกราฟิก ISO 32000-1 — ไม่ใช่ตารางพิกเซล วิธีปกติทั่วไปในการพิมพ์คือการแปลงหน้ากระดาษให้เป็นแรสเตอร์บิตแมปแล้วส่งภาพบิตแมปนั้นไปที่แคนวาส (canvas) ของเครื่องพิมพ์ วิธีนี้ใช้งานได้จริงแต่จะเป็นการสูญเสียประสิทธิภาพที่แท้จริงของเครื่องพิมพ์ เครื่องพิมพ์เลเซอร์สมัยใหม่สามารถประมวลผลความละเอียดได้ถึง 600 หรือ 1200 DPI ในขณะที่รูปภาพบิตแมปที่แปลงความละเอียดมาเพียง 150 หรือ 300 DPI เมื่อนำมาขยายขนาดให้พอดีกระดาษจะทำให้ภาพเบลอ ตัวหนังสือหยัก และเห็นรอยแตกได้ชัดเจน เมธอด RenderLoadedPageToDC จึงเลือกใช้วิธีที่ดีกว่าคือ: การนำเอาสตรีมเนื้อหาของหน้ากระดาษมารันใหม่เป็นคำสั่ง GDI ส่งไปยังบริบทอุปกรณ์ปลายทางโดยตรง เพื่อให้ข้อความเวกเตอร์และลายเส้นส่งไปถึงเครื่องพิมพ์ในรูปแบบเวกเตอร์และผ่านการแปลงแรสเตอร์เพียงครั้งเดียวโดยเอนจินของเครื่องพิมพ์ที่ความละเอียดดั้งเดิมของตัวเครื่องพิมพ์เอง
จะพิมพ์ PDF ที่โหลดเข้ามาไปยังเครื่องพิมพ์จริงใน Delphi ได้อย่างไร?
HotPDF พิมพ์เอกสารที่โหลดเข้ามาด้วย PrintLoadedDocument(Printer, Options) ซึ่งจะรับออบเจกต์ VCL TPrinter ที่กำหนดให้ และโครงสร้างข้อมูล THPDFPrintOptions ทำการพิมพ์หน้าเอกสารที่เลือก และส่งคืนจำนวนหน้าที่ส่งออกไป ก่อนอื่นให้กำหนด Printer.PrinterIndex เพื่อเลือกอุปกรณ์ จากนั้นกรอกข้อมูลตัวเลือกในโครงสร้างข้อมูล — ฟังก์ชันคลาส THPDFPrintOptions.Default จะให้ค่าเริ่มต้นที่เหมาะสมแก่คุณ — แล้วเรียกใช้หนึ่งครั้ง ไลบรารีจะเปิดงานพิมพ์ด้วย Printer.BeginDoc วนลูปตามช่วงหน้ากระดาษโดยแทรกคำสั่ง Printer.NewPage ระหว่างหน้า และปิดงานพิมพ์ด้วย Printer.EndDoc ทำให้คุณไม่ต้องจัดการวงจรอายุของงานพิมพ์ด้วยตัวเองเลย
uses Printers;
var
Pdf: THotPDF;
Opts: THPDFPrintOptions;
begin
Pdf := THotPDF.Create(nil);
try
if Pdf.LoadFromFile('invoice.pdf') > 0 then
begin
Printer.PrinterIndex := -1; // -1 selects the default printer
Opts := THPDFPrintOptions.Default; // all pages, 300 DPI, FitPage, colour
Opts.PageRange := '1,3-5'; // one-based; empty prints every page
Opts.Copies := 2;
Pdf.PrintLoadedDocument(Printer, Opts);
end;
finally
Pdf.Free;
end;
end;
สตริง PageRange จะเริ่มนับจาก 1 และอ่านค่าได้เช่นเดียวกับที่กำหนดในกล่องโต้ตอบการพิมพ์: ตัวอย่างเช่น '1,3-5' จะพิมพ์หน้า 1 และหน้า 3 ถึง 5 ส่วนสตริงว่างจะหมายถึงการพิมพ์เอกสารทั้งหมด Copies จะชี้ไปยัง Printer.Copies โดยตรง อย่างไรก็ตาม ควรพิจารณาเรื่อง Collate (จัดชุด) ตามจริง: เนื่องจาก VCL แสดงคุณสมบัติการจัดชุดไม่สอดคล้องกันในแต่ละเวอร์ชันของ Delphi ตัว HotPDF จึงทำหน้าที่เพียงกำหนดจำนวนสำเนาและปล่อยให้การจัดชุดเป็นหน้าที่ของไดรเวอร์เครื่องพิมพ์เริ่มต้น ดังนั้นหากคุณต้องการความถูกต้องแน่นอนของการจัดชุดเอกสาร โปรดเลือกตั้งค่าที่ตัวไดรเวอร์ผ่าน TPrinterSetupDialog แทนที่จะพึ่งพาแฟล็กดังกล่าว
DPI และ FitPage กำหนดขนาดการพิมพ์อย่างไร?
การทำงานร่วมกันระหว่าง FitPage และ DPI เป็นสิ่งที่คุณควรทำความเข้าใจก่อนเริ่มงานจริง เมื่อตั้งค่า FitPage เป็น True — ซึ่งเป็นค่าเริ่มต้น — HotPDF จะอ่านค่า MediaBox ของแต่ละหน้า ปรับขนาดให้พอดีกับ Printer.PageWidth และ Printer.PageHeight โดยรักษาสัดส่วนภาพเอาไว้ และเรนเดอร์ในขนาดที่ทำให้หน้ากระดาษแสดงผลเต็มกระดาษพิมพ์ ในโหมดนี้ ค่า Options.DPI จะถูกเขียนทับด้วยขนาดที่ปรับให้พอดีเนื่องจากเอาต์พุตจะต้องสอดคล้องกับมิติกระดาษจริงของเครื่องพิมพ์ แต่หากกำหนด FitPage เป็น False ตัว HotPDF จะเรนเดอร์แต่ละหน้าในอัตราส่วน 1:1 ที่ความละเอียด Options.DPI พอดี โดยจับคู่ 72 หน่วย PDF เข้ากับพิกเซลอุปกรณ์ DPI ซึ่งเหมาะสำหรับกรณีที่หน้ากระดาษต้นทางและกระดาษพิมพ์มีขนาดเท่ากันอยู่แล้ว และคุณต้องการกำหนดความละเอียดที่แน่นอน เลือกใช้ FitPage เมื่อขนาดหน้าต้นทางและถาดกระดาษพิมพ์ต่างกัน และเลือกใช้ 1:1 เมื่อขนาดตรงกันและคุณต้องการควบคุมขนาดการพิมพ์ที่แม่นยำ
ตัวเลือกสองตัวที่เพิ่มเข้ามาในเวอร์ชัน v2.348.0 จะช่วยแก้ปัญหาเครื่องพิมพ์ที่พิมพ์ออกมาเกือบจะถูกต้อง เครื่องพิมพ์จริงทุกเครื่องจะมีระยะขอบแข็ง (hard margin) — ซึ่งเป็นขอบเขตพิมพ์ไม่ได้ที่หัวพิมพ์ไม่สามารถเข้าถึง — และตามค่าเริ่มต้น จุดเริ่มต้นหน้ากระดาษจะอยู่ภายในระยะขอบนั้น ทำให้หน้ากระดาษแบบพิมพ์เต็มขอบ (full-bleed) สูญเสียขอบไปสองด้าน หากกำหนด IgnoreHardMargin เป็น True ตัว HotPDF จะค้นหาค่า PHYSICALOFFSETX และ PHYSICALOFFSETY ของเครื่องพิมพ์ จากนั้นจะเลื่อนจุดเริ่มต้นอุปกรณ์เพื่อล้างค่าออฟเซ็ตนั้นออกไป ช่วยให้จุดเริ่มต้นหน้ากระดาษตรงกับมุมกระดาษจริงอย่างถูกต้อง ส่วนตัวเลือกที่สองคือ AutoRotate จะเปิดทำงานตามค่าเริ่มต้น: โดยจะอ่าน MediaBox ของแต่ละหน้า และเมื่อหน้ากระดาษมีความกว้างมากกว่าความสูง มันจะสลับโหมดเครื่องพิมพ์เป็นแนวนอน (landscape) เพื่อให้หน้ากระดาษกว้างได้รับการพิมพ์โดยไม่ถูกตัดขอบ แทนที่จะถูกตัดให้เหลือเท่าแนวตั้ง AutoRotate จะหยุดทำงานทันทีที่คุณกำหนด Orientation เองอย่างชัดเจน ดังนั้นการตั้งค่าการจัดวางกระดาษโดยเจตนาจะมีผลเหนือกว่าเสมอ
จะเรนเดอร์หน้า PDF ลงในบริบทอุปกรณ์ใดๆ ได้อย่างไร?
RenderLoadedPageToDC(PageIndex, DC, DPI, W, H) คือฟังก์ชันระดับล่างที่อยู่ภายใต้การทำงานของลูปการพิมพ์ และมีประโยชน์ในการใช้งานแยกต่างหาก PrintLoadedDocument จะเรียกใช้งานฟังก์ชันนี้หนึ่งครั้งต่อหนึ่งหน้าเทียบกับแคนวาสของเครื่องพิมพ์ แต่เป้าหมายสามารถเปลี่ยนเป็น HDC ใดๆ ของ Windows ได้ เช่น บริบทอุปกรณ์หน่วยความจำนอกจอ (off-screen memory DC), แคนวาสของส่วนควบคุมในโปรแกรมดูภาพแบบกำหนดเอง หรือหน้าต่างแสดงตัวอย่างก่อนพิมพ์ โดย PageIndex จะเริ่มจาก 0 ส่วน W และ H คือหน่วยอุปกรณ์ของพื้นที่เป้าหมาย ตัวเรนเดอร์จะไล่ดูข้อมูล /Contents ของหน้ากระดาษและส่งคำสั่ง GDI ไปที่ DC ของคุณ พฤติกรรมประการหนึ่งที่คุณควรทราบคือ: เมธอดนี้จะไม่มีการวาดพื้นหลังสีพื้น ผู้เรียกใช้งานเป็นผู้ครอบครองพื้นที่วาด ดังนั้นหากคุณต้องการให้มีกระดาษสีขาวอยู่เบื้องหลังหน้ากระดาษ คุณจะต้องถมสี DC ด้วยตนเองก่อนเริ่มเรนเดอร์ ซึ่งวิธีนี้ช่วยให้คุณสามารถนำหน้ากระดาษไปวางซ้อนทับบนแคนวาสที่มีอยู่แล้วได้ตามต้องการ
// Draw page 1 into an off-screen 24-bit surface at 150 DPI
var
Surface: TBitmap;
begin
Surface := TBitmap.Create;
try
Surface.PixelFormat := pf24bit;
Surface.SetSize(1275, 1650); // 8.5 x 11 in at 150 DPI
Surface.Canvas.Brush.Color := clWhite;
Surface.Canvas.FillRect(Surface.Canvas.ClipRect); // caller paints the background
Pdf.RenderLoadedPageToDC(0, Surface.Canvas.Handle, 150, Surface.Width, Surface.Height);
// Surface now holds the composited page, ready to blit or save
finally
Surface.Free;
end;
end;
เมื่อคุณต้องการเพียงออบเจกต์ TBitmap ที่พร้อมใช้งาน — เช่น ภาพตัวอย่างขนาดเล็ก (thumbnail), การส่งออกรูปภาพ หรือภาพตัวอย่างก่อนพิมพ์ที่คุณต้องการแคชไว้ — ให้เลือกใช้เมธอด RenderLoadedPageToBitmap แทน ซึ่งอธิบายรายละเอียดไว้ในบทความคู่กันเรื่อง rendering PDF pages to a bitmap ความแตกต่างคือใครเป็นผู้ครอบครองพื้นที่วาด: การเรียกใช้บิตแมปจะจัดสรรหน่วยความจำและส่งคืนพิกเซลบัฟเฟอร์กลับมาให้ ในขณะที่ RenderLoadedPageToDC จะวาดภาพลงในบริบทอุปกรณ์ที่คุณมีอยู่แล้ว ซึ่งเป็นสิ่งที่แคนวาสเครื่องพิมพ์หรือตัวจัดการการวาดส่งต่อมาให้คุณ ทั้งสองแบบจะใช้ล่ามแปลสตรีมเนื้อหาและเอนจินประมวลผลตัวอักษรฝังตัวตัวเดียวกัน ดังนั้นข้อความที่แสดงออกมาจะมีลักษณะโครงร่างเส้นที่ถูกต้องแม่นยำเหมือนกันทั้งสองวิธี
จะวางหน้า PDF ลงใน Word หรือโปรแกรมแก้ไขรูปภาพได้อย่างไร?
RenderLoadedPageToClipboard(PageIndex, DPI, AsMetafile) จะส่งหน้ากระดาษหนึ่งหน้าไปยังคลิปบอร์ดของ Windows เพื่อเตรียมพร้อมสำหรับการวางลงใน Word, PowerPoint, อีเมล หรือโปรแกรมแก้ไขรูปภาพ แฟล็ก AsMetafile จะเป็นตัวเลือกรูปแบบ ซึ่งมีความสำคัญมากกว่าที่เห็นภายนอก หากส่งค่า False ตัว HotPDF จะส่งบิตแมปอุปกรณ์ขนาด 24 บิต (CF_BITMAP) ที่เรนเดอร์ตามความละเอียด DPI ของคุณ — ซึ่งเป็นตารางพิกเซลคงที่ซึ่งสามารถวางได้ทุกที่แต่ภาพจะแตกเมื่อผู้รับนำไปขยายขนาด หากส่งค่า True มันจะส่งข้อมูลเป็น Enhanced Metafile (CF_ENHMETAFILE) ซึ่งข้อความและภาพเวกเตอร์บนหน้ากระดาษจะถูกส่งเป็นชุดคำสั่งการวาดของ GDI ทำให้รูปภาพที่วางยังคงความชัดเจนในทุกระดับการซูมและย่อขยายขนาดได้ตามต้องการในเอกสารปลายทาง
// Copy page 2 as a scalable vector metafile for pasting into Word
Pdf.RenderLoadedPageToClipboard(1, 300, True);
// Copy the same page as a fixed 300-DPI bitmap instead
Pdf.RenderLoadedPageToClipboard(1, 300, False);
กฎเกณฑ์พิจารณาง่ายๆ คือ: หากผู้ใช้ต้องการนำหน้ากระดาษไปวางลงในเอกสารและอาจปรับขนาดภายหลัง — เช่น แผนภูมิในรายงาน หรือข้อกำหนดที่แทรกลงในร่างสัญญา — ให้เลือกใช้รูปแบบเมตาไฟล์ เนื่องจากข้อความเวกเตอร์จะพิมพ์และซูมได้อย่างคมชัด แต่หากโปรแกรมปลายทางรองรับเฉพาะข้อมูลภาพแรสเตอร์ หรือคุณต้องการบันทึกภาพนิ่งที่มีความละเอียดเฉพาะเจาะจง ให้เลือกใช้บิตแมป ส่วนการดึงคำศัพท์ออกจากหน้าเอกสารแทนการบันทึกภาพจะเป็นงานอีกประเภทหนึ่งซึ่งจัดการโดย the text extraction API ซึ่งจะส่งคืนค่าตัวอักษรและตำแหน่งแทนที่จะเป็นรูปภาพที่เรนเดอร์แล้ว
ข้อจำกัดของพาธการพิมพ์
ฟังก์ชันการทำงานทั้งหมดในหน้านี้รองรับเฉพาะระบบปฏิบัติการ Windows เท่านั้น และนี่คือข้อจำกัดที่ควรระบุอย่างชัดเจน PrintLoadedDocument, RenderLoadedPageToDC และ RenderLoadedPageToClipboard ถูกสร้างขึ้นบนโครงสร้างของ TPrinter, โมเดลบริบทอุปกรณ์ GDI, คลิปบอร์ดของ Windows และ Enhanced Metafiles — ซึ่งล้วนเป็นโครงสร้างของ Win32 และ Win64 สำหรับเป้าหมายระบบอื่นนั้น ตัว HotPDF จะยังคงสามารถสร้าง แก้ไข และเปิดอ่าน PDF ได้ตามปกติ แต่จะไม่สามารถใช้งานส่วนการพิมพ์และคลิปบอร์ดที่ทำงานร่วมกับ GDI ได้ นอกจากนี้ตัวเรนเดอร์จะมุ่งเน้นไปที่ส่วนประกอบเอกสารทั่วไป เช่น ข้อความ, พาธ และรูปภาพ ดังนั้นหน้าออกแบบที่มีการไล่สีหนาแน่นหรือการพิมพ์ที่ต้องใช้ระบบสี ICC-managed จะแสดงผลเป็นภาพตัวอย่างที่ใกล้เคียงแทนที่จะเป็นสีที่ถูกต้องแม่นยำตามมาตรฐานทางสี ซึ่งเป็นข้อจำกัดทำนองเดียวกับตัวเรนเดอร์บิตแมป
สำหรับการพิมพ์แบบกลุ่มข้ามไฟล์หลายไฟล์ ให้ทำการโหลดและพิมพ์แต่ละเอกสารตามลำดับและติดตามการใช้งานหน่วยความจำ: PrintLoadedDocument จะเรนเดอร์ทีละหน้า ทว่าโครงสร้างออบเจกต์ของเอกสารที่โหลดเข้ามาจะคงอยู่ในหน่วยความจำตลอดช่วงการทำงาน เมื่อคุณต้องการพิมพ์ไฟล์ขนาดใหญ่จำนวนหลายร้อยไฟล์ การสตรีมมิ่งผ่าน Direct File API for large-PDF workflows จะทำงานร่วมกับพาธการพิมพ์ได้เป็นอย่างดี — โดยแยก, รวม หรือเลือกเฉพาะหน้ากระดาษที่คุณต้องการบนดิสก์ก่อน จากนั้นจึงโหลดเฉพาะผลลัพธ์ขนาดเล็กเข้ามาพิมพ์ วิธีนี้คือลักษณะการส่งมอบงานของ PrintLoadedDocument, RenderLoadedPageToDC และ RenderLoadedPageToClipboard ซึ่งเป็นส่วนหนึ่งของ HotPDF Component สำหรับ Delphi และ C++Builder — ซึ่งเป็นไลบรารี VCL ดั้งเดิมที่ไม่มีการพึ่งพาไฟล์ DLL ภายนอก รองรับทั้งการสร้าง, แก้ไข, ดึงข้อความ, เรนเดอร์ และขณะนี้สามารถพิมพ์โดยตรงไปที่ TPrinter, บริบทอุปกรณ์ใดๆ หรือคลิปบอร์ดได้เรียบร้อยแล้ว