def render_cover(self, book_id): if self.ignore_render_requests.is_set(): return tcdata, timestamp = self.thumbnail_cache[book_id] use_cache = False if timestamp is None: # Not in cache has_cover, cdata, timestamp = self.model( ).db.new_api.cover_or_cache(book_id, 0) else: has_cover, cdata, timestamp = self.model( ).db.new_api.cover_or_cache(book_id, timestamp) if has_cover and cdata is None: # The cached cover is fresh cdata = tcdata use_cache = True if has_cover: p = QImage() p.loadFromData(cdata, CACHE_FORMAT if cdata is tcdata else 'JPEG') if p.isNull() and cdata is tcdata: # Invalid image in cache self.thumbnail_cache.invalidate((book_id, )) self.update_item.emit(book_id) return cdata = None if p.isNull() else p if not use_cache: # cache is stale if cdata is not None: width, height = p.width(), p.height() scaled, nwidth, nheight = fit_image( width, height, self.delegate.cover_size.width(), self.delegate.cover_size.height()) if scaled: if self.ignore_render_requests.is_set(): return p = p.scaled(nwidth, nheight, Qt.IgnoreAspectRatio, Qt.SmoothTransformation) cdata = p # update cache if cdata is None: self.thumbnail_cache.invalidate((book_id, )) else: try: self.thumbnail_cache.insert(book_id, timestamp, image_to_data(cdata)) except EncodeError as err: self.thumbnail_cache.invalidate((book_id, )) prints(err) except Exception: import traceback traceback.print_exc() elif tcdata is not None: # Cover was removed, but it exists in cache, remove from cache self.thumbnail_cache.invalidate((book_id, )) self.delegate.cover_cache.set(book_id, cdata) self.update_item.emit(book_id)
def render_cover(self, book_id): if self.ignore_render_requests.is_set(): return tcdata, timestamp = self.thumbnail_cache[book_id] use_cache = False if timestamp is None: # Not in cache has_cover, cdata, timestamp = self.model().db.new_api.cover_or_cache(book_id, 0) else: has_cover, cdata, timestamp = self.model().db.new_api.cover_or_cache(book_id, timestamp) if has_cover and cdata is None: # The cached cover is fresh cdata = tcdata use_cache = True if has_cover: p = QImage() p.loadFromData(cdata, CACHE_FORMAT if cdata is tcdata else "JPEG") if p.isNull() and cdata is tcdata: # Invalid image in cache self.thumbnail_cache.invalidate((book_id,)) self.update_item.emit(book_id) return cdata = None if p.isNull() else p if not use_cache: # cache is stale if cdata is not None: width, height = p.width(), p.height() scaled, nwidth, nheight = fit_image( width, height, self.delegate.cover_size.width(), self.delegate.cover_size.height() ) if scaled: if self.ignore_render_requests.is_set(): return p = p.scaled(nwidth, nheight, Qt.IgnoreAspectRatio, Qt.SmoothTransformation) cdata = p # update cache if cdata is None: self.thumbnail_cache.invalidate((book_id,)) else: try: self.thumbnail_cache.insert(book_id, timestamp, image_to_data(cdata)) except EncodeError as err: self.thumbnail_cache.invalidate((book_id,)) prints(err) except Exception: import traceback traceback.print_exc() elif tcdata is not None: # Cover was removed, but it exists in cache, remove from cache self.thumbnail_cache.invalidate((book_id,)) self.delegate.cover_cache.set(book_id, cdata) self.update_item.emit(book_id)
def paste(self): clipboard = QApplication.clipboard() md = clipboard.mimeData() if md.hasImage(): img = QImage(md.imageData()) if not img.isNull(): self.undo_stack.push(Replace(img, _('Paste image'), self)) else: error_dialog(self, _('No image'), _( 'No image available in the clipboard'), show=True)
def __init__(self, dirpath): pictureflow.FlowImages.__init__(self) self.images = [] self.captions = [] self.subtitles = [] for f in os.listdir(dirpath): f = os.path.join(dirpath, f) img = QImage(f) if not img.isNull(): self.images.append(img) self.captions.append(os.path.basename(f)) self.subtitles.append('%d bytes'%os.stat(f).st_size)
def __init__(self, dirpath): pictureflow.FlowImages.__init__(self) self.images = [] self.captions = [] self.subtitles = [] for f in os.listdir(dirpath): f = os.path.join(dirpath, f) img = QImage(f) if not img.isNull(): self.images.append(img) self.captions.append(os.path.basename(f)) self.subtitles.append('%d bytes' % os.stat(f).st_size)
def render_cover(self, book_id): cdata = self.model().db.new_api.cover(book_id) if self.ignore_render_requests.is_set(): return if cdata is not None: p = QImage() p.loadFromData(cdata) cdata = None if not p.isNull(): width, height = p.width(), p.height() scaled, nwidth, nheight = fit_image(width, height, self.delegate.cover_size.width(), self.delegate.cover_size.height()) if scaled: if self.ignore_render_requests.is_set(): return p = p.scaled(nwidth, nheight, Qt.IgnoreAspectRatio, Qt.SmoothTransformation) cdata = p self.delegate.cover_cache.set(book_id, cdata) self.update_item.emit(book_id)
def __call__(self, container): from PyQt4.Qt import QImage from calibre.gui2 import pixmap_to_data ext = container.mime_map[self.name].split('/')[-1].upper() if ext == 'JPG': ext = 'JPEG' if ext not in ('PNG', 'JPEG', 'GIF'): return False with container.open(self.name, 'r+b') as f: raw = f.read() i = QImage() i.loadFromData(raw) if i.isNull(): return False raw = pixmap_to_data(i, format=ext, quality=95) f.seek(0) f.truncate() f.write(raw) return True
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.undo_stack.push(Replace(x.toImage(), _('Drop image'), self)) else: d = DownloadDialog(x, y, self.gui) d.start_download() if d.err is None: with open(d.fpath, 'rb') as f: img = QImage() img.loadFromData(f.read()) if not img.isNull(): self.undo_stack.push(Replace(img, _('Drop image'), self)) event.accept()
class VoivoiShow(Slide): ''' VoiVoi Slideshow class for displaying images from voivoi database ''' imgList = list() eventID = 0 mostRecent = datetime.fromtimestamp(0) host = "127.0.0.1" user = "******" passwd = "secret" db = "voivoi" def __init__(self, parent = None): ''' Constructor ''' super(VoivoiShow, self).__init__(parent) #self.setStyleSheet("background: #000;") self.splashscreen = QImage("res/splashscreen.jpg") #print(self.splashscreen.isNull()) if not self.splashscreen.isNull(): self.imgList.append(self.splashscreen) self.imageLabel = QLabel() self.imageLabel.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored) self.imageLabel.setParent(self) self.httpPool = urllib3.PoolManager() self.slideIterator = 0 self.timer.timeout.connect(self.nextImage) self.updateTimer = QTimer() self.updateTimer.timeout.connect(self.updateImages) self.mostRecent = datetime.fromtimestamp(0) self.layout = QHBoxLayout() self.layout.setMargin(0) self.layout.addWidget(self.imageLabel) self.layout.setAlignment(self.imageLabel, Qt.AlignHCenter) self.setLayout(self.layout) self.voivoifont = QFont("Helvetica", 48) self.voivoifont.setBold(True) def setup(self, host, user, passwd, event_id, database="voivoi", slideInterval=10, updateInterval=60): ''' setup the slide for it's display routine ''' self.host = host print(self.host) self.user = user self.passwd = passwd self.interval = slideInterval self.updateInterval = updateInterval self.db=database self.eventID = event_id self.updateImages() def updateImages(self, buffer_limit=20): try: db_connection = pymysql.connect(self.host, self.user, self.passwd, self.db) except: print("Database connection not available") return sqlquery = "SELECT `categoryOrder`, `userID`, `dayID`, `comment`, `timestamp`, `eventID` FROM `pictures` WHERE `eventID`>=" + str(self.eventID) + " AND `timestamp`>'" + str(self.mostRecent) + "' ORDER BY `timestamp` ASC" #print(sqlquery) try: with db_connection.cursor() as cursor: cursor.execute(sqlquery) result = cursor.fetchall() for entry in result: print(entry[4]) #print(self.mostRecent) if entry[4] > self.mostRecent: if entry[0] == 0: print("BREAKING") continue self.mostRecent = entry[4] image_url = "http://voivoi.eventfive.de/events/" + str(entry[5]) + "/uploads/" + str(entry[0]) + "_" + str(entry[1]) + "_" + str(entry[2]) + ".jpg" req = self.httpPool.request('GET',image_url) if req.status == 200: data = req.data print("Newer file downloaded") might_be_image = QImage() if might_be_image.loadFromData(data) : #print("URL is valid") self.drawOverlay(might_be_image, entry) if len(self.imgList) > buffer_limit-1: #TODO: change behaviour to iteration over fixed list, to prevent jumps self.imgList.pop(1) self.imgList.append(might_be_image) finally: print("Update done, closing connection") db_connection.close() def drawOverlay(self, image, entry): #establish painter painter = QPainter() #set adjustment factor corner_fac = 0.037 category_fac = 0.27 text_fac = 0.03 #load images category = QImage("res/" + str(entry[0]) + ".png") upperLeft = QImage("res/upperLeft.png") upperRight = QImage("res/upperRight.png") lowerLeft = QImage("res/lowerLeft.png") lowerRight = QImage("res/lowerRight.png") #adjust overlays to image size category = category.scaledToHeight(category_fac*image.height(), Qt.SmoothTransformation) upperLeft = upperLeft.scaledToHeight(corner_fac*image.height(), Qt.SmoothTransformation) upperRight = upperRight.scaledToHeight(corner_fac*image.height(), Qt.SmoothTransformation) lowerLeft = lowerLeft.scaledToHeight(corner_fac*image.height(), Qt.SmoothTransformation) lowerRight = lowerRight.scaledToHeight(corner_fac*image.height(), Qt.SmoothTransformation) self.voivoifont.setPixelSize(text_fac*image.height()) # create size calculator for font size_calculator = QFontMetrics(self.voivoifont) text_width = size_calculator.boundingRect(entry[3]).width() text_height = size_calculator.height() #define text-boundary margin_hor = 0.01*image.width() max_text_bound = QRect(margin_hor,image.height()-image.height()/3, image.width()-image.width()/3, image.height()/3) #format text for display #text_elided = size_calculator.elidedText(entry[3].upper(), Qt.ElideRight, max_text_bound.width(), Qt.TextWordWrap) text_upper = entry[3].upper() text_bounds = size_calculator.boundingRect(max_text_bound, Qt.TextWordWrap, text_upper) text_width = text_bounds.width() text_height = text_bounds.height() #calculate positions margin_ver = 0.018*image.height() #margin_hor = 0.01*image.width() lower_bound = image.height()-margin_ver upper_bound = lower_bound-lowerRight.height()-text_height-upperLeft.height() #begin painting on image painter.begin(image) #first paint category painter.drawImage(image.width()-category.width()-margin_hor, margin_ver, category) # now background rectangle and corners + comment if len(text_upper) > 0: painter.fillRect(margin_hor, upper_bound , lowerLeft.width()+text_width+lowerRight.width(), lowerLeft.height()+text_height+upperLeft.height(), QColor(qRgb(255,255,255))) painter.drawImage(margin_hor, lower_bound-lowerLeft.height(), lowerLeft) painter.drawImage(margin_hor, upper_bound, upperLeft) painter.drawImage(margin_hor+lowerLeft.width()+text_width, upper_bound, upperRight) painter.drawImage(margin_hor+lowerLeft.width()+text_width,lower_bound-lowerRight.height(), lowerRight) # write text to prepared rectangle painter.setPen(QColor(qRgb(17,195,159))) painter.setFont(self.voivoifont) #print(text_upper) painter.drawText(margin_hor+lowerLeft.width(),image.height()-lowerRight.height()-margin_ver-text_height, text_width, text_height, Qt.TextWordWrap, text_upper) painter.end() def run(self): ''' run the widgets display routine ''' self.timer.start(self.interval*1000) self.updateTimer.start(self.updateInterval*1000) self.nextImage() def nextImage(self): ''' take image from list and scale it to height of parent widget (which should be QMainWindow). Then generate a pixmap from the scaled image and display it on a QLabel''' if len(self.imgList) > 0: image = self.imgList[self.slideIterator%len(self.imgList)] else: return #print("IMAGE SIZE AFTER: " + str(image.size())) currImage = QPixmap.fromImage(image.scaledToHeight(self.parentWidget().height(), Qt.SmoothTransformation)) self.imageLabel.setPixmap(currImage) self.slideIterator += 1 def stop(self): Slide.stop(self) self.timer.stop() def shutdown(self): qWarning("Shutting down Slideshow-Module, this will purge all loaded images! \nTo pause, use stop() instead") Slide.shutdown(self) self.timer.stop() self.imgList.clear()
def rescale(self, qt=True): from calibre.utils.magick.draw import Image is_image_collection = getattr(self.opts, 'is_image_collection', False) if is_image_collection: page_width, page_height = self.opts.dest.comic_screen_size else: page_width, page_height = self.opts.dest.width, self.opts.dest.height page_width -= (self.opts.margin_left + self.opts.margin_right) * self.opts.dest.dpi/72. page_height -= (self.opts.margin_top + self.opts.margin_bottom) * self.opts.dest.dpi/72. for item in self.oeb.manifest: if item.media_type.startswith('image'): ext = item.media_type.split('/')[-1].upper() if ext == 'JPG': ext = 'JPEG' if ext not in ('PNG', 'JPEG', 'GIF'): ext = 'JPEG' raw = item.data if hasattr(raw, 'xpath') or not raw: # Probably an svg image continue try: img = Image() img.load(raw) except: continue width, height = img.size try: if self.check_colorspaces and img.colorspace == 'CMYKColorspace': # We cannot do an imagemagick conversion of CMYK to RGB as # ImageMagick inverts colors if you just set the colorspace # to rgb. See for example: https://bugs.launchpad.net/bugs/1246710 from PyQt4.Qt import QImage from calibre.gui2 import pixmap_to_data qimg = QImage() qimg.loadFromData(raw) if not qimg.isNull(): raw = item.data = pixmap_to_data(qimg, format=ext, quality=95) img = Image() img.load(raw) self.log.warn( 'The image %s is in the CMYK colorspace, converting it ' 'to RGB as Adobe Digital Editions cannot display CMYK' % item.href) else: self.log.warn( 'The image %s is in the CMYK colorspace, you should convert' ' it to sRGB as Adobe Digital Editions cannot render CMYK' % item.href) except Exception: pass scaled, new_width, new_height = fit_image(width, height, page_width, page_height) if scaled: new_width = max(1, new_width) new_height = max(1, new_height) self.log('Rescaling image from %dx%d to %dx%d'%( width, height, new_width, new_height), item.href) try: img.size = (new_width, new_height) data = img.export(ext.lower()) except KeyboardInterrupt: raise except: self.log.exception('Failed to rescale image') else: item.data = data item.unload_data_from_memory()
class GLButton(Action, GLFrame): def __init__(self, parent, x=0, y=0, width=None, height=None, img=None, text=None, togglable=False, imgoff=None, action=None, params=None): Action.__init__(self, action, params) GLFrame.__init__(self, parent, x, y, width, height) self.img = img self.setText(text) self.textColor = QColor(0, 0, 0) self.togglable = togglable self.toggled = False self.imgoff = imgoff self.focus = False self.enabled = True self.__initialized__ = False def setText(self, text): self.__text = text self.__computeTextPosition() def geometryChangedEvent(self): self.__computeTextPosition() def actionEvent(self): if self.togglable: self.toggled = not self.toggled def __computeTextPosition(self): if not self.__text is None: qf = QFontMetrics(self.parent.font()) self.__textx = self.x + (self.width - qf.width(self.__text)) / 2 self.__texty = self.y + qf.ascent() + (self.height - qf.height()) / 2 def __del__(self): self.parent.deleteTexture(self.textureId) if self.imgoff: self.parent.deleteTexture(self.textureOffId) def init(self): if not self.__initialized__: self.__initialized__ = True if self.img: self.imgV = QImage(self.img) assert not self.imgV.isNull() if self.width is None: self.width = self.imgV.width() if self.height is None: self.height = self.imgV.height() self.textureId = self.importTexture(self.imgV) if self.imgoff: self.imgoffV = QImage(self.imgoff) self.textureOffId = self.importTexture(self.imgoffV) self.__defaulttoggled = self.toggled self.__defaultenabled = self.enabled else: self.toggled = self.__defaulttoggled self.enabled = self.__defaultenabled def importTexture(self, img): return self.parent.bindTexture(img) def draw(self): if self.visible: glDisable(GL_LIGHTING) glEnable(GL_BLEND) glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) self.parent.startScreenCoordinatesSystem() glLineWidth(2) glDisable(GL_LIGHTING) glPolygonMode(GL_FRONT_AND_BACK, GL_LINE) if not self.enabled: glColor4f(0.5, 0.5, 0.5, 1.0) else: glColor4f(0, 0, 0, 1.0) self.drawBox() glPolygonMode(GL_FRONT_AND_BACK, GL_FILL) if not self.enabled: glColor4f(1.0, 1.0, 1.0, 0.2) elif self.focus: glColor4f(1.0, 1.0, 1.0, 0.6) else: glColor4f(1.0, 1.0, 1.0, 0.4) self.drawBox() if self.img: glTranslatef(0, 0, -0.05) glEnable(GL_TEXTURE_2D) if not self.toggled and self.enabled: glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE) glBindTexture(GL_TEXTURE_2D, self.textureId) else: if self.imgoff: glBindTexture(GL_TEXTURE_2D, self.textureOffId) else: if not self.toggled: glColor4f(1, 1, 1, 0.7) else: if self.enabled: glColor4f(0.2, 0.2, 0.2, 0.5) else: glColor4f(0.2, 0.2, 0.2, 0.3) glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE) glBindTexture(GL_TEXTURE_2D, self.textureId) glMatrixMode(GL_TEXTURE) glLoadIdentity() self.drawTexBox() glDisable(GL_TEXTURE_2D) glTranslatef(0, 0, 0.05) glLineWidth(1) if not self.__text is None: glColor4f(self.textColor.redF(), self.textColor.greenF(), self.textColor.blueF(), self.textColor.alphaF()) self.parent.drawText(self.__textx, self.__texty, self.__text) glEnable(GL_LIGHTING) self.parent.stopScreenCoordinatesSystem() def mousePressEvent(self, event): if self.enabled and self.visible and self.containspos(event.pos()): return True return False def mouseMoveEvent(self, event): if self.enabled and self.visible and self.containspos(event.pos()): self.parent.setFocusWidget(self) return True return False def mouseReleaseEvent(self, event): if self.enabled and self.visible and self.containspos(event.pos()): self.parent.selectedButton = None self.applyAction() return True return False