第二章 目标
2.1 API 的目标
Image I/O API 的设计是受到了对支持一系列主要目标的渴望的影响。每个目标都提供了对应的一系列API功能被设计的理由。这些目标可被分为主要由客户端应用程序需求所推动的和被服务器端应用需求推动的。当然,这些主要目标仅代表了API所有能力的一小部分。它们在此列举的目的是提供API设计动机的一种概念。
作为概览的通用规则,不论何时,在方便应用开发者使用及插件开发者使用之间的权衡都是必须的,应用的开发者被赋予了更高的优先权。由于相对来说希望编写插件的API使用者还是占少数,而且甚至这些编写插件的开发者通常也不会写为了支持相关的图片格式使之立即投入使用的代码之外的东西,所以把复杂的东西尽量推到插件开发方而不是应用程序开发方是很有道理的。
为了减轻插件开发的复杂度,我们提供了一些用来作为公用函数的工具方法和实现类。然而,将所有功能情景都涉及到是不可能的,并且如果提供的工具类和方法过量的话,所有API用户的机器付出的额外开销就会变得很大,即便这些用户可能并不需要用到这些标准包之外的功能。当在使用多个、独立开发的插件时,可能也会造成一定的赘余,但大多数用户还是倾向于在任何情况下都尽可能减少使用插件的数量。所以我们认为,加载理论上可能会被分享但实际上没有的代码,其性能的开销更容易超过在使用插件时,由于加载一些重复代码而造成的的开销。
2.1.1 客户端应用程序的目标
可插性
使用了Image I/O API 的应用程序应该具有无需任何重写和重编译既可自动使用新插件的能力。这就需要插件尽可能地遵守一系列格式中立的接口。然而,每种图像格式都有自己独有的且插件必须要可以暴露给应用程序的属性和功能。这将由允许插件扩展一系列API 的接口来实现。应用程序在不知道具体使用了哪个插件扩展之前,将继续以通常插件的情形去使用这些功能,而那些确定自己使用了具体插件的应用程序则可以使用被扩展的接口。
针对不同图像格式,不论是通常的还是插件专用的,对元数据(图片格式中除了图像数据以外的信息)获取,都由插件提供的元数据访问方法来实现。包括工业标准格式,由API定义的插件中立格式,以及插件专用格式。
插件的自动或手动选择及安装
对于通常无需用户干涉图片加载过程的简单应用程序来说,基于文件的内容自动选择对应的读取插件就很重要。然而,要令人满意,那么在用户不需要的时候,就得避免加载和实例化那些复杂的插件。插件必须能判定它是否可以在不必加载自己所有代码的时候就处理一张给定的图片。为了实现这个目标,插件们将由一种不加载插件主体代码就可以进行简单判定的服务提供者接口机制实例化。
所有同某个插件相关的二进制码(.class)文件应该被放在一个JAR包里,这样它就可以被永久性安装到Java运行时环境里,或者使用应用的CLASSPATH
机制被动态的载入。
手动插件选择
尽管自动插件选择对很多应用陈旭来说很方便,但对于许多更加专业的程序来说,对插件选择处理做更高级的控制也是必须要有的。该功能由应用程序自行判定和操作插件的运行时注册机制实现。
直接I/O、基于磁盘及网络
渐渐地,应用程序需要同时处理基于磁盘的和基于网络的数据。在很多时候,甚至基于磁盘的数据都会因为其他API的需要而通过某种InputSteam
被处理。Image I/O API 提供了一系列允许处理来自File
、InputSteam
或其他来源的数据的接口,从而保持前向后向查找的方式统一。API允许新的I/O接口,包括对图片获取及输出设备的直接接口直接使用而不需要重写程序代码。
访问元数据
在图片数据旁边的元数据有时和图片数据本身一样重要。Java Image I/O API 提供了对元数据灵活且彻底的访问。由于元数据可能会采用不同形式、并且包含专用的信息,所以提供对元数据直接访问的通用API是十分困难的。因此,API需要插件将它们的元数据转换为XML文档结构,也许会附加对对象的引用作为纹理数据的补充。一旦这些工作完成了,元数据就可以使用标准的XML DOM(文档对象模型)接口来进行访问和修改了。插件与插件之间文档的语法可能是不同的,但其结构却可以在对插件没有任何了解的情况下被展示、修改或遍历。
对高级应用程序的支持
为了支持高级应用程序,API必须支持访问诸如“缩略图”、单文件里储存的多张图片、多分辨率图像及瓦片拼接图形等功能。必须具有解码某张巨大图片中的某一部分的功能和在解码时进行二次抽样的功能,从而支持对极巨大图片的展示。当写入图片的时候,必须要保证不需要现将整张图片存入内存,而是按块切分,逐块写入图片。
2.1.2 服务器端使用的情况
动态图片生成
现代Web服务器通常动态地生成大部分内容。Java Servlet 和 Java Server Pages(JSP)的API提供了方便的根据来自网络浏览器请求,生成HTML页面响应的途径。给每个用户生成的自定义HTML可能都是不同的,针对图片内容的定制也是可以的。
在很多时候,需要动态的生成图片内容。例如,对股市价格图表的支持。尽管为每个列出的股票产生并保存有限数量个图表文件也是可行的,但如果允许用户进行自定义操作,比如价格所处的时间间隔需要显示出来或者需要对一个或多个股票之间进行价格的比较时,需要保存的图片个数将会变得无法预测。只用使用动态生成的途径才可能支持这种定制化。
图片定制化
网络图片通常是“一个大小适配所有”的,不管接受者的显示能力直接传送相同的图片数据。而激增的无线或手持设备需要定制化的适合他们有限显示宽度和显示能力的图片。桌面电脑频繁增加的显示分辨率,也会导致一些网络图片显得过小。缺乏可放缩图片的同样会给视力障碍的用户造成麻烦。服务器端图像定制化可基于用户偏好的分辨率、色彩特征为所有用户提供最佳化的图片,
2.2 非目标
线程安全
一个指定的ImageReader
或ImageWriter
实例不需要支持对其方法再进入的(同时的)调用(给后来调用的方法抛出异常,告诉它当前读取器或写入器正在被占用)。然而,同一个插件的多个实例同时进行操作是必须要支持的。出于简洁的目的,接下来我们只针对读取器插件进行讨论。
完全支持并发调用要求读取器将它所有的状态信息(例如当前的输入源)绑定到一个独立的状态对象中,从而工作中的方法可以使用另外一个独立进程修改了的下次操作使用的状态信息继续工作。
相比于强制要求每个ImageReader
用这种方式追踪保存他们自己的状态,倒不如简单地要求应用程序在需要多线程操作的时候实例化多个相同ImageReader
类的实例。这意味着每个ImageReader
的状态必须只使用非京台实例变量来保持,这对插件开发者来说应该不算是个负担。