Mercurial > hgrepos > Python2 > PyMuPDF
comparison mupdf-source/thirdparty/zxing-cpp/wrappers/rust/src/lib.rs @ 2:b50eed0cc0ef upstream
ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4.
The directory name has changed: no version number in the expanded directory now.
| author | Franz Glasner <fzglas.hg@dom66.de> |
|---|---|
| date | Mon, 15 Sep 2025 11:43:07 +0200 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 1:1d09e1dec1d9 | 2:b50eed0cc0ef |
|---|---|
| 1 /* | |
| 2 * Copyright 2024 Axel Waggershauser | |
| 3 */ | |
| 4 // SPDX-License-Identifier: Apache-2.0 | |
| 5 | |
| 6 #![allow(unknown_lints)] // backward compatibility | |
| 7 #![allow(unused_unsafe)] | |
| 8 #![allow(clippy::useless_transmute)] | |
| 9 #![allow(clippy::redundant_closure_call)] | |
| 10 #![allow(clippy::missing_transmute_annotations)] // introduced in 1.79 | |
| 11 | |
| 12 mod tests; | |
| 13 | |
| 14 #[allow(dead_code)] | |
| 15 #[allow(non_camel_case_types)] | |
| 16 #[allow(non_snake_case)] | |
| 17 #[allow(non_upper_case_globals)] | |
| 18 mod bindings { | |
| 19 include!("bindings.rs"); | |
| 20 } | |
| 21 | |
| 22 use bindings::*; | |
| 23 | |
| 24 use flagset::{flags, FlagSet}; | |
| 25 use paste::paste; | |
| 26 use std::ffi::{c_char, c_int, c_uint, c_void, CStr, CString, NulError}; | |
| 27 use std::fmt::{Display, Formatter}; | |
| 28 use std::marker::PhantomData; | |
| 29 use std::mem::transmute; | |
| 30 use std::rc::Rc; | |
| 31 use thiserror::Error; | |
| 32 | |
| 33 #[derive(Error, Debug)] | |
| 34 pub enum Error { | |
| 35 #[error("{0}")] | |
| 36 InvalidInput(String), | |
| 37 | |
| 38 #[error("NulError from CString::new")] | |
| 39 NulError(#[from] NulError), | |
| 40 // | |
| 41 // #[error("data store disconnected")] | |
| 42 // IOError(#[from] std::io::Error), | |
| 43 // #[error("the data for key `{0}` is not available")] | |
| 44 // Redaction(String), | |
| 45 // #[error("invalid header (expected {expected:?}, found {found:?})")] | |
| 46 // InvalidHeader { | |
| 47 // expected: String, | |
| 48 // found: String, | |
| 49 // }, | |
| 50 // #[error("unknown data store error")] | |
| 51 // Unknown, | |
| 52 } | |
| 53 | |
| 54 // see https://github.com/dtolnay/thiserror/issues/62 | |
| 55 impl From<std::convert::Infallible> for Error { | |
| 56 fn from(_: std::convert::Infallible) -> Self { | |
| 57 unreachable!() | |
| 58 } | |
| 59 } | |
| 60 | |
| 61 fn c2r_str(str: *mut c_char) -> String { | |
| 62 let mut res = String::new(); | |
| 63 if !str.is_null() { | |
| 64 unsafe { res = CStr::from_ptr(str).to_string_lossy().to_string() }; | |
| 65 unsafe { ZXing_free(str as *mut c_void) }; | |
| 66 } | |
| 67 res | |
| 68 } | |
| 69 | |
| 70 fn c2r_vec(buf: *mut u8, len: c_int) -> Vec<u8> { | |
| 71 let mut res = Vec::<u8>::new(); | |
| 72 if !buf.is_null() && len > 0 { | |
| 73 unsafe { res = std::slice::from_raw_parts(buf, len as usize).to_vec() }; | |
| 74 unsafe { ZXing_free(buf as *mut c_void) }; | |
| 75 } | |
| 76 res | |
| 77 } | |
| 78 | |
| 79 fn last_error() -> Error { | |
| 80 match unsafe { ZXing_LastErrorMsg().as_mut() } { | |
| 81 None => panic!("Internal error: ZXing_LastErrorMsg() returned NULL"), | |
| 82 Some(error) => Error::InvalidInput(c2r_str(error)), | |
| 83 } | |
| 84 } | |
| 85 | |
| 86 macro_rules! last_error_or { | |
| 87 ($expr:expr) => { | |
| 88 match unsafe { ZXing_LastErrorMsg().as_mut() } { | |
| 89 None => Ok($expr), | |
| 90 Some(error) => Err(Error::InvalidInput(c2r_str(error))), | |
| 91 } | |
| 92 }; | |
| 93 } | |
| 94 | |
| 95 macro_rules! last_error_if_null_or { | |
| 96 ($ptr:ident, $expr:expr) => { | |
| 97 match $ptr.is_null() { | |
| 98 true => Err(last_error()), | |
| 99 false => Ok($expr), | |
| 100 } | |
| 101 }; | |
| 102 } | |
| 103 | |
| 104 macro_rules! make_zxing_class { | |
| 105 ($r_class:ident, $c_class:ident) => { | |
| 106 paste! { | |
| 107 pub struct $r_class(*mut $c_class); | |
| 108 | |
| 109 impl Drop for $r_class { | |
| 110 fn drop(&mut self) { | |
| 111 unsafe { [<$c_class _delete>](self.0) } | |
| 112 } | |
| 113 } | |
| 114 } | |
| 115 }; | |
| 116 } | |
| 117 | |
| 118 macro_rules! make_zxing_class_with_default { | |
| 119 ($r_class:ident, $c_class:ident) => { | |
| 120 make_zxing_class!($r_class, $c_class); | |
| 121 paste! { | |
| 122 impl $r_class { | |
| 123 pub fn new() -> Self { | |
| 124 unsafe { $r_class([<$c_class _new>]()) } | |
| 125 } | |
| 126 } | |
| 127 | |
| 128 impl Default for $r_class { | |
| 129 fn default() -> Self { | |
| 130 Self::new() | |
| 131 } | |
| 132 } | |
| 133 } | |
| 134 }; | |
| 135 } | |
| 136 | |
| 137 macro_rules! getter { | |
| 138 ($class:ident, $c_name:ident, $r_name:ident, $conv:expr, $type:ty) => { | |
| 139 pub fn $r_name(&self) -> $type { | |
| 140 paste! { unsafe { $conv([<ZXing_ $class _ $c_name>](self.0)) } } | |
| 141 } | |
| 142 }; | |
| 143 ($class:ident, $c_name:ident, $conv:expr, $type:ty) => { | |
| 144 paste! { getter! { $class, $c_name, [<$c_name:snake>], $conv, $type } } | |
| 145 }; | |
| 146 } | |
| 147 | |
| 148 macro_rules! property { | |
| 149 ($class:ident, $c_name:ident, $r_name:ident, String) => { | |
| 150 pub fn $r_name(self, v: impl AsRef<str>) -> Self { | |
| 151 let cstr = CString::new(v.as_ref()).unwrap(); | |
| 152 paste! { unsafe { [<ZXing_ $class _set $c_name>](self.0, cstr.as_ptr()) } }; | |
| 153 self | |
| 154 } | |
| 155 | |
| 156 paste! { | |
| 157 pub fn [<set_ $r_name>](&mut self, v : impl AsRef<str>) -> &mut Self { | |
| 158 let cstr = CString::new(v.as_ref()).unwrap(); | |
| 159 unsafe { [<ZXing_ $class _set $c_name>](self.0, cstr.as_ptr()) }; | |
| 160 self | |
| 161 } | |
| 162 | |
| 163 pub fn [<get_ $r_name>](&self) -> String { | |
| 164 unsafe { c2r_str([<ZXing_ $class _get $c_name>](self.0)) } | |
| 165 } | |
| 166 } | |
| 167 }; | |
| 168 | |
| 169 ($class:ident, $c_name:ident, $r_name:ident, $type:ty) => { | |
| 170 pub fn $r_name(self, v: impl Into<$type>) -> Self { | |
| 171 paste! { unsafe { [<ZXing_ $class _set $c_name>](self.0, transmute(v.into())) } }; | |
| 172 self | |
| 173 } | |
| 174 | |
| 175 paste! { | |
| 176 pub fn [<set_ $r_name>](&mut self, v : impl Into<$type>) -> &mut Self { | |
| 177 unsafe { [<ZXing_ $class _set $c_name>](self.0, transmute(v.into())) }; | |
| 178 self | |
| 179 } | |
| 180 | |
| 181 pub fn [<get_ $r_name>](&self) -> $type { | |
| 182 unsafe { transmute([<ZXing_ $class _get $c_name>](self.0)) } | |
| 183 } | |
| 184 } | |
| 185 }; | |
| 186 | |
| 187 ($class:ident, $c_name:ident, $type:ty) => { | |
| 188 paste! { property! { $class, $c_name, [<$c_name:snake>], $type } } | |
| 189 }; | |
| 190 } | |
| 191 | |
| 192 macro_rules! make_zxing_enum { | |
| 193 ($name:ident { $($field:ident),* }) => { | |
| 194 #[repr(u32)] | |
| 195 #[derive(Debug, Copy, Clone, PartialEq)] | |
| 196 pub enum $name { | |
| 197 $($field = paste! { [<ZXing_ $name _ $field>] },)* | |
| 198 } | |
| 199 } | |
| 200 } | |
| 201 | |
| 202 macro_rules! make_zxing_flags { | |
| 203 ($name:ident { $($field:ident),* }) => { | |
| 204 flags! { | |
| 205 #[repr(u32)] | |
| 206 pub enum $name: c_uint { | |
| 207 $($field = paste! { [<ZXing_ $name _ $field>] },)* | |
| 208 } | |
| 209 } | |
| 210 } | |
| 211 } | |
| 212 #[rustfmt::skip] // workaround for broken #[rustfmt::skip::macros(make_zxing_enum)] | |
| 213 make_zxing_enum!(ImageFormat { Lum, LumA, RGB, BGR, RGBA, ARGB, BGRA, ABGR }); | |
| 214 #[rustfmt::skip] | |
| 215 make_zxing_enum!(ContentType { Text, Binary, Mixed, GS1, ISO15434, UnknownECI }); | |
| 216 #[rustfmt::skip] | |
| 217 make_zxing_enum!(Binarizer { LocalAverage, GlobalHistogram, FixedThreshold, BoolCast }); | |
| 218 #[rustfmt::skip] | |
| 219 make_zxing_enum!(TextMode { Plain, ECI, HRI, Hex, Escaped }); | |
| 220 #[rustfmt::skip] | |
| 221 make_zxing_enum!(EanAddOnSymbol { Ignore, Read, Require }); | |
| 222 | |
| 223 #[rustfmt::skip] | |
| 224 make_zxing_flags!(BarcodeFormat { | |
| 225 None, Aztec, Codabar, Code39, Code93, Code128, DataBar, DataBarExpanded, DataBarLimited, DataMatrix, | |
| 226 EAN8, EAN13, ITF, MaxiCode, PDF417, QRCode, UPCA, UPCE, MicroQRCode, RMQRCode, DXFilmEdge, | |
| 227 LinearCodes, MatrixCodes, Any | |
| 228 }); | |
| 229 | |
| 230 impl Display for BarcodeFormat { | |
| 231 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { | |
| 232 write!(f, "{}", unsafe { c2r_str(ZXing_BarcodeFormatToString(BarcodeFormats::from(*self).bits())) }) | |
| 233 } | |
| 234 } | |
| 235 | |
| 236 impl Display for ContentType { | |
| 237 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { | |
| 238 write!(f, "{}", unsafe { c2r_str(ZXing_ContentTypeToString(transmute(*self))) }) | |
| 239 } | |
| 240 } | |
| 241 | |
| 242 pub type BarcodeFormats = FlagSet<BarcodeFormat>; | |
| 243 | |
| 244 pub trait FromStr: Sized { | |
| 245 fn from_str(str: impl AsRef<str>) -> Result<Self, Error>; | |
| 246 } | |
| 247 | |
| 248 impl FromStr for BarcodeFormat { | |
| 249 fn from_str(str: impl AsRef<str>) -> Result<BarcodeFormat, Error> { | |
| 250 let cstr = CString::new(str.as_ref())?; | |
| 251 let res = unsafe { BarcodeFormats::new_unchecked(ZXing_BarcodeFormatFromString(cstr.as_ptr())) }; | |
| 252 match res.bits() { | |
| 253 u32::MAX => last_error_or!(BarcodeFormat::None), | |
| 254 _ => Ok(res.into_iter().last().unwrap()), | |
| 255 } | |
| 256 } | |
| 257 } | |
| 258 | |
| 259 impl FromStr for BarcodeFormats { | |
| 260 fn from_str(str: impl AsRef<str>) -> Result<BarcodeFormats, Error> { | |
| 261 let cstr = CString::new(str.as_ref())?; | |
| 262 let res = unsafe { BarcodeFormats::new_unchecked(ZXing_BarcodeFormatsFromString(cstr.as_ptr())) }; | |
| 263 match res.bits() { | |
| 264 u32::MAX => last_error_or!(BarcodeFormats::default()), | |
| 265 0 => Ok(BarcodeFormats::full()), | |
| 266 _ => Ok(res), | |
| 267 } | |
| 268 } | |
| 269 } | |
| 270 | |
| 271 #[derive(Debug, PartialEq)] | |
| 272 struct ImageViewOwner<'a>(*mut ZXing_ImageView, PhantomData<&'a u8>); | |
| 273 | |
| 274 impl Drop for ImageViewOwner<'_> { | |
| 275 fn drop(&mut self) { | |
| 276 unsafe { ZXing_ImageView_delete(self.0) } | |
| 277 } | |
| 278 } | |
| 279 #[derive(Debug, Clone, PartialEq)] | |
| 280 pub struct ImageView<'a>(Rc<ImageViewOwner<'a>>); | |
| 281 | |
| 282 impl<'a> From<&'a ImageView<'a>> for ImageView<'a> { | |
| 283 fn from(img: &'a ImageView) -> Self { | |
| 284 img.clone() | |
| 285 } | |
| 286 } | |
| 287 | |
| 288 impl<'a> ImageView<'a> { | |
| 289 fn try_into_int<T: TryInto<c_int>>(val: T) -> Result<c_int, Error> { | |
| 290 val.try_into().map_err(|_| Error::InvalidInput("Could not convert Integer into c_int.".to_string())) | |
| 291 } | |
| 292 | |
| 293 /// Constructs an ImageView from a raw pointer and the width/height (in pixels) | |
| 294 /// and row_stride/pix_stride (in bytes). | |
| 295 /// | |
| 296 /// # Safety | |
| 297 /// | |
| 298 /// The memory gets accessed inside the c++ library at random places between | |
| 299 /// `ptr` and `ptr + height * row_stride` or `ptr + width * pix_stride`. | |
| 300 /// Note that both the stride values could be negative, e.g. if the image | |
| 301 /// view is rotated. | |
| 302 pub unsafe fn from_ptr<T: TryInto<c_int>, U: TryInto<c_int>>( | |
| 303 ptr: *const u8, | |
| 304 width: T, | |
| 305 height: T, | |
| 306 format: ImageFormat, | |
| 307 row_stride: U, | |
| 308 pix_stride: U, | |
| 309 ) -> Result<Self, Error> { | |
| 310 let iv = ZXing_ImageView_new( | |
| 311 ptr, | |
| 312 Self::try_into_int(width)?, | |
| 313 Self::try_into_int(height)?, | |
| 314 format as ZXing_ImageFormat, | |
| 315 Self::try_into_int(row_stride)?, | |
| 316 Self::try_into_int(pix_stride)?, | |
| 317 ); | |
| 318 last_error_if_null_or!(iv, ImageView(Rc::new(ImageViewOwner(iv, PhantomData)))) | |
| 319 } | |
| 320 | |
| 321 pub fn from_slice<T: TryInto<c_int>>(data: &'a [u8], width: T, height: T, format: ImageFormat) -> Result<Self, Error> { | |
| 322 unsafe { | |
| 323 let iv = ZXing_ImageView_new_checked( | |
| 324 data.as_ptr(), | |
| 325 data.len() as c_int, | |
| 326 Self::try_into_int(width)?, | |
| 327 Self::try_into_int(height)?, | |
| 328 format as ZXing_ImageFormat, | |
| 329 0, | |
| 330 0, | |
| 331 ); | |
| 332 last_error_if_null_or!(iv, ImageView(Rc::new(ImageViewOwner(iv, PhantomData)))) | |
| 333 } | |
| 334 } | |
| 335 | |
| 336 pub fn cropped(self, left: i32, top: i32, width: i32, height: i32) -> Self { | |
| 337 unsafe { ZXing_ImageView_crop((self.0).0, left, top, width, height) } | |
| 338 self | |
| 339 } | |
| 340 | |
| 341 pub fn rotated(self, degree: i32) -> Self { | |
| 342 unsafe { ZXing_ImageView_rotate((self.0).0, degree) } | |
| 343 self | |
| 344 } | |
| 345 } | |
| 346 | |
| 347 #[cfg(feature = "image")] | |
| 348 use image; | |
| 349 | |
| 350 #[cfg(feature = "image")] | |
| 351 impl<'a> From<&'a image::GrayImage> for ImageView<'a> { | |
| 352 fn from(img: &'a image::GrayImage) -> Self { | |
| 353 ImageView::from_slice(img.as_ref(), img.width(), img.height(), ImageFormat::Lum).unwrap() | |
| 354 } | |
| 355 } | |
| 356 | |
| 357 #[cfg(feature = "image")] | |
| 358 impl<'a> TryFrom<&'a image::DynamicImage> for ImageView<'a> { | |
| 359 type Error = Error; | |
| 360 | |
| 361 fn try_from(img: &'a image::DynamicImage) -> Result<Self, Error> { | |
| 362 let format = match img { | |
| 363 image::DynamicImage::ImageLuma8(_) => Some(ImageFormat::Lum), | |
| 364 image::DynamicImage::ImageLumaA8(_) => Some(ImageFormat::LumA), | |
| 365 image::DynamicImage::ImageRgb8(_) => Some(ImageFormat::RGB), | |
| 366 image::DynamicImage::ImageRgba8(_) => Some(ImageFormat::RGBA), | |
| 367 _ => None, | |
| 368 }; | |
| 369 match format { | |
| 370 Some(format) => Ok(ImageView::from_slice(img.as_bytes(), img.width(), img.height(), format)?), | |
| 371 None => Err(Error::InvalidInput("Invalid image format (must be either luma8|lumaA8|rgb8|rgba8)".to_string())), | |
| 372 } | |
| 373 } | |
| 374 } | |
| 375 | |
| 376 make_zxing_class!(Image, ZXing_Image); | |
| 377 | |
| 378 impl Image { | |
| 379 getter!(Image, width, transmute, i32); | |
| 380 getter!(Image, height, transmute, i32); | |
| 381 getter!(Image, format, transmute, ImageFormat); | |
| 382 | |
| 383 pub fn data(&self) -> Vec<u8> { | |
| 384 let ptr = unsafe { ZXing_Image_data(self.0) }; | |
| 385 if ptr.is_null() { | |
| 386 Vec::<u8>::new() | |
| 387 } else { | |
| 388 unsafe { std::slice::from_raw_parts(ptr, (self.width() * self.height()) as usize).to_vec() } | |
| 389 } | |
| 390 } | |
| 391 } | |
| 392 | |
| 393 #[cfg(feature = "image")] | |
| 394 impl From<&Image> for image::GrayImage { | |
| 395 fn from(img: &Image) -> image::GrayImage { | |
| 396 image::GrayImage::from_vec(img.width() as u32, img.height() as u32, img.data()).unwrap() | |
| 397 } | |
| 398 } | |
| 399 | |
| 400 #[derive(Error, Debug, PartialEq)] | |
| 401 pub enum BarcodeError { | |
| 402 #[error("")] | |
| 403 None(), | |
| 404 | |
| 405 #[error("{0}")] | |
| 406 Checksum(String), | |
| 407 | |
| 408 #[error("{0}")] | |
| 409 Format(String), | |
| 410 | |
| 411 #[error("{0}")] | |
| 412 Unsupported(String), | |
| 413 } | |
| 414 | |
| 415 pub type PointI = ZXing_PointI; | |
| 416 #[repr(C)] | |
| 417 #[derive(Debug, Copy, Clone)] | |
| 418 pub struct Position { | |
| 419 pub top_left: PointI, | |
| 420 pub top_right: PointI, | |
| 421 pub bottom_right: PointI, | |
| 422 pub bottom_left: PointI, | |
| 423 } | |
| 424 | |
| 425 impl Display for PointI { | |
| 426 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { | |
| 427 write!(f, "{}x{}", self.x, self.y) | |
| 428 } | |
| 429 } | |
| 430 | |
| 431 impl Display for Position { | |
| 432 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { | |
| 433 write!(f, "{}", unsafe { | |
| 434 c2r_str(ZXing_PositionToString(*(self as *const Position as *const ZXing_Position))) | |
| 435 }) | |
| 436 } | |
| 437 } | |
| 438 | |
| 439 make_zxing_class!(Barcode, ZXing_Barcode); | |
| 440 | |
| 441 impl Barcode { | |
| 442 getter!(Barcode, isValid, transmute, bool); | |
| 443 getter!(Barcode, format, (|f| BarcodeFormats::new(f).unwrap().into_iter().last().unwrap()), BarcodeFormat); | |
| 444 getter!(Barcode, contentType, transmute, ContentType); | |
| 445 getter!(Barcode, text, c2r_str, String); | |
| 446 getter!(Barcode, ecLevel, c2r_str, String); | |
| 447 getter!(Barcode, symbologyIdentifier, c2r_str, String); | |
| 448 getter!(Barcode, position, transmute, Position); | |
| 449 getter!(Barcode, orientation, transmute, i32); | |
| 450 getter!(Barcode, hasECI, has_eci, transmute, bool); | |
| 451 getter!(Barcode, isInverted, transmute, bool); | |
| 452 getter!(Barcode, isMirrored, transmute, bool); | |
| 453 getter!(Barcode, lineCount, transmute, i32); | |
| 454 | |
| 455 pub fn bytes(&self) -> Vec<u8> { | |
| 456 let mut len: c_int = 0; | |
| 457 unsafe { c2r_vec(ZXing_Barcode_bytes(self.0, &mut len), len) } | |
| 458 } | |
| 459 pub fn bytes_eci(&self) -> Vec<u8> { | |
| 460 let mut len: c_int = 0; | |
| 461 unsafe { c2r_vec(ZXing_Barcode_bytesECI(self.0, &mut len), len) } | |
| 462 } | |
| 463 | |
| 464 pub fn error(&self) -> BarcodeError { | |
| 465 let error_type = unsafe { ZXing_Barcode_errorType(self.0) }; | |
| 466 let error_msg = unsafe { c2r_str(ZXing_Barcode_errorMsg(self.0)) }; | |
| 467 #[allow(non_upper_case_globals)] | |
| 468 match error_type { | |
| 469 ZXing_ErrorType_None => BarcodeError::None(), | |
| 470 ZXing_ErrorType_Format => BarcodeError::Format(error_msg), | |
| 471 ZXing_ErrorType_Checksum => BarcodeError::Checksum(error_msg), | |
| 472 ZXing_ErrorType_Unsupported => BarcodeError::Unsupported(error_msg), | |
| 473 _ => panic!("Internal error: invalid ZXing_ErrorType"), | |
| 474 } | |
| 475 } | |
| 476 | |
| 477 pub fn to_svg_with(&self, opts: &BarcodeWriter) -> Result<String, Error> { | |
| 478 let str = unsafe { ZXing_WriteBarcodeToSVG(self.0, opts.0) }; | |
| 479 last_error_if_null_or!(str, c2r_str(str)) | |
| 480 } | |
| 481 | |
| 482 pub fn to_svg(&self) -> Result<String, Error> { | |
| 483 self.to_svg_with(&BarcodeWriter::default()) | |
| 484 } | |
| 485 | |
| 486 pub fn to_image_with(&self, opts: &BarcodeWriter) -> Result<Image, Error> { | |
| 487 let img = unsafe { ZXing_WriteBarcodeToImage(self.0, opts.0) }; | |
| 488 last_error_if_null_or!(img, Image(img)) | |
| 489 } | |
| 490 | |
| 491 pub fn to_image(&self) -> Result<Image, Error> { | |
| 492 self.to_image_with(&BarcodeWriter::default()) | |
| 493 } | |
| 494 } | |
| 495 | |
| 496 make_zxing_class_with_default!(BarcodeReader, ZXing_ReaderOptions); | |
| 497 | |
| 498 impl BarcodeReader { | |
| 499 property!(ReaderOptions, TryHarder, bool); | |
| 500 property!(ReaderOptions, TryRotate, bool); | |
| 501 property!(ReaderOptions, TryInvert, bool); | |
| 502 property!(ReaderOptions, TryDownscale, bool); | |
| 503 property!(ReaderOptions, IsPure, bool); | |
| 504 property!(ReaderOptions, ReturnErrors, bool); | |
| 505 property!(ReaderOptions, Formats, BarcodeFormats); | |
| 506 property!(ReaderOptions, TextMode, TextMode); | |
| 507 property!(ReaderOptions, Binarizer, Binarizer); | |
| 508 property!(ReaderOptions, EanAddOnSymbol, EanAddOnSymbol); | |
| 509 property!(ReaderOptions, MaxNumberOfSymbols, i32); | |
| 510 property!(ReaderOptions, MinLineCount, i32); | |
| 511 | |
| 512 pub fn from<'a, IV>(&self, image: IV) -> Result<Vec<Barcode>, Error> | |
| 513 where | |
| 514 IV: TryInto<ImageView<'a>>, | |
| 515 IV::Error: Into<Error>, | |
| 516 { | |
| 517 let iv_: ImageView = image.try_into().map_err(Into::into)?; | |
| 518 unsafe { | |
| 519 let results = ZXing_ReadBarcodes((iv_.0).0, self.0); | |
| 520 if !results.is_null() { | |
| 521 let size = ZXing_Barcodes_size(results); | |
| 522 let mut vec = Vec::<Barcode>::with_capacity(size as usize); | |
| 523 for i in 0..size { | |
| 524 vec.push(Barcode(ZXing_Barcodes_move(results, i))); | |
| 525 } | |
| 526 ZXing_Barcodes_delete(results); | |
| 527 Ok(vec) | |
| 528 } else { | |
| 529 Err(last_error()) | |
| 530 } | |
| 531 } | |
| 532 } | |
| 533 } | |
| 534 | |
| 535 make_zxing_class!(BarcodeCreator, ZXing_CreatorOptions); | |
| 536 | |
| 537 impl BarcodeCreator { | |
| 538 pub fn new(format: BarcodeFormat) -> Self { | |
| 539 unsafe { BarcodeCreator(ZXing_CreatorOptions_new(BarcodeFormats::from(format).bits())) } | |
| 540 } | |
| 541 | |
| 542 property!(CreatorOptions, ReaderInit, bool); | |
| 543 property!(CreatorOptions, ForceSquareDataMatrix, bool); | |
| 544 property!(CreatorOptions, EcLevel, String); | |
| 545 | |
| 546 pub fn from_str(&self, str: impl AsRef<str>) -> Result<Barcode, Error> { | |
| 547 let cstr = CString::new(str.as_ref())?; | |
| 548 let bc = unsafe { ZXing_CreateBarcodeFromText(cstr.as_ptr(), 0, self.0) }; | |
| 549 last_error_if_null_or!(bc, Barcode(bc)) | |
| 550 } | |
| 551 | |
| 552 pub fn from_slice(&self, data: impl AsRef<[u8]>) -> Result<Barcode, Error> { | |
| 553 let data = data.as_ref(); | |
| 554 let bc = unsafe { ZXing_CreateBarcodeFromBytes(data.as_ptr() as *const c_void, data.len() as i32, self.0) }; | |
| 555 last_error_if_null_or!(bc, Barcode(bc)) | |
| 556 } | |
| 557 } | |
| 558 | |
| 559 make_zxing_class_with_default!(BarcodeWriter, ZXing_WriterOptions); | |
| 560 | |
| 561 impl BarcodeWriter { | |
| 562 property!(WriterOptions, Scale, i32); | |
| 563 property!(WriterOptions, SizeHint, i32); | |
| 564 property!(WriterOptions, Rotate, i32); | |
| 565 property!(WriterOptions, WithHRT, with_hrt, bool); | |
| 566 property!(WriterOptions, WithQuietZones, bool); | |
| 567 } | |
| 568 | |
| 569 pub fn read() -> BarcodeReader { | |
| 570 BarcodeReader::default() | |
| 571 } | |
| 572 | |
| 573 pub fn create(format: BarcodeFormat) -> BarcodeCreator { | |
| 574 BarcodeCreator::new(format) | |
| 575 } | |
| 576 | |
| 577 pub fn write() -> BarcodeWriter { | |
| 578 BarcodeWriter::default() | |
| 579 } |
