add logging
This commit is contained in:
@@ -9,6 +9,7 @@ use crate::text_utils::{
|
||||
use crate::tounicode::FontCMaps;
|
||||
use crate::types::{ItemType, PdfRect, TextItem};
|
||||
use crate::PdfError;
|
||||
use log::trace;
|
||||
use lopdf::{Document, Encoding, Object, ObjectId};
|
||||
use std::collections::HashMap;
|
||||
|
||||
@@ -100,6 +101,7 @@ pub(crate) fn extract_page_text_items(
|
||||
let mut actual_text_start_tm: Option<[f32; 6]> = None; // text matrix at BDC entry
|
||||
|
||||
for op in &content.operations {
|
||||
trace!("{} {:?}", op.operator, op.operands);
|
||||
match op.operator.as_str() {
|
||||
"q" => {
|
||||
// Save graphics state
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
use crate::glyph_names::glyph_to_char;
|
||||
use crate::tounicode::FontCMaps;
|
||||
use crate::types::{FontEncodingMap, FontWidthInfo, PageFontEncodings, PageFontWidths};
|
||||
use log::debug;
|
||||
use lopdf::{Document, Encoding, Object};
|
||||
use std::collections::HashMap;
|
||||
|
||||
@@ -42,6 +43,37 @@ pub(crate) fn build_font_widths(
|
||||
|
||||
for (font_name, font_dict) in fonts {
|
||||
let resource_name = String::from_utf8_lossy(font_name).to_string();
|
||||
|
||||
let subtype = font_dict
|
||||
.get(b"Subtype")
|
||||
.ok()
|
||||
.and_then(|o| o.as_name().ok())
|
||||
.map(|n| String::from_utf8_lossy(n).to_string())
|
||||
.unwrap_or_default();
|
||||
let base_font = font_dict
|
||||
.get(b"BaseFont")
|
||||
.ok()
|
||||
.and_then(|o| o.as_name().ok())
|
||||
.map(|n| String::from_utf8_lossy(n).to_string())
|
||||
.unwrap_or_default();
|
||||
let has_tounicode = font_dict.get(b"ToUnicode").is_ok();
|
||||
let has_descendants = font_dict.get(b"DescendantFonts").is_ok();
|
||||
let encoding_str = font_dict
|
||||
.get(b"Encoding")
|
||||
.ok()
|
||||
.map(|o| match o {
|
||||
Object::Name(n) => String::from_utf8_lossy(n).to_string(),
|
||||
Object::Reference(_) => "ref(dict)".to_string(),
|
||||
Object::Dictionary(_) => "dict".to_string(),
|
||||
_ => format!("{:?}", o),
|
||||
})
|
||||
.unwrap_or_else(|| "none".to_string());
|
||||
|
||||
debug!(
|
||||
"font {:<10} sub={:<12} base={:<45} toUni={:<6} enc={:<20} cid={}",
|
||||
resource_name, subtype, base_font, has_tounicode, encoding_str, has_descendants
|
||||
);
|
||||
|
||||
if let Some(info) = parse_font_widths(doc, font_dict) {
|
||||
widths.insert(resource_name, info);
|
||||
}
|
||||
@@ -452,6 +484,7 @@ pub(crate) fn parse_encoding_dictionary(
|
||||
|
||||
let mut encoding_map = FontEncodingMap::new();
|
||||
let mut current_code: u8 = 0;
|
||||
let mut ligature_count = 0u32;
|
||||
|
||||
for item in diff_array {
|
||||
match item {
|
||||
@@ -462,6 +495,17 @@ pub(crate) fn parse_encoding_dictionary(
|
||||
Object::Name(name) => {
|
||||
// Map current code to glyph name -> Unicode
|
||||
let glyph_name = String::from_utf8_lossy(&name).to_string();
|
||||
if glyph_name == "fi"
|
||||
|| glyph_name == "fl"
|
||||
|| glyph_name == "ffi"
|
||||
|| glyph_name == "ffl"
|
||||
{
|
||||
debug!(
|
||||
" Differences: code=0x{:02X} glyph={:?} (ligature)",
|
||||
current_code, glyph_name
|
||||
);
|
||||
ligature_count += 1;
|
||||
}
|
||||
if let Some(ch) = glyph_to_char(&glyph_name) {
|
||||
encoding_map.insert(current_code, ch);
|
||||
}
|
||||
@@ -471,6 +515,14 @@ pub(crate) fn parse_encoding_dictionary(
|
||||
}
|
||||
}
|
||||
|
||||
if ligature_count > 0 {
|
||||
debug!(
|
||||
" Differences: {} total entries, {} ligatures",
|
||||
encoding_map.len(),
|
||||
ligature_count
|
||||
);
|
||||
}
|
||||
|
||||
if encoding_map.is_empty() {
|
||||
None
|
||||
} else {
|
||||
|
||||
+54
-1
@@ -2,6 +2,7 @@
|
||||
|
||||
use crate::text_utils::{effective_width, sort_line_items};
|
||||
use crate::types::{TextItem, TextLine};
|
||||
use log::debug;
|
||||
|
||||
/// Represents a column region on a page
|
||||
#[derive(Debug, Clone)]
|
||||
@@ -170,6 +171,16 @@ pub(crate) fn detect_columns(items: &[TextItem], page: u32) -> Vec<ColumnRegion>
|
||||
return vec![ColumnRegion { x_min, x_max }];
|
||||
}
|
||||
|
||||
debug!(
|
||||
"page {}: {} columns detected (boundaries: {:?})",
|
||||
page,
|
||||
valid_valleys.len() + 1,
|
||||
valid_valleys
|
||||
.iter()
|
||||
.map(|(s, e)| x_min + ((*s + *e) as f32 / 2.0) * BIN_WIDTH)
|
||||
.collect::<Vec<_>>()
|
||||
);
|
||||
|
||||
// Limit to at most 3 gutters (4 columns) — keep the widest if more found
|
||||
if valid_valleys.len() > 3 {
|
||||
valid_valleys.sort_by(|a, b| {
|
||||
@@ -401,6 +412,39 @@ pub fn group_into_lines(items: Vec<TextItem>) -> Vec<TextLine> {
|
||||
col_buckets[best_col].push(item.clone());
|
||||
}
|
||||
|
||||
debug!(
|
||||
"page {}: {} columns, {} spanning items",
|
||||
page,
|
||||
columns.len(),
|
||||
spanning_items.len()
|
||||
);
|
||||
for (ci, col) in columns.iter().enumerate() {
|
||||
debug!(
|
||||
" col {}: x=[{:.0}..{:.0}] {} items",
|
||||
ci,
|
||||
col.x_min,
|
||||
col.x_max,
|
||||
col_buckets[ci].len()
|
||||
);
|
||||
}
|
||||
if log::log_enabled!(log::Level::Trace) {
|
||||
for (ci, bucket) in col_buckets.iter().enumerate() {
|
||||
for item in bucket {
|
||||
log::trace!(
|
||||
" col {} <- x={:7.1} y={:7.1} {:?}",
|
||||
ci,
|
||||
item.x,
|
||||
item.y,
|
||||
if item.text.len() > 60 {
|
||||
&item.text[..60]
|
||||
} else {
|
||||
&item.text
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut per_column_lines: Vec<Vec<TextLine>> = Vec::new();
|
||||
for col_items in col_buckets {
|
||||
let lines = group_single_column(col_items);
|
||||
@@ -410,7 +454,14 @@ pub fn group_into_lines(items: Vec<TextItem>) -> Vec<TextLine> {
|
||||
// Process spanning items as their own group
|
||||
let spanning_lines = group_single_column(spanning_items);
|
||||
|
||||
if is_newspaper_layout(&per_column_lines) {
|
||||
let is_newspaper = is_newspaper_layout(&per_column_lines);
|
||||
debug!(
|
||||
"page {}: layout={}",
|
||||
page,
|
||||
if is_newspaper { "newspaper" } else { "tabular" }
|
||||
);
|
||||
|
||||
if is_newspaper {
|
||||
// Newspaper: columns are independent text flows.
|
||||
// 1. Split each column into its densest cluster (core) and stragglers
|
||||
// 2. Use core columns to determine the above/below threshold
|
||||
@@ -631,5 +682,7 @@ fn group_single_column(items: Vec<TextItem>) -> Vec<TextLine> {
|
||||
sort_line_items(&mut line.items);
|
||||
}
|
||||
|
||||
debug!("group_single_column: {} lines", lines.len());
|
||||
|
||||
lines
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ use crate::text_utils::is_rtl_text;
|
||||
use crate::tounicode::FontCMaps;
|
||||
use crate::types::{PdfRect, TextItem};
|
||||
use crate::PdfError;
|
||||
use log::debug;
|
||||
use lopdf::{Document, Object, ObjectId};
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::path::Path;
|
||||
@@ -145,6 +146,30 @@ fn extract_positioned_text_from_doc(
|
||||
}
|
||||
}
|
||||
let (items, rects) = extract_page_text_items(doc, page_id, *page_num, font_cmaps)?;
|
||||
debug!(
|
||||
"page {}: {} text items, {} rects",
|
||||
page_num,
|
||||
items.len(),
|
||||
rects.len()
|
||||
);
|
||||
if log::log_enabled!(log::Level::Trace) {
|
||||
for item in &items {
|
||||
log::trace!(
|
||||
" p={} x={:7.1} y={:7.1} w={:7.1} fs={:5.1} font={:6} {:?}",
|
||||
page_num,
|
||||
item.x,
|
||||
item.y,
|
||||
item.width,
|
||||
item.font_size,
|
||||
item.font,
|
||||
if item.text.len() > 80 {
|
||||
&item.text[..80]
|
||||
} else {
|
||||
&item.text
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
all_items.extend(items);
|
||||
all_rects.extend(rects);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user