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文件转换为图片,这里也贴出一些常见的文章链接:

  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;
        }

  速度还可以,没有水印,不需要存储到服务器,基本都是流操作,完美!!!