Не удается заставить image :: load_from_memory () работать при компиляции в WebAssembly - PullRequest
0 голосов
/ 18 мая 2018

Я пытаюсь загрузить изображение из JavaScript в WebAssembly с Rust, используя ящик с изображениями .

У меня есть следующий код 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

В функции read_img() я наивно обрабатываю ошибки по двум векторам: [333] для OK и [331] для любой ошибки.Я прочитал эти векторы на стороне JavaScript, чтобы узнать, было ли изображение загружено успешно.

Метод 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 ]

1 Ответ

0 голосов
/ 19 мая 2018

В принципе невозможно отлаживать вещи без доступа к отладчику или возможности распечатывать сообщения.Из-за этого я перенес ваш код для использования 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 и 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.Данный кодек может или не может работать еще;Вероятно, лучше всего подавать проблемы с сопровождающими из основной ветки разработки.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...