DEV Community

Cover image for HEIC 格式的圖片怎麼辦?使用 heic2any.js 轉換為 JPEG 或 PNG
Let's Write
Let's Write

Posted on • Edited on • Originally published at letswrite.tw

HEIC 格式的圖片怎麼辦?使用 heic2any.js 轉換為 JPEG 或 PNG

本篇要解決的問題

「本文介紹了如何使用 heic2any.js,一個 JavaScript 套件,可以將 HEIC 格式的圖片轉換為 JPEG 或 PNG 格式。同時提供了程式碼範例和使用方法,方便大家進行實際操作。」

上面那段是 ChatGPT 提供的頁面 description,因為看上去蠻有這麼一回事的,就拿來當本篇第一段重點。(是有沒有這麼懶)

簡單來說,就是前陣子 August 遇到了一個需求,要把 HEIC 的圖檔呈現在網頁上,也是因為遇到這個需求,才知道,咦?原來 HEIC 的圖片格式不能直接放在網頁上啊?(驚)

詢問了前同事後,知道了 heic2any.js 這個套件,然後進到套件的 GitHub 頁面後,咦?沒有寫使用說明啊?(驚 again)

然後,又因為懶,所以直接請 ChatGPT 寫一個 heic2any.js 的範例,結果,出來的程式碼是錯的!(驚 again * 2)

沒辦法,只好翻了一下套件的原始碼,再參考 ChatGPT 的寫法,去研究怎麼使用。

相信看到這篇的你,也是對官方沒有提供說明文件而感到震驚跟打擊,所以本篇除了會寫一個 Demo 出來,也會提供研究出來的程式碼。

大家取用本篇的程式碼前,希望可以分享本篇,或對 Demo 的 GitHub 專案打個星星。

畢竟這也是 August 花了時間整理出來的。

heic2any:https://github.com/alexcorvi/heic2any

本篇實作 Demo:https://letswritetw.github.io/letswrite-heic2any/


什麼是 HEIC?

以下是 ChatGPT 給的解釋:

HEIC 是 High Efficiency Image Format 的縮寫,是一種現代的圖像格式,由國際標準組織 MPEG(Moving Picture Experts Group)所定義。HEIC 格式通常使用在 iOS 11 及以上版本的 iPhone、iPad 和 macOS High Sierra 及以上版本的 Mac 上,作為照片和圖像的預設格式。

HEIC 格式相比傳統的 JPEG 格式具有更好的壓縮效率,可以在保持同樣圖像質量的情況下,大幅減小檔案大小。此外,HEIC 格式還支援更多的高級功能,例如多幅圖像的合成、深度圖和 Live Photo 等。

不過,HEIC 格式目前在一些應用上還存在一些限制,例如在某些瀏覽器和操作系統上無法直接顯示,需要進行轉換才能使用。因此,對於需要與多種平台和應用進行兼容性的使用者,可能需要將 HEIC 格式的圖片轉換為其他常見的圖像格式,例如 JPEG 或 PNG。

HEIC 格式的圖片在 Windows 和 Android 系統上也需要進行轉換才能直接顯示。

簡單來說,就是 iPhone、Mac 宇宙產出來的無生命但卻讓工程師處理起來要多一道工的格式。But,HEIC 格式比 JPEG 格式確實有很多優點,只是目前還存在一些兼容性問題,所以也不能說這個產物是投錯胎了。

大部份情況會是後端在收到圖,要存在圖庫或轉為 Base64 存在資料庫前,會先轉為 PNG 或 JPG 來儲存,之後 API 返回的圖檔路徑或是 Base64 就不會再是 HEIC。

不過,人生就是人生,難免會有存進去前漏了轉檔的意外,就會需要由前端來處理。


使用 heic2any.js

安裝 heic2any.js 的方式就跟我們使用其它 JavaScript 套件一樣,可以用 CDN 直接引用,或是用 npm package install 後再用 import 使用。

這邊,建議用 CDN 的方式,因為 heic2any.js 的檔案很~~~~大,未壓縮的檔案大小是 2.43 MB,壓縮過的也有 1.15 MB。用 CDN 來處理才不會對自己的主機產生太大的流量。

CDN

<script src="https://cdnjs.cloudflare.com/ajax/libs/heic2any/0.0.3/heic2any.min.js"></script>
Enter fullscreen mode Exit fullscreen mode

npm

$ npm install heic2any
或
$ yarn add heic2any
Enter fullscreen mode Exit fullscreen mode
import heic2any from 'heic2any';
Enter fullscreen mode Exit fullscreen mode

引用了 JS 後,使用 heic2any.js 的函式如下:

// 讀取圖片檔案
const file = document.querySelector('input[type=file]').files[0];

// 轉換圖片格式為 JPEG
heic2any.convert({
    blob: file,
    toType: 'image/jpeg',
    quality: 0.9
}).then(function(blob) {
    // 使用轉換後的 Blob 物件
    const imgSrc = URL.createObjectURL(blob);
}).catch(function (error) {
  // 轉換失敗時的處理
});
Enter fullscreen mode Exit fullscreen mode

toType:轉換成什麼格式,可以有 image/jpegimage/png,是 png 的話,quality 的參數會無效。

quality:轉檔後品質,只在 toTypeimage/jpeg 時有效,值是 0 - 1。


狀況 1:使用者從 iPhone 上傳圖

使用者從 iPhone 選取圖片然後上傳,有機會遇到檔案是 HEIC 的格式。

這時,可以在前端傳給後端前先轉檔,或是後端收到圖片後再轉檔。

本篇用 heic2any.js 就是前端轉好再給後端的方式。

呈現的結果可以在 Demo 頁上看到,這邊不再說明,直接上程式碼:

HTML

<input class="hidden" id="file" type="file" accept="image/heic"/>
Enter fullscreen mode Exit fullscreen mode

JS

const fileInput = document.getElementById('file');

fileInput.addEventListener('change', async (e) => {
    const type = document.getElementById('type').value;
    const file = e.target.files[0];
    const result = await heic2any({
      blob: file,
      toType: toType: 'image/jpeg',
      quality: 1
    });
    const uri = URL.createObjectURL(result);

    // 執行下載
    const filename = file.name.split('.heic')[0];
    const link = document.createElement('a');
    link.download = `檔名.${type}`;
    link.href = uri;
    link.click();

    // 清空 file input 的值
    fileInput.value = '';
});
Enter fullscreen mode Exit fullscreen mode

狀況 2:API 回應的圖檔,是 HEIC 的 Base64 格式

第二種狀況,之前使用者所傳的圖檔就是 HEIC 的格式,而後端在轉成 Base64 儲存前未轉檔,所以之後 API 給的圖片值是 HEIC 的。

JS

// imgBase64 就是 HEIC 的 Base64 值,因為太長,就只顯示開頭的部份
const imgBase64 = "data:image/heic;base64,AAAAGGZ0eXBoZ......";

// 用 fetch 將 Base64 轉成 blob
const base64ToBlob = await fetch(imgBase64).then(res => res.blob());
const defaultImg = await heic2any({
  blob: base64ToBlob,
  toType: 'image/jpeg',
  quality: 1
});

// 執行下載
const src = URL.createObjectURL(defaultImg);
const link = document.createElement('a');
link.download = `檔名.${type}`;
link.href = src;
link.click();
Enter fullscreen mode Exit fullscreen mode

這邊有一個偷懶的寫法,就是把 HEIC 的 Base64 用 fetch 的方式轉成 blob 格式。

之所以說懶,是因為用 fetch 只需要寫一行。

一般常看到轉 Base64 的方法其實是 atob()

const imgBase64 = "data:image/heic;base64,AAAAGGZ0eXBoZ......";

// 用 atob 將 Base64 轉為 blob
const base64ToBlob = (base64) => {
  const binary = atob(base64.split(',')[1]);
  const mime = base64.split(',')[0].match(/:(.*?);/)[1];
  const len = binary.length;
  const buffer = new ArrayBuffer(len);
  const view = new Uint8Array(buffer);
  for (let i = 0; i < len; i++) {
    view[i] = binary.charCodeAt(i);
  }
  return new Blob([buffer], { type: mime });
};

const defaultImg = await heic2any({
  blob: base64ToBlob(imgBase64),
  toType: 'image/jpeg',
  quality: 1
});
Enter fullscreen mode Exit fullscreen mode

本篇 Demo 及原始碼

本篇的程式碼有放上 GitHub 上,也用 GitHub Pages 產生了 Demo,請自行取用,但希望在取用前能分享本篇,或在 GitHub 上點個星星,你的一個小小動作對本站都是大大的鼓勵。

原始碼:https://github.com/letswritetw/letswrite-heic2any

Demo:https://letswritetw.github.io/letswrite-heic2any/

Heroku

Simplify your DevOps and maximize your time.

Since 2007, Heroku has been the go-to platform for developers as it monitors uptime, performance, and infrastructure concerns, allowing you to focus on writing code.

Learn More

Top comments (0)

Billboard image

The Next Generation Developer Platform

Coherence is the first Platform-as-a-Service you can control. Unlike "black-box" platforms that are opinionated about the infra you can deploy, Coherence is powered by CNC, the open-source IaC framework, which offers limitless customization.

Learn more