Canvas画好的图片虽然可以通过toDataURL()转成二进制流的字符串格式,图片稍大一点就无法发送了,当然如果需求简单的话,可以在页面上加一个image元素,将转成的流直接赋给image的src就可以显示图片了。
但是大部分的时候我们还希望弹出保存框,保存图片到我们自己想要的路径下,或者添加一些统计和分析的信息到pdf中一起保存成一个pdf文件,这就需要在后台处理了,两种方式:后台新建一个Web Browser加载当前的页面,然后将获得到的图片流的信息再发送到前台弹出保存的对话框,后台发送到前台是没有字符长度的限制的,不过这种办法就是如果保存成pdf,他是要截图然后放到pdf中,图片太长就截断了;另外一种方式就是将用到的参数传到后台,后台用GDI+在Bitmap上重新画一遍,Canvas能实现的,后台的GDI+同样都能实现,而且有些实现可能更方便一些,这个方法的好处是,没有图片大小的限制。
我最近做得一个项目用的是第二种方法实现的,贴下代码吧:
1、前台代码【点击保存图片按钮】:
var width = drawObject.getCanvas().width; var height = drawObject.getCanvas().height; var figures = drawObject.getCurrentFigures(); $.ajax( { url: "./WareHousePrintHandler.ashx?action=drawpng&width=" + width + "&height=" + height, type: "post", data: "datas=" + JSON.stringify(figures), success: function (fileName) { $('#frameImage').attr('src', "./WareHousePrintHandler.ashx?action=getpng&fileName=" + fileName); }, error: function (err) { alert("Print failed."); } });
将前台需要画图的信息通过ajax传到后台的一个handler中,handler负责接收参数,并且将画好的图片保存至某个IIS的共享路径下,图片名称返回到前台,前台再用一个大小为0的iframe去通过重新加载页面,通过此图片名称去后台取图片流并弹出保存提示框。
2、iframe的代码
<iframe width="0" height="0" id="frameImage" name="frameImage" frameborder="0" scrolling="no"></iframe>
3、后台代码
if (action.ToString() == "drawpng") { if (context.Request["datas"] == null) { return; } double w = double.Parse(context.Request["width"].ToString()); double h = double.Parse(context.Request["height"].ToString()); string allFigures = context.Server.UrlDecode(context.Request["datas"].ToString()); List<DrawModel> figureList = AspSoft.WareHouse.Util.JsonHelper.JsonDeserialize<List<DrawModel>>(allFigures); WareHouseDrawing drawing = new WareHouseDrawing(); string fileName = drawing.GetImageUrl((int)w, (int)h, figureList, filePath); context.Response.Write(fileName); //ms.WriteTo(Response.OutputStream); context.Response.End(); } else if (action.ToString() == "getpng") { string fileName = context.Request["fileName"].ToString(); string fullFileName = filePath + "/" + fileName; context.Response.AppendHeader("Content-Disposition", string.Format("Attachment; FileName={0}.png;", HttpUtility.UrlEncode(DateTime.Now.ToString("yyyyMMdd_HHmmss"), System.Text.Encoding.UTF8))); context.Response.WriteFile(fullFileName); context.Response.End(); }
GetImageUrl是具体画的方法,将画好的图片保存到一个共享路径下,必须是IIS能访问的共享路径,不能是本地的路径,第二次请求是获得png,实际是获得png的路径,iframe加载图片的路径后会自动获得图片的流信息,这是浏览器自动处理的,这里关键的是要加上Attachment,要以附件的形式发送。
此方法必须发送两次请求到后来才能完成,因为如果第一次就通过iframe的src方式请求图片,由于只能通过querystring的方式请求,不能传大的数据,因为需要画图的数据量也是比较大,必须先通过ajax请求。PDF的道理同上,就是将bitmap的信息放到PDF中就可以了。