from PIL import ImageEnhance, ImageFilter, ImageChops from PyQt5.QtGui import QColor, QFont from PyQt5 import QtGui, QtCore, QtWidgets import os from component import Component from toolkit.frame import FramePainter, PaintColor class Component(Component): name = 'Title Text' version = '1.0.1' def widget(self, *args): super().widget(*args) self.title = 'Text' self.alignment = 1 self.titleFont = QFont() self.fontSize = self.height / 13.5 self.page.comboBox_textAlign.addItem("Left") self.page.comboBox_textAlign.addItem("Middle") self.page.comboBox_textAlign.addItem("Right") self.page.comboBox_textAlign.setCurrentIndex(int(self.alignment)) self.page.spinBox_fontSize.setValue(int(self.fontSize)) self.page.lineEdit_title.setText(self.title) self.page.pushButton_center.clicked.connect(self.centerXY) self.page.fontComboBox_titleFont.currentFontChanged.connect( self.update ) self.trackWidgets({ 'textColor': self.page.lineEdit_textColor, 'title': self.page.lineEdit_title, 'alignment': self.page.comboBox_textAlign, 'fontSize': self.page.spinBox_fontSize, 'xPosition': self.page.spinBox_xTextAlign, 'yPosition': self.page.spinBox_yTextAlign, 'fontStyle': self.page.comboBox_fontStyle, 'stroke': self.page.spinBox_stroke, 'strokeColor': self.page.lineEdit_strokeColor, 'shadow': self.page.checkBox_shadow, 'shadX': self.page.spinBox_shadX, 'shadY': self.page.spinBox_shadY, 'shadBlur': self.page.spinBox_shadBlur, }, colorWidgets={ 'textColor': self.page.pushButton_textColor, 'strokeColor': self.page.pushButton_strokeColor, }, relativeWidgets=[ 'xPosition', 'yPosition', 'fontSize', 'stroke', 'shadX', 'shadY', 'shadBlur' ]) self.centerXY() def update(self): self.titleFont = self.page.fontComboBox_titleFont.currentFont() if self.page.checkBox_shadow.isChecked(): self.page.label_shadX.setHidden(False) self.page.spinBox_shadX.setHidden(False) self.page.spinBox_shadY.setHidden(False) self.page.label_shadBlur.setHidden(False) self.page.spinBox_shadBlur.setHidden(False) else: self.page.label_shadX.setHidden(True) self.page.spinBox_shadX.setHidden(True) self.page.spinBox_shadY.setHidden(True) self.page.label_shadBlur.setHidden(True) self.page.spinBox_shadBlur.setHidden(True) def centerXY(self): self.setRelativeWidget('xPosition', 0.5) self.setRelativeWidget('yPosition', 0.521) def getXY(self): '''Returns true x, y after considering alignment settings''' fm = QtGui.QFontMetrics(self.titleFont) if self.alignment == 0: # Left x = int(self.xPosition) if self.alignment == 1: # Middle offset = int(fm.width(self.title)/2) x = self.xPosition - offset if self.alignment == 2: # Right offset = fm.width(self.title) x = self.xPosition - offset return x, self.yPosition def loadPreset(self, pr, *args): super().loadPreset(pr, *args) font = QFont() font.fromString(pr['titleFont']) self.page.fontComboBox_titleFont.setCurrentFont(font) def savePreset(self): saveValueStore = super().savePreset() saveValueStore['titleFont'] = self.titleFont.toString() return saveValueStore def previewRender(self): return self.addText(self.width, self.height) def properties(self): props = ['static'] if not self.title: props.append('error') return props def error(self): return "No text provided." def frameRender(self, frameNo): return self.addText(self.width, self.height) def addText(self, width, height): font = self.titleFont font.setPixelSize(self.fontSize) font.setStyle(QFont.StyleNormal) font.setWeight(QFont.Normal) font.setCapitalization(QFont.MixedCase) if self.fontStyle == 1: font.setWeight(QFont.DemiBold) if self.fontStyle == 2: font.setWeight(QFont.Bold) elif self.fontStyle == 3: font.setStyle(QFont.StyleItalic) elif self.fontStyle == 4: font.setWeight(QFont.Bold) font.setStyle(QFont.StyleItalic) elif self.fontStyle == 5: font.setStyle(QFont.StyleOblique) elif self.fontStyle == 6: font.setCapitalization(QFont.SmallCaps) image = FramePainter(width, height) x, y = self.getXY() if self.stroke > 0: outliner = QtGui.QPainterPathStroker() outliner.setWidth(self.stroke) path = QtGui.QPainterPath() if self.fontStyle == 6: # PathStroker ignores smallcaps so we need this weird hack path.addText(x, y, font, self.title[0]) fm = QtGui.QFontMetrics(font) newX = x + fm.width(self.title[0]) strokeFont = self.page.fontComboBox_titleFont.currentFont() strokeFont.setCapitalization(QFont.SmallCaps) strokeFont.setPixelSize(int((self.fontSize / 7) * 5)) strokeFont.setLetterSpacing(QFont.PercentageSpacing, 139) path.addText(newX, y, strokeFont, self.title[1:]) else: path.addText(x, y, font, self.title) path = outliner.createStroke(path) image.setPen(QtCore.Qt.NoPen) image.setBrush(PaintColor(*self.strokeColor)) image.drawPath(path) image.setFont(font) image.setPen(self.textColor) image.drawText(x, y, self.title) # turn QImage into Pillow frame frame = image.finalize() if self.shadow: shadImg = ImageEnhance.Contrast(frame).enhance(0.0) shadImg = shadImg.filter(ImageFilter.GaussianBlur(self.shadBlur)) shadImg = ImageChops.offset(shadImg, self.shadX, self.shadY) shadImg.paste(frame, box=(0, 0), mask=frame) frame = shadImg return frame def commandHelp(self): print('Enter a string to use as centred white text:') print(' "title=User Error"') print('Specify a text color:\n color=255,255,255') print('Set custom x, y position:\n x=500 y=500') def command(self, arg): if '=' in arg: key, arg = arg.split('=', 1) if key == 'color': self.page.lineEdit_textColor.setText(arg) return elif key == 'size': self.page.spinBox_fontSize.setValue(int(arg)) return elif key == 'x': self.page.spinBox_xTextAlign.setValue(int(arg)) return elif key == 'y': self.page.spinBox_yTextAlign.setValue(int(arg)) return elif key == 'title': self.page.lineEdit_title.setText(arg) return super().command(arg)