def drawIconWithShadow(icon, rect, p, iconMode, radius, color, offset): cache = QPixmap() pixmapName = "icon {0} {1} {2}".format(icon.cacheKey(), iconMode, rect.height()) if not QPixmapCache.find(pixmapName, cache): px = icon.pixmap(rect.size()) cache = QPixmap(px.size() + QSize(radius * 2, radius * 2)) cache.fill(Qt.transparent) cachePainter = QPainter(cache) if iconMode == QIcon.Disabled: im = px.toImage().convertToFormat(QImage.Format_ARGB32) for y in range(im.height()): scanLine = im.scanLine(y) for x in range(im.width()): pixel = scanLine intensity = qGray(pixel) scanLine = qRgba(intensity, intensity, intensity, qAlpha(pixel)) scanLine += 1 px = QPixmap.fromImage(im) # Draw shadow tmp = QImage(px.size() + QSize(radius * 2, radius * 2 + 1), QImage.Format_ARGB32_Premultiplied) tmp.fill(Qt.transparent) tmpPainter = QPainter(tmp) tmpPainter.setCompositionMode(QPainter.CompositionMode_Source) tmpPainter.drawPixmap(QPoint(radius, radius), px) tmpPainter.end() # blur the alpha channel blurred = QImage(tmp.size(), QImage.Format_ARGB32_Premultiplied) blurred.fill(Qt.transparent) blurPainter = QPainter(blurred) # todo : blur image blurPainter.end() tmp = blurred # blacken the image tmpPainter.begin(tmp) tmpPainter.setCompositionMode(QPainter.CompositionMode_SourceIn) tmpPainter.fillRect(tmp.rect(), color) tmpPainter.end() tmpPainter.begin(tmp) tmpPainter.setCompositionMode(QPainter.CompositionMode_SourceIn) tmpPainter.fillRect(tmp.rect(), color) tmpPainter.end() # draw the blurred drop shadow... cachePainter.drawImage(QRect(0, 0, cache.rect().width(), cache.rect().height()), tmp) # Draw the actual pixmap... cachePainter.drawPixmap(QPoint(radius, radius) + offset, px) QPixmapCache.insert(pixmapName, cache) targetRect = cache.rect() targetRect.moveCenter(rect.center()) p.drawPixmap(targetRect.topLeft() - offset, cache)
def requestImage(self, name, rsize, size): """@reimp @public @param[in] providerId unicode unused @param[out] rsize QSize @param[in] size QSize @return QImage not None virtual QImage requestImage(const QString &id, QSize *size, const QSize &requestedSize) """ ret = QImage(rc.image_path(name)) if ret.isNull(): derror("failed to load image: '%s'" % name) elif ret.size() != size: ret = ( ret.scaled(size, Qt.KeepAspectRatio, Qt.SmoothTransformation) if not size.isEmpty() else ret.scaledToWidth( size.width(), Qt.SmoothTransformation) if size.width() > 0 else ret.scaledToHeight(size.height(), Qt.SmoothTransformation) if size.height() > 0 else ret) rsize.setWidth(ret.width()) rsize.setHeight(ret.height()) return ret
class CircuitItem(QGraphicsItem): """Graphical wrapper around the engine Circuit class.""" textH = 12 """Height of text.""" ioH = 20 """Height between to I/O pins.""" ioW = 15 """Length of I/O pins.""" radius = 10 """Radius of I/O pin heads.""" def __init__(self, circuit): super(CircuitItem, self).__init__() self.setFlag(QGraphicsItem.ItemIsMovable) self.setFlag(QGraphicsItem.ItemIsSelectable) self.setFlag(QGraphicsItem.ItemSendsGeometryChanges) imgDir = filePath('icons/') self.data = circuit """The real info. The class CircuitItem is just a graphical container around it. data is saved / loaded to / from file. """ self.image = QImage(imgDir + circuit.__class__.__name__ + '.png') """The graphical representation of our item on screen.""" if not self.image: self.image = QImage(imgDir + 'Default.png') self.showCategory = True self.showName = True """Is the item's name shown on screen?""" self.showCategory = False """Is the item's category (circuit class) shown on screen?""" self.name = QGraphicsSimpleTextItem(self) # that won't rotate when the PlugItem is rotated by the user. self.name.setFlag(QGraphicsItem.ItemIgnoresTransformations) self.name.setText(self.data.name) self.category = QGraphicsSimpleTextItem(self) self.category.setFlag(QGraphicsItem.ItemIgnoresTransformations) self.category.setText(self.data.category) self.setupPaint() def boundingRect(self): """Qt requires overloading this when overloading QGraphicsItem.""" W = 2 * self.radius + 2 * self.ioW + self.imgW ni = self.data.nb_inputs() no = self.data.nb_outputs() t = (1 - int(max(ni, no) / 2)) * self.ioH - self.radius / 2 b = (1 + int(max(ni, no) / 2)) * self.ioH + self.radius / 2 return ( QRectF(-self.ioW - self.radius, t, W, b - t) if max(ni, no) > 1 else QRectF(-self.ioW - self.radius, 0, W, self.image.height())) def handleAtPos(self, pos): """Is there an interactive handle where the mouse is? Return it.""" for i in range(self.nIn): if self.inputPaths[i].contains(pos): return self.data.inputList[i] for i in range(self.nOut): if self.outputPaths[i].contains(pos): return self.data.outputList[i] def itemChange(self, change, value): """Warning view it will soon have to correct pos.""" if change == QGraphicsItem.ItemPositionHasChanged: # Restart till we stop moving. self.scene().views()[0].timer.start() return QGraphicsItem.itemChange(self, change, value) def paint(self, painter, option, widget): """Draws the item.""" painter.setPen(QPen(QColor('black'), 2)) ni = self.data.nb_inputs() no = self.data.nb_outputs() for i in range(1 - int(ni / 2), 2 + int(ni / 2)): if i != 1 or ni % 2: painter.drawLine(-self.ioW, i * self.ioH, 0, i * self.ioH) for i in range(1 - int(no / 2), 2 + int(no / 2)): if i != 1 or no % 2: painter.drawLine( self.imgW, i * self.ioH, self.imgW + self.ioW, i * self.ioH) painter.drawImage(QRectF(0, 0, self.imgW, self.imgH), self.image) for i in range(ni): painter.drawPath(self.inputPaths[i]) painter.drawLine( 0, (1 - int(ni / 2)) * self.ioH, 0, (1 + int(ni / 2)) * self.ioH) for i in range(no): painter.drawPath(self.outputPaths[i]) painter.drawLine( self.imgW, (1 - int(no / 2)) * self.ioH, self.imgW, (1 + int(no / 2)) * self.ioH) # Default selection box doesn't work; simple reimplementation. if option.state & QStyle.State_Selected: pen = QPen(Qt.black, 1, Qt.DashLine) painter.setPen(pen) painter.drawRect(self.boundingRect()) def setCategoryVisibility(self, isVisible): """Show/Hide circuit category (mostly useful for user circuits).""" self.showCategory = isVisible self.setupPaint() def setNameVisibility(self, isVisible): """Shows/Hide the item name in the graphical view.""" self.showName = isVisible self.setupPaint() def setNbInputs(self, nb): """Add/Remove inputs (for logical gates).""" if nb > self.data.nb_inputs(): for x in range(nb - self.data.nb_inputs()): Plug(True, None, self.data) elif nb < self.data.nb_inputs(): for x in range(self.data.nb_inputs() - nb): self.data.remove_input(self.data.inputList[0]) self.setupPaint() def setupPaint(self): """Offscreen rather than onscreen redraw (few changes).""" self.nIn = self.data.nb_inputs() self.nOut = self.data.nb_outputs() # 3 sections with different heights must be aligned : self.imgH = self.image.size().height() # central (png image) self.imgW = self.image.size().width() self.inH = (self.nIn - 1) * self.ioH + 2 * self.radius # inputs self.outH = (self.nOut - 1) * self.ioH + 2 * self.radius # outputs # therefore we calculate a vertical offset for each section : self.maxH = max(self.imgH, self.inH, self.outH) self.imgOff = ( 0 if self.maxH == self.imgH else (self.maxH - self.imgH) / 2.) self.inOff = ( 0 if self.maxH == self.inH else (self.maxH - self.inH) / 2.) self.outOff = ( 0 if self.maxH == self.outH else (self.maxH - self.outH) / 2.) # i/o mouseover detection. Create once, use on each mouseMoveEvent. self.inputPaths = [] self.outputPaths = [] ni = self.data.nb_inputs() no = self.data.nb_outputs() for i in range(1 - int(ni / 2), 2 + int(ni / 2)): if i != 1 or ni % 2: path = QPainterPath() path.addEllipse( -self.ioW - self.radius, i * self.ioH - self.radius / 2, self.radius, self.radius) self.inputPaths.append(path) for i in range(1 - int(no / 2), 2 + int(no / 2)): if i != 1 or no % 2: path = QPainterPath() path.addEllipse( self.imgW + self.ioW, i * self.ioH - self.radius / 2, self.radius, self.radius) self.outputPaths.append(path) self.name.setVisible(self.showName) self.category.setVisible(self.showCategory) if self.showName or self.showCategory: br = self.mapToScene(self.boundingRect()) w = self.boundingRect().width() h = self.boundingRect().height() realX = min([i.x() for i in br]) realY = min([i.y() for i in br]) firstY = realY + (w if self.rotation() % 180 else h) + 1 secondY = firstY + self.textH if self.showName: self.name.setBrush(QColor('red')) self.name.setText(self.data.name) self.name.setPos(self.mapFromScene(realX, firstY)) if self.showCategory: self.category.setBrush(QColor('green')) self.category.setText( self.data.category if self.data.category else self.data.__class__.__name__) self.category.setPos(self.mapFromScene( realX, secondY if self.showName else firstY)) self.prepareGeometryChange() # Must be called (cf Qt doc) self.update() # Force onscreen redraw after changes.
from PySide.QtCore import QCoreApplication from PySide.QtGui import QImage if __name__ == "__main__": app = QCoreApplication([]) img = QImage("lenna.png") w, h = img.size().width(), img.size().width() for p in ((x, y) for x in range(w) for y in range(h)): colour = img.pixel(p[0], p[1]) # AARRGGBB r = (colour >> 16) & 0xFF g = (colour >> 8) & 0xFF b = colour & 0xFF avg = round((r + g + b) / 3) # Naïve method (no colour weighting) new_colour = 0xff000000 + (avg << 16) + (avg << 8) + avg img.setPixel(p[0], p[1], new_colour) img.save("output.png")
from PySide.QtCore import QCoreApplication from PySide.QtGui import QImage if __name__ == "__main__": app = QCoreApplication([]) img = QImage("lenna.png") w, h = img.size().width(), img.size().width() for p in ((x, y) for x in range(w) for y in range(h)): colour = img.pixel(p[0], p[1]) # AARRGGBB r = (colour >> 16) & 0xFF g = (colour >> 8) & 0xFF b = colour & 0xFF avg = round((r + g + b) / 3) # Naïve method (no colour weighting) new_colour = 0xff000000 + (avg << 16) + (avg << 8) + avg img.setPixel(p[0], p[1], new_colour) img.save("output.png")