/src/xpdf-4.06/xpdf/TextOutputDev.h
Line | Count | Source |
1 | | //======================================================================== |
2 | | // |
3 | | // TextOutputDev.h |
4 | | // |
5 | | // Copyright 1997-2012 Glyph & Cog, LLC |
6 | | // |
7 | | //======================================================================== |
8 | | |
9 | | #ifndef TEXTOUTPUTDEV_H |
10 | | #define TEXTOUTPUTDEV_H |
11 | | |
12 | | #include <aconf.h> |
13 | | |
14 | | #include <stdio.h> |
15 | | #include "gtypes.h" |
16 | | #include "GfxFont.h" |
17 | | #include "OutputDev.h" |
18 | | |
19 | | class GList; |
20 | | class UnicodeMap; |
21 | | class UnicodeRemapping; |
22 | | class PDFDoc; |
23 | | |
24 | | class TextBlock; |
25 | | class TextChar; |
26 | | class TextGaps; |
27 | | class TextLink; |
28 | | class TextPage; |
29 | | |
30 | | //------------------------------------------------------------------------ |
31 | | |
32 | | typedef void (*TextOutputFunc)(void *stream, const char *text, int len); |
33 | | |
34 | | //------------------------------------------------------------------------ |
35 | | // TextOutputControl |
36 | | //------------------------------------------------------------------------ |
37 | | |
38 | | enum TextOutputMode { |
39 | | textOutReadingOrder, // format into reading order |
40 | | textOutPhysLayout, // maintain original physical layout |
41 | | textOutSimpleLayout, // simple one-column physical layout |
42 | | textOutSimple2Layout, // simple one-column physical layout |
43 | | textOutTableLayout, // similar to PhysLayout, but optimized |
44 | | // for tables |
45 | | textOutLinePrinter, // strict fixed-pitch/height layout |
46 | | textOutRawOrder // keep text in content stream order |
47 | | }; |
48 | | |
49 | | enum TextOutputOverlapHandling { |
50 | | textOutIgnoreOverlaps, // no special handling for overlaps |
51 | | textOutAppendOverlaps, // append overlapping text to main text |
52 | | textOutDiscardOverlaps // discard overlapping text |
53 | | }; |
54 | | |
55 | | class TextOutputControl { |
56 | | public: |
57 | | |
58 | | TextOutputControl(); |
59 | 0 | ~TextOutputControl() {} |
60 | | |
61 | | TextOutputMode mode; // formatting mode |
62 | | double fixedPitch; // if this is non-zero, assume fixed-pitch |
63 | | // characters with this width |
64 | | // (only relevant for PhysLayout, Table, |
65 | | // and LinePrinter modes) |
66 | | double fixedLineSpacing; // fixed line spacing (only relevant for |
67 | | // LinePrinter mode) |
68 | | GBool html; // enable extra processing for HTML |
69 | | GBool clipText; // separate clipped text and add it back |
70 | | // in after forming columns |
71 | | GBool discardDiagonalText; // discard all text that's not close to |
72 | | // 0/90/180/270 degrees |
73 | | GBool discardRotatedText; // discard all text that's not horizontal |
74 | | // (0 degrees) |
75 | | GBool discardInvisibleText; // discard all invisible characters |
76 | | GBool discardClippedText; // discard all clipped characters |
77 | | GBool splitRotatedWords; // do not combine horizontal and |
78 | | // non-horizontal chars in a single |
79 | | // word |
80 | | TextOutputOverlapHandling // how to handle overlapping text |
81 | | overlapHandling; |
82 | | GBool separateLargeChars; // separate "large" characters from |
83 | | // "regular" characters |
84 | | GBool insertBOM; // insert a Unicode BOM at the start of |
85 | | // the text output |
86 | | double marginLeft, // characters outside the margins are |
87 | | marginRight, // discarded |
88 | | marginTop, |
89 | | marginBottom; |
90 | | GBool cmykColors; // false for RGB, true for CMYK |
91 | | }; |
92 | | |
93 | | //------------------------------------------------------------------------ |
94 | | // TextFontInfo |
95 | | //------------------------------------------------------------------------ |
96 | | |
97 | | class TextFontInfo { |
98 | | public: |
99 | | |
100 | | // Create a TextFontInfo for the current font in [state]. |
101 | | TextFontInfo(GfxState *state); |
102 | | |
103 | | // Create a dummy TextFontInfo. |
104 | | TextFontInfo(); |
105 | | |
106 | | ~TextFontInfo(); |
107 | | |
108 | | GBool matches(GfxState *state); |
109 | | |
110 | | // Get the font name (which may be NULL). |
111 | 0 | GString *getFontName() { return fontName; } |
112 | | |
113 | | // Get font descriptor flags. |
114 | 0 | GBool isFixedWidth() { return flags & fontFixedWidth; } |
115 | 0 | GBool isSerif() { return flags & fontSerif; } |
116 | 0 | GBool isSymbolic() { return flags & fontSymbolic; } |
117 | 0 | GBool isItalic() { return flags & fontItalic; } |
118 | 0 | GBool isBold() { return flags & fontBold; } |
119 | | |
120 | | // Get the width of the 'm' character, if available. |
121 | 0 | double getMWidth() { return mWidth; } |
122 | | |
123 | 0 | double getAscent() { return ascent; } |
124 | 0 | double getDescent() { return descent; } |
125 | | |
126 | 0 | GBool isProblematic() { return problematic; } |
127 | | |
128 | 0 | Ref getFontID() { return fontID; } |
129 | | |
130 | | private: |
131 | | |
132 | | Ref fontID; |
133 | | GString *fontName; |
134 | | int flags; |
135 | | double mWidth; |
136 | | double ascent, descent; |
137 | | GBool problematic; |
138 | | |
139 | | friend class TextLine; |
140 | | friend class TextPage; |
141 | | friend class TextWord; |
142 | | }; |
143 | | |
144 | | //------------------------------------------------------------------------ |
145 | | // TextWord |
146 | | //------------------------------------------------------------------------ |
147 | | |
148 | | class TextWord { |
149 | | public: |
150 | | |
151 | | TextWord(GList *chars, int start, int lenA, |
152 | | int rotA, GBool rotatedA, int dirA, GBool spaceAfterA); |
153 | | ~TextWord(); |
154 | 0 | TextWord *copy() { return new TextWord(this); } |
155 | | |
156 | | // Get the TextFontInfo object associated with this word. |
157 | 0 | TextFontInfo *getFontInfo() { return font; } |
158 | | |
159 | 0 | int getLength() { return len; } |
160 | 0 | Unicode getChar(int idx) { return text[idx]; } |
161 | | GString *getText(); |
162 | 0 | GString *getFontName() { return font->fontName; } |
163 | | void getColor(double *r, double *g, double *b) |
164 | 0 | { *r = colorR; *g = colorG; *b = colorB; } |
165 | | void getCMYKColor(double *c, double *m, double *y, double *k) |
166 | 0 | { *c = colorR; *m = colorG; *y = colorB; *k = colorK; } |
167 | 0 | GBool isInvisible() { return invisible; } |
168 | | void getBBox(double *xMinA, double *yMinA, double *xMaxA, double *yMaxA) |
169 | 0 | { *xMinA = xMin; *yMinA = yMin; *xMaxA = xMax; *yMaxA = yMax; } |
170 | | void getCharBBox(int charIdx, double *xMinA, double *yMinA, |
171 | | double *xMaxA, double *yMaxA); |
172 | 0 | double getFontSize() { return fontSize; } |
173 | 0 | int getRotation() { return rot; } |
174 | 0 | GBool isRotated() { return (GBool)rotated; } |
175 | 0 | int getCharPos() { return charPos[0]; } |
176 | 0 | int getCharLen() { return charPos[len] - charPos[0]; } |
177 | 0 | int getDirection() { return dir; } |
178 | 0 | GBool getSpaceAfter() { return spaceAfter; } |
179 | | double getBaseline(); |
180 | 0 | GBool isUnderlined() { return underlined; } |
181 | | GString *getLinkURI(); |
182 | | int getLinkPage(PDFDoc *doc); |
183 | | |
184 | | private: |
185 | | |
186 | | TextWord(TextWord *word); |
187 | | static int cmpYX(const void *p1, const void *p2); |
188 | | static int cmpCharPos(const void *p1, const void *p2); |
189 | | |
190 | | double xMin, xMax; // bounding box x coordinates |
191 | | double yMin, yMax; // bounding box y coordinates |
192 | | Unicode *text; // the text |
193 | | int *charPos; // character position (within content stream) |
194 | | // of each char (plus one extra entry for |
195 | | // the last char) |
196 | | double *edge; // "near" edge x or y coord of each char |
197 | | // (plus one extra entry for the last char) |
198 | | int len; // number of characters |
199 | | TextFontInfo *font; // font information |
200 | | double fontSize; // font size |
201 | | TextLink *link; |
202 | | double colorR, // word color (RGB or CMYK) |
203 | | colorG, |
204 | | colorB, |
205 | | colorK; |
206 | | GBool invisible; // set for invisible text (render mode 3) |
207 | | |
208 | | // group the byte-size fields to minimize object size |
209 | | Guchar rot; // rotation, multiple of 90 degrees |
210 | | // (0, 1, 2, or 3) |
211 | | char rotated; // set if this word is non-horizontal |
212 | | char dir; // character direction (+1 = left-to-right; |
213 | | // -1 = right-to-left; 0 = neither) |
214 | | char spaceAfter; // set if there is a space between this |
215 | | // word and the next word on the line |
216 | | char underlined; |
217 | | |
218 | | friend class TextBlock; |
219 | | friend class TextLine; |
220 | | friend class TextPage; |
221 | | }; |
222 | | |
223 | | //------------------------------------------------------------------------ |
224 | | // TextLine |
225 | | //------------------------------------------------------------------------ |
226 | | |
227 | | class TextLine { |
228 | | public: |
229 | | |
230 | | TextLine(GList *wordsA, double xMinA, double yMinA, |
231 | | double xMaxA, double yMaxA, double fontSizeA); |
232 | | ~TextLine(); |
233 | | |
234 | 0 | double getXMin() { return xMin; } |
235 | 0 | double getYMin() { return yMin; } |
236 | 0 | double getXMax() { return xMax; } |
237 | 0 | double getYMax() { return yMax; } |
238 | | double getBaseline(); |
239 | 0 | int getRotation() { return rot; } |
240 | 0 | GList *getWords() { return words; } |
241 | 0 | Unicode *getUnicode() { return text; } |
242 | 0 | int getLength() { return len; } |
243 | 0 | double getEdge(int idx) { return edge[idx]; } |
244 | 0 | GBool getHyphenated() { return hyphenated; } |
245 | | |
246 | | private: |
247 | | |
248 | | static int cmpX(const void *p1, const void *p2); |
249 | | |
250 | | GList *words; // [TextWord] |
251 | | int rot; // rotation, multiple of 90 degrees |
252 | | // (0, 1, 2, or 3) |
253 | | double xMin, xMax; // bounding box x coordinates |
254 | | double yMin, yMax; // bounding box y coordinates |
255 | | double fontSize; // main (max) font size for this line |
256 | | Unicode *text; // Unicode text of the line, including |
257 | | // spaces between words |
258 | | double *edge; // "near" edge x or y coord of each char |
259 | | // (plus one extra entry for the last char) |
260 | | int len; // number of Unicode chars |
261 | | GBool hyphenated; // set if last char is a hyphen |
262 | | int px; // x offset (in characters, relative to |
263 | | // containing column) in physical layout mode |
264 | | int pw; // line width (in characters) in physical |
265 | | // layout mode |
266 | | |
267 | | friend class TextSuperLine; |
268 | | friend class TextPage; |
269 | | friend class TextParagraph; |
270 | | }; |
271 | | |
272 | | //------------------------------------------------------------------------ |
273 | | // TextParagraph |
274 | | //------------------------------------------------------------------------ |
275 | | |
276 | | class TextParagraph { |
277 | | public: |
278 | | |
279 | | TextParagraph(GList *linesA, GBool dropCapA); |
280 | | ~TextParagraph(); |
281 | | |
282 | | // Get the list of TextLine objects. |
283 | 0 | GList *getLines() { return lines; } |
284 | | |
285 | 0 | GBool hasDropCap() { return dropCap; } |
286 | | |
287 | 0 | double getXMin() { return xMin; } |
288 | 0 | double getYMin() { return yMin; } |
289 | 0 | double getXMax() { return xMax; } |
290 | 0 | double getYMax() { return yMax; } |
291 | | |
292 | | private: |
293 | | |
294 | | GList *lines; // [TextLine] |
295 | | GBool dropCap; // paragraph starts with a drop capital |
296 | | double xMin, xMax; // bounding box x coordinates |
297 | | double yMin, yMax; // bounding box y coordinates |
298 | | |
299 | | friend class TextPage; |
300 | | }; |
301 | | |
302 | | //------------------------------------------------------------------------ |
303 | | // TextColumn |
304 | | //------------------------------------------------------------------------ |
305 | | |
306 | | class TextColumn { |
307 | | public: |
308 | | |
309 | | TextColumn(GList *paragraphsA, double xMinA, double yMinA, |
310 | | double xMaxA, double yMaxA); |
311 | | ~TextColumn(); |
312 | | |
313 | | // Get the list of TextParagraph objects. |
314 | 0 | GList *getParagraphs() { return paragraphs; } |
315 | | |
316 | 0 | double getXMin() { return xMin; } |
317 | 0 | double getYMin() { return yMin; } |
318 | 0 | double getXMax() { return xMax; } |
319 | 0 | double getYMax() { return yMax; } |
320 | | |
321 | | int getRotation(); |
322 | | |
323 | | private: |
324 | | |
325 | | static int cmpX(const void *p1, const void *p2); |
326 | | static int cmpY(const void *p1, const void *p2); |
327 | | static int cmpPX(const void *p1, const void *p2); |
328 | | |
329 | | GList *paragraphs; // [TextParagraph] |
330 | | double xMin, xMax; // bounding box x coordinates |
331 | | double yMin, yMax; // bounding box y coordinates |
332 | | int px, py; // x, y position (in characters) in physical |
333 | | // layout mode |
334 | | int pw, ph; // column width, height (in characters) in |
335 | | // physical layout mode |
336 | | |
337 | | friend class TextPage; |
338 | | }; |
339 | | |
340 | | //------------------------------------------------------------------------ |
341 | | // TextWordList |
342 | | //------------------------------------------------------------------------ |
343 | | |
344 | | class TextWordList { |
345 | | public: |
346 | | |
347 | | TextWordList(GList *wordsA, GBool primaryLRA); |
348 | | |
349 | | ~TextWordList(); |
350 | | |
351 | | // Return the number of words on the list. |
352 | | int getLength(); |
353 | | |
354 | | // Return the <idx>th word from the list. |
355 | | TextWord *get(int idx); |
356 | | |
357 | | // Returns true if primary direction is left-to-right, or false if |
358 | | // right-to-left. |
359 | 0 | GBool getPrimaryLR() { return primaryLR; } |
360 | | |
361 | | private: |
362 | | |
363 | | GList *words; // [TextWord] |
364 | | GBool primaryLR; |
365 | | }; |
366 | | |
367 | | //------------------------------------------------------------------------ |
368 | | // TextPosition |
369 | | //------------------------------------------------------------------------ |
370 | | |
371 | | // Position within a TextColumn tree. The position is in column |
372 | | // [colIdx], paragraph [parIdx], line [lineIdx], before character |
373 | | // [charIdx]. |
374 | | class TextPosition { |
375 | | public: |
376 | | |
377 | 0 | TextPosition(): colIdx(0), parIdx(0), lineIdx(0), charIdx(0) {} |
378 | | TextPosition(int colIdxA, int parIdxA, int lineIdxA, int charIdxA): |
379 | 0 | colIdx(colIdxA), parIdx(parIdxA), lineIdx(lineIdxA), charIdx(charIdxA) {} |
380 | | |
381 | | int operator==(TextPosition pos); |
382 | | int operator!=(TextPosition pos); |
383 | | int operator<(TextPosition pos); |
384 | | int operator>(TextPosition pos); |
385 | | |
386 | | int colIdx, parIdx, lineIdx, charIdx; |
387 | | }; |
388 | | |
389 | | //------------------------------------------------------------------------ |
390 | | // TextPage |
391 | | //------------------------------------------------------------------------ |
392 | | |
393 | | class TextPage { |
394 | | public: |
395 | | |
396 | | TextPage(TextOutputControl *controlA); |
397 | | ~TextPage(); |
398 | | |
399 | | // Write contents of page to a stream. |
400 | | void write(void *outputStream, TextOutputFunc outputFunc); |
401 | | |
402 | | // Find a string. If <startAtTop> is true, starts looking at the |
403 | | // top of the page; else if <startAtLast> is true, starts looking |
404 | | // immediately after the last find result; else starts looking at |
405 | | // <xMin>,<yMin>. If <stopAtBottom> is true, stops looking at the |
406 | | // bottom of the page; else if <stopAtLast> is true, stops looking |
407 | | // just before the last find result; else stops looking at |
408 | | // <xMax>,<yMax>. |
409 | | GBool findText(Unicode *s, int len, |
410 | | GBool startAtTop, GBool stopAtBottom, |
411 | | GBool startAtLast, GBool stopAtLast, |
412 | | GBool caseSensitive, GBool backward, |
413 | | GBool wholeWord, |
414 | | double *xMin, double *yMin, |
415 | | double *xMax, double *yMax); |
416 | | |
417 | | // Get the text which is inside the specified rectangle. Multi-line |
418 | | // text always includes end-of-line markers at the end of each line. |
419 | | // If <forceEOL> is true, an end-of-line marker will be appended to |
420 | | // single-line text as well. |
421 | | GString *getText(double xMin, double yMin, |
422 | | double xMax, double yMax, |
423 | | GBool forceEOL = gFalse); |
424 | | |
425 | | // Find a string by character position and length. If found, sets |
426 | | // the text bounding rectangle and returns true; otherwise returns |
427 | | // false. |
428 | | GBool findCharRange(int pos, int length, |
429 | | double *xMin, double *yMin, |
430 | | double *xMax, double *yMax); |
431 | | |
432 | | // Returns true if x,y falls inside a column. |
433 | | GBool checkPointInside(double x, double y); |
434 | | |
435 | | // Find a point inside a column. Returns false if x,y fall outside |
436 | | // all columns. |
437 | | GBool findPointInside(double x, double y, TextPosition *pos); |
438 | | |
439 | | // Find a point in the nearest column. Returns false only if there |
440 | | // are no columns. |
441 | | GBool findPointNear(double x, double y, TextPosition *pos); |
442 | | |
443 | | // Find the start and end of a word inside a column. Returns false |
444 | | // if x,y fall outside all columns. |
445 | | GBool findWordPoints(double x, double y, |
446 | | TextPosition *startPos, TextPosition *endPos); |
447 | | |
448 | | // Find the start and end of a line inside a column. Returns false |
449 | | // if x,y fall outside all columns. |
450 | | GBool findLinePoints(double x, double y, |
451 | | TextPosition *startPos, TextPosition *endPos); |
452 | | |
453 | | // Get the upper point of a TextPosition. |
454 | | void convertPosToPointUpper(TextPosition *pos, double *x, double *y); |
455 | | |
456 | | // Get the lower point of a TextPosition. |
457 | | void convertPosToPointLower(TextPosition *pos, double *x, double *y); |
458 | | |
459 | | // Get the upper left corner of the line containing a TextPosition. |
460 | | void convertPosToPointLeftEdge(TextPosition *pos, double *x, double *y); |
461 | | |
462 | | // Get the lower right corner of the line containing a TextPosition. |
463 | | void convertPosToPointRightEdge(TextPosition *pos, double *x, double *y); |
464 | | |
465 | | // Get the upper right corner of a column. |
466 | | void getColumnUpperRight(int colIdx, double *x, double *y); |
467 | | |
468 | | // Get the lower left corner of a column. |
469 | | void getColumnLowerLeft(int colIdx, double *x, double *y); |
470 | | |
471 | | // Create and return a list of TextColumn objects. |
472 | | GList *makeColumns(); |
473 | | |
474 | | // Get the list of all TextFontInfo objects used on this page. |
475 | 0 | GList *getFonts() { return fonts; } |
476 | | |
477 | | // Build a flat word list, in the specified ordering. |
478 | | TextWordList *makeWordList(); |
479 | | |
480 | | // Build a word list containing only words inside the specified |
481 | | // rectangle. |
482 | | TextWordList *makeWordListForRect(double xMin, double yMin, |
483 | | double xMax, double yMax); |
484 | | |
485 | | // Get the primary rotation of text on the page. |
486 | 0 | int getPrimaryRotation() { return primaryRot; } |
487 | | |
488 | | // Returns true if the primary character direction is left-to-right, |
489 | | // false if it is right-to-left. |
490 | | GBool primaryDirectionIsLR(); |
491 | | |
492 | | // Get the counter values. |
493 | 0 | int getNumVisibleChars() { return nVisibleChars; } |
494 | 0 | int getNumInvisibleChars() { return nInvisibleChars; } |
495 | 0 | int getNumRemovedDupChars() { return nRemovedDupChars; } |
496 | | |
497 | | // Returns true if any of the fonts used on this page are likely to |
498 | | // be problematic when converting text to Unicode. |
499 | 0 | GBool problematicForUnicode() { return problematic; } |
500 | | |
501 | | // Add a 'special' character to this TextPage. This is currently |
502 | | // used by pdftohtml to insert markers for form fields. |
503 | | void addSpecialChar(double xMin, double yMin, double xMax, double yMax, |
504 | | int rot, TextFontInfo *font, double fontSize, |
505 | | Unicode u); |
506 | | |
507 | | // Remove characters that fall inside a region. |
508 | | void removeChars(double xMin, double yMin, double xMax, double yMax, |
509 | | double xOverlapThresh, double yOverlapThresh); |
510 | | |
511 | | private: |
512 | | |
513 | | void startPage(GfxState *state); |
514 | | void clear(); |
515 | | void updateFont(GfxState *state); |
516 | | void addChar(GfxState *state, double x, double y, |
517 | | double dx, double dy, |
518 | | CharCode c, int nBytes, Unicode *u, int uLen); |
519 | | void incCharCount(int nChars); |
520 | | void beginActualText(GfxState *state, Unicode *u, int uLen); |
521 | | void endActualText(GfxState *state); |
522 | | void addUnderline(double x0, double y0, double x1, double y1); |
523 | | void addLink(double xMin, double yMin, double xMax, double yMax, |
524 | | Link *link); |
525 | | |
526 | | // output |
527 | | void writeReadingOrder(void *outputStream, |
528 | | TextOutputFunc outputFunc, |
529 | | UnicodeMap *uMap, |
530 | | char *space, int spaceLen, |
531 | | char *eol, int eolLen); |
532 | | void writePhysLayout(void *outputStream, |
533 | | TextOutputFunc outputFunc, |
534 | | UnicodeMap *uMap, |
535 | | char *space, int spaceLen, |
536 | | char *eol, int eolLen); |
537 | | void writeSimpleLayout(void *outputStream, |
538 | | TextOutputFunc outputFunc, |
539 | | UnicodeMap *uMap, |
540 | | char *space, int spaceLen, |
541 | | char *eol, int eolLen); |
542 | | void writeSimple2Layout(void *outputStream, |
543 | | TextOutputFunc outputFunc, |
544 | | UnicodeMap *uMap, |
545 | | char *space, int spaceLen, |
546 | | char *eol, int eolLen); |
547 | | void writeLinePrinter(void *outputStream, |
548 | | TextOutputFunc outputFunc, |
549 | | UnicodeMap *uMap, |
550 | | char *space, int spaceLen, |
551 | | char *eol, int eolLen); |
552 | | void writeRaw(void *outputStream, |
553 | | TextOutputFunc outputFunc, |
554 | | UnicodeMap *uMap, |
555 | | char *space, int spaceLen, |
556 | | char *eol, int eolLen); |
557 | | void encodeFragment(Unicode *text, int len, UnicodeMap *uMap, |
558 | | GBool primaryLR, GString *s); |
559 | | GBool unicodeEffectiveTypeLOrNum(Unicode u, Unicode left, Unicode right); |
560 | | GBool unicodeEffectiveTypeR(Unicode u, Unicode left, Unicode right); |
561 | | |
562 | | // analysis |
563 | | int rotateChars(GList *charsA); |
564 | | void rotateCharsToZero(GList *charsA); |
565 | | void rotateUnderlinesAndLinks(int rot); |
566 | | void unrotateChars(GList *charsA, int rot); |
567 | | void unrotateCharsFromZero(GList *charsA); |
568 | | void unrotateColumnsFromZero(GList *columns); |
569 | | void unrotateColumns(GList *columns, int rot); |
570 | | void unrotateWords(GList *words, int rot); |
571 | | GBool checkPrimaryLR(GList *charsA); |
572 | | void removeDuplicates(GList *charsA, int rot); |
573 | | GList *separateOverlappingText(GList *charsA); |
574 | | TextColumn *buildOverlappingTextColumn(GList *overlappingChars); |
575 | | TextBlock *splitChars(GList *charsA); |
576 | | TextBlock *split(GList *charsA, int rot); |
577 | | GList *getChars(GList *charsA, double xMin, double yMin, |
578 | | double xMax, double yMax); |
579 | | void findGaps(GList *charsA, int rot, |
580 | | double *xMinOut, double *yMinOut, |
581 | | double *xMaxOut, double *yMaxOut, |
582 | | double *avgFontSizeOut, double *minFontSizeOut, |
583 | | GList *splitLines, |
584 | | TextGaps *horizGaps, TextGaps *vertGaps); |
585 | | void mergeSplitLines(GList *charsA, int rot, GList *splitLines); |
586 | | void tagBlock(TextBlock *blk); |
587 | | void insertLargeChars(GList *largeChars, TextBlock *blk); |
588 | | void insertLargeCharsInFirstLeaf(GList *largeChars, TextBlock *blk); |
589 | | void insertLargeCharInLeaf(TextChar *ch, TextBlock *blk); |
590 | | void insertIntoTree(TextBlock *subtree, TextBlock *primaryTree, |
591 | | GBool doReorder); |
592 | | void reorderBlocks(TextBlock *blk); |
593 | | void insertColumnIntoTree(TextBlock *column, TextBlock *tree); |
594 | | void insertClippedChars(GList *clippedChars, TextBlock *tree); |
595 | | TextBlock *findClippedCharLeaf(TextChar *ch, TextBlock *tree); |
596 | | GList *buildColumns(TextBlock *tree, GBool primaryLR); |
597 | | void buildColumns2(TextBlock *blk, GList *columns, GBool primaryLR); |
598 | | TextColumn *buildColumn(TextBlock *tree); |
599 | | double getLineIndent(TextLine *line, TextBlock *blk); |
600 | | double getAverageLineSpacing(GList *lines); |
601 | | double getLineSpacing(TextLine *line0, TextLine *line1); |
602 | | void buildLines(TextBlock *blk, GList *lines, GBool splitSuperLines); |
603 | | GList *buildSimple2Columns(GList *charsA); |
604 | | GList *buildSimple2Lines(GList *charsA, int rot); |
605 | | TextLine *buildLine(TextBlock *blk); |
606 | | TextLine *buildLine(GList *charsA, int rot, |
607 | | double xMin, double yMin, double xMax, double yMax); |
608 | | void getLineChars(TextBlock *blk, GList *charsA); |
609 | | double computeWordSpacingThreshold(GList *charsA, int rot); |
610 | | void adjustCombiningChars(GList *charsA, int rot); |
611 | | int getCharDirection(TextChar *ch); |
612 | | int getCharDirection(TextChar *ch, TextChar *left, TextChar *right); |
613 | | int assignPhysLayoutPositions(GList *columns); |
614 | | void assignLinePhysPositions(GList *columns); |
615 | | void computeLinePhysWidth(TextLine *line, UnicodeMap *uMap); |
616 | | int assignColumnPhysPositions(GList *columns); |
617 | | void buildSuperLines(TextBlock *blk, GList *superLines); |
618 | | void assignSimpleLayoutPositions(GList *superLines, UnicodeMap *uMap); |
619 | | void generateUnderlinesAndLinks(GList *columns); |
620 | | void findPointInColumn(TextColumn *col, double x, double y, |
621 | | TextPosition *pos); |
622 | | void buildFindCols(); |
623 | | |
624 | | // debug |
625 | | #if 0 //~debug |
626 | | void dumpChars(GList *charsA); |
627 | | void dumpTree(TextBlock *tree, int indent = 0); |
628 | | void dumpColumns(GList *columns, GBool dumpWords = gFalse); |
629 | | void dumpUnderlines(); |
630 | | #endif |
631 | | |
632 | | // word list |
633 | | TextWordList *makeWordListForChars(GList *charList); |
634 | | |
635 | | TextOutputControl control; // formatting parameters |
636 | | |
637 | | UnicodeRemapping *remapping; |
638 | | Unicode *uBuf; |
639 | | int uBufSize; |
640 | | |
641 | | double pageWidth, pageHeight; // width and height of current page |
642 | | int charPos; // next character position (within content |
643 | | // stream) |
644 | | TextFontInfo *curFont; // current font |
645 | | double curFontSize; // current font size |
646 | | int curRot; // current rotation |
647 | | GBool diagonal; // set if rotation is not close to |
648 | | // 0/90/180/270 degrees |
649 | | GBool rotated; // set if text is not horizontal (0 degrees) |
650 | | int nTinyChars; // number of "tiny" chars seen so far |
651 | | Unicode *actualText; // current "ActualText" span |
652 | | int actualTextLen; |
653 | | double actualTextX0, |
654 | | actualTextY0, |
655 | | actualTextX1, |
656 | | actualTextY1; |
657 | | int actualTextNBytes; |
658 | | |
659 | | GList *chars; // [TextChar] |
660 | | GList *fonts; // all font info objects used on this |
661 | | // page [TextFontInfo] |
662 | | int primaryRot; // primary rotation |
663 | | |
664 | | GList *underlines; // [TextUnderline] |
665 | | GList *links; // [TextLink] |
666 | | |
667 | | int nVisibleChars; // number of visible chars on the page |
668 | | int nInvisibleChars; // number of invisible chars on the page |
669 | | int nRemovedDupChars; // number of duplicate chars removed |
670 | | |
671 | | GList *findCols; // text used by the findText**/findPoint** |
672 | | // functions [TextColumn] |
673 | | double lastFindXMin, // coordinates of the last "find" result |
674 | | lastFindYMin; |
675 | | GBool haveLastFind; |
676 | | |
677 | | GBool problematic; // true if any of the fonts used on this |
678 | | // page are marked as problematic for |
679 | | // Unicode conversion |
680 | | |
681 | | friend class TextOutputDev; |
682 | | }; |
683 | | |
684 | | //------------------------------------------------------------------------ |
685 | | // TextOutputDev |
686 | | //------------------------------------------------------------------------ |
687 | | |
688 | | class TextOutputDev: public OutputDev { |
689 | | public: |
690 | | |
691 | | // Open a text output file. If <fileName> is NULL, no file is |
692 | | // written (this is useful, e.g., for searching text). If |
693 | | // <physLayoutA> is true, the original physical layout of the text |
694 | | // is maintained. If <rawOrder> is true, the text is kept in |
695 | | // content stream order. |
696 | | TextOutputDev(char *fileName, TextOutputControl *controlA, |
697 | | GBool append, GBool fileNameIsUTF8 = gFalse); |
698 | | |
699 | | // Create a TextOutputDev which will write to a generic stream. If |
700 | | // <physLayoutA> is true, the original physical layout of the text |
701 | | // is maintained. If <rawOrder> is true, the text is kept in |
702 | | // content stream order. |
703 | | TextOutputDev(TextOutputFunc func, void *stream, |
704 | | TextOutputControl *controlA); |
705 | | |
706 | | // Destructor. |
707 | | virtual ~TextOutputDev(); |
708 | | |
709 | | // Check if file was successfully created. |
710 | 0 | virtual GBool isOk() { return ok; } |
711 | | |
712 | | //---- get info about output device |
713 | | |
714 | | // Does this device use upside-down coordinates? |
715 | | // (Upside-down means (0,0) is the top left corner of the page.) |
716 | 0 | virtual GBool upsideDown() { return gTrue; } |
717 | | |
718 | | // Does this device use drawChar() or drawString()? |
719 | 0 | virtual GBool useDrawChar() { return gTrue; } |
720 | | |
721 | | // Does this device use beginType3Char/endType3Char? Otherwise, |
722 | | // text in Type 3 fonts will be drawn with drawChar/drawString. |
723 | 0 | virtual GBool interpretType3Chars() { return gFalse; } |
724 | | |
725 | | // Does this device need non-text content? |
726 | 0 | virtual GBool needNonText() { return gFalse; } |
727 | | |
728 | | // Does this device require incCharCount to be called for text on |
729 | | // non-shown layers? |
730 | 0 | virtual GBool needCharCount() { return gTrue; } |
731 | | |
732 | | //----- initialization and control |
733 | | |
734 | | // Start a page. |
735 | | virtual void startPage(int pageNum, GfxState *state); |
736 | | |
737 | | // End a page. |
738 | | virtual void endPage(); |
739 | | |
740 | | //----- save/restore graphics state |
741 | | virtual void restoreState(GfxState *state); |
742 | | |
743 | | //----- update text state |
744 | | virtual void updateFont(GfxState *state); |
745 | | |
746 | | //----- text drawing |
747 | | virtual void beginString(GfxState *state, GString *s); |
748 | | virtual void endString(GfxState *state); |
749 | | virtual void drawChar(GfxState *state, double x, double y, |
750 | | double dx, double dy, |
751 | | double originX, double originY, |
752 | | CharCode c, int nBytes, Unicode *u, int uLen, |
753 | | GBool fill, GBool stroke, GBool makePath); |
754 | | virtual void incCharCount(int nChars); |
755 | | virtual void beginActualText(GfxState *state, Unicode *u, int uLen); |
756 | | virtual void endActualText(GfxState *state); |
757 | | |
758 | | //----- path painting |
759 | | virtual void stroke(GfxState *state); |
760 | | virtual void fill(GfxState *state); |
761 | | virtual void eoFill(GfxState *state); |
762 | | |
763 | | //----- link borders |
764 | | virtual void processLink(Link *link); |
765 | | |
766 | | //----- special access |
767 | | |
768 | | // Find a string. If <startAtTop> is true, starts looking at the |
769 | | // top of the page; else if <startAtLast> is true, starts looking |
770 | | // immediately after the last find result; else starts looking at |
771 | | // <xMin>,<yMin>. If <stopAtBottom> is true, stops looking at the |
772 | | // bottom of the page; else if <stopAtLast> is true, stops looking |
773 | | // just before the last find result; else stops looking at |
774 | | // <xMax>,<yMax>. |
775 | | GBool findText(Unicode *s, int len, |
776 | | GBool startAtTop, GBool stopAtBottom, |
777 | | GBool startAtLast, GBool stopAtLast, |
778 | | GBool caseSensitive, GBool backward, |
779 | | GBool wholeWord, |
780 | | double *xMin, double *yMin, |
781 | | double *xMax, double *yMax); |
782 | | |
783 | | // Get the text which is inside the specified rectangle. |
784 | | GString *getText(double xMin, double yMin, |
785 | | double xMax, double yMax); |
786 | | |
787 | | // Find a string by character position and length. If found, sets |
788 | | // the text bounding rectangle and returns true; otherwise returns |
789 | | // false. |
790 | | GBool findCharRange(int pos, int length, |
791 | | double *xMin, double *yMin, |
792 | | double *xMax, double *yMax); |
793 | | |
794 | | // Build a flat word list, in content stream order (if |
795 | | // this->rawOrder is true), physical layout order (if |
796 | | // this->physLayout is true and this->rawOrder is false), or reading |
797 | | // order (if both flags are false). |
798 | | TextWordList *makeWordList(); |
799 | | |
800 | | // Build a word list containing only words inside the specified |
801 | | // rectangle. |
802 | | TextWordList *makeWordListForRect(double xMin, double yMin, |
803 | | double xMax, double yMax); |
804 | | |
805 | | // Returns the TextPage object for the last rasterized page, |
806 | | // transferring ownership to the caller. |
807 | | TextPage *takeText(); |
808 | | |
809 | | // Turn extra processing for HTML conversion on or off. |
810 | 0 | void enableHTMLExtras(GBool html) { control.html = html; } |
811 | | |
812 | | // Get the counter values. |
813 | 0 | int getNumVisibleChars() { return text->nVisibleChars; } |
814 | 0 | int getNumInvisibleChars() { return text->nInvisibleChars; } |
815 | 0 | int getNumRemovedDupChars() { return text->nRemovedDupChars; } |
816 | | |
817 | | private: |
818 | | |
819 | | void generateBOM(); |
820 | | void handleCoveredText(); |
821 | | |
822 | | TextOutputFunc outputFunc; // output function |
823 | | void *outputStream; // output stream |
824 | | GBool needClose; // need to close the output file? |
825 | | // (only if outputStream is a FILE*) |
826 | | TextPage *text; // text for the current page |
827 | | TextOutputControl control; // formatting parameters |
828 | | GBool ok; // set up ok? |
829 | | }; |
830 | | |
831 | | #endif |