예제 #1
0
 def __init__(self, page_size):
     super().__init__({
         'Type': Name('Pages'),
         'MediaBox': Array([0, 0, page_size[0], page_size[1]]),
         'Kids': Array(),
         'Count': 0,
     })
예제 #2
0
 def pdf_serialize(self, stream, font_name):
     if not self.text: return
     stream.write_line('BT ')
     serialize(Name(font_name), stream)
     stream.write(' %g Tf '%self.size)
     stream.write(' '.join(map(type(u''), self.transform)) + ' Tm ')
     if self.horizontal_scale != self.default_horizontal_scale:
         stream.write('%g Tz '%self.horizontal_scale)
     if self.word_spacing != self.default_word_spacing:
         stream.write('%g Tw '%self.word_spacing)
     if self.char_space != self.default_char_space:
         stream.write('%g Tc '%self.char_space)
     stream.write_line()
     if self.glyph_adjust is self.default_glyph_adjust:
         serialize(String(self.text), stream)
         stream.write(' Tj ')
     else:
         chars = Array()
         frac, widths = self.glyph_adjust
         for c, width in izip(self.text, widths):
             chars.append(String(c))
             chars.append(int(width * frac))
         serialize(chars, stream)
         stream.write(' TJ ')
     stream.write_line('ET')
예제 #3
0
 def add_extra_keys(self, d):
     d['Type'] = Name('Pattern')
     d['PatternType'] = 1
     d['PaintType'] = self.paint_type
     d['TilingType'] = 1
     d['BBox'] = Array([0, 0, self.w, self.h])
     d['XStep'] = self.w
     d['YStep'] = self.h
     d['Matrix'] = Array(self.matrix)
     d['Resources'] = self.resources
예제 #4
0
    def apply_stroke(self, state, pdf_system, painter):
        # TODO: Support miter limit by using QPainterPathStroker
        pen = state.stroke
        self.pending_state.do_stroke = True
        pdf = self.pdf

        # Width
        w = pen.widthF()
        if pen.isCosmetic():
            t = painter.transform()
            try:
                w /= sqrt(t.m11()**2 + t.m22()**2)
            except ZeroDivisionError:
                pass
        pdf.serialize(w)
        pdf.current_page.write(' w ')

        # Line cap
        cap = {
            Qt.FlatCap: 0,
            Qt.RoundCap: 1,
            Qt.SquareCap: 2
        }.get(pen.capStyle(), 0)
        pdf.current_page.write('%d J ' % cap)

        # Line join
        join = {
            Qt.MiterJoin: 0,
            Qt.RoundJoin: 1,
            Qt.BevelJoin: 2
        }.get(pen.joinStyle(), 0)
        pdf.current_page.write('%d j ' % join)

        # Dash pattern
        if pen.style() == Qt.CustomDashLine:
            pdf.serialize(Array(pen.dashPattern()))
            pdf.current_page.write(' %d d ' % pen.dashOffset())
        else:
            ps = {
                Qt.DashLine: [3],
                Qt.DotLine: [1, 2],
                Qt.DashDotLine: [3, 2, 1, 2],
                Qt.DashDotDotLine: [3, 2, 1, 2, 1, 2]
            }.get(pen.style(), [])
            pdf.serialize(Array(ps))
            pdf.current_page.write(' 0 d ')

        # Stroke fill
        color, opacity, pattern, self.pending_state.do_stroke = self.convert_brush(
            pen.brush(), state.brush_origin, state.opacity, pdf_system,
            painter.transform())
        self.pdf.apply_stroke(color, pattern, opacity)
        if pen.style() == Qt.NoPen:
            self.pending_state.do_stroke = False
예제 #5
0
파일: links.py 프로젝트: zyhong/calibre
 def add_links(self):
     for link in self.links:
         path, href, frag = link[0]
         page, rect = link[1:]
         combined_path = os.path.normcase(
             os.path.abspath(
                 os.path.join(os.path.dirname(path),
                              *unquote(href).split('/'))))
         is_local = not href or combined_path in self.anchors
         annot = Dictionary({
             'Type': Name('Annot'),
             'Subtype': Name('Link'),
             'Rect': rect,
             'Border': Array([0, 0, 0]),
         })
         if self.mark_links:
             annot.update({
                 'Border': Array([16, 16, 1]),
                 'C': Array([1.0, 0, 0])
             })
         if is_local:
             path = combined_path if href else path
             try:
                 annot['Dest'] = self.anchors[path][frag]
             except KeyError:
                 try:
                     annot['Dest'] = self.anchors[path][None]
                 except KeyError:
                     pass
         else:
             url = href + (('#' + frag) if frag else '')
             try:
                 purl = urlparse(url)
             except Exception:
                 self.pdf.debug('Ignoring unparseable URL: %r' % url)
                 continue
             if purl.scheme and purl.scheme != 'file':
                 action = Dictionary({
                     'Type': Name('Action'),
                     'S': Name('URI'),
                 })
                 # Do not try to normalize/quote/unquote this URL as if it
                 # has a query part, it will get corrupted
                 action['URI'] = String(url)
                 annot['A'] = action
         if 'A' in annot or 'Dest' in annot:
             if 'Annots' not in page:
                 page['Annots'] = Array()
             page['Annots'].append(self.pdf.objects.add(annot))
         else:
             self.pdf.debug(
                 'Could not find destination for link: %s in file %s' %
                 (href, path))
예제 #6
0
    def __init__(self, brush, matrix, pdf, pixel_page_width, pixel_page_height):
        self.matrix = (matrix.m11(), matrix.m12(), matrix.m21(), matrix.m22(),
                       matrix.dx(), matrix.dy())
        gradient = sip.cast(brush.gradient(), QLinearGradient)

        start, stop, stops = self.spread_gradient(gradient, pixel_page_width,
                                                  pixel_page_height, matrix)

        # TODO: Handle colors with different opacities
        self.const_opacity = stops[0].color[-1]

        funcs = Array()
        bounds = Array()
        encode = Array()

        for i, current_stop in enumerate(stops):
            if i < len(stops) - 1:
                next_stop = stops[i+1]
                func = Dictionary({
                    'FunctionType': 2,
                    'Domain': Array([0, 1]),
                    'C0': Array(current_stop.color[:3]),
                    'C1': Array(next_stop.color[:3]),
                    'N': 1,
                })
                funcs.append(func)
                encode.extend((0, 1))
                if i+1 < len(stops) - 1:
                    bounds.append(next_stop.t)

        func = Dictionary({
            'FunctionType': 3,
            'Domain': Array([stops[0].t, stops[-1].t]),
            'Functions': funcs,
            'Bounds': bounds,
            'Encode': encode,
        })

        shader = Dictionary({
            'ShadingType': 2,
            'ColorSpace': Name('DeviceRGB'),
            'AntiAlias': True,
            'Coords': Array([start.x(), start.y(), stop.x(), stop.y()]),
            'Function': func,
            'Extend': Array([True, True]),
        })

        Dictionary.__init__(self, {
            'Type': Name('Pattern'),
            'PatternType': 2,
            'Shading': shader,
            'Matrix': Array(self.matrix),
        })

        self.cache_key = (self.__class__.__name__, self.matrix,
                          tuple(shader['Coords']), stops)
예제 #7
0
 def add_links(self):
     for link in self.links:
         path, href, frag = link[0]
         page, rect = link[1:]
         combined_path = os.path.abspath(
             os.path.join(os.path.dirname(path),
                          *unquote(href).split('/')))
         is_local = not href or combined_path in self.anchors
         annot = Dictionary({
             'Type': Name('Annot'),
             'Subtype': Name('Link'),
             'Rect': rect,
             'Border': Array([0, 0, 0]),
         })
         if self.mark_links:
             annot.update({
                 'Border': Array([16, 16, 1]),
                 'C': Array([1.0, 0, 0])
             })
         if is_local:
             path = combined_path if href else path
             try:
                 annot['Dest'] = self.anchors[path][frag]
             except KeyError:
                 try:
                     annot['Dest'] = self.anchors[path][None]
                 except KeyError:
                     pass
         else:
             url = href + (('#' + frag) if frag else '')
             purl = urlparse(url)
             if purl.scheme and purl.scheme != 'file':
                 action = Dictionary({
                     'Type': Name('Action'),
                     'S': Name('URI'),
                 })
                 parts = (x.encode('utf-8')
                          if isinstance(x, type(u'')) else x for x in purl)
                 url = urlunparse(map(quote, map(unquote,
                                                 parts))).decode('ascii')
                 action['URI'] = String(url)
                 annot['A'] = action
         if 'A' in annot or 'Dest' in annot:
             if 'Annots' not in page:
                 page['Annots'] = Array()
             page['Annots'].append(self.pdf.objects.add(annot))
         else:
             self.pdf.debug(
                 'Could not find destination for link: %s in file %s' %
                 (href, path))
예제 #8
0
 def add_resources(self):
     r = Dictionary()
     if self.opacities:
         extgs = Dictionary()
         for opref, name in iteritems(self.opacities):
             extgs[name] = opref
         r['ExtGState'] = extgs
     if self.fonts:
         fonts = Dictionary()
         for ref, name in iteritems(self.fonts):
             fonts[name] = ref
         r['Font'] = fonts
     if self.xobjects:
         xobjects = Dictionary()
         for ref, name in iteritems(self.xobjects):
             xobjects[name] = ref
         r['XObject'] = xobjects
     if self.patterns:
         r['ColorSpace'] = Dictionary(
             {'PCSp': Array([Name('Pattern'),
                             Name('DeviceRGB')])})
         patterns = Dictionary()
         for ref, name in iteritems(self.patterns):
             patterns[name] = ref
         r['Pattern'] = patterns
     if r:
         self.page_dict['Resources'] = r
예제 #9
0
    def __init__(self, metrics, num, objects, compress):
        self.metrics, self.compress = metrics, compress
        self.is_otf = self.metrics.is_otf
        self.subset_tag = str(
            re.sub('.', lambda m: codepoint_to_chr(int(m.group())+ord('A')), oct(num).replace('o', '')
        )).rjust(6, 'A')
        self.font_stream = FontStream(metrics.is_otf, compress=compress)
        try:
            psname = metrics.postscript_name
        except Exception:
            psname = uuid4()
        self.font_descriptor = Dictionary({
            'Type': Name('FontDescriptor'),
            'FontName': Name('%s+%s'%(self.subset_tag, psname)),
            'Flags': 0b100,  # Symbolic font
            'FontBBox': Array(metrics.pdf_bbox),
            'ItalicAngle': metrics.post.italic_angle,
            'Ascent': metrics.pdf_ascent,
            'Descent': metrics.pdf_descent,
            'CapHeight': metrics.pdf_capheight,
            'AvgWidth': metrics.pdf_avg_width,
            'StemV': metrics.pdf_stemv,
        })
        self.descendant_font = Dictionary({
            'Type':Name('Font'),
            'Subtype':Name('CIDFontType' + ('0' if metrics.is_otf else '2')),
            'BaseFont': self.font_descriptor['FontName'],
            'FontDescriptor':objects.add(self.font_descriptor),
            'CIDSystemInfo':Dictionary({
                'Registry':String('Adobe'),
                'Ordering':String('Identity'),
                'Supplement':0,
            }),
        })
        if not self.is_otf:
            self.descendant_font['CIDToGIDMap'] = Name('Identity')

        self.font_dict = Dictionary({
            'Type':Name('Font'),
            'Subtype':Name('Type0'),
            'Encoding':Name('Identity-H'),
            'BaseFont':self.descendant_font['BaseFont'],
            'DescendantFonts':Array([objects.add(self.descendant_font)]),
        })

        self.used_glyphs = set()
예제 #10
0
파일: fonts.py 프로젝트: BobPyron/calibre
    def write_widths(self, objects):
        glyphs = sorted(self.used_glyphs|{0})
        widths = {g:self.metrics.pdf_scale(w) for g, w in izip(glyphs,
                                        self.metrics.glyph_widths(glyphs))}
        counter = Counter()
        for g, w in widths.iteritems():
            counter[w] += 1
        most_common = counter.most_common(1)[0][0]
        self.descendant_font['DW'] = most_common
        widths = {g:w for g, w in widths.iteritems() if w != most_common}

        groups = Array()
        for k, g in groupby(enumerate(widths.iterkeys()), lambda (i,x):i-x):
            group = list(map(itemgetter(1), g))
            gwidths = [widths[g] for g in group]
            if len(set(gwidths)) == 1 and len(group) > 1:
                w = (min(group), max(group), gwidths[0])
            else:
                w = (min(group), Array(gwidths))
            groups.extend(w)
예제 #11
0
    def write_widths(self, objects):
        glyphs = sorted(self.used_glyphs|{0})
        widths = {g:self.metrics.pdf_scale(w) for g, w in zip(glyphs,
                                        self.metrics.glyph_widths(glyphs))}
        counter = Counter()
        for g, w in iteritems(widths):
            counter[w] += 1
        most_common = counter.most_common(1)[0][0]
        self.descendant_font['DW'] = most_common
        widths = {g:w for g, w in iteritems(widths) if w != most_common}

        groups = Array()
        for k, g in groupby(enumerate(widths), lambda i_x:i_x[0]-i_x[1]):
            group = list(map(itemgetter(1), g))
            gwidths = [widths[g] for g in group]
            if len(set(gwidths)) == 1 and len(group) > 1:
                w = (min(group), max(group), gwidths[0])
            else:
                w = (min(group), Array(gwidths))
            groups.extend(w)
        self.descendant_font['W'] = objects.add(groups)
예제 #12
0
 def add(self, base_path, start_page, links, anchors):
     path = os.path.normcase(os.path.abspath(base_path))
     self.anchors[path] = a = {}
     a[None] = Destination(start_page, self.start, self.pdf.get_pageref)
     for anchor, pos in anchors.iteritems():
         a[anchor] = Destination(start_page, pos, self.pdf.get_pageref)
     for link in links:
         href, page, rect = link
         p, frag = href.partition('#')[0::2]
         link = ((path, p, frag
                  or None), self.pdf.get_pageref(page).obj, Array(rect))
         self.links.append(link)
예제 #13
0
 def add_extra_keys(self, d):
     d['Type'] = Name('XObject')
     d['Subtype'] = Name('Image')
     d['Width'] = self.width
     d['Height'] = self.height
     if self.depth == 1:
         d['ImageMask'] = True
         d['Decode'] = Array([1, 0])
     else:
         d['BitsPerComponent'] = 8
         d['ColorSpace'] = Name('Device' +
                                ('RGB' if self.depth == 32 else 'Gray'))
     if self.mask is not None:
         d['Mask'] = self.mask
     if self.soft_mask is not None:
         d['SMask'] = self.soft_mask
예제 #14
0
파일: serialize.py 프로젝트: zyhong/calibre
 def end(self):
     if self.current_page.getvalue():
         self.end_page()
     self.font_manager.embed_fonts(self.debug)
     inforef = self.objects.add(self.info)
     self.links.add_links()
     self.objects.pdf_serialize(self.stream)
     self.write_line()
     startxref = self.objects.write_xref(self.stream)
     file_id = String(as_unicode(self.stream.hashobj.hexdigest()))
     self.write_line('trailer')
     trailer = Dictionary({'Root':self.catalog, 'Size':len(self.objects)+1,
                           'ID':Array([file_id, file_id]), 'Info':inforef})
     serialize(trailer, self.stream)
     self.write_line('startxref')
     self.write_line('%d'%startxref)
     self.stream.write('%%EOF')
예제 #15
0
 def add(self, base_path, start_page, links, anchors):
     path = os.path.normcase(os.path.abspath(base_path))
     self.anchors[path] = a = {}
     a[None] = Destination(start_page, self.start, self.pdf.get_pageref)
     for anchor, pos in anchors.iteritems():
         a[anchor] = Destination(start_page, pos, self.pdf.get_pageref)
     for link in links:
         href, page, rect = link
         p, frag = href.partition('#')[0::2]
         try:
             pref = self.pdf.get_pageref(page).obj
         except IndexError:
             try:
                 pref = self.pdf.get_pageref(page-1).obj
             except IndexError:
                 self.pdf.debug('Unable to find page for link: %r, ignoring it' % link)
                 continue
             self.pdf.debug('The link %s points to non-existent page, moving it one page back' % href)
         self.links.append(((path, p, frag or None), pref, Array(rect)))
예제 #16
0
    def __init__(self, brush, matrix, pdf, pixel_page_width,
                 pixel_page_height):
        self.matrix = (matrix.m11(), matrix.m12(), matrix.m21(), matrix.m22(),
                       matrix.dx(), matrix.dy())
        gradient = sip.cast(brush.gradient(), QLinearGradient)

        start, stop, stops = self.spread_gradient(gradient, pixel_page_width,
                                                  pixel_page_height, matrix)

        # TODO: Handle colors with different opacities
        self.const_opacity = stops[0].color[-1]

        funcs = Array()
        bounds = Array()
        encode = Array()

        for i, current_stop in enumerate(stops):
            if i < len(stops) - 1:
                next_stop = stops[i + 1]
                func = Dictionary({
                    'FunctionType': 2,
                    'Domain': Array([0, 1]),
                    'C0': Array(current_stop.color[:3]),
                    'C1': Array(next_stop.color[:3]),
                    'N': 1,
                })
                funcs.append(func)
                encode.extend((0, 1))
                if i + 1 < len(stops) - 1:
                    bounds.append(next_stop.t)

        func = Dictionary({
            'FunctionType': 3,
            'Domain': Array([stops[0].t, stops[-1].t]),
            'Functions': funcs,
            'Bounds': bounds,
            'Encode': encode,
        })

        shader = Dictionary({
            'ShadingType':
            2,
            'ColorSpace':
            Name('DeviceRGB'),
            'AntiAlias':
            True,
            'Coords':
            Array([start.x(), start.y(),
                   stop.x(), stop.y()]),
            'Function':
            func,
            'Extend':
            Array([True, True]),
        })

        Dictionary.__init__(
            self, {
                'Type': Name('Pattern'),
                'PatternType': 2,
                'Shading': shader,
                'Matrix': Array(self.matrix),
            })

        self.cache_key = (self.__class__.__name__, self.matrix,
                          tuple(shader['Coords']), stops)