Skip to content

Commit

Permalink
parser/pdf: workaround for the weird ToUnicode casing bug
Browse files Browse the repository at this point in the history
See the comment and also
jrmuizel/pdf-extract#41
  • Loading branch information
badicsalex committed Sep 19, 2022
1 parent 396fad1 commit f0f66c1
Show file tree
Hide file tree
Showing 4 changed files with 145 additions and 7 deletions.
53 changes: 48 additions & 5 deletions src/parser/pdf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -207,23 +207,49 @@ impl pdf_extract::OutputDev for PdfExtractor {
width: f64,
spacing: f64,
font_size: f64,
cid: pdf_extract::CharCode,
char: &str,
) -> Result<(), pdf_extract::OutputError> {
let transformed_width = (width * font_size + spacing) * trm.m11;
let width = (width * font_size + spacing) * trm.m11;
let width_of_space = self.width_of_space * trm.m11 * font_size;
let x_start = trm.m31;
let y = trm.m32;

if cid < 256 && char.len() == 1 {
// TODO: horrible workaround for weird InDesign quirk, where in some cases,
// the casing is wrong for several characters in the ToUnicode map.
// Since all of these documents (I hope) have ActualText tags, this could be solved
// by handling the ActualText in the pdf extractor level.
let cid_char = LATIN2_CHARS[cid as usize];
let mut cid_str_buf = [0; 4];
let cid_str = cid_char.encode_utf8(&mut cid_str_buf);
if cid_char != '�' && cid_str.to_uppercase() == char.to_uppercase() {
if cid_char != ' ' && self.crop.is_inside(x_start, y) {
self.pages.last_mut().unwrap().chars.push(PositionedChar {
x: x_start,
y,
width,
width_of_space,
content: cid_char,
bold: self.current_font_is_bold,
});
}
return Ok(());
}
}

// Horrible hack to separate ligatures into graphemes.
// We don't really need to be exact, this 'x' information will probably not be used
let x_step = transformed_width / (char.chars().count() as f64);
let y = trm.m32;
let x_step = width / (char.chars().count() as f64);

let new_positioned_chars_iter = char
.chars()
.enumerate()
.map(|(i, raw_char)| PositionedChar {
x: x_start + x_step * (i as f64),
y,
width: transformed_width,
width_of_space: self.width_of_space * trm.m11 * font_size,
width,
width_of_space,
content: fix_character_coding_quirks(raw_char),
bold: self.current_font_is_bold,
})
Expand Down Expand Up @@ -287,3 +313,20 @@ pub fn parse_pdf(buffer: &[u8], crop: CropBox) -> Result<Vec<PageOfLines>> {
pdf_extract::output_doc(&document, &mut output)?;
output.get_parsed_pages()
}

const LATIN2_CHARS: [char; 256] = [
'�', '�', '�', '�', '�', '�', '�', '�', '�', '�', '�', '�', '�', '�', '�', '�', '�', '�', '�',
'�', '�', '�', '�', '�', '�', '�', '�', '�', '�', '�', '�', '�', ' ', '!', '\'', '#', '$', '%',
'&', '\"', '(', ')', '*', '+', ',', '-', '.', '/', '0', '1', '2', '3', '4', '5', '6', '7', '8',
'9', ':', ';', '<', '=', '>', '?', '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K',
'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '[', '\\', ']', '^',
'_', '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q',
'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '{', '|', '}', '~', '�', '�', '�', '�', '�', '�',
'�', '�', '�', '�', '�', '�', '�', '�', '�', '�', '�', '�', '�', '�', '�', '�', '�', '�', '�',
'�', '�', '�', '�', '�', '�', '�', '�', '�', 'Ą', '˘', 'Ł', '¤', 'Ľ', 'Ś', '§', '¨', 'Š', 'Ş',
'Ť', 'Ź', '�', 'Ž', 'Ż', '°', 'ą', '˛', 'ł', '´', 'ľ', 'ś', 'ˇ', '¸', 'š', 'ş', 'ť', 'ź', '˝',
'ž', 'ż', 'Ŕ', 'Á', 'Â', 'Ă', 'Ä', 'Ĺ', 'Ć', 'Ç', 'Č', 'É', 'Ę', 'Ë', 'Ě', 'Í', 'Î', 'Ď', 'Đ',
'Ń', 'Ň', 'Ó', 'Ô', 'Ő', 'Ö', '×', 'Ř', 'Ů', 'Ú', 'Ű', 'Ü', 'Ý', 'Ţ', 'ß', 'ŕ', 'á', 'â', 'ă',
'ä', 'ĺ', 'ć', 'ç', 'č', 'é', 'ę', 'ë', 'ě', 'í', 'î', 'ď', 'đ', 'ń', 'ň', 'ó', 'ô', 'ő', 'ö',
'÷', 'ř', 'ů', 'ú', 'ű', 'ü', 'ý', 'ţ', '˙',
];
4 changes: 2 additions & 2 deletions tests/datatests/data_pdf_parser/2013_66_part.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
is_justified: true
content: "(A fegyveres szerv személyi állományába tartozó, de a fegyveres szervnél szolgálati beosztást be nem töltő személyt"
- indent: 104.8789
content: "rendelkezési állományba kell helyezni. ennek megfelelően a fegyveres szerv rendelkezési állományába tartozik:)"
content: "rendelkezési állományba kell helyezni. Ennek megfelelően a fegyveres szerv rendelkezési állományába tartozik:)"
- indent: 104.8789
content: "„h) az MRK elnöke, az elnöki megbízatás megszűnéséig;”"
- indent: 89.4799
Expand All @@ -32,7 +32,7 @@
is_justified: true
content: "(A fegyveres szerv személyi állományába tartozó, de a fegyveres szervnél szolgálati beosztást be nem töltő személyt"
- indent: 104.8789
content: "rendelkezési állományba kell helyezni. ennek megfelelően a fegyveres szerv rendelkezési állományába tartozik:)"
content: "rendelkezési állományba kell helyezni. Ennek megfelelően a fegyveres szerv rendelkezési állományába tartozik:)"
- indent: 104.8789
is_justified: true
content: "„k) akinek a szolgálati viszonyát a (3a) bekezdés alapján felmentéssel meg kellene szüntetni, de a felmentésére a Hszt."
Expand Down
Binary file added tests/datatests/data_pdf_parser/2020_285_part.pdf
Binary file not shown.
95 changes: 95 additions & 0 deletions tests/datatests/data_pdf_parser/2020_285_part.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
- indent: 104.8819
is_justified: true
content: n) 1. mellékletében foglalt táblázat V. címében az „engedélyezett” szövegrész helyébe a „deklarált vagy
- indent: 130.3969
content: engedélyezett” szöveg,
- indent: 104.8819
is_justified: true
content: o) 1. mellékletében foglalt táblázat VII. címében az „1034/2011 és 1035/2011 EU rendeletek” szövegrész helyébe
- indent: 130.3969
content: a „2017/373 EU rendelet” szöveg
- indent: 104.8819
content: lép.
- {}
- indent: 104.8819
is_bold: true
content: 2. A szabálysértésekről, a szabálysértési eljárásról és a szabálysértési nyilvántartási rendszerről szóló
- indent: 104.8819
is_bold: true
content: 2012. évi II. törvény módosítása
- {}
- indent: 56.6929
is_justified: true
content: 21. § (1) A szabálysértésekről, a szabálysértési eljárásról és a szabálysértési nyilvántartási rendszerről szóló 2012. évi
- indent: 104.8789
content: 'II. törvény (a továbbiakban: Szabs. tv.) 166. §-a a következő (1a) bekezdéssel egészül ki:'
- indent: 104.8789
is_justified: true
content: „(1a) Aki pilóta nélküli légijármű jogosulatlan használata során más lakásáról, egyéb helyiségéről, vagy ezekhez
- indent: 104.8789
content: tartozó bekerített helyről jogosulatlanul hang- vagy képfelvételt készít, szabálysértést követ el.”
- indent: 89.4799
content: '(2) A Szabs. tv. a következő 183. alcímmel egészül ki:'
- indent: 104.8789
is_bold: true
content: „183. Pilóta nélküli légijárművel végzett jogosulatlan tevékenység
- indent: 104.8789
content: 229. § (1) Aki lakott terület felett pilóta nélküli légijárművet jogosulatlanul használ, szabálysértést követ el.
- indent: 104.8789
is_justified: true
content: (2) Az (1) bekezdésben meghatározott szabálysértés miatt a hivatásos katasztrófavédelmi szerv erre felhatalmazott
- indent: 104.8789
content: ügyintézője is szabhat ki helyszíni bírságot.”
- {}
- indent: 104.8819
is_bold: true
content: 3. A Büntető Törvénykönyvről szóló 2012. évi C. törvény módosítása
- {}
- indent: 56.6929
is_justified: true
content: 22. § A Büntető Törvénykönyvről szóló 2012. évi C. törvény „Tiltott adatszerzés” című alcíme a következő 422/A. §-sal
- indent: 104.8789
content: 'egészül ki:'
- indent: 104.8789
is_justified: true
content: „422/A. § (1) Aki pilóta nélküli légi jármű jogosulatlan használatával más lakását, egyéb helyiségét, vagy ezekhez
- indent: 104.8789
is_justified: true
content: tartozó bekerített helyet megfigyeli és az ott történteket rögzíti, ha más bűncselekmény nem valósul meg, vétség
- indent: 104.8789
content: miatt elzárással büntetendő.
- indent: 104.8789
is_justified: true
content: (2) Egy évig terjedő szabadságvesztéssel büntetendő, ha más bűncselekmény nem valósul meg, aki
- indent: 104.8789
is_justified: true
content: az (1) bekezdésben meghatározott megfigyelés során készített hang- vagy képfelvételt a nagy nyilvánosság számára
- indent: 104.8789
content: hozzáférhetővé teszi.
- indent: 104.8789
content: (3) Az (1)–(2) bekezdésben meghatározott bűncselekmény csak magánindítványra büntethető.”
- {}
- indent: 104.8819
is_bold: true
content: 4. Záró rendelkezések
- {}
- indent: 56.6929
content: 23. § (1) Ez a törvény – a (2) és (3) bekezdésben meghatározott kivétellel – 2021. január 1-jén lép hatályba.
- indent: 89.47989999999999
content: (2) A 15. § (1) bekezdése a kihirdetést követő 16. napon lép hatályba.
- indent: 89.47989999999999
content: (3) A 9. § (2) bekezdése és a 16. § a kihirdetést követő 31. napon lép hatályba.
- {}
- indent: 56.69289999999999
is_justified: true
content: 24. § Az 1–20. § tervezetének a műszaki szabályokkal és az információs társadalom szolgáltatásaira vonatkozó
- indent: 104.87889999999999
is_justified: true
content: szabályokkal kapcsolatos információszolgáltatási eljárás megállapításáról szóló, 2015. szeptember 9-i
- indent: 104.87889999999993
content: (EU) 2015/1535 európai parlamenti és tanácsi irányelv 5–7. cikke szerinti előzetes bejelentése megtörtént.
- {}
- indent: 185.11389999999992
content: Áder János s. k., Kövér László s. k.,
- indent: 186.5509
content: köztársasági elnök az Országgyűlés elnöke

0 comments on commit f0f66c1

Please sign in to comment.