COM组件浅析(一) - 使用Java操作Adobe Illustrator


​  在Windows下,使用Java操作Adobe Illustrator(下称“AI”),需要通过JNI技术调用C++来实现。在本地安装好AI后,AI会在注册表注册自己的COM信息。C++之所以能够操作COM组件,是因为Windows提供了一整套技术来支持。

​  ​当然,在2021年,我们已经不需要自己去手动写C++代码来对对AI进行操作,而是使用Jacob开源中间件(发音类似“雅各布”,协议LGPLv2)。Jacob全称是Java-COM Bridge,也就是它是一个方便Java调用COM组件的一个库。Jacob是一个从1999年就开始的开源项目。Jacob最初将源代码托管在sourceforgehttps://sourceforge.net/projects/jacob-project/ 上,在去年9月份(2020-9-25)迁移到了github上。最新的v1.20支持在Windows 10+Java8 32/64位下运行。

​  不过有个奇怪的事情,如果你在github搜索,会发现一份最后更新时间为2011年的Jacob项目:https://github.com/joval/jacob。具体原因我就没有深究了。同时,在开源中国上也有一个相关的项目Jacob:https://www.oschina.net/p/jacob。

​  ​当然,在开始下面的步骤之前,你的电脑上应该安装了Adobe Illustrator并能够正常使用。我这里安装的版本是Adobe Illustrator CC 2017(21.0.0),需要注意的是,如果安装了Adobe Illustrator CC 2019(23.0.0)会出现无法通过Java打开Illustrator的情况,貌似需要升级到23.0.2。

环境说明:

  1. 操作系统:Windows 10 64位
  2. JDK:JDK1.8 102 32位
  3. Jacob:1.20
  4. IDEA:2020.3.3
  5. Adobe Illustrator: CC 2017(21.0.0)

一、下载Jacob

​​  Jacob迁移到github之后,sourceforge上就无法下载了。可以在此处https://github.com/freemansoft/jacob-project/releases 下载最新版1.20(2020-9-25发布)。或者,直接点击jacob-1.20.ziphttps://github.com/freemansoft/jacob-project/releases/download/Root_B-1_20/jacob-1.20.zip 下载不带源码版的压缩包。解压后文件夹内容如下:
在这里插入图片描述
​​  其中,jacob.jar需要在Java工程中引入,而jacob-1.20-x86.dll或jacob-1.20-x64.dll需要加载到当前Java程序的库目录下(比如:当前目录、java.library.path等文件夹下都可以)。

二、创建JacobDemo maven工程,引入jacob依赖

1. 创建工程

​​  这里我使用IntelliJ IDEA 2020.3.3创建maven工程对jacob进行简单的介绍。在菜单上,点击File -> New -> Project…打开如下对话框,左侧选择maven。
在这里插入图片描述
​  新项目的名称定为JacobDemo,点击Finish完成项目创建。
在这里插入图片描述

2. 引入jacob依赖

​​  项目创建完成后,我们将解压出来的jacob.jar、jacob-1.20-x86.dll、jacob-1.20-x64.dll复制到项目根目录下,在我这即是~/IdeaProjects/JacobDemo/

​​  如果没有正确复制dll文件,那么会在执行时抛出异常:no jacob-1.20-x86 in java.library.path

3. 在pom.xml中引入jacob.jar

​​  在pom.xml中增加如下配置

<dependencies>
  <dependency>
    <groupId>com.jacob</groupId>
    <artifactId>Jacob</artifactId>
    <version>1.20</version>
    <scope>system</scope>
    <systemPath>${basedir}/jacob.jar</systemPath>
  </dependency>
</dependencies>

三、在代码中操作Adobe Illustrator

​​  下一步,我们创建一个JacobDemo类,并填充样例代码。

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

public class JacobDemo {
    public static void main(String[] args) {
        ActiveXComponent app = new ActiveXComponent("Illustrator.Application"); // 创建一个Application对象
        Dispatch docs = Dispatch.call(app, "Documents").toDispatch(); // 获取app中所有的文稿对象Documents
        Dispatch doc = Dispatch.call(docs, "Add").toDispatch(); // 调用Documents的Add方法,得到一个新文稿

        Dispatch textFrames = Dispatch.call(doc, "TextFrames").toDispatch(); // 获取doc下的所有TextFrames
        Dispatch textFrame = Dispatch.call(textFrames, "Add").toDispatch();
        Dispatch.put(textFrame, "Top", 600);
        Dispatch.put(textFrame, "Left", 100);
        Dispatch.put(textFrame, "Contents", "hello, illustrator");

    }
}

​​  执行上述main方法,可以看到,在执行过程中,Adobe Illustrator会自动打开,并新建一个窗口,在窗口左上角添加了一个文本框,框中内容为“hello, illustrator”。如下图所示。
在这里插入图片描述

​​  好了,这就是一个基本的使用Java调用Adobe Illustrator的Demo。

四、Jacob中的Dispatch简单介绍

​​  通过阅读demo代码我们可以发现,基本上都是调用Dispatch类的静态方法来达到操作目的。假如Java中有相应的类,那么demo的代码将等同于如下代码。

public class JacobDemo {
    public static void main(String[] args) {
        Illustrator.Application app = new Illustrator.Application();
        Document doc = app.getDocuments().Add();
        TextFrame textFrame = doc.getTextFrames().Add();
        textFrame.setTop(600);
        textFrame.setLeft(100);
        textFrame.setContents("hello, illustrator");
    }
}

​​  实际上,通过Java调用Illustrator.Application中暴露出来的方法,基本上分为这三类:

  1. 获取基本属性的值,如获取文本框的宽度,高度等
  2. 设置基本属性的值,如设置文本框的偏移量、文本内容等
  3. 调用某个对象的某个方法。

​​  所以,针对以上三类,对应着Dispatch中的3个方法:Dispatch.get(Dispatch, String)、Dispatch.put(Dispatch,String,Object)、Dispatch.call(Dispatch,String,Object…)。我们增加JacobDemo2,代码如下。

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

public class JacobDemo2 {
    public static void main(String[] args) {
        ActiveXComponent app = new ActiveXComponent("Illustrator.Application");
        Dispatch docs = Dispatch.get(app, "Documents").toDispatch(); // 此处修改为get,与call等效,但语义更明确
        Dispatch doc = Dispatch.call(docs, "Add").toDispatch();

        Dispatch textFrames = Dispatch.get(doc, "TextFrames").toDispatch();// 此处修改为get,与call等效,但语义更明确
        Variant textFrameVar = Dispatch.call(textFrames, "Add"); // 看一看call方法的返回类型
        Dispatch textFrame = textFrameVar.toDispatch();
        Dispatch.put(textFrame, "Top", 600);
        Dispatch.put(textFrame, "Left", 100);
        Dispatch.put(textFrame, "Contents", "hello, illustrator");

        Variant widthVar = Dispatch.get(textFrame, "Width");
        double width = widthVar.getDouble();
        System.out.println("width = " + width); // 控制台输出:width = 72.94677734375
      
        // 以下是另存为一个新文件,并关闭的代码示例
        ActiveXComponent saveOptions = new ActiveXComponent("Illustrator.IllustratorSaveOptions");
        Dispatch.put(saveOptions, "Compatibility", 17);
        Dispatch.put(saveOptions, "FlattenOutput", 1);
        Dispatch.call(doc, "SaveAs", "~\\IdeaProjects\\JacobDemo\\test.ai", saveOptions);
        Dispatch.call(doc, "Close");
    }
}	

​​  通过Demo代码,我们还可以发现,Dispatch贯穿代码始终,那么这个Dispatch是什么呢?在这里,你可以简单理解为,如果通过Dispatch.get/put/call方法得到的返回值为基本数据类型(如,获取文本框的宽高),那么不能转为Dispatch(毕竟,基本数据类型已经不需要继续调用Dipatch的方法了)。如果需要进一步调用Dispatch.get/put/call方法时,需要需要将前一次调用的返回值toDispatch()之后传递给这次的第一个参数。

​​  Dispatch.get/put/call返回值是一个Variant对象,系统并不知道这个返回值是否是一个可继续调用的对象,所以,我们需要根据API来决定是否把这个Variant转为Dispatch(toDispatch方法)还是某个具体的基本数据类型(getIntgetDouble等方法)。

本篇文章IDEA工程下载链接:https://download.csdn.net/download/weixin_37504415/16427670

下一篇,我们将使用C#来实现Demo2,并能够更清晰地看到AI中每个对象的属性及方法。


系列文章
第一篇 COM组件浅析(一) - 使用Java操作Adobe Illustrator
第二篇 COM组件浅析(二) - 使用C#操作Adobe Illustrator
第三篇 COM组件浅析(三)- 使用C/C++操作Adobe Illustrator

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值