使用JavaScript將JPG格式圖片轉(zhuǎn)為BMP格式的完整代碼
將 JPG 轉(zhuǎn)換為 BMP 的核心邏輯與 PNG 轉(zhuǎn) BMP 一致(都是通過 Canvas 讀取像素后按 BMP 格式組裝字節(jié)),僅需調(diào)整文件選擇的 accept 類型,且 JPG 本身無 Alpha 通道,轉(zhuǎn)換時(shí)無需額外處理透明通道,兼容性更優(yōu)。以下是完整可運(yùn)行的實(shí)現(xiàn)方案:
完整代碼(JPG 轉(zhuǎn) BMP)
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>JPG 轉(zhuǎn) BMP</title>
</head>
<body>
<input type="file" id="fileInput" accept="image/jpeg,image/jpg">
<button id="convertBtn" disabled>轉(zhuǎn)換為 BMP</button>
<script>
let imageData = null;
const fileInput = document.getElementById('fileInput');
const convertBtn = document.getElementById('convertBtn');
// 監(jiān)聽文件選擇(支持 JPG/JPEG)
fileInput.addEventListener('change', async (e) => {
const file = e.target.files[0];
if (!file || !['image/jpeg', 'image/jpg'].includes(file.type)) {
alert('請(qǐng)選擇 JPG/JPEG 格式圖片');
return;
}
imageData = await getImageData(file);
convertBtn.disabled = false;
});
// 轉(zhuǎn)換并下載 BMP
convertBtn.addEventListener('click', () => {
if (!imageData) return;
const bmpBlob = jpgToBmp(imageData);
downloadBlob(bmpBlob, 'converted.bmp');
});
/**
* 讀取 JPG 圖片并獲取 Canvas ImageData
* @param {File} file - JPG 文件
* @returns {Promise<ImageData>} 像素?cái)?shù)據(jù)
*/
function getImageData(file) {
return new Promise((resolve) => {
const img = new Image();
img.crossOrigin = 'anonymous'; // 解決跨域(本地文件無需,在線需配置)
img.onload = () => {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
canvas.width = img.width;
canvas.height = img.height;
ctx.drawImage(img, 0, 0);
resolve(ctx.getImageData(0, 0, img.width, img.height));
};
img.src = URL.createObjectURL(file);
});
}
/**
* 將 ImageData 轉(zhuǎn)換為 24 位無壓縮 BMP Blob
* @param {ImageData} imageData - Canvas 像素?cái)?shù)據(jù)
* @returns {Blob} BMP 格式 Blob
*/
function jpgToBmp(imageData) {
const { width, height, data } = imageData;
// 計(jì)算每行字節(jié)數(shù)(4字節(jié)對(duì)齊)
const rowBytes = Math.floor((24 * width + 31) / 32) * 4;
const pixelDataSize = rowBytes * height;
const totalFileSize = 14 + 40 + pixelDataSize; // BMP 總大小
// 創(chuàng)建 ArrayBuffer 存儲(chǔ) BMP 數(shù)據(jù)
const buffer = new ArrayBuffer(totalFileSize);
const dv = new DataView(buffer);
// ------------------- 1. 寫入 BMP 文件頭(14字節(jié)) -------------------
dv.setUint8(0, 0x42); // 'B'
dv.setUint8(1, 0x4D); // 'M'
dv.setUint32(2, totalFileSize, true); // 文件總大?。ㄐ《诵颍?
dv.setUint16(6, 0, true); // 保留字段1
dv.setUint16(8, 0, true); // 保留字段2
dv.setUint32(10, 54, true); // 像素?cái)?shù)據(jù)偏移(14+40)
// ------------------- 2. 寫入 BMP 信息頭(40字節(jié),BITMAPINFOHEADER) -------------------
dv.setUint32(14, 40, true); // 信息頭大小
dv.setInt32(18, width, true); // 寬度
dv.setInt32(22, -height, true); // 高度(負(fù)數(shù)=從上到下繪制)
dv.setUint16(26, 1, true); // 平面數(shù)=1
dv.setUint16(28, 24, true); // 位深度=24(無Alpha)
dv.setUint32(30, 0, true); // 壓縮方式=無壓縮(BI_RGB)
dv.setUint32(34, pixelDataSize, true); // 像素?cái)?shù)據(jù)大小
dv.setInt32(38, 2835, true); // 水平分辨率(96 DPI)
dv.setInt32(42, 2835, true); // 垂直分辨率(96 DPI)
dv.setUint32(46, 0, true); // 調(diào)色板顏色數(shù)=0(24位無需)
dv.setUint32(50, 0, true); // 重要顏色數(shù)=0
// ------------------- 3. 寫入像素?cái)?shù)據(jù)(BGR 格式 + 行對(duì)齊) -------------------
let offset = 54; // 像素?cái)?shù)據(jù)起始偏移
for (let y = 0; y < height; y++) {
for (let x = 0; x < width; x++) {
const pixelIdx = (y * width + x) * 4;
dv.setUint8(offset++, data[pixelIdx + 2]); // 藍(lán)通道(B)
dv.setUint8(offset++, data[pixelIdx + 1]); // 綠通道(G)
dv.setUint8(offset++, data[pixelIdx]); // 紅通道(R)
// JPG 無 Alpha,24位 BMP 也無需存儲(chǔ) Alpha
}
// 補(bǔ)充行對(duì)齊的 0 字節(jié)(確保每行字節(jié)數(shù)是4的倍數(shù))
const padding = rowBytes - (width * 3);
for (let p = 0; p < padding; p++) {
dv.setUint8(offset++, 0);
}
}
// 返回 BMP Blob(MIME 類型為 image/bmp)
return new Blob([buffer], { type: 'image/bmp' });
}
/**
* 下載 Blob 文件到本地
* @param {Blob} blob - BMP 格式 Blob
* @param {string} fileName - 下載文件名
*/
function downloadBlob(blob, fileName) {
const a = document.createElement('a');
a.href = URL.createObjectURL(blob);
a.download = fileName;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(a.href); // 釋放內(nèi)存
}
</script>
</body>
</html>
使用步驟
- 將代碼保存為
.html文件,用瀏覽器打開; - 點(diǎn)擊文件選擇框,選擇任意 JPG/JPEG 圖片;
- 點(diǎn)擊「轉(zhuǎn)換為 BMP」按鈕,自動(dòng)下載轉(zhuǎn)換后的 BMP 文件。
關(guān)鍵注意事項(xiàng)
- 跨域問題:若在線使用(非本地文件),需確保 JPG 圖片所在服務(wù)器配置了
Access-Control-Allow-Origin響應(yīng)頭,否則 Canvas 無法讀取像素?cái)?shù)據(jù); - 位深度:示例生成 24 位 BMP(最通用,無 Alpha),如需 32 位 BMP(帶 Alpha),只需修改:
- 信息頭
biBitCount(偏移 28)改為 32; - 像素?cái)?shù)據(jù)寫入時(shí)增加 Alpha 通道:
dv.setUint8(offset++, data[pixelIdx + 3]);; - 行字節(jié)數(shù)公式改為
Math.floor((32 * width + 31) / 32) * 4(32位每行天然4字節(jié)對(duì)齊,無需補(bǔ)0);
- 信息頭
- 性能優(yōu)化:處理超大 JPG(如 4K/8K)時(shí),可分片讀取像素?cái)?shù)據(jù),避免瀏覽器卡頓;
- 瀏覽器兼容:支持所有現(xiàn)代瀏覽器(Chrome/Firefox/Edge/Safari),IE 不支持
Blob/DataView,需兼容 IE 需額外適配。
驗(yàn)證轉(zhuǎn)換結(jié)果
轉(zhuǎn)換后的 BMP 文件可通過以下方式驗(yàn)證:
- 用系統(tǒng)自帶畫圖工具打開,能正常顯示則格式正確;
- 用十六進(jìn)制編輯器查看文件開頭,前 2 字節(jié)應(yīng)為
42 4D(BM 標(biāo)識(shí))。
到此這篇關(guān)于使用JavaScript將JPG格式圖片轉(zhuǎn)為BMP格式的完整代碼的文章就介紹到這了,更多相關(guān)JavaScript JPG格式轉(zhuǎn)為BMP格式內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
js設(shè)置隨機(jī)切換背景圖片的簡(jiǎn)單實(shí)例
下面小編就為大家?guī)硪黄猨s設(shè)置隨機(jī)切換背景圖片的簡(jiǎn)單實(shí)例。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-11-11
微信小程序與webview交互實(shí)現(xiàn)支付功能
這篇文章主要介紹了微信小程序與webview交互實(shí)現(xiàn)支付功能,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用小程序具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧2019-06-06
JavaScript實(shí)現(xiàn)圖片輪播組件代碼示例
本篇文章主要介紹了JavaScript實(shí)現(xiàn)圖片輪播組件代碼示例,對(duì)圖片輪播效果感興趣的小伙伴們可以參考一下。2016-11-11
javascript阻止scroll事件多次執(zhí)行的思路及實(shí)現(xiàn)
阻止scroll事件多次執(zhí)行主要是為了解決一些常見網(wǎng)頁特效在js解析時(shí)預(yù)期與效果不同,感興趣的朋友可以了解下2013-11-11
typescript在node.js下使用別名(paths)無效的問題詳解
這篇文章主要給大家介紹了關(guān)于typescript在node.js下使用別名(paths)無效問題的相關(guān)資料,文中通過圖文以及示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2022-07-07
微信小程序?qū)崿F(xiàn)瀑布流分頁滾動(dòng)加載
這篇文章主要為大家詳細(xì)介紹了微信小程序?qū)崿F(xiàn)瀑布流分頁滾動(dòng)加載,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-09-09
JS實(shí)現(xiàn)table表格內(nèi)針對(duì)某列內(nèi)容進(jìn)行即時(shí)搜索篩選功能
這篇文章主要介紹了JS實(shí)現(xiàn)table表格內(nèi)針對(duì)某列內(nèi)容進(jìn)行即時(shí)搜索篩選功能,涉及javascript針對(duì)HTML元素的遍歷、屬性動(dòng)態(tài)修改相關(guān)操作技巧,需要的朋友可以參考下2018-05-05

