编译为 WebAssembly 时无法使 image::load_from_memory() 工作

2024-04-16

我正在尝试使用 Rust 将图像从 JavaScript 加载到 WebAssembly图像箱 https://crates.io/crates/image.

我有以下 Rust 代码:

extern crate image;
extern crate libc;

use libc::c_void;
use std::mem;

#[no_mangle]
pub extern "C" fn alloc(size: usize) -> *mut c_void {
    let mut buf = Vec::with_capacity(size);
    let ptr = buf.as_mut_ptr();
    mem::forget(buf);

    return ptr as *mut c_void;
}

#[no_mangle]
pub extern "C" fn read_img(buff_ptr: *mut u8, buff_len: usize) -> *mut i32 {
    let mut img: Vec<u8> = unsafe { Vec::from_raw_parts(buff_ptr, buff_len, buff_len) };
    let ok = Box::new([333]);
    let err = Box::new([331]);

    return match image::load_from_memory(&img) {
        Ok(img) => Box::into_raw(ok) as *mut i32,
        Err(_) => Box::into_raw(err) as *mut i32,
    };
}

fn main() {}

我使用以下工具进行编译:

cargo +nightly build --target wasm32-unknown-unknown --release

In the read_img()函数中,我天真地通过两个向量处理错误:[333]为确定和[331]对于任何错误。我在 JavaScript 端读取这些向量来了解图像是否已成功加载。

The load_from_memory方法失败,因为我得到了[331]向量。如果我更换load_from_memory方法与guess_format方法,我得到[333]向量。我还对 PNG 和 JPG 进行了一些模式匹配,它正确读取了缓冲区。

我找不到如何更彻底地调试这种行为。

在 JavaScript 部分,我只需加载图像的arrayBuffer进入 WASM 的共享内存。

这是我在 JavaScript 方面所做的事情:

function compile(wasmFile = 'distil_wasm.gc.wasm') {
    return fetch(wasmFile)
        .then(r => r.arrayBuffer())
        .then(r => {
            let module = new WebAssembly.Module(r);
            let importObject = {}
            for (let imp of WebAssembly.Module.imports(module)) {
                if (typeof importObject[imp.module] === "undefined")
                    importObject[imp.module] = {};
                switch (imp.kind) {
                case "function": importObject[imp.module][imp.name] = () => {}; break;
                case "table": importObject[imp.module][imp.name] = new WebAssembly.Table({ initial: 256, maximum: 256, element: "anyfunc" }); break;
                case "memory": importObject[imp.module][imp.name] = new WebAssembly.Memory({ initial: 256 }); break;
                case "global": importObject[imp.module][imp.name] = 0; break;
                }
            }

            return WebAssembly.instantiate(r, importObject);
        });
}

function loadImgIntoMem(img, memory, alloc) {
    return new Promise(resolve => {
        fetch(img)
            .then(r => r.arrayBuffer())
            .then(buff => {
                const imgPtr = alloc(buff.byteLength);
                const imgHeap = new Uint8Array(memory.buffer, imgPtr, buff.byteLength);

                imgHeap.set(new Uint8Array(buff));

                resolve({ imgPtr, len: buff.byteLength });
            });
    });
}


function run(img) {
    return compile().then(m => {
        return loadImgIntoMem(img, m.instance.exports.memory, m.instance.exports.alloc).then(r => {
            window.WASM = m;
            return m.instance.exports.read_img(r.imgPtr, r.len);
        });
    });
}

run('img-2.jpg')
   .then(ptr => console.log(new Int32Array(WASM.instance.exports.memory.buffer, ptr, 1)))

该控制台记录:

Int32Array [ 331 ]

如果无法访问调试器或无法打印消息,则基本上不可能进行调试。因此,我将您的代码移植到使用wasm-bindgen https://github.com/rustwasm/wasm-bindgen,纯粹是为了能够从 Rust 代码内部访问控制台:

#![feature(proc_macro, wasm_custom_section, wasm_import_module)]

extern crate wasm_bindgen;
extern crate image;

use wasm_bindgen::prelude::*;
use std::mem;

pub mod console {
    use wasm_bindgen::prelude::*;

    #[wasm_bindgen]
    extern {
        #[wasm_bindgen(js_namespace = console)]
        pub fn log(s: &str);
    }
}

#[wasm_bindgen]
pub fn alloc(len: usize) -> *mut u8 {
    let mut buf = Vec::with_capacity(len);
    let ptr = buf.as_mut_ptr();
    mem::forget(buf);
    ptr
}

#[wasm_bindgen]
pub fn read_img(ptr: *mut u8, len: usize) {
    let img = unsafe { Vec::from_raw_parts(ptr, len, len) };

    if let Err(e) = image::load_from_memory(&img) {
        console::log(&e.to_string());
    }
}

更新后的 JavaScript:

const js = import("./imaj_bg");

async function loadImgIntoMem(img, { alloc, memory }) {
  const resp = await fetch(img);
  const buf = await resp.arrayBuffer();

  const len = buf.byteLength;
  const ptr = alloc(len);

  const imgArray = new Uint8Array(memory.buffer, ptr, len);    
  imgArray.set(new Uint8Array(buf));

  return { ptr, len };
}

async function go(js) {
  const { ptr, len } = await loadImgIntoMem('cat.jpg', js);
  js.read_img(ptr, len);
};

js.then(go);

构建和服务代码:

$ cargo build --target wasm32-unknown-unknown --release
$ wasm-bindgen target/wasm32-unknown-unknown/release/imaj.wasm --out-dir=.
$ yarn serve

访问该页面并查看控制台日志会显示以下虎头蛇尾的消息:

operation not supported on wasm yet

事实是,Rust 标准库的很大一部分在 WebAssembly 中尚不存在。其中许多都被删除以返回此错误。

我不知道您的代码到底缺少哪个平台支持。最明显的一个是线程,jpeg_rayon and hdr功能,但关闭除jpeg仍然报告同样的错误。很可能还需要其他东西。

然而,它似乎确实特定于给定的图像编解码器。如果您尝试相同的代码但加载 PNG 图像,则会成功:

pub fn read_img(ptr: *mut u8, len: usize) {
    let img = unsafe { Vec::from_raw_parts(ptr, len, len) };

    let img = match image::load_from_memory(&img) {
        Ok(i) => i,
        Err(e) => {
            console::log(&e.to_string());
            return;
        }
    };

    console::log(&format!("{:?}", img.to_rgba()));
}
ImageBuffer { width: 305, height: 314, _phantom: PhantomData, data: [255, 255, 255, 0 /* remaining pixels skipped */

这表明 JPEG 代码尚不能与 WASM 配合使用。给定的编解码器可能工作也可能不工作;最好向上游维护者提出问题。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

编译为 WebAssembly 时无法使 image::load_from_memory() 工作 的相关文章

随机推荐

  • Magento 1.7.0.0 上的 SOAP V2 url 是什么

    1 7 0 0 版本中访问 Magento SOAP V2 的 url 是否已更改 当我尝试访问 上的服务 时http www somedomain com api v2 soap wsdl 1 http www somedomain co
  • 从 Web 服务下载文件 - 在 ASP.NET 站点中

    我想使用网络服务将文件从网站推送到浏览器 我当前正在将文件读入 base64 字节数组 并从 Web 服务返回该文件 这个网络服务是从网站调用的 我一直在思考如何将其作为原始文件推送到浏览器 理想情况下 我想将字节数组读入内存流 然后如果可
  • 当超过两次下载正在进行时 HttpSendRequest 阻塞

    在我们的程序中 每次需要发出HTTP请求时都会创建一个新线程 并且可以有多个线程同时运行 我遇到的问题是 如果我已经有两个线程正在运行 它们在读取时循环InternetReadFile 打电话后HttpSendRequest 任何后续尝试调
  • pandas.to_json 以特定形式输出日期格式

    数据框中日期的原始形式是 Date 2018 09 17 12 83 12 92 12 38 12 65 12 65 1937329 0 2018 09 10 12 92 13 12 12 81 12 83 12 83 1150470 0
  • C++ boost enable_if问题

    我有什么办法可以简化以下陈述吗 可能 使用boost enable if 我有一个简单的类结构 Base基类 Derived1 Derived2继承自Base 我有以下代码 template
  • 嵌套启动 --watch 更改后不重新加载(嵌套启动 --watch 不工作)

    我安装了 Nest js 当我运行 npm run start dev 运行 start watch 时 一切正常并且出现绿色日志 问题是 当我更新代码中的某些内容时 nest 不再更新 并且卡在下图中 我确信这不是我的代码的问题 因为我在
  • Dojo 拖放:如何检索项目的顺序?

    我创建了一个 Source 对象并进行配置 通过创建者 以便它呈现一组数据供我的用户根据需要进行排序 这一切工作正常 但是 我无法弄清楚如何在用户重新排序后检索数据 getAllNodes 返回 dom 节点 我需要原始数据对象 这真的很简
  • java - 文件lastModified与读取文件

    我正在使用一个文件 并且需要在修改文件时更新 java 中的值 所以 我想使用检查修改时间lastModified of File类 如果修改 则读取文件并更新文件中的单个属性 我的疑问是 是lastModified与从文件中读取单个属性
  • 从 C# .net 调用 python.py

    我在从 C 调用 python 脚本时遇到问题 我的 python 脚本根据参数 1 和参数 2 计算一个值并发送计算出的值 我无法获得计算值 比如说 我正在使用一个简单的 python 类并调用 C 以下是 python py impor
  • C库函数获取活动线程数

    我正在用 C 语言开发一个多线程 Unix 应用程序 有没有一种简单的方法来获取同时活动线程的数量 如果库已经可以为我完成的话 我不想编写代码来跟踪活动线程的数量 我正在使用 POSIX pthreads 并且我正在尝试为 Unix 和类
  • 重命名字典中的键

    我想重命名字典的键是整数 并且我需要它们是带有前导零的整数 以便它们正确排序 例如我的钥匙是这样的 1 101 11 我需要它们是 001 101 011 这就是我现在正在做的事情 但我知道有更好的方法 tmpDict for oldKey
  • 如何在 ES6 中使用所有默认值解构选项参数?

    我将 ES6 功能与 babel 编译器一起使用 我有一个将选项对象作为参数的函数 function myFunction option1 true option2 whatever console log option1 option2
  • 如何在使用支持库时构建带有 ListView 的 AppWidget?

    我想在早期版本的 Android 上的 AppWidget 中使用 ListView 拉格纳的回答在这个问题中 https stackoverflow com questions 8846743 app widget with listvi
  • 如何删除供应商代码插入的回调?

    我正在使用的 gem 插入了一个我想删除的 after save 回调 在我看来 从数组中删除符号比用猴子补丁解决问题更干净 如何访问回调数组 class UserSession lt Authlogic Session Base Don
  • symfony 2 中相同的 url 需要多个角色

    这是我的 security yml 的访问控制列表的样子 access control path admin roles IS AUTHENTICATED FULLY path admin roles ROLE ADMIN 我想要做的是 用
  • 为什么最多 4 个元素的集合是有序的,而更大的元素则不是?

    Given val xs1 Set 3 2 1 4 5 6 7 val ys1 Set 7 2 1 4 5 6 3 xs1 and ys1两者都导致scala collection immutable Set Int Set 5 1 6 2
  • 如何使用 Homebrew cask 安装 Sublime Text 3

    如何使用 Homebrew cask 安装 Sublime Text 3 当使用 Homebrew 的搜索时 我只看到 Sublime Text 2 我什至尝试点击自制软件 版本 https github com Homebrew home
  • 最容易实现的 Voronoi 图算法? [关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 实现 Voronoi 图的简单算法有哪些 我找不到任何专门以伪形式出现的算法 请分享一些 Vorono
  • 新值 EditText 未显示,没有任何错误

    编辑 顺便说一句 如果我在范围内硬编码 edt4 setText any text 它会显示该值 编辑2 尝试重建 清理项目 这可能是 settext 方法中的错误 看起来我做得对 当我用 settext 查看其他代码时 编辑3 start
  • 编译为 WebAssembly 时无法使 image::load_from_memory() 工作

    我正在尝试使用 Rust 将图像从 JavaScript 加载到 WebAssembly图像箱 https crates io crates image 我有以下 Rust 代码 extern crate image extern crat