在用uwp生成pdf的時候,發展此類類庫有限,有的也需要錢,我最后實現pdf的底層方法生成pdf,代碼如下
private async void GeneratePdf() { var file = await ApplicationData.Current.LocalFolder.CreateFileAsync("uwpCSharp.pdf", Windows.Storage.CreationCollisionOption.ReplaceExisting); using (var stream = await System.IO.WindowsRuntimeStorageExtensions.OpenStreamForWriteAsync(file)) { using (var writer = new System.IO.StreamWriter(stream, System.Text.Encoding.UTF8)) { List<long> xrefs = new List<long>(); writer.WriteLine("%PDF-1.2"); writer.Write("%"); writer.Flush(); byte[] bytes = { 0, 0, 0, 0 }; stream.Write(bytes, 0, 4); stream.Flush(); writer.WriteLine(""); writer.Flush(); stream.Flush(); xrefs.Add(stream.Position); writer.WriteLine("1 0 obj"); writer.WriteLine("<<"); writer.WriteLine(" /Type /Catalog"); writer.WriteLine(" /Pages 2 0 R"); writer.WriteLine(">>"); writer.WriteLine("endobj"); // #2: 頁面列表 - 我們只有一頁文字 writer.Flush(); stream.Flush(); xrefs.Add(stream.Position); writer.WriteLine("2 0 obj"); writer.WriteLine("<<"); writer.WriteLine(" /Type /Pages"); writer.WriteLine(" /Kids [3 0 R]"); writer.WriteLine(" /Count 1"); writer.WriteLine(">>"); writer.WriteLine("endobj"); // #3: 頁面 - 這里放文字、資源等 writer.Flush(); stream.Flush(); xrefs.Add(stream.Position); writer.WriteLine("3 0 obj"); writer.WriteLine("<<"); writer.WriteLine(" /Type /Page"); writer.WriteLine(" /Parent 2 0 R"); writer.WriteLine(" /MediaBox [0 0 612 792]"); // 默認的用戶空間: 72/inch writer.WriteLine(" /Resources"); writer.WriteLine(" <<"); writer.WriteLine(" /ProcSet [/PDF/Text]"); // 這個pdf只有文本 writer.WriteLine(" /Font"); writer.WriteLine(" <<"); writer.WriteLine(" /F0 4 0 R"); // 定義的三種字體, #4, #5 和 #6 writer.WriteLine(" /F1 5 0 R"); writer.WriteLine(" /F2 6 0 R"); writer.WriteLine(" >>"); writer.WriteLine(" >>"); writer.WriteLine(" /Contents 7 0 R"); writer.WriteLine(">>"); writer.WriteLine("endobj"); // #4, #5, #6: 三鍾字體,我們使用pdf默認字體 //使用WinAnsi字符編碼,定義如下 writer.Flush(); stream.Flush(); xrefs.Add(stream.Position); writer.WriteLine("4 0 obj"); writer.WriteLine("<<"); writer.WriteLine(" /Type /Font"); writer.WriteLine(" /Subtype /Type1"); writer.WriteLine(" /Encoding /WinAnsiEncoding"); writer.WriteLine(" /BaseFont /Times-Roman"); writer.WriteLine(">>"); writer.Flush(); stream.Flush(); xrefs.Add(stream.Position); writer.WriteLine("5 0 obj"); writer.WriteLine("<<"); writer.WriteLine(" /Type /Font"); writer.WriteLine(" /Subtype /Type1"); writer.WriteLine(" /Encoding /WinAnsiEncoding"); writer.WriteLine(" /BaseFont /Times-Bold"); writer.WriteLine(">>"); writer.Flush(); stream.Flush(); xrefs.Add(stream.Position); writer.WriteLine("6 0 obj"); writer.WriteLine("<<"); writer.WriteLine(" /Type /Font"); writer.WriteLine(" /Subtype /Type1"); writer.WriteLine(" /Encoding /WinAnsiEncoding"); writer.WriteLine(" /BaseFont /Times-Italic"); writer.WriteLine(">>"); // #7:內容頁面。這是用postscript編寫的, // 有興趣的朋友可以查看PDF 1.2參考手冊第8章 writer.Flush(); stream.Flush(); xrefs.Add(stream.Position); System.Text.StringBuilder sb = new System.Text.StringBuilder(); sb.AppendLine("BT"); // BT =開始文本對象 sb.AppendLine("/F0 30 Tf"); // Tf = 使用文字 "F0" 定義文字大小為 "30" sb.AppendLine("30 TL"); // TL = 設置高度為 "30" sb.AppendLine("140.0 780.0 Td"); // Td = 文本坐標的位置 "140.0", "780.0" sb.AppendLine("1.0 0.0 0.6 rg"); // rg = 字體前景顏色設置 sb.AppendLine("(Microsoft Corporation India) '"); sb.AppendLine("ET"); //畫線 //頂部的線 sb.AppendLine("BT"); sb.AppendLine("10 TL"); sb.AppendLine("50.0 730.0 Td"); sb.AppendLine("0.0 0.0 0.0 rg"); sb.AppendLine("(__________________________________)'"); sb.AppendLine("ET"); //左邊 sb.AppendLine("BT"); sb.AppendLine("10 TL"); sb.AppendLine("47.0 703.0 Td"); sb.AppendLine("0.0 0.0 0.0 rg"); for (int i = 0; i <= 60; i++) { sb.AppendLine("(|)'"); } sb.AppendLine("ET"); //中間的線 sb.AppendLine("BT"); sb.AppendLine("10 TL"); sb.AppendLine("240.0 703.0 Td"); sb.AppendLine("0.0 0.0 0.0 rg"); for (int i = 0; i <= 60; i++) { sb.AppendLine("(|)'"); } sb.AppendLine("ET"); //畫右邊的線 sb.AppendLine("BT"); sb.AppendLine("10 TL"); sb.AppendLine("557.0 703.0 Td"); sb.AppendLine("0.0 0.0 0.0 rg"); for (int i = 0; i <= 60; i++) { sb.AppendLine("(|)'"); } sb.AppendLine("ET"); //底部的線 sb.AppendLine("BT"); sb.AppendLine("10 TL"); sb.AppendLine("50.0 102.0 Td"); sb.AppendLine("0.0 0.0 0.0 rg"); sb.AppendLine("(__________________________________)'"); sb.AppendLine("ET"); //文字 sb.AppendLine("BT"); sb.AppendLine("/F0 15 Tf"); sb.AppendLine("20 TL"); sb.AppendLine("70.0 670.0 Td"); sb.AppendLine("0.0 0.2 1.0 rg"); sb.AppendLine("(Parameter1)'"); sb.AppendLine("ET"); // sb.AppendLine("BT"); sb.AppendLine("/F0 15 Tf"); sb.AppendLine("20 TL"); sb.AppendLine("0.0 0.0 0.0 rg"); sb.AppendLine("260.0 670.0 Td"); sb.AppendLine("(test1) '"); sb.AppendLine("ET"); // sb.AppendLine("BT"); sb.AppendLine("/F0 15 Tf"); sb.AppendLine("20 TL"); sb.AppendLine("0.0 0.2 1.0 rg"); sb.AppendLine("70.0 645.0 Td"); sb.AppendLine("(Parameter2)'"); sb.AppendLine("ET"); // sb.AppendLine("BT"); sb.AppendLine("/F0 15 Tf"); sb.AppendLine("20 TL"); sb.AppendLine("0.0 0.0 0.0 rg"); sb.AppendLine("260.0 645.0 Td"); sb.AppendLine("(test2) '"); sb.AppendLine("ET"); // sb.AppendLine("BT"); sb.AppendLine("/F0 15 Tf"); sb.AppendLine("20 TL"); sb.AppendLine("0.0 0.2 1.0 rg"); sb.AppendLine("70.0 615.0 Td"); sb.AppendLine("(Parameter3)'"); sb.AppendLine("ET"); // sb.AppendLine("BT"); sb.AppendLine("/F0 15 Tf"); sb.AppendLine("20 TL"); sb.AppendLine("260.0 615.0 Td"); sb.AppendLine("0.0 0.0 0.0 rg"); sb.AppendLine("(test3) '"); // // sb.AppendLine("BT"); sb.AppendLine("/F0 15 Tf"); sb.AppendLine("20 TL"); sb.AppendLine("0.0 0.2 1.0 rg"); sb.AppendLine("70.0 575.0 Td"); sb.AppendLine("(Parameter4)'"); sb.AppendLine("ET"); // sb.AppendLine("BT"); sb.AppendLine("/F0 15 Tf"); sb.AppendLine("20 TL"); sb.AppendLine("260.0 575.0 Td"); sb.AppendLine("0.0 0.0 0.0 rg"); sb.AppendLine("(test4) '"); sb.AppendLine("ET"); // writer.WriteLine("7 0 obj"); writer.WriteLine("<<"); writer.WriteLine(" /Length " + sb.Length); writer.WriteLine(">>"); writer.WriteLine("stream"); writer.Write(sb.ToString()); writer.WriteLine(" q"); writer.WriteLine(" 156 0 0 272 100 200 cm"); //[1 2 3 4 5 6 cm] translate to (5,6) and scale for 1 writer.WriteLine(" /Img1 Do"); writer.WriteLine(" Q"); writer.WriteLine("endstream"); writer.WriteLine("endobj"); writer.Flush(); stream.Flush(); dynamic xref_pos = stream.Position; writer.WriteLine("xref"); writer.WriteLine("1 " + xrefs.Count); long xref = 0; foreach (long xref_loopVariable in xrefs) { xref = xref_loopVariable; writer.WriteLine("{0:0000000000} {1:00000} n", xref, 0); } // PDF-TRAILER. PDF以這個節點結尾. writer.WriteLine("trailer"); writer.WriteLine("<<"); writer.WriteLine(" /Size " + xrefs.Count); writer.WriteLine(" /Root 1 0 R"); writer.WriteLine(">>"); writer.WriteLine("startxref"); writer.WriteLine(xref_pos); writer.WriteLine("%%EOF"); } } await Windows.System.Launcher.LaunchFileAsync(file); }