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

閱讀時間約 11 分鐘

本篇要解決的問題

「本文介紹了如何使用 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 花了時間整理出來的。

什麼是 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>
npm
$ npm install heic2any
$ yarn add heic2any
import heic2any from 'heic2any';
引用了 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) {
  // 轉換失敗時的處理
});
toType:轉換成什麼格式,可以有 image/jpeg、image/png,是 png 的話,quality 的參數會無效。
quality:轉檔的品質,只在 toType 是 image/jpeg 時有效,值是 0 – 1。

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

使用者從 iPhone 選取圖片然後上傳,有機會遇到檔案是 HEIC 的格式。
這時,可以在前端傳給後端前先轉檔,或是後端收到圖片後再轉檔。
本篇用 heic2any.js 就是前端轉好再給後端的方式。
呈現的結果可以在 Demo 頁上看到,這邊不再說明,直接上程式碼:
HTML
<input class="hidden" id="file" type="file" accept="image/heic"/>
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 = '';
});

狀況 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();
這邊有一個偷懶的寫法,就是把 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
});

本篇 Demo 及原始碼

本篇的程式碼有放上 GitHub 上,也用 GitHub Pages 產生了 Demo,請自行取用,但希望在取用前能分享本篇,或在 GitHub 上點個星星,你的一個小小動作對本站都是大大的鼓勵。
9會員
19內容數
沙龍到底是…做什麼用的勒?
留言0
查看全部
發表第一個留言支持創作者!
你可能也想看
Google News 追蹤
Thumbnail
這個秋,Chill 嗨嗨!穿搭美美去賞楓,裝備款款去露營⋯⋯你的秋天怎麼過?秋日 To Do List 等你分享! 秋季全站徵文,我們準備了五個創作主題,參賽還有機會獲得「火烤兩用鍋」,一起來看看如何參加吧~
Thumbnail
美國總統大選只剩下三天, 我們觀察一整週民調與金融市場的變化(包含賭局), 到本週五下午3:00前為止, 誰是美國總統幾乎大概可以猜到60-70%的機率, 本篇文章就是以大選結局為主軸來討論近期甚至到未來四年美股可能的改變
Thumbnail
Faker昨天真的太扯了,中國主播王多多點評的話更是精妙,分享給各位 王多多的點評 「Faker是我們的處境,他是LPL永遠繞不開的一個人和話題,所以我們特別渴望在決賽跟他相遇,去直面我們的處境。 我們曾經稱他為最高的山,最長的河,以為山海就是盡頭,可是Faker用他28歲的年齡...
Thumbnail
全書主旨用圖表說好故事、強調有條理的重要性,以五個章節著重視覺呈現與表達,從各種視覺元素圖表的說明、視覺認知的去蕪存菁,到以整體設計師思維檢視圖表呈現,再以範例解析何謂美、接受度高的圖表。最後幾章節則組織整份簡報,教讀者怎麼說故事、怎麼編排敘事架構,並附上實際改造前後的案例,讓讀者從頭到尾一氣呵成。
Thumbnail
當人什麼都相信的時候,也代表他什麼都不信。從小生長於印度教信仰家庭的Pi,同時信仰著基督教、伊斯蘭教,他遵循著每種宗教的儀式,禮拜、用餐前禱告,而他的父親對他說:「當人什麼都相信的時候,也代表他什麼都不信。」
Thumbnail
要相信人會改變,要相信人會變好。―楊斯棓​ 看完這本書後才明白原來在臺灣有那麼多溫情的故事,有這麼多位臺灣醫療、民主無私奉獻的仁醫烈士們,讀完後內心有滿滿澎湃的情緒,許多的感謝跟感動,讓這張圖卡以跟過往不同的新風貌呈現。
Thumbnail
大多數人應該都可以同意巴黎是一個很有魅力的城市, 不管有去過,沒去過。 如果去法國旅形沒去巴黎逛逛, 就好像從來沒去到過這個國家一樣。 作者在前言就詳述了他作為一個「思想導遊」的可能性, 有愉快的導覽,豐富的故事,也會有深入分析的內容。
Thumbnail
不斷的寫,不斷的創作,這就是他應對生活的方式
★即使讀來令人衝擊,卻是許多人曾經或正在經歷的傷痛。 正視這些暴力,才能避免下一次傷害。 獻給每一個在日常中感受到「不對勁」的你我。 ●20則真實性暴力受害者的故事,有些來自線上匿名投稿,有些是由作者訪談紀錄。每則故事的主角年齡、性別、所處情境都各不相同;施暴者可能是熟人、陌生人、或親密關係中的人,
Thumbnail
看圖說故事來解釋股價表現,其實更接近是投機而不是投資,如果可以帶來穩定的獲利,投機沒有甚麼不好,怕的是沒有認清楚自己是在投資或投機,或是做投機的行為卻自以為是投資,混淆兩者的邏輯
Thumbnail
111學測國寫的參考試卷卷一第二題,題目給了一張名為〈炙艾圖〉的畫作,並且請考生們要觀察畫中的人物,編一則有角色、對白、情節等三要素的故事。 桃花源記雖然沒有明顯的角色塑造,但是它也是個故事,故事編寫的題材對於許多同學而言可能是非常陌生的考題,國中時代的作文訓練也鮮少有這樣的題材,那麼我們就從桃花源
Thumbnail
每週一是「園丁與花」定期開會的日子,在今天的會議中,我們接續討論上週的事項,更深入地交流彼此對於「園丁與花」的看法,以及之後即將進行的計畫。另外,今天分享的速寫本內頁,紀錄了畫出有故事的圖畫的基本步驟。假如有人好奇,在沒有任何想法的情況下,要如何透過圖畫說故事,也許今天的速寫本內頁可以提供一些靈感。
Thumbnail
    最近很喜歡用HyRead 3電子書閱讀,只要登錄住家附近或學校的借書證就可以免費閱讀,真的很方便,而且可以借閱的書籍也很充足。偶然間翻閱到這本《這不是沒關係 20則性暴力受害者的圖像故事》便決定透過作者筆下的圖像了解這二十則性暴力受害者的故事。
Thumbnail
這個秋,Chill 嗨嗨!穿搭美美去賞楓,裝備款款去露營⋯⋯你的秋天怎麼過?秋日 To Do List 等你分享! 秋季全站徵文,我們準備了五個創作主題,參賽還有機會獲得「火烤兩用鍋」,一起來看看如何參加吧~
Thumbnail
美國總統大選只剩下三天, 我們觀察一整週民調與金融市場的變化(包含賭局), 到本週五下午3:00前為止, 誰是美國總統幾乎大概可以猜到60-70%的機率, 本篇文章就是以大選結局為主軸來討論近期甚至到未來四年美股可能的改變
Thumbnail
Faker昨天真的太扯了,中國主播王多多點評的話更是精妙,分享給各位 王多多的點評 「Faker是我們的處境,他是LPL永遠繞不開的一個人和話題,所以我們特別渴望在決賽跟他相遇,去直面我們的處境。 我們曾經稱他為最高的山,最長的河,以為山海就是盡頭,可是Faker用他28歲的年齡...
Thumbnail
全書主旨用圖表說好故事、強調有條理的重要性,以五個章節著重視覺呈現與表達,從各種視覺元素圖表的說明、視覺認知的去蕪存菁,到以整體設計師思維檢視圖表呈現,再以範例解析何謂美、接受度高的圖表。最後幾章節則組織整份簡報,教讀者怎麼說故事、怎麼編排敘事架構,並附上實際改造前後的案例,讓讀者從頭到尾一氣呵成。
Thumbnail
當人什麼都相信的時候,也代表他什麼都不信。從小生長於印度教信仰家庭的Pi,同時信仰著基督教、伊斯蘭教,他遵循著每種宗教的儀式,禮拜、用餐前禱告,而他的父親對他說:「當人什麼都相信的時候,也代表他什麼都不信。」
Thumbnail
要相信人會改變,要相信人會變好。―楊斯棓​ 看完這本書後才明白原來在臺灣有那麼多溫情的故事,有這麼多位臺灣醫療、民主無私奉獻的仁醫烈士們,讀完後內心有滿滿澎湃的情緒,許多的感謝跟感動,讓這張圖卡以跟過往不同的新風貌呈現。
Thumbnail
大多數人應該都可以同意巴黎是一個很有魅力的城市, 不管有去過,沒去過。 如果去法國旅形沒去巴黎逛逛, 就好像從來沒去到過這個國家一樣。 作者在前言就詳述了他作為一個「思想導遊」的可能性, 有愉快的導覽,豐富的故事,也會有深入分析的內容。
Thumbnail
不斷的寫,不斷的創作,這就是他應對生活的方式
★即使讀來令人衝擊,卻是許多人曾經或正在經歷的傷痛。 正視這些暴力,才能避免下一次傷害。 獻給每一個在日常中感受到「不對勁」的你我。 ●20則真實性暴力受害者的故事,有些來自線上匿名投稿,有些是由作者訪談紀錄。每則故事的主角年齡、性別、所處情境都各不相同;施暴者可能是熟人、陌生人、或親密關係中的人,
Thumbnail
看圖說故事來解釋股價表現,其實更接近是投機而不是投資,如果可以帶來穩定的獲利,投機沒有甚麼不好,怕的是沒有認清楚自己是在投資或投機,或是做投機的行為卻自以為是投資,混淆兩者的邏輯
Thumbnail
111學測國寫的參考試卷卷一第二題,題目給了一張名為〈炙艾圖〉的畫作,並且請考生們要觀察畫中的人物,編一則有角色、對白、情節等三要素的故事。 桃花源記雖然沒有明顯的角色塑造,但是它也是個故事,故事編寫的題材對於許多同學而言可能是非常陌生的考題,國中時代的作文訓練也鮮少有這樣的題材,那麼我們就從桃花源
Thumbnail
每週一是「園丁與花」定期開會的日子,在今天的會議中,我們接續討論上週的事項,更深入地交流彼此對於「園丁與花」的看法,以及之後即將進行的計畫。另外,今天分享的速寫本內頁,紀錄了畫出有故事的圖畫的基本步驟。假如有人好奇,在沒有任何想法的情況下,要如何透過圖畫說故事,也許今天的速寫本內頁可以提供一些靈感。
Thumbnail
    最近很喜歡用HyRead 3電子書閱讀,只要登錄住家附近或學校的借書證就可以免費閱讀,真的很方便,而且可以借閱的書籍也很充足。偶然間翻閱到這本《這不是沒關係 20則性暴力受害者的圖像故事》便決定透過作者筆下的圖像了解這二十則性暴力受害者的故事。