近年來愈來愈多的投影片會採用 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 可以單獨換 大台落地型也可以單獨換,但比較難取得 如果是副廠的碳就直接換一隻碳粉了 沒多少錢的

Post a comment