use crate::bounding_box::BoundingBox;
use crate::errors::OneOcrError;
use crate::ocr_word::OcrWord;
use serde::Serialize;
use std::ffi::{CStr, c_char, c_void};
use std::ptr;
use crate::ffi::{
GetOcrLineBoundingBox, GetOcrLineContent, GetOcrLineStyle, GetOcrLineWordCount, GetOcrWord,
RawBBox,
};
use crate::check_ocr_call;
#[derive(Debug, Serialize)]
pub struct OcrLine {
#[serde(skip_serializing)]
line_handle: *mut c_void,
pub text: String,
pub bounding_box: BoundingBox,
pub words: Option<Vec<OcrWord>>,
}
impl OcrLine {
pub(crate) fn new(
line_handle: *mut c_void,
word_level_detail: bool,
) -> Result<Self, OneOcrError> {
let mut line_content: *const c_char = ptr::null();
check_ocr_call!(
unsafe { GetOcrLineContent(line_handle, &mut line_content) },
"Failed to get line content"
);
let line_content_cstr = unsafe { CStr::from_ptr(line_content) };
let line_content_str = line_content_cstr.to_string_lossy().to_string();
let mut bounding_box_ptr: *const RawBBox = ptr::null();
check_ocr_call!(
unsafe { GetOcrLineBoundingBox(line_handle, &mut bounding_box_ptr) },
"Failed to get line bounding box"
);
if bounding_box_ptr.is_null() {
return Err(OneOcrError::OcrApiError {
result: -1,
message: "GetOcrLineBoundingBox returned a null pointer.".to_string(),
});
}
let raw_bbox = unsafe { ptr::read(bounding_box_ptr) };
let bounding_box = BoundingBox::new(raw_bbox);
if !word_level_detail {
return Ok(Self {
line_handle,
text: line_content_str,
bounding_box,
words: None,
});
}
let mut word_count: i64 = 0;
check_ocr_call!(
unsafe { GetOcrLineWordCount(line_handle, &mut word_count) },
"Failed to get word count"
);
let mut words = Vec::with_capacity(word_count as usize);
for i in 0..word_count {
let mut word: *mut c_void = ptr::null_mut();
check_ocr_call!(
unsafe { GetOcrWord(line_handle, i, &mut word) },
"Failed to get word"
);
let ocr_word = OcrWord::new(word)?;
words.push(ocr_word);
}
Ok(Self {
line_handle,
text: line_content_str,
bounding_box,
words: Some(words),
})
}
pub fn get_line_style(&self) -> Result<(bool, f32), OneOcrError> {
let mut style: i32 = 0;
let mut handwritten_confidence: f32 = 0.0;
check_ocr_call!(
unsafe { GetOcrLineStyle(self.line_handle, &mut style, &mut handwritten_confidence) },
"Failed to get OCR line style"
);
Ok((style == 0, handwritten_confidence))
}
}
impl PartialEq for OcrLine {
fn eq(&self, other: &Self) -> bool {
self.text == other.text
&& self.bounding_box == other.bounding_box
&& self.words == other.words
}
}