C# Asp.Net 实现PPT/PDF转成图片(不依赖office)
最近公司有个需求,将PPT课件转成图片列表,然后在前端展示成轮播图,于是一开始通过Microsoft.Office.Interop.PowerPoint包实现了这个需求具体代码如下:
/// <summary> /// 将PPT转换为图片 /// </summary> /// <param name="pptPath"></param> /// <param name="imgPath"></param> public static List<string> UploadPptImage(HttpRequestBase request) { var imgUrls = new List<string>(); var file = request.Files["ppt_file"]; if (string.IsNullOrEmpty(file.FileName)) { return new List<string>(); } var path = AppDomain.CurrentDomain.BaseDirectory + "imagesfromppt/" + file.FileName; var savepath = AppDomain.CurrentDomain.BaseDirectory + "ppt/"; if (!System.IO.Directory.Exists(path)) { System.IO.Directory.CreateDirectory(path); } if (!System.IO.Directory.Exists(savepath)) { System.IO.Directory.CreateDirectory(savepath); } var filepath = Path.Combine(savepath, file.FileName); file.SaveAs(filepath); Microsoft.Office.Interop.PowerPoint.Application application = null; Presentation persentation = null; var imagPathList = new List<string>(); try { application = new Microsoft.Office.Interop.PowerPoint.Application(); persentation = application.Presentations.Open(filepath); //persentation.Slides[1].Export(path + "\\page" + 1 + ".jpg", "JPG", 800, 600); for (var k = 1; k <= persentation.Slides.Count; k++) { var imgPath = path + "\\page" + k + ".jpg"; imagPathList.Add(imgPath); persentation.Slides[k].Export(imgPath, "JPG", 800, 600); } imagPathList.ForEach(p => { using (MemoryStream ms = new MemoryStream()) { using (var fs = new FileStream(p, FileMode.Open)) { byte[] buffer = new byte[1024]; int result = 0; while ((result = fs.Read(buffer, 0, buffer.Length)) > 0) { ms.Write(buffer, 0, result); } } ms.Seek(0, SeekOrigin.Begin); var fileData = ms.ToArray(); string url = ;//此处为云存储,不重要,上传后获得url imgUrls.Add(url); } }); } catch (Exception ex) { //记录异常 } finally { if (persentation != null) { persentation.Close(); persentation = null; } if (application != null) { application.Quit(); application = null; } GC.Collect(); GC.WaitForPendingFinalizers(); imagPathList.ForEach(p => { if (File.Exists(p)) { File.Delete(p); } }); if (File.Exists(filepath)) { File.Delete(filepath); } if (Directory.Exists(path)) { Directory.Delete(path); } } return imgUrls; }
由于我们图片都是云存储,所以存到文件系统后又删掉了,貌似没有直接存成流的方式,不重要
发布到线上后发现服务器没有安装office,因此无法正常使用,但又不能在服务器上安装,因此踩坑一天左右,找到了一些方法
一、使用Spire.Presentation
使用Spire.Presentation可以轻松的将ppt转换为image,代码如下
/// <summary> /// 将PPT转换为图片 /// </summary> /// <param name="pptPath"></param> /// <param name="imgPath"></param> public static List<string> UploadPptImage(HttpRequestBase request) { var imgUrls = new List<string>(); var file = request.Files["ppt_file"]; if (string.IsNullOrEmpty(file.FileName)) { return new List<string>(); } Presentation ppt = new Presentation(); ppt.LoadFromStream(file.InputStream, FileFormat.Auto); var slidescount = ppt.Slides.Count; try { if (slidescount > 0) { for (int i = 0; i < slidescount; i++) { ppt.Slides[i].SaveAsImage();//把ppt转换成emf格式图片 Image image = ppt.Slides[i].SaveAsImage(); using (var ms = new MemoryStream()) { image.Save(ms, ImageFormat.Png); ms.Seek(0, SeekOrigin.Begin); var fileData = ms.ToArray(); string url = ;//云存储,返回url imgUrls.Add(url); } } } } catch (Exception ex) { //记录异常 } return imgUrls; }
可以看到,代码简单,并且不需要存储到服务器上,但是Spire.Presentation是商用的,免费使用有10页的限制,并且会有水印
于是继续寻找方法
二、最后解决方案是,先将PPT转换为pdf(这里使用Aspose.Slides),然后将pdf文件转换为图片,这里也贴出一些常见的文章链接:
文章中使用的方法我没有全试,总结一下优缺点:
1、O2S.Components.PDFRender4NET.dll
该dll可用,虽然免费版有水印但是网上还是能找到破解的,这里不贴了,但ppt中使用了png格式的图片,会丢失,并且使用图片清晰度调大会很卡
2、Acrobat.dll
该dll在asp .net环境下,直接无法添加引用,不知道是不是我自己的问题
3. PDFLibNet.dll
该dll只支持32位的,我尝试过,没有成功,报错了,可能是我自己的问题
4. Ghostscript
网上很多人都采用这个方法(貌似功能很强大),博主觉得代码复杂,没有深入研究。不适用
上面是我试过的方法,可能是我自己的原因,最后不尽如人意,于是我继续找,看到了一篇文章:
文章使用PdfiumViewer包来实现,参照代码写了一下,原代码是winform的。
最后引用了nuget包PdfiumViewer,但是报错:找不到一个叫PDFium的dll文件,于是我找到了github,发现有人改源代码实现了,但是我比较菜,自己改不动,于是放弃
后面又尝试了一遍,发现nuget中这个包的作者有上传了另外两个包,看起来是用来处理这个问题的,于是我尝试引用了其中一个,还不行,引用另一个,可以了:
包名是PdfiumViewer.Native.x86.v8-xfa和PdfiumViewer.Native.x86_64.v8-xfa
最后贴出代码:
/// <summary> /// 将PPT转换为图片 /// </summary> /// <param name="pptPath"></param> /// <param name="imgPath"></param> public static List<string> UploadPptImage(HttpRequestBase request) { var imgUrls = new List<string>(); var file = request.Files["ppt_file"]; if (string.IsNullOrEmpty(file.FileName)) { return new List<string>(); } Presentation ppt = new Presentation(file.InputStream); using (var mspdf = new MemoryStream()) { var pageCount = ppt.Slides.Count; ppt.Save(mspdf, Aspose.Slides.Export.SaveFormat.Pdf); using (var pdf = PdfDocument.Load(mspdf)) { try { var pagesizes = pdf.PageSizes; for (int i = 0; i < pdf.PageCount; i++) { Size size = new Size(); size.Height = (int)pagesizes[(i)].Height; size.Width = (int)pagesizes[(i)].Width; using (var image = pdf.Render(i, size.Width, size.Height, PdfRenderFlags.Annotations)) { using (var ms = new MemoryStream()) { image.Save(ms, ImageFormat.Png); ms.Seek(0, SeekOrigin.Begin); var fileData = ms.ToArray(); string url = ;//云存储,返回url imgUrls.Add(url); } } } } catch (Exception ex) { //异常记录 } } } return imgUrls; }
速度还可以,没有水印,不需要存储到服务器,基本都是流操作,完美!!!