method renamed: finish(self) -> analyze(self, laparams).

pull/1/head
Yusuke Shinyama 2010-12-26 16:56:21 +09:00
parent bf44e52cf7
commit 3da3adad9b
3 changed files with 50 additions and 53 deletions

View File

@ -9,7 +9,7 @@
<div align=right class=lastmod> <div align=right class=lastmod>
<!-- hhmts start --> <!-- hhmts start -->
Last Modified: Thu Dec 23 12:28:41 UTC 2010 Last Modified: Sat Dec 25 09:40:02 UTC 2010
<!-- hhmts end --> <!-- hhmts end -->
</div> </div>

View File

@ -27,26 +27,28 @@ class PDFLayoutAnalyzer(PDFTextDevice):
(x0,y0) = apply_matrix_pt(ctm, (x0,y0)) (x0,y0) = apply_matrix_pt(ctm, (x0,y0))
(x1,y1) = apply_matrix_pt(ctm, (x1,y1)) (x1,y1) = apply_matrix_pt(ctm, (x1,y1))
mediabox = (0, 0, abs(x0-x1), abs(y0-y1)) mediabox = (0, 0, abs(x0-x1), abs(y0-y1))
self.cur_item = LTPage(self.pageno, mediabox, laparams=self.laparams) self.cur_item = LTPage(self.pageno, mediabox)
return return
def end_page(self, page): def end_page(self, page):
assert not self.stack assert not self.stack
assert isinstance(self.cur_item, LTPage) assert isinstance(self.cur_item, LTPage)
self.cur_item.finish() if self.laparams is not None:
self.cur_item.analyze(self.laparams)
self.pageno += 1 self.pageno += 1
self.receive_layout(self.cur_item) self.receive_layout(self.cur_item)
return return
def begin_figure(self, name, bbox, matrix): def begin_figure(self, name, bbox, matrix):
self.stack.append(self.cur_item) self.stack.append(self.cur_item)
self.cur_item = LTFigure(name, bbox, mult_matrix(matrix, self.ctm), laparams=self.laparams) self.cur_item = LTFigure(name, bbox, mult_matrix(matrix, self.ctm))
return return
def end_figure(self, _): def end_figure(self, _):
fig = self.cur_item fig = self.cur_item
assert isinstance(self.cur_item, LTFigure) assert isinstance(self.cur_item, LTFigure)
self.cur_item.finish() if self.laparams is not None:
self.cur_item.analyze(self.laparams)
self.cur_item = self.stack.pop() self.cur_item = self.stack.pop()
self.cur_item.add(fig) self.cur_item.add(fig)
return return

View File

@ -277,7 +277,8 @@ class LTExpandableContainer(LTContainer):
max(self.x1, obj.x1), max(self.y1, obj.y1))) max(self.x1, obj.x1), max(self.y1, obj.y1)))
return return
def finish(self): def analyze(self, laparams):
"""Perform the layout analysis."""
return self return self
@ -294,10 +295,10 @@ class LTTextLine(LTExpandableContainer, LTText):
return ('<%s %s %r>' % return ('<%s %s %r>' %
(self.__class__.__name__, bbox2str(self.bbox), self.text)) (self.__class__.__name__, bbox2str(self.bbox), self.text))
def finish(self): def analyze(self, laparams):
LTContainer.add(self, LTAnon('\n')) LTContainer.add(self, LTAnon('\n'))
self.text = ''.join( obj.text for obj in self if isinstance(obj, LTText) ) self.text = ''.join( obj.text for obj in self if isinstance(obj, LTText) )
return LTExpandableContainer.finish(self) return LTExpandableContainer.analyze(self, laparams)
def find_neighbors(self, plane, ratio): def find_neighbors(self, plane, ratio):
raise NotImplementedError raise NotImplementedError
@ -362,24 +363,24 @@ class LTTextBox(LTExpandableContainer):
(self.__class__.__name__, self.index, (self.__class__.__name__, self.index,
bbox2str(self.bbox), self.text[:20])) bbox2str(self.bbox), self.text[:20]))
def finish(self): def analyze(self, laparams):
self.text = ''.join( obj.text for obj in self if isinstance(obj, LTTextLine) ) self.text = ''.join( obj.text for obj in self if isinstance(obj, LTTextLine) )
return LTExpandableContainer.finish(self) return LTExpandableContainer.analyze(self, laparams)
class LTTextBoxHorizontal(LTTextBox): class LTTextBoxHorizontal(LTTextBox):
def finish(self): def analyze(self, laparams):
self._objs = csort(self._objs, key=lambda obj: -obj.y1) self._objs = csort(self._objs, key=lambda obj: -obj.y1)
return LTTextBox.finish(self) return LTTextBox.analyze(self, laparams)
def get_writing_mode(self): def get_writing_mode(self):
return 'lr-tb' return 'lr-tb'
class LTTextBoxVertical(LTTextBox): class LTTextBoxVertical(LTTextBox):
def finish(self): def analyze(self, laparams):
self._objs = csort(self._objs, key=lambda obj: -obj.x1) self._objs = csort(self._objs, key=lambda obj: -obj.x1)
return LTTextBox.finish(self) return LTTextBox.analyze(self, laparams)
def get_writing_mode(self): def get_writing_mode(self):
return 'tb-rl' return 'tb-rl'
@ -396,44 +397,38 @@ class LTTextGroup(LTExpandableContainer):
class LTTextGroupLRTB(LTTextGroup): class LTTextGroupLRTB(LTTextGroup):
def finish(self): def analyze(self, laparams):
# reorder the objects from top-left to bottom-right. # reorder the objects from top-left to bottom-right.
self._objs = csort(self._objs, key=lambda obj: obj.x0+obj.x1-(obj.y0+obj.y1)) self._objs = csort(self._objs, key=lambda obj: obj.x0+obj.x1-(obj.y0+obj.y1))
return LTTextGroup.finish(self) return LTTextGroup.analyze(self, laparams)
class LTTextGroupTBRL(LTTextGroup): class LTTextGroupTBRL(LTTextGroup):
def finish(self): def analyze(self, laparams):
# reorder the objects from top-right to bottom-left. # reorder the objects from top-right to bottom-left.
self._objs = csort(self._objs, key=lambda obj: -(obj.x0+obj.x1)-(obj.y0+obj.y1)) self._objs = csort(self._objs, key=lambda obj: -(obj.x0+obj.x1)-(obj.y0+obj.y1))
return LTTextGroup.finish(self) return LTTextGroup.analyze(self, laparams)
## LTLayoutContainer ## LTLayoutContainer
## ##
class LTLayoutContainer(LTContainer): class LTLayoutContainer(LTContainer):
def __init__(self, bbox, laparams=None): def __init__(self, bbox):
LTContainer.__init__(self, bbox) LTContainer.__init__(self, bbox)
self.laparams = laparams
self.layout = None self.layout = None
return return
def finish(self): def analyze(self, laparams):
"""Perform the layout analysis."""
if self.laparams is None: return
# textobjs is a list of LTChar objects, i.e. # textobjs is a list of LTChar objects, i.e.
# it has all the individual characters in the page. # it has all the individual characters in the page.
(textobjs, otherobjs) = self.get_textobjs(self._objs) (textobjs, otherobjs) = self.get_textobjs(self._objs)
if not textobjs: return if not textobjs: return
textlines = list(self.get_textlines(textobjs, textlines = list(self.get_textlines(laparams, textobjs))
self.laparams.line_overlap,
self.laparams.char_margin,
self.laparams.word_margin))
assert len(textobjs) <= sum( len(line._objs) for line in textlines ) assert len(textobjs) <= sum( len(line._objs) for line in textlines )
textboxes = list(self.get_textboxes(textlines, self.laparams.line_margin)) textboxes = list(self.get_textboxes(laparams, textlines))
assert len(textlines) == sum( len(box._objs) for box in textboxes ) assert len(textlines) == sum( len(box._objs) for box in textboxes )
top = self.group_textboxes(textboxes) top = self.group_textboxes(laparams, textboxes)
def assign_index(obj, i): def assign_index(obj, i):
if isinstance(obj, LTTextBox): if isinstance(obj, LTTextBox):
obj.index = i obj.index = i
@ -459,15 +454,15 @@ class LTLayoutContainer(LTContainer):
otherobjs.append(obj) otherobjs.append(obj)
return (textobjs, otherobjs) return (textobjs, otherobjs)
def get_textlines(self, objs, line_overlap, char_margin, word_margin): def get_textlines(self, laparams, objs):
obj0 = None obj0 = None
line = None line = None
for obj1 in objs: for obj1 in objs:
if obj0 is not None: if obj0 is not None:
k = 0 k = 0
if (obj0.is_compatible(obj1) and obj0.is_voverlap(obj1) and if (obj0.is_compatible(obj1) and obj0.is_voverlap(obj1) and
min(obj0.height, obj1.height) * line_overlap < obj0.voverlap(obj1) and min(obj0.height, obj1.height) * laparams.line_overlap < obj0.voverlap(obj1) and
obj0.hdistance(obj1) < max(obj0.width, obj1.width) * char_margin): obj0.hdistance(obj1) < max(obj0.width, obj1.width) * laparams.char_margin):
# obj0 and obj1 is horizontally aligned: # obj0 and obj1 is horizontally aligned:
# #
# +------+ - - - # +------+ - - -
@ -480,8 +475,8 @@ class LTLayoutContainer(LTContainer):
# (char_margin) # (char_margin)
k |= 1 k |= 1
if (obj0.is_compatible(obj1) and obj0.is_hoverlap(obj1) and if (obj0.is_compatible(obj1) and obj0.is_hoverlap(obj1) and
min(obj0.width, obj1.width) * line_overlap < obj0.hoverlap(obj1) and min(obj0.width, obj1.width) * laparams.line_overlap < obj0.hoverlap(obj1) and
obj0.vdistance(obj1) < max(obj0.height, obj1.height) * char_margin): obj0.vdistance(obj1) < max(obj0.height, obj1.height) * laparams.char_margin):
# obj0 and obj1 is vertically aligned: # obj0 and obj1 is vertically aligned:
# #
# +------+ # +------+
@ -501,37 +496,37 @@ class LTLayoutContainer(LTContainer):
(k & 2 and isinstance(line, LTTextLineVertical)) ): (k & 2 and isinstance(line, LTTextLineVertical)) ):
line.add(obj1) line.add(obj1)
elif line is not None: elif line is not None:
yield line.finish() yield line.analyze(laparams)
line = None line = None
else: else:
if k == 2: if k == 2:
line = LTTextLineVertical(word_margin) line = LTTextLineVertical(laparams.word_margin)
line.add(obj0) line.add(obj0)
line.add(obj1) line.add(obj1)
elif k == 1: elif k == 1:
line = LTTextLineHorizontal(word_margin) line = LTTextLineHorizontal(laparams.word_margin)
line.add(obj0) line.add(obj0)
line.add(obj1) line.add(obj1)
else: else:
line = LTTextLineHorizontal(word_margin) line = LTTextLineHorizontal(laparams.word_margin)
line.add(obj0) line.add(obj0)
yield line.finish() yield line.analyze(laparams)
line = None line = None
obj0 = obj1 obj0 = obj1
if line is None: if line is None:
line = LTTextLineHorizontal(word_margin) line = LTTextLineHorizontal(laparams.word_margin)
line.add(obj0) line.add(obj0)
yield line.finish() yield line.analyze(laparams)
return return
def get_textboxes(self, lines, line_margin): def get_textboxes(self, laparams, lines):
plane = Plane(lines) plane = Plane(lines)
for line in lines: for line in lines:
plane.add(line) plane.add(line)
plane.finish() plane.finish()
boxes = {} boxes = {}
for line in lines: for line in lines:
neighbors = line.find_neighbors(plane, line_margin) neighbors = line.find_neighbors(plane, laparams.line_margin)
assert line in neighbors, line assert line in neighbors, line
members = [] members = []
for obj1 in neighbors: for obj1 in neighbors:
@ -550,10 +545,10 @@ class LTLayoutContainer(LTContainer):
box = boxes[line] box = boxes[line]
if box in done: continue if box in done: continue
done.add(box) done.add(box)
yield box.finish() yield box.analyze(laparams)
return return
def group_textboxes(self, boxes): def group_textboxes(self, laparams, boxes):
def dist(obj1, obj2): def dist(obj1, obj2):
"""A distance function between two TextBoxes. """A distance function between two TextBoxes.
@ -593,7 +588,7 @@ class LTLayoutContainer(LTContainer):
group = LTTextGroupTBRL([obj1, obj2]) group = LTTextGroupTBRL([obj1, obj2])
else: else:
group = LTTextGroupLRTB([obj1, obj2]) group = LTTextGroupLRTB([obj1, obj2])
boxes.append(group.finish()) boxes.append(group.analyze(laparams))
assert len(boxes) == 1 assert len(boxes) == 1
return boxes.pop() return boxes.pop()
@ -602,13 +597,13 @@ class LTLayoutContainer(LTContainer):
## ##
class LTFigure(LTLayoutContainer): class LTFigure(LTLayoutContainer):
def __init__(self, name, bbox, matrix, laparams=None): def __init__(self, name, bbox, matrix):
self.name = name self.name = name
self.matrix = matrix self.matrix = matrix
(x,y,w,h) = bbox (x,y,w,h) = bbox
bbox = get_bound( apply_matrix_pt(matrix, (p,q)) bbox = get_bound( apply_matrix_pt(matrix, (p,q))
for (p,q) in ((x,y), (x+w,y), (x,y+h), (x+w,y+h)) ) for (p,q) in ((x,y), (x+w,y), (x,y+h), (x+w,y+h)) )
LTLayoutContainer.__init__(self, bbox, laparams=laparams) LTLayoutContainer.__init__(self, bbox)
return return
def __repr__(self): def __repr__(self):
@ -616,17 +611,17 @@ class LTFigure(LTLayoutContainer):
(self.__class__.__name__, self.name, (self.__class__.__name__, self.name,
bbox2str(self.bbox), matrix2str(self.matrix))) bbox2str(self.bbox), matrix2str(self.matrix)))
def finish(self): def analyze(self, laparams):
if self.laparams is None or not self.laparams.all_texts: return if not laparams.all_texts: return
return LTLayoutContainer.finish(self) return LTLayoutContainer.analyze(self, laparams)
## LTPage ## LTPage
## ##
class LTPage(LTLayoutContainer): class LTPage(LTLayoutContainer):
def __init__(self, pageid, bbox, rotate=0, laparams=None): def __init__(self, pageid, bbox, rotate=0):
LTLayoutContainer.__init__(self, bbox, laparams=laparams) LTLayoutContainer.__init__(self, bbox)
self.pageid = pageid self.pageid = pageid
self.rotate = rotate self.rotate = rotate
return return