diff --git a/README.md b/README.md index eacc7a2..8c7e1a7 100644 --- a/README.md +++ b/README.md @@ -131,6 +131,9 @@ This repository contains examples demonstrating how to utilize the **Dynamsoft B ![Raspberry Pi barcode QR detection](https://www.dynamsoft.com/codepool/img/2020/06/raspberry-pi-barcode-qr.png) +- [Rust](./examples/9.x/rust/) + + ![Rust Barcode Reader](https://www.dynamsoft.com/codepool/img/2024/06/rust-command-line-barcode-reader.jpg) ## Blog - [CMake: Build C++ Project for Windows, Linux and macOS](https://www.dynamsoft.com/codepool/cmake-cc-windows-linux-macos.html) diff --git a/examples/9.x/rust/.gitignore b/examples/9.x/rust/.gitignore new file mode 100644 index 0000000..53eaa21 --- /dev/null +++ b/examples/9.x/rust/.gitignore @@ -0,0 +1,2 @@ +/target +**/*.rs.bk diff --git a/examples/9.x/rust/Cargo.lock b/examples/9.x/rust/Cargo.lock new file mode 100644 index 0000000..f7bdaad --- /dev/null +++ b/examples/9.x/rust/Cargo.lock @@ -0,0 +1,118 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "cc" +version = "1.0.98" +source = "registry+/~https://github.com/rust-lang/crates.io-index" +checksum = "41c270e7540d725e65ac7f1b212ac8ce349719624d7bcff99f8e2e488e8cf03f" + +[[package]] +name = "hello_world" +version = "0.1.0" +dependencies = [ + "cc", + "walkdir", +] + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+/~https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+/~https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "winapi-util" +version = "0.1.8" +source = "registry+/~https://github.com/rust-lang/crates.io-index" +checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+/~https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.5" +source = "registry+/~https://github.com/rust-lang/crates.io-index" +checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.5" +source = "registry+/~https://github.com/rust-lang/crates.io-index" +checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.5" +source = "registry+/~https://github.com/rust-lang/crates.io-index" +checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.5" +source = "registry+/~https://github.com/rust-lang/crates.io-index" +checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.5" +source = "registry+/~https://github.com/rust-lang/crates.io-index" +checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.5" +source = "registry+/~https://github.com/rust-lang/crates.io-index" +checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.5" +source = "registry+/~https://github.com/rust-lang/crates.io-index" +checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.5" +source = "registry+/~https://github.com/rust-lang/crates.io-index" +checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.5" +source = "registry+/~https://github.com/rust-lang/crates.io-index" +checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" diff --git a/examples/9.x/rust/Cargo.toml b/examples/9.x/rust/Cargo.toml new file mode 100644 index 0000000..8bc8784 --- /dev/null +++ b/examples/9.x/rust/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "hello_world" +version = "0.1.0" +edition = "2018" + +[build-dependencies] +cc = "1.0" +walkdir = "2.5.0" \ No newline at end of file diff --git a/examples/9.x/rust/README.md b/examples/9.x/rust/README.md new file mode 100644 index 0000000..3ed10d4 --- /dev/null +++ b/examples/9.x/rust/README.md @@ -0,0 +1,28 @@ +# Command-Line Barcode Reader in Rust +This project showcases a simple command-line barcode reader built using Rust and the Dynamsoft Barcode Reader SDK. + +## Prequisites +- [Rust](https://www.rust-lang.org/tools/install) +- [Dynamsoft Barcode Reader Trial License](https://www.dynamsoft.com/customer/license/trialLicense/?product=dbr) + +## Usage +1. Set the license key in `src/main.rs`: + + ```rust + let license = "LICENSE-KEY"; + ``` + +2. Clean and build the app: + + ```bash + cargo clean + cargo build + ``` + +3. Run the app: + + ```bash + cargo run + ``` + + ![Rust Barcode Reader](https://www.dynamsoft.com/codepool/img/2024/06/rust-command-line-barcode-reader.jpg) diff --git a/examples/9.x/rust/build.rs b/examples/9.x/rust/build.rs new file mode 100644 index 0000000..de9ca96 --- /dev/null +++ b/examples/9.x/rust/build.rs @@ -0,0 +1,100 @@ +use std::env; +use cc::Build; + +use std::fs; +use walkdir::WalkDir; +use std::path::{Path, PathBuf}; + +fn main() { + // Determine the target operating system + let target_os = env::var("CARGO_CFG_TARGET_OS").unwrap(); + println!("cargo:warning=OS: {}..............................................", target_os); + + match target_os.as_str() { + "windows" => { + // Link Dynamsoft Barcode Reader for Windows + println!("cargo:rustc-link-search=../../../platforms/win/lib"); + println!("cargo:rustc-link-lib=static=DBRx64"); + + // Copy *.dll files to the output path for Windows + let src_dir = Path::new("../../../platforms/win/bin"); + copy_shared_libs_from_dir_to_out_dir(src_dir, &get_out_dir(), "dll"); + }, + "linux" => { + // Link Dynamsoft Barcode Reader for Linux + println!("cargo:rustc-link-search=../../../platforms/linux"); + println!("cargo:rustc-link-lib=dylib=DynamsoftBarcodeReader"); + + // Set rpath for Linux + println!("cargo:rustc-link-arg=-Wl,-rpath,../../../platforms/linux"); + + // Copy *.so files to the output path for Linux + let src_dir = Path::new("../../../platforms/linux/bin"); + copy_shared_libs_from_dir_to_out_dir(src_dir, &get_out_dir(), "so"); + }, + "macos" => { + // Link Dynamsoft Barcode Reader for macOS + println!("cargo:rustc-link-search=../../../platforms/macos"); + println!("cargo:rustc-link-lib=dylib=DynamsoftBarcodeReader"); + + // Set rpath for macOS + println!("cargo:rustc-link-arg=-Wl,-rpath,@loader_path/../../../platforms/macos"); + + // Copy *.dylib files to the output path for macOS + let src_dir = Path::new("../../../platforms/macos"); + copy_shared_libs_from_dir_to_out_dir(src_dir, &get_out_dir(), "dylib"); + }, + _ => { + panic!("Unsupported target OS: {}", target_os); + } + } + + // Compile the C++ code + Build::new() + .cpp(true) + .include("../../../include") + .file("lib/bridge.cpp") + .compile("bridge"); + + // Tell cargo to tell rustc to link the compiled C library + println!("cargo:rustc-link-lib=static=bridge"); + + // Add the directory where the library was built to the search path + println!("cargo:rustc-link-search=native={}", env::var("OUT_DIR").unwrap()); +} + +fn get_out_dir() -> PathBuf { + let out_dir = env::var("OUT_DIR").unwrap(); + let debug_offset = out_dir.find("debug").unwrap_or(0); + let release_offset = out_dir.find("release").unwrap_or(0); + let mut path = String::from(""); + + if debug_offset > 0 { + println!(">>> where is debug {}", debug_offset); + path.push_str(&format!("{}", &out_dir[..debug_offset])); + path.push_str("debug"); + println!("{}", path); + } + + if release_offset > 0 { + println!(">>> where is release {}", release_offset); + path.push_str(&format!("{}", &out_dir[..release_offset])); + path.push_str("release"); + println!("{}", path); + } + + PathBuf::from(path) +} + +fn copy_shared_libs_from_dir_to_out_dir(src_dir: &Path, out_dir: &Path, extension: &str) { + for entry in WalkDir::new(src_dir).into_iter().filter_map(|e| e.ok()) { + if entry.path().extension().and_then(|ext| ext.to_str()) == Some(extension) { + let lib_path = entry.path(); + let file_name = lib_path.file_name().unwrap(); + let dest_path = out_dir.join(file_name); + + fs::copy(lib_path, dest_path.clone()).expect("Failed to copy shared library"); + println!("Copied {} to {}", lib_path.display(), dest_path.display()); + } + } +} \ No newline at end of file diff --git a/examples/9.x/rust/lib/bridge.cpp b/examples/9.x/rust/lib/bridge.cpp new file mode 100644 index 0000000..a26e29a --- /dev/null +++ b/examples/9.x/rust/lib/bridge.cpp @@ -0,0 +1,64 @@ +#include "bridge.h" +#include +#include + +Barcode *create_barcode(const char *type, const char *value, int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4) +{ + Barcode *barcode = (Barcode *)std::malloc(sizeof(Barcode)); + barcode->barcode_type = strdup(type); + barcode->barcode_value = strdup(value); + barcode->x1 = x1; + barcode->y1 = y1; + barcode->x2 = x2; + barcode->y2 = y2; + barcode->x3 = x3; + barcode->y3 = y3; + barcode->x4 = x4; + barcode->y4 = y4; + return barcode; +} + +void free_barcode(BarcodeResults *results) +{ + for (int i = 0; i < results->count; i++) + { + std::free((void *)results->barcodes[i].barcode_type); + std::free((void *)results->barcodes[i].barcode_value); + } + std::free(results->barcodes); + std::free(results); +} + +int init_license(const char *license) +{ + char errorMsgBuffer[512]; + // Click https://www.dynamsoft.com/customer/license/trialLicense/?product=dbr to get a trial license. + int ret = DBR_InitLicense(license, errorMsgBuffer, 512); + return ret; +} + +BarcodeResults *decode_barcode_file(void *instance, const char *filename) +{ + char errorMsgBuffer[512]; + TextResultArray *pResults = NULL; + BarcodeResults *all_barcodes = NULL; + int ret = DBR_DecodeFile(instance, filename, ""); + DBR_GetAllTextResults(instance, &pResults); + if (pResults->resultsCount > 0) + { + all_barcodes = (BarcodeResults *)std::malloc(sizeof(BarcodeResults)); + all_barcodes->count = pResults->resultsCount; + all_barcodes->barcodes = (Barcode *)std::malloc(sizeof(Barcode) * pResults->resultsCount); + for (int iIndex = 0; iIndex < pResults->resultsCount; iIndex++) + { + LocalizationResult *localizationResult = pResults->results[iIndex]->localizationResult; + Barcode *barcode = create_barcode(pResults->results[iIndex]->barcodeFormatString, pResults->results[iIndex]->barcodeText, + localizationResult->x1, localizationResult->y1, localizationResult->x2, localizationResult->y2, + localizationResult->x3, localizationResult->y3, localizationResult->x4, localizationResult->y4); + all_barcodes->barcodes[iIndex] = *barcode; + } + } + + DBR_FreeTextResults(&pResults); + return all_barcodes; +} \ No newline at end of file diff --git a/examples/9.x/rust/lib/bridge.h b/examples/9.x/rust/lib/bridge.h new file mode 100644 index 0000000..2e4ffda --- /dev/null +++ b/examples/9.x/rust/lib/bridge.h @@ -0,0 +1,40 @@ +#ifndef BRIDGE_H +#define BRIDGE_H + +#include "DynamsoftBarcodeReader.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + + typedef struct + { + const char *barcode_type; + const char *barcode_value; + int x1; + int y1; + int x2; + int y2; + int x3; + int y3; + int x4; + int y4; + } Barcode; + + typedef struct + { + Barcode *barcodes; + int count; + } BarcodeResults; + + Barcode *create_barcode(const char *type, const char *value, int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4); + BarcodeResults *decode_barcode_file(void *instance, const char *filename); + void free_barcode(BarcodeResults *results); + int init_license(const char *license); + +#ifdef __cplusplus +} +#endif + +#endif // BRIDGE_H diff --git a/examples/9.x/rust/src/bindings.rs b/examples/9.x/rust/src/bindings.rs new file mode 100644 index 0000000..78828b7 --- /dev/null +++ b/examples/9.x/rust/src/bindings.rs @@ -0,0 +1,43 @@ +use std::ffi::c_void; +use std::os::raw::c_char; +use std::os::raw::c_int; + +#[repr(C)] +pub struct Barcode { + pub barcode_type: *const c_char, + pub barcode_value: *const c_char, + pub x1: c_int, + pub y1: c_int, + pub x2: c_int, + pub y2: c_int, + pub x3: c_int, + pub y3: c_int, + pub x4: c_int, + pub y4: c_int, +} + +#[repr(C)] +pub struct BarcodeResults { + pub barcodes: *mut Barcode, + pub count: c_int, +} + +extern "C" { + pub fn free_barcode(barcode: *mut BarcodeResults); + pub fn init_license(license: *const c_char) -> c_int; + pub fn decode_barcode_file(instance: *mut c_void, filename: *const c_char) -> *mut BarcodeResults; + pub fn DBR_CreateInstance() -> *mut c_void; + pub fn DBR_DestroyInstance(barcodeReader: *mut c_void); +} + +// pub fn create_dbr_instance() -> *mut c_void { +// unsafe { +// DBR_CreateInstance() +// } +// } + +// pub fn destroy_dbr_instance(instance_ptr: *mut c_void) { +// unsafe { +// DBR_DestroyInstance(instance_ptr); +// } +// } \ No newline at end of file diff --git a/examples/9.x/rust/src/main.rs b/examples/9.x/rust/src/main.rs new file mode 100644 index 0000000..4b2e6b8 --- /dev/null +++ b/examples/9.x/rust/src/main.rs @@ -0,0 +1,72 @@ +mod bindings; +use std::io::{self, Write}; +use std::ffi::CString; +use bindings::*; + +fn main() { + let license = "DLS2eyJoYW5kc2hha2VDb2RlIjoiMjAwMDAxLTE2NDk4Mjk3OTI2MzUiLCJvcmdhbml6YXRpb25JRCI6IjIwMDAwMSIsInNlc3Npb25QYXNzd29yZCI6IndTcGR6Vm05WDJrcEQ5YUoifQ=="; + + let ret = unsafe { + let license = CString::new(license).expect("CString::new failed"); + init_license(license.as_ptr()) + }; + + println!("InitLicense: {}", ret); + + let reader_ptr = unsafe { DBR_CreateInstance() }; + if reader_ptr.is_null() { + panic!("Failed to create barcode reader instance"); + } + + loop { + // Prompt the user to enter the file name + print!("Please enter the file name (or type 'exit' to quit): "); + io::stdout().flush().unwrap(); // Ensure the prompt is printed before reading input + + let mut file_name = String::new(); + io::stdin().read_line(&mut file_name).expect("Failed to read line"); + + // Remove the newline character from the input + let file_name = file_name.trim(); + + // Check if the user wants to exit + if file_name.to_lowercase() == "exit" { + break; + } + + // Use file_name for further processing + println!("Processing file: {}", file_name); + + let path = CString::new(file_name).expect("CString::new failed"); + + unsafe { + let results_ptr = decode_barcode_file(reader_ptr, path.as_ptr()); + + if results_ptr.is_null() { + println!("No barcodes found."); + } else { + let results = &*results_ptr; + let barcodes = std::slice::from_raw_parts(results.barcodes, results.count as usize); + + for (i, barcode) in barcodes.iter().enumerate() { + let barcode_type = std::ffi::CStr::from_ptr(barcode.barcode_type).to_string_lossy(); + let barcode_value = std::ffi::CStr::from_ptr(barcode.barcode_value).to_string_lossy(); + + println!("Barcode {}: type = {}, value = {}", i + 1, barcode_type, barcode_value); + println!( + "Coordinates: ({}, {}), ({}, {}), ({}, {}), ({}, {})", + barcode.x1, barcode.y1, barcode.x2, barcode.y2, + barcode.x3, barcode.y3, barcode.x4, barcode.y4 + ); + } + + free_barcode(results_ptr); + } + } + } + + // Free the reader instance after usage + unsafe { + DBR_DestroyInstance(reader_ptr); + } +}