#![cfg_attr(not(feature = "std"), no_std)]
#![deny(unsafe_code)]
#[cfg(not(feature = "std"))]
extern crate alloc;
pub mod iff;
pub mod error;
pub(crate) mod info;
#[allow(unused_imports)]
pub(crate) use djvu_zp as zp_impl;
#[allow(dead_code)]
pub mod bzz_new;
#[cfg(feature = "std")]
pub mod bzz_encode;
#[cfg(feature = "std")]
pub mod djvm;
pub(crate) mod dirm;
pub mod jb2;
#[path = "iw44_new.rs"]
pub mod iw44_new;
#[cfg(feature = "std")]
pub mod iw44_encode;
#[cfg(feature = "std")]
pub mod jb2_encode;
#[cfg(feature = "std")]
pub mod fgbz_encode;
#[cfg(feature = "std")]
pub mod djvu_encode;
#[cfg(feature = "std")]
pub mod segment;
pub mod djvu_document;
#[cfg(feature = "std")]
pub mod djvu_mut;
pub mod djvu_render;
pub(crate) mod fgbz;
pub mod text;
pub mod annotation;
pub mod metadata;
#[cfg(feature = "std")]
mod export_common;
#[cfg(feature = "std")]
pub mod pdf;
#[cfg(feature = "epub")]
pub mod epub;
#[cfg(feature = "tiff")]
pub mod tiff_export;
#[cfg(feature = "async")]
pub mod djvu_async;
#[cfg(feature = "image")]
pub mod image_compat;
#[cfg(feature = "std")]
pub mod ocr_export;
#[cfg(feature = "std")]
pub mod ocr;
#[cfg(feature = "ocr-tesseract")]
pub mod ocr_tesseract;
#[cfg(feature = "ocr-onnx")]
pub mod ocr_onnx;
#[cfg(feature = "ocr-neural")]
pub mod ocr_neural;
#[cfg(feature = "std")]
pub mod text_encode;
#[cfg(feature = "std")]
pub mod navm_encode;
pub mod smmr;
#[cfg(feature = "wasm")]
pub mod wasm;
#[cfg(feature = "std")]
#[allow(unsafe_code)]
pub mod ffi;
pub use error::{BzzError, DjVuError, IffError, Iw44Error, Jb2Error};
pub use djvu_document::{DjVuBookmark, DjVuDocument, DjVuPage, DocError};
pub use info::{PageInfo, Rotation};
#[doc(hidden)]
pub(crate) mod bitmap;
#[doc(hidden)]
pub(crate) mod pixmap;
pub use bitmap::Bitmap;
pub use pixmap::{GrayPixmap, Pixmap};
#[cfg(feature = "std")]
pub use text::{TextLayer, TextZone, TextZoneKind};
#[cfg(feature = "std")]
pub type Bookmark = DjVuBookmark;
#[cfg(feature = "std")]
pub use error::LegacyError as Error;
#[cfg(feature = "std")]
pub struct Document {
doc: DjVuDocument,
}
#[cfg(feature = "std")]
impl Document {
pub fn open(path: impl AsRef<std::path::Path>) -> Result<Self, Error> {
let data = std::fs::read(path.as_ref())
.map_err(|e| Error::FormatError(format!("failed to read file: {}", e)))?;
Self::from_bytes(data)
}
pub fn open_dir(path: impl AsRef<std::path::Path>) -> Result<Self, Error> {
let path = path.as_ref();
let data = std::fs::read(path)
.map_err(|e| Error::FormatError(format!("failed to read file: {}", e)))?;
let base_dir = path.parent().unwrap_or(std::path::Path::new("."));
let doc = DjVuDocument::parse_from_dir(&data, base_dir)
.map_err(|e| Error::FormatError(e.to_string()))?;
Ok(Document { doc })
}
pub fn from_reader(reader: impl std::io::Read) -> Result<Self, Error> {
let mut reader = reader;
let mut data = Vec::new();
reader
.read_to_end(&mut data)
.map_err(|e| Error::FormatError(format!("failed to read: {}", e)))?;
Self::from_bytes(data)
}
pub fn from_bytes(data: Vec<u8>) -> Result<Self, Error> {
let doc = DjVuDocument::parse(&data).map_err(|e| Error::FormatError(e.to_string()))?;
Ok(Document { doc })
}
pub fn bookmarks(&self) -> Result<Vec<Bookmark>, Error> {
Ok(self.doc.bookmarks().to_vec())
}
pub fn page_count(&self) -> usize {
self.doc.page_count()
}
pub fn page(&self, index: usize) -> Result<Page<'_>, Error> {
let page = self
.doc
.page(index)
.map_err(|e| Error::FormatError(e.to_string()))?;
Ok(Page { page, index })
}
}
#[cfg(feature = "std")]
pub struct Page<'a> {
page: &'a DjVuPage,
index: usize,
}
#[cfg(feature = "std")]
impl<'a> Page<'a> {
pub fn width(&self) -> u32 {
self.page.width() as u32
}
pub fn height(&self) -> u32 {
self.page.height() as u32
}
pub fn display_width(&self) -> u32 {
self.display_dims().0
}
pub fn display_height(&self) -> u32 {
self.display_dims().1
}
fn display_dims(&self) -> (u32, u32) {
djvu_render::display_dimensions(self.page)
}
fn opts_for_scale(&self, scale: f32) -> djvu_render::RenderOptions {
let (dw, dh) = self.display_dims();
let w = ((dw as f32 * scale).round() as u32).max(1);
let h = ((dh as f32 * scale).round() as u32).max(1);
djvu_render::RenderOptions {
width: w,
height: h,
scale,
..Default::default()
}
}
fn opts_for_size(&self, width: u32, height: u32) -> djvu_render::RenderOptions {
let mut opts = djvu_render::RenderOptions::fit_to_width(self.page, width);
opts.height = height;
opts
}
pub fn render_with(&self, opts: &djvu_render::RenderOptions) -> Result<Pixmap, Error> {
djvu_render::render_pixmap(self.page, opts).map_err(Self::render_err)
}
pub fn dpi(&self) -> u16 {
self.page.dpi()
}
pub fn index(&self) -> usize {
self.index
}
pub fn rotation(&self) -> info::Rotation {
self.page.rotation()
}
fn render_err(e: djvu_render::RenderError) -> Error {
Error::FormatError(e.to_string())
}
pub fn decode_mask(&self) -> Result<Option<Bitmap>, Error> {
self.page
.extract_mask()
.map_err(|e| Error::FormatError(e.to_string()))
}
pub fn render(&self) -> Result<Pixmap, Error> {
self.render_with(&self.opts_for_scale(1.0))
}
pub fn render_to_size(&self, width: u32, height: u32) -> Result<Pixmap, Error> {
self.render_with(&self.opts_for_size(width, height))
}
#[deprecated(
since = "0.20.0",
note = "use `render_with` with `RenderOptions { bold, ..fit_to_width(page, w) }`"
)]
pub fn render_bold(&self, dilate_passes: u32) -> Result<Pixmap, Error> {
let mut opts = self.opts_for_scale(1.0);
opts.bold = dilate_passes.min(255) as u8;
self.render_with(&opts)
}
#[deprecated(
since = "0.20.0",
note = "use `render_with` with `RenderOptions { bold, ..fit_to_width(page, w) }`"
)]
pub fn render_to_size_bold(
&self,
width: u32,
height: u32,
dilate_passes: u32,
) -> Result<Pixmap, Error> {
let mut opts = self.opts_for_size(width, height);
opts.bold = dilate_passes.min(255) as u8;
self.render_with(&opts)
}
#[deprecated(
since = "0.20.0",
note = "use `render_with` with `RenderOptions { aa: true, ..fit_to_width(page, w) }`"
)]
pub fn render_aa(&self, width: u32, height: u32) -> Result<Pixmap, Error> {
let mut opts = self.opts_for_size(width, height);
opts.aa = true;
self.render_with(&opts)
}
pub fn thumbnail(&self) -> Result<Option<Pixmap>, Error> {
self.page
.thumbnail()
.map_err(|e| Error::FormatError(e.to_string()))
}
pub fn text_layer(&self) -> Result<Option<TextLayer>, Error> {
self.page
.text_layer()
.map_err(|e| Error::FormatError(e.to_string()))
}
pub fn text(&self) -> Result<Option<String>, Error> {
Ok(self.text_layer()?.map(|tl| tl.text))
}
#[deprecated(
since = "0.20.0",
note = "use `djvu_render::render_coarse` with `RenderOptions::fit_to_width`"
)]
pub fn render_scaled_coarse(&self, scale: f32) -> Result<Option<Pixmap>, Error> {
djvu_render::render_coarse(self.page, &self.opts_for_scale(scale)).map_err(Self::render_err)
}
#[deprecated(
since = "0.20.0",
note = "use `djvu_render::render_progressive_all` with `RenderOptions::fit_to_width`"
)]
pub fn render_scaled_progressive(&self, scale: f32) -> Result<Vec<Pixmap>, Error> {
djvu_render::render_progressive_all(self.page, &self.opts_for_scale(scale))
.map_err(Self::render_err)
}
#[deprecated(
since = "0.20.0",
note = "use `render_with` with `RenderOptions::fit_to_width`/`fit_to_box`"
)]
pub fn render_scaled(&self, scale: f32) -> Result<Pixmap, Error> {
self.render_with(&self.opts_for_scale(scale))
}
}
#[cfg(feature = "std")]
#[allow(dead_code)]
const _: () = {
fn assert_send<T: Send>() {}
fn assert_sync<T: Sync>() {}
fn assertions() {
assert_send::<Document>();
assert_sync::<Document>();
}
};