C# 将 Word 转化分享为电子期刊

 

目录

需求

方案分析

相关库引入

关键代码

Word 转 Pdf

Pdf 转批量 Jpeg

Jpeg 转为电子书

实现效果演示

小结


需求

曾经的一个项目,要求实现制作电子期刊定期发送给企业进行阅读,基本的需求如下:

1、由编辑人员使用 Microsoft Word 编辑期刊内容,上传到系统,生成PDF文件。

2、将生成的PDF文件转化为JPEG文件。

3、将JPEG文件制作目录结构,并生成电子书模式。

方案分析

分析了一下需求,制作了初步的实现方案,主要有以下几点分析:

1、Microsoft Word 仍然是目前比较常用和广泛使用的应用程序,适用于各类人群,他们只需要编写好自己的文稿即可(包括文字、图片、排版),所以可以作为实现电子书的基础。

2、较高版本的 Word 如2016、2019及以上,可以提供另存为PDF的能力,利用API可以将DOCX另存为PDF文件,为进一步生成JPEG图片提供基础。

3、利用改造过的 turn.js 实现电子书及翻页效果。 

相关库引入

实现功能要引入相关库,包括 PdfiumViewer.dll 和 turn.js 相关包,完整下载链接请访问:

https://download.csdn.net/download/michaelline/88647689

另外,在服务器端您需要安装 Microsoft Word 2016 或以上版本。

关键代码

Word 转 Pdf

在操作界面,上传WORD文件,通过API将其另存为PDF文件。

示例代码如下:

        public string WordToPdf(string _filename)
		{
            string resultReport=""; //调试信息
            Object Nothing =System.Reflection.Missing.Value;
//在上传目录下一定要创建一个tempbfile目录用于存储临时文件
			string _file="",_path=Path.GetDirectoryName(_filename)+"\\tempbfile\\",_ext="";

			_file=Path.GetFileNameWithoutExtension(_filename);
			_ext=Path.GetExtension(_filename);
			string _validfilename=Guid.NewGuid().ToString()+_ext;
			string _lastfile=_path+_validfilename;
            string _pdfFile = _path + Guid.NewGuid().ToString() + ".pdf";

            File.Copy(_filename,_lastfile,true);
  	    if(!File.Exists(_lastfile))
		{
                resultReport += "create " + _lastfile + " fail.<br>";
				return "";
		}

            //取得Word文件保存路径
            object filename=_lastfile;
			//创建一个名为WordApp的组件对象
			Word.Application WordApp=new Word.Application();
			//创建一个名为WordDoc的文档对象
			WordApp.DisplayAlerts=Word.WdAlertLevel.wdAlertsNone;
			Word.Document WordDoc=WordApp.Documents.Open(ref filename,ref Nothing,ref Nothing,ref Nothing,ref Nothing,ref Nothing,ref Nothing,ref Nothing,ref Nothing,ref Nothing,ref Nothing,ref Nothing,ref Nothing,ref Nothing,ref Nothing,ref Nothing);
            WordDoc.SpellingChecked = false;
            WordDoc.ShowSpellingErrors = false;
            string    pdfFilename = "";
//导出到pdf文件
                WordDoc.ExportAsFixedFormat(_pdfFile, Microsoft.Office.Interop.Word.WdExportFormat.wdExportFormatPDF,false,Word.WdExportOptimizeFor.wdExportOptimizeForPrint,
                    wdExportRange,pagefrom,pageto,Word.WdExportItem.wdExportDocumentContent,false,true,Word.WdExportCreateBookmarks.wdExportCreateNoBookmarks,
                    true,true,false, ref Nothing);
                if (File.Exists(_pdfFile))
                {
                    pdfFilename = _pdfFile;
                }

            WordDoc.Close(ref Nothing, ref Nothing, ref Nothing);
			//关闭WordApp组件对象
			WordApp.Quit(ref Nothing, ref Nothing, ref Nothing);
  	    return pdfFilename;



        }

Pdf 转批量 Jpeg

生成pdf文件后,我们需要将其转化到指定目录下,批量生成JPEG图片,以备客户端JS进行调用。

方法介绍:

public void PdfToImage(string pdfInputPath, string imageOutputPath,string imageName)

//参数1:PDF文件路径,参数2:输出图片的路径,参数3:图片文件名的前缀,比如输入Img,则会输出Img_001.jpg、Img_002.jpg。。。以此类推。
 

示例代码如下:

//参数1:PDF文件路径,参数2:输出图片的路径,参数3:图片文件名的前缀,比如输入Img,则会输出Img_001.jpg、Img_002.jpg以此类推
public void PdfToImage(string pdfInputPath, string imageOutputPath,string imageName)
        {
            //            PdfRenderFlags.Annotations 改成 PdfRenderFlags.CorrectFromDpi DPI值设置成600 即可高清图像
            if (Directory.Exists(imageOutputPath) == false)
            {
                Directory.CreateDirectory(imageOutputPath);
            }

            var pdf = PdfiumViewer.PdfDocument.Load(pdfInputPath);

            var pdfpage = pdf.PageCount;
            var pagesizes = pdf.PageSizes;
            if (pdfpage == 0)
            {
                pdf.Dispose();
                return;
            }
            var document = PdfiumViewer.PdfDocument.Load(pdfInputPath);
            for (int i = 1; i <= pdfpage; i++)
            {
                Size size = new Size();
                size.Height = (int)pagesizes[(i - 1)].Height;
                size.Width = (int)pagesizes[(i - 1)].Width;
                //可以把".jpg"写成其他形式
                string tmpfile = imageOutputPath + imageName + "_" + i.ToString().PadLeft(3, '0') + ".jpg";
                var stream = new FileStream(tmpfile, FileMode.Create);
                var image = document.Render(i - 1, size.Width, size.Height, 120, 120, PdfRenderFlags.CorrectFromDpi);
                image.Save(stream, System.Drawing.Imaging.ImageFormat.Jpeg);
                stream.Close();

            }
            document.Dispose();
            pdf.Dispose();
        }

Jpeg 转为电子书

根据 turn.js 的格式要求,我们在服务端 Page_Load 事件里生成一个 ViewState,直接输出到客户端,ViewState["result"] 是我们要输出的变量,我们对指定的 jpgTmpPath 变量目录进行遍历,符合jpeg或jpg扩展名的文件则进行记录。

服务端示例代码如下:

protected void Page_Load(object sender, EventArgs e)
    {
        ViewState["result"] = "";  //关键的viewsate,用于存储JPEG地址数组格式
        string _cid=Request.QueryString["cid"];
        if ( _cid!= null)
        {
            string result = "";
            string jpgTmpPath = Request.PhysicalApplicationPath + "\\ebook\\" + _cid + "\\";
            if (Directory.Exists(jpgTmpPath))
            {
                string[] allfs = System.IO.Directory.GetFiles(jpgTmpPath);
                for (int i = 0; i < allfs.Length; i++)
                {
                    string jpgfile = allfs[i].ToLower();
                    string filename = System.IO.Path.GetFileName(jpgfile);
                    if (jpgfile.IndexOf(".jpg") == -1 && jpgfile.IndexOf(".jpeg") == -1)
                    {
                        continue;
                    }
                    result += "\"../../ebook/" + _cid + "/" + filename + "\",\r\n";
                }
                ViewState["result"] = result;
            }
        }
        if (ViewState["result"].ToString() == "")
        {
            Response.Write("没有预览资源");
            Response.End();
        }
}

中间UI代码引用示例:


<head runat="server">
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"/>
    <meta http-equiv="pragma" content="no-cache" />
    <meta http-equiv="Cache-Control" content="no-cache,no-store,must-revalidate"/>
    <meta http-equiv="Expires" content="0" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"/>
    <meta name="format-detection" content="telephone=no">
    <meta name="apple-mobile-web-app-capable" content="yes"/>
    <title>电子期刊预览</title>
    
    <link rel="stylesheet" type="text/css" href="css/basic.css"/>
    <script type="text/javascript" src="js/jquery.js"></script>
    <script type="text/javascript" src="js/modernizr.2.5.3.min.js"></script>
</head>


<div class="shade">
    <div class="sk-fading-circle">
        <div class="sk-circle1 sk-circle"></div>
        <div class="sk-circle2 sk-circle"></div>
        <div class="sk-circle3 sk-circle"></div>
        <div class="sk-circle4 sk-circle"></div>
        <div class="sk-circle5 sk-circle"></div>
        <div class="sk-circle6 sk-circle"></div>
        <div class="sk-circle7 sk-circle"></div>
        <div class="sk-circle8 sk-circle"></div>
        <div class="sk-circle9 sk-circle"></div>
        <div class="sk-circle10 sk-circle"></div>
        <div class="sk-circle11 sk-circle"></div>
        <div class="sk-circle12 sk-circle"></div>
    </div>
    <div class="number"></div>
</div>

<div class="flipbook-viewport" style="display:none;">
    <div class="previousPage"></div>
    <div class="nextPage"></div>
    <div class="return"></div>
    <img class="btnImg" src="./image/btn.gif" style="display: none"/>
    <div class="container">
        <div class="flipbook">
        </div>

        <div class="pagenumber">
        </div>
    </div>
</div> 

客户端脚本:

在客户端我们接收来自 ViewState["result"] 的变量值,实现电子书的效果:

<script type="text/javascript">
    var loading_img_url = [
    <%=ViewState["result"]%>
    ];
</script>
<script type="text/javascript" src="js/main.js"></script>
<script>
    //自定义弹出层
    (function ($) {
        //ios confirm box
        jQuery.fn.confirm = function (title, option, okCall, cancelCall) {
            var defaults = {
                title: null, //what text
                cancelText: '取消', //the cancel btn text
                okText: '确定' //the ok btn text
            };

            if (undefined === option) {
                option = {};
            }
            if ('function' != typeof okCall) {
                okCall = $.noop;
            }
            if ('function' != typeof cancelCall) {
                cancelCall = $.noop;
            }

            var o = $.extend(defaults, option, { title: title, okCall: okCall, cancelCall: cancelCall });

            var $dom = $(this);

            var dom = $('<div class="g-plugin-confirm">');
            var dom1 = $('<div>').appendTo(dom);
            var dom_content = $('<div>').html(o.title).appendTo(dom1);
            var dom_btn = $('<div>').appendTo(dom1);
            var btn_cancel = $('<a href="#"></a>').html(o.cancelText).appendTo(dom_btn);
            var btn_ok = $('<a href="#"></a>').html(o.okText).appendTo(dom_btn);
            btn_cancel.on('click', function (e) {
                o.cancelCall();
                dom.remove();
                e.preventDefault();
            });
            btn_ok.on('click', function (e) {
                o.okCall();
                dom.remove();
                e.preventDefault();
            });

            dom.appendTo($('body'));
            return $dom;
        };
    })(jQuery);

    if ($(window).width() > 1024 && $(window).height() > 700) {
        //上一页
        $(".previousPage").bind("click", function () {
            var pageCount = $(".flipbook").turn("pages"); //总页数
            var currentPage = $(".flipbook").turn("page"); //当前页
            if (currentPage > 2) {
                $(".flipbook").turn('page', currentPage - 2);
            } else if (currentPage == 2) {
                $(".flipbook").turn('page', currentPage - 1);
            }
        });
        // 下一页
        $(".nextPage").bind("click", function () {
            var pageCount = $(".flipbook").turn("pages"); //总页数
            var currentPage = $(".flipbook").turn("page"); //当前页
            if (currentPage < pageCount - 1) {
                $(".flipbook").turn('page', currentPage + 2);
            } else if (currentPage == pageCount - 1) {
                $(".flipbook").turn('page', currentPage + 1);
            }
        });
    } else {
        //上一页
        $(".previousPage").bind("click", function () {
            var pageCount = $(".flipbook").turn("pages"); //总页数
            var currentPage = $(".flipbook").turn("page"); //当前页
            if (currentPage >= 2) {
                $(".flipbook").turn('page', currentPage - 1);
            } else {
            }
        });
        // 下一页
        $(".nextPage").bind("click", function () {
            var pageCount = $(".flipbook").turn("pages"); //总页数
            var currentPage = $(".flipbook").turn("page"); //当前页
            if (currentPage <= pageCount) {
                $(".flipbook").turn('page', currentPage + 1);
            } else {
            }
        });
    }
    //返回到目录页
   

    $(".return").bind("click", function () {
        $(document).confirm('您确定要返回首页吗?', {}, function () {
            $(".flipbook").turn('page', 1); //跳转页数
        }, function () {
        });
    });
    function gotopage(pageindex) {
        $(".flipbook").turn('page',pageindex);
    }



</script>

实现效果演示

小结

以上提供的代码仅供参考,turn.js 我花了一些时间进行了改造,我们也可以根据自己的需要对样式、控制进行改造。其它的一些细节我们可以进一步调整,如图片生成质量、权限控制等。

另外,还可以实现下载、评价、点赞、收藏等其它功能,这里就不再一一介绍。

以上就是自己的一些分享,时间仓促,不妥之处还请大家批评指正!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/259310.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Lucene

目录 1. Lucene概述 1.1 什么是Lucene 1.2 Lucene的原理 2. Lucene的使用 2.1 准备 2.2 生成索引 2.3 全文检索 2.4 多Field检索 2.5 中文分词器 2.6 停用词 2.7 是否索引,是否储存 1. Lucene概述 1.1 什么是Lucene Lucene是一个全文搜索框架&#xff0c;而不是应用…

标准库中的string类(上)——“C++”

各位CSDN的uu们好呀&#xff0c;好久没有更新小雅兰的C专栏的知识啦&#xff0c;接下来一段时间&#xff0c;小雅兰就又会开始更新C这方面的知识点啦&#xff0c;以及期末复习的一些知识点&#xff0c;下面&#xff0c;让我们进入西嘎嘎string的世界吧&#xff01;&#xff01;…

智能优化算法应用:基于混沌博弈算法3D无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于混沌博弈算法3D无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于混沌博弈算法3D无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.混沌博弈算法4.实验参数设定5.算法结果6.…

HamronyOS 自动化测试框架使用指南

概述 为支撑 HarmonyOS 操作系统的自动化测试活动开展&#xff0c;我们提供了支持 JS/TS 语言的单元及 UI 测试框架&#xff0c;支持开发者针对应用接口进行单元测试&#xff0c;并且可基于 UI 操作进行 UI 自动化脚本的编写。 本指南重点介绍自动化测试框架的主要功能&#x…

跟着我学Python进阶篇:01.试用Python完成一些简单问题

往期文章 跟着我学Python基础篇&#xff1a;01.初露端倪 跟着我学Python基础篇&#xff1a;02.数字与字符串编程 跟着我学Python基础篇&#xff1a;03.选择结构 跟着我学Python基础篇&#xff1a;04.循环 跟着我学Python基础篇&#xff1a;05.函数 跟着我学Python基础篇&#…

c语言力扣题目:消失的数字(有关时间复杂度O(N²)O(N))以及对异或操作符的更深入的理解(如何用人脑的十进制去考量二进制)

目录 Way One :暴力求解,时间复杂度为 O(N) 代码1 Way Two : 时间复杂度限制到 O(N) 代码及其详解 如题 Way One :暴力求解,时间复杂度为 O(N) 大体思路:比如这里我们需要处理的整型数组是"3,0,1",我们可以用冒泡排序或者 qsort函数将他从大到小进行排序成"…

纳米流体传热CFD模拟仿真

纳米流体传热CFD模拟仿真 一、引言 纳米流体传热是当前研究热点之一,由于其独特的传热特性和应用前景,受到了广泛关注。计算流体动力学(CFD)模拟作为一种有效的研究手段,在纳米流体传热领域发挥着重要作用。本文将介绍纳米流体传热CFD模拟的基本原理、方法、应用及未来发…

100GPTS计划-AI编码CodeWizard

地址 https://chat.openai.com/g/g-vX7yfHNcC-code-wizard https://poe.com/CodeWizardGPT 测试 sql 优化 select a.id,a.name,count(b.id),count(c.id) from product a LEFT JOIN secretkey b on a.id b.productId group by a.id LEFT JOIN secretkey c on a.id c.pr…

SLAM算法与工程实践——RTKLIB编译

SLAM算法与工程实践系列文章 下面是SLAM算法与工程实践系列文章的总链接&#xff0c;本人发表这个系列的文章链接均收录于此 SLAM算法与工程实践系列文章链接 下面是专栏地址&#xff1a; SLAM算法与工程实践系列专栏 文章目录 SLAM算法与工程实践系列文章SLAM算法与工程实践…

node.js mongoose middleware

目录 官方文档 简介 定义模型 注册中间件 创建doc实例&#xff0c;并进行增删改查 方法名和注册的中间件名相匹配 执行结果 分析 错误处理中间件 手动抛出错误 注意点 官方文档 Mongoose v8.0.3: Middleware 简介 在mongoose中&#xff0c;中间件是一种允许在执…

Linux静态ip

Linux静态ip Ⅰ、修改静态ip Ⅰ、修改静态ip 修改静态ip必须是root用户 su root //切换root用户 ip a //查看修改前的动态ipvi /etc/sysconfig/network-scripts/ifcfg-ens33 //打开网卡配置文件&#xff0c;修改一处&#xff0c;新增四处 BOOTPROTO&quo…

NumPy教程(一)—— ndarray:多维数组对象

前言 该numpy学习笔记参考了菜鸟教程网、b站up主 孙兴华zz 的《孙兴华中文讲python数据分析三部曲》以及《北理-python数据分析与展示》&#xff0c;课本推荐使用《利用python进行数据分析》 Numpy简介&#xff1a; NumPy(Numerical Python) 是 Python 语言的一个扩展程序库&a…

RHCE8 资料整理(十一)

RHCE8 资料整理 第 32 章 控制语句32.1 判断语句 when32.1.1 when 判断中>、<、!和的使用32.1.2 when 判断中 in的用法32.1.3 when 判断中 is的用法 32.2 判断语句 block-rescue32.3 循环语句 第 32 章 控制语句 一个play中可以包含多个task&#xff0c;如果不想所有的t…

电子学会C/C++编程等级考试2022年06月(六级)真题解析

C/C++等级考试(1~8级)全部真题・点这里 第1题:小白鼠再排队2 N只小白鼠(1 < N < 100),每只鼠头上戴着一顶有颜色的帽子。现在称出每只白鼠的重量,要求按照白鼠重量从小到大的顺序输出它们头上帽子的颜色。帽子的颜色用 “red”,“blue”等字符串来表示。不同的小白…

董宇辉“回归”成为东方甄选高级合伙人,尘埃落地后是谁赢了?

董宇辉“回归”成为东方甄选高级合伙人&#xff0c;尘埃落地后是谁赢了&#xff1f; 董宇辉的“小作文事件”“CEO摔手机事件”迎来大结局了&#xff01; 就在12月18日&#xff0c;董宇辉被任命为新东方教育科技集团董事长文化助理&#xff0c;兼任新东方文旅集团副总裁。有朋…

Excel如何将行的值转换为列值?

问题:Excel如何将行的值转换为列值?(如图左表变成右表) 1.用 SUMIFS(求和区域, 条件区域1, 条件1, [条件区域2, 条件2], ...)函数 比如:=SUMIFS($C$2:$C$8,$A$2:$A$8,H3,$B$2:$B$8,"快车") 2.直接用简单的透视表 (1)随机点击目标目标表格任何位置,点击插入…

Gin之GORM事务(转账操作)

禁用默认事务的操作 为了确保数据一致性,GORM 会在事务里执行写入操作(创建、更新、删除)。如果没有这方面的要求,您可以在初始化时禁用它,这将获得大约 30%+ 性能提升。 // 全局禁用 db, err := gorm.Open(sqlite.Open("gorm.db"), &gorm.Config{SkipDef…

Just Laws -- 中华人民共和国法律文库,简单便捷的打开方式

链接&#xff1a;JustLaws | Home 一个简洁便捷的中华人民共和国法律文库&#xff0c;而且收录比较完善&#xff0c;都是平常网民可能用到比较多的法律知识&#xff0c;目前包括宪法及宪法相关法、民商法、行政法、经济法、社会法、刑法和程序法等等 页面以文档的风格展示每一…

Java设计模式:工厂模式(简单工厂模式、工厂方法模式、抽象工厂模式)

❤ 作者主页&#xff1a;欢迎来到我的技术博客&#x1f60e; ❀ 个人介绍&#xff1a;大家好&#xff0c;本人热衷于Java后端开发&#xff0c;欢迎来交流学习哦&#xff01;(&#xffe3;▽&#xffe3;)~* &#x1f34a; 如果文章对您有帮助&#xff0c;记得关注、点赞、收藏、…

正向代理和反向代理的区别与联系

一、代理 代理就相当于中间商,本来A和B是可以直接连接的,但是此时添加了一个C在中间,A跟B不直接连接,而是通过C作为中介进行连接。最常见的例子就是二手东,其实很多我们租房子时签约的人不是房子的真正房东,而是房东委托的中介,房东不想管事或者房子太多,只靠自己无法进行管理,…