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