C# 读取多条数据记录导出到 Word标签模板之图片输出改造
目录
应用需求
设计
范例运行环境
配置Office DCOM
实现代码
组件库引入
核心代码
调用示例
小结
应用需求
在我的文章《C# 读取多条数据记录导出到 Word 标签模板》里,讲述读取多条数据记录结合 WORD 标签模板输出文件的功能,原有输出图片的约定是在 WORD 模板文件中借助书签设置进行输出,如下图:
该书签名称代表了一条指令,格式为(输出关键字_图片宽度_图片高度)。如图中书签名称设置,当系统遇到 ds_qz 关键字时,输出按后继设置进行,图片宽度为100、图片高度为 50。
现有一模板需求如下图:
我们需要在考官评语和考官本人签字位置输出手写图片,原有的书签模式输出会遇到一些问题:
(1)只能为嵌入式,位置输出无法设置,无法进一步调整到较优呈现位置。
(2)只能插入式输出,无法实现嵌入式如文字浮动、环绕效果。
(3)需要在无关位置插入书签,否则会在输出关键字时被替换掉,而无法识别配置。
(4)书签的名称不能输入一些特定字符,如%,减号等,给配置带来一些麻烦。
(5)如果在文档里真需要设置书签,容易造成混乱。
设计
设计提供一个 ArrayList 类型参数取代书签模式的设计,其格式为 (输出关键字_图片宽度_图片高度_图片 Left 相对值_图片 Top 相对值 )。如添加 ds_qz_100_50_500_-20 字符串,当系统遇到 ds_qz 关键字时,输出按后继设置进行,图片宽度为100、图片高度为 50、图片 Left 为500、图片 Top 为 -20。后四个参数如果设置null则表示忽略,ds_qz_null_null_500_-20 ,则表示忽略宽度和高度设置,即表示原始大小输出。
定位到的图片输出,采取浮动于文字下方的处理。
范例运行环境
操作系统: Windows Server 2019 DataCenter
操作系统上安装 Office Word 2016
数据库:Microsoft SQL Server 2016
.net版本: .netFramework4.7.2 或以上
开发工具:VS2019 C#
配置Office DCOM
配置方法可参照我的文章《C# 读取Word表格到DataSet》进行处理和配置。
实现代码
组件库引入
核心代码
public string DataTableToWord(string _filename,string _repeatKey,object _dataset,ArrayList DataSetPictureConfig),该方法提供4个参数,WORD模板文件名、自定义关键字、System.Data.DataSet,配置图片用的 ArrayList 列表指令。
public void DataTableToWord(string _filename,string _repeatKey,object _dataset,ArrayList DataSetPictureConfig){if (DataSetPictureConfig == null) { DataSetPictureConfig = new ArrayList(); }Object Nothing = System.Reflection.Missing.Value;object filename = _filename;//创建一个名为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;//关闭显示拼写错误提示框WordApp.Selection.WholeStory();WordApp.Selection.Cut();DataSet ds=(DataSet)_dataset;System.Data.DataTable dt=ds.Tables[0];for(int i=0;i<dt.Rows.Count;i++){WordApp.Selection.Paste();for(int j=0;j<dt.Columns.Count;j++){string _repKey=_repeatKey+dt.Columns[j].ColumnName.ToString();string _repValue=string.Format("{0}",dt.Rows[i][j].ToString());bool isPhoto=false;if(dt.Columns[j].DataType==typeof(System.Byte[])){isPhoto=true;_repValue="";}WordApp.Options.ReplaceSelection=true;Word.Find fnd = WordApp.Selection.Find;fnd.ClearFormatting();Object findText = _repKey;Object matchCase = false;Object matchWholeWord = Type.Missing;Object matchWildcards = false;Object matchSoundsLike = false;Object matchAllWordForms = false;Object forward = true;Object wrap =Word.WdFindWrap.wdFindContinue;Object format = false;Object replaceWith ="";Object replace =Type.Missing;;Object matchKashida = Type.Missing;Object matchDiacritics = Type.Missing;Object matchAlefHamza = Type.Missing;Object matchControl = Type.Missing;while(fnd.Execute(ref findText, ref matchCase, ref matchWholeWord,ref matchWildcards, ref matchSoundsLike, ref matchAllWordForms, ref forward, ref wrap, ref format, ref replaceWith,ref replace, ref matchKashida, ref matchDiacritics,ref matchAlefHamza, ref matchControl)){string r_f=WordApp.Selection.Font.Name.ToString();WordApp.Selection.Range.Text=_repValue;if(isPhoto==true){string _jpgfile=_path+System.Guid.NewGuid()+".jpg";if (dt.Rows[i][j] == System.DBNull.Value){continue;}byte[] filedata = (byte[])dt.Rows[i][j];System.IO.MemoryStream ms = new MemoryStream(filedata);System.Drawing.Image img1 = System.Drawing.Image.FromStream(ms);img1.Save(@_jpgfile);ms.Close();Word.InlineShape pic= WordApp.Selection.InlineShapes.AddPicture(@_jpgfile,false,true);foreach (string bm in DataSetPictureConfig){string _findkey=_repKey+"_";int _f1 =bm.IndexOf(_findkey);if(_f1==0 && bm.Length>(_findkey.Length)){string[] _paras=bm.Substring(_findkey.Length,bm.Length-_findkey.Length).Split('_');if(_paras.GetLength(0)>1){if (_paras[0] != "null"){int def_width = int.Parse(_paras[0]);pic.Width = def_width;}if (_paras[1] != "null"){int def_height = int.Parse(_paras[1]);pic.Height = def_height;}}}}Word.Shape pic2 = pic.ConvertToShape();pic2.WrapFormat.Type = Word.WdWrapType.wdWrapThrough;pic2.WrapFormat.Type = Word.WdWrapType.wdWrapBehind;pic2.Left = 0;pic2.Top = 0;foreach (string bm in DataSetPictureConfig){string _findkey = _repKey + "_";int _f1 = bm.IndexOf(_findkey);if (_f1 == 0 && bm.Length > (_findkey.Length)){string[] _paras = bm.Substring(_findkey.Length, bm.Length - _findkey.Length).Split('_');if (_paras.GetLength(0) > 3){if (_paras[2] != "null")pic2.Left = float.Parse(_paras[2]);if (_paras[3] != "null")pic2.Top =float.Parse(_paras[3]);}}}File.Delete(@_jpgfile);}}}object dummy = System.Reflection.Missing.Value;object what = Word.WdGoToItem.wdGoToLine;object which = Word.WdGoToDirection.wdGoToLast;object count = System.Reflection.Missing.Value;
// WordApp.Selection.GoTo(ref oGoToItem, ref oGoToLast, ref Nothing, ref Nothing);WordApp.Selection.GoTo(ref what, ref which, ref count, ref dummy);//default 表示每行记录之间插入分页符,最后一行时不再插入分页符,以免造成多余一空白页if(i!=dt.Rows.Count-1){object ib = Word.WdBreakType.wdPageBreak; WordApp.Selection.InsertBreak(ref ib);}}}WordDoc.Save();WordDoc.Close(ref Nothing, ref Nothing, ref Nothing);//关闭WordApp组件对象WordApp.Quit(ref Nothing, ref Nothing, ref Nothing);}
调用示例
示例代码如下:
DataSet rv = GetDataSet("select * from tabble");ArrayList picconfig = new ArrayList(); //可配置每个图片字段的大小及位置
picconfig.Add("ds_kg_sign_100_50_500_-20"); //格式为: key_width_height_left_top
string ModuleFile = "d:\\bfile\\word\\面试评分表.docx"; //假设的模板文件
string _lastfile = DataTableToWord(ModuleFile,"ds_",ds,picconfig);MessageBox.Show(string.Format("已成功导出文件:{0}", _lastfile));
运行结果预览如下图:
小结
核心代码中需要将 Word.InlineShape 转换为 Word.Shape 后,可以进行环绕文字的操作,如下:
Word.Shape pic2 = pic.ConvertToShape();
pic2.WrapFormat.Type = Word.WdWrapType.wdWrapThrough;
pic2.WrapFormat.Type = Word.WdWrapType.wdWrapBehind;
pic2.Left = 0;
pic2.Top = 0;
使用 ConvertToShape() 方法转换为 pic2 , pic2.WrapFormat.Type = Word.WdWrapType.wdWrapBehind; 可以浮动于文字下方,然后初始图片的 Left 和 Top ,否则有可能无法正常显示位置。
我们可以根据自己的实际情况设置环绕格式,可参阅读如下地址:
https://learn.microsoft.com/zh-cn/office/vba/api/word.wdwraptypemerged
这些代码我们提供了一些操作WORD相关的关键方法,这里仅作参考,欢迎大家评论指教!
相关文章:

C# 读取多条数据记录导出到 Word标签模板之图片输出改造
目录 应用需求 设计 范例运行环境 配置Office DCOM 实现代码 组件库引入 核心代码 调用示例 小结 应用需求 在我的文章《C# 读取多条数据记录导出到 Word 标签模板》里,讲述读取多条数据记录结合 WORD 标签模板输出文件的功能,原有输出图片的…...

NSSCTF web刷题
1 虽然找到了flag,但是我要怎么去改他的代码,让他直接输出flag呢? (好像是要得到他的json代码,这题不让看) 2 wllm应该就是他的密码,进入许可了 意思是服务器可以执行通过POST的请求方式传入参数为wllm的命令,那这就是典型的命令执行,当然,…...
对象排序得到方式
java实现 list 排序的方式,有三种 ① 对象实现Comparable 接口,然后代码里直接调用Collections.sort(list) ②使用内部类Comparator ③使用stream.sort 代码如下 实现Comparable接口的实体类 Data public class Student implements Comparable<Stud…...
Day2 洛谷1035+1047+1085+1089+1150+1151
零基础洛谷刷题记录 Day1 2024.11.18 Day2 2024.11.25 文章目录 零基础洛谷刷题记录1035:题目描述1035:解答代码1035:学习成果1047:题目描述(成功写出)1047:解答代码1047:学习成果1085…...

Linux:进程间通信之进程池和日志
一、进程池的设计 因为每一次我们要进行进程间通信都需要fork,和操作系统做交互是存在很大成本的,所以我们是不是可以提前fork出几个进程,然后当我们想要使用的时候直接去给他们安排任务,这样就减少了系统调用的次数从而提高了内存…...

详细介绍HTTP与RPC:为什么有了HTTP,还需要RPC?
目录 一、HTTP 二、RPC 介绍 工作原理 核心功能 如何服务寻址 如何进行序列化和反序列化 如何网络传输 基于 TCP 协议的 RPC 调用 基于 HTTP 协议的 RPC 调用 实现方式 优点和缺点 使用场景 常见框架 示例 三、问题 问题一:是先有HTTP还是先有RPC&…...
Paddle Inference部署推理(十二)
十二:Paddle Inference推理 (python)API详解 15. PredictorPool 类 PredictorPool 对 Predictor 进行了简单的封装,通过传入 config 和 thread 的数目来完成初始化,在每个线程中,根据自己的线程 id 直接从…...
外观模式 (Facade Pattern)
外观模式 (Facade Pattern) 外观模式是一种 结构型设计模式,通过为子系统中的一组接口提供一个统一的高层接口,简化了子系统的使用,让复杂系统更易于访问。 原理 核心思想: 提供一个 统一的接口 来访问子系统中的多个接口&#…...

人工智能-深度学习-Torch框架-手动构建回归流程
from sklearn.datasets import make_regression import math import random import torch from sklearn.datasets import make_regression: 导入make_regression函数,用于生成回归数据集。 import math: 导入math模块,用于进行数学计算,例如…...

SpringBoot源码解析(五):准备应用环境
SpringBoot源码系列文章 SpringBoot源码解析(一):SpringApplication构造方法 SpringBoot源码解析(二):引导上下文DefaultBootstrapContext SpringBoot源码解析(三):启动开始阶段 SpringBoot源码解析(四):解析应用参数args Sp…...

MySQL面试-1
InnoDB中ACID的实现 先说一下原子性是怎么实现的。 事务要么失败,要么成功,不能做一半。聪明的InnoDB,在干活儿之前,先将要做的事情记录到一个叫undo log的日志文件中,如果失败了或者主动rollback,就可以通…...
nginx配置不缓存资源
方法1 location / {index index.html index.htm;add_header Cache-Control no-cache,no-store;try_files $uri $uri/ /index.html;#include mime.types;if ($request_filename ~* .*\.(htm|html)$) {add_header Cache-Control "private, no-store, no-cache, must-revali…...
PHP导出EXCEL含合计行,设置单元格格式
PHP导出EXCEL含合计行,设置单元格格式,水平居中 垂直居中 public function exportSalary(Request $request){//水平居中 垂直居中$styleArray [alignment > [horizontal > Alignment::HORIZONTAL_CENTER,vertical > Alignment::VERTICAL_CE…...

RabbitMQ 之 死信队列
一、死信的概念 先从概念解释上搞清楚这个定义,死信,顾名思义就是无法被消费的消息,字面意思可以这样理 解,一般来说,producer 将消息投递到 broker 或者直接到 queue 里了,consumer 从 queue 取出消息进行…...
【创建型设计模式】单例模式
【创建型设计模式】单例模式 这篇博客接下来几篇都将阐述设计模式相关内容。 接下来的顺序大概是:单例模式、工厂方法模式、抽象工厂模式、建造者模式、原型模式。 一、什么是单例模式 单例模式是一种创建型设计模式,它保证一个类仅有一个实例&#…...

Charles抓包工具-笔记
摘要 概念: Charles是一款基于 HTTP 协议的代理服务器,通过成为电脑或者浏览器的代理,然后截取请求和请求结果来达到分析抓包的目的。 功能: Charles 是一个功能全面的抓包工具,适用于各种网络调试和优化场景。 它…...
Go语言使用 kafka-go 消费 Kafka 消息教程
Go语言使用 kafka-go 消费 Kafka 消息教程 在这篇教程中,我们将介绍如何使用 kafka-go 库来消费 Kafka 消息,并重点讲解 FetchMessage 和 ReadMessage 的区别,以及它们各自适用的场景。通过这篇教程,你将了解如何有效地使用 kafk…...

【论文笔记】Number it: Temporal Grounding Videos like Flipping Manga
🍎个人主页:小嗷犬的个人主页 🍊个人网站:小嗷犬的技术小站 🥭个人信条:为天地立心,为生民立命,为往圣继绝学,为万世开太平。 基本信息 标题: Number it: Temporal Grou…...

C语言菜鸟入门·关键字·int的用法
目录 1. int关键字 1.1 取值范围 1.2 符号类型 1.3 运算 1.3.1 加法运算() 1.3.2 减法运算(-) 1.3.3 乘法运算(*) 1.3.4 除法运算(/) 1.3.5 取余运算(%) 1.3.6 自增()与自减(--) 1.3.7 位运算 2. 更多关键字 1. int关键字 int 是一个关键字࿰…...

基于企业微信客户端设计一个文件下载与预览系统
在企业内部沟通与协作中,文件分享和管理是不可或缺的一部分。企业微信(WeCom)作为一款广泛应用于企业的沟通工具,提供了丰富的API接口和功能,帮助企业进行高效的团队协作。然而,随着文件交换和协作的日益增…...
变量 varablie 声明- Rust 变量 let mut 声明与 C/C++ 变量声明对比分析
一、变量声明设计:let 与 mut 的哲学解析 Rust 采用 let 声明变量并通过 mut 显式标记可变性,这种设计体现了语言的核心哲学。以下是深度解析: 1.1 设计理念剖析 安全优先原则:默认不可变强制开发者明确声明意图 let x 5; …...

【JavaEE】-- HTTP
1. HTTP是什么? HTTP(全称为"超文本传输协议")是一种应用非常广泛的应用层协议,HTTP是基于TCP协议的一种应用层协议。 应用层协议:是计算机网络协议栈中最高层的协议,它定义了运行在不同主机上…...
Java 8 Stream API 入门到实践详解
一、告别 for 循环! 传统痛点: Java 8 之前,集合操作离不开冗长的 for 循环和匿名类。例如,过滤列表中的偶数: List<Integer> list Arrays.asList(1, 2, 3, 4, 5); List<Integer> evens new ArrayList…...

屋顶变身“发电站” ,中天合创屋面分布式光伏发电项目顺利并网!
5月28日,中天合创屋面分布式光伏发电项目顺利并网发电,该项目位于内蒙古自治区鄂尔多斯市乌审旗,项目利用中天合创聚乙烯、聚丙烯仓库屋面作为场地建设光伏电站,总装机容量为9.96MWp。 项目投运后,每年可节约标煤3670…...

高危文件识别的常用算法:原理、应用与企业场景
高危文件识别的常用算法:原理、应用与企业场景 高危文件识别旨在检测可能导致安全威胁的文件,如包含恶意代码、敏感数据或欺诈内容的文档,在企业协同办公环境中(如Teams、Google Workspace)尤为重要。结合大模型技术&…...

相机从app启动流程
一、流程框架图 二、具体流程分析 1、得到cameralist和对应的静态信息 目录如下: 重点代码分析: 启动相机前,先要通过getCameraIdList获取camera的个数以及id,然后可以通过getCameraCharacteristics获取对应id camera的capabilities(静态信息)进行一些openCamera前的…...

在WSL2的Ubuntu镜像中安装Docker
Docker官网链接: https://docs.docker.com/engine/install/ubuntu/ 1、运行以下命令卸载所有冲突的软件包: for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do sudo apt-get remove $pkg; done2、设置Docker…...
高效线程安全的单例模式:Python 中的懒加载与自定义初始化参数
高效线程安全的单例模式:Python 中的懒加载与自定义初始化参数 在软件开发中,单例模式(Singleton Pattern)是一种常见的设计模式,确保一个类仅有一个实例,并提供一个全局访问点。在多线程环境下,实现单例模式时需要注意线程安全问题,以防止多个线程同时创建实例,导致…...

中医有效性探讨
文章目录 西医是如何发展到以生物化学为药理基础的现代医学?传统医学奠基期(远古 - 17 世纪)近代医学转型期(17 世纪 - 19 世纪末)现代医学成熟期(20世纪至今) 中医的源远流长和一脉相承远古至…...
AGain DB和倍数增益的关系
我在设置一款索尼CMOS芯片时,Again增益0db变化为6DB,画面的变化只有2倍DN的增益,比如10变为20。 这与dB和线性增益的关系以及传感器处理流程有关。以下是具体原因分析: 1. dB与线性增益的换算关系 6dB对应的理论线性增益应为&…...