如何在 Java 中将常见文档转换为 PNG 图像数组

简介: 如何在 Java 中将常见文档转换为 PNG 图像数组

如何使用 Java 中的 Web API 轻松地将各种常见文档格式转换为 PNG 图像数组。在进入本文的演示部分之前,我们将首先回顾一下将文档转换为不太灵活的格式背后的常见逻辑,并最终讨论 PNG 格式相对于其他常见格式(如 PDF 或 JPG)提供的优势。

为什么要将文档转换为不灵活的格式?

       针对文档编辑和操作优化的文件格式通常不会针对其他方案的效率进行优化。有一长串论据支持将此类文档转换为静态格式(如 PDF),用于文档编辑和操作以外的任何场景。

       内容安全是其中最有力的论据之一。设计为在编辑应用程序中打开和操作的文档格式在设计上保留了高度可访问和易于互换的属性,这意味着未经请求的第三方(即未知的陌生人)可以随意更改这些应用程序中的文档。其中技术娴熟的人甚至可以毫不费力地对常见的文档格式进行编程/自动更改。例如,不乏旨在解压缩和操作 XLSX、DOCX 或 PPTX 等开放式办公室 XML (OpenXML) 文件的 API 和库(我在之前的文章中已经写过很多)。以原始格式公开共享或显示 Office 文档会带来麻烦;在现实世界中,我们几乎看不到这样做是有原因的。

       当然,这不仅仅是关于安全性。复杂的 OpenXML 文件和其他类似的分层文档格式旨在将大量数据保留在一个地方(包括文本、链接、元数据和多媒体),这使得存储、传输或流式传输这些文件成为任何规模的负担。例如,如果我们要与网络中的利益相关者共享一系列最终确定的 Excel XLSX 报告(包括图形和数字),我们将在此过程中占用大量带宽,因此我们的传输速度会受到影响。如果我们将所有这些文件存储在一起而不压缩它们,我们将消耗不成比例的大量文件存储分配,随着时间的推移,这可能会证明成本很高——尤其是对于现代即用即付的云存储模型。同样,如果我们编写应用程序以将 Excel 文件管道传输到 Web 应用程序门户上基于 Web 的文件查看器(即,使用 iframe 标记),我们可能会大大减慢该页面的加载速度。

在现实世界中,这些挑战的结果是,大多数文档在进入存储、传输或流式处理状态之前,通常会转换为安全、静态且相对简单的格式。在大多数情况下,该格式为 PDF。

PDF的优缺点

       PDF 是大多数常见内容形式(尤其是 OpenXML 文档)事实上的发布格式,这是有充分理由的。它可以在任何 Web 浏览器上访问,并提供各种安全优势,同时与无数文件渲染和处理应用程序保持兼容。它可以结构为多媒体矢量文件或光栅(位图)文件,确保可以适应各种独特的内容类型,以适应同样广泛的显示方案。

       但是,PDF本身并不能立即解决的问题是压缩。PDF 仍然是相对复杂的文件,通常在其文件结构中存储布局、字体、矢量图形、文档历史记录和文档元数据。此外,光栅 PDF 以位图格式显示像素,默认情况下,该格式包含比其他图像类型更高的颜色深度范围(例如 24 位或 32 位)。这使得光栅 PDF 成为高质量静态文档内容显示和文档打印的绝佳选择,但对于轻量级存储和传输来说却不太有利。

选择PNG而不是JPG作为PDF替代品

       当 PDF 文件结构的特性和功能超出我们的需求时,我们可以将注意力转向更简单、重量更轻的格式选项。在这些选项中,有两种最常见的图像格式:PNG 和 JPG。

       这两种格式都提供了显着的压缩功能,JPG 比 PNG 在更大程度上做到了这一点。然而,对于JPG,这种压缩的成本要高得多。JPG 压缩算法试图通过删除一些我们通常不容易注意到的图像细节来减小文件大小,使用颜色子采样(即以低于亮度信息的分辨率存储颜色信息)和量化(即降低图像中颜色和亮度值的整体精度)等技术。随着时间的推移,JPG压缩变得越来越明显,这使得将详细文档转换为JPG屏幕截图成为一项冒险的工作。另一方面,PNG 牺牲了稍大的最终文件大小,以获得不会丢弃与图像质量相关的数据的压缩算法。PNG 压缩采用预测编码和像素值过滤等概念来优化图像数据,并使用 Deflate Compression 来识别图像数据中的重复模式,并用较短的代码替换这些模式。生成的 PNG 文件可能比 JPG 略大,但它们的质量可以保证随着时间的推移保持一致,使其成为存储和显示高质量文档内容的绝佳选择。

示范

       在本文的演示部分,我们将逐步学习如何调用免费 API,该 API 可自动检测各种输入文档类型(包括所有主要的 Office 文档格式、PDF 和 100 多种不同的图像格式)并将其转换为 PNG 图像数组。在实践中,它实际上是一种自动屏幕截图解决方案,我们可以直接将其插入到我们的 Java Web 应用程序中。它通过将 PNG 文件内容作为临时 URL 数组(每个 PNG 图像一个)返回来优化转换后的下载过程,随后可以下载这些 URL 并将其转换为文件字节。要使用此 API,我们只需要一个免费的 API 密钥,这将使我们每月使用 800 次 API 调用的限制。

要开始构建我们的 API 调用,我们将首先安装 Maven SDK(jitpack 用于动态编译库)。让我们在 pom.xml 中添加对存储库的引用。

XML格式

<repositories>
    <repository>
        <id>jitpack.io</id>
        <url>https://jitpack.io</url>
    </repository>
</repositories>

之后,让我们在 pom.xml 中添加对依赖项的引用:

XML格式

<dependencies>
<dependency>
    <groupId>com.github.Cloudmersive</groupId>
    <artifactId>Cloudmersive.APIClient.Java</artifactId>
    <version>v4.25</version>
</dependency>
</dependencies>

在下一步中,我们会将以下导入添加到文件顶部:

// Import classes:
//import com.cloudmersive.client.invoker.ApiClient;
//import com.cloudmersive.client.invoker.ApiException;
//import com.cloudmersive.client.invoker.Configuration;
//import com.cloudmersive.client.invoker.auth.*;
//import com.cloudmersive.client.ConvertDocumentApi;

之后,我们将添加配置代码段来捕获我们的 API 密钥:

ApiClient defaultClient = Configuration.getDefaultApiClient();
// Configure API key authorization: Apikey
ApiKeyAuth Apikey = (ApiKeyAuth) defaultClient.getAuthentication("Apikey");
Apikey.setApiKey("YOUR API KEY");
// Uncomment the following line to set a prefix for the API key, e.g. "Token" (defaults to null)
//Apikey.setApiKeyPrefix("Token");

最后,我们将添加以下代码片段以创建 API 实例并调用该函数进行转换:

ConvertDocumentApi apiInstance = new ConvertDocumentApi();
File inputFile = new File("/path/to/inputfile"); // File | Input file to perform the operation on.
try {
    AutodetectToPngResult result = apiInstance.convertDocumentAutodetectToPngArray(inputFile);
    System.out.println(result);
} catch (ApiException e) {
    System.err.println("Exception when calling ConvertDocumentApi#convertDocumentAutodetectToPngArray");
    e.printStackTrace();
}

我们可以通过几种不同的方式处理从临时 URL 到 PNG 文件字节的转换。我们可以使用以下代码进行辅助 API 调用(来自同一库并遵循与以前相同的基本结构)来处理该问题:

// Import classes:
//import com.cloudmersive.client.invoker.ApiClient;
//import com.cloudmersive.client.invoker.ApiException;
//import com.cloudmersive.client.invoker.Configuration;
//import com.cloudmersive.client.invoker.auth.*;
//import com.cloudmersive.client.EditDocumentApi;

ApiClient defaultClient = Configuration.getDefaultApiClient();

// Configure API key authorization: Apikey
ApiKeyAuth Apikey = (ApiKeyAuth) defaultClient.getAuthentication("Apikey");
Apikey.setApiKey("YOUR API KEY");
// Uncomment the following line to set a prefix for the API key, e.g. "Token" (defaults to null)
//Apikey.setApiKeyPrefix("Token");

EditDocumentApi apiInstance = new EditDocumentApi();
FinishEditingRequest reqConfig = new FinishEditingRequest(); // FinishEditingRequest | Cloudmersive Document URL to complete editing on
try {
    byte[] result = apiInstance.editDocumentFinishEditing(reqConfig);
    System.out.println(result);
} catch (ApiException e) {
    System.err.println("Exception when calling EditDocumentApi#editDocumentFinishEditing");
    e.printStackTrace();
}

或者,我们可以使用 from 类( 的基本部分)。这允许我们从文件 URL 创建一个 URL 对象,从 URL 读取和写入文件字节,并将字节流转换为可下载的文件内容。java.net.HttpURLConnectionjava.netJDK

       无论哪种情况,我们只需要将文件字节写入新的 PNG 文档,我们就可以轻松地在转换工作流程下游的任何位置存储、传输或流式传输该内容。

以静态图像格式存储、传输和流式传输文档的一些原因,并了解了 PNG 如何以 PDF 和 JPG 无法做到的方式提供轻量级无损压缩。


目录
相关文章
|
25天前
|
存储 人工智能 Java
打乱数组内容引发的问题( Java)
本文介绍了两种实现数组随机打乱的方法,并深入探讨了Java中原始数据类型与对象类型的差异。方法一通过自定义随机数交换数组元素位置,方法二借助`Collections.shuffle()`函数完成数组打乱。同时,文章详细解析了`int`和`Integer`的区别,包括声明方式、内存占用、初始化以及对象特性等,并讲解了自动装箱与拆箱的功能,帮助读者更好地理解Java的基础知识。
|
3月前
|
人工智能 Java
Java 中数组Array和列表List的转换
本文介绍了数组与列表之间的相互转换方法,主要包括三部分:1)使用`Collections.addAll()`方法将数组转为列表,适用于引用类型,效率较高;2)通过`new ArrayList&lt;&gt;()`构造器结合`Arrays.asList()`实现类似功能;3)利用JDK8的`Stream`流式计算,支持基本数据类型数组的转换。此外,还详细讲解了列表转数组的方法,如借助`Stream`实现不同类型数组间的转换,并附带代码示例与执行结果,帮助读者深入理解两种数据结构的互转技巧。
Java 中数组Array和列表List的转换
|
5月前
|
存储 Java 索引
Java快速入门之数组、方法
### Java快速入门之数组与方法简介 #### 一、数组 数组是一种容器,用于存储同种数据类型的多个值。定义数组时需指定数据类型,如`int[]`只能存储整数。数组的初始化分为静态和动态两种: - **静态初始化**:直接指定元素,系统自动计算长度,如`int[] arr = {1, 2, 3};` - **动态初始化**:手动指定长度,系统给定默认值,如`int[] arr = new int[3];` 数组访问通过索引完成,索引从0开始,最大索引为`数组.length - 1`。遍历数组常用`for`循环。常见操作包括求和、找最值、统计特定条件元素等。
|
3月前
|
存储 监控 Java
《从头开始学java,一天一个知识点》之:数组入门:一维数组的定义与遍历
**你是否也经历过这些崩溃瞬间?** - 看了三天教程,连`i++`和`++i`的区别都说不清 - 面试时被追问&quot;`a==b`和`equals()`的区别&quot;,大脑突然空白 - 写出的代码总是莫名报NPE,却不知道问题出在哪个运算符 这个系列就是为你打造的Java「速效救心丸」!我们承诺:每天1分钟,地铁通勤、午休间隙即可完成学习;直击痛点,只讲高频考点和实际开发中的「坑位」;拒绝臃肿,没有冗长概念堆砌,每篇都有可运行的代码标本。明日预告:《多维数组与常见操作》。 通过实例讲解数组的核心认知、趣味场景应用、企业级开发规范及优化技巧,帮助你快速掌握Java数组的精髓。
88 23
|
3月前
|
存储 Java 索引
Java 复制数组
本文介绍了Java中数组的基础知识与常用操作,包括数组的概念、创建、访问元素、遍历、复制、排序和搜索等方法。同时详细讲解了数组的五种赋值方式,并通过代码示例演示了求总和平均值、最大最小值、升序降序排序及Arrays类的常用方法。内容深入浅出,适合初学者学习掌握Java数组的核心功能与应用场景。
|
2月前
|
存储 Java 数据挖掘
Java 中数组的多种定义方式
本文深入解析了Java中数组的多种定义方式,涵盖基础的`new`关键字创建、直接初始化、动态初始化,到多维数组、`Arrays.fill()`方法以及集合类转换为数组等高级用法。通过理论与实践结合的方式,探讨了每种定义方法的适用场景、优缺点及其背后的原理,帮助开发者掌握高效、灵活的数组操作技巧,从而编写更优质的Java代码。
111 0
|
5月前
|
存储 Java C++
Java数组:静态初始化与动态初始化详解
本文介绍了Java中数组的定义、特点及初始化方式。
299 12
|
8月前
|
存储 缓存 算法
Java 数组
【10月更文挑战第19天】Java 数组是一种非常实用的数据结构,它为我们提供了一种简单而有效的方式来存储和管理数据。通过合理地使用数组,我们能够提高程序的运行效率和代码的可读性。更加深入地了解和掌握 Java 数组的特性和应用,为我们的编程之旅增添更多的精彩。
78 4
|
8月前
|
存储 缓存 算法
提高 Java 数组性能的方法
【10月更文挑战第19天】深入探讨了提高 Java 数组性能的多种方法。通过合理运用这些策略,我们可以在处理数组时获得更好的性能表现,提升程序的运行效率。
104 2
|
8月前
|
存储 Java
什么是带有示例的 Java 中的交错数组?
什么是带有示例的 Java 中的交错数组?
122 9