更新了wasm 支持了渐进式jpg

This commit is contained in:
kura 2025-11-28 11:05:01 +08:00
parent 408a1cd8d5
commit f9d6e45dc7
15 changed files with 55 additions and 4779 deletions

BIN
.DS_Store vendored

Binary file not shown.

7
.gitignore vendored Normal file
View File

@ -0,0 +1,7 @@
output/.DS_Store
output/output/.DS_Store
output/output/convert_image_to_webp(H5原始胶水代码).js
output/output/readme.md
output/output/utils(小程序兼容代码).js
output/output/256MB/convert_image_to_webp.js
output/output/512MB/convert_image_to_webp.wasm

View File

@ -3,6 +3,7 @@
"*.sdp": "xml",
"*.json": "jsonc",
"vector": "cpp",
"type_traits": "cpp"
"type_traits": "cpp",
"__config": "cpp"
}
}

View File

@ -1,10 +1,12 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "webp/encode.h" // WebP 头文件,用于编码 WebP
#include "stb_image.h" // stb_image 头文件,用于解码 PNG/JPG
#define STB_IMAGE_IMPLEMENTATION
#define STB_IMAGE_RESIZE_IMPLEMENTATION
#include "stb_image.h" // stb_image 头文件,用于解码 PNG/JPG
#include "stb_image_resize.h"
#include "webp/encode.h" // WebP 头文件,用于编码 WebP
extern "C" {
@ -14,7 +16,7 @@ extern "C" {
unsigned char *decoded_data = nullptr;
if (!is_original) {
decoded_data = stbi_load_from_memory(input_data, input_size, &width, &height, &channels, preserve_alpha ? 4 : 3); // 根据是否保留 alpha 通道加载
decoded_data = stbi_load_from_memory(input_data, input_size, &width, &height, &channels, 0); // 0自动判断是否保留 alpha 通道加载
} else {
decoded_data = (unsigned char *)input_data;
// 当使用原始数据时需要确保width和height已设置
@ -25,6 +27,7 @@ extern "C" {
// 使用 stb_image 解码输入图像(根据 preserve_alpha 决定加载通道数)
if (!decoded_data) {
// printf("stbi_failure_reason: %s\n", stbi_failure_reason());
return nullptr; // 图像解码失败
}
@ -32,7 +35,7 @@ extern "C" {
unsigned char *resized_data = decoded_data;
if (target_width > 0 && target_height > 0) {
// 分配用于存储调整大小后图像的缓冲区
resized_data = (unsigned char *)malloc(target_width * target_height * (preserve_alpha ? 4 : 3)); // 根据是否保留 alpha 通道调整缓冲区大小
resized_data = (unsigned char *)malloc(target_width * target_height * channels); // 根据是否保留 alpha 通道调整缓冲区大小
if (!resized_data) {
// 内存分配失败的处理
@ -43,7 +46,7 @@ extern "C" {
// 使用 stb_image_resize 调整图像大小
int result = stbir_resize_uint8(decoded_data, width, height, 0,
resized_data, target_width, target_height, 0, preserve_alpha ? 4 : 3);
resized_data, target_width, target_height, 0, channels);
if (!result) {
// 如果调整大小失败,释放已分配的内存
@ -59,9 +62,9 @@ extern "C" {
// 使用 libwebp 的有损编码函数WebPEncodeRGB将 RGB 图像编码为 WebP
unsigned char *webp_output = NULL;
if (preserve_alpha) {
if (channels == 4) {
*output_size = WebPEncodeRGBA(resized_data, target_width, target_height, target_width * 4, quality_factor, &webp_output);
} else {
} else if (channels == 3) {
*output_size = WebPEncodeRGB(resized_data, target_width, target_height, target_width * 3, quality_factor, &webp_output);
}

File diff suppressed because one or more lines are too long

BIN
output/convert_image_to_webp.wasm Executable file

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@ -7985,4 +7985,4 @@ AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
------------------------------------------------------------------------------
*/
*/

View File

@ -1,10 +1,11 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "webp/encode.h" // WebP 头文件,用于编码 WebP
#include "stb_image.h" // stb_image 头文件,用于解码 PNG/JPG
#define STB_IMAGE_IMPLEMENTATION
#define STB_IMAGE_RESIZE_IMPLEMENTATION
#include "stb_image.h" // stb_image 头文件,用于解码 PNG/JPG
#include "stb_image_resize.h"
#include "webp/encode.h" // WebP 头文件,用于编码 WebP
extern "C" {
@ -25,6 +26,7 @@ extern "C" {
// 使用 stb_image 解码输入图像(根据 preserve_alpha 决定加载通道数)
if (!decoded_data) {
printf("stbi_failure_reason: %s\n", stbi_failure_reason());
return nullptr; // 图像解码失败
}

View File

@ -1111,79 +1111,16 @@ function dbg(...args) {
var _emscripten_memcpy_js = (dest, src, num) => HEAPU8.copyWithin(dest, src, src + num);
var getHeapMax = () =>
// Stay one Wasm page short of 4GB: while e.g. Chrome is able to allocate
// full 4GB Wasm memories, the size will wrap back to 0 bytes in Wasm side
// for any code that deals with heap sizes, which would require special
// casing all heap size related code to treat 0 specially.
2147483648;
HEAPU8.length;
var growMemory = (size) => {
var b = wasmMemory.buffer;
var pages = (size - b.byteLength + 65535) / 65536;
try {
// round size grow request up to wasm page size (fixed 64KB per spec)
wasmMemory.grow(pages); // .grow() takes a delta compared to the previous size
updateMemoryViews();
return 1 /*success*/;
} catch(e) {
err(`growMemory: Attempted to grow heap from ${b.byteLength} bytes to ${size} bytes, but got error: ${e}`);
}
// implicit 0 return to save code size (caller will cast "undefined" into 0
// anyhow)
var abortOnCannotGrowMemory = (requestedSize) => {
abort(`Cannot enlarge memory arrays to size ${requestedSize} bytes (OOM). Either (1) compile with -sINITIAL_MEMORY=X with X higher than the current value ${HEAP8.length}, (2) compile with -sALLOW_MEMORY_GROWTH which allows increasing the size at runtime, or (3) if you want malloc to return NULL (0) instead of this abort, compile with -sABORTING_MALLOC=0`);
};
var _emscripten_resize_heap = (requestedSize) => {
var oldSize = HEAPU8.length;
// With CAN_ADDRESS_2GB or MEMORY64, pointers are already unsigned.
requestedSize >>>= 0;
// With multithreaded builds, races can happen (another thread might increase the size
// in between), so return a failure, and let the caller retry.
assert(requestedSize > oldSize);
// Memory resize rules:
// 1. Always increase heap size to at least the requested size, rounded up
// to next page multiple.
// 2a. If MEMORY_GROWTH_LINEAR_STEP == -1, excessively resize the heap
// geometrically: increase the heap size according to
// MEMORY_GROWTH_GEOMETRIC_STEP factor (default +20%), At most
// overreserve by MEMORY_GROWTH_GEOMETRIC_CAP bytes (default 96MB).
// 2b. If MEMORY_GROWTH_LINEAR_STEP != -1, excessively resize the heap
// linearly: increase the heap size by at least
// MEMORY_GROWTH_LINEAR_STEP bytes.
// 3. Max size for the heap is capped at 2048MB-WASM_PAGE_SIZE, or by
// MAXIMUM_MEMORY, or by ASAN limit, depending on which is smallest
// 4. If we were unable to allocate as much memory, it may be due to
// over-eager decision to excessively reserve due to (3) above.
// Hence if an allocation fails, cut down on the amount of excess
// growth, in an attempt to succeed to perform a smaller allocation.
// A limit is set for how much we can grow. We should not exceed that
// (the wasm binary specifies it, so if we tried, we'd fail anyhow).
var maxHeapSize = getHeapMax();
if (requestedSize > maxHeapSize) {
err(`Cannot enlarge memory, requested ${requestedSize} bytes, but the limit is ${maxHeapSize} bytes!`);
return false;
}
var alignUp = (x, multiple) => x + (multiple - x % multiple) % multiple;
// Loop through potential heap size increases. If we attempt a too eager
// reservation that fails, cut down on the attempted size and reserve a
// smaller bump instead. (max 3 times, chosen somewhat arbitrarily)
for (var cutDown = 1; cutDown <= 4; cutDown *= 2) {
var overGrownHeapSize = oldSize * (1 + 0.2 / cutDown); // ensure geometric growth
// but limit overreserving (default to capping at +96MB overgrowth at most)
overGrownHeapSize = Math.min(overGrownHeapSize, requestedSize + 100663296 );
var newSize = Math.min(maxHeapSize, alignUp(Math.max(requestedSize, overGrownHeapSize), 65536));
var replacement = growMemory(newSize);
if (replacement) {
return true;
}
}
err(`Failed to grow the heap from ${oldSize} bytes to ${newSize} bytes, not enough memory!`);
return false;
abortOnCannotGrowMemory(requestedSize);
};
var SYSCALLS = {
@ -1436,8 +1373,8 @@ var wasmImports = {
};
var wasmExports = createWasm();
var ___wasm_call_ctors = createExportWrapper('__wasm_call_ctors');
var _malloc = Module['_malloc'] = createExportWrapper('malloc');
var _free = Module['_free'] = createExportWrapper('free');
var _malloc = Module['_malloc'] = createExportWrapper('malloc');
var _convert_image_to_webp = Module['_convert_image_to_webp'] = createExportWrapper('convert_image_to_webp');
var _fflush = createExportWrapper('fflush');
var _emscripten_stack_init = () => (_emscripten_stack_init = wasmExports['emscripten_stack_init'])();
@ -1469,6 +1406,7 @@ var missingLibrarySymbols = [
'convertU32PairToI53',
'zeroMemory',
'exitJS',
'growMemory',
'isLeapYear',
'ydayFromDate',
'arraySum',
@ -1663,7 +1601,7 @@ var unexportedSymbols = [
'convertI32PairToI53Checked',
'ptrToString',
'getHeapMax',
'growMemory',
'abortOnCannotGrowMemory',
'ENV',
'MONTH_DAYS_REGULAR',
'MONTH_DAYS_LEAP',

Binary file not shown.

File diff suppressed because one or more lines are too long

View File

@ -13,10 +13,10 @@
<input type="file" id="imageUpload" accept="image/*" onchange="handleFileUpload(event)">
<br>
<label for="width">宽度:</label>
<input type="number" id="width" value="0">
<input type="number" id="width" value="1920">
<br>
<label for="height">高度:</label>
<input type="number" id="height" value="0">
<input type="number" id="height" value="1080">
<br>
<label for="quality">质量:</label>
<input type="number" id="quality" value="50" min="0" max="100">
@ -45,7 +45,7 @@
return btoa(binary); // 使用 JavaScript 的 btoa() 函数
}
var fileurl = './image.bin'
var fileurl = './img1.jpg'
// 初始化 WebAssembly 模块
var Module = {
onRuntimeInitialized: function () {
@ -102,11 +102,11 @@
* @param {number} qualityFactor - 压缩质量 (0 - 100)
*/
function decodeToWebpp(buffer, targetWidth = 0, targetHeight = 0, qualityFactor = 50) {
setTimeout(() => {
decodeItbyworker(buffer);
// setTimeout(() => {
// decodeItbyworker(buffer);
}, 1000);
return
// }, 1000);
// return
// 显示原始图片大小
let size = (buffer.byteLength / 1024).toFixed(2);
@ -119,7 +119,9 @@
// 设置目标宽高和质量因子
var inputDataPtr = Module._malloc(inputData.length);
Module.HEAPU8.set(inputData, inputDataPtr);
var webpPtr = Module._convert_image_to_webp(inputDataPtr, inputData.length, targetWidth, targetHeight, qualityFactor, outputSizePtr);
var webpPtr = Module._convert_image_to_webp(
inputDataPtr, inputData.length, 0,0,targetWidth, targetHeight, qualityFactor, outputSizePtr,0,0
);
// 调用 WebAssembly 函数进行图像转换,返回 WebP 数据指针
@ -142,16 +144,16 @@
Module._free(webpPtr);
Module._free(inputDataPtr);
}
var worker = new Worker('./worker.js');
worker.onmessage = function (e) {
console.log(e.data);
switch(e.data.type){
case 'webp':
let img = document.getElementById("webpImage");
img.src = "data:image/webp;base64," + arrayBufferToBase64(e.data.webpData);
break;
}
}
// var worker = new Worker('./worker.js');
// worker.onmessage = function (e) {
// console.log(e.data);
// switch(e.data.type){
// case 'webp':
// let img = document.getElementById("webpImage");
// img.src = "data:image/webp;base64," + arrayBufferToBase64(e.data.webpData);
// break;
// }
// }
function decodeItbyworker(buffer, width=0, height=0, quality=50) {
worker.postMessage({
buffer,

Binary file not shown.

4
生成
View File

@ -1,6 +1,6 @@
# 调试模式
docker run --rm -v $(pwd):/src emscripten/emsdk emcc convert_image_to_webp.cpp stb_image.c libwebp.a libsharpyuv.a libwebpdecoder.a libwebpdemux.a libwebpmux.a -o ./test/convert_image_to_webp.js -g -s WASM=1 -s INITIAL_MEMORY=20MB -s ALLOW_MEMORY_GROWTH=1 -s EXPORTED_FUNCTIONS="['_free','_malloc','_convert_image_to_webp']" -s EXTRA_EXPORTED_RUNTIME_METHODS='["cwrap", "getValue"]' -gsource-map
docker run --rm -v $(pwd):/src emscripten/emsdk emcc convert_image_to_webp.cpp libwebp.a libsharpyuv.a libwebpdecoder.a libwebpdemux.a libwebpmux.a -o ./test/convert_image_to_webp.js -g -s WASM=1 -s INITIAL_MEMORY=256MB -s EXPORTED_FUNCTIONS="['_free','_malloc','_convert_image_to_webp']" -s EXTRA_EXPORTED_RUNTIME_METHODS='["cwrap", "getValue"]' -gsource-map
# 优化后的命令
docker run --rm -v $(pwd):/src emscripten/emsdk emcc convert_image_to_webp.cpp stb_image.c libwebp.a libsharpyuv.a -o ./output/convert_image_to_webp.js -s WASM=1 -s NO_FILESYSTEM=1 -s INITIAL_MEMORY=512MB -s EXPORTED_FUNCTIONS="['_free','_malloc','_convert_image_to_webp']" -s EXTRA_EXPORTED_RUNTIME_METHODS='["cwrap", "getValue"]' -O2
docker run --rm -v $(pwd):/src emscripten/emsdk emcc convert_image_to_webp.cpp libwebp.a libsharpyuv.a -o ./output/convert_image_to_webp.js -s WASM=1 -s NO_FILESYSTEM=1 -s INITIAL_MEMORY=64MB -s EXPORTED_FUNCTIONS="['_free','_malloc','_convert_image_to_webp']" -s EXTRA_EXPORTED_RUNTIME_METHODS='["cwrap", "getValue"]' -O2