Open insinfo opened 3 years ago
how do I pass an "ArrayBuffer" from a jpeg file that I have in memory to the photon lib for it to resize and return an "ArrayBuffer" already resized
on dart I use this code below to read the JPG file from an input file element and return me the ArrayBuffer
<input (change)="handleFileUpload($event.target.files)" type="file" class="">
void handleFileUpload(html.FileList files) {
var file = files[0];
var fileBytes = await fileToArrayBuffer(file);
//here I need to pass this arrayBuffer to lib photon and it returns an arrayBuffer of the resized image
}
static Future<dynamic> fileToArrayBuffer(html.File file) async {
final completer = Completer();
final reader = html.FileReader();
reader.onLoad.listen((progressEvent) {
final loadedFile = progressEvent.currentTarget as html.FileReader;
completer.complete(loadedFile.result);
});
reader.readAsArrayBuffer(file);
return completer.future;
}
How to do this optimally so you don't have to keep creating Canva elements
Hi Isaque! At the moment, it's only possible to create canvas elements and then pass those to Photon, but I'm planning to add a feature which supports passing ArrayBuffers to a future version of the library! 😄 Hopefully that answers your question! As for the builds, webpack or npm is needed to make use of the library, but I see in Rust's wasm-bindgen documentation that builds for the browser only (without needing webpack) can be outputted, so I'll look into this for the future too ✅
If you have any other questions, make sure to let me know! Thanks! 👍
I saw in the rust documentation https://rustwasm.github.io/docs/wasm-bindgen/reference/deployment.html the possibility of compiling with the option "wasm-pack build --target no-modules", then I cloned this repository and compiled it with this option and managed to load the photon with the code below:
<!DOCTYPE html>
<html>
<head>
<title>teste</title>
<script id="script-photon" src="photon_rs.js"></script>
<script>
window.photon;
async function initPhoton() {
var scri = document.querySelector('#script-photon');
var url = scri.src.replace(/\.js$/, '_bg.wasm');
window.photon = await wasm_bindgen(url);
}
initPhoton();
function filterImage() {
// Create a canvas and get a 2D context from the canvas
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var newimg = document.getElementById('img');
// Draw the image element onto the canvas
ctx.drawImage(newimg, 0, 0);
console.log(canvas.width);
console.log(newimg);
console.log(ctx);
// Convert the ImageData found in the canvas to a PhotonImage (so that it can communicate with the core Rust library)
let image = photon.open_image(canvas, ctx);
// Filter the image, the PhotonImage's raw pixels are modified
// window.photon.filter(image, "radio");
// Place the modified image back on the canvas
// window.photon.putImageData(canvas, ctx, image);
}
window.onload = function (e) {
setTimeout(function (e) {
filterImage();
}, 2000);
};
</script>
</head>
<body>
<h1>teste</h1>
<img id="img"
src="https://dyl80ryjxr1ke.cloudfront.net/external_assets/hero_examples/hair_beach_v391182663/original.jpeg"
width="640px" height="480px" style="width: 640px;height: 480px;">
<canvas id="canvas" width="640px" height="480px" style="width: 640px;height: 480px;"></canvas>
</body>
</html>
https://github.com/insinfo/photon-test
photon_rs.js:3608 wasm-bindgen: imported JS function that was not marked as `catch` threw an error: Cannot read property 'width' of undefined
Stack:
TypeError: Cannot read property 'width' of undefined
at http://127.0.0.1:8080/photon_rs.js:4126:34
at logError (http://127.0.0.1:8080/photon_rs.js:3599:18)
at imports.wbg.__wbg_width_9eb2c66ac9dde633 (http://127.0.0.1:8080/photon_rs.js:4125:68)
at web_sys::features::gen_HtmlCanvasElement::HtmlCanvasElement::width::ha1230d8c7e88e329 (<anonymous>:wasm-function[11977]:0x51107a)
at photon_rs::get_image_data::hd6bde4bd49151578 (<anonymous>:wasm-function[2773]:0x3a72b2)
at photon_rs::open_image::h5e03354885b8c3ab (<anonymous>:wasm-function[2530]:0x3921c4)
at open_image (<anonymous>:wasm-function[4627]:0x422b05)
at filterImage (http://127.0.0.1:8080/:32:32)
at http://127.0.0.1:8080/:43:17
logError @ photon_rs.js:3608
imports.wbg.__wbg_width_9eb2c66ac9dde633 @ photon_rs.js:4125
web_sys::features::gen_HtmlCanvasElement::HtmlCanvasElement::width::ha1230d8c7e88e329 @ 01c9dde2:0x51107a
photon_rs::get_image_data::hd6bde4bd49151578 @ 01c9dde2:0x3a72b2
photon_rs::open_image::h5e03354885b8c3ab @ 01c9dde2:0x3921c4
open_image @ 01c9dde2:0x422b05
filterImage @ (index):32
(anonymous) @ (index):43
setTimeout (async)
window.onload @ (index):42
load (async)
(anonymous) @ (index):41
photon_rs.js:4126 Uncaught TypeError: Cannot read property 'width' of undefined
at photon_rs.js:4126
at logError (photon_rs.js:3599)
at imports.wbg.__wbg_width_9eb2c66ac9dde633 (photon_rs.js:4125)
at web_sys::features::gen_HtmlCanvasElement::HtmlCanvasElement::width::ha1230d8c7e88e329 (<anonymous>:wasm-function[11977]:0x51107a)
at photon_rs::get_image_data::hd6bde4bd49151578 (<anonymous>:wasm-function[2773]:0x3a72b2)
at photon_rs::open_image::h5e03354885b8c3ab (<anonymous>:wasm-function[2530]:0x3921c4)
at open_image (<anonymous>:wasm-function[4627]:0x422b05)
at filterImage ((index):32)
at (index):43
(anonymous) @ photon_rs.js:4126
logError @ photon_rs.js:3599
imports.wbg.__wbg_width_9eb2c66ac9dde633 @ photon_rs.js:4125
web_sys::features::gen_HtmlCanvasElement::HtmlCanvasElement::width::ha1230d8c7e88e329 @ 01c9dde2:0x51107a
photon_rs::get_image_data::hd6bde4bd49151578 @ 01c9dde2:0x3a72b2
photon_rs::open_image::h5e03354885b8c3ab @ 01c9dde2:0x3921c4
open_image @ 01c9dde2:0x422b05
filterImage @ (index):32
(anonymous) @ (index):43
setTimeout (async)
window.onload @ (index):42
load (async)
(anonymous) @ (index):41
wasm-bindgen: imported JS function that was not marked as `catch` threw an error: Cannot read property 'width' of undefined
after a lot of brainstorming, I found out where the problem was, the "wasm-pack" is generating the javascript with error on this line: "wasm_bindgen = Object.assign(init, __exports);"
so to solve the problem I replace this line, so:
//wasm_bindgen = Object.assign(init, __exports);
wasm_bindgen = init;
/**
* Overwrites obj1's values with obj2's and adds obj2's if non existent in obj1
* @param obj1
* @param obj2
* @returns obj3 a new object based on obj1 and obj2
*/
function merge_options(obj1, obj2) {
var obj3 = {};
for (var attrname in obj1) { obj3[attrname] = obj1[attrname]; }
for (var attrname in obj2) { obj3[attrname] = obj2[attrname]; }
return obj3;
}
and this line "return wasm;" that is why
//return wasm;
return merge_options(wasm, __exports);
Hi Isaque, Really glad to hear that you've found the issue, I see that you've also let the wasm-pack team know about this also, hopefully it'll be fixed in a new patch release 👍 Thanks again for pinpointing the issue here, I'll be sure to keep this in mind when building the library for the browser only ✅
@silvia-odwyer
I managed to implement the function to work with Uint8Array that I needed in your library, the implementation was as follows:
It's working correctly.
/// open image from a js Uint8Array and convert to rgba8 PhotonImage;
#[wasm_bindgen]
pub fn open_image_from_uint8array(bytes: Vec<u8>) -> PhotonImage {
console_error_panic_hook::set_once();
let img = image::load_from_memory(&bytes).unwrap();
let (width, height) = img.dimensions();
// Convert the DynamicImage type to raw vec representing RGBA pixels (not RGB)
let raw_pixels = img.into_rgba8().to_vec();
PhotonImage {
raw_pixels,
width: width,
height: height,
}
}
/// create um uint8array of PhotonImage to uploud/download or manipulate on JavaScript
///
/// var downloadBlob, downloadURL;
/// downloadBlob = function (data, fileName, mimeType) {
/// var blob, url;
/// blob = new Blob([data], {
/// type: mimeType
/// });
/// url = window.URL.createObjectURL(blob);
/// downloadURL(url, fileName);
/// setTimeout(function () {
/// return window.URL.revokeObjectURL(url);
/// }, 1000);
/// };
/// downloadURL = function (data, fileName) {
/// var a;
/// a = document.createElement('a');
/// a.href = data;
/// a.download = fileName;
/// document.body.appendChild(a);
/// a.style = 'display: none';
/// a.click();
/// a.remove();
/// };
/// let buf = await fetch("https://i.imgur.com/LYVUrUf.jpg", { referrer: "" }).then(r => r.arrayBuffer());
/// let image = open_image_from_uint8array(new Uint8Array(buf));
/// var array = to_jpeg_uint8array(image, 30);
/// downloadBlob(array, 'some-file.jpg', 'image/jpeg');
///
#[wasm_bindgen]
pub fn to_jpeg_uint8array(img: PhotonImage, quality: u8) -> Vec<u8> {
let raw_pixels = img.raw_pixels;
let width = img.width;
let height = img.height;
let img_buffer = ImageBuffer::from_vec(width, height, raw_pixels).unwrap();
let dynimage = ImageRgba8(img_buffer);
let mut buf = Vec::new();
dynimage
.write_to(&mut buf, image::ImageOutputFormat::Jpeg(quality))
.unwrap();
return buf;
}
To work correctly I had to remove these lines from the toml:
@insinfo I'd love to incorporate this functionality into the library, so would you mind if I added your logic to the library? Or if you want to submit a PR too, whatever suits best 😄
Thanks for the feedback, feel free to incorporate this implementation.
@insinfo Thanks, that's much appreciated! I'm looking forward to adding an implementation of this to the library 😄
how can i use this lib without "webpack" and "npm".
I have fav many AngularDart projects and in dart I can call javascript functions, but I don't know how to put this lib in my index.html as I do with other libs like "mapbox"
index.html
from dart code