2007-12-31 03:41:45 +00:00
|
|
|
#!/usr/bin/env python
|
2010-01-30 07:30:01 +00:00
|
|
|
import sys, os.path
|
2009-11-03 13:39:34 +00:00
|
|
|
from pdfdevice import PDFDevice, PDFTextDevice
|
2009-11-03 01:27:30 +00:00
|
|
|
from pdffont import PDFUnicodeNotDefined
|
2010-01-30 07:30:01 +00:00
|
|
|
from pdftypes import LITERALS_DCT_DECODE
|
2010-04-10 11:05:02 +00:00
|
|
|
from pdfcolor import LITERAL_DEVICE_GRAY, LITERAL_DEVICE_RGB
|
2010-04-10 11:29:30 +00:00
|
|
|
from layout import LTContainer, LTPage, LTText, LTLine, LTRect, LTPolygon
|
2010-03-22 04:00:18 +00:00
|
|
|
from layout import LTFigure, LTImage, LTChar, LTTextLine, LTTextBox, LTTextGroup
|
2009-11-03 13:39:34 +00:00
|
|
|
from utils import apply_matrix_pt, mult_matrix
|
2010-04-10 11:05:02 +00:00
|
|
|
from utils import enc, bbox2str, create_bmp
|
2009-07-23 14:03:58 +00:00
|
|
|
|
|
|
|
|
2009-05-15 14:25:32 +00:00
|
|
|
## PDFPageAggregator
|
|
|
|
##
|
2009-07-23 14:03:58 +00:00
|
|
|
class PDFPageAggregator(PDFTextDevice):
|
2009-05-15 14:25:32 +00:00
|
|
|
|
2009-10-24 04:41:59 +00:00
|
|
|
def __init__(self, rsrc, pageno=1, laparams=None):
|
|
|
|
PDFTextDevice.__init__(self, rsrc)
|
|
|
|
self.laparams = laparams
|
|
|
|
self.pageno = pageno
|
|
|
|
self.stack = []
|
|
|
|
return
|
|
|
|
|
|
|
|
def begin_page(self, page, ctm):
|
|
|
|
(x0,y0,x1,y1) = page.mediabox
|
|
|
|
(x0,y0) = apply_matrix_pt(ctm, (x0,y0))
|
|
|
|
(x1,y1) = apply_matrix_pt(ctm, (x1,y1))
|
|
|
|
mediabox = (0, 0, abs(x0-x1), abs(y0-y1))
|
|
|
|
self.cur_item = LTPage(self.pageno, mediabox)
|
|
|
|
return
|
|
|
|
|
|
|
|
def end_page(self, _):
|
|
|
|
assert not self.stack
|
|
|
|
assert isinstance(self.cur_item, LTPage)
|
2010-04-10 11:30:03 +00:00
|
|
|
self.cur_item.fixate()
|
|
|
|
self.cur_item.analyze(self.laparams)
|
2009-10-24 04:41:59 +00:00
|
|
|
self.pageno += 1
|
|
|
|
return self.cur_item
|
|
|
|
|
|
|
|
def begin_figure(self, name, bbox, matrix):
|
|
|
|
self.stack.append(self.cur_item)
|
|
|
|
self.cur_item = LTFigure(name, bbox, mult_matrix(matrix, self.ctm))
|
|
|
|
return
|
|
|
|
|
|
|
|
def end_figure(self, _):
|
|
|
|
fig = self.cur_item
|
2010-04-10 11:30:03 +00:00
|
|
|
assert isinstance(self.cur_item, LTFigure)
|
2009-10-24 04:41:59 +00:00
|
|
|
self.cur_item.fixate()
|
2010-04-10 11:30:03 +00:00
|
|
|
self.cur_item.analyze(self.laparams)
|
2009-10-24 04:41:59 +00:00
|
|
|
self.cur_item = self.stack.pop()
|
|
|
|
self.cur_item.add(fig)
|
|
|
|
return
|
|
|
|
|
2010-01-30 07:30:01 +00:00
|
|
|
def render_image(self, name, stream):
|
|
|
|
assert isinstance(self.cur_item, LTFigure)
|
2010-04-10 11:05:02 +00:00
|
|
|
item = LTImage(name, stream,
|
2010-01-30 07:30:01 +00:00
|
|
|
(self.cur_item.x0, self.cur_item.y0,
|
2010-04-10 11:05:02 +00:00
|
|
|
self.cur_item.x1, self.cur_item.y1))
|
2010-01-30 07:30:01 +00:00
|
|
|
self.cur_item.add(item)
|
|
|
|
return
|
|
|
|
|
2009-10-24 04:41:59 +00:00
|
|
|
def paint_path(self, gstate, stroke, fill, evenodd, path):
|
|
|
|
shape = ''.join(x[0] for x in path)
|
2010-01-04 12:50:59 +00:00
|
|
|
if shape == 'ml':
|
|
|
|
# horizontal/vertical line
|
2009-10-24 04:41:59 +00:00
|
|
|
(_,x0,y0) = path[0]
|
|
|
|
(_,x1,y1) = path[1]
|
|
|
|
(x0,y0) = apply_matrix_pt(self.ctm, (x0,y0))
|
|
|
|
(x1,y1) = apply_matrix_pt(self.ctm, (x1,y1))
|
2009-12-20 02:38:01 +00:00
|
|
|
self.cur_item.add(LTLine(gstate.linewidth, (x0,y0), (x1,y1)))
|
2009-10-24 04:41:59 +00:00
|
|
|
elif shape == 'mlllh':
|
|
|
|
# rectangle
|
|
|
|
(_,x0,y0) = path[0]
|
|
|
|
(_,x1,y1) = path[1]
|
|
|
|
(_,x2,y2) = path[2]
|
|
|
|
(_,x3,y3) = path[3]
|
|
|
|
(x0,y0) = apply_matrix_pt(self.ctm, (x0,y0))
|
|
|
|
(x1,y1) = apply_matrix_pt(self.ctm, (x1,y1))
|
|
|
|
(x2,y2) = apply_matrix_pt(self.ctm, (x2,y2))
|
|
|
|
(x3,y3) = apply_matrix_pt(self.ctm, (x3,y3))
|
|
|
|
if ((x0 == x1 and y1 == y2 and x2 == x3 and y3 == y0) or
|
|
|
|
(y0 == y1 and x1 == x2 and y2 == y3 and x3 == x0)):
|
|
|
|
self.cur_item.add(LTRect(gstate.linewidth, (x0,y0,x2,y2)))
|
2009-12-20 02:38:01 +00:00
|
|
|
else:
|
|
|
|
# other polygon
|
|
|
|
pts = []
|
|
|
|
for p in path:
|
|
|
|
for i in xrange(1, len(p), 2):
|
|
|
|
pts.append(apply_matrix_pt(self.ctm, (p[i], p[i+1])))
|
|
|
|
self.cur_item.add(LTPolygon(gstate.linewidth, pts))
|
2009-10-24 04:41:59 +00:00
|
|
|
return
|
|
|
|
|
2010-02-27 03:59:25 +00:00
|
|
|
def render_char(self, matrix, font, fontsize, scaling, cid):
|
|
|
|
item = LTChar(matrix, font, fontsize, scaling, cid)
|
2009-10-24 04:41:59 +00:00
|
|
|
self.cur_item.add(item)
|
|
|
|
return item.adv
|
2009-05-15 14:25:32 +00:00
|
|
|
|
2008-06-23 13:22:27 +00:00
|
|
|
|
2009-03-28 17:23:53 +00:00
|
|
|
## PDFConverter
|
2009-05-05 12:26:29 +00:00
|
|
|
##
|
2009-03-28 17:23:53 +00:00
|
|
|
class PDFConverter(PDFPageAggregator):
|
2009-10-24 04:41:59 +00:00
|
|
|
|
|
|
|
def __init__(self, rsrc, outfp, codec='utf-8', pageno=1, laparams=None):
|
|
|
|
PDFPageAggregator.__init__(self, rsrc, pageno=pageno, laparams=laparams)
|
|
|
|
self.outfp = outfp
|
|
|
|
self.codec = codec
|
|
|
|
return
|
|
|
|
|
|
|
|
def write(self, text):
|
|
|
|
self.outfp.write(enc(text, self.codec))
|
|
|
|
return
|
|
|
|
|
2010-04-10 11:05:02 +00:00
|
|
|
def write_image(self, image):
|
|
|
|
stream = image.stream
|
|
|
|
filters = stream.get_filters()
|
|
|
|
if len(filters) == 1 and filters[0] in LITERALS_DCT_DECODE:
|
|
|
|
ext = '.jpg'
|
|
|
|
data = stream.get_rawdata()
|
|
|
|
elif stream.colorspace is LITERAL_DEVICE_RGB:
|
|
|
|
ext = '.bmp'
|
|
|
|
data = create_bmp(stream.get_data(), stream.bits*3, image.width, image.height)
|
|
|
|
elif stream.colorspace is LITERAL_DEVICE_GRAY:
|
|
|
|
ext = '.bmp'
|
|
|
|
data = create_bmp(stream.get_data(), stream.bits, image.width, image.height)
|
|
|
|
else:
|
|
|
|
ext = '.img'
|
|
|
|
data = stream.get_data()
|
|
|
|
name = image.name+ext
|
|
|
|
path = os.path.join(self.outdir, name)
|
|
|
|
fp = file(path, 'wb')
|
|
|
|
fp.write(data)
|
|
|
|
fp.close()
|
|
|
|
return name
|
|
|
|
return
|
|
|
|
|
2009-10-24 04:41:59 +00:00
|
|
|
|
2010-01-31 02:12:51 +00:00
|
|
|
## TextConverter
|
2008-07-27 04:30:37 +00:00
|
|
|
##
|
2010-01-31 02:12:51 +00:00
|
|
|
class TextConverter(PDFConverter):
|
2008-07-27 04:30:37 +00:00
|
|
|
|
2010-01-31 02:12:51 +00:00
|
|
|
def __init__(self, rsrc, outfp, codec='utf-8', pageno=1, laparams=None,
|
|
|
|
showpageno=False):
|
2009-10-31 03:04:56 +00:00
|
|
|
PDFConverter.__init__(self, rsrc, outfp, codec=codec, pageno=pageno, laparams=laparams)
|
2010-01-31 02:12:51 +00:00
|
|
|
self.showpageno = showpageno
|
|
|
|
return
|
|
|
|
|
|
|
|
def write(self, text):
|
|
|
|
self.outfp.write(text.encode(self.codec, 'ignore'))
|
2009-10-31 03:04:56 +00:00
|
|
|
return
|
2010-01-30 07:30:01 +00:00
|
|
|
|
2009-10-24 04:41:59 +00:00
|
|
|
def end_page(self, page):
|
|
|
|
def render(item):
|
2010-01-31 02:12:51 +00:00
|
|
|
if isinstance(item, LTText):
|
|
|
|
self.write(item.text)
|
2010-04-10 11:29:30 +00:00
|
|
|
elif isinstance(item, LTContainer):
|
2009-10-24 04:41:59 +00:00
|
|
|
for child in item:
|
|
|
|
render(child)
|
2010-01-31 02:12:51 +00:00
|
|
|
if isinstance(item, LTTextBox):
|
|
|
|
self.write('\n')
|
2009-10-24 04:41:59 +00:00
|
|
|
page = PDFConverter.end_page(self, page)
|
2010-01-31 02:12:51 +00:00
|
|
|
if self.showpageno:
|
2010-03-22 04:00:18 +00:00
|
|
|
self.write('Page %s\n' % page.pageid)
|
2009-10-24 04:41:59 +00:00
|
|
|
render(page)
|
2010-01-31 02:12:51 +00:00
|
|
|
self.write('\f')
|
2009-10-31 03:04:56 +00:00
|
|
|
return
|
|
|
|
|
2008-07-27 04:30:37 +00:00
|
|
|
|
|
|
|
## HTMLConverter
|
|
|
|
##
|
2009-03-28 17:23:53 +00:00
|
|
|
class HTMLConverter(PDFConverter):
|
2008-07-27 04:30:37 +00:00
|
|
|
|
2009-10-24 04:41:59 +00:00
|
|
|
def __init__(self, rsrc, outfp, codec='utf-8', pageno=1, laparams=None,
|
2010-01-31 02:09:28 +00:00
|
|
|
scale=1, showpageno=True, pagepad=50, outdir=None):
|
2009-10-24 04:41:59 +00:00
|
|
|
PDFConverter.__init__(self, rsrc, outfp, codec=codec, pageno=pageno, laparams=laparams)
|
|
|
|
self.showpageno = showpageno
|
|
|
|
self.pagepad = pagepad
|
2010-01-31 02:09:28 +00:00
|
|
|
self.outdir = outdir
|
2009-10-24 04:41:59 +00:00
|
|
|
self.scale = scale
|
|
|
|
self.outfp.write('<html><head>\n')
|
|
|
|
self.outfp.write('<meta http-equiv="Content-Type" content="text/html; charset=%s">\n' %
|
|
|
|
self.codec)
|
|
|
|
self.outfp.write('</head><body>\n')
|
|
|
|
self.yoffset = self.pagepad
|
|
|
|
return
|
|
|
|
|
|
|
|
def write_rect(self, color, width, x, y, w, h):
|
|
|
|
self.outfp.write('<span style="position:absolute; border: %s %dpx solid; '
|
|
|
|
'left:%dpx; top:%dpx; width:%dpx; height:%dpx;"></span>\n' %
|
2010-03-22 04:00:18 +00:00
|
|
|
(color, width,
|
|
|
|
x*self.scale, (self.yoffset-y)*self.scale,
|
|
|
|
w*self.scale, h*self.scale))
|
|
|
|
return
|
|
|
|
|
|
|
|
def write_text(self, text, x, y, size):
|
|
|
|
self.outfp.write('<span style="position:absolute; left:%dpx; top:%dpx; font-size:%dpx;">' %
|
|
|
|
(x*self.scale, (self.yoffset-y)*self.scale, size*self.scale))
|
|
|
|
self.write(text)
|
|
|
|
self.outfp.write('</span>\n')
|
2009-10-24 04:41:59 +00:00
|
|
|
return
|
|
|
|
|
|
|
|
def end_page(self, page):
|
|
|
|
def render(item):
|
|
|
|
if isinstance(item, LTPage):
|
|
|
|
self.yoffset += item.y1
|
2010-03-22 04:00:18 +00:00
|
|
|
self.write_rect('gray', 1, item.x0, item.y1, item.width, item.height)
|
2009-10-24 04:41:59 +00:00
|
|
|
if self.showpageno:
|
|
|
|
self.outfp.write('<div style="position:absolute; top:%dpx;">' %
|
|
|
|
((self.yoffset-item.y1)*self.scale))
|
2010-03-22 04:00:18 +00:00
|
|
|
self.outfp.write('<a name="%s">Page %s</a></div>\n' % (page.pageid, page.pageid))
|
2009-10-24 04:41:59 +00:00
|
|
|
for child in item:
|
|
|
|
render(child)
|
2010-02-27 03:59:25 +00:00
|
|
|
elif isinstance(item, LTChar):
|
2010-03-22 04:00:18 +00:00
|
|
|
self.write_text(item.text, item.x0, item.y1, item.get_size())
|
2009-10-24 04:41:59 +00:00
|
|
|
if self.debug:
|
2010-03-22 04:00:18 +00:00
|
|
|
self.write_rect('red', 1, item.x0, item.y1, item.width, item.height)
|
2009-12-20 02:38:01 +00:00
|
|
|
elif isinstance(item, LTPolygon):
|
2010-03-22 04:00:18 +00:00
|
|
|
self.write_rect('black', 1, item.x0, item.y1, item.width, item.height)
|
2009-10-24 04:41:59 +00:00
|
|
|
elif isinstance(item, LTTextLine):
|
|
|
|
for child in item:
|
|
|
|
render(child)
|
|
|
|
elif isinstance(item, LTTextBox):
|
2010-03-22 04:00:18 +00:00
|
|
|
self.write_rect('blue', 1, item.x0, item.y1, item.width, item.height)
|
2010-03-21 02:21:37 +00:00
|
|
|
for child in item:
|
|
|
|
render(child)
|
|
|
|
if self.debug:
|
2010-03-22 04:00:18 +00:00
|
|
|
self.write_text(str(item.index+1), item.x0, item.y1, 20)
|
2009-10-24 04:41:59 +00:00
|
|
|
elif isinstance(item, LTFigure):
|
2010-03-22 04:00:18 +00:00
|
|
|
self.write_rect('green', 1, item.x0, item.y1, item.width, item.height)
|
2009-10-24 04:41:59 +00:00
|
|
|
for child in item:
|
|
|
|
render(child)
|
2010-01-30 07:30:01 +00:00
|
|
|
elif isinstance(item, LTImage):
|
2010-01-31 02:09:28 +00:00
|
|
|
if self.outdir:
|
2010-04-10 11:05:02 +00:00
|
|
|
name = self.write_image(item)
|
2010-04-10 11:30:03 +00:00
|
|
|
self.outfp.write('<img src="%s" style="position:absolute; left:%dpx; top:%dpx;" '
|
|
|
|
'width="%d" height="%d" />\n' %
|
|
|
|
(enc(name),
|
|
|
|
item.x0*self.scale, (self.yoffset-item.y1)*self.scale,
|
|
|
|
item.width*self.scale, item.height*self.scale))
|
2009-10-24 04:41:59 +00:00
|
|
|
return
|
|
|
|
page = PDFConverter.end_page(self, page)
|
|
|
|
render(page)
|
2010-03-26 11:11:35 +00:00
|
|
|
if self.debug and page.layout:
|
2010-03-22 04:00:18 +00:00
|
|
|
def show_layout(item):
|
|
|
|
if isinstance(item, LTTextGroup):
|
|
|
|
self.write_rect('red', 1, item.x0, item.y1, item.width, item.height)
|
|
|
|
for child in item:
|
|
|
|
show_layout(child)
|
|
|
|
return
|
|
|
|
show_layout(page.layout)
|
2009-10-24 04:41:59 +00:00
|
|
|
self.yoffset += self.pagepad
|
|
|
|
return
|
|
|
|
|
|
|
|
def close(self):
|
|
|
|
self.outfp.write('<div style="position:absolute; top:0px;">Page: %s</div>\n' %
|
|
|
|
', '.join('<a href="#%s">%s</a>' % (i,i) for i in xrange(1,self.pageno)))
|
|
|
|
self.outfp.write('</body></html>\n')
|
|
|
|
return
|
2008-07-27 04:30:37 +00:00
|
|
|
|
|
|
|
|
2010-01-31 02:12:51 +00:00
|
|
|
## XMLConverter
|
2009-03-28 17:23:53 +00:00
|
|
|
##
|
2010-01-31 02:12:51 +00:00
|
|
|
class XMLConverter(PDFConverter):
|
2009-03-28 17:23:53 +00:00
|
|
|
|
2010-01-31 02:12:51 +00:00
|
|
|
def __init__(self, rsrc, outfp, codec='utf-8', pageno=1, laparams=None, outdir=None):
|
2009-10-24 04:41:59 +00:00
|
|
|
PDFConverter.__init__(self, rsrc, outfp, codec=codec, pageno=pageno, laparams=laparams)
|
2010-01-31 02:12:51 +00:00
|
|
|
self.outdir = outdir
|
|
|
|
self.outfp.write('<?xml version="1.0" encoding="%s" ?>\n' % codec)
|
|
|
|
self.outfp.write('<pages>\n')
|
2009-10-24 04:41:59 +00:00
|
|
|
return
|
|
|
|
|
|
|
|
def end_page(self, page):
|
|
|
|
def render(item):
|
2010-01-31 02:12:51 +00:00
|
|
|
if isinstance(item, LTPage):
|
|
|
|
self.outfp.write('<page id="%s" bbox="%s" rotate="%d">\n' %
|
2010-03-22 04:00:18 +00:00
|
|
|
(item.pageid, bbox2str(item.bbox), item.rotate))
|
2009-10-24 04:41:59 +00:00
|
|
|
for child in item:
|
|
|
|
render(child)
|
2010-01-31 02:12:51 +00:00
|
|
|
self.outfp.write('</page>\n')
|
2010-03-22 04:00:18 +00:00
|
|
|
elif isinstance(item, LTLine):
|
|
|
|
self.outfp.write('<line linewidth="%d" bbox="%s" />\n' %
|
|
|
|
(item.linewidth, bbox2str(item.bbox)))
|
2010-01-31 02:12:51 +00:00
|
|
|
elif isinstance(item, LTRect):
|
2010-02-27 03:59:25 +00:00
|
|
|
self.outfp.write('<rect linewidth="%d" bbox="%s" />\n' %
|
|
|
|
(item.linewidth, bbox2str(item.bbox)))
|
2010-01-31 02:12:51 +00:00
|
|
|
elif isinstance(item, LTPolygon):
|
2010-02-27 03:59:25 +00:00
|
|
|
self.outfp.write('<polygon linewidth="%d" bbox="%s" pts="%s"/>\n' %
|
|
|
|
(item.linewidth, bbox2str(item.bbox), item.get_pts()))
|
2010-01-31 02:12:51 +00:00
|
|
|
elif isinstance(item, LTFigure):
|
2010-03-22 04:00:18 +00:00
|
|
|
self.outfp.write('<figure name="%s" bbox="%s">\n' %
|
|
|
|
(item.name, bbox2str(item.bbox)))
|
2010-01-31 02:12:51 +00:00
|
|
|
for child in item:
|
|
|
|
render(child)
|
|
|
|
self.outfp.write('</figure>\n')
|
|
|
|
elif isinstance(item, LTTextLine):
|
2010-02-27 03:59:25 +00:00
|
|
|
self.outfp.write('<textline bbox="%s">\n' % bbox2str(item.bbox))
|
2010-01-31 02:12:51 +00:00
|
|
|
for child in item:
|
|
|
|
render(child)
|
|
|
|
self.outfp.write('</textline>\n')
|
|
|
|
elif isinstance(item, LTTextBox):
|
2010-03-22 04:00:18 +00:00
|
|
|
self.outfp.write('<textbox id="%d" bbox="%s">\n' % (item.index, bbox2str(item.bbox)))
|
2010-01-31 02:12:51 +00:00
|
|
|
for child in item:
|
|
|
|
render(child)
|
|
|
|
self.outfp.write('</textbox>\n')
|
2010-02-27 03:59:25 +00:00
|
|
|
elif isinstance(item, LTChar):
|
2010-04-10 11:05:02 +00:00
|
|
|
vertical = ''
|
|
|
|
if item.is_vertical():
|
|
|
|
vertical = 'vertical="true" '
|
|
|
|
self.outfp.write('<text font="%s" %sbbox="%s" size="%.3f">' %
|
|
|
|
(enc(item.font.fontname), vertical,
|
2010-02-27 03:59:25 +00:00
|
|
|
bbox2str(item.bbox), item.get_size()))
|
2010-01-31 02:12:51 +00:00
|
|
|
self.write(item.text)
|
|
|
|
self.outfp.write('</text>\n')
|
|
|
|
elif isinstance(item, LTText):
|
|
|
|
self.outfp.write('<text>%s</text>\n' % item.text)
|
|
|
|
elif isinstance(item, LTImage):
|
|
|
|
if self.outdir:
|
|
|
|
name = self.write_image(item)
|
2010-04-10 11:30:03 +00:00
|
|
|
self.outfp.write('<image src="%s" width="%d" height="%d" />\n' %
|
|
|
|
(enc(name), item.width, item.height))
|
|
|
|
else:
|
|
|
|
self.outfp.write('<image width="%d" height="%d" />\n' %
|
|
|
|
(item.width, item.height))
|
2010-01-31 02:12:51 +00:00
|
|
|
else:
|
|
|
|
assert 0, item
|
|
|
|
return
|
2009-10-24 04:41:59 +00:00
|
|
|
page = PDFConverter.end_page(self, page)
|
|
|
|
render(page)
|
2010-03-22 04:00:18 +00:00
|
|
|
if page.layout:
|
|
|
|
def show_layout(item):
|
|
|
|
if isinstance(item, LTTextBox):
|
|
|
|
self.outfp.write('<textbox id="%d" bbox="%s" />\n' % (item.index, bbox2str(item.bbox)))
|
|
|
|
elif isinstance(item, LTTextGroup):
|
|
|
|
self.outfp.write('<textgroup bbox="%s">\n' % bbox2str(item.bbox))
|
|
|
|
for child in item:
|
|
|
|
show_layout(child)
|
|
|
|
self.outfp.write('</textgroup>\n')
|
|
|
|
return
|
|
|
|
self.outfp.write('<layout>\n')
|
|
|
|
show_layout(page.layout)
|
|
|
|
self.outfp.write('</layout>\n')
|
2010-01-31 02:12:51 +00:00
|
|
|
return
|
|
|
|
|
|
|
|
def close(self):
|
|
|
|
self.outfp.write('</pages>\n')
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
|
|
## TagExtractor
|
|
|
|
##
|
|
|
|
class TagExtractor(PDFDevice):
|
|
|
|
|
|
|
|
def __init__(self, rsrc, outfp, codec='utf-8'):
|
|
|
|
PDFDevice.__init__(self, rsrc)
|
|
|
|
self.outfp = outfp
|
|
|
|
self.codec = codec
|
|
|
|
self.pageno = 0
|
|
|
|
self.tag = None
|
|
|
|
return
|
|
|
|
|
|
|
|
def render_string(self, textstate, seq):
|
|
|
|
font = textstate.font
|
|
|
|
text = ''
|
|
|
|
for obj in seq:
|
|
|
|
if not isinstance(obj, str): continue
|
|
|
|
chars = font.decode(obj)
|
|
|
|
for cid in chars:
|
|
|
|
try:
|
|
|
|
char = font.to_unichr(cid)
|
|
|
|
text += char
|
|
|
|
except PDFUnicodeNotDefined:
|
|
|
|
pass
|
|
|
|
self.outfp.write(enc(text, self.codec))
|
|
|
|
return
|
|
|
|
|
|
|
|
def begin_page(self, page, ctm):
|
|
|
|
self.outfp.write('<page id="%s" bbox="%s" rotate="%d">' %
|
2010-02-27 03:59:25 +00:00
|
|
|
(self.pageno, bbox2str(page.mediabox), page.rotate))
|
2010-01-31 02:12:51 +00:00
|
|
|
return
|
|
|
|
|
|
|
|
def end_page(self, page):
|
|
|
|
self.outfp.write('</page>\n')
|
|
|
|
self.pageno += 1
|
|
|
|
return
|
|
|
|
|
|
|
|
def begin_tag(self, tag, props=None):
|
|
|
|
s = ''
|
|
|
|
if props:
|
|
|
|
s = ''.join( ' %s="%s"' % (enc(k), enc(str(v))) for (k,v)
|
|
|
|
in sorted(props.iteritems()) )
|
|
|
|
self.outfp.write('<%s%s>' % (enc(tag.name), s))
|
|
|
|
self.tag = tag
|
|
|
|
return
|
|
|
|
|
|
|
|
def end_tag(self):
|
|
|
|
assert self.tag
|
|
|
|
self.outfp.write('</%s>' % enc(self.tag.name))
|
|
|
|
self.tag = None
|
|
|
|
return
|
|
|
|
|
|
|
|
def do_tag(self, tag, props=None):
|
|
|
|
self.begin_tag(tag, props)
|
|
|
|
self.tag = None
|
2009-10-24 04:41:59 +00:00
|
|
|
return
|