diff --git a/Cargo.toml b/Cargo.toml index c4fb70f..82c274d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rxing-wasm" -version = "0.2.11" +version = "0.3.0" edition = "2021" description = "wasm bindings for rxing to provide commong barcode operations (decode/encode)" repository = "https://github.com/rxing-core/rxing-wasm" @@ -23,7 +23,7 @@ js-sys = "0.3.69" # logging them with `console.error`. This is great for development, but requires # all the `std::fmt` and `std::panicking` infrastructure, so isn't great for # code size when deploying. -console_error_panic_hook = { version = "0.1.6", optional = true } +console_error_panic_hook = { version = "0.1.7", optional = true } rxing = {version = "~0.6.1", default-features = false, features = ["wasm_support"]} #rxing = {path="../rxing", version = "~0.2.23", default-features = false, features = ["wasm_support"]} diff --git a/README.md b/README.md index 4cfb611..d7cbea6 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,10 @@ # rxing-wasm WASM bindings for common rxing functions. The NPM link is [https://www.npmjs.com/package/rxing-wasm](https://www.npmjs.com/package/rxing-wasm) and the rust source is [https://github.com/rxing-core/rxing-wasm](https://github.com/hschimke/rxing-wasm). +## Decode Multi Breaking Change with v0.3.0 +Version `0.3.0` now returns `BarcodeResult` objects in a native javascript array. This fully deprecates the old method +which returned a custom object with internal state. + ## Data The `convert_js_image_to_luma` function is used to convert canvas image data to the luma 8 format that rxing expects. An example might look like to below. @@ -99,7 +103,8 @@ pub fn decode_multi( width: u32, height: u32, hints: &mut decode_hints::DecodeHintDictionary, -) -> Result; + filter_image: Option, +) -> Result, String>; ``` ```rust @@ -113,6 +118,4 @@ pub fn encode_barcode_with_hints( ``` ## Beta Features -`decode_multi` is currently in beta. The output may be unexpected, or undefined. Please use with caution. The interface may be unstable, and change. - `encode_barcode_with_hints` is currently in alpha. The output and behaviour is unexpected and poorly documented. Use at your own risk, feature may change, unstable interface. \ No newline at end of file diff --git a/examples/webpack+js/index.html b/examples/webpack+js/index.html index 6586961..75ac07b 100644 --- a/examples/webpack+js/index.html +++ b/examples/webpack+js/index.html @@ -19,7 +19,8 @@

RXing - Decode Barcodes

- + @@ -32,33 +33,15 @@

RXing - Decode Barcodes

- + - - - - - - - - - - - - - - - - - - - - - + + + +
+
@@ -66,7 +49,61 @@

RXing - Decode Barcodes

+ + - \ No newline at end of file + \ No newline at end of file diff --git a/examples/webpack+js/index.js b/examples/webpack+js/index.js index ad44f14..c04cdeb 100644 --- a/examples/webpack+js/index.js +++ b/examples/webpack+js/index.js @@ -1,17 +1,20 @@ -import { convert_js_image_to_luma, decode_barcode_with_hints, DecodeHintDictionary, DecodeHintTypes, BarcodeFormat } from "rxing-wasm"; +import { convert_js_image_to_luma, decode_barcode_with_hints, decode_multi, DecodeHintDictionary, DecodeHintTypes, BarcodeFormat } from "rxing-wasm"; const text_hints = ["Other", "PossibleFormats", "CharacterSet", "AllowedLengths", "AllowedEanExtensions"]; const bool_hints = ["PureBarcode", "TryHarder", "AssumeCode39CheckDigit", "ReturnCodabarStartEnd", "AssumeGs1", "AlsoInverted", "TelepenAsNumeric"] const scan_btn = document.getElementById('scan_btn'); const input = document.getElementById('image_file_input'); -const output = document.getElementById("output"); +const output = document.getElementById("output_container"); +const multi_btn = document.getElementById('scan_multi'); input.addEventListener('change', handleFiles); scan_btn.addEventListener('click', onClickScan); +multi_btn.addEventListener('click', onClickMulti); function handleFiles(e) { scan_btn.disabled = true; + multi_btn.disabled = true; output.hidden = true; const canvas = document.getElementById('cvs'); const ctx = canvas.getContext('2d'); @@ -22,10 +25,12 @@ function handleFiles(e) { canvas.height = img.height; ctx.drawImage(img, 0, 0, img.width, img.height); scan_btn.disabled = false; + multi_btn.disabled = false; } } function onClickScan() { + output.innerHTML = ''; const canvas = document.getElementById('cvs'); const context = canvas.getContext('2d'); const imageData = context.getImageData(0, 0, canvas.width, canvas.height); @@ -39,35 +44,51 @@ function onClickScan() { alert("Issue decoding: " + e); } write_results(result.format(), result.text(), result.raw_bytes(), result.result_points(), result.get_meta_data()); + + output.hidden = false; } -function write_results(format, text, raw_bytes, _points, metadata) { - // const points_formatted = []; - // const chunkSize = 2; - // console.log(JSON.stringify(points)); - // for (let i = 0; i < points.length; i += chunkSize) { - // const chunk = points.slice(i, i + chunkSize); - // points_formatted.push([chunk[0], chunk[1]]); - // } +function onClickMulti() { + output.innerHTML = ''; + const canvas = document.getElementById('cvs'); + const context = canvas.getContext('2d'); + const imageData = context.getImageData(0, 0, canvas.width, canvas.height); + const luma_data = convert_js_image_to_luma(imageData.data); + const filter_image = document.getElementById("FilterInput").checked; + const hints = getHints(); + let result; + try { + result = decode_multi(luma_data, canvas.width, canvas.height, hints, filter_image); + } catch (e) { + alert("Issue decoding: " + e); + } - let metadata_string = ""; - metadata.forEach((k,v) => {metadata_string += `${k}: ${v}\n`}); - // for (const md_k of metadata.keys()){ - // // console.log(`${md_k}: ${metadata.get(md_k)}\n`); - // metadata += `${md_k}: ${metadata.get(md_k)}\n`; - // } + for (const res of result) { + write_results(res.format(), res.text(), res.raw_bytes(), res.result_points(), res.get_meta_data()); + } - document.getElementById("text_result_td").innerText = text; + output.hidden = false; +} - document.getElementById("format_result_td").innerText = BarcodeFormat[format]; +function write_results(format, text, raw_bytes, _points, metadata) { + let metadata_string = ""; + metadata.forEach((k, v) => { metadata_string += `${k}: ${v}\n` }); - // document.getElementById("points_result_td").innerText = points_formatted.reduce((acc, point) => { acc + "(" + point[0] + "," + point[1], ") " }, ""); + const new_element = document.createElement("rxing-result-display"); - document.getElementById("raw_bytes_result_td").innerText = Object.keys(raw_bytes).map((k) => raw_bytes[k]).join(', '); //.toString().split(",");//.reduce((acc,v)=>{acc + "-" + v}, ""); + add_template_slot("text_result", text, new_element); + add_template_slot("format_result", BarcodeFormat[format], new_element); + add_template_slot("raw_bytes_result", Object.keys(raw_bytes).map((k) => raw_bytes[k]).join(', '), new_element); + add_template_slot("medata_data_result", metadata_string, new_element); - document.getElementById("medata_data_result_td").innerText = metadata_string; + output.appendChild(new_element); +} - output.hidden = false; +function add_template_slot(slot_name, slot_data, template) { + const new_slot_span = document.createElement("span"); + new_slot_span.setAttribute("slot", slot_name); + new_slot_span.innerText = slot_data; + template.appendChild(new_slot_span); } function get_text_hint(id) { @@ -92,4 +113,18 @@ function getHints() { hint_dictionary.remove_hint(DecodeHintTypes["PureBarcode"]); } return hint_dictionary; -} \ No newline at end of file +} + +customElements.define( + "rxing-result-display", + class extends HTMLElement { + constructor() { + super(); + const template = document.getElementById( + "result-element-template", + ).content; + const shadowRoot = this.attachShadow({ mode: "open" }); + shadowRoot.appendChild(template.cloneNode(true)); + } + }, +); \ No newline at end of file diff --git a/examples/webpack+js/package.json b/examples/webpack+js/package.json index b345def..fe5b5fd 100644 --- a/examples/webpack+js/package.json +++ b/examples/webpack+js/package.json @@ -20,6 +20,6 @@ "webpack-dev-server": "^4.11.1" }, "dependencies": { - "rxing-wasm": "0.2.11" + "rxing-wasm": "0.3.0" } } diff --git a/examples/webpack+js/styles.css b/examples/webpack+js/styles.css index af2261f..9a4fce6 100644 --- a/examples/webpack+js/styles.css +++ b/examples/webpack+js/styles.css @@ -9,20 +9,6 @@ grid-template-columns: 1fr 1.5fr; } -#output { - padding-top: 2em; - width: 75%; -} - -#output td { - padding-top: .5em; -} - -#output .field { - width: 10%; - font-family: 'Courier New', Courier, monospace; -} - -#output .data { - width: 90%; +#cvs { + width: 100%; } \ No newline at end of file diff --git a/src/encode_hints.rs b/src/encode_hints.rs index e9c11e2..3900069 100644 --- a/src/encode_hints.rs +++ b/src/encode_hints.rs @@ -1,5 +1,5 @@ use rxing::{datamatrix::encoder::SymbolShapeHint, Dimension}; -use std::collections::{HashMap}; +use std::collections::HashMap; use wasm_bindgen::prelude::*; #[wasm_bindgen] diff --git a/src/lib.rs b/src/lib.rs index c92fca6..c7e81e3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -317,13 +317,11 @@ pub fn decode_barcode( let detection_function = if matches!(filter_image, Some(true)) { rxing::helpers::detect_in_luma_filtered_with_hints - }else { + } else { rxing::helpers::detect_in_luma_with_hints }; - let Ok(result) = - detection_function(data, width, height, None, &mut hints) - else { + let Ok(result) = detection_function(data, width, height, None, &mut hints) else { return Err("not found".to_owned()); }; Ok(result.into()) @@ -402,9 +400,8 @@ pub fn decode_barcode_with_hints( width: u32, height: u32, hints: &mut decode_hints::DecodeHintDictionary, - filter_image: Option, + filter_image: Option, ) -> Result { - let results = if matches!(filter_image, Some(true)) { rxing::helpers::detect_in_luma_filtered_with_hints( data, @@ -413,7 +410,7 @@ pub fn decode_barcode_with_hints( None, hints.get_dictionary_mut(), ) - }else { + } else { rxing::helpers::detect_in_luma_with_hints( data, width, @@ -422,44 +419,13 @@ pub fn decode_barcode_with_hints( hints.get_dictionary_mut(), ) }; - + let Ok(result) = results else { return Err("not found".to_owned()); }; Ok(result.into()) } -#[wasm_bindgen] -pub struct MultiDecodeResult { - pointer: usize, - results: Vec, -} - -#[wasm_bindgen] -impl MultiDecodeResult { - #[wasm_bindgen(constructor)] - pub fn new() -> MultiDecodeResult { - MultiDecodeResult { - pointer: 0, - results: Vec::default(), - } - } - - fn with_results(results: Vec) -> MultiDecodeResult { - MultiDecodeResult { - pointer: 0, - results, - } - } - - #[wasm_bindgen] - pub fn next(&mut self) -> Option { - let ret = self.results.get(self.pointer).map(|b| b.clone()); - self.pointer += 1; - ret - } -} - #[cfg(feature = "decode_hints")] #[wasm_bindgen] pub fn decode_multi( @@ -467,16 +433,37 @@ pub fn decode_multi( width: u32, height: u32, hints: &mut decode_hints::DecodeHintDictionary, -) -> Result { - let Ok(results) = rxing::helpers::detect_multiple_in_luma_with_hints( - data, - width, - height, - hints.get_dictionary_mut(), - ) else { - return Err("not found".to_owned()); + filter_image: Option, +) -> Result, String> { + use rxing::{ + common::HybridBinarizer, + multi::{GenericMultipleBarcodeReader, MultipleBarcodeReader}, + BinaryBitmap, FilteredImageReader, Luma8LuminanceSource, MultiFormatReader, RXingResult, + }; + + let result = if matches!(filter_image, Some(true)) { + let mut reader = GenericMultipleBarcodeReader::new(FilteredImageReader::new( + MultiFormatReader::default(), + )); + + reader.decode_multiple_with_hints( + &mut BinaryBitmap::new(HybridBinarizer::new(Luma8LuminanceSource::new( + data, width, height, + ))), + &hints.get_dictionary_mut(), + ) + } else { + rxing::helpers::detect_multiple_in_luma_with_hints( + data, + width, + height, + hints.get_dictionary_mut(), + ) }; - Ok(MultiDecodeResult::with_results( - results.into_iter().map(|r| r.into()).collect(), - )) + result + .map(|value| { + let r: Vec = value.into_iter().map(|v| v.into()).collect(); + r + }) + .map_err(|err| err.to_string()) }