Code Monkey home page Code Monkey logo

Comments (24)

hschimke avatar hschimke commented on July 17, 2024 2

https://www.npmjs.com/package/rxing-wasm should enable the correct features in chrono crate and remove the SystemTime calls

from rxing.

hschimke avatar hschimke commented on July 17, 2024 1

I'll look into this. I'm not particularly familiar with wasm at this point, so a little research would be necessary. Off the top of my head I see a few potential issues:

  1. My limited understanding of wasm suggests that it works best with no_std libraries, which rxing currently is not. I have some future plans to move rxing to no_std, but those don't have a timeline yet.
  2. The current version is really only well tested when using images from the image crate as an input source. I don't think that would be the preferred way to handle things in a wasm library, at least in part because the image crate is pretty large.

I'll look into it.

from rxing.

hschimke avatar hschimke commented on July 17, 2024 1

I've done a little experimentation, though a bit more is needed. The library compiles to wasm just fine, and I was able to get a simple barcode generator working without too much work.

I'll play around with it and see if I can make a realistic wasm binding library for decode.

from rxing.

hschimke avatar hschimke commented on July 17, 2024 1

I'm in the process of porting the c++ datamatrix detector. Apparently it's better in some situations.

from rxing.

hschimke avatar hschimke commented on July 17, 2024 1

I have a couple fixes I'm backporting from c++ this weekend too (all datamatrix related). They will all be rolled up in the 0.1.5 realease on npm once I'm done.

from rxing.

hschimke avatar hschimke commented on July 17, 2024 1

Watch out for versions 0.1.7 - 0.1.11. A change in some dependencies has caused some havoc I'm still sorting out. I suggest pinning to 0.1.6

from rxing.

hschimke avatar hschimke commented on July 17, 2024 1

I’m closing this for now, feel free to open a new issue if anything comes up!

from rxing.

hschimke avatar hschimke commented on July 17, 2024

Do you have a sample barcode you would want to decode? What sorts of formats are you looking at decoding, what input formats do you have available.

My preliminary idea is to make a very simple npm package that provides methods for:

  • Encoding barcodes to any of the supported formats, though what output format would be provided I haven't settled on.
  • Decoding a single barcode in an image defined by an array of luma8 values. This skips the (much less performant) code that handles multiple barcodes in a single image.

from rxing.

arogozhnikov avatar arogozhnikov commented on July 17, 2024

Single barcode is completely fine.

I am looking for ECC implementations that can handle DMRE: https://www.e-d-c.info/en/projects/dmre-en.html
It is the only format I found which is non-square, and for vials/tubes rectangular barcode is better. (Update: technically, PDF417 is too, but visually ECC DMRE is more compact)

This single-page example exposes image as a bytestream + dimensions, and I believe that's just RGB values interleaved. Converting to luminosity-only sounds reasonable

<!DOCTYPE html>
<!-- saved from url=(0059)https://usefulangle.com/demos/352/camera-capture-photo.html -->
<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Demo - Capture Photo From Webcam Using Javascript</title>

<meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no">
<style type="text/css">

button {
    width: 120px;
    padding: 10px;
    display: block;
    margin: 20px auto;
    border: 2px solid #111111;
    cursor: pointer;
    background-color: white;
}

#start-camera {
    margin-top: 50px;
}

#video {
    display: none;
    margin: 50px auto 0 auto;
}

#click-photo {
    display: none;
}

#dataurl-container {
    display: none;
}

#canvas {
    display: block;
    margin: 0 auto 20px auto;
}

#dataurl-header {
    text-align: center;
    font-size: 15px;
}

#dataurl {
    display: block;
    height: 100px;
    width: 320px;
    margin: 10px auto;
    resize: none;
    outline: none;
    border: 1px solid #111111;
    padding: 5px;
    font-size: 13px;
    box-sizing: border-box;
}

</style>
</head>

<body>

<button id="start-camera">Start Camera</button>
<video id="video" width="320" height="240" autoplay=""></video>
<button id="click-photo">Click Photo</button>
<div id="dataurl-container">
    <canvas id="canvas" width="320" height="240"></canvas>
    <div id="dataurl-header">Image Data URL</div>
    <textarea id="dataurl" readonly=""></textarea>
</div>

<script>

let camera_button = document.querySelector("#start-camera");
let video = document.querySelector("#video");
let click_button = document.querySelector("#click-photo");
let canvas = document.querySelector("#canvas");
let dataurl = document.querySelector("#dataurl");
let dataurl_container = document.querySelector("#dataurl-container");


function recognizeBarcode() {
    let context = canvas.getContext('2d');
    let imageData = context.getImageData(0, 0, canvas.width, canvas.height);
    let code = callToWasmUnimplemented(imageData.data, imageData.width, imageData.height, {
        inversionAttempts: "dontInvert",
    });
    if (code) {
        alert(code.data);
    }
}


camera_button.addEventListener('click', async function() {
   	let stream = null;

    try {
    	stream = await navigator.mediaDevices.getUserMedia({ video: true, audio: false });
    }
    catch(error) {
    	alert(error.message);
    	return;
    }

    video.srcObject = stream;

    video.style.display = 'block';
    camera_button.style.display = 'none';
    click_button.style.display = 'block';
    // run recognition three times a second.
    setInterval(recognizeBarcode, 300);
});

click_button.addEventListener('click', function() {
    canvas.getContext('2d').drawImage(video, 0, 0, canvas.width, canvas.height);
   	let image_data_url = canvas.toDataURL('image/jpeg');
    
    dataurl.value = image_data_url;
    dataurl_container.style.display = 'block';
});

</script>


</body></html>

from rxing.

hschimke avatar hschimke commented on July 17, 2024

very early initial version (0.1.0) available on npm: https://www.npmjs.com/package/rxing-wasm

the detection code for datamatrix behaves oddly when the images provided to it are small, so keep that in mind.

I'd call it an early beta release.

from rxing.

arogozhnikov avatar arogozhnikov commented on July 17, 2024

so far no success in detecting anything in js, likely doing something wrong

I've tested on QR codes, in very rare cases it throws "Unreachable", which is probably equal to panic in rust.
In all other cases it just throws an exception "Not Found",

I've set equal dimensions to height and width (480x480) in case there is some mismatch in element ordering, but nothing changed.

I use following functions (checked that output looks sane):

function convertCanvasToGrayscale(canvas) {
    let context = canvas.getContext('2d');
    let height = canvas.height;
    let width = canvas.width;
    let imageData = context.getImageData(0, 0, width, height);

    let data = imageData.data;
    let array = new Uint8Array(data.length / 4);
    // get only the red channel
    for (let i = 0; i < array.length; i += 1) {
        array[i] = data[i * 4];
    }
    return {array, width, height};
}
function convertCanvasToUint32(canvas) {
    let context = canvas.getContext('2d');
    let height = canvas.height;
    let width = canvas.width;
    let imageData = context.getImageData(0, 0, width, height);

    let data = imageData.data;
    console.assert(data.length === width * height * 4);
    let array = new Uint32Array(width * height);
    for (let i = 0; i < array.length; i += 1) {
        // unsure about the ordering
        array[i] = data[i * 4] + (data[i * 4 + 1] << 8) + (data[i * 4 + 2] << 16) + (data[i * 4 + 3] << 24);
    }
    return {array, width, height};
}

outputs are used like this:

        const {array, width, height} = convertCanvasToGrayscale(canvas);
        let parsedBarcode = decode_barcode(array, width, height);

or

        const {array, width, height} = convertCanvasToUint32(canvas);
        let parsedBarcode = decode_barcode_rgb(array, width, height);

from rxing.

arogozhnikov avatar arogozhnikov commented on July 17, 2024

encoding into ascii works without issues

from rxing.

hschimke avatar hschimke commented on July 17, 2024

I generated the below qrcode and tested it with the rust luma8 decoder. It didn't have any issue decoding it, but I admit to not having tested that as extensively as the image decoder. You might try using it as the input.

Here is the luma conversion that rxing (and zxing) use internally when an image is used as the source:

Luma([((306 * (red as u64)
                    + 601 * (green as u64)
                    + 117 * (blue as u64)
                    + 0x200)
                    >> 10) as u8])

You might try using that as your conversion.

For rgb images the conversion from u32 uses the following bit shifts:

for offset in 0..size {
            //for (int offset = 0; offset < size; offset++) {
            let pixel = pixels[offset];
            let r = (pixel >> 16) & 0xff; // red
            let g2 = (pixel >> 7) & 0x1fe; // 2 * green
            let b = pixel & 0xff; // blue
                                  // Calculate green-favouring average cheaply
            luminances[offset] = ((r + g2 + b) / 4).try_into().unwrap();
        }

There are a lot of weird issues with the datamatrix decoder, most of which I think are present in the original java. It detects datamatrix codes perfectly, but then when it comes to grid sampling them it gives up some strange data. It's the same code used by both the qrcode and aztec components, which handle it fine, so I suspect it's an issue with how the datamatrix decoder handles the input. I'm still poking at it.

If the barcodes are "pure" barcodes, that is, the image contains nothing but a barcode, then the decoder works perfectly (though that requires a bit of extra config for the decoder to know that they're "pure" barcodes).

For a simpler (no wasm) interface you could also look at: https://github.com/zxing-js/library and https://github.com/LazarSoft/jsqrcode

Sample qrcode (verified to decode with luma8) (verified in rust)
sample_barcode

Sample raw luma bytes, verified to decode with the luma8 source (80x80 image) (in rust)
luma_raw.txt

from rxing.

hschimke avatar hschimke commented on July 17, 2024

I also have a potential fix for datamatrix reading, but still implementing

from rxing.

arogozhnikov avatar arogozhnikov commented on July 17, 2024

I've created a sample BW barcode too, it should be readable without doubt - but I get "unreachable" on every call, most likely this is the reason:

rustwasm/wasm-pack#724

from rxing.

hschimke avatar hschimke commented on July 17, 2024

Ah, didn't realize SystemTime was a no go. I'll get wasm feature added to Chrono and get system time out.

from rxing.

arogozhnikov avatar arogozhnikov commented on July 17, 2024

it works now πŸŽ‰ ! Fast enough to run 10 times a second on 1024x768 (did not experiment much with sizes).

Works nicely with QR, finicky with ECC200 DMRE

from rxing.

hschimke avatar hschimke commented on July 17, 2024

I just pushed v0.1.2 of the npm package. After a harrowing trip into c++, rxing now includes the c++ version of the datamatrix detector (https://github.com/zxing-cpp/zxing-cpp). From my initial testing it's much better at finding symbols, especially when those symbols are small, have very slim borders. It seems specifically more likely to work with DMRE codes, but I don't have a ton to test with.

from rxing.

arogozhnikov avatar arogozhnikov commented on July 17, 2024

that's great news, thank you!

I am about to test this in a lab, currently experiencing unrelated issues with deployment πŸ˜…
Will follow up after I fix things.

from rxing.

arogozhnikov avatar arogozhnikov commented on July 17, 2024

Yup rxing does a good job at detecting datamatrix, great work @hschimke!
Will use rectangular barcodes now πŸŽ‰ .
IMG_0410

from rxing.

hschimke avatar hschimke commented on July 17, 2024

I pushed out v0.1.4 of the NPM package, which allows the use of DecodeHints. This might be helpful if you wanted to limit the types of barcodes being searched for. I haven't benchmarked, but my guess would be that it might speed up detection (possibly by a lot).

It also adds a new method to convert the data from a 2dCanvas into luma8, which might be faster in wasm than javascript, but I'm honestly not sure.

from rxing.

arogozhnikov avatar arogozhnikov commented on July 17, 2024

great, thanks for letting know. Will test this soon

from rxing.

arogozhnikov avatar arogozhnikov commented on July 17, 2024

integrated both luma conversion and decode hints (I've left only two types: QR and datamatrix).
All works, does not react to other types of barcodes.

Very crude estimate ~ approximately twice lower CPU load judging by profiler peaks.

from rxing.

hschimke avatar hschimke commented on July 17, 2024

This is resolved with npm version 0.1.12, apparently I didn't correctly pin the wasm_bindgen dependency in my deployment environment, so it worked fine in test and then deployed with an update that broke things, oops!

from rxing.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.