HEIC2OTHERS开发流程

首先的首先,放一下成品

前言

苹果推出的HEIC格式图片,在图像压缩率方面有极大的优势,比JPG格式图片占用空间小、画质更优。上传百度网盘时,保持原有HEIC格式上传,但在Windows系统下载时,仍然是HEIC,但HEIC对Windows支持不佳,因此还是需要转换为传统JPG格式图片。

由于需求是我母亲提出来的,较为硬核向的工具、需要一定代码基础的工具不可行,需要能够直接使用的。为此,我考虑过多种解决方法,但是现有的工具中,都有我不喜欢的部分。我讨厌需要下载的工具,因为它们几乎都含有大量广告,或者大量不需要的冗余功能;在线的转换网站往往上传速度堪忧,并且安全性也得不到保障。

我首先考虑到的解决方式是使用Python或Java开发一个小客户端,因为有这方面的基础,以前也给我母亲写过办公自动化的工具,但是Python和Java的打包较为麻烦,工具的体量也十分巨大。虽然这个问题是可以容忍的问题,但是实际刚着手,便发现 pyheif工具仅支持Mac或Linux操作系统,作者也明确说明了不会支持Windows,因此这种方法也排除了。

后来我又去网上寻找解决方案,比较多的解决方案是基于 heif2any,也提供了相应的在线转换工具,但是示例网站只能转换GIF格式,不能完全满足需求。

我以前没有接触过前端的一切东西,唯一在本科选修过面向包括文体美专业在内的所有人开放的动态网站制作课,现在回看,就是上课做了一个静态网页,用markdown完全可以胜任这个课上的全部内容。由于零基础,不是很确定自己能完成这个工具的开发。

不过解决方案仅此一个,也正好最近对开发感兴趣,同时学学前端的东西,经过一天多的折腾,解决了大大小小的bug,终于是开发完成了。中间很多问题都没有记下来,要么随手解决了,要么尝试了无数种解决方案之后难以静下心来归纳。

本文是这个工具的开发流程,并不全面,仅供参考。

依赖安装

在对应Project的文件夹内安装 heic2any

1
npm install heic2any

自动局部安装于 node_modules 文件夹内,同时生成 package.jsonpackage-lock.json 文件

转换过程

参考https://github.com/alexcorvi/heic2any/blob/master/docs/getting-started.md提供的转换过程

将转换过程写在新的 .js 文件中,在 html 中通过 <script src=""> 的方式引入脚本文件

1
<script type="module" src="./heics2jpgs.js"></script>

使用官方doc的示例代码,以及此文对于Fetch中下载Blob的应用示例,可以运行代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
fetch(para_path)
.then((res) => res.blob())
.then((blob) =>
heic2any({
blob,
toType: para_format,
quality : para_rate
})
)
.then((conversionResult) => {
// conversionResult is a BLOB
// of the PNG formatted image
let a = document.createElement("a");
a.href = URL.createObjectURL(conversionResult);
a.download = file_name + "." + file_type;
a.style.display = "none";
document.body.appendChild(a);
a.click();
URL.revokeObjectURL(a.href); // 释放URL 对象
a.remove();
})
.catch((e) => {
// see error handling section
console.log(e);
});

经过测试,原图尺寸约为2.8M时,转为JPG后图像尺寸约为18M,这是由于HEIC的先进压缩算法,使得原图可以很小,而转为JPG后压缩算法的压缩率下降,是正常现象。

前端页面

在写好前端页面中的几个选项之后,开始考虑js和HTML的交互,其中遇到了各种问题,包括依赖包格式、找不到对应函数等。

经过各种暴露包、修改路径的尝试,未果,发现在 <script> 中定义 type="module" 后,便无法和 <button>onclick 进行交互了。

同类问题

最终,不适用外部js文件,而是在 html 内部使用,通过 import 的方式引入

1
2
import {convert} from './convert.js';
document.querySelector('#hello').addEventListener('click', convert)

成功引入,能够调用对应 import 的js文件中的方法

数据传递

html 中获取的信息,需要传递到 .js 文件中

前端收集信息的模块有唯一的Attribute id ,因此可以在.js 文件中获取

1
document.getElementById("element_id").value;

根据参考中的内容,这部分好像并不算参数传递,而是直接获取到的

数据处理

传递来的信息有压缩率、图片路径、目标格式,需要对其进行预处理

  • 目标格式

    目标格式在前端已经进行过处理,用户选择后传递的值即为 image/jpg 字符串,无需额外处理

  • 图片路径

    路径传递后,接收到的文件名是正常的,但是路径是有问题的,会有 c:\fakepath\ ,是错误的绝对路径。

    暂时先不处理,使用与 html 同路径的方法

    如果通过

    1
    document.getElementById("files").value;

    则获取的是第一个文件带有 fakepath 的路径,因此需要使用 files 属性获取multiple

  • 压缩率

    压缩率通过 parseFloat() 更改格式

部署

新建一个Git项目 heic2others,增加Page界面

此后就可以通过 smy1999.github.io/heic2others/ 访问了

遇到了GItHub Pages无法读取 node_modules 下js文件的问题,已解决

修改关键流程

上线部署到Github Pages后,发现fetch只能读取url,不能读取本地文件,之前在本地测试的时候,文件也都是在Project的目录中,使用绝对路径之后发现并不能成功读取到文件,于是决定不再使用heic2any提供的流程。

事实上,从 <input type="file" multiple> 读取到的已经是 FileList 格式的文件信息,文件已经被读入前端了,此前的方式多此一举地从文件中提取了文件名,再次使用 Fetch 加载文件。

由于 heic2any 的输入是 blobblob[],起初考虑将 FIle 转换为 blob 输入,经过查询发现, File 已经是 blob 的子类,因此直接将 File 和其他参数传入 heic2any

heic2any 的返回值是 Promise<blob | blob[]> 的格式,通过 .then() 的方式获取其 PromiseResult 属性值,也就是转换后的 blob,将这个 blob 再使用 URL下载。

优化方向

  • 文件批量下载
  • 前端界面优化
  • 稳定性增强

Reference

https://www.mulingyuer.com/archives/553/

https://github.com/alexcorvi/heic2any/blob/master/docs/getting-started.md

值传递:https://stackoverflow.com/questions/21397743/passing-html-input-value-as-a-javascript-function-parameter