动态页面转静态页面+HTML转换PDF+导出PDF

这几天客户有一个需求:学生的成绩提供打印和导出PDF格式文件两种方法。由于之前没有接触过生成PDF文件,所以在这个上面话了一点时间。下面是这两天的研究成果:

生成PDF文件在网上有很多资源。大部分是用到ITextSharp。我就省事直接从别人的例子里面拿过来了。

 1  private void CreatPdf()
 2         {
 3             Document doc = new Document(PageSize.A4, 9, 18, 36, 36);//左右上下
 4             MemoryStream ms = new MemoryStream();
 5             try
 6             {
 7                 PdfWriter writer = PdfWriter.GetInstance(doc, ms);
 8                 writer.CloseStream = false;
 9                 doc.Open();
10                 url =Request.Url.AbsoluteUri;
11                 Thread thread = new Thread(new ThreadStart(setBitmap));
12                 thread.SetApartmentState(ApartmentState.STA);
13                 thread.Start();
14                 while (thread.IsAlive)
15                     Thread.Sleep(100);
16                 bitmap.Save(Server.MapPath("t.bmp"));
17 
18                 iTextSharp.text.Image img = iTextSharp.text.Image.GetInstance(bitmap, System.Drawing.Imaging.ImageFormat.Bmp);
19                 img.ScalePercent(75);//560 630
20                 doc.Add(img);
21             }
22             catch (Exception err)
23             {
24                 throw new Exception(err.Message);
25             }
26             finally
27             {
28                 doc.Close();
29                 using (FileStream fs = new FileStream(Server.MapPath("out.pdf"), FileMode.Create))
30                 {
31                     ms.Position = 0;
32                     byte[] bit = new byte[ms.Length];
33                     ms.Read(bit, 0, (int)ms.Length);
34                     fs.Write(bit, 0, bit.Length);
35                 }
36                 System.IO.File.Delete(ViewState["pdf"].ToString());
37                 ViewPdf(ms);
38             }
39         }
40 
41         private void ViewPdf(Stream fs)
42         {
43             Response.Clear();
44             //中文名的话
45             //Response.AppendHeader("Content-Disposition", "attachment;filename=" +
46             //             HttpUtility.UrlEncode(fileName, System.Text.Encoding.UTF8) + ";charset=GB2312");
47             Response.AddHeader("Content-Disposition", "attachment;FileName=out.pdf");
48             Response.AddHeader("Content-Length", fs.Length.ToString());
49             Response.ContentType = "application/pdf";
50             long fileLength = fs.Length;
51             int size = 10240;//10K一--分块下载,10K为1块
52             byte[] readData = new byte[size];
53             if (size > fileLength)
54                 size = Convert.ToInt32(fileLength);
55             long fPos = 0;
56             bool isEnd = false;
57             while (!isEnd)
58             {
59                 if ((fPos + size) >= fileLength)
60                 {
61                     size = Convert.ToInt32(fileLength - fPos);
62                     isEnd = true;
63                 }
64                 readData = new byte[size];
65                 fs.Position = fPos;
66                 fs.Read(readData, 0, size);
67                 Response.BinaryWrite(readData);
68                 Response.OutputStream.Flush();
69                 fPos += size;
70             }
71             fs.Close();
72             Response.OutputStream.Close();
73             Response.End();//非常重要,没有这句的话,页面的HTML代码将会保存到文件中
74             Response.Close();
75         }
View Code

 

最主要的问题是,怎么样把本页面转换成PDF?ITextSharp没有直接把html画到PDF文件的方法。

首先,有一个想法,那就是把页面转换成图片。再把这个图片加到PDF文件就方便了。

那么怎么把本页面转换成图片呢?在System.Windows.Forms.WebBrowser类下有一个DrawToBitmap方法,好了,这就简单了。我们创建一个WebBrowser实例,让它把本页面加载进去再画图片就可以了。

 1  public void setBitmap()
 2         {
 3             using (WebBrowser wb = new WebBrowser())
 4             {
 5                 wb.Width = w;
 6                 wb.Height = h;
 7                 wb.ScrollBarsEnabled = false;
 8                 wb.Navigate(ViewState["pdf"].ToString());
 9                 //确保页面被解析完全
10                 while (wb.ReadyState != WebBrowserReadyState.Complete)
11                 {
12                     System.Windows.Forms.Application.DoEvents();
13                 }
14                 bitmap = new System.Drawing.Bitmap(w, h);
15                 wb.DrawToBitmap(bitmap, new System.Drawing.Rectangle(0, 0, w, h));
16                 wb.Dispose();
17             }
18         }
View Code

 

这个想法是可以的,在一些不需要登录信息的页面是可用的,可是我想打印的是学生成绩。必须需要登录才拿到成绩信息打印出来。当新建一个WebBrowser再指向成绩页面的时候就没有了登录信息。成为了匿名访问。打印出来的是系统的登录页面。

解决这个问题的时候我想到了单点登录的方法,但是想想为了一个导出功能用上了单点登录有点大材小用了。就在苦苦思考的时候突然想了起来,既然上面的导出方法对于导出静态页面是有效的,为什么不在点击打印的时候把本页面转换成静态html页面保存在服务器目录上提供导出,再导出之后再删掉呢?

现在问题又变了,如何导出静态页面呢?这个简单。

 1  protected void Button1_Click(object sender, EventArgs e)
 2         {
 3             //把页面保存成静态页面再导出,这样就不会因为未登录而打印到登陆页面。
 4             //第一步:
 5             string paf = Guid.NewGuid ().ToString();//获取唯一表示。防止多用户并发时导出别人页面。
 6             ViewState["pdf"] = Server.MapPath("~") + paf + "pdf.html";//静态页面的保存路径。为了图片能够显示,Server.MapPath("~")你得改成你相应的文件夹下。
 7             ToHTML("~/PDFForm.aspx?type=pdf", ViewState["pdf"].ToString());//保存静态页面。
 8             //第二部:导出PDF文件
 9             CreatPdf();
10         }
11         private void ToHTML(string url, string savefile)
12         {
13             StreamWriter sw = new StreamWriter(savefile, false, System.Text.Encoding.GetEncoding("gb2312"));
14             Server.Execute(url, sw, true);
15 
16             sw.Flush();
17             sw.Close();
18         }
View Code

就在以为大事告成的时候问题出现了,因为是在点击导出按钮的时候生成静态页面,又要访问本页面一次,这就造成了死循环。这次的解决方法是:在生成静态页面的时候带上参数,在Page_Load事件里面把按钮的时间去掉。这就可以了。

 1   private System.Drawing.Bitmap bitmap;
 2         private string url;
 3         private int w = 760, h = 900;
 4         protected void Page_Load(object sender, EventArgs e)
 5         {
 6             if (Request["type"] != null && Request["type"] == "pdf")
 7             {
 8                 Button1.Visible = false;
 9                 Button1.Click -= Button1_Click;//如果没有写,会成为死循环!
10             }
11         }
View Code

 

posted on 2013-09-27 16:16  WeiLight  阅读(2825)  评论(0编辑  收藏  举报