Detect and decode QR Codes, written in 100% Rust.
This library came about after perusing the Not Yet Awesome Rust list. It strives to be modular so algorithms with different strengths, speeds and robustness can be used interchangeably.
Add the following to your Cargo.toml
:
[dependencies]
bardecoder = "0.3.0"
image = "0.23"
The quickest way to integrate is to use the built-in default decoder. This will work for the vast majority of cases, though please keep in mind the Tips below.
fn main() {
let img = image::open("<<image location>>").unwrap();
// Use default decoder
let decoder = bardecoder::default_decoder();
let results = decoder.decode(&img);
for result in results {
println!("{}", result.unwrap());
}
}
If you want a little customizability, you can start with the default builder instead. It will be pre-populated with the default components but you are free to replace any of them with modified parameters.
use bardecoder;
use bardecoder::prepare::BlockedMean;
use image;
fn main() {
let img = image::open("<<image location>>").unwrap();
// Use default decoder builder
let mut db = bardecoder::default_builder();
// Use some different arguments in one of the default components
db.prepare(Box::new(BlockedMean::new(7, 9)));
// Build the actual decoder
let decoder = db.build();
let results = decoder.decode(&img);
for result in results {
println!("{}", result.unwrap());
}
}
You can also start with a completely empty builder but be aware that the build()
function will Panic!
if any of the components are missing.
use bardecoder::DecoderBuilder;
let mut decoder_builder = DecoderBuilder::new();
If you want to go absolutely nuts, you can also provide your own implementations for the various components. Use at your own risk!
use bardecoder;
use bardecoder::prepare::BlockedMean;
use bardecoder::detect::{Detect, Location};
use image;
use image::GrayImage;
struct MyDetector {}
impl MyDetector {
pub fn new() -> MyDetector {
MyDetector {}
}
}
impl Detect<GrayImage> for MyDetector {
fn detect(&self, prepared: &GrayImage) -> Vec<Location> {
vec![]
}
}
fn main() {
let img = image::open("<<image location>>").unwrap();
// Use default decoder builder
let mut db = bardecoder::default_builder();
// Use some different arguments in one of the default components
db.prepare(Box::new(BlockedMean::new(7, 9)));
// Use your homemade Detector!
db.detect(Box::new(MyDetector::new()));
// Build the actual decoder
let decoder = db.build();
let results = decoder.decode(&img);
for result in results {
println!("{}", result.unwrap());
}
}
Though this library can handle all sorts of QR images, here are some tips for optimal results:
- Keep the resolution of the source image low-ish, say between 400x300 and 800x600 pixels. Any higher and it takes quite long to detect any codes.
- Keep the QR code centered and zoomed in.
- Keep the QR code free of errors, deliberate or otherwise. While QR codes are self-correcting, the actual correction is not cheap. However before starting that process it is easy to detect that a QR code is error free so in that case an early exit is taken.
Bardecoder
exposes the following features for use in your project:
-
debug-images
: Some of the default components will output debug images in the<tmp>/bardecoder-debug-images
folder, where<tmp>
is the default OS temp folder. This can help show visually what the algorithms are doing. Be aware that some of the components (for exampleQRExtractor
) output a lot of images so definitely do not use this feature other than to have a look what is happening when things are going wrong. -
fail-on-warnings
: if you fancy that sort of thing, though its purpose is mostly fortravis-ci
.
If you find an image with a QR code that this library is unable to decode, please raise an Issue. Please include the image and the code you are trying to decode it with (especially when using the Modified method). I will try my best improve the algorithm though I cannot 100% guarantee that I will succeed, especially with more esoteric QR codes.
If you find a small bug and manage to fix it yourself, please feel free to submit a pull request. For larger refactorings and more fundamental issues please submit a ticket outlining the problem and potential solution.