Example #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)
Example #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
Example #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
Example #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
Example #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
Example #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)
Example #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())))
Example #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
Example #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)
Example #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
Example #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
Example #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
Example #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())
Example #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)
Example #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 = {}
Example #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
Example #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()
Example #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)
Example #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)
Example #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)
Example #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
Example #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)
Example #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)
Example #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()
Example #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)
Example #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()))
Example #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)
Example #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)
Example #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')