示例#1
0
文件: widgets.py 项目: dusual/calibre
 def paint(self, painter, option, index):
     QStyledItemDelegate.paint(self, painter, option, index)
     text, positions = index.data(Qt.UserRole).toPyObject()
     self.initStyleOption(option, index)
     painter.save()
     painter.setFont(option.font)
     p = option.palette
     c = p.HighlightedText if option.state & QStyle.State_Selected else p.Text
     group = (p.Active if option.state & QStyle.State_Active else p.Inactive)
     c = p.color(group, c)
     painter.setClipRect(option.rect)
     if positions is None or -1 in positions:
         painter.setPen(c)
         painter.drawText(option.rect, Qt.AlignLeft | Qt.AlignVCenter | Qt.TextSingleLine, text)
     else:
         to = QTextOption()
         to.setWrapMode(to.NoWrap)
         to.setAlignment(Qt.AlignLeft | Qt.AlignVCenter)
         positions = sorted(set(positions) - {-1}, reverse=True)
         text = '<body>%s</body>' % make_highlighted_text(Results.EMPH, text, positions)
         doc = QTextDocument()
         c = 'rgb(%d, %d, %d)'%c.getRgb()[:3]
         doc.setDefaultStyleSheet(' body { color: %s }'%c)
         doc.setHtml(text)
         doc.setDefaultFont(option.font)
         doc.setDocumentMargin(0.0)
         doc.setDefaultTextOption(to)
         height = doc.size().height()
         painter.translate(option.rect.left(), option.rect.top() + (max(0, option.rect.height() - height) // 2))
         doc.drawContents(painter)
     painter.restore()
示例#2
0
 def __init__(self, *args):
     QPlainTextEdit.__init__(self, *args)
     # Default options to RightToleft
     options=QTextOption();
     options = self.document().defaultTextOption();
     options.setAlignment(Qt.AlignRight);
     options.setTextDirection(Qt.RightToLeft);
     self.document().setDefaultTextOption(options)
     # Default dictionary based on the current locale.
     self.dict = myspeller()
     # self.highlighter = Highlighter(self.document())
     # self.highlighter.setDict(self.dict)
     self.pretxt=''
示例#3
0
 def paint(self, painter, option, index):
     QStyledItemDelegate.paint(self, painter, option, index)
     text, positions = index.data(Qt.UserRole).toPyObject()
     self.initStyleOption(option, index)
     painter.save()
     painter.setFont(option.font)
     p = option.palette
     c = p.HighlightedText if option.state & QStyle.State_Selected else p.Text
     group = (p.Active if option.state & QStyle.State_Active else p.Inactive)
     c = p.color(group, c)
     painter.setClipRect(option.rect)
     if positions is None or -1 in positions:
         painter.setPen(c)
         painter.drawText(option.rect, Qt.AlignLeft | Qt.AlignVCenter | Qt.TextSingleLine, text)
     else:
         to = QTextOption()
         to.setWrapMode(to.NoWrap)
         to.setAlignment(Qt.AlignLeft | Qt.AlignVCenter)
         positions = sorted(set(positions) - {-1}, reverse=True)
         text = '<body>%s</body>' % make_highlighted_text(Results.EMPH, text, positions)
         doc = QTextDocument()
         c = 'rgb(%d, %d, %d)'%c.getRgb()[:3]
         doc.setDefaultStyleSheet(' body { color: %s }'%c)
         doc.setHtml(text)
         doc.setDefaultFont(option.font)
         doc.setDocumentMargin(0.0)
         doc.setDefaultTextOption(to)
         height = doc.size().height()
         painter.translate(option.rect.left(), option.rect.top() + (max(0, option.rect.height() - height) // 2))
         doc.drawContents(painter)
     painter.restore()
示例#4
0
    def __init__(self, parent=None):
        QWidget.__init__(self, parent=parent)

        self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        self.results = ()
        self.current_result = -1
        self.max_result = -1
        self.mouse_hover_result = -1
        self.setMouseTracking(True)
        self.setFocusPolicy(Qt.NoFocus)
        self.text_option = to = QTextOption()
        to.setWrapMode(to.NoWrap)
        self.divider = QStaticText('\xa0→ \xa0')
        self.divider.setTextFormat(Qt.PlainText)
示例#5
0
    def __init__(
        self,
        file_object,
        page_width,
        page_height,
        left_margin,
        top_margin,
        right_margin,
        bottom_margin,
        width,
        height,
        errors=print,
        debug=print,
        compress=True,
    ):
        QPaintEngine.__init__(self, self.features)
        self.file_object = file_object
        self.compress = compress
        self.page_height, self.page_width = page_height, page_width
        self.left_margin, self.top_margin = left_margin, top_margin
        self.right_margin, self.bottom_margin = right_margin, bottom_margin
        self.pixel_width, self.pixel_height = width, height
        # Setup a co-ordinate transform that allows us to use co-ords
        # from Qt's pixel based co-ordinate system with its origin at the top
        # left corner. PDF's co-ordinate system is based on pts and has its
        # origin in the bottom left corner. We also have to implement the page
        # margins. Therefore, we need to translate, scale and reflect about the
        # x-axis.
        dy = self.page_height - self.top_margin
        dx = self.left_margin
        sx = (self.page_width - self.left_margin - self.right_margin) / self.pixel_width
        sy = (self.page_height - self.top_margin - self.bottom_margin) / self.pixel_height

        self.pdf_system = QTransform(sx, 0, 0, -sy, dx, dy)
        self.do_stroke = True
        self.do_fill = False
        self.scale = sqrt(sy ** 2 + sx ** 2)
        self.xscale, self.yscale = sx, sy
        self.graphics_state = GraphicsState()
        self.errors_occurred = False
        self.errors, self.debug = errors, debug
        self.text_option = QTextOption()
        self.text_option.setWrapMode(QTextOption.NoWrap)
        self.fonts = {}
        i = QImage(1, 1, QImage.Format_ARGB32)
        i.fill(qRgba(0, 0, 0, 255))
        self.alpha_bit = i.constBits().asstring(4).find(b"\xff")
        self.current_page_num = 1
        self.current_page_inited = False
示例#6
0
 def __init__(self, *args):
     QPlainTextEdit.__init__(self, *args)
     # Default options to RightToleft
     options = QTextOption()
     options = self.document().defaultTextOption()
     options.setAlignment(Qt.AlignRight)
     options.setTextDirection(Qt.RightToLeft)
     self.document().setDefaultTextOption(options)
     # Default dictionary based on the current locale.
     self.dict = myspeller()
     # self.highlighter = Highlighter(self.document())
     # self.highlighter.setDict(self.dict)
     self.pretxt = ''
示例#7
0
class PdfEngine(QPaintEngine):
    def __init__(
        self,
        file_object,
        page_width,
        page_height,
        left_margin,
        top_margin,
        right_margin,
        bottom_margin,
        width,
        height,
        errors=print,
        debug=print,
        compress=True,
    ):
        QPaintEngine.__init__(self, self.features)
        self.file_object = file_object
        self.compress = compress
        self.page_height, self.page_width = page_height, page_width
        self.left_margin, self.top_margin = left_margin, top_margin
        self.right_margin, self.bottom_margin = right_margin, bottom_margin
        self.pixel_width, self.pixel_height = width, height
        # Setup a co-ordinate transform that allows us to use co-ords
        # from Qt's pixel based co-ordinate system with its origin at the top
        # left corner. PDF's co-ordinate system is based on pts and has its
        # origin in the bottom left corner. We also have to implement the page
        # margins. Therefore, we need to translate, scale and reflect about the
        # x-axis.
        dy = self.page_height - self.top_margin
        dx = self.left_margin
        sx = (self.page_width - self.left_margin - self.right_margin) / self.pixel_width
        sy = (self.page_height - self.top_margin - self.bottom_margin) / self.pixel_height

        self.pdf_system = QTransform(sx, 0, 0, -sy, dx, dy)
        self.do_stroke = True
        self.do_fill = False
        self.scale = sqrt(sy ** 2 + sx ** 2)
        self.xscale, self.yscale = sx, sy
        self.graphics_state = GraphicsState()
        self.errors_occurred = False
        self.errors, self.debug = errors, debug
        self.text_option = QTextOption()
        self.text_option.setWrapMode(QTextOption.NoWrap)
        self.fonts = {}
        i = QImage(1, 1, QImage.Format_ARGB32)
        i.fill(qRgba(0, 0, 0, 255))
        self.alpha_bit = i.constBits().asstring(4).find(b"\xff")
        self.current_page_num = 1
        self.current_page_inited = False

    def init_page(self):
        self.pdf.transform(self.pdf_system)
        self.pdf.set_rgb_colorspace()
        width = self.painter().pen().widthF() if self.isActive() else 0
        self.pdf.set_line_width(width)
        self.do_stroke = True
        self.do_fill = False
        self.graphics_state.reset()
        self.pdf.save_stack()
        self.current_page_inited = True

    @property
    def features(self):
        return (
            QPaintEngine.Antialiasing
            | QPaintEngine.AlphaBlend
            | QPaintEngine.ConstantOpacity
            | QPaintEngine.PainterPaths
            | QPaintEngine.PaintOutsidePaintEvent
            | QPaintEngine.PrimitiveTransform
        )

    def begin(self, device):
        if not hasattr(self, "pdf"):
            try:
                self.pdf = PDFStream(self.file_object, (self.page_width, self.page_height), compress=self.compress)
            except:
                self.errors.append(traceback.format_exc())
                return False
        return True

    def end_page(self):
        if self.current_page_inited:
            self.pdf.restore_stack()
            self.pdf.end_page()
            self.current_page_inited = False
            self.current_page_num += 1

    def end(self):
        try:
            self.end_page()
            self.pdf.end()
        except:
            self.errors.append(traceback.format_exc())
            return False
        finally:
            self.pdf = self.file_object = None
        return True

    def type(self):
        return QPaintEngine.Pdf

    @store_error
    def drawPixmap(self, rect, pixmap, source_rect):
        self.graphics_state(self)
        source_rect = source_rect.toRect()
        pixmap = pixmap if source_rect == pixmap.rect() else pixmap.copy(source_rect)
        image = pixmap.toImage()
        ref = self.add_image(image, pixmap.cacheKey())
        if ref is not None:
            self.pdf.draw_image(rect.x(), rect.height() + rect.y(), rect.width(), -rect.height(), ref)

    @store_error
    def drawImage(self, rect, image, source_rect, flags=Qt.AutoColor):
        self.graphics_state(self)
        source_rect = source_rect.toRect()
        image = image if source_rect == image.rect() else image.copy(source_rect)
        ref = self.add_image(image, image.cacheKey())
        if ref is not None:
            self.pdf.draw_image(rect.x(), rect.height() + rect.y(), rect.width(), -rect.height(), ref)

    def add_image(self, img, cache_key):
        if img.isNull():
            return
        ref = self.pdf.get_image(cache_key)
        if ref is not None:
            return ref

        fmt = img.format()
        image = QImage(img)
        if (
            image.depth() == 1
            and img.colorTable().size() == 2
            and img.colorTable().at(0) == QColor(Qt.black).rgba()
            and img.colorTable().at(1) == QColor(Qt.white).rgba()
        ):
            if fmt == QImage.Format_MonoLSB:
                image = image.convertToFormat(QImage.Format_Mono)
            fmt = QImage.Format_Mono
        else:
            if fmt != QImage.Format_RGB32 and fmt != QImage.Format_ARGB32:
                image = image.convertToFormat(QImage.Format_ARGB32)
                fmt = QImage.Format_ARGB32

        w = image.width()
        h = image.height()
        d = image.depth()

        if fmt == QImage.Format_Mono:
            bytes_per_line = (w + 7) >> 3
            data = image.constBits().asstring(bytes_per_line * h)
            return self.pdf.write_image(data, w, h, d, cache_key=cache_key)

        ba = QByteArray()
        buf = QBuffer(ba)
        image.save(buf, "jpeg", 94)
        data = bytes(ba.data())
        has_alpha = has_mask = False
        soft_mask = mask = None

        if fmt == QImage.Format_ARGB32:
            tmask = image.constBits().asstring(4 * w * h)[self.alpha_bit :: 4]
            sdata = bytearray(tmask)
            vals = set(sdata)
            vals.discard(255)
            has_mask = bool(vals)
            vals.discard(0)
            has_alpha = bool(vals)

        if has_alpha:
            soft_mask = self.pdf.write_image(tmask, w, h, 8)
        elif has_mask:
            # dither the soft mask to 1bit and add it. This also helps PDF
            # viewers without transparency support
            bytes_per_line = (w + 7) >> 3
            mdata = bytearray(0 for i in xrange(bytes_per_line * h))
            spos = mpos = 0
            for y in xrange(h):
                for x in xrange(w):
                    if sdata[spos]:
                        mdata[mpos + x >> 3] |= 0x80 >> (x & 7)
                    spos += 1
                mpos += bytes_per_line
            mdata = bytes(mdata)
            mask = self.pdf.write_image(mdata, w, h, 1)

        return self.pdf.write_image(data, w, h, 32, mask=mask, dct=True, soft_mask=soft_mask, cache_key=cache_key)

    @store_error
    def updateState(self, state):
        self.graphics_state.read(state)

    def convert_path(self, path):
        p = Path()
        i = 0
        while i < path.elementCount():
            elem = path.elementAt(i)
            em = (elem.x, elem.y)
            i += 1
            if elem.isMoveTo():
                p.move_to(*em)
            elif elem.isLineTo():
                p.line_to(*em)
            elif elem.isCurveTo():
                added = False
                if path.elementCount() > i + 1:
                    c1, c2 = path.elementAt(i), path.elementAt(i + 1)
                    if c1.type == path.CurveToDataElement and c2.type == path.CurveToDataElement:
                        i += 2
                        p.curve_to(em[0], em[1], c1.x, c1.y, c2.x, c2.y)
                        added = True
                if not added:
                    raise ValueError("Invalid curve to operation")
        return p

    @store_error
    def drawPath(self, path):
        self.graphics_state(self)
        p = self.convert_path(path)
        fill_rule = {Qt.OddEvenFill: "evenodd", Qt.WindingFill: "winding"}[path.fillRule()]
        self.pdf.draw_path(p, stroke=self.do_stroke, fill=self.do_fill, fill_rule=fill_rule)

    def add_clip(self, path):
        p = self.convert_path(path)
        fill_rule = {Qt.OddEvenFill: "evenodd", Qt.WindingFill: "winding"}[path.fillRule()]
        self.pdf.add_clip(p, fill_rule=fill_rule)

    @store_error
    def drawPoints(self, points):
        self.graphics_state(self)
        p = Path()
        for point in points:
            p.move_to(point.x(), point.y())
            p.line_to(point.x(), point.y() + 0.001)
        self.pdf.draw_path(p, stroke=self.do_stroke, fill=False)

    @store_error
    def drawRects(self, rects):
        self.graphics_state(self)
        for rect in rects:
            bl = rect.topLeft()
            self.pdf.draw_rect(bl.x(), bl.y(), rect.width(), rect.height(), stroke=self.do_stroke, fill=self.do_fill)

    def get_text_layout(self, text_item, text):
        tl = QTextLayout(text, text_item.font(), self.paintDevice())
        self.text_option.setTextDirection(
            Qt.RightToLeft if text_item.renderFlags() & text_item.RightToLeft else Qt.LeftToRight
        )
        tl.setTextOption(self.text_option)
        return tl

    def update_glyph_map(self, text, indices, text_item, glyph_map):
        """
        Map glyphs back to the unicode text they represent.
        """
        pos = 0
        tl = self.get_text_layout(text_item, "")
        indices = list(indices)

        def get_glyphs(string):
            tl.setText(string)
            tl.beginLayout()
            line = tl.createLine()
            if not line.isValid():
                tl.endLayout()
                return []
            line.setLineWidth(int(1e12))
            tl.endLayout()
            ans = []
            for run in tl.glyphRuns():
                ans.extend(run.glyphIndexes())
            return ans

        ipos = 0
        while ipos < len(indices):
            if indices[ipos] in glyph_map:
                t = glyph_map[indices[ipos]]
                if t == text[pos : pos + len(t)]:
                    pos += len(t)
                    ipos += 1
                    continue

            found = False
            for l in xrange(1, 10):
                string = text[pos : pos + l]
                g = get_glyphs(string)
                if g and g[0] == indices[ipos]:
                    found = True
                    glyph_map[g[0]] = string
                    break
            if not found:
                self.debug("Failed to find glyph->unicode mapping for text: %s" % text)
                break
            ipos += 1
            pos += l

        return text[pos:]

    @store_error
    def drawTextItem(self, point, text_item):
        # super(PdfEngine, self).drawTextItem(point, text_item)
        self.graphics_state(self)
        text = type("")(text_item.text()).replace("\n", " ")
        text = unicodedata.normalize("NFKC", text)
        tl = self.get_text_layout(text_item, text)
        tl.setPosition(point)
        tl.beginLayout()
        line = tl.createLine()
        if not line.isValid():
            tl.endLayout()
            return
        line.setLineWidth(int(1e12))
        tl.endLayout()
        for run in tl.glyphRuns():
            rf = run.rawFont()
            name = hash(bytes(rf.fontTable("name")))
            if name not in self.fonts:
                self.fonts[name] = Font(Sfnt(rf))
            metrics = self.fonts[name]
            indices = run.glyphIndexes()
            text = self.update_glyph_map(text, indices, text_item, metrics.glyph_map)
            glyphs = []
            pdf_pos = point
            first_baseline = None
            for i, pos in enumerate(run.positions()):
                if first_baseline is None:
                    first_baseline = pos.y()
                glyph_pos = point + pos
                delta = glyph_pos - pdf_pos
                glyphs.append((delta.x(), pos.y() - first_baseline, indices[i]))
                pdf_pos = glyph_pos

            self.pdf.draw_glyph_run([1, 0, 0, -1, point.x(), point.y()], rf.pixelSize(), metrics, glyphs)

    @store_error
    def drawPolygon(self, points, mode):
        self.graphics_state(self)
        if not points:
            return
        p = Path()
        p.move_to(points[0].x(), points[0].y())
        for point in points[1:]:
            p.line_to(point.x(), point.y())
        p.close()
        fill_rule = {self.OddEvenMode: "evenodd", self.WindingMode: "winding"}.get(mode, "evenodd")
        self.pdf.draw_path(
            p, stroke=True, fill_rule=fill_rule, fill=(mode in (self.OddEvenMode, self.WindingMode, self.ConvexMode))
        )

    def set_metadata(self, *args, **kwargs):
        self.pdf.set_metadata(*args, **kwargs)

    def __enter__(self):
        self.pdf.save_stack()
        self.saved_ps = (self.do_stroke, self.do_fill)

    def __exit__(self, *args):
        self.do_stroke, self.do_fill = self.saved_ps
        self.pdf.restore_stack()