aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortassaron2017-07-13 00:05:11 -0400
committertassaron2017-07-13 00:05:11 -0400
commit8811b699a9c2d6b78af1e2a332d3031aef73aec4 (patch)
treee62f318fb625c5c79314de2eb0ce4b7b93e7496c
parent2e37dafd7036973a315b525f131850a6fb6d0b35 (diff)
merge consecutive static components
-rw-r--r--src/components/color.py13
-rw-r--r--src/components/image.py16
-rw-r--r--src/components/original.py9
-rw-r--r--src/components/text.py21
-rw-r--r--src/components/video.py6
-rw-r--r--src/core.py2
-rw-r--r--src/frame.py21
-rw-r--r--src/mainwindow.py2
-rw-r--r--src/preview_thread.py38
-rw-r--r--src/video_thread.py27
10 files changed, 100 insertions, 55 deletions
diff --git a/src/components/color.py b/src/components/color.py
index 82b45b3..da3bcf9 100644
--- a/src/components/color.py
+++ b/src/components/color.py
@@ -15,6 +15,7 @@ class Component(Component):
def widget(self, parent):
self.parent = parent
+ self.settings = self.parent.core.settings
page = self.loadUi('color.ui')
self.color1 = (0, 0, 0)
@@ -42,9 +43,9 @@ class Component(Component):
page.spinBox_x.valueChanged.connect(self.update)
page.spinBox_y.valueChanged.connect(self.update)
page.spinBox_width.setValue(
- int(parent.settings.value("outputWidth")))
+ int(self.settings.value("outputWidth")))
page.spinBox_height.setValue(
- int(parent.settings.value("outputHeight")))
+ int(self.settings.value("outputHeight")))
page.lineEdit_color1.textChanged.connect(self.update)
page.lineEdit_color2.textChanged.connect(self.update)
@@ -113,16 +114,16 @@ class Component(Component):
super().update()
def previewRender(self, previewWorker):
- width = int(previewWorker.core.settings.value('outputWidth'))
- height = int(previewWorker.core.settings.value('outputHeight'))
+ width = int(self.settings.value('outputWidth'))
+ height = int(self.settings.value('outputHeight'))
return self.drawFrame(width, height)
def properties(self):
return ['static']
def frameRender(self, layerNo, frameNo):
- width = int(self.worker.core.settings.value('outputWidth'))
- height = int(self.worker.core.settings.value('outputHeight'))
+ width = int(self.settings.value('outputWidth'))
+ height = int(self.settings.value('outputHeight'))
return self.drawFrame(width, height)
def drawFrame(self, width, height):
diff --git a/src/components/image.py b/src/components/image.py
index 07abc3f..6465bc9 100644
--- a/src/components/image.py
+++ b/src/components/image.py
@@ -13,7 +13,7 @@ class Component(Component):
def widget(self, parent):
self.parent = parent
- self.settings = parent.settings
+ self.settings = self.parent.core.settings
page = self.loadUi('image.ui')
page.lineEdit_image.textChanged.connect(self.update)
@@ -42,24 +42,24 @@ class Component(Component):
super().update()
def previewRender(self, previewWorker):
- width = int(previewWorker.core.settings.value('outputWidth'))
- height = int(previewWorker.core.settings.value('outputHeight'))
+ width = int(self.settings.value('outputWidth'))
+ height = int(self.settings.value('outputHeight'))
return self.drawFrame(width, height)
def properties(self):
props = ['static']
- if not os.path.exists(self.imagePath):
+ if self.imagePath and not os.path.exists(self.imagePath):
props.append('error')
return props
def error(self):
if not os.path.exists(self.imagePath):
- return "The image path selected on " \
- "layer %s no longer exists!" % str(self.compPos)
+ return "The image selected on " \
+ "layer %s does not exist!" % str(self.compPos)
def frameRender(self, layerNo, frameNo):
- width = int(self.worker.core.settings.value('outputWidth'))
- height = int(self.worker.core.settings.value('outputHeight'))
+ width = int(self.settings.value('outputWidth'))
+ height = int(self.settings.value('outputHeight'))
return self.drawFrame(width, height)
def drawFrame(self, width, height):
diff --git a/src/components/original.py b/src/components/original.py
index 638095d..3599c30 100644
--- a/src/components/original.py
+++ b/src/components/original.py
@@ -21,6 +21,7 @@ class Component(Component):
def widget(self, parent):
self.parent = parent
+ self.settings = self.parent.core.settings
self.visColor = (255, 255, 255)
self.scale = 20
self.y = 0
@@ -76,8 +77,8 @@ class Component(Component):
def previewRender(self, previewWorker):
spectrum = numpy.fromfunction(
lambda x: float(self.scale)/2500*(x-128)**2, (255,), dtype="int16")
- width = int(previewWorker.core.settings.value('outputWidth'))
- height = int(previewWorker.core.settings.value('outputHeight'))
+ width = int(self.settings.value('outputWidth'))
+ height = int(self.settings.value('outputHeight'))
return self.drawBars(
width, height, spectrum, self.visColor, self.layout
)
@@ -88,8 +89,8 @@ class Component(Component):
self.smoothConstantUp = 0.8
self.lastSpectrum = None
self.spectrumArray = {}
- self.width = int(self.worker.core.settings.value('outputWidth'))
- self.height = int(self.worker.core.settings.value('outputHeight'))
+ self.width = int(self.settings.value('outputWidth'))
+ self.height = int(self.settings.value('outputHeight'))
for i in range(0, len(self.completeAudioArray), self.sampleSize):
if self.canceled:
diff --git a/src/components/text.py b/src/components/text.py
index ed50064..4435b80 100644
--- a/src/components/text.py
+++ b/src/components/text.py
@@ -17,10 +17,11 @@ class Component(Component):
self.titleFont = QFont()
def widget(self, parent):
- height = int(parent.settings.value('outputHeight'))
- width = int(parent.settings.value('outputWidth'))
-
self.parent = parent
+ self.settings = self.parent.core.settings
+ height = int(self.settings.value('outputHeight'))
+ width = int(self.settings.value('outputWidth'))
+
self.textColor = (255, 255, 255)
self.title = 'Text'
self.alignment = 1
@@ -78,12 +79,12 @@ class Component(Component):
x = int(self.xPosition)
if self.alignment == 1: # Middle
- offset = fm.width(self.title)/2
- x = int(self.xPosition - offset)
+ offset = int(fm.width(self.title)/2)
+ x = self.xPosition - offset
if self.alignment == 2: # Right
offset = fm.width(self.title)
- x = int(self.xPosition - offset)
+ x = self.xPosition - offset
return x, self.yPosition
def loadPreset(self, pr, presetName=None):
@@ -115,16 +116,16 @@ class Component(Component):
}
def previewRender(self, previewWorker):
- width = int(previewWorker.core.settings.value('outputWidth'))
- height = int(previewWorker.core.settings.value('outputHeight'))
+ width = int(self.settings.value('outputWidth'))
+ height = int(self.settings.value('outputHeight'))
return self.addText(width, height)
def properties(self):
return ['static']
def frameRender(self, layerNo, frameNo):
- width = int(self.worker.core.settings.value('outputWidth'))
- height = int(self.worker.core.settings.value('outputHeight'))
+ width = int(self.settings.value('outputWidth'))
+ height = int(self.settings.value('outputHeight'))
return self.addText(width, height)
def addText(self, width, height):
diff --git a/src/components/video.py b/src/components/video.py
index 5303e3a..49bd145 100644
--- a/src/components/video.py
+++ b/src/components/video.py
@@ -158,14 +158,14 @@ class Component(Component):
if self.useAudio:
# props.append('audio')
pass
- if not os.path.exists(self.videoPath):
+ if self.videoPath and not os.path.exists(self.videoPath):
props.append('error')
return props
def error(self):
if not os.path.exists(self.videoPath):
- return "The video path selected on " \
- "layer %s no longer exists!" % str(self.compPos)
+ return "The video selected on " \
+ "layer %s does not exist!" % str(self.compPos)
def audio(self):
return (self.videoPath, {})
diff --git a/src/core.py b/src/core.py
index 450e43b..64f55eb 100644
--- a/src/core.py
+++ b/src/core.py
@@ -11,6 +11,7 @@ from importlib import import_module
from PyQt5.QtCore import QStandardPaths
import toolkit
+from frame import Frame
class Core:
@@ -20,6 +21,7 @@ class Core:
opens projects and presets, and stores settings/paths to data.
'''
def __init__(self):
+ Frame.core = self
self.dataDir = QStandardPaths.writableLocation(
QStandardPaths.AppConfigLocation
)
diff --git a/src/frame.py b/src/frame.py
index c066cdb..cddb611 100644
--- a/src/frame.py
+++ b/src/frame.py
@@ -5,6 +5,11 @@ from PyQt5 import QtGui
from PIL import Image
from PIL.ImageQt import ImageQt
import sys
+import os
+
+
+class Frame:
+ '''Controller class for all frames.'''
class FramePainter(QtGui.QPainter):
@@ -43,5 +48,19 @@ def FloodFrame(width, height, RgbaTuple):
def BlankFrame(width, height):
- '''The base frame used by each component to start drawing'''
+ '''The base frame used by each component to start drawing.'''
return FloodFrame(width, height, (0, 0, 0, 0))
+
+
+def Checkerboard(width, height):
+ '''
+ A checkerboard to represent transparency to the user.
+ TODO: Would be cool to generate this image with numpy instead.
+ '''
+ image = FloodFrame(1920, 1080, (0, 0, 0, 0))
+ image.paste(Image.open(
+ os.path.join(Frame.core.wd, "background.png")),
+ (0, 0)
+ )
+ image = image.resize((width, height))
+ return image
diff --git a/src/mainwindow.py b/src/mainwindow.py
index d21ba0a..771b6b8 100644
--- a/src/mainwindow.py
+++ b/src/mainwindow.py
@@ -306,6 +306,7 @@ class MainWindow(QtWidgets.QMainWindow):
QtWidgets.QShortcut("Ctrl+A", self.window, self.openSaveProjectDialog)
QtWidgets.QShortcut("Ctrl+O", self.window, self.openOpenProjectDialog)
QtWidgets.QShortcut("Ctrl+N", self.window, self.createNewProject)
+ QtWidgets.QShortcut("Ctrl+Alt+Shift+R", self.window, self.drawPreview)
QtWidgets.QShortcut(
"Ctrl+T", self.window,
@@ -585,6 +586,7 @@ class MainWindow(QtWidgets.QMainWindow):
self.autosave(force)
self.updateWindowTitle()
+ @QtCore.pyqtSlot(QtGui.QImage)
def showPreviewImage(self, image):
self.previewWindow.changePixmap(image)
diff --git a/src/preview_thread.py b/src/preview_thread.py
index fb3b792..4ffb7f6 100644
--- a/src/preview_thread.py
+++ b/src/preview_thread.py
@@ -10,12 +10,12 @@ import core
from queue import Queue, Empty
import os
-from frame import FloodFrame
+from frame import Checkerboard
class Worker(QtCore.QObject):
- imageCreated = pyqtSignal(['QImage'])
+ imageCreated = pyqtSignal(QtGui.QImage)
error = pyqtSignal()
def __init__(self, parent=None, queue=None):
@@ -24,14 +24,12 @@ class Worker(QtCore.QObject):
parent.processTask.connect(self.process)
self.parent = parent
self.core = self.parent.core
+ self.settings = self.parent.core.settings
self.queue = queue
- self.width = int(self.core.settings.value('outputWidth'))
- self.height = int(self.core.settings.value('outputHeight'))
- # create checkerboard background to represent transparency
- self.background = FloodFrame(1920, 1080, (0, 0, 0, 0))
- self.background.paste(Image.open(os.path.join(
- self.core.wd, "background.png")))
+ width = int(self.settings.value('outputWidth'))
+ height = int(self.settings.value('outputHeight'))
+ self.background = Checkerboard(width, height)
@pyqtSlot(list)
def createPreviewImage(self, components):
@@ -42,6 +40,8 @@ class Worker(QtCore.QObject):
@pyqtSlot()
def process(self):
+ width = int(self.settings.value('outputWidth'))
+ height = int(self.settings.value('outputHeight'))
try:
nextPreviewInformation = self.queue.get(block=False)
while self.queue.qsize() >= 2:
@@ -50,22 +50,27 @@ class Worker(QtCore.QObject):
except Empty:
continue
- if self.background.width != self.width:
- self.background = self.background.resize(
- (self.width, self.height))
+ if self.background.width != width \
+ or self.background.height != height:
+ self.background = Checkerboard(width, height)
+
frame = self.background.copy()
components = nextPreviewInformation["components"]
for component in reversed(components):
try:
+ newFrame = component.previewRender(self)
frame = Image.alpha_composite(
- frame, component.previewRender(self)
+ frame, newFrame
)
except ValueError as e:
errMsg = "Bad frame returned by %s's preview renderer. " \
- "%s. This is a fatal error." % (
- str(component), str(e).capitalize()
+ "%s. New frame size was %s*%s; should be %s*%s. " \
+ "This is a fatal error." % (
+ str(component), str(e).capitalize(),
+ newFrame.width, newFrame.height,
+ width, height
)
print(errMsg)
self.parent.showMessage(
@@ -76,8 +81,11 @@ class Worker(QtCore.QObject):
)
self.error.emit()
break
+ except RuntimeError as e:
+ print(e)
else:
- self.imageCreated.emit(QtGui.QImage(ImageQt(frame)))
+ self.frame = ImageQt(frame)
+ self.imageCreated.emit(QtGui.QImage(self.frame))
except Empty:
True
diff --git a/src/video_thread.py b/src/video_thread.py
index b00d512..f736013 100644
--- a/src/video_thread.py
+++ b/src/video_thread.py
@@ -20,7 +20,7 @@ import signal
import core
from toolkit import openPipe, checkOutput
-from frame import FloodFrame
+from frame import Checkerboard
class Worker(QtCore.QObject):
@@ -56,8 +56,10 @@ class Worker(QtCore.QObject):
frame = None
for compNo, comp in reversed(list(enumerate(self.components))):
- if compNo in self.staticComponents and \
- self.staticComponents[compNo] is not None:
+ if compNo in self.staticComponents:
+ if self.staticComponents[compNo] is None:
+ # this layer was merged into a following layer
+ continue
# static component
if frame is None: # bottom-most layer
frame = self.staticComponents[compNo]
@@ -93,10 +95,7 @@ class Worker(QtCore.QObject):
Grabs frames from the previewQueue, adds them to the checkerboard
and emits a final QImage to the MainWindow for the live preview
'''
- background = FloodFrame(1920, 1080, (0, 0, 0, 0))
- background.paste(Image.open(os.path.join(
- self.core.wd, "background.png")))
- background = background.resize((self.width, self.height))
+ background = Checkerboard(self.width, self.height)
while not self.stopped:
audioI, frame = self.previewQueue.get()
@@ -164,8 +163,20 @@ class Worker(QtCore.QObject):
self.staticComponents[compNo] = \
comp.frameRender(compNo, 0).copy()
+ # Merge consecutive static component frames together
+ for compNo in range(len(self.components), 0, -1):
+ if compNo not in self.staticComponents \
+ or compNo - 1 not in self.staticComponents:
+ continue
+ self.staticComponents[compNo - 1] = Image.alpha_composite(
+ self.staticComponents.pop(compNo),
+ self.staticComponents[compNo - 1]
+ )
+ self.staticComponents[compNo] = None
+
ffmpegCommand = self.core.createFfmpegCommand(inputFile, outputFile)
- print(ffmpegCommand)
+ print('###### FFMPEG COMMAND ######\n %s' % " ".join(ffmpegCommand))
+ print('###### -------------- ######')
self.out_pipe = openPipe(
ffmpegCommand, stdin=sp.PIPE, stdout=sys.stdout, stderr=sys.stdout
)