Coding4Fun - PDF 投影片兩張一頁排版列印
1 |
近年來愈來愈多的投影片會採用 PDF 格式提供,我想整理成一張 A4 紙兩頁,雙面列印,用 4 孔夾裝冊。每張投影片希望加上邊框,配合裝訂孔要單數頁右靠、雙數頁左靠,頁碼也依單雙頁放在右下角或左下角。
這需求有些龜毛,我猜有現成軟體或印表機功能可實現,但我實在懶得花時間找,加上前陣子剛學了 PdfSharp,就把它當題目練手感吧~
很幸運有找到兩頁直式 A4 排進一頁橫式 A4 的官方範例,從中學會 gfx.DrawImage(XForm, XRectBox) 的技巧,在 PdfSharp 中,Form 物件可將一堆圖形、文字、圖片及其他 Form 物件視為一個集合,將整塊內容繪製到指定的矩形範圍,實現複製或縮放整頁內容,配合一些簡單的邊界、尺寸計算,依輸出結果校正打孔位置,一個 100% 客製化的投影片排版程式就完成了:
using System.Drawing.Printing;
using PdfSharp;
using PdfSharp.Charting;
using PdfSharp.Drawing;
using PdfSharp.Fonts;
using PdfSharp.Pdf;
using PdfSharp.Pdf.IO;
using PdfSharp.Snippets.Font;
string filename = "D:\\Source.pdf";
// 建立輸出 PDF 文件
PdfDocument outputDocument = new PdfDocument();
// 設定開啟 PDF 時顯示單頁
outputDocument.PageLayout = PdfPageLayout.SinglePage;
XFont font = new XFont("Tahoma", 12, XFontStyleEx.Bold);
XStringFormat format = new XStringFormat();
format.Alignment = XStringAlignment.Center;
format.LineAlignment = XLineAlignment.Far;
XGraphics gfx;
XRect box;
// 開啟來源 PDF 文件
XPdfForm form = XPdfForm.FromFile(filename);
// 指定 PDF 邊界
var outCurPageNo = 1;
// 指定裝訂邊界
double bindingMargin = 18;
double margin = 20;
double leftMargin = 0;
for (int idx = 0; idx < form.PageCount; idx += 2)
{
// 建立新頁,直式放入兩頁橫式投影片頁
PdfPage page = outputDocument.AddPage();
page.Size = PageSize.A4;
page.Orientation = PageOrientation.Portrait;
double width = page.Width;
double height = page.Height;
// 左邊界 (保留打孔裝訂空間)
// 單數頁偏右,雙數頁偏左
leftMargin = outCurPageNo % 2 == 1 ? bindingMargin + margin : margin;
gfx = XGraphics.FromPdfPage(page);
// 切換來源 PDF 文件的頁數
form.PageNumber = idx + 1;
// 決定擺放位置及尺寸
double scaleRatio = (width - bindingMargin - margin - margin) / width;
var heightOffset = height / 2 * (1 - scaleRatio);
box = new XRect(leftMargin, heightOffset * 2 / 3, width * scaleRatio, height / 2 * scaleRatio);
// 將來源 PDF 文件的頁面畫到新頁上
gfx.DrawImage(form, box);
// 繪製投影片邊框
gfx.DrawRectangle(XPens.DarkGray, box);
// 若還有次頁
if (idx + 1 < form.PageCount)
{
// 將次頁畫在下半部
form.PageNumber = idx + 2;
box = new XRect(leftMargin, height / 2 + (heightOffset / 3), width * scaleRatio, height / 2 * scaleRatio);
gfx.DrawImage(form, box);
gfx.DrawRectangle(XPens.DarkGray, box);
}
// 繪製打孔位置
var ppcmX = width / (21.1 - 0.8); // A4 尺寸需扣除印表機無法印到的部分
var ppcmY = height / (29.7 - 1.2);
var pgNoX = 0;
if (outCurPageNo % 2 == 1)
{
var y = ppcmY * (2.8 - 0.6);
var holeSize = Convert.ToInt32(0.6 * ppcmX);
for (var i = 0; i < 4; i++)
{
gfx.DrawPie(XPens.Black, new System.Drawing.RectangleF(
(float)(ppcmX * 0.3), (float)(i * 8 * ppcmY + y),
holeSize, holeSize), 0, 360);
}
pgNoX = Convert.ToInt32(width - 65);
}
gfx.DrawString("P." + outCurPageNo, font, XBrushes.Black,
new XRect(pgNoX, height - 40, 65, 30), format);
outCurPageNo++;
}
filename = "D:\\Final.pdf";
outputDocument.Save(filename);
成功!
題外話,家裡印表機的列印品質愈來愈差(顏色變淡、模糊化),懷疑是感光鼓壞了,猶豫要不要賭一把換看看,有人有相關經驗可分享嗎?
Comments
# by Anonymous
感光鼓是粍材 如果是小型機器,HP 是做在碳粉匣裡面,Brother 可以單獨換 大台落地型也可以單獨換,但比較難取得 如果是副廠的碳就直接換一隻碳粉了 沒多少錢的