花了两天时间,参考了一些资料,总算是处理好了这样一个技术点。
关键的心得如下:
使用jacob,重点不是jacob本身,而是office的一些API资料。比如需要知道光标的移动, 包括上下左右的move(MoveUp, MoveDown,MoveLeft, MoveRight),包括回到首页起点Dispatch.put(selection, "Start", 0)等等。
严格的说,这边并没有很系统化的去了解jacob的底层。但对于一些关键点,还是可以拿出来分享的。比如插入一张图片之后,系统可以拿到一个Dispatch对象(例如叫做obj),我们则需要调用Dispatch.call(obj,"select"),这样相当于使用鼠标在word选中了新插入的图片,而后我们就可以通过Dispatch得到图片的ShapeRange,进而得到ShapeRange的WrapFormat,再对WrapFormat进行设定。对应的结构可以归纳为:Image->ShapeRange->WrapFormat。但是要想知道WrapFormat对应到的是哪些值,且有哪些作用,则需要去查询MSDN。这边查询到的相关值如下:
wdWrapInline 7 将形状嵌入到文字中。
wdWrapNone 3 将形状放在文字前面。请参阅 wdWrapFront 。 wdWrapSquare 0 使文字环绕形状。行在形状的另一侧延续。 wdWrapThrough 2 使文字环绕形状。 wdWrapTight 1 使文字紧密地环绕形状。 wdWrapTopBottom 4 将文字放在形状的上方和下方。 wdWrapBehind 5 将形状放在文字后面。 wdWrapFront 6 将形状放在文字前面。这种匈牙利命名法的变量名,其实都对应到一个整型数据(应该是一个常量型的变量)。比如这次代码中需要用到的将印章图片盖在文字的前面,对应到得变量是wdWrapFront,也就是数值6.
再有就是要知道传入的word文件共有几页,加印的话,应该是每一页都要盖章的,于是就需要通过Dispatch.call(cursor,"information",4)来获取,此时cursor(光标)可能是需要回到word首页的开始位置(还未测试)。然后的思路就是要将光标指定到某个位置并以在文字前面的方式插入印章图片,实现的方式是:光标遍历到每一页的开始位置,并在此基础上移动到当前页的显眼位置。在开发过程中,将光标移动到每一页的开始位置,是花了相当的时间的。MSDN上并没有给出很直观的例子,甚至还找到了此功能无法实现的文章。直到找到了一篇名为“”的帖子,并注意到里面使用的
//定位到第i页
PageRange := wordapp.Selection.GoTo(wdGoToPage, wdGoToNext, IntToStr(i)); //<---->再一次匈牙利命名法的变量这种不太一样的写法正是对应到了
Dispatch.invoke(this.cursor, "Goto", Dispatch.Method, new Object[] {1, 2, String.valueOf(index)}, new int[1]);//<---->匈牙利命名法的变量对应到的整型常量,参考。
以下是完整的Java代码,要正确使用的话,需要将jacob的jar包放进工程,并在运行环境中加入jacob.dll。
1 import com.jacob.activeX.ActiveXComponent; 2 import com.jacob.com.Dispatch; 3 import com.jacob.com.Variant; 4 import com.jacob.com.ComThread; 5 6 public class WordInsertPicture { 7 8 public WordInsertPicture() { 9 } 10 11 // 声明一个静态的类实例化对象 12 private static WordInsertPicture instance; 13 // 声明word文档对象 14 private Dispatch doc = null; 15 // 声明word文档当前活动视窗对象 16 private Dispatch activeWindow = null; 17 // 声明word文档选定区域或插入点对象 18 private Dispatch docSelection = null; 19 // 声明所有word文档集合对象 20 private Dispatch wrdDocs = null; 21 // 声明word文档名称对象 22 private String fileName; 23 // 声明ActiveX组件对象:word.Application,Excel.Application,Powerpoint.Application等等 24 private ActiveXComponent wrdCom; 25 26 /** 27 * 获取Word操作静态实例对象 28 * 29 * @return 报表汇总业务操作 30 */ 31 public final static synchronized WordInsertPicture getInstance() { 32 if (instance == null) 33 instance = new WordInsertPicture(); 34 return instance; 35 } 36 37 /** 38 * 初始化Word对象 39 * 40 * @return 是否初始化成功 41 */ 42 public boolean initWordObj() { 43 boolean retFlag = false; 44 ComThread.InitSTA();// 初始化com的线程,非常重要!!使用结束后要调用 realease方法 45 wrdCom = new ActiveXComponent("Word.Application");// 实例化ActiveX组件对象:对word进行操作 46 try { 47 /* 48 * 返回wrdCom.Documents的Dispatch 49 * 获取Dispatch的Documents对象,可以把每个Dispatch对象看成是对Activex控件的一个操作 50 * 这一步是获得该ActiveX控件的控制权。 51 */ 52 wrdDocs = wrdCom.getProperty("Documents").toDispatch(); 53 // 设置打开的word应用程序是否可见 54 wrdCom.setProperty("Visible", new Variant(false)); 55 retFlag = true; 56 } catch (Exception e) { 57 retFlag = false; 58 e.printStackTrace(); 59 } 60 return retFlag; 61 } 62 63 /** 64 * 创建一个新的word文档 65 * 66 */ 67 public void createNewDocument() { 68 // 创建一个新的文档 69 doc = Dispatch.call(wrdDocs, "Add").toDispatch(); 70 // 获得当前word文档文本 71 docSelection = Dispatch.get(wrdCom, "Selection").toDispatch(); 72 } 73 74 /** 75 * 取得活动窗体对象 76 * 77 */ 78 public void getActiveWindow() { 79 // 获得活动窗体对象 80 activeWindow = wrdCom.getProperty("ActiveWindow").toDispatch(); 81 } 82 83 /** 84 * 打开一个已存在的文档 85 * 86 * @param docPath 87 */ 88 public void openDocument(String docPath) { 89 if (this.doc != null) { 90 this.closeDocument(); 91 } 92 this.doc = Dispatch.call(wrdDocs, "Open", docPath).toDispatch(); 93 this.docSelection = Dispatch.get(wrdCom, "Selection").toDispatch(); 94 } 95 96 /** 97 * 关闭当前word文档 98 * 99 */100 public void closeDocument() {101 if (this.doc != null) {102 Dispatch.call(this.doc, "Save");103 Dispatch.call(this.doc, "Close", new Variant(true));104 this.doc = null;105 }106 }107 /**108 * 文档设置图片水印109 * 110 * @param waterMarkPath111 * 水印路径 */112 public void setWaterMark(String waterMarkPath) {113 // 取得活动窗格对象114 Dispatch activePan = Dispatch.get(this.activeWindow, "ActivePane")115 .toDispatch();116 // 取得视窗对象117 Dispatch view = Dispatch.get(activePan, "View").toDispatch();118 // 打开页眉,值为9,页脚为10119 Dispatch.put(view, "SeekView", new Variant(9));120 //获取页眉和页脚121 Dispatch headfooter = Dispatch.get(this.docSelection, "HeaderFooter")122 .toDispatch();123 // 获取水印图形对象124 Dispatch shapes = Dispatch.get(headfooter, "Shapes").toDispatch();125 // 给文档全部加上水印,设置了水印效果,内容,字体,大小,是否加粗,是否斜体,左边距,上边距。126 //调用shapes对象的AddPicture方法将全路径为picname的图片插入当前文档127 Dispatch picture = Dispatch.call(shapes, "AddPicture", waterMarkPath).toDispatch();128 //选择当前word文档的水印129 Dispatch.call(picture, "Select");130 Dispatch.put(picture, "Left", new Variant(0));131 Dispatch.put(picture, "Top", new Variant(150));132 Dispatch.put(picture, "Width", new Variant(150));133 Dispatch.put(picture, "Height", new Variant(80));134 135 //关闭页眉136 Dispatch.put(view, "SeekView", new Variant(0));137 }138 139 /**140 * 关闭Word资源141 * 142 * 143 */144 public void closeWordObj() {145 // 关闭word文件146 wrdCom.invoke("Quit", new Variant[] {});147 // 释放com线程。根据jacob的帮助文档,com的线程回收不由java的垃圾回收器处理148 ComThread.Release();149 }150 151 /**152 * 得到文件名153 * 154 * @return .155 */156 public String getFileName() {157 return fileName;158 }159 160 /**161 * 设置文件名162 * 163 * @param fileName .164 */165 public void setFileName(String fileName) {166 this.fileName = fileName;167 }168 169 /**170 * 开始为word文档添加水印171 * 172 * @param wordPath173 * word文档的路径174 * @param waterMarkPath175 * 添加的水印图片路径176 * @return 是否成功添加177 */178 public boolean addWaterMark(String wordPath, String waterMarkPath) {179 try {180 if (initWordObj()) {181 openDocument(wordPath);182 getActiveWindow();183 setWaterMark(waterMarkPath);184 closeDocument();185 closeWordObj();186 return true;187 188 } else189 return false;190 } catch (Exception e) {191 e.printStackTrace();192 closeDocument();193 closeWordObj();194 return false;195 }196 }197 198 public boolean insertImage(String wordPath,String imagePath)199 {200 try {201 if (initWordObj()) {202 openDocument(wordPath);203 getActiveWindow();204 // 用于指定位置MoveRight以及MoveDown205 Dispatch selection = Dispatch.get(wrdCom, "Selection").toDispatch(); 206 for(int i = 0; i < 10; i++){207 Dispatch.call(selection, "MoveRight");208 }209 for(int i = 0; i < 10; i++){210 Dispatch.call(selection, "MoveDown");211 }212 Dispatch image = Dispatch.get(selection, "InlineShapes").toDispatch();213 Dispatch dv = Dispatch.call(image, "AddPicture", imagePath).toDispatch(); 214 Dispatch.call(dv, "Select");215 216 //Dispatch Left = Dispatch.get(position, "Left").toDispatch();217 selection = Dispatch.get(wrdCom, "Selection").toDispatch();218 Dispatch shaperange = Dispatch.get(selection, "ShapeRange").toDispatch();219 Dispatch wf = Dispatch.get(shaperange, "WrapFormat").toDispatch();220 Dispatch.put(wf, "Type", "6");221 int pcnt = Integer.parseInt(Dispatch.call(selection,"information",4).toString());222 for(int p = 1; p < pcnt; p++){223 Dispatch.invoke(selection, "Goto", Dispatch.Method, new Object[] {1, 2, String.valueOf(p)}, new int[1]);224 for(int i = 0; i < 10; i++){225 Dispatch.call(selection, "MoveRight");226 }227 for(int i = 0; i < 10; i++){228 Dispatch.call(selection, "MoveDown");229 }230 Dispatch imagef = Dispatch.get(selection, "InlineShapes").toDispatch();231 Dispatch dvf = Dispatch.call(imagef, "AddPicture", imagePath).toDispatch(); 232 Dispatch.call(dvf, "Select");233 234 //Dispatch Left = Dispatch.get(position, "Left").toDispatch();235 selection = Dispatch.get(wrdCom, "Selection").toDispatch();236 Dispatch shaperangef = Dispatch.get(selection, "ShapeRange").toDispatch();237 Dispatch wff = Dispatch.get(shaperangef, "WrapFormat").toDispatch();238 Dispatch.put(wff, "Type", "6");239 240 Dispatch.put(selection, "Start", 0); // 回到页首241 }242 243 closeDocument();244 closeWordObj();245 return true;246 } else247 return false;248 } catch (Exception e) {249 e.printStackTrace();250 closeDocument();251 closeWordObj();252 return false;253 }254 }255 256 257 /**258 * 测试功能259 * 260 */261 public static void main(String[] argv) {262 WordInsertPicture wordObj = WordInsertPicture.getInstance();263 //System.out.println(wordObj.getDocPages());264 wordObj.insertImage("e://1//Adf.docx", "e://1//watermark.png");265 //wordObj.addWaterMark("e://1//1.doc", "e://1//watermark.png");266 }267 }