photon icon indicating copy to clipboard operation
photon copied to clipboard

how can i use this lib without "webpack" and "npm" in pure javascript inline

Open insinfo opened this issue 3 years ago • 9 comments

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

<script src='https://api.mapbox.com/mapbox-gl-js/v2.1.1/mapbox-gl.js'></script>
 <script>

    function loadMap(selectorId, latitude, longitude, zoom, markerText, accessToken) {     
      mapboxgl.accessToken = accessToken;
      var map = new mapboxgl.Map({
        container: selectorId,
        style: 'mapbox://styles/mapbox/streets-v11',
        center: [longitude, latitude], // starting position [lng, lat]
        zoom: zoom // starting zoom
      });
   
      var popup = new mapboxgl.Popup({ offset: 25 }).setText(
        markerText
      );

      var popup = new mapboxgl.Popup({ closeOnClick: true })
        .setLngLat([longitude, latitude])
        .setText(markerText)     
        .addTo(map);

      var marker = new mapboxgl.Marker({     
      }).setLngLat([longitude, latitude])
    
        .addTo(map);
    }
 </script>
 <script defer src="main.dart.js"></script>

from dart code

//wrapper interop dart <=> js
@JS()
library mapbox;

@JS('loadMap')
external void loadMap( dynamic id, double latitude, double longitude, double zoom, String markerText, String accessToken);

//execute 
loadMap(htmlElement, -22, -40, 14, 'test', 'asdasdsad-asdad');

insinfo avatar Jun 16 '21 22:06 insinfo

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

insinfo avatar Jun 16 '21 23:06 insinfo

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! 👍

silvia-odwyer avatar Jun 17 '21 02:06 silvia-odwyer

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

but i'm faced with this error:


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

image

insinfo avatar Jun 18 '21 15:06 insinfo

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);

insinfo avatar Jun 18 '21 22:06 insinfo

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 avatar Jun 18 '21 23:06 silvia-odwyer

@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:

#[features] #default = ["console_error_panic_hook", "rayon"] #rayon = ["image/jpeg_rayon", "imageproc/rayon"]

insinfo avatar Jun 21 '21 22:06 insinfo

@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 😄

silvia-odwyer avatar Jun 22 '21 01:06 silvia-odwyer

Thanks for the feedback, feel free to incorporate this implementation.

insinfo avatar Jun 22 '21 13:06 insinfo

@insinfo Thanks, that's much appreciated! I'm looking forward to adding an implementation of this to the library 😄

silvia-odwyer avatar Jun 23 '21 01:06 silvia-odwyer