Пример #1
0
 def __call__(self, ok):
     from PyQt5.Qt import QImage, QPainter, QByteArray, QBuffer
     try:
         if not ok:
             raise RuntimeError('Rendering of HTML failed.')
         de = self.page.mainFrame().documentElement()
         pe = de.findFirst('parsererror')
         if not pe.isNull():
             raise ParserError(pe.toPlainText())
         image = QImage(self.page.viewportSize(), QImage.Format_ARGB32)
         image.setDotsPerMeterX(96 * (100 / 2.54))
         image.setDotsPerMeterY(96 * (100 / 2.54))
         painter = QPainter(image)
         self.page.mainFrame().render(painter)
         painter.end()
         ba = QByteArray()
         buf = QBuffer(ba)
         buf.open(QBuffer.WriteOnly)
         image.save(buf, 'JPEG')
         self.data = str(ba.data())
     except Exception as e:
         self.exception = e
         self.traceback = traceback.format_exc()
     finally:
         self.loop.exit(0)
Пример #2
0
def create_profile():
    ans = getattr(create_profile, 'ans', None)
    if ans is None:
        ans = QWebEngineProfile(QApplication.instance())
        osname = 'windows' if iswindows else ('macos' if isosx else 'linux')
        # DO NOT change the user agent as it is used to workaround
        # Qt bugs see workaround_qt_bug() in ajax.pyj
        ua = 'calibre-viewer {} {}'.format(__version__, osname)
        ans.setHttpUserAgent(ua)
        if is_running_from_develop:
            from calibre.utils.rapydscript import compile_viewer
            prints('Compiling viewer code...')
            compile_viewer()
        js = P('viewer.js', data=True, allow_user_override=False)
        translations_json = get_translations_data() or b'null'
        js = js.replace(b'__TRANSLATIONS_DATA__', translations_json, 1)
        insert_scripts(ans, create_script('viewer.js', js))
        url_handler = UrlSchemeHandler(ans)
        ans.installUrlSchemeHandler(QByteArray(FAKE_PROTOCOL.encode('ascii')),
                                    url_handler)
        s = ans.settings()
        s.setDefaultTextEncoding('utf-8')
        s.setAttribute(s.LinksIncludedInFocusChain, False)
        create_profile.ans = ans
    return ans
Пример #3
0
def create_profile():
    ans = getattr(create_profile, 'ans', None)
    if ans is None:
        ans = QWebEngineProfile(QApplication.instance())
        ua = 'calibre-editor-preview ' + __version__
        ans.setHttpUserAgent(ua)
        if is_running_from_develop:
            from calibre.utils.rapydscript import compile_editor
            compile_editor()
        js = P('editor.js', data=True, allow_user_override=False)
        cparser = P('csscolorparser.js', data=True, allow_user_override=False)
        dark_mode_css = P('dark_mode.css',
                          data=True,
                          allow_user_override=False).decode('utf-8')

        insert_scripts(
            ans, create_script('csscolorparser.js', cparser),
            create_script('editor.js', js),
            create_script('dark-mode.js',
                          '''
            (function() {
                var settings = JSON.parse(navigator.userAgent.split('|')[1]);
                var dark_css = CSS;

                function apply_body_colors(event) {
                    if (document.documentElement) {
                        if (settings.bg) document.documentElement.style.backgroundColor = settings.bg;
                        if (settings.fg) document.documentElement.style.color = settings.fg;
                    }
                    if (document.body) {
                        if (settings.bg) document.body.style.backgroundColor = settings.bg;
                        if (settings.fg) document.body.style.color = settings.fg;
                    }
                }

                function apply_css() {
                    var css = '';
                    if (settings.link) css += 'html > body :link, html > body :link * { color: ' + settings.link + ' !important; }';
                    if (settings.is_dark_theme) { css += dark_css; }
                    var style = document.createElement('style');
                    style.textContent = css;
                    document.documentElement.appendChild(style);
                    apply_body_colors();
                }

                apply_body_colors();
                document.addEventListener("DOMContentLoaded", apply_css);
            })();
            '''.replace('CSS', json.dumps(dark_mode_css), 1),
                          injection_point=QWebEngineScript.DocumentCreation))
        url_handler = UrlSchemeHandler(ans)
        ans.installUrlSchemeHandler(QByteArray(FAKE_PROTOCOL.encode('ascii')),
                                    url_handler)
        s = ans.settings()
        s.setDefaultTextEncoding('utf-8')
        s.setAttribute(s.FullScreenSupportEnabled, False)
        s.setAttribute(s.LinksIncludedInFocusChain, False)
        create_profile.ans = ans
    return ans
Пример #4
0
 def __getstate__(self):
     result = dict(self.__dict__)
     result['url'] = result['url'].toEncoded()
     data = QByteArray()
     ds = QDataStream(data, QIODevice.WriteOnly)
     ds.writeQVariant(self.icon)
     result['icon'] = data.data()
     return result
Пример #5
0
def image_and_format_from_data(data):
    ' Create an image object from the specified data which should be a bytsestring and also return the format of the image '
    ba = QByteArray(data)
    buf = QBuffer(ba)
    buf.open(QBuffer.ReadOnly)
    r = QImageReader(buf)
    fmt = bytes(r.format()).decode('utf-8')
    return r.read(), fmt
Пример #6
0
def icon_to_dbus_menu_icon(icon, size=32):
    if icon.isNull():
        return None
    ba = QByteArray()
    buf = QBuffer(ba)
    buf.open(QIODevice.OpenModeFlag.WriteOnly)
    icon.pixmap(32).save(buf, 'PNG')
    return dbus.ByteArray(ba)
Пример #7
0
def icon_to_dbus_menu_icon(icon, size=32):
    if icon.isNull():
        return None
    ba = QByteArray()
    buf = QBuffer(ba)
    buf.open(QBuffer.WriteOnly)
    icon.pixmap(32).save(buf, 'PNG')
    return dbus.ByteArray(bytes((ba.data())))
Пример #8
0
def create_profile(parent=None, private=False):
    from .vise_scheme import UrlSchemeHandler
    from .url_intercept import Interceptor
    if parent is None:
        parent = QApplication.instance()
    if private:
        from .downloads import download_requested
        ans = QWebEngineProfile(parent)
        ans.downloadRequested.connect(download_requested)
    else:
        ans = QWebEngineProfile(appname, parent)
        ans.setCachePath(os.path.join(cache_dir, appname, 'cache'))
        safe_makedirs(ans.cachePath())
        ans.setPersistentStoragePath(
            os.path.join(cache_dir, appname, 'storage'))
        safe_makedirs(ans.persistentStoragePath())
    # TODO: Enable spellchecking when
    # https://bugreports.qt.io/browse/QTBUG-58512 is implemented.
    # See https://doc.qt.io/qt-5/qtwebengine-webenginewidgets-spellchecker-example.html for how to create the Qt .bdic files
    ua = ' '.join(x for x in ans.httpUserAgent().split()
                  if 'QtWebEngine' not in x)
    ans.setHttpUserAgent(ua)
    ans.setRequestInterceptor(Interceptor(ans))
    try:
        insert_scripts(ans, client_script())
    except FileNotFoundError as err:
        if '-client.js' in str(err):
            raise SystemExit(
                'You need to compile the rapydscript parts of vise before running it. Install rapydscript-ng and run the build script'
            )
        raise
    ans.url_handler = UrlSchemeHandler(ans)
    ans.installUrlSchemeHandler(QByteArray(b'vise'), ans.url_handler)
    s = ans.settings()
    s.setDefaultTextEncoding('utf-8')
    s.setAttribute(s.FullScreenSupportEnabled, True)
    s.setAttribute(s.LinksIncludedInFocusChain, False)
    from .config import font_families, font_sizes
    for ftype, family in font_families().items():
        if ftype != 'default' and family:
            ftype = ftype.replace('-', '').capitalize().replace(
                'serif', 'Serif') + 'Font'
            ftype = getattr(s, ftype, None)
            if ftype:
                s.setFontFamily(ftype, family)

    for ftype, sz in font_sizes().items():
        if sz > 0:
            ftype = {
                'minimum': 'Minimum',
                'minimum-logical': 'MinimumLogical',
                'default-size': 'Default',
                'default-monospace-size': 'DefaultFixed'
            }.get(ftype)
            if ftype:
                ftype = getattr(s, ftype + 'FontSize')
                s.setFontSize(ftype, sz)
    return ans
Пример #9
0
 def loadResource(self, rtype, qurl):
     if qurl.isLocalFile():
         path = qurl.toLocalFile()
         try:
             with lopen(path, 'rb') as f:
                 data = f.read()
         except EnvironmentError:
             if path.rpartition('.')[-1].lower() in {'jpg', 'jpeg', 'gif', 'png', 'bmp', 'webp'}:
                 return QByteArray(bytearray.fromhex(
                     '89504e470d0a1a0a0000000d49484452'
                     '000000010000000108060000001f15c4'
                     '890000000a49444154789c6300010000'
                     '0500010d0a2db40000000049454e44ae'
                     '426082'))
         else:
             return QByteArray(data)
     else:
         return QTextBrowser.loadResource(self, rtype, qurl)
Пример #10
0
 def __setstate__(self, state):
     for key, val in state.items():
         if key == 'url':
             self.__dict__[key] = QUrl.fromEncoded(val)
         elif key == 'icon':
             ds = QDataStream(QByteArray(val))
             self.__dict__[key] = ds.readQVariant()
         else:
             self.__dict__[key] = val
Пример #11
0
def get_welcome_html():
    if not hasattr(get_welcome_html, 'html'):
        d = get_data('welcome.html').decode('utf-8')
        ic = get_data('images/vise.svg')
        d = d.replace(
            'VISE_ICON', 'data:image/svg+xml;base64,' +
            base64.standard_b64encode(ic).decode('ascii'))
        get_welcome_html.html = QByteArray(d.encode('utf-8'))
    return get_welcome_html.html
Пример #12
0
def image_to_data(image):  # {{{
    ba = QByteArray()
    buf = QBuffer(ba)
    buf.open(QBuffer.WriteOnly)
    if not image.save(buf, CACHE_FORMAT):
        raise EncodeError('Failed to encode thumbnail')
    ret = ba.data()
    buf.close()
    return ret
Пример #13
0
def pixmap_to_data(pixmap, format='JPEG', quality=90):
    '''
    Return the QPixmap pixmap as a string saved in the specified format.
    '''
    ba = QByteArray()
    buf = QBuffer(ba)
    buf.open(QBuffer.WriteOnly)
    pixmap.save(buf, format, quality=quality)
    return bytes(ba.data())
Пример #14
0
    def add_image(self, img, cache_key):
        ref = self.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.write_image(data, w, h, d, cache_key=cache_key)

        has_alpha = False
        soft_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)  # discard opaque pixels
            has_alpha = bool(vals)
            if has_alpha:
                # Blend image onto a white background as otherwise Qt will render
                # transparent pixels as black
                background = QImage(image.size(), QImage.Format_ARGB32_Premultiplied)
                background.fill(Qt.white)
                painter = QPainter(background)
                painter.drawImage(0, 0, image)
                painter.end()
                image = background

        ba = QByteArray()
        buf = QBuffer(ba)
        image.save(buf, 'jpeg', 94)
        data = ba.data()

        if has_alpha:
            soft_mask = self.write_image(tmask, w, h, 8)

        return self.write_image(data, w, h, 32, dct=True,
                                soft_mask=soft_mask, cache_key=cache_key)
Пример #15
0
 def clear(self):
     self.title = ''
     self.url = QUrl()
     self.icon = QIcon()
     self.history = QByteArray()
     self.isPinned = False
     self.zoomLevel = 1
     self.parentTab = -1
     self.childTabs = []
     self.sessionData = {}
Пример #16
0
    def __getstate__(self):
        data = QByteArray()
        stream = QDataStream(data, QIODevice.WriteOnly)
        stream.writeQVariant(self.windows)

        stream.writeInt(self._s_restoreDataVersion)
        stream.writeQVariant(self.crashedSession)
        stream.writeQVariant(self.closedWindows)

        return data
Пример #17
0
def to_png(bmp):
    from PyQt5.Qt import QImage, QByteArray, QBuffer
    i = QImage()
    if not i.loadFromData(bmp):
        raise ValueError('Invalid image data')
    ba = QByteArray()
    buf = QBuffer(ba)
    buf.open(QBuffer.WriteOnly)
    i.save(buf, 'png')
    return ba.data()
Пример #18
0
    def rasterize_svg(self, elem, width=0, height=0, format='PNG'):
        view_box = elem.get('viewBox', elem.get('viewbox', None))
        sizes = None
        logger = self.oeb.logger

        if view_box is not None:
            try:
                box = [float(x) for x in filter(None, re.split('[, ]', view_box))]
                sizes = [box[2]-box[0], box[3] - box[1]]
            except (TypeError, ValueError, IndexError):
                logger.warn('SVG image has invalid viewBox="%s", ignoring the viewBox' % view_box)
            else:
                for image in elem.xpath('descendant::*[local-name()="image" and '
                        '@height and contains(@height, "%")]'):
                    logger.info('Found SVG image height in %, trying to convert...')
                    try:
                        h = float(image.get('height').replace('%', ''))/100.
                        image.set('height', str(h*sizes[1]))
                    except:
                        logger.exception('Failed to convert percentage height:',
                                image.get('height'))

        data = QByteArray(xml2str(elem, with_tail=False))
        svg = QSvgRenderer(data)
        size = svg.defaultSize()
        if size.width() == 100 and size.height() == 100 and sizes:
            size.setWidth(sizes[0])
            size.setHeight(sizes[1])
        if width or height:
            size.scale(width, height, Qt.KeepAspectRatio)
        logger.info('Rasterizing %r to %dx%d'
                    % (elem, size.width(), size.height()))
        image = QImage(size, QImage.Format_ARGB32_Premultiplied)
        image.fill(QColor("white").rgb())
        painter = QPainter(image)
        svg.render(painter)
        painter.end()
        array = QByteArray()
        buffer = QBuffer(array)
        buffer.open(QIODevice.WriteOnly)
        image.save(buffer, format)
        return str(array)
Пример #19
0
 def rasterize_external(self, elem, style, item, svgitem):
     width = style['width']
     height = style['height']
     width = (width / 72) * self.profile.dpi
     height = (height / 72) * self.profile.dpi
     data = QByteArray(str(svgitem))
     svg = QSvgRenderer(data)
     size = svg.defaultSize()
     size.scale(width, height, Qt.KeepAspectRatio)
     key = (svgitem.href, size.width(), size.height())
     if key in self.images:
         href = self.images[key]
     else:
         logger = self.oeb.logger
         logger.info('Rasterizing %r to %dx%d' %
                     (svgitem.href, size.width(), size.height()))
         image = QImage(size, QImage.Format_ARGB32_Premultiplied)
         image.fill(QColor("white").rgb())
         painter = QPainter(image)
         svg.render(painter)
         painter.end()
         array = QByteArray()
         buffer = QBuffer(array)
         buffer.open(QIODevice.WriteOnly)
         image.save(buffer, 'PNG')
         data = str(array)
         manifest = self.oeb.manifest
         href = os.path.splitext(svgitem.href)[0] + '.png'
         id, href = manifest.generate(svgitem.id, href)
         manifest.add(id, href, PNG_MIME, data=data)
         self.images[key] = href
     elem.tag = XHTML('img')
     for attr in elem.attrib:
         if attr not in KEEP_ATTRS:
             del elem.attrib[attr]
     elem.attrib['src'] = item.relhref(href)
     if elem.text:
         elem.attrib['alt'] = elem.text
         elem.text = None
     for child in elem:
         elem.remove(child)
Пример #20
0
 def __init__(self, webTab=None):
     self.title = ''
     self.url = QUrl()
     self.icon = QIcon()
     self.history = QByteArray()
     self.isPinned = False
     self.zoomLevel = 1
     self.parentTab = -1
     self.childTabs = []
     self.sessionData = {}
     if webTab:
         self.setWebTab(webTab)
Пример #21
0
 def historyData(self):
     '''
     @return QByteArray
     '''
     if self.isRestored():
         historyArray = QByteArray()
         stream = QDataStream(historyArray, QIODevice.WriteOnly)
         history = self._webView.history()
         stream << history
         return historyArray
     else:
         return self._savedTab.history
 def mimeData(self, indices):
     mimeData = QMimeData()
     encodedData = QByteArray()
     stream = QDataStream(encodedData, QIODevice.WriteOnly)
     for index in indices:
         if index.column() == 1:
             d = QVariant(self.data(index, Qt.DecorationRole))
         else:
             d = QVariant(self.data(index, Qt.DisplayRole).toString())
         stream << d
     mimeData.setData('application/target.tableitem.creepy', encodedData)
     return mimeData
Пример #23
0
    def handle_embedded_fonts(self):
        ''' On windows, Qt uses GDI which does not support OpenType
        (CFF) fonts, so we need to nuke references to OpenType
        fonts. Qt's directwrite text backend is not mature.
        Also make sure all fonts are embeddable. '''
        from calibre.ebooks.oeb.base import urlnormalize
        from calibre.utils.fonts.utils import remove_embed_restriction
        from PyQt5.Qt import QByteArray, QRawFont

        font_warnings = set()
        processed = set()
        is_cff = {}
        for item in list(self.oeb.manifest):
            if not hasattr(item.data, 'cssRules'):
                continue
            remove = set()
            for i, rule in enumerate(item.data.cssRules):
                if rule.type == rule.FONT_FACE_RULE:
                    try:
                        s = rule.style
                        src = s.getProperty('src').propertyValue[0].uri
                    except:
                        continue
                    path = item.abshref(src)
                    ff = self.oeb.manifest.hrefs.get(urlnormalize(path), None)
                    if ff is None:
                        continue

                    raw = nraw = ff.data
                    if path not in processed:
                        processed.add(path)
                        try:
                            nraw = remove_embed_restriction(raw)
                        except:
                            continue
                        if nraw != raw:
                            ff.data = nraw
                            self.oeb.container.write(path, nraw)

                    if iswindows:
                        if path not in is_cff:
                            f = QRawFont(QByteArray(nraw), 12)
                            is_cff[path] = f.isValid() and len(
                                f.fontTable('head')) == 0
                        if is_cff[path]:
                            if path not in font_warnings:
                                font_warnings.add(path)
                                self.log.warn(
                                    'CFF OpenType fonts are not supported on windows, ignoring: %s'
                                    % path)
                            remove.add(i)
            for i in sorted(remove, reverse=True):
                item.data.cssRules.pop(i)
Пример #24
0
 def return_data_to_clients(self, client_id, data):
     try:
         for client_socket in self.clients:
             return_data_string = 'Client {} sent: {}'.format(client_id, data)
             data_byte_array =QByteArray()
             stream =QDataStream(data_byte_array, QIODevice.WriteOnly)
             stream.setVersion(QDataStream.Qt_5_9)
             stream.writeUInt32(0)
             stream.writeQString(return_data_string)
             client_socket.write(data_byte_array)
     except Exception as e:
         print(e)
Пример #25
0
    def __init__(self, parent=None):
        super().__init__(parent)
        self._ui = uic.loadUi('mc/other/ClearPrivateData.ui', self)
        self._ui.buttonBox.setFocus()
        self._ui.history.clicked.connect(self._historyClicked)
        self._ui.clear.clicked.connect(self._dialogAccepted)
        self._ui.optimizeDb.clicked.connect(self._optimizeDb)
        self._ui.editCookies.clicked.connect(self._showCookieManager)

        settings = Settings()
        settings.beginGroup('ClearPrivateData')
        self._restoreState(settings.value('state', QByteArray()))
        settings.endGroup()
Пример #26
0
 def loadResource(self, rtype, qurl):
     if self.base_url:
         if qurl.isRelative():
             qurl = self.base_url.resolved(qurl)
         if qurl.isLocalFile():
             path = qurl.toLocalFile()
             try:
                 with lopen(path, 'rb') as f:
                     data = f.read()
             except EnvironmentError:
                 pass
             else:
                 return QByteArray(data)
Пример #27
0
def encode_jpeg(file_path, quality=80):
    from calibre.utils.speedups import ReadOnlyFileBuffer
    quality = max(0, min(100, int(quality)))
    exe = get_exe_path('cjpeg')
    cmd = [exe] + '-optimize -progressive -maxmemory 100M -quality'.split() + [str(quality)]
    img = QImage()
    if not img.load(file_path):
        raise ValueError('%s is not a valid image file' % file_path)
    ba = QByteArray()
    buf = QBuffer(ba)
    buf.open(QBuffer.WriteOnly)
    if not img.save(buf, 'PPM'):
        raise ValueError('Failed to export image to PPM')
    return run_optimizer(file_path, cmd, as_filter=True, input_data=ReadOnlyFileBuffer(ba.data()))
Пример #28
0
    def load_fonts(self, lrf, load_substitutions=True):
        font_map = {}

        for font in lrf.font_map:
            fdata = QByteArray(lrf.font_map[font].data)
            id = QFontDatabase.addApplicationFontFromData(fdata)
            if id != -1:
                font_map[font] = [str(i) for i in QFontDatabase.applicationFontFamilies(id)][0]

        if load_substitutions:
            base = P('fonts/liberation/*.ttf')
            for f in glob.glob(base):
                QFontDatabase.addApplicationFont(f)

        self.font_loader = FontLoader(font_map, self.dpi)
Пример #29
0
    def save(self, save_proc):
        if self._text.isModified():
            self._text.setModified(False)
            if self._cfg.get("TextEditor/PlainText", 0):
                txt = str(self._text.toPlainText())
                if self._cfg.get("TextEditor/ReplaceTabWithSpace", 0):
                    cnt = self._cfg.get("TextEditor/CountSpaceInTab", 1)
                    txt = txt.replace("\t", " " * cnt)
                res = save_proc(txt)
            else:
                res = save_proc(str(self._text.toHtml(encoding=QByteArray())))
            if res is not None:
                self._text.setModified(True)

        self.change(self._text_edit_cursor)
Пример #30
0
def magick_to_qimage(img):
    fmt = get_pixel_map()
    # ImageMagick can only output raw data in some formats that can be
    # read into QImage directly, if the QImage format is not one of those, use
    # PNG
    if fmt in {'RGBA', 'BGRA'}:
        w, h = img.size
        img.depth = 8  # QImage expects 8bpp
        raw = img.export(fmt)
        i = QImage(raw, w, h, QImage.Format_ARGB32)
        del raw  # According to the documentation, raw is supposed to not be deleted, but it works, so make it explicit
        return i
    else:
        raw = img.export('PNG')
        return QImage.fromData(QByteArray(raw), 'PNG')