应用场景
我们在一个求职简历打印的项目功能里,需要根据一定的查询条件,得到结果并批量导出指定格式的文件。导出的格式可能有多种,比如WORD格式、EXCEL格式、PDF格式等,实现方式是通过设置对应的模板进行输出,实际情况是,简历的内容是灵活设置的,没有固定的格式,模板数量是不固定的。
通过动态页面技术,可以实现简历配置后的网页内容输出,但制作对应的各种模板会遇到开发效率和服务跟进的问题。为了保障原样输出,折中而简单的方案就是将动态输出的页面转化为图片格式。
实现代码
创建一个 UrlToImage 类,创建实例的时候传递指定的 URL, 并调用 SaveToImageFile(string outputFilename)方法,该方法传递要输出的文件名参数即可即可。
调用示例代码如下:
string url = "https://" + Request.Url.Host + "/printResume.aspx"; UrlToImage uti = new UrlToImage(url); bool irv = uti.SaveToImageFile(Request.PhysicalApplicationPath + "\\test.jpg"); if(bool==false){ Response.Write("save failed."); Response.End(); }
类及实现代码如下:
public class UrlToImage { private Bitmap m_Bitmap; private string m_Url; private string m_FileName = string.Empty; int initheight = 0; public UrlToImage(string url) { // Without file m_Url = url; } public UrlToImage(string url, string fileName) { // With file m_Url = url; m_FileName = fileName; } public Bitmap Generate() { // Thread var m_thread = new Thread(_Generate); m_thread.SetApartmentState(ApartmentState.STA); m_thread.Start(); m_thread.Join(); return m_Bitmap; } public bool SaveToImageFile(string filename) { Bitmap bt=Generate(); if (bt == null) { return false; } bt.Save(filename); return File.Exists(filename); } private void _Generate() { var browser = new WebBrowser { ScrollBarsEnabled = false }; browser.ScriptErrorsSuppressed = true; initheight = 0; browser.Navigate(m_Url); browser.DocumentCompleted += WebBrowser_DocumentCompleted; while (browser.ReadyState != WebBrowserReadyState.Complete) { Application.DoEvents(); } browser.Dispose(); } private void WebBrowser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e) { // Capture var browser = (WebBrowser)sender; browser.ClientSize = new Size(browser.Document.Body.ScrollRectangle.Width, browser.Document.Body.ScrollRectangle.Bottom); browser.ScrollBarsEnabled = false; m_Bitmap = new Bitmap(browser.Document.Body.ScrollRectangle.Width, browser.Document.Body.ScrollRectangle.Bottom); browser.BringToFront(); browser.DrawToBitmap(m_Bitmap, browser.Bounds); // Save as file? if (m_FileName.Length > 0) { // Save m_Bitmap.SaveJPG100(m_FileName); } if (initheight == browser.Document.Body.ScrollRectangle.Bottom) { browser.DocumentCompleted -= new WebBrowserDocumentCompletedEventHandler(WebBrowser_DocumentCompleted); } initheight = browser.Document.Body.ScrollRectangle.Bottom; } }
生成压缩包
对于批量生成的图片文件,我们可以生成压缩包为客户提供下载功能,压缩功能引用的是ICSharpCode.SharpZipLib.dll,创建 ZipCompress 类的实例,ZipDirectory(zippath, zipfile, password) 方法,需要提供的参数包括,压缩的目录、生成的压缩文件名,压缩包的打开密码。
示例代码如下:
string zippath = Request.PhysicalApplicationPath + "\\des\\" ; if (!Directory.Exists(zippath)) { Directory.CreateDirectory(zippath); } string zipfile = Request.PhysicalApplicationPath + "\\des\\test.zip"; ZipCompress allgzip = new ZipCompress(); System.IO.DirectoryInfo alldi = new System.IO.DirectoryInfo(zippath); string password = "123456"; allgzip.ZipDirectory(zippath, zipfile, password); //以下是生成完压缩包后,清除目录及文件 string[] allfs = Directory.GetFiles(zippath); for (int i = 0; i < allfs.Length; i++) { File.Delete(allfs[i]); } Directory.Delete(zippath);
类及实现代码如下:
public class ZipCompress { public byte[] Compress(byte[] inputBytes) { using (MemoryStream outStream = new MemoryStream()) { using (GZipStream zipStream = new GZipStream(outStream, CompressionMode.Compress, true)) { zipStream.Write(inputBytes, 0, inputBytes.Length); zipStream.Close(); //很重要,必须关闭,否则无法正确解压 return outStream.ToArray(); } } } public byte[] Decompress(byte[] inputBytes) { using (MemoryStream inputStream = new MemoryStream(inputBytes)) { using (MemoryStream outStream = new MemoryStream()) { using (GZipStream zipStream = new GZipStream(inputStream, CompressionMode.Decompress)) { zipStream.CopyTo(outStream); zipStream.Close(); return outStream.ToArray(); } } } } public string Compress(string input) { byte[] inputBytes = Encoding.Default.GetBytes(input); byte[] result = Compress(inputBytes); return Convert.ToBase64String(result); } public string Decompress(string input) { byte[] inputBytes = Convert.FromBase64String(input); byte[] depressBytes = Decompress(inputBytes); return Encoding.Default.GetString(depressBytes); } public void Compress(DirectoryInfo dir) { foreach (FileInfo fileToCompress in dir.GetFiles()) { Compress(fileToCompress); } } public void Decompress(DirectoryInfo dir) { foreach (FileInfo fileToCompress in dir.GetFiles()) { Decompress(fileToCompress); } } public void Compress(FileInfo fileToCompress) { using (FileStream originalFileStream = fileToCompress.OpenRead()) { if ((File.GetAttributes(fileToCompress.FullName) & FileAttributes.Hidden) != FileAttributes.Hidden & fileToCompress.Extension != ".gz") { using (FileStream compressedFileStream = File.Create(fileToCompress.FullName + ".gz")) { using (GZipStream compressionStream = new GZipStream(compressedFileStream, CompressionMode.Compress)) { originalFileStream.CopyTo(compressionStream); } } } } } public void Decompress(FileInfo fileToDecompress,string desfilename="") { using (FileStream originalFileStream = fileToDecompress.OpenRead()) { string currentFileName = fileToDecompress.FullName; string newFileName = currentFileName.Remove(currentFileName.Length - fileToDecompress.Extension.Length); if (desfilename != "") { newFileName = desfilename; } using (FileStream decompressedFileStream = File.Create(newFileName)) { using (GZipStream decompressionStream = new GZipStream(originalFileStream, CompressionMode.Decompress)) { decompressionStream.CopyTo(decompressedFileStream); } } } } public void ZipDirectory(string folderToZip, string zipedFileName,string password) { ZipDirectory(folderToZip, zipedFileName,(password==""?string.Empty:password), true, string.Empty, string.Empty, true); } public void ZipDirectory(string folderToZip, string zipedFileName, string password, bool isRecurse, string fileRegexFilter, string directoryRegexFilter, bool isCreateEmptyDirectories) { FastZip fastZip = new FastZip(); fastZip.CreateEmptyDirectories = isCreateEmptyDirectories; fastZip.Password = password; fastZip.CreateZip(zipedFileName, folderToZip, isRecurse, fileRegexFilter, directoryRegexFilter); } public void UnZipDirectory(string zipedFileName, string targetDirectory, string password,string fileFilter=null) { FastZip fastZip = new FastZip(); fastZip.Password = password; fastZip.ExtractZip(zipedFileName, targetDirectory,fileFilter); } public void UnZip(string zipFilePath, string unZipDir) { if (zipFilePath == string.Empty) { throw new Exception("压缩文件不能为空!"); } if (!File.Exists(zipFilePath)) { throw new FileNotFoundException("压缩文件不存在!"); } //解压文件夹为空时默认与压缩文件同一级目录下,跟压缩文件同名的文件夹 if (unZipDir == string.Empty) unZipDir = zipFilePath.Replace(Path.GetFileName(zipFilePath), Path.GetFileNameWithoutExtension(zipFilePath)); if (!unZipDir.EndsWith("/")) unZipDir += "/"; if (!Directory.Exists(unZipDir)) Directory.CreateDirectory(unZipDir); using (var s = new ZipInputStream(File.OpenRead(zipFilePath))) { ZipEntry theEntry; while ((theEntry = s.GetNextEntry()) != null) { string directoryName = Path.GetDirectoryName(theEntry.Name); string fileName = Path.GetFileName(theEntry.Name); if (!string.IsNullOrEmpty(directoryName)) { Directory.CreateDirectory(unZipDir + directoryName); } if (directoryName != null && !directoryName.EndsWith("/")) { } if (fileName != String.Empty) { using (FileStream streamWriter = File.Create(unZipDir + theEntry.Name)) { int size; byte[] data = new byte[2048]; while (true) { size = s.Read(data, 0, data.Length); if (size > 0) { streamWriter.Write(data, 0, size); } else { break; } } } } } } } }
小结
对于生成的图片文件,我们还可以结合其它的API应用,来判断图片是否有被PS的情况,来提升和扩展应用程序的功能。另外,对于被访问的动态页面,建议使用访问控制,只有正常登录或提供访问令牌的用户才可以生成结果图片,以保证数据的安全性。
以上代码仅供参考,欢迎大家指正,再次感谢您的阅读!