Skip to main content

bwipp/
lib.rs

1#![allow(
2    clippy::doc_lazy_continuation,
3    clippy::doc_overindented_list_items,
4    clippy::almost_complete_range,
5    clippy::needless_range_loop,
6    clippy::single_match,
7    clippy::type_complexity,
8    unused_parens
9)]
10//! # bwipp-rs
11//!
12//! Pure-Rust port of [BWIPP](https://github.com/bwipp/postscriptbarcode)
13//! (Barcode Writer in Pure PostScript).
14//!
15//! Current scope: **every user-facing BWIPP catalog encoder** —
16//! monochrome 1D, monochrome 2D (matrix, stacked, dot, hex), and the
17//! single colour 2D entry (`ultracode`, 6-colour palette). Output is
18//! SVG (vector) or PNG (raster); the colour path is a new
19//! `Encoded::ColorMatrix` carrier added in Stage 4. The [`Symbology`]
20//! enum tells you exactly what's implemented; see
21//! [`PORT_STATUS.md`](https://github.com/erdzan12/bwipp-rs/blob/main/rust/PORT_STATUS.md)
22//! for the per-row verification status (169 verified + 0 partial out
23//! of 169 catalog rows as of this revision).
24//!
25//! ## Quick start
26//!
27//! ```
28//! use bwipp::{Symbology, Options, render_svg};
29//!
30//! let svg = render_svg(Symbology::Code128, "Hello, world!", &Options::default()).unwrap();
31//! assert!(svg.starts_with("<svg"));
32//! ```
33//!
34//! ## PNG output
35//!
36//! ```
37//! use bwipp::{Symbology, Options, render_png};
38//!
39//! let png = render_png(Symbology::Ean13, "0123456789012", &Options::default()).unwrap();
40//! // PNG files always start with the 8-byte signature \x89 P N G \r \n \x1A \n.
41//! assert_eq!(&png[..4], b"\x89PNG");
42//! ```
43//!
44//! ## Looking up a symbology by ID
45//!
46//! ```
47//! use bwipp::Symbology;
48//!
49//! assert_eq!(Symbology::from_id("code39"), Some(Symbology::Code39));
50//! assert_eq!(Symbology::from_id("code128a"), Some(Symbology::Code128)); // alias
51//! assert!(Symbology::from_id("not_a_real_symbology").is_none());
52//! ```
53//!
54//! ## Customising rendering
55//!
56//! The renderer-level fields (`scale`, `bar_height`, `quiet_zone`,
57//! `include_text`, foreground/background colours) are typed fields on
58//! `Options`; encoder-specific switches go in the `extras` list via
59//! [`Options::with`].
60//!
61//! ```
62//! use bwipp::{Symbology, Options, render_svg};
63//!
64//! let mut opts = Options::default();
65//! opts.scale = 3;            // 3 pixels per module (default 4)
66//! opts.include_text = true;  // draw the human-readable text below the bars
67//! let opts = opts.with("includecheck", "true"); // encoder-specific
68//!
69//! let svg = render_svg(Symbology::Code39, "HELLO", &opts).unwrap();
70//! assert!(svg.contains("<svg"));
71//! ```
72//!
73//! ## Error handling
74//!
75//! Every entry point returns `Result<_, Error>`. Match on the variant
76//! to distinguish a bad payload from a bad option from a backend
77//! failure:
78//!
79//! ```
80//! use bwipp::{render_svg, Options, Symbology, Error};
81//!
82//! match render_svg(Symbology::Ean13, "not digits", &Options::default()) {
83//!     Ok(_)                   => panic!("EAN-13 should reject letters"),
84//!     Err(Error::InvalidData(msg))   => assert!(msg.contains("digit") || msg.contains("EAN-13")),
85//!     Err(Error::InvalidOption(_))   => panic!("not an option problem"),
86//!     Err(Error::Unimplemented(_))   => panic!("EAN-13 is implemented"),
87//!     Err(Error::Backend(_))         => panic!("not a backend problem"),
88//! }
89//! ```
90
91#![forbid(unsafe_code)]
92#![deny(missing_docs)]
93
94pub mod encoding;
95pub mod error;
96pub mod options;
97pub mod render;
98pub mod symbology;
99pub(crate) mod util;
100
101#[cfg(feature = "wasm")]
102pub mod wasm;
103
104pub use encoding::{
105    Bar4State, BitMatrix, ColorMatrix, DotMatrix, Encoded, LinearPattern, Postal4Pattern, Rgb8,
106    StackedPattern,
107};
108pub use error::Error;
109pub use options::Options;
110pub use render::{render_png, render_svg, Format};
111pub use symbology::Symbology;
112
113// MaxiCode hex-grid carrier for `Encoded::Hex`. Re-exported here so
114// consumers pattern-matching on `Encoded::Hex(sym)` can name the
115// inner type without spelling the full
116// `crate::symbology::maxicode::MaxiCodeSymbol` path. The other
117// `Encoded::*` carriers (`BitMatrix`, `ColorMatrix`, `DotMatrix`,
118// `LinearPattern`, `Postal4Pattern`, `StackedPattern`) are already
119// re-exported above; this keeps the public surface symmetric.
120pub use symbology::maxicode::MaxiCodeSymbol;