-
Notifications
You must be signed in to change notification settings - Fork 21
Add RTL text direction support for 0.8.1 #155
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
e670620
20231e0
2662bf5
b9a7f89
22f366d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -8,7 +8,10 @@ use crate::core::traits::{ | |
| adapter::{AdapterInfo, ModelAdapter}, | ||
| task::Task, | ||
| }; | ||
| use crate::domain::tasks::{TextRecognitionConfig, TextRecognitionOutput, TextRecognitionTask}; | ||
| use crate::domain::tasks::{ | ||
| TextRecognitionConfig, TextRecognitionOutput, TextRecognitionTask, | ||
| postprocess_text_direction_with_order_change, | ||
| }; | ||
| use crate::impl_adapter_builder; | ||
| use crate::models::recognition::crnn::{CRNNModel, CRNNModelBuilder, CRNNPreprocessConfig}; | ||
|
|
||
|
|
@@ -83,11 +86,18 @@ impl ModelAdapter for TextRecognitionAdapter { | |
| ) | ||
| { | ||
| if score >= effective_config.score_threshold { | ||
| result_texts.push(text); | ||
| let (text, changed_order) = postprocess_text_direction_with_order_change(text); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
In environments where the recognition model already returns Unicode logical RTL strings, such as Useful? React with 👍 / 👎. |
||
| result_scores.push(score); | ||
| result_positions.push(positions); | ||
| result_col_indices.push(col_indices); | ||
| result_seq_lengths.push(seq_len); | ||
| result_texts.push(text); | ||
| if changed_order { | ||
| result_positions.push(Vec::new()); | ||
| result_col_indices.push(Vec::new()); | ||
| result_seq_lengths.push(0); | ||
| } else { | ||
| result_positions.push(positions); | ||
| result_col_indices.push(col_indices); | ||
| result_seq_lengths.push(seq_len); | ||
| } | ||
| } else { | ||
| // Keep entry to preserve index correspondence, but mark as filtered | ||
| result_texts.push(String::new()); | ||
|
|
@@ -179,6 +189,7 @@ impl_adapter_builder! { | |
| self.return_word_box = enable; | ||
| self | ||
| } | ||
|
|
||
| } | ||
|
|
||
| build: |builder: TextRecognitionAdapterBuilder, model_source: crate::core::ModelSource| -> Result<TextRecognitionAdapter, OCRError> { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -9,6 +9,7 @@ use crate::core::traits::TaskDefinition; | |
| use crate::core::traits::task::{ImageTaskInput, Task, TaskSchema, TaskType}; | ||
| use crate::utils::ScoreValidator; | ||
| use serde::{Deserialize, Serialize}; | ||
| use unicode_bidi::BidiInfo; | ||
|
|
||
| /// Configuration for text recognition task. | ||
| /// | ||
|
|
@@ -28,6 +29,47 @@ impl Default for TextRecognitionConfig { | |
| } | ||
| } | ||
|
|
||
| fn reorder_bidi_line(line: &str) -> String { | ||
| let bidi_info = BidiInfo::new(line, None); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The fresh evidence after the earlier auto-direction fixes is this new Useful? React with 👍 / 👎. |
||
| let Some(para) = bidi_info.paragraphs.first() else { | ||
| return line.to_string(); | ||
| }; | ||
|
|
||
| bidi_info | ||
| .reorder_line(para, para.range.clone()) | ||
| .into_owned() | ||
| } | ||
|
|
||
| fn reorder_bidi_text(text: &str) -> (String, bool) { | ||
| let mut out = String::with_capacity(text.len()); | ||
| let mut changed_order = false; | ||
|
|
||
| for segment in text.split_inclusive('\n') { | ||
| if let Some(line) = segment.strip_suffix('\n') { | ||
| let converted = reorder_bidi_line(line); | ||
| changed_order |= converted != line; | ||
| out.push_str(&converted); | ||
| out.push('\n'); | ||
| } else { | ||
| let converted = reorder_bidi_line(segment); | ||
| changed_order |= converted != segment; | ||
| out.push_str(&converted); | ||
| } | ||
| } | ||
|
|
||
| (out, changed_order) | ||
| } | ||
|
|
||
| /// Applies Unicode bidi post-processing to decoded OCR text. | ||
| pub fn postprocess_text_direction(text: String) -> String { | ||
| postprocess_text_direction_with_order_change(text).0 | ||
| } | ||
|
|
||
| /// Applies Unicode bidi post-processing and reports whether character order changed. | ||
| pub fn postprocess_text_direction_with_order_change(text: String) -> (String, bool) { | ||
| reorder_bidi_text(&text) | ||
| } | ||
|
|
||
| /// Output from text recognition task. | ||
| #[derive(Debug, Clone)] | ||
| pub struct TextRecognitionOutput { | ||
|
|
@@ -185,4 +227,24 @@ mod tests { | |
| assert!(schema.input_types.contains(&"text_boxes".to_string())); | ||
| assert!(schema.output_types.contains(&"text_strings".to_string())); | ||
| } | ||
|
|
||
| #[test] | ||
| fn bidi_postprocess_leaves_ltr_text_unchanged() { | ||
| assert_eq!( | ||
| postprocess_text_direction("hello 123".to_string()), | ||
| "hello 123" | ||
| ); | ||
| } | ||
|
|
||
| #[test] | ||
| fn bidi_postprocess_reports_order_changes() { | ||
| assert_eq!( | ||
| postprocess_text_direction_with_order_change("hello 123".to_string()), | ||
| ("hello 123".to_string(), false) | ||
| ); | ||
| assert_eq!( | ||
| postprocess_text_direction_with_order_change("ابحرم".to_string()), | ||
| ("مرحبا".to_string(), true) | ||
| ); | ||
| } | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.