1#![allow(unknown_lints)] #![allow(unused_unsafe)]
8#![allow(clippy::useless_transmute)]
9#![allow(clippy::redundant_closure_call)]
10#![allow(clippy::missing_transmute_annotations)] mod tests;
13
14#[allow(dead_code)]
15#[allow(non_camel_case_types)]
16#[allow(non_snake_case)]
17#[allow(non_upper_case_globals)]
18mod bindings {
19 include!("bindings.rs");
20}
21
22use bindings::*;
23
24use paste::paste;
25use std::ffi::{c_char, c_int, c_void, CStr, CString, NulError};
26use std::fmt::{Display, Formatter};
27use std::marker::PhantomData;
28use std::mem::transmute;
29use std::ptr::null;
30use std::rc::Rc;
31use std::slice;
32use thiserror::Error;
33
34#[derive(Error, Debug)]
35pub enum Error {
36 #[error("{0}")]
37 InvalidInput(String),
38
39 #[error("NulError from CString::new")]
40 NulError(#[from] NulError),
41 }
54
55impl From<std::convert::Infallible> for Error {
57 fn from(_: std::convert::Infallible) -> Self {
58 unreachable!()
59 }
60}
61
62fn c2r_str(str: *mut c_char) -> String {
63 let mut res = String::new();
64 if !str.is_null() {
65 unsafe { res = CStr::from_ptr(str).to_string_lossy().to_string() };
66 unsafe { ZXing_free(str as *mut c_void) };
67 }
68 res
69}
70
71fn c2r_vec(buf: *mut u8, len: c_int) -> Vec<u8> {
72 let mut res = Vec::<u8>::new();
73 if !buf.is_null() && len > 0 {
74 unsafe { res = std::slice::from_raw_parts(buf, len as usize).to_vec() };
75 unsafe { ZXing_free(buf as *mut c_void) };
76 }
77 res
78}
79
80fn last_error() -> Error {
81 match unsafe { ZXing_LastErrorMsg().as_mut() } {
82 None => panic!("Internal error: ZXing_LastErrorMsg() returned NULL"),
83 Some(error) => Error::InvalidInput(c2r_str(error)),
84 }
85}
86
87macro_rules! last_error_or {
90 ($expr:expr) => {
91 match unsafe { ZXing_LastErrorMsg().as_mut() } {
92 None => Ok($expr),
93 Some(error) => Err(Error::InvalidInput(c2r_str(error))),
94 }
95 };
96}
97
98macro_rules! last_error_if_null_or {
99 ($ptr:ident, $expr:expr) => {
100 match $ptr.is_null() {
101 true => Err(last_error()),
102 false => Ok($expr),
103 }
104 };
105}
106
107macro_rules! make_zxing_class {
108 ($r_class:ident, $c_class:ident) => {
109 paste! {
110 pub struct $r_class(*mut $c_class);
111
112 impl Drop for $r_class {
113 fn drop(&mut self) {
114 unsafe { [<$c_class _delete>](self.0) }
115 }
116 }
117 }
118 };
119}
120
121macro_rules! make_zxing_class_with_default {
122 ($r_class:ident, $c_class:ident) => {
123 make_zxing_class!($r_class, $c_class);
124 paste! {
125 impl $r_class {
126 pub fn new() -> Self {
127 unsafe { $r_class([<$c_class _new>]()) }
128 }
129 }
130
131 impl Default for $r_class {
132 fn default() -> Self {
133 Self::new()
134 }
135 }
136 }
137 };
138}
139
140macro_rules! getter {
141 ($class:ident, $c_name:ident, $r_name:ident, $conv:expr, $type:ty) => {
142 pub fn $r_name(&self) -> $type {
143 paste! { unsafe { $conv([<ZXing_ $class _ $c_name>](self.0)) } }
144 }
145 };
146 ($class:ident, $c_name:ident, $conv:expr, $type:ty) => {
147 paste! { getter! { $class, $c_name, [<$c_name:snake>], $conv, $type } }
148 };
149}
150
151macro_rules! property {
159 ($class:ident, $c_name:ident, $r_name:ident, String) => {
160 pub fn $r_name(self, v: impl AsRef<str>) -> Self {
161 let cstr = CString::new(v.as_ref()).unwrap();
162 paste! { unsafe { [<ZXing_ $class _set $c_name>](self.0, cstr.as_ptr()) } };
163 self
164 }
165
166 paste! {
167 pub fn [<set_ $r_name>](&mut self, v : impl AsRef<str>) -> &mut Self {
168 let cstr = CString::new(v.as_ref()).unwrap();
169 unsafe { [<ZXing_ $class _set $c_name>](self.0, cstr.as_ptr()) };
170 self
171 }
172
173 pub fn [<get_ $r_name>](&self) -> String {
174 unsafe { c2r_str([<ZXing_ $class _get $c_name>](self.0)) }
175 }
176 }
177 };
178
179 ($class:ident, $c_name:ident, $r_name:ident, $type:ty) => {
180 pub fn $r_name(self, v: impl Into<$type>) -> Self {
181 paste! { unsafe { [<ZXing_ $class _set $c_name>](self.0, transmute(v.into())) } };
182 self
183 }
184
185 paste! {
186 pub fn [<set_ $r_name>](&mut self, v : impl Into<$type>) -> &mut Self {
187 unsafe { [<ZXing_ $class _set $c_name>](self.0, transmute(v.into())) };
188 self
189 }
190
191 pub fn [<get_ $r_name>](&self) -> $type {
192 unsafe { transmute([<ZXing_ $class _get $c_name>](self.0)) }
193 }
194 }
195 };
196
197 ($class:ident, $c_name:ident, $type:ty) => {
198 paste! { property! { $class, $c_name, [<$c_name:snake>], $type } }
199 };
200}
201
202macro_rules! make_zxing_enum {
203 ($name:ident { $($field:ident),* }) => {
204 #[repr(u32)]
205 #[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord)]
206 pub enum $name {
207 $($field = paste! { [<ZXing_ $name _ $field>] },)*
208 }
209 }
210}
211
212#[rustfmt::skip] make_zxing_enum!(ImageFormat { Lum, LumA, RGB, BGR, RGBA, ARGB, BGRA, ABGR });
216#[rustfmt::skip]
217make_zxing_enum!(ContentType { Text, Binary, Mixed, GS1, ISO15434, UnknownECI });
218#[rustfmt::skip]
219make_zxing_enum!(Binarizer { LocalAverage, GlobalHistogram, FixedThreshold, BoolCast });
220#[rustfmt::skip]
221make_zxing_enum!(TextMode { Plain, ECI, HRI, Escaped, Hex, HexECI });
222#[rustfmt::skip]
223make_zxing_enum!(EanAddOnSymbol { Ignore, Read, Require });
224
225#[rustfmt::skip]
226make_zxing_enum!(BarcodeFormat {
227 Invalid, None, All, AllReadable, AllCreatable, AllLinear, AllMatrix, AllGS1,
228 Codabar, Code39, PZN, Code93, Code128, ITF,
229 DataBar, DataBarOmni, DataBarStk, DataBarStkOmni, DataBarLtd, DataBarExp, DataBarExpStk,
230 EANUPC, EAN13, EAN8, EAN5, EAN2, ISBN, UPCA, UPCE, OtherBarcode, DXFilmEdge,
231 PDF417, CompactPDF417, MicroPDF417,
232 Aztec, AztecCode, AztecRune,
233 QRCode, QRCodeModel1, QRCodeModel2, MicroQRCode, RMQRCode,
234 DataMatrix, MaxiCode
235});
236
237impl Display for BarcodeFormat {
238 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
239 write!(f, "{}", unsafe { c2r_str(ZXing_BarcodeFormatToString(transmute(*self))) })
240 }
241}
242
243impl Display for ContentType {
244 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
245 write!(f, "{}", unsafe { c2r_str(ZXing_ContentTypeToString(transmute(*self))) })
246 }
247}
248
249impl BarcodeFormat {
250 pub fn symbology(self) -> BarcodeFormat {
251 unsafe { transmute(ZXing_BarcodeFormatSymbology(transmute(self))) }
252 }
253}
254
255#[derive(Clone, Debug, Default)]
258pub struct BarcodeFormats(pub Vec<BarcodeFormat>);
259
260impl BarcodeFormats {
261 pub fn as_slice(&self) -> &[BarcodeFormat] {
262 &self.0
263 }
264 pub fn is_empty(&self) -> bool {
265 self.0.is_empty()
266 }
267 pub fn len(&self) -> usize {
268 self.0.len()
269 }
270 pub fn contains(&self, f: BarcodeFormat) -> bool {
271 self.0.contains(&f)
272 }
273 pub fn iter(&self) -> std::slice::Iter<'_, BarcodeFormat> {
274 self.0.iter()
275 }
276
277 pub fn list(filter: BarcodeFormat) -> Self {
278 unsafe {
279 let mut size: c_int = 0;
280 let ptr = ZXing_BarcodeFormatsList(transmute(filter), &mut size) as *const BarcodeFormat;
281 if ptr.is_null() || size == 0 {
282 BarcodeFormats::default()
283 } else {
284 BarcodeFormats(slice::from_raw_parts(ptr, size as usize).to_vec())
285 }
286 }
287 }
288}
289
290impl PartialEq<[BarcodeFormat]> for BarcodeFormats {
291 fn eq(&self, other: &[BarcodeFormat]) -> bool {
292 self.0.as_slice() == other
293 }
294}
295
296impl PartialEq<BarcodeFormats> for [BarcodeFormat] {
297 fn eq(&self, other: &BarcodeFormats) -> bool {
298 self == other.0.as_slice()
299 }
300}
301
302impl Display for BarcodeFormats {
303 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
304 write!(f, "{}", unsafe {
305 c2r_str(ZXing_BarcodeFormatsToString(transmute(self.0.as_ptr()), self.0.len() as c_int))
306 })
307 }
308}
309
310impl From<Vec<BarcodeFormat>> for BarcodeFormats {
317 fn from(v: Vec<BarcodeFormat>) -> Self {
318 BarcodeFormats(v)
319 }
320}
321impl From<&[BarcodeFormat]> for BarcodeFormats {
322 fn from(s: &[BarcodeFormat]) -> Self {
323 BarcodeFormats(s.to_vec())
324 }
325}
326
327impl AsRef<[BarcodeFormat]> for BarcodeFormats {
328 fn as_ref(&self) -> &[BarcodeFormat] {
329 &self.0
330 }
331}
332
333impl AsRef<[BarcodeFormat]> for BarcodeFormat {
334 fn as_ref(&self) -> &[BarcodeFormat] {
335 std::slice::from_ref(self)
336 }
337}
338
339pub trait FromStr: Sized {
340 fn from_str(str: impl AsRef<str>) -> Result<Self, Error>;
341}
342
343impl FromStr for BarcodeFormat {
344 fn from_str(str: impl AsRef<str>) -> Result<BarcodeFormat, Error> {
345 let cstr = CString::new(str.as_ref())?;
346 let fmt = unsafe { ZXing_BarcodeFormatFromString(cstr.as_ptr()) };
347 if fmt == ZXing_BarcodeFormat_Invalid {
348 last_error_or!(BarcodeFormat::Invalid)
349 } else {
350 Ok(unsafe { transmute(fmt) })
351 }
352 }
353}
354
355impl FromStr for BarcodeFormats {
356 fn from_str(str: impl AsRef<str>) -> Result<BarcodeFormats, Error> {
357 let cstr = CString::new(str.as_ref())?;
358 let mut size: c_int = 0;
359 let ptr = unsafe { ZXing_BarcodeFormatsFromString(cstr.as_ptr(), &mut size) as *const BarcodeFormat };
360 if ptr.is_null() || size == 0 {
361 last_error_or!(BarcodeFormats::default())
362 } else {
363 Ok(BarcodeFormats(unsafe { slice::from_raw_parts(ptr, size as usize).to_vec() }))
364 }
365 }
366}
367
368#[derive(Debug, PartialEq)]
371struct ImageViewOwner<'a>(*mut ZXing_ImageView, PhantomData<&'a u8>);
372
373impl Drop for ImageViewOwner<'_> {
374 fn drop(&mut self) {
375 unsafe { ZXing_ImageView_delete(self.0) }
376 }
377}
378#[derive(Debug, Clone, PartialEq)]
379pub struct ImageView<'a>(Rc<ImageViewOwner<'a>>);
380
381impl<'a> From<&'a ImageView<'a>> for ImageView<'a> {
382 fn from(img: &'a ImageView) -> Self {
383 img.clone()
384 }
385}
386
387impl<'a> ImageView<'a> {
388 fn try_into_int<T: TryInto<c_int>>(val: T) -> Result<c_int, Error> {
389 val.try_into().map_err(|_| Error::InvalidInput("Could not convert Integer into c_int.".to_string()))
390 }
391
392 pub unsafe fn from_ptr<T: TryInto<c_int>, U: TryInto<c_int>>(
402 ptr: *const u8,
403 width: T,
404 height: T,
405 format: ImageFormat,
406 row_stride: U,
407 pix_stride: U,
408 ) -> Result<Self, Error> {
409 let iv = ZXing_ImageView_new(
410 ptr,
411 Self::try_into_int(width)?,
412 Self::try_into_int(height)?,
413 format as ZXing_ImageFormat,
414 Self::try_into_int(row_stride)?,
415 Self::try_into_int(pix_stride)?,
416 );
417 last_error_if_null_or!(iv, ImageView(Rc::new(ImageViewOwner(iv, PhantomData))))
418 }
419
420 pub fn from_slice<T: TryInto<c_int>>(data: &'a [u8], width: T, height: T, format: ImageFormat) -> Result<Self, Error> {
421 unsafe {
422 let iv = ZXing_ImageView_new_checked(
423 data.as_ptr(),
424 data.len() as c_int,
425 Self::try_into_int(width)?,
426 Self::try_into_int(height)?,
427 format as ZXing_ImageFormat,
428 0,
429 0,
430 );
431 last_error_if_null_or!(iv, ImageView(Rc::new(ImageViewOwner(iv, PhantomData))))
432 }
433 }
434
435 pub fn cropped(self, left: i32, top: i32, width: i32, height: i32) -> Self {
436 unsafe { ZXing_ImageView_crop((self.0).0, left, top, width, height) }
437 self
438 }
439
440 pub fn rotated(self, degree: i32) -> Self {
441 unsafe { ZXing_ImageView_rotate((self.0).0, degree) }
442 self
443 }
444}
445
446#[cfg(feature = "image")]
447use image;
448
449#[cfg(feature = "image")]
450impl<'a> From<&'a image::GrayImage> for ImageView<'a> {
451 fn from(img: &'a image::GrayImage) -> Self {
452 ImageView::from_slice(img.as_ref(), img.width(), img.height(), ImageFormat::Lum).unwrap()
453 }
454}
455
456#[cfg(feature = "image")]
457impl<'a> TryFrom<&'a image::DynamicImage> for ImageView<'a> {
458 type Error = Error;
459
460 fn try_from(img: &'a image::DynamicImage) -> Result<Self, Error> {
461 let format = match img {
462 image::DynamicImage::ImageLuma8(_) => Some(ImageFormat::Lum),
463 image::DynamicImage::ImageLumaA8(_) => Some(ImageFormat::LumA),
464 image::DynamicImage::ImageRgb8(_) => Some(ImageFormat::RGB),
465 image::DynamicImage::ImageRgba8(_) => Some(ImageFormat::RGBA),
466 _ => None,
467 };
468 match format {
469 Some(format) => Ok(ImageView::from_slice(img.as_bytes(), img.width(), img.height(), format)?),
470 None => Err(Error::InvalidInput("Invalid image format (must be either luma8|lumaA8|rgb8|rgba8)".to_string())),
471 }
472 }
473}
474
475make_zxing_class!(Image, ZXing_Image);
478
479impl Image {
480 getter!(Image, width, transmute, i32);
481 getter!(Image, height, transmute, i32);
482 getter!(Image, format, transmute, ImageFormat);
483
484 pub fn data(&self) -> Vec<u8> {
485 let ptr = unsafe { ZXing_Image_data(self.0) };
486 if ptr.is_null() {
487 Vec::<u8>::new()
488 } else {
489 unsafe { std::slice::from_raw_parts(ptr, (self.width() * self.height()) as usize).to_vec() }
490 }
491 }
492}
493
494#[cfg(feature = "image")]
495impl From<&Image> for image::GrayImage {
496 fn from(img: &Image) -> image::GrayImage {
497 image::GrayImage::from_vec(img.width() as u32, img.height() as u32, img.data()).unwrap()
498 }
499}
500
501#[derive(Error, Debug, PartialEq)]
502pub enum BarcodeError {
503 #[error("")]
504 None(),
505
506 #[error("{0}")]
507 Checksum(String),
508
509 #[error("{0}")]
510 Format(String),
511
512 #[error("{0}")]
513 Unsupported(String),
514}
515
516pub type PointI = ZXing_PointI;
519#[repr(C)]
520#[derive(Debug, Copy, Clone)]
521pub struct Position {
522 pub top_left: PointI,
523 pub top_right: PointI,
524 pub bottom_right: PointI,
525 pub bottom_left: PointI,
526}
527
528impl Display for PointI {
529 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
530 write!(f, "{}x{}", self.x, self.y)
531 }
532}
533
534impl Display for Position {
535 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
536 write!(f, "{}", unsafe {
537 c2r_str(ZXing_PositionToString(*(self as *const Position as *const ZXing_Position)))
538 })
539 }
540}
541
542make_zxing_class!(Barcode, ZXing_Barcode);
545
546impl Barcode {
547 getter!(Barcode, isValid, transmute, bool);
548 getter!(Barcode, format, transmute, BarcodeFormat);
549 getter!(Barcode, symbology, transmute, BarcodeFormat);
550 getter!(Barcode, contentType, transmute, ContentType);
551 getter!(Barcode, text, c2r_str, String);
552 getter!(Barcode, symbologyIdentifier, c2r_str, String);
553 getter!(Barcode, position, transmute, Position);
554 getter!(Barcode, orientation, transmute, i32);
555 getter!(Barcode, hasECI, has_eci, transmute, bool);
556 getter!(Barcode, isInverted, transmute, bool);
557 getter!(Barcode, isMirrored, transmute, bool);
558 getter!(Barcode, lineCount, transmute, i32);
559 getter!(Barcode, sequenceSize, transmute, i32);
560 getter!(Barcode, sequenceIndex, transmute, i32);
561 getter!(Barcode, sequenceId, c2r_str, String);
562
563 pub fn bytes(&self) -> Vec<u8> {
564 let mut len: c_int = 0;
565 unsafe { c2r_vec(ZXing_Barcode_bytes(self.0, &mut len), len) }
566 }
567 pub fn bytes_eci(&self) -> Vec<u8> {
568 let mut len: c_int = 0;
569 unsafe { c2r_vec(ZXing_Barcode_bytesECI(self.0, &mut len), len) }
570 }
571
572 pub fn extra(&self) -> String {
573 unsafe { c2r_str(ZXing_Barcode_extra(self.0, null())) }
574 }
575
576 pub fn extra_with_key(&self, key: impl AsRef<str>) -> String {
577 let cstr = CString::new(key.as_ref()).unwrap();
578 unsafe { c2r_str(ZXing_Barcode_extra(self.0, cstr.as_ptr())) }
579 }
580
581 pub fn error(&self) -> BarcodeError {
582 let error_type = unsafe { ZXing_Barcode_errorType(self.0) };
583 let error_msg = unsafe { c2r_str(ZXing_Barcode_errorMsg(self.0)) };
584 #[allow(non_upper_case_globals)]
585 match error_type {
586 ZXing_ErrorType_None => BarcodeError::None(),
587 ZXing_ErrorType_Format => BarcodeError::Format(error_msg),
588 ZXing_ErrorType_Checksum => BarcodeError::Checksum(error_msg),
589 ZXing_ErrorType_Unsupported => BarcodeError::Unsupported(error_msg),
590 _ => panic!("Internal error: invalid ZXing_ErrorType"),
591 }
592 }
593
594 pub fn to_svg_with(&self, opts: &BarcodeWriter) -> Result<String, Error> {
595 let str = unsafe { ZXing_WriteBarcodeToSVG(self.0, opts.0) };
596 last_error_if_null_or!(str, c2r_str(str))
597 }
598
599 pub fn to_svg(&self) -> Result<String, Error> {
600 self.to_svg_with(&BarcodeWriter::default())
601 }
602
603 pub fn to_image_with(&self, opts: &BarcodeWriter) -> Result<Image, Error> {
604 let img = unsafe { ZXing_WriteBarcodeToImage(self.0, opts.0) };
605 last_error_if_null_or!(img, Image(img))
606 }
607
608 pub fn to_image(&self) -> Result<Image, Error> {
609 self.to_image_with(&BarcodeWriter::default())
610 }
611}
612
613make_zxing_class_with_default!(BarcodeReader, ZXing_ReaderOptions);
616
617impl BarcodeReader {
618 property!(ReaderOptions, TryHarder, bool);
619 property!(ReaderOptions, TryRotate, bool);
620 property!(ReaderOptions, TryInvert, bool);
621 property!(ReaderOptions, TryDownscale, bool);
622 property!(ReaderOptions, IsPure, bool);
623 property!(ReaderOptions, ValidateOptionalChecksum, bool);
624 property!(ReaderOptions, ReturnErrors, bool);
625 property!(ReaderOptions, Binarizer, Binarizer);
626 property!(ReaderOptions, EanAddOnSymbol, EanAddOnSymbol);
627 property!(ReaderOptions, TextMode, TextMode);
628 property!(ReaderOptions, MinLineCount, i32);
629 property!(ReaderOptions, MaxNumberOfSymbols, i32);
630
631 pub fn formats(self, v: impl AsRef<[BarcodeFormat]>) -> Self {
632 unsafe { ZXing_ReaderOptions_setFormats(self.0, transmute(v.as_ref().as_ptr()), v.as_ref().len() as c_int) };
633 self
634 }
635
636 pub fn set_formats(&mut self, v: impl AsRef<[BarcodeFormat]>) -> &mut Self {
637 unsafe { ZXing_ReaderOptions_setFormats(self.0, transmute(v.as_ref().as_ptr()), v.as_ref().len() as c_int) };
638 self
639 }
640
641 pub fn get_formats(&self) -> BarcodeFormats {
642 unsafe {
643 let mut size: c_int = 0;
644 let ptr = ZXing_ReaderOptions_getFormats(self.0, &mut size) as *const BarcodeFormat;
645 if ptr.is_null() || size == 0 {
646 BarcodeFormats::default()
647 } else {
648 BarcodeFormats(slice::from_raw_parts(ptr, size as usize).to_vec())
649 }
650 }
651 }
652
653 pub fn from<'a, IV>(&self, image: IV) -> Result<Vec<Barcode>, Error>
654 where
655 IV: TryInto<ImageView<'a>>,
656 IV::Error: Into<Error>,
657 {
658 let iv_: ImageView = image.try_into().map_err(Into::into)?;
659 unsafe {
660 let results = ZXing_ReadBarcodes((iv_.0).0, self.0);
661 if !results.is_null() {
662 let size = ZXing_Barcodes_size(results);
663 let mut vec = Vec::<Barcode>::with_capacity(size as usize);
664 for i in 0..size {
665 vec.push(Barcode(ZXing_Barcodes_move(results, i)));
666 }
667 ZXing_Barcodes_delete(results);
668 Ok(vec)
669 } else {
670 Err(last_error())
671 }
672 }
673 }
674}
675
676make_zxing_class!(BarcodeCreator, ZXing_CreatorOptions);
679
680impl BarcodeCreator {
681 pub fn new(format: BarcodeFormat) -> Self {
682 unsafe { BarcodeCreator(ZXing_CreatorOptions_new(format as ZXing_BarcodeFormat)) }
683 }
684
685 property!(CreatorOptions, Options, String);
686
687 pub fn from_str(&self, str: impl AsRef<str>) -> Result<Barcode, Error> {
688 let cstr = CString::new(str.as_ref())?;
689 let bc = unsafe { ZXing_CreateBarcodeFromText(cstr.as_ptr(), 0, self.0) };
690 last_error_if_null_or!(bc, Barcode(bc))
691 }
692
693 pub fn from_slice(&self, data: impl AsRef<[u8]>) -> Result<Barcode, Error> {
694 let data = data.as_ref();
695 let bc = unsafe { ZXing_CreateBarcodeFromBytes(data.as_ptr() as *const c_void, data.len() as i32, self.0) };
696 last_error_if_null_or!(bc, Barcode(bc))
697 }
698}
699
700make_zxing_class_with_default!(BarcodeWriter, ZXing_WriterOptions);
703
704impl BarcodeWriter {
705 property!(WriterOptions, Scale, i32);
706 property!(WriterOptions, Rotate, i32);
707 property!(WriterOptions, AddHRT, add_hrt, bool);
708 property!(WriterOptions, AddQuietZones, bool);
709}
710
711pub fn read() -> BarcodeReader {
714 BarcodeReader::default()
715}
716
717pub fn create(format: BarcodeFormat) -> BarcodeCreator {
718 BarcodeCreator::new(format)
719}
720
721pub fn write() -> BarcodeWriter {
722 BarcodeWriter::default()
723}