花了两天时间,参考了一些资料,总算是处理好了这样一个技术点。

关键的心得如下:

使用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上并没有给出很直观的例子,甚至还找到了此功能无法实现的文章。直到找到了一篇名为“delphi读取WORD文档每一页的内容”的帖子,并注意到里面使用的

  //定位到第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。

 import com.jacob.activeX.ActiveXComponent;
 import com.jacob.com.Dispatch;
 import com.jacob.com.Variant;
 import com.jacob.com.ComThread;

 public class WordInsertPicture {

  public WordInsertPicture() {
  }

  // 声明一个静态的类实例化对象
  private static WordInsertPicture instance;
  // 声明word文档对象
  private Dispatch doc = null;
  // 声明word文档当前活动视窗对象
  private Dispatch activeWindow = null;
  // 声明word文档选定区域或插入点对象
  private Dispatch docSelection = null;
  // 声明所有word文档集合对象
  private Dispatch wrdDocs = null;
  // 声明word文档名称对象
  private String fileName;
  // 声明ActiveX组件对象:word.Application,Excel.Application,Powerpoint.Application等等
  private ActiveXComponent wrdCom;

  /**
   * 获取Word操作静态实例对象
   *
   * @return 报表汇总业务操作
   */
  public final static synchronized WordInsertPicture getInstance() {
   if (instance == null)
    instance = new WordInsertPicture();
   return instance;
  }

  /**
   * 初始化Word对象
   *
   * @return 是否初始化成功
   */
  public boolean initWordObj() {
   boolean retFlag = false;
   ComThread.InitSTA();// 初始化com的线程,非常重要!!使用结束后要调用 realease方法
   wrdCom = new ActiveXComponent("Word.Application");// 实例化ActiveX组件对象:对word进行操作
   try {
    /*
     * 返回wrdCom.Documents的Dispatch
     * 获取Dispatch的Documents对象,可以把每个Dispatch对象看成是对Activex控件的一个操作
     * 这一步是获得该ActiveX控件的控制权。
     */
    wrdDocs = wrdCom.getProperty("Documents").toDispatch();
    // 设置打开的word应用程序是否可见
    wrdCom.setProperty("Visible", new Variant(false));
    retFlag = true;
   } catch (Exception e) {
    retFlag = false;
    e.printStackTrace();
   }
   return retFlag;
  }

  /**
   * 创建一个新的word文档
   *
   */
  public void createNewDocument() {
   // 创建一个新的文档
   doc = Dispatch.call(wrdDocs, "Add").toDispatch();
   // 获得当前word文档文本
   docSelection = Dispatch.get(wrdCom, "Selection").toDispatch();
  }

  /**
   * 取得活动窗体对象
   *
   */
  public void getActiveWindow() {
   // 获得活动窗体对象
   activeWindow = wrdCom.getProperty("ActiveWindow").toDispatch();
  }

  /**
   * 打开一个已存在的文档
   *
   * @param docPath
   */
  public void openDocument(String docPath) {
   if (this.doc != null) {
    this.closeDocument();
   }
   this.doc = Dispatch.call(wrdDocs, "Open", docPath).toDispatch();
   this.docSelection = Dispatch.get(wrdCom, "Selection").toDispatch();
  }

  /**
   * 关闭当前word文档
   *
   */
  public void closeDocument() {
   if (this.doc != null) {
    Dispatch.call(this.doc, "Save");
    Dispatch.call(this.doc, "Close", new Variant(true));
    this.doc = null;
   }
  }
   /**
   * 文档设置图片水印
   *
   * @param waterMarkPath
   *            水印路径  */
  public void setWaterMark(String waterMarkPath) {
   // 取得活动窗格对象
   Dispatch activePan = Dispatch.get(this.activeWindow, "ActivePane")
     .toDispatch();
   // 取得视窗对象
   Dispatch view = Dispatch.get(activePan, "View").toDispatch();
   // 打开页眉,值为9,页脚为10
   Dispatch.put(view, "SeekView", new Variant(9));
   //获取页眉和页脚
   Dispatch headfooter = Dispatch.get(this.docSelection, "HeaderFooter")
     .toDispatch();
   // 获取水印图形对象
   Dispatch shapes = Dispatch.get(headfooter, "Shapes").toDispatch();
   // 给文档全部加上水印,设置了水印效果,内容,字体,大小,是否加粗,是否斜体,左边距,上边距。
     //调用shapes对象的AddPicture方法将全路径为picname的图片插入当前文档
      Dispatch picture = Dispatch.call(shapes, "AddPicture", waterMarkPath).toDispatch();
   //选择当前word文档的水印
   Dispatch.call(picture, "Select");
   Dispatch.put(picture, "Left", new Variant(0));
   Dispatch.put(picture, "Top", new Variant(150));
   Dispatch.put(picture, "Width", new Variant(150));
   Dispatch.put(picture, "Height", new Variant(80));

  //关闭页眉
   Dispatch.put(view, "SeekView", new Variant(0));
  }

  /**
   * 关闭Word资源
   *
   *
   */
  public void closeWordObj() {
   // 关闭word文件
   wrdCom.invoke("Quit", new Variant[] {});
   // 释放com线程。根据jacob的帮助文档,com的线程回收不由java的垃圾回收器处理
   ComThread.Release();
  }

  /**
   * 得到文件名
   *
   * @return .
   */
  public String getFileName() {
   return fileName;
  }

  /**
   * 设置文件名
   *
   * @param fileName .
   */
  public void setFileName(String fileName) {
   this.fileName = fileName;
  }

  /**
   * 开始为word文档添加水印
   *
   * @param wordPath
   *            word文档的路径
   * @param waterMarkPath
   *            添加的水印图片路径
   * @return 是否成功添加
   */
  public boolean addWaterMark(String wordPath, String waterMarkPath) {
   try {
    if (initWordObj()) {
     openDocument(wordPath);
     getActiveWindow();
     setWaterMark(waterMarkPath);
     closeDocument();
     closeWordObj();
     return true;

    } else
     return false;
   } catch (Exception e) {
       e.printStackTrace();
       closeDocument();
       closeWordObj();
       return false;
   }
  }

  public boolean insertImage(String wordPath,String imagePath)
  {
       try {
            if (initWordObj()) {
             openDocument(wordPath);
             getActiveWindow();
             // 用于指定位置MoveRight以及MoveDown
             Dispatch selection = Dispatch.get(wrdCom, "Selection").toDispatch();
             for(int i = 0; i < 10; i++){
                 Dispatch.call(selection, "MoveRight");
             }
             for(int i = 0; i < 10; i++){
                 Dispatch.call(selection, "MoveDown");
             }
             Dispatch image = Dispatch.get(selection, "InlineShapes").toDispatch();
             Dispatch dv = Dispatch.call(image, "AddPicture", imagePath).toDispatch();
             Dispatch.call(dv, "Select");

             //Dispatch Left = Dispatch.get(position, "Left").toDispatch();
             selection = Dispatch.get(wrdCom, "Selection").toDispatch();
             Dispatch shaperange   = Dispatch.get(selection, "ShapeRange").toDispatch();
             Dispatch wf = Dispatch.get(shaperange, "WrapFormat").toDispatch();
             Dispatch.put(wf, "Type", "6");
             int pcnt = Integer.parseInt(Dispatch.call(selection,"information",4).toString());
             for(int p = 1; p < pcnt; p++){
                 Dispatch.invoke(selection, "Goto", Dispatch.Method, new Object[] {1, 2, String.valueOf(p)}, new int[1]);
                 for(int i = 0; i < 10; i++){
                     Dispatch.call(selection, "MoveRight");
                 }
                 for(int i = 0; i < 10; i++){
                     Dispatch.call(selection, "MoveDown");
                 }
                 Dispatch imagef = Dispatch.get(selection, "InlineShapes").toDispatch();
                 Dispatch dvf = Dispatch.call(imagef, "AddPicture", imagePath).toDispatch();
                 Dispatch.call(dvf, "Select");

                 //Dispatch Left = Dispatch.get(position, "Left").toDispatch();
                 selection = Dispatch.get(wrdCom, "Selection").toDispatch();
                 Dispatch shaperangef   = Dispatch.get(selection, "ShapeRange").toDispatch();
                 Dispatch wff = Dispatch.get(shaperangef, "WrapFormat").toDispatch();
                 Dispatch.put(wff, "Type", "6");

                 Dispatch.put(selection, "Start", 0); // 回到页首
             }

             closeDocument();
             closeWordObj();
             return true;
            } else
             return false;
           } catch (Exception e) {
               e.printStackTrace();
               closeDocument();
               closeWordObj();
               return false;
           }
  }

  /**
   * 测试功能
   *
   */
  public static void main(String[] argv) {
   WordInsertPicture wordObj = WordInsertPicture.getInstance();
 //System.out.println(wordObj.getDocPages());
   wordObj.insertImage("e://1//Adf.docx", "e://1//watermark.png");
   //watermark.png");
  }
 }

jacob 给word加印的功能的更多相关文章

  1. Java文件操作系列[3]——使用jacob操作word文档

    Java对word文档的操作需要通过第三方组件实现,例如jacob.iText.POI和java2word等.jacob组件的功能最强大,可以操作word,Excel等格式的文件.该组件调用的的是操作 ...

  2. Excel与Word套打功能使用技巧及EXCEL数据处理成绩

    Excel与Word套打功能使用技巧 婚礼邀请友人参加,就需要写请柬.而且写请柬不但要求字写得端正,还不能有错别字,再加上邀请的朋友多,写请柬就是一个劳累活.这时我们利用Word的套打功能,就会让写请 ...

  3. jacob 操作word转pdf

    项目需要对上传的word及pdf进行在线预览,因基于jquery的pdf插件,很方面实现在线预览,而word实现在线预览费劲不少,于是想到在进行上传处理时,直接将word转成pdf,在预览时直接预览p ...

  4. 【文件】使用jacob将word转换成pdf格式

    使用jacob将word转换成pdf格式   1.需要安装word2007或以上版本,若安装07版本学确保该版本已安装2downbank0204MicrosoftSaveasPDF_ XPS,否则安装 ...

  5. ckeditor粘贴word图片自动上传功能

    由于工作需要必须将word文档内容粘贴到编辑器中使用 但发现word中的图片粘贴后变成了file:///xxxx.jpg这种内容,如果上传到服务器后其他人也访问不了,网上找了很多编辑器发现没有一个能直 ...

  6. MindManager导出Word文档功能介绍

    Mindmanager思维导图软件作为一款能与Microsoft office软件无缝集成的思维导图软件,支持Word文档的快速导入与导出,并支持Word文档的目录生成.模板套用等,极大地方便了用户完 ...

  7. jacob 操作word

    1. 首先下载jacob-1.18.zip,解压后有两个文件jacob.jar 和 jacob.dll.需要把jacob.jar放到你工程的classpath中并且把jacob.dll放到jdk的bi ...

  8. 使用Jacob与Word文件交互

    转自:http://www.blogjava.net/lonsy/archive/2009/01/09/250713.html Jacob项目的官方地址: Http://sourceforge.net ...

  9. Java使用Jacob转换Word为HTML

    从今天开始,我也要养成记录开发中遇到的问题和解决方法的好习惯! 最近开发一个Android项目,需要用到查看Word和Pdf文档的功能,由于Android没有直接显示Word和PDF文档的组件,只有一 ...

随机推荐

  1. C++面试题:list和vector有什么区别?

    原文:http://genwoxuevc.blog.51cto.com/1852984/503337 C++面试题:list和vector有什么区别?考点:理解list和vector的区别出现频率:★ ...

  2. Game: Map Design Considerations 游戏地图设计指南

    依据前文伏击战场景手稿, 用Tile Studio "草草"制作出该场景的地图: 生成的C源码: #ifndef _open_war_1Gfx_c #define _open_wa ...

  3. kmp算法简明教程

    在字符串s中寻找模式串p的位置,这是一个字符串匹配问题. 举例说明: i = 0 1 2 3 4 5 6 7 8 9 10 11 12 13 s = a b a a c a b a a a b a a ...

  4. JS 公共方法

    1.Format函数 $.GM.Format = function (source, params) { if (arguments.length == 1) return function () { ...

  5. C++11实现Qt的信号槽机制

    概述 Qt的信号槽机制是Qt的核心机制,按钮点击的响应.线程间通信等都是通过信号槽来实现的,boost里也有信号槽,但和Qt提供的使用接口很不一样,本文主要是用C++11来实现一个简单的信号槽,该信号 ...

  6. LeetCode27 Remove Element

    题目: Given an array and a value, remove all instances of that value in place and return the new lengt ...

  7. 优化 App 的启动速度

    App 的启动速度不仅影响我们调试,也直接关系到用户体验.之前有些很久没有打开过的项目,需要花费很长的时间才完成编译:对应的 App 在点击后,许久才出现启动画面.你是否为这些问题苦恼过呢? 这是我观 ...

  8. 用英文加优先级来解读C的声明

    比如:int ( * func_p ) ( double ); 首先着眼于标识符. func_p is 因为存在括号,(* func_p) 先被处理,这里着眼于* func_p is a pointe ...

  9. OC之protocol监听器的实现

    画图 图解 代码 总结 一.画图 本人画了一个图(字体和画图水平请忽略) 二.图解 1.首先我们上边是一个按钮的类,按钮当中包括了一条线,这个线是什么呢? 其实难理解就难理解到这条线上了 1⃣️这条线 ...

  10. XMLObject 简易xml格式接口数据生成和解析工具

    简单的请求封装,相当于封装了Book对象,但比Book对象参数更灵活 XMLObject xml = new XMLObject("book");xml.add("aut ...