c#实现生成PDF的底层方法

在用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);
        }