def dnd_get_image(md, image_exts=None): ''' Get the image in the QMimeData object md. :return: None, None if no image is found QPixmap, None if an image is found, the pixmap is guaranteed not null url, filename if a URL that points to an image is found ''' if md.hasImage(): for x in md.formats(): x = unicode_type(x) if x.startswith('image/'): cdata = bytes(md.data(x)) pmap = QPixmap() pmap.loadFromData(cdata) if not pmap.isNull(): return pmap, None break if md.hasFormat('application/octet-stream'): cdata = bytes(md.data('application/octet-stream')) pmap = QPixmap() pmap.loadFromData(cdata) if not pmap.isNull(): return pmap, None if image_exts is None: image_exts = image_extensions() # No image, look for an URL pointing to an image urls = urls_from_md(md) paths = [path_from_qurl(u) for u in urls] # First look for a local file images = [xi for xi in paths if posixpath.splitext(unquote(xi))[1][1:].lower() in image_exts] images = [xi for xi in images if os.path.exists(xi)] p = QPixmap() for path in images: try: with open(path, 'rb') as f: p.loadFromData(f.read()) except Exception: continue if not p.isNull(): return p, None # No local images, look for remote ones # First, see if this is from Firefox rurl, fname = get_firefox_rurl(md, image_exts) if rurl and fname: return rurl, fname # Look through all remaining URLs for remote_url, filename in remote_urls_from_qurl(urls, image_exts): return remote_url, filename return None, None
class CoverView(QWidget): def __init__(self, parent=None): QWidget.__init__(self, parent) self.current_pixmap_size = QSize(0, 0) self.pixmap = QPixmap() self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) def set_pixmap(self, data): self.pixmap.loadFromData(data) self.current_pixmap_size = self.pixmap.size() self.update() def paintEvent(self, event): if self.pixmap.isNull(): return canvas_size = self.rect() width = self.current_pixmap_size.width() extrax = canvas_size.width() - width if extrax < 0: extrax = 0 x = int(extrax / 2.0) height = self.current_pixmap_size.height() extray = canvas_size.height() - height if extray < 0: extray = 0 y = int(extray / 2.0) target = QRect(x, y, min(canvas_size.width(), width), min(canvas_size.height(), height)) p = QPainter(self) p.setRenderHints(QPainter.Antialiasing | QPainter.SmoothPixmapTransform) p.drawPixmap(target, self.pixmap.scaled(target.size(), Qt.KeepAspectRatio, Qt.SmoothTransformation)) p.end() def sizeHint(self): return QSize(300, 400)
def initialize_metadata_options(self): self.initialize_combos() self.author.editTextChanged.connect(self.deduce_author_sort) mi = self.db.get_metadata(self.book_id, index_is_id=True) self.title.setText(mi.title) self.publisher.show_initial_value(mi.publisher if mi.publisher else '') self.author_sort.setText(mi.author_sort if mi.author_sort else '') self.tags.setText(', '.join(mi.tags if mi.tags else [])) self.tags.update_items_cache(self.db.all_tags()) self.comment.html = comments_to_html(mi.comments) if mi.comments else '' self.series.show_initial_value(mi.series if mi.series else '') if mi.series_index is not None: try: self.series_index.setValue(mi.series_index) except: self.series_index.setValue(1.0) cover = self.db.cover(self.book_id, index_is_id=True) if cover: pm = QPixmap() pm.loadFromData(cover) if not pm.isNull(): self.cover.setPixmap(pm) self.cover_data = cover self.set_cover_tooltip(pm) else: self.cover.setPixmap(QPixmap(I('default_cover.png'))) self.cover.setToolTip(_('This book has no cover')) for x in ('author', 'series', 'publisher'): x = getattr(self, x) x.lineEdit().deselect()
def select_cover(self): files = choose_images(self, 'change cover dialog', _('Choose cover for ') + unicode(self.title.text())) if not files: return _file = files[0] if _file: _file = os.path.abspath(_file) if not os.access(_file, os.R_OK): d = error_dialog(self.parent(), _('Cannot read'), _('You do not have permission to read the file: ') + _file) d.exec_() return cf, cover = None, None try: cf = open(_file, "rb") cover = cf.read() except IOError as e: d = error_dialog(self.parent(), _('Error reading file'), _("<p>There was an error reading from file: <br /><b>") + _file + "</b></p><br />"+str(e)) d.exec_() if cover: pix = QPixmap() pix.loadFromData(cover) if pix.isNull(): d = error_dialog(self.parent(), _('Error reading file'), _file + _(" is not a valid picture")) d.exec_() else: self.cover_path.setText(_file) self.set_cover_tooltip(pix) self.cover.setPixmap(pix) self.cover_changed = True self.cpixmap = pix self.cover_data = cover
def load(data): p = QPixmap() p.loadFromData(bytes(data)) try: dpr = self.devicePixelRatioF() except AttributeError: dpr = self.devicePixelRatio() p.setDevicePixelRatio(dpr) if data and p.isNull(): p = self.failed_img return p
def __init__(self, parent, collection, item): QWidget.__init__(self, parent) self.setupUi(self) self.parent = parent self.item = item self.collection = collection self.header.setText(collection.title) self.description.setText(collection.description) icon = QPixmap(":/gui/pics/%s" % collection.icon) if icon.isNull(): icon = QPixmap(":/gui/pics/systemsettings.png") self.icon.setPixmap(icon)
def icon(self): if self._icon is None: self._icon = QIcon() url = places.favicon_url(self.place_id) if url is not None: f = QApplication.instance().disk_cache.data(QUrl(url)) if f is not None: with closing(f): raw = f.readAll() p = QPixmap() p.loadFromData(raw) if not p.isNull(): self._icon.addPixmap(p) return self._icon
def from_mi(self, mi): p = getattr(mi, 'cover', None) if p and os.path.exists(p): pmap = QPixmap() with open(p, 'rb') as f: pmap.loadFromData(f.read()) if not pmap.isNull(): self.pixmap = pmap self.update() self.changed.emit() return cd = getattr(mi, 'cover_data', (None, None)) if cd and cd[1]: pmap = QPixmap() pmap.loadFromData(cd[1]) if not pmap.isNull(): self.pixmap = pmap self.update() self.changed.emit() return self.pixmap = None self.update() self.changed.emit()
def update_cover(self, pmap=None, cdata=None): if pmap is None: pmap = QPixmap() pmap.loadFromData(cdata) if pmap.isNull(): return self.pixmap = pmap self.do_layout() self.update() self.update_tooltip(getattr(self.parent(), 'current_path', '')) if not config['disable_animations']: self.animation.start() id_ = self.data.get('id', None) if id_ is not None: self.cover_changed.emit(id_, cdata or pixmap_to_data(pmap))
def read_icon(handle, icon): must_use_qt() resource = win32api.LoadResource(handle, win32con.RT_ICON, icon.id) pixmap = QPixmap() pixmap.loadFromData(resource) hicon = None if pixmap.isNull(): if icon.width > 0 and icon.height > 0: hicon = ctypes.windll.user32.CreateIconFromResourceEx( resource, len(resource), True, 0x00030000, icon.width, icon.height, win32con.LR_DEFAULTCOLOR) else: hicon = win32gui.CreateIconFromResource(resource, True) pixmap = hicon_to_pixmap(hicon).copy() win32gui.DestroyIcon(hicon) return pixmap
def update_result(self, plugin_name, width, height, data): if plugin_name.endswith("}"): # multi cover plugin plugin_name = plugin_name.partition("{")[0] plugin = [plugin for plugin in self.plugin_map if plugin.name == plugin_name] if not plugin: return plugin = plugin[0] last_row = max(self.plugin_map[plugin]) pmap = QPixmap() pmap.loadFromData(data) if pmap.isNull(): return self.beginInsertRows(QModelIndex(), last_row, last_row) for rows in self.plugin_map.itervalues(): for i in xrange(len(rows)): if rows[i] >= last_row: rows[i] += 1 self.plugin_map[plugin].insert(-1, last_row) self.covers.insert(last_row, self.get_item(plugin_name, pmap, waiting=False)) self.endInsertRows() else: # single cover plugin idx = None for plugin, rows in self.plugin_map.iteritems(): if plugin.name == plugin_name: idx = rows[0] break if idx is None: return pmap = QPixmap() pmap.loadFromData(data) if pmap.isNull(): return self.covers[idx] = self.get_item(plugin_name, pmap, waiting=False) self.dataChanged.emit(self.index(idx), self.index(idx))
def onSelectionChange (self): warrior = self.model.selectedWarrior[self.model.first_selected] p = QPixmap(warrior.attribs['picture']) diff_V = p.height()/self.picture.height() diff_H = p.width()/self.picture.width() if not p.isNull(): if diff_V < diff_H: p = p.scaledToHeight(self.picture.height()) else: p = p.scaledToWidth(self.picture.width()) self.picture.setPixmap(p) self.Title.setText(warrior.name) self.faction_name.setText(warrior.faction().name) self.empire_name.setText(warrior.empire().name) self.royaume_name.setText(warrior.kingdom().name) self.groupe_name.setText(warrior.groupe().name)
def insert_cover(self): if not isinstance(self.cover_data, bytes): return item_path = os.path.join(self.tmp_path, 'cover.pdf') printer = get_pdf_printer(self.opts, output_file_name=item_path, for_comic=True) self.combine_queue.insert(0, item_path) p = QPixmap() p.loadFromData(self.cover_data) if not p.isNull(): painter = QPainter(printer) draw_image_page(printer, painter, p, preserve_aspect_ratio=self.opts.preserve_cover_aspect_ratio) painter.end() self.append_doc(item_path) printer.abort()
def cached_emblem(self, cache, name, raw_icon=None): ans = cache.get(name, False) if ans is not False: return ans sz = self.emblem_size ans = None if raw_icon is not None: ans = raw_icon.pixmap(sz, sz) elif name == ':ondevice': ans = QPixmap(I('ok.png')).scaled(sz, sz, transformMode=Qt.SmoothTransformation) elif name: pmap = QPixmap(os.path.join(config_dir, 'cc_icons', name)) if not pmap.isNull(): ans = pmap.scaled(sz, sz) cache[name] = ans return ans
def set_color(self): r, g, b = gprefs['cover_grid_color'] pal = QPalette() col = QColor(r, g, b) pal.setColor(pal.Base, col) tex = gprefs['cover_grid_texture'] if tex: from calibre.gui2.preferences.texture_chooser import texture_path path = texture_path(tex) if path: pm = QPixmap(path) if not pm.isNull(): val = pm.scaled(1, 1).toImage().pixel(0, 0) r, g, b = qRed(val), qGreen(val), qBlue(val) pal.setBrush(pal.Base, QBrush(pm)) dark = (r + g + b)/3.0 < 128 pal.setColor(pal.Text, QColor(Qt.white if dark else Qt.black)) self.setPalette(pal) self.delegate.highlight_color = pal.color(pal.Text)
def render_images(self, outpath, mi, items): printer = get_pdf_printer(self.opts, for_comic=True, output_file_name=outpath) printer.setDocName(mi.title) painter = QPainter(printer) painter.setRenderHints(QPainter.Antialiasing|QPainter.SmoothPixmapTransform) for i, imgpath in enumerate(items): self.log('Rendering image:', i) p = QPixmap() p.load(imgpath) if not p.isNull(): if i > 0: printer.newPage() draw_image_page(printer, painter, p) else: self.log.warn('Failed to load image', i) painter.end()
def data(self, role): if role == Qt.DisplayRole: return (self.title) if role == Qt.DecorationRole: if self.icon is None: icon = '%s.png'%self.urn[8:] p = QPixmap() if icon in self.favicons: try: with zipfile.ZipFile(self.zf, 'r') as zf: p.loadFromData(zf.read(self.favicons[icon])) except: pass if not p.isNull(): self.icon = (QIcon(p)) else: self.icon = self.default_icon return self.icon return None
def files_dropped_on_book(self, event, paths, cid=None, do_confirm=True): accept = False if self.gui.current_view() is not self.gui.library_view: return db = self.gui.library_view.model().db cover_changed = False current_idx = self.gui.library_view.currentIndex() if cid is None: if not current_idx.isValid(): return cid = db.id(current_idx.row()) if cid is None else cid formats = [] from calibre.gui2.dnd import image_extensions image_exts = set(image_extensions()) - set(tweaks['cover_drop_exclude']) for path in paths: ext = os.path.splitext(path)[1].lower() if ext: ext = ext[1:] if ext in image_exts: pmap = QPixmap() pmap.load(path) if not pmap.isNull(): accept = True db.set_cover(cid, pmap) cover_changed = True else: formats.append((ext, path)) accept = True if accept and event is not None: event.accept() if do_confirm and formats: if not confirm( _('You have dropped some files onto the book <b>%s</b>. This will' ' add or replace the files for this book. Do you want to proceed?') % db.title(cid, index_is_id=True), 'confirm_drop_on_book', parent=self.gui): formats = [] for ext, path in formats: db.add_format_with_hooks(cid, ext, path, index_is_id=True) if current_idx.isValid(): self.gui.library_view.model().current_changed(current_idx, current_idx) if cover_changed: self.gui.refresh_cover_browser()
def data(self, role): if role == Qt.DisplayRole: return (self.title) if role == Qt.DecorationRole: if self.icon is None: icon = '%s.png'%self.urn[8:] p = QPixmap() if icon in self.favicons: try: with zipfile.ZipFile(self.zf, 'r') as zf: p.loadFromData(zf.read(self.favicons[icon])) except Exception: pass if not p.isNull(): self.icon = (QIcon(p)) else: self.icon = self.default_icon return self.icon if role == Qt.UserRole: return self.urn
class ImagePopup(object): def __init__(self, parent): self.current_img = QPixmap() self.current_url = QUrl() self.parent = parent self.dialogs = [] def __call__(self): if self.current_img.isNull(): return d = ImageView(self.parent, self.current_img, self.current_url) self.dialogs.append(d) d.finished.connect(self.cleanup, type=Qt.QueuedConnection) d() def cleanup(self): for d in tuple(self.dialogs): if not d.isVisible(): self.dialogs.remove(d)
def dropEvent(self, event): event.setDropAction(Qt.CopyAction) md = event.mimeData() x, y = dnd_get_image(md) if x is not None: # We have an image, set cover event.accept() if y is None: # Local image self.handle_image_drop(x) else: # Remote files, use the first file d = DownloadDialog(x, y, self) d.start_download() if d.err is None: pmap = QPixmap() pmap.loadFromData(open(d.fpath, 'rb').read()) if not pmap.isNull(): self.handle_image_drop(pmap)
class ImagePopup(object): def __init__(self, parent): self.current_img = QPixmap() self.current_url = QUrl() self.parent = parent self.dialogs = [] def __call__(self): if self.current_img.isNull(): return d = ImageView(self.parent, self.current_img, self.current_url) self.dialogs.append(d) d.finished.connect(self.cleanup, type=Qt.QueuedConnection) d() def cleanup(self): for d in tuple(self.dialogs): if not d.isVisible(): self.dialogs.remove(d)
def dropEvent(self, event): event.setDropAction(Qt.CopyAction) md = event.mimeData() x, y = dnd_get_image(md) if x is not None: # We have an image, set cover event.accept() if y is None: # Local image self.handle_image_drop(x) else: # Remote files, use the first file d = DownloadDialog(x, y, self) d.start_download() if d.err is None: pmap = QPixmap() pmap.loadFromData(open(d.fpath, 'rb').read()) if not pmap.isNull(): self.handle_image_drop(pmap)
def insert_cover(self): if not isinstance(self.cover_data, bytes): return item_path = os.path.join(self.tmp_path, 'cover.pdf') printer = get_pdf_printer(self.opts, output_file_name=item_path, for_comic=True) self.combine_queue.insert(0, item_path) p = QPixmap() p.loadFromData(self.cover_data) if not p.isNull(): painter = QPainter(printer) draw_image_page( printer, painter, p, preserve_aspect_ratio=self.opts.preserve_cover_aspect_ratio) painter.end() self.append_doc(item_path) printer.abort()
class CoverView(QWidget): def __init__(self, parent=None): QWidget.__init__(self, parent) self.current_pixmap_size = QSize(0, 0) self.pixmap = QPixmap() self.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding) def set_pixmap(self, data): self.pixmap.loadFromData(data) self.current_pixmap_size = self.pixmap.size() self.update() def paintEvent(self, event): if self.pixmap.isNull(): return canvas_size = self.rect() width = self.current_pixmap_size.width() extrax = canvas_size.width() - width if extrax < 0: extrax = 0 x = int(extrax / 2.) height = self.current_pixmap_size.height() extray = canvas_size.height() - height if extray < 0: extray = 0 y = int(extray / 2.) target = QRect(x, y, min(canvas_size.width(), width), min(canvas_size.height(), height)) p = QPainter(self) p.setRenderHints(QPainter.RenderHint.Antialiasing | QPainter.RenderHint.SmoothPixmapTransform) p.drawPixmap( target, self.pixmap.scaled(target.size(), Qt.AspectRatioMode.KeepAspectRatio, Qt.TransformationMode.SmoothTransformation)) p.end() def sizeHint(self): return QSize(300, 400)
def select_cover(self): files = choose_images(self, 'change cover dialog', _('Choose cover for ') + str(self.title.text())) if not files: return _file = files[0] if _file: _file = os.path.abspath(_file) if not os.access(_file, os.R_OK): d = error_dialog( self.parent(), _('Cannot read'), _('You do not have permission to read the file: ') + _file) d.exec_() return cf, cover = None, None try: cf = open(_file, "rb") cover = cf.read() except IOError as e: d = error_dialog( self.parent(), _('Error reading file'), _("<p>There was an error reading from file: <br /><b>") + _file + "</b></p><br />" + str(e)) d.exec_() if cover: pix = QPixmap() pix.loadFromData(cover) pix.setDevicePixelRatio( getattr(self, 'devicePixelRatioF', self.devicePixelRatio)()) if pix.isNull(): d = error_dialog(self.parent(), _('Error reading file'), _file + _(" is not a valid picture")) d.exec_() else: self.cover_path.setText(_file) self.set_cover_tooltip(pix) self.cover.setPixmap(pix) self.cover_changed = True self.cpixmap = pix self.cover_data = cover
def render_images(self, outpath, mi, items): printer = get_pdf_printer(self.opts, for_comic=True, output_file_name=outpath) printer.setDocName(mi.title) painter = QPainter(printer) painter.setRenderHints(QPainter.Antialiasing | QPainter.SmoothPixmapTransform) for i, imgpath in enumerate(items): self.log('Rendering image:', i) p = QPixmap() p.load(imgpath) if not p.isNull(): if i > 0: printer.newPage() draw_image_page(printer, painter, p) else: self.log.warn('Failed to load image', i) painter.end()
def initialize_metadata_options(self): self.initialize_combos() self.author.editTextChanged.connect(self.deduce_author_sort) mi = self.db.get_metadata(self.book_id, index_is_id=True) self.title.setText(mi.title) self.publisher.show_initial_value(mi.publisher if mi.publisher else '') self.author_sort.setText(mi.author_sort if mi.author_sort else '') self.tags.setText(', '.join(mi.tags if mi.tags else [])) self.tags.update_items_cache(self.db.all_tags()) self.comment.html = comments_to_html( mi.comments) if mi.comments else '' self.series.show_initial_value(mi.series if mi.series else '') if mi.series_index is not None: try: self.series_index.setValue(mi.series_index) except: self.series_index.setValue(1.0) cover = self.db.cover(self.book_id, index_is_id=True) if cover: pm = QPixmap() pm.loadFromData(cover) if not pm.isNull(): pm.setDevicePixelRatio( getattr(self, 'devicePixelRatioF', self.devicePixelRatio)()) self.cover.setPixmap(pm) self.cover_data = cover self.set_cover_tooltip(pm) else: pm = QPixmap(I('default_cover.png')) pm.setDevicePixelRatio( getattr(self, 'devicePixelRatioF', self.devicePixelRatio)()) self.cover.setPixmap(pm) self.cover.setToolTip(_('This book has no cover')) for x in ('author', 'series', 'publisher'): x = getattr(self, x) x.lineEdit().deselect() self.series_changed()
def set_color(self): r, g, b = gprefs['cover_grid_color'] tex = gprefs['cover_grid_texture'] pal = self.palette() pal.setColor(pal.Base, QColor(r, g, b)) self.setPalette(pal) ss = '' if tex: from calibre.gui2.preferences.texture_chooser import texture_path path = texture_path(tex) if path: path = os.path.abspath(path).replace(os.sep, '/') ss += 'background-image: url({});'.format(path) ss += 'background-attachment: fixed;' pm = QPixmap(path) if not pm.isNull(): val = pm.scaled(1, 1).toImage().pixel(0, 0) r, g, b = qRed(val), qGreen(val), qBlue(val) dark = max(r, g, b) < 115 ss += 'color: {};'.format('white' if dark else 'black') self.delegate.highlight_color = QColor(Qt.white if dark else Qt.black) self.setStyleSheet('QListView {{ {} }}'.format(ss))
def dnd_get_image(md, image_exts=IMAGE_EXTENSIONS): ''' Get the image in the QMimeData object md. :return: None, None if no image is found QPixmap, None if an image is found, the pixmap is guaranteed not null url, filename if a URL that points to an image is found ''' if dnd_has_image(md): for x in md.formats(): x = unicode(x) if x.startswith('image/'): cdata = bytes(md.data(x)) pmap = QPixmap() pmap.loadFromData(cdata) if not pmap.isNull(): return pmap, None break # No image, look for a URL pointing to an image if md.hasUrls(): urls = [unicode(u.toString(QUrl.None)) for u in md.urls()]
def dump(self, items, out_stream, pdf_metadata): opts = self.opts page_size = get_page_size(self.opts) xdpi, ydpi = self.view.logicalDpiX(), self.view.logicalDpiY() def margin(which): val = getattr(opts, 'pdf_page_margin_' + which) if val == 0.0: val = getattr(opts, 'margin_' + which) return val ml, mr, mt, mb = map(margin, 'left right top bottom'.split()) # We cannot set the side margins in the webview as there is no right # margin for the last page (the margins are implemented with # -webkit-column-gap) self.doc = PdfDevice(out_stream, page_size=page_size, left_margin=ml, top_margin=0, right_margin=mr, bottom_margin=0, xdpi=xdpi, ydpi=ydpi, errors=self.log.error, debug=self.log.debug, compress=not opts.uncompressed_pdf, opts=opts, mark_links=opts.pdf_mark_links, page_margins=(ml, mr, mt, mb)) self.footer = opts.pdf_footer_template if self.footer: self.footer = self.footer.strip() if not self.footer and opts.pdf_page_numbers: self.footer = '<p style="text-align:center; text-indent: 0">_PAGENUM_</p>' self.header = opts.pdf_header_template if self.header: self.header = self.header.strip() min_margin = 1.5 * opts._final_base_font_size if self.footer and mb < min_margin: self.log.warn( 'Bottom margin is too small for footer, increasing it to %.1fpts' % min_margin) mb = min_margin if self.header and mt < min_margin: self.log.warn( 'Top margin is too small for header, increasing it to %.1fpts' % min_margin) mt = min_margin self.page.setViewportSize(QSize(self.doc.width(), self.doc.height())) self.render_queue = items self.total_items = len(items) mt, mb = map(self.doc.to_px, (mt, mb)) self.margin_top, self.margin_bottom = map(lambda x: int(floor(x)), (mt, mb)) self.painter = QPainter(self.doc) try: self.book_language = pdf_metadata.mi.languages[0] except Exception: self.book_language = 'eng' self.doc.set_metadata(title=pdf_metadata.title, author=pdf_metadata.author, tags=pdf_metadata.tags, mi=pdf_metadata.mi) self.doc_title = pdf_metadata.title self.doc_author = pdf_metadata.author self.painter.save() try: if self.cover_data is not None: p = QPixmap() try: p.loadFromData(self.cover_data) except TypeError: self.log.warn( 'This ebook does not have a raster cover, cannot generate cover for PDF' '. Cover type: %s' % type(self.cover_data)) if not p.isNull(): self.doc.init_page() draw_image_page(QRect(*self.doc.full_page_rect), self.painter, p, preserve_aspect_ratio=self.opts. preserve_cover_aspect_ratio) self.doc.end_page() finally: self.painter.restore() QTimer.singleShot(0, self.render_book) if self.loop.exec_() == 1: raise Exception('PDF Output failed, see log for details') if self.toc is not None and len(self.toc) > 0: self.doc.add_outline(self.toc) self.painter.end() if self.doc.errors_occurred: raise Exception('PDF Output failed, see log for details')
class ImageView(QWidget, ImageDropMixin): # {{{ BORDER_WIDTH = 1 cover_changed = pyqtSignal(object) def __init__(self, parent=None, show_size_pref_name=None, default_show_size=False): QWidget.__init__(self, parent) self.show_size_pref_name = ('show_size_on_cover_' + show_size_pref_name) if show_size_pref_name else None self._pixmap = QPixmap() self.setMinimumSize(QSize(150, 200)) ImageDropMixin.__init__(self) self.draw_border = True self.show_size = False if self.show_size_pref_name: self.show_size = gprefs.get(self.show_size_pref_name, default_show_size) def setPixmap(self, pixmap): if not isinstance(pixmap, QPixmap): raise TypeError('Must use a QPixmap') self._pixmap = pixmap self.updateGeometry() self.update() def build_context_menu(self): m = ImageDropMixin.build_context_menu(self) if self.show_size_pref_name: text = _('Hide size in corner') if self.show_size else _('Show size in corner') m.addAction(text, self.toggle_show_size) return m def toggle_show_size(self): self.show_size ^= True if self.show_size_pref_name: gprefs[self.show_size_pref_name] = self.show_size self.update() def pixmap(self): return self._pixmap def sizeHint(self): if self._pixmap.isNull(): return self.minimumSize() return self._pixmap.size() def paintEvent(self, event): QWidget.paintEvent(self, event) pmap = self._pixmap if pmap.isNull(): return w, h = pmap.width(), pmap.height() ow, oh = w, h cw, ch = self.rect().width(), self.rect().height() scaled, nw, nh = fit_image(w, h, cw, ch) if scaled: pmap = pmap.scaled(nw, nh, Qt.IgnoreAspectRatio, Qt.SmoothTransformation) w, h = pmap.width(), pmap.height() x = int(abs(cw - w)/2.) y = int(abs(ch - h)/2.) target = QRect(x, y, w, h) p = QPainter(self) p.setRenderHints(QPainter.Antialiasing | QPainter.SmoothPixmapTransform) p.drawPixmap(target, pmap) if self.draw_border: pen = QPen() pen.setWidth(self.BORDER_WIDTH) p.setPen(pen) p.drawRect(target) if self.show_size: sztgt = target.adjusted(0, 0, 0, -4) f = p.font() f.setBold(True) p.setFont(f) sz = u'\u00a0%d x %d\u00a0'%(ow, oh) flags = Qt.AlignBottom|Qt.AlignRight|Qt.TextSingleLine szrect = p.boundingRect(sztgt, flags, sz) p.fillRect(szrect.adjusted(0, 0, 0, 4), QColor(0, 0, 0, 200)) p.setPen(QPen(QColor(255,255,255))) p.drawText(sztgt, flags, sz) p.end()
def pixmap(self, thumbnail_height, entry): pmap = QPixmap(current_container().name_to_abspath(entry.name)) if entry.width > 0 and entry.height > 0 else QPixmap() scaled, width, height = fit_image(entry.width, entry.height, thumbnail_height, thumbnail_height) if scaled and not pmap.isNull(): pmap = pmap.scaled(width, height, transformMode=Qt.SmoothTransformation) return pmap
class DesktopNotification(QWidget): def __init__(self, setPosition=False): super().__init__(None) self._ui = uic.loadUi('mc/notifications/DesktopNotification.ui', self) self._settingPosition = setPosition self._dragPosition = QPoint() self._icon = QPixmap() self._heading = '' self._text = '' self._timeout = 6000 self._timer = QTimer(self) self.setAttribute(Qt.WA_DeleteOnClose) self.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint | Qt.X11BypassWindowManagerHint) self._timer.setSingleShot(True) self._timer.timeout.connect(self.close) if self._settingPosition: self.setCursor(Qt.OpenHandCursor) self._savedPos = None closedSignal = pyqtSignal() def setPixmap(self, icon): ''' @param: icon QPixmap ''' self._icon = icon def setHeading(self, heading): ''' @param: heading QString ''' self._heading = heading def setText(self, text): ''' @param: text QString ''' self._text = text def setTimeout(self, timeout): ''' @param: timeout int ''' self._timeout = timeout def show(self): self._ui.icon.setPixmap(self._icon) self._ui.icon.setVisible(not self._icon.isNull()) self._ui.heading.setText(self._heading) self._ui.text.setText(self._text) if self._settingPosition: self._timer.setInterval(self._timeout) self._timer.start() super().show() # private: # override def mousePressEvent(self, event): ''' @param: event QMouseEvent ''' if not self._settingPosition: self.close() return if event.buttons() == Qt.LeftButton: self._dragPosition = event.globalPos() - self.frameGeometry( ).topLeft() event.accept() def mouseMoveEvent(self, event): ''' @param event QMouseEvent ''' if event.buttons() & Qt.LeftButton: self.move(event.globalPos() - self._dragPosition) event.accept() def closeEvent(self, event): self.closedSignal.emit() self._savedPos = self.pos() super().closeEvent(event) def savedPos(self): if not self._savedPos: self._savedPos = self.pos() return self._savedPos
class FancyTabWidget(QWidget): # Values are persisted = only add to the end # enum Mode Mode_None = 0 Mode_LargeSidebar = 1 Mode_SmallSidebar = 2 Mode_Tabs = 3 Mode_IconOnlyTabs = 4 Mode_PlainSidebar = 5 def __init__(self, parent=None): super().__init__(parent) self._mode = self.Mode_None self._items = [] # QList<Item> self._tab_bar = None # QWidget self._stack = QStackedLayout() # QStackedLayout self._background_pixmap = QPixmap() self._side_widget = QWidget() # QWidget self._side_layout = QVBoxLayout() # QVBoxLayout self._top_layout = QVBoxLayout() # QVBoxLayout self._use_background = False # bool self._menu = None # QMenu self._proxy_style = FancyTabProxyStyle() # FancyTabProxyStyle self._side_layout.setSpacing(0) self._side_layout.setContentsMargins(0, 0, 0, 0) self._side_layout.addSpacerItem( QSpacerItem(0, 0, QSizePolicy.Fixed, QSizePolicy.Expanding)) self._side_widget.setLayout(self._side_layout) self._side_widget.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Expanding) self._top_layout.setSpacing(0) self._top_layout.setContentsMargins(0, 0, 0, 0) self._top_layout.addLayout(self._stack) main_layout = QHBoxLayout() main_layout.setContentsMargins(0, 0, 0, 0) main_layout.setSpacing(1) main_layout.addWidget(self._side_widget) main_layout.addLayout(self._top_layout) self.setLayout(main_layout) class Item: # enum Type Type_Tab = 0 Type_Spacer = 1 def __init__(self, icon, label): ''' @param: icon QIcon @param: label QString ''' self.type = self.Type_Tab # Type self.tab_label = label # QString self.tab_icon = icon # QIcon self.spacer_size = 0 def AddTab(self, tab, icon, label): ''' @param: tab QWidget @param: icon Qicon @param: label QString ''' self._stack.addWidget(tab) self._items.append(self.Item(icon, label)) def AddSpacer(self, size=40): self._items.append(self.Item(size)) def SetBackgroundPixmap(self, pixmap): ''' @param: pixmap QPixmap ''' self._background_pixmap = pixmap self.update() def AddBottomWidget(self, widget): ''' @param: widget QWidget ''' self._top_layout.addWidget(widget) def current_index(self): ''' @return: int ''' return self._stack.currentIndex() def mode(self): ''' @return: Mode ''' return self._mode def bgPixmap(self): ''' @return: QPixmap ''' return self._background_pixmap bgPixmap = pyqtProperty(QPixmap, bgPixmap, SetBackgroundPixmap) # public Q_SLOTS: def SetCurrentIndex(self, index): bar = self._tab_bar if isinstance(bar, FancyTabBar): bar.setCurrentIndex(index) elif isinstance(bar, QTabBar): bar.setCurrentIndex(index) else: self._stack.setCurrentIndex(index) def SetMode(self, mode): # Remove previous tab bar del self._tab_bar self._tab_bar = None self._use_background = False # Create new tab bar if mode == self.Mode_None: pass elif mode == self.Mode_LargeSidebar: bar = FancyTabBar(self) self._side_layout.insertWidget(0, bar) self._tab_bar = bar for item in self._items: if item.type == self.Item.Type_Spacer: bar.addSpacer(item.spacer_size) else: bar.addTab(item.tab_icon, item.tab_label) bar.setCurrentIndex(self._stack.currentIndex()) bar.currentChanged.connect(self._ShowWidget) self._use_background = True elif mode == self.Mode_Tabs: self._MakeTabBar(QTabBar.RoundedNorth, True, False, False) elif mode == self.Mode_IconOnlyTabs: self._MakeTabBar(QTabBar.RoundedNorth, False, True, False) elif mode == self.Mode_SmallSidebar: self._MakeTabBar(QTabBar.RoundedWest, True, True, True) self._use_background = True elif mode == self.Mode_PlainSidebar: self._MakeTabBar(QTabBar.RoundedWest, True, True, False) else: print('DEBUG: Unknown fancy tab mode %s' % mode) self._tab_bar.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred) self._mode = mode self.ModeChanged.emit(mode) self.update() # Q_SIGNALS: CurrentChanged = pyqtSignal(int) # index ModeChanged = pyqtSignal(int) # mode FancyTabWidget::Mode # protected: # override def paintEvent(self, event): ''' @param: event QPaintEvent ''' if not self._use_background: return painter = QPainter(self) rect = self._side_widget.rect().adjusted(0, 0, 1, 0) rect = self.style().visualRect(self.layoutDirection(), self.geometry(), rect) styleHelper.verticalGradient(painter, rect, rect) if not self._background_pixmap.isNull(): pixmap_rect = QRect(self._background_pixmap.rect()) pixmap_rect.moveTo(rect.topLeft()) while pixmap_rect.top() < rect.bottom(): source_rect = QRect(pixmap_rect.intersected(rect)) source_rect.moveTo(0, 0) painter.drawPixmap(pixmap_rect.topLeft(), self._background_pixmap, source_rect) pixmap_rect.moveTop(pixmap_rect.bottom() - 10) painter.setPen(styleHelper.borderColor()) painter.drawLine(rect.topRight(), rect.bottomRight()) # QColor light = styleHelper.sidebarHighlight() painter.setPen(light) painter.drawLine(rect.bottomLeft(), rect.bottomRight()) # override def contextMenuEvent(self, event): ''' @param: event QContextMenuEvent ''' pass # private Q_SLOTS: def _ShowWidget(self, index): self._stack.setCurrentIndex(index) self.CurrentChanged.emit(index) # private: def _MakeTabBar(self, shap, text, icons, fancy): ''' @param: shap QTabBar::Shap @param: text bool @param: icons bool @param: fancy bool ''' bar = QTabBar(self) bar.setShape(shap) bar.setDocumentMode(True) bar.setUsesScrollButtons(True) if shap == QTabBar.RoundedWest: bar.setIconSize(QSize(22, 22)) if fancy: bar.setStyle(self._proxy_style) if shap == QTabBar.RoundedNorth: self._top_layout.insertWidget(0, bar) else: self._side_layout.insertWidget(0, bar) # Item for item in self._items: if item.type != self.Item.Type_Tab: continue label = item.tab_label if shap == QTabBar.RoundedWest: label = QFontMetrics(self.font()).elidedText( label, Qt.ElideMiddle, 100) tab_id = -1 if icons and text: tab_id = bar.addTab(item.tab_icon, label) elif icons: tab_id = bar.addTab(item.tab_icon, '') elif text: tab_id = bar.addTab(label) bar.setTabToolTip(tab_id, item.tab_label) bar.setCurrentIndex(self._stack.currentIndex()) bar.currentChanged.connect(self._ShowWidget) self._tab_bar = bar def _AddMenuItem(self, mapper, group, text, mode): ''' @param: mapper QSignalMapper @param: group QActionGroup @param: text QString @param: mode Mode ''' # QAction action = group.addAction(text) action.setCheckable(True) mapper.setMapping(action, mode) action.triggered.connect(mapper.map) if mode == self._mode: action.setChecked(True)
def load(data): p = QPixmap() p.loadFromData(bytes(data)) if data and p.isNull(): p = self.failed_img return p
class ImageView(QWidget, ImageDropMixin): BORDER_WIDTH = 1 cover_changed = pyqtSignal(object) def __init__(self, parent=None, show_size_pref_name=None, default_show_size=False): QWidget.__init__(self, parent) self.show_size_pref_name = ( 'show_size_on_cover_' + show_size_pref_name) if show_size_pref_name else None self._pixmap = QPixmap() self.setMinimumSize(QSize(150, 200)) ImageDropMixin.__init__(self) self.draw_border = True self.show_size = False if self.show_size_pref_name: self.show_size = gprefs.get(self.show_size_pref_name, default_show_size) def setPixmap(self, pixmap): if not isinstance(pixmap, QPixmap): raise TypeError('Must use a QPixmap') self._pixmap = pixmap self.updateGeometry() self.update() def build_context_menu(self): m = ImageDropMixin.build_context_menu(self) if self.show_size_pref_name: text = _('Hide size in corner') if self.show_size else _( 'Show size in corner') m.addAction(text, self.toggle_show_size) return m def toggle_show_size(self): self.show_size ^= True if self.show_size_pref_name: gprefs[self.show_size_pref_name] = self.show_size self.update() def pixmap(self): return self._pixmap def sizeHint(self): if self._pixmap.isNull(): return self.minimumSize() return self._pixmap.size() def paintEvent(self, event): QWidget.paintEvent(self, event) pmap = self._pixmap if pmap.isNull(): return w, h = pmap.width(), pmap.height() ow, oh = w, h cw, ch = self.rect().width(), self.rect().height() scaled, nw, nh = fit_image(w, h, cw, ch) if scaled: pmap = pmap.scaled(int(nw * pmap.devicePixelRatio()), int(nh * pmap.devicePixelRatio()), Qt.IgnoreAspectRatio, Qt.SmoothTransformation) w, h = int(pmap.width() / pmap.devicePixelRatio()), int( pmap.height() / pmap.devicePixelRatio()) x = int(abs(cw - w) / 2) y = int(abs(ch - h) / 2) target = QRect(x, y, w, h) p = QPainter(self) p.setRenderHints(QPainter.Antialiasing | QPainter.SmoothPixmapTransform) p.drawPixmap(target, pmap) if self.draw_border: pen = QPen() pen.setWidth(self.BORDER_WIDTH) p.setPen(pen) p.drawRect(target) if self.show_size: draw_size(p, target, ow, oh) p.end()
def load(data): p = QPixmap() p.loadFromData(bytes(data)) if data and p.isNull(): p = self.failed_img return p
def pixmap(self, thumbnail_height, entry): pmap = QPixmap(current_container().name_to_abspath(entry.name)) if entry.width > 0 and entry.height > 0 else QPixmap() scaled, width, height = fit_image(entry.width, entry.height, thumbnail_height, thumbnail_height) if scaled and not pmap.isNull(): pmap = pmap.scaled(width, height, transformMode=Qt.SmoothTransformation) return pmap
class ImageView(QWidget, ImageDropMixin): # {{{ BORDER_WIDTH = 1 cover_changed = pyqtSignal(object) def __init__(self, parent=None, show_size_pref_name=None, default_show_size=False): QWidget.__init__(self, parent) self.show_size_pref_name = ( 'show_size_on_cover_' + show_size_pref_name) if show_size_pref_name else None self._pixmap = QPixmap() self.setMinimumSize(QSize(150, 200)) ImageDropMixin.__init__(self) self.draw_border = True self.show_size = False if self.show_size_pref_name: self.show_size = gprefs.get(self.show_size_pref_name, default_show_size) def setPixmap(self, pixmap): if not isinstance(pixmap, QPixmap): raise TypeError('Must use a QPixmap') self._pixmap = pixmap self.updateGeometry() self.update() def build_context_menu(self): m = ImageDropMixin.build_context_menu(self) if self.show_size_pref_name: text = _('Hide size in corner') if self.show_size else _( 'Show size in corner') m.addAction(text, self.toggle_show_size) return m def toggle_show_size(self): self.show_size ^= True if self.show_size_pref_name: gprefs[self.show_size_pref_name] = self.show_size self.update() def pixmap(self): return self._pixmap def sizeHint(self): if self._pixmap.isNull(): return self.minimumSize() return self._pixmap.size() def paintEvent(self, event): QWidget.paintEvent(self, event) pmap = self._pixmap if pmap.isNull(): return w, h = pmap.width(), pmap.height() ow, oh = w, h cw, ch = self.rect().width(), self.rect().height() scaled, nw, nh = fit_image(w, h, cw, ch) if scaled: pmap = pmap.scaled(nw, nh, Qt.IgnoreAspectRatio, Qt.SmoothTransformation) w, h = pmap.width(), pmap.height() x = int(abs(cw - w) / 2.) y = int(abs(ch - h) / 2.) target = QRect(x, y, w, h) p = QPainter(self) p.setRenderHints(QPainter.Antialiasing | QPainter.SmoothPixmapTransform) p.drawPixmap(target, pmap) if self.draw_border: pen = QPen() pen.setWidth(self.BORDER_WIDTH) p.setPen(pen) p.drawRect(target) if self.show_size: sztgt = target.adjusted(0, 0, 0, -4) f = p.font() f.setBold(True) p.setFont(f) sz = u'\u00a0%d x %d\u00a0' % (ow, oh) flags = Qt.AlignBottom | Qt.AlignRight | Qt.TextSingleLine szrect = p.boundingRect(sztgt, flags, sz) p.fillRect(szrect.adjusted(0, 0, 0, 4), QColor(0, 0, 0, 200)) p.setPen(QPen(QColor(255, 255, 255))) p.drawText(sztgt, flags, sz) p.end()
class TabIcon(QWidget): class Data: def __init__(self): self.framesCount = 0 self.animationInterval = 0 self.animationPixmap = QPixmap() self.audioPlayingPixmap = QPixmap() self.audioMutedPixmap = QPixmap() def __init__(self, parent): ''' @param parent QWidget ''' super().__init__(parent) self._tab = None # WebTab self._updateTimer = None # QTimer self._hideTimer = None # QTimer self._sitePixmap = QPixmap() self._currentFrame = 0 self._animationRunning = False self._audioIconDisplayed = False self._audioIconRect = QRect() self.setObjectName('tab-icon') self._updateTimer = QTimer(self) self._updateTimer.setInterval(self.data().animationInterval) self._updateTimer.timeout.connect(self._updateAnimationFrame) self._hideTimer = QTimer(self) self._hideTimer.setInterval(250) self._hideTimer.timeout.connect(self._hide) self.resize(16, 16) def setWebTab(self, tab): ''' @param: tab WebTab ''' self._tab = tab self._tab.webView().loadStarted.connect(self._showLoadingAnimation) #self._tab.webView().loadFinished.connect(self._hideLoadingAnimation) self._tab.webView().loadProgress.connect(self._hideLoadingAnimation) self._tab.webView().iconChanged.connect(self.updateIcon) self._tab.webView().backgroundActivityChanged.connect( lambda: self.update()) def pageChangedCb(page): ''' @param: page WebPage ''' page.recentlyAudibleChanged.connect(self._updateAudioIcon) pageChangedCb(self._tab.webView().page()) self._tab.webView().pageChanged.connect(pageChangedCb) self.updateIcon() def updateIcon(self): self._sitePixmap = self._tab.icon(True).pixmap(16) # allowNull if self._sitePixmap.isNull(): if self._tab.url().isEmpty() or self._tab.url().scheme( ) == const.APP_SCHEME: self._hide() else: self._hideTimer.start() else: self._show() self.update() _s_data = None def data(self): ''' @return: Data ''' if self._s_data is None: self._s_data = data = self.Data() data.animationInterval = 70 data.animationPixmap = QIcon(':/icons/other/loading.png').pixmap( 288, 16) data.framesCount = data.animationPixmap.width( ) / data.animationPixmap.height() data.audioPlayingPixmap = QIcon.fromTheme( 'audio-volume-high', QIcon(':/icons/other/audioplaying.svg')).pixmap(16) data.audioMutedPixmap = QIcon.fromTheme( 'audio-volume-muted', QIcon(':/icons/other/audiomuted.svg')).pixmap(16) return self._s_data # Q_SIGNALS resized = pyqtSignal() # private Q_SLOTS: def _showLoadingAnimation(self): self._currentFrame = 0 self._updateAnimationFrame() self._show() def _hideLoadingAnimation(self, progress): if progress == 100: self._animationRunning = False self._updateTimer.stop() self.updateIcon() def _updateAudioIcon(self, recentlyAudible): if self._tab.isMuted() or recentlyAudible: self._audioIconDisplayed = True self._show() else: self._audioIconDisplayed = False self._hide() self.update() def _updateAnimationFrame(self): if not self._animationRunning: self._updateTimer.start() self._animationRunning = True self.update() self._currentFrame = (self._currentFrame + 1) % self.data().framesCount # private: def _show(self): if not self._shouldBeVisible(): return self._hideTimer.stop() if self.isVisible() and self.width() == 16: return self.setFixedSize(16, max(self.minimumHeight(), 16)) self.resized.emit() super().show() def _hide(self): if self._shouldBeVisible(): return if self.isHidden() and self.width() == 1: return self.setFixedSize(1, max(self.minimumHeight(), 16)) self.resized.emit() super().hide() def _shouldBeVisible(self): return not self._sitePixmap.isNull() or self._animationRunning or \ self._audioIconDisplayed or (self._tab and self._tab.isPinned()) # override def event(self, event): ''' @param: event QEvent ''' if event.type() == QEvent.ToolTip: # QHelpEvent if self._audioIconDisplayed and self._audioIconRect.contains( event.pos()): QToolTip.showText( event.globalPos(), self._tab.isMuted() and _('Unmute Tab') or _('Mute Tab'), self) event.accept() return True return super().event(event) # override def paintEvent(self, event): ''' @param event QPaintEvent ''' p = QPainter(self) p.setRenderHint(QPainter.Antialiasing) size = 16 pixmapSize = round(size * self.data().animationPixmap.devicePixelRatioF()) # Center the pixmap in rect r = QRect(self.rect()) r.setX((r.width() - size) / 2) r.setY((r.height() - size) / 2) r.setWidth(size) r.setHeight(size) if self._animationRunning: p.drawPixmap( r, self.data().animationPixmap, QRect(self._currentFrame * pixmapSize, 0, pixmapSize, pixmapSize)) elif self._audioIconDisplayed and not self._tab.isPinned(): self._audioIconRect = QRect(r) p.drawPixmap( r, self._tab.isMuted() and self.data().audioMutedPixmap or self.data().audioPlayingPixmap) elif not self._sitePixmap.isNull(): p.drawPixmap(r, self._sitePixmap) elif self._tab and self._tab.isPinned(): p.drawPixmap(r, IconProvider.emptyWebIcon().pixmap(size)) # Draw audio icon on top of site icon for pinned tabs if not self._animationRunning and self._audioIconDisplayed and self._tab.isPinned( ): s = size - 4 r0 = QRect(self.width() - 4, 0, s, s) self._audioIconRect = r0 c = self.palette().color(QPalette.Window) c.setAlpha(180) p.setPen(c) p.setBrush(c) p.drawEllipse(r) p.drawPixmap( r, self._tab.isMuted() and self.data().audioMutedPixmap or self.data().audioPlayingPixmap) # Draw background activity indicator if self._tab and self._tab.isPinned() and self._tab.webView( ).backgroundActivity(): s = 5 # Background r1 = QRect(self.width() - s - 2, self.height() - s - 2, s + 2, s + 2) c1 = self.palette().color(QPalette.Window) c1.setAlpha(180) p.setPen(Qt.transparent) p.setBrush(c1) p.drawEllipse(r1) # Forground r2 = QRect(self.width() - s - 1, self.height() - s - 1, s, s) c2 = self.palette().color(QPalette.Text) p.setPen(Qt.transparent) p.setBrush(c2) p.drawEllipse(r2) # override def mousePressEvent(self, event): ''' @param event QMouseEvent ''' if self._audioIconDisplayed and event.button() == Qt.LeftButton and \ self._audioIconRect.contains(event.pos()): self._tab.toggleMuted() return super().mousePressEvent(event)
def dump(self, items, out_stream, pdf_metadata): opts = self.opts page_size = get_page_size(self.opts) xdpi, ydpi = self.view.logicalDpiX(), self.view.logicalDpiY() # We cannot set the side margins in the webview as there is no right # margin for the last page (the margins are implemented with # -webkit-column-gap) ml, mr = opts.margin_left, opts.margin_right self.doc = PdfDevice(out_stream, page_size=page_size, left_margin=ml, top_margin=0, right_margin=mr, bottom_margin=0, xdpi=xdpi, ydpi=ydpi, errors=self.log.error, debug=self.log.debug, compress=not opts.uncompressed_pdf, opts=opts, mark_links=opts.pdf_mark_links) self.footer = opts.pdf_footer_template if self.footer: self.footer = self.footer.strip() if not self.footer and opts.pdf_page_numbers: self.footer = '<p style="text-align:center; text-indent: 0">_PAGENUM_</p>' self.header = opts.pdf_header_template if self.header: self.header = self.header.strip() min_margin = 1.5 * opts._final_base_font_size if self.footer and opts.margin_bottom < min_margin: self.log.warn('Bottom margin is too small for footer, increasing it to %.1fpts' % min_margin) opts.margin_bottom = min_margin if self.header and opts.margin_top < min_margin: self.log.warn('Top margin is too small for header, increasing it to %.1fpts' % min_margin) opts.margin_top = min_margin self.page.setViewportSize(QSize(self.doc.width(), self.doc.height())) self.render_queue = items self.total_items = len(items) mt, mb = map(self.doc.to_px, (opts.margin_top, opts.margin_bottom)) self.margin_top, self.margin_bottom = map(lambda x:int(floor(x)), (mt, mb)) self.painter = QPainter(self.doc) self.doc.set_metadata(title=pdf_metadata.title, author=pdf_metadata.author, tags=pdf_metadata.tags, mi=pdf_metadata.mi) self.doc_title = pdf_metadata.title self.doc_author = pdf_metadata.author self.painter.save() try: if self.cover_data is not None: p = QPixmap() try: p.loadFromData(self.cover_data) except TypeError: self.log.warn('This ebook does not have a raster cover, cannot generate cover for PDF' '. Cover type: %s' % type(self.cover_data)) if not p.isNull(): self.doc.init_page() draw_image_page(QRect(*self.doc.full_page_rect), self.painter, p, preserve_aspect_ratio=self.opts.preserve_cover_aspect_ratio) self.doc.end_page() finally: self.painter.restore() QTimer.singleShot(0, self.render_book) if self.loop.exec_() == 1: raise Exception('PDF Output failed, see log for details') if self.toc is not None and len(self.toc) > 0: self.doc.add_outline(self.toc) self.painter.end() if self.doc.errors_occurred: raise Exception('PDF Output failed, see log for details')
class ImageView(QWidget, ImageDropMixin): BORDER_WIDTH = 1 cover_changed = pyqtSignal(object) def __init__(self, parent=None, show_size_pref_name=None, default_show_size=False): QWidget.__init__(self, parent) self.show_size_pref_name = ('show_size_on_cover_' + show_size_pref_name) if show_size_pref_name else None self._pixmap = QPixmap() self.setMinimumSize(QSize(150, 200)) ImageDropMixin.__init__(self) self.draw_border = True self.show_size = False if self.show_size_pref_name: self.show_size = gprefs.get(self.show_size_pref_name, default_show_size) def setPixmap(self, pixmap): if not isinstance(pixmap, QPixmap): raise TypeError('Must use a QPixmap') self._pixmap = pixmap self.updateGeometry() self.update() def build_context_menu(self): m = ImageDropMixin.build_context_menu(self) if self.show_size_pref_name: text = _('Hide size in corner') if self.show_size else _('Show size in corner') m.addAction(text, self.toggle_show_size) return m def toggle_show_size(self): self.show_size ^= True if self.show_size_pref_name: gprefs[self.show_size_pref_name] = self.show_size self.update() def pixmap(self): return self._pixmap def sizeHint(self): if self._pixmap.isNull(): return self.minimumSize() return self._pixmap.size() def paintEvent(self, event): QWidget.paintEvent(self, event) pmap = self._pixmap if pmap.isNull(): return w, h = pmap.width(), pmap.height() ow, oh = w, h cw, ch = self.rect().width(), self.rect().height() scaled, nw, nh = fit_image(w, h, cw, ch) if scaled: pmap = pmap.scaled(int(nw*pmap.devicePixelRatio()), int(nh*pmap.devicePixelRatio()), Qt.IgnoreAspectRatio, Qt.SmoothTransformation) w, h = int(pmap.width()/pmap.devicePixelRatio()), int(pmap.height()/pmap.devicePixelRatio()) x = int(abs(cw - w)/2.) y = int(abs(ch - h)/2.) target = QRect(x, y, w, h) p = QPainter(self) p.setRenderHints(QPainter.Antialiasing | QPainter.SmoothPixmapTransform) p.drawPixmap(target, pmap) if self.draw_border: pen = QPen() pen.setWidth(self.BORDER_WIDTH) p.setPen(pen) p.drawRect(target) if self.show_size: draw_size(p, target, ow, oh) p.end()
md.urls()] purls = [urlparse(u) for u in urls] # First look for a local file images = [u2p(xu) for xu in purls if xu.scheme in ('', 'file')] images = [xi for xi in images if posixpath.splitext(urllib.unquote(xi))[1][1:].lower() in image_exts] images = [xi for xi in images if os.path.exists(xi)] p = QPixmap() for path in images: try: with open(path, 'rb') as f: p.loadFromData(f.read()) except: continue if not p.isNull(): return p, None # No local images, look for remote ones # First, see if this is from Firefox rurl, fname = get_firefox_rurl(md, image_exts) if rurl and fname: return rurl, fname # Look through all remaining URLs remote_urls = [xu for xu in purls if xu.scheme in ('http', 'https', 'ftp') and posixpath.splitext(xu.path)[1][1:].lower() in image_exts] if remote_urls: rurl = remote_urls[0] fname = posixpath.basename(urllib.unquote(rurl.path))