various bugfixes, blankFrame method for components
don't crash from broken project files or nonexistent videopaths, and shareable common paths in core.py
This commit is contained in:
parent
8603fa12e3
commit
c05efc73ee
|
@ -1,4 +1,5 @@
|
||||||
from PyQt4 import QtGui, QtCore
|
from PyQt4 import QtGui, QtCore
|
||||||
|
from PIL import Image
|
||||||
|
|
||||||
|
|
||||||
class Component(QtCore.QObject):
|
class Component(QtCore.QObject):
|
||||||
|
@ -45,6 +46,9 @@ class Component(QtCore.QObject):
|
||||||
for var, value in kwargs.items():
|
for var, value in kwargs.items():
|
||||||
exec('self.%s = value' % var)
|
exec('self.%s = value' % var)
|
||||||
|
|
||||||
|
def blankFrame(self, width, height):
|
||||||
|
return Image.new("RGBA", (width, height), (0, 0, 0, 0))
|
||||||
|
|
||||||
def pickColor(self):
|
def pickColor(self):
|
||||||
dialog = QtGui.QColorDialog()
|
dialog = QtGui.QColorDialog()
|
||||||
dialog.setOption(QtGui.QColorDialog.ShowAlphaChannel, True)
|
dialog.setOption(QtGui.QColorDialog.ShowAlphaChannel, True)
|
||||||
|
|
|
@ -71,7 +71,7 @@ class Component(__base__.Component):
|
||||||
|
|
||||||
def drawFrame(self, width, height):
|
def drawFrame(self, width, height):
|
||||||
r, g, b = self.color1
|
r, g, b = self.color1
|
||||||
return Image.new("RGBA", (width, height), (r, g, b, 255))
|
return self.blankFrame(width, height)
|
||||||
|
|
||||||
def loadPreset(self, pr, presetName=None):
|
def loadPreset(self, pr, presetName=None):
|
||||||
super().loadPreset(pr, presetName)
|
super().loadPreset(pr, presetName)
|
||||||
|
|
|
@ -38,6 +38,7 @@ class Component(__base__.Component):
|
||||||
super().update()
|
super().update()
|
||||||
|
|
||||||
def previewRender(self, previewWorker):
|
def previewRender(self, previewWorker):
|
||||||
|
self.imageFormats = previewWorker.core.imageFormats
|
||||||
width = int(previewWorker.core.settings.value('outputWidth'))
|
width = int(previewWorker.core.settings.value('outputWidth'))
|
||||||
height = int(previewWorker.core.settings.value('outputHeight'))
|
height = int(previewWorker.core.settings.value('outputHeight'))
|
||||||
return self.drawFrame(width, height)
|
return self.drawFrame(width, height)
|
||||||
|
@ -52,7 +53,7 @@ class Component(__base__.Component):
|
||||||
return self.drawFrame(width, height)
|
return self.drawFrame(width, height)
|
||||||
|
|
||||||
def drawFrame(self, width, height):
|
def drawFrame(self, width, height):
|
||||||
frame = Image.new("RGBA", (width, height), (0, 0, 0, 0))
|
frame = self.blankFrame(width, height)
|
||||||
if self.imagePath and os.path.exists(self.imagePath):
|
if self.imagePath and os.path.exists(self.imagePath):
|
||||||
image = Image.open(self.imagePath)
|
image = Image.open(self.imagePath)
|
||||||
if self.stretched and image.size != (width, height):
|
if self.stretched and image.size != (width, height):
|
||||||
|
@ -85,7 +86,8 @@ class Component(__base__.Component):
|
||||||
def pickImage(self):
|
def pickImage(self):
|
||||||
imgDir = self.settings.value("backgroundDir", os.path.expanduser("~"))
|
imgDir = self.settings.value("backgroundDir", os.path.expanduser("~"))
|
||||||
filename = QtGui.QFileDialog.getOpenFileName(
|
filename = QtGui.QFileDialog.getOpenFileName(
|
||||||
self.page, "Choose Image", imgDir, "Image Files (*.jpg *.png)")
|
self.page, "Choose Image", imgDir,
|
||||||
|
"Image Files (%s)" % " ".join(self.imageFormats))
|
||||||
if filename:
|
if filename:
|
||||||
self.settings.setValue("backgroundDir", os.path.dirname(filename))
|
self.settings.setValue("backgroundDir", os.path.dirname(filename))
|
||||||
self.page.lineEdit_image.setText(filename)
|
self.page.lineEdit_image.setText(filename)
|
||||||
|
|
|
@ -230,7 +230,7 @@
|
||||||
<number>10</number>
|
<number>10</number>
|
||||||
</property>
|
</property>
|
||||||
<property name="maximum">
|
<property name="maximum">
|
||||||
<number>200</number>
|
<number>400</number>
|
||||||
</property>
|
</property>
|
||||||
<property name="value">
|
<property name="value">
|
||||||
<number>100</number>
|
<number>100</number>
|
||||||
|
|
|
@ -145,7 +145,7 @@ class Component(__base__.Component):
|
||||||
bF = width / 64
|
bF = width / 64
|
||||||
bH = bF / 2
|
bH = bF / 2
|
||||||
bQ = bF / 4
|
bQ = bF / 4
|
||||||
imTop = Image.new("RGBA", (width, height), (0, 0, 0, 0))
|
imTop = self.blankFrame(width, height)
|
||||||
draw = ImageDraw.Draw(imTop)
|
draw = ImageDraw.Draw(imTop)
|
||||||
r, g, b = color
|
r, g, b = color
|
||||||
color2 = (r, g, b, 125)
|
color2 = (r, g, b, 125)
|
||||||
|
@ -163,7 +163,7 @@ class Component(__base__.Component):
|
||||||
|
|
||||||
imBottom = imTop.transpose(Image.FLIP_TOP_BOTTOM)
|
imBottom = imTop.transpose(Image.FLIP_TOP_BOTTOM)
|
||||||
|
|
||||||
im = Image.new("RGBA", (width, height), (0, 0, 0, 0))
|
im = self.blankFrame(width, height)
|
||||||
|
|
||||||
if layout == 0:
|
if layout == 0:
|
||||||
y = 0 - int(height/100*43)
|
y = 0 - int(height/100*43)
|
||||||
|
|
|
@ -126,7 +126,7 @@ class Component(__base__.Component):
|
||||||
|
|
||||||
def addText(self, width, height):
|
def addText(self, width, height):
|
||||||
x, y = self.getXY()
|
x, y = self.getXY()
|
||||||
im = Image.new("RGBA", (width, height), (0, 0, 0, 0))
|
im = self.blankFrame(width, height)
|
||||||
image = ImageQt(im)
|
image = ImageQt(im)
|
||||||
|
|
||||||
painter = QPainter(image)
|
painter = QPainter(image)
|
||||||
|
|
|
@ -128,12 +128,13 @@ class Component(__base__.Component):
|
||||||
super().update()
|
super().update()
|
||||||
|
|
||||||
def previewRender(self, previewWorker):
|
def previewRender(self, previewWorker):
|
||||||
|
self.videoFormats = previewWorker.core.videoFormats
|
||||||
width = int(previewWorker.core.settings.value('outputWidth'))
|
width = int(previewWorker.core.settings.value('outputWidth'))
|
||||||
height = int(previewWorker.core.settings.value('outputHeight'))
|
height = int(previewWorker.core.settings.value('outputHeight'))
|
||||||
self.updateChunksize(width, height)
|
self.updateChunksize(width, height)
|
||||||
frame = self.getPreviewFrame(width, height)
|
frame = self.getPreviewFrame(width, height)
|
||||||
if not frame:
|
if not frame:
|
||||||
return Image.new("RGBA", (width, height), (0, 0, 0, 0))
|
return self.blankFrame(width, height)
|
||||||
else:
|
else:
|
||||||
return frame
|
return frame
|
||||||
|
|
||||||
|
@ -141,6 +142,7 @@ class Component(__base__.Component):
|
||||||
super().preFrameRender(**kwargs)
|
super().preFrameRender(**kwargs)
|
||||||
width = int(self.worker.core.settings.value('outputWidth'))
|
width = int(self.worker.core.settings.value('outputWidth'))
|
||||||
height = int(self.worker.core.settings.value('outputHeight'))
|
height = int(self.worker.core.settings.value('outputHeight'))
|
||||||
|
self.blankFrame_ = self.blankFrame(width, height)
|
||||||
self.updateChunksize(width, height)
|
self.updateChunksize(width, height)
|
||||||
self.video = Video(
|
self.video = Video(
|
||||||
ffmpeg=self.parent.core.FFMPEG_BIN, videoPath=self.videoPath,
|
ffmpeg=self.parent.core.FFMPEG_BIN, videoPath=self.videoPath,
|
||||||
|
@ -148,10 +150,13 @@ class Component(__base__.Component):
|
||||||
frameRate=int(self.settings.value("outputFrameRate")),
|
frameRate=int(self.settings.value("outputFrameRate")),
|
||||||
parent=self.parent, loopVideo=self.loopVideo,
|
parent=self.parent, loopVideo=self.loopVideo,
|
||||||
component=self, scale=self.scale
|
component=self, scale=self.scale
|
||||||
)
|
) if os.path.exists(self.videoPath) else None
|
||||||
|
|
||||||
def frameRender(self, moduleNo, arrayNo, frameNo):
|
def frameRender(self, moduleNo, arrayNo, frameNo):
|
||||||
return self.video.frame(frameNo)
|
if self.video:
|
||||||
|
return self.video.frame(frameNo)
|
||||||
|
else:
|
||||||
|
return self.blankFrame_
|
||||||
|
|
||||||
def loadPreset(self, pr, presetName=None):
|
def loadPreset(self, pr, presetName=None):
|
||||||
super().loadPreset(pr, presetName)
|
super().loadPreset(pr, presetName)
|
||||||
|
@ -177,7 +182,7 @@ class Component(__base__.Component):
|
||||||
imgDir = self.settings.value("backgroundDir", os.path.expanduser("~"))
|
imgDir = self.settings.value("backgroundDir", os.path.expanduser("~"))
|
||||||
filename = QtGui.QFileDialog.getOpenFileName(
|
filename = QtGui.QFileDialog.getOpenFileName(
|
||||||
self.page, "Choose Video",
|
self.page, "Choose Video",
|
||||||
imgDir, "Video Files (*.mp4 *.mov)"
|
imgDir, "Video Files (%s)" % " ".join(self.videoFormats)
|
||||||
)
|
)
|
||||||
if filename:
|
if filename:
|
||||||
self.settings.setValue("backgroundDir", os.path.dirname(filename))
|
self.settings.setValue("backgroundDir", os.path.dirname(filename))
|
||||||
|
@ -228,10 +233,14 @@ def scale(scale, width, height, returntype=None):
|
||||||
|
|
||||||
def finalizeFrame(self, imageData, width, height):
|
def finalizeFrame(self, imageData, width, height):
|
||||||
if self.distort:
|
if self.distort:
|
||||||
image = Image.frombytes(
|
try:
|
||||||
'RGBA',
|
image = Image.frombytes(
|
||||||
(width, height),
|
'RGBA',
|
||||||
imageData)
|
(width, height),
|
||||||
|
imageData)
|
||||||
|
except ValueError:
|
||||||
|
print('#### ignored invalid data caused by distortion ####')
|
||||||
|
image = self.blankFrame(width, height)
|
||||||
else:
|
else:
|
||||||
image = Image.frombytes(
|
image = Image.frombytes(
|
||||||
'RGBA',
|
'RGBA',
|
||||||
|
@ -240,7 +249,7 @@ def finalizeFrame(self, imageData, width, height):
|
||||||
|
|
||||||
if self.scale != 100 \
|
if self.scale != 100 \
|
||||||
or self.xPosition != 0 or self.yPosition != 0:
|
or self.xPosition != 0 or self.yPosition != 0:
|
||||||
frame = Image.new("RGBA", (width, height), (0, 0, 0, 0))
|
frame = self.blankFrame(width, height)
|
||||||
frame.paste(image, box=(self.xPosition, self.yPosition))
|
frame.paste(image, box=(self.xPosition, self.yPosition))
|
||||||
else:
|
else:
|
||||||
frame = image
|
frame = image
|
||||||
|
|
|
@ -234,7 +234,7 @@
|
||||||
<number>10</number>
|
<number>10</number>
|
||||||
</property>
|
</property>
|
||||||
<property name="maximum">
|
<property name="maximum">
|
||||||
<number>200</number>
|
<number>400</number>
|
||||||
</property>
|
</property>
|
||||||
<property name="value">
|
<property name="value">
|
||||||
<number>100</number>
|
<number>100</number>
|
||||||
|
|
102
core.py
102
core.py
|
@ -24,6 +24,32 @@ class Core():
|
||||||
self.presetDir = os.path.join(self.dataDir, 'presets')
|
self.presetDir = os.path.join(self.dataDir, 'presets')
|
||||||
self.wd = os.path.dirname(os.path.realpath(__file__))
|
self.wd = os.path.dirname(os.path.realpath(__file__))
|
||||||
self.loadEncoderOptions()
|
self.loadEncoderOptions()
|
||||||
|
self.videoFormats = Core.appendUppercase([
|
||||||
|
'*.mp4',
|
||||||
|
'*.mov',
|
||||||
|
'*.mkv',
|
||||||
|
'*.avi',
|
||||||
|
'*.webm',
|
||||||
|
'*.flv',
|
||||||
|
])
|
||||||
|
self.audioFormats = Core.appendUppercase([
|
||||||
|
'*.mp3',
|
||||||
|
'*.wav',
|
||||||
|
'*.ogg',
|
||||||
|
'*.fla',
|
||||||
|
'*.aac',
|
||||||
|
])
|
||||||
|
self.imageFormats = Core.appendUppercase([
|
||||||
|
'*.png',
|
||||||
|
'*.jpg',
|
||||||
|
'*.tif',
|
||||||
|
'*.tiff',
|
||||||
|
'*.gif',
|
||||||
|
'*.bmp',
|
||||||
|
'*.ico',
|
||||||
|
'*.xbm',
|
||||||
|
'*.xpm',
|
||||||
|
])
|
||||||
|
|
||||||
self.findComponents()
|
self.findComponents()
|
||||||
self.selectedComponents = []
|
self.selectedComponents = []
|
||||||
|
@ -116,44 +142,48 @@ class Core():
|
||||||
which implements an insertComponent method'''
|
which implements an insertComponent method'''
|
||||||
errcode, data = self.parseAvFile(filepath)
|
errcode, data = self.parseAvFile(filepath)
|
||||||
if errcode == 0:
|
if errcode == 0:
|
||||||
for i, tup in enumerate(data['Components']):
|
try:
|
||||||
name, vers, preset = tup
|
for i, tup in enumerate(data['Components']):
|
||||||
clearThis = False
|
name, vers, preset = tup
|
||||||
|
clearThis = False
|
||||||
|
|
||||||
# add loaded named presets to savedPresets dict
|
# add loaded named presets to savedPresets dict
|
||||||
if 'preset' in preset and preset['preset'] != None:
|
|
||||||
nam = preset['preset']
|
|
||||||
filepath2 = os.path.join(
|
|
||||||
self.presetDir, name, str(vers), nam)
|
|
||||||
origSaveValueStore = self.getPreset(filepath2)
|
|
||||||
if origSaveValueStore:
|
|
||||||
self.savedPresets[nam] = dict(origSaveValueStore)
|
|
||||||
else:
|
|
||||||
# saved preset was renamed or deleted
|
|
||||||
clearThis = True
|
|
||||||
|
|
||||||
# insert component into the loader
|
|
||||||
loader.insertComponent(
|
|
||||||
self.moduleIndexFor(name), -1)
|
|
||||||
try:
|
|
||||||
if 'preset' in preset and preset['preset'] != None:
|
if 'preset' in preset and preset['preset'] != None:
|
||||||
self.selectedComponents[-1].loadPreset(
|
nam = preset['preset']
|
||||||
preset
|
filepath2 = os.path.join(
|
||||||
)
|
self.presetDir, name, str(vers), nam)
|
||||||
else:
|
origSaveValueStore = self.getPreset(filepath2)
|
||||||
self.selectedComponents[-1].loadPreset(
|
if origSaveValueStore:
|
||||||
preset,
|
self.savedPresets[nam] = dict(origSaveValueStore)
|
||||||
preset['preset']
|
else:
|
||||||
)
|
# saved preset was renamed or deleted
|
||||||
except KeyError as e:
|
clearThis = True
|
||||||
print('%s missing value %s' %
|
|
||||||
(self.selectedComponents[-1], e))
|
|
||||||
|
|
||||||
if clearThis:
|
# insert component into the loader
|
||||||
self.clearPreset(-1, loader)
|
loader.insertComponent(
|
||||||
|
self.moduleIndexFor(name), -1)
|
||||||
|
try:
|
||||||
|
if 'preset' in preset and preset['preset'] != None:
|
||||||
|
self.selectedComponents[-1].loadPreset(
|
||||||
|
preset
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
self.selectedComponents[-1].loadPreset(
|
||||||
|
preset,
|
||||||
|
preset['preset']
|
||||||
|
)
|
||||||
|
except KeyError as e:
|
||||||
|
print('%s missing value %s' %
|
||||||
|
(self.selectedComponents[-1], e))
|
||||||
|
|
||||||
|
if clearThis:
|
||||||
|
self.clearPreset(-1, loader)
|
||||||
|
except:
|
||||||
|
errcode = 1
|
||||||
|
data = sys.exc_info()
|
||||||
|
|
||||||
|
|
||||||
elif errcode == 1:
|
if errcode == 1:
|
||||||
typ, value, _ = data
|
typ, value, _ = data
|
||||||
if typ.__name__ == KeyError:
|
if typ.__name__ == KeyError:
|
||||||
# probably just an old version, still loadable
|
# probably just an old version, still loadable
|
||||||
|
@ -398,3 +428,9 @@ class Core():
|
||||||
def presetFromString(string):
|
def presetFromString(string):
|
||||||
'''Turns a string repr of OrderedDict into a regular dict'''
|
'''Turns a string repr of OrderedDict into a regular dict'''
|
||||||
return dict(eval(string))
|
return dict(eval(string))
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def appendUppercase(lst):
|
||||||
|
for form, i in zip(lst, range(len(lst))):
|
||||||
|
lst.append(form.upper())
|
||||||
|
return lst
|
||||||
|
|
|
@ -310,7 +310,7 @@ class MainWindow(QtCore.QObject):
|
||||||
|
|
||||||
fileName = QtGui.QFileDialog.getOpenFileName(
|
fileName = QtGui.QFileDialog.getOpenFileName(
|
||||||
self.window, "Open Music File",
|
self.window, "Open Music File",
|
||||||
inputDir, "Music Files (*.mp3 *.wav *.ogg *.fla *.aac)")
|
inputDir, "Music Files (%s)" % " ".join(self.core.audioFormats))
|
||||||
|
|
||||||
if not fileName == "":
|
if not fileName == "":
|
||||||
self.settings.setValue("inputDir", os.path.dirname(fileName))
|
self.settings.setValue("inputDir", os.path.dirname(fileName))
|
||||||
|
@ -322,7 +322,7 @@ class MainWindow(QtCore.QObject):
|
||||||
fileName = QtGui.QFileDialog.getSaveFileName(
|
fileName = QtGui.QFileDialog.getSaveFileName(
|
||||||
self.window, "Set Output Video File",
|
self.window, "Set Output Video File",
|
||||||
outputDir,
|
outputDir,
|
||||||
"Video Files (*.mp4 *.mov *.mkv *.avi *.webm *.flv);; All Files (*)")
|
"Video Files (%s);; All Files (*)" % " ".join(self.core.videoFormats))
|
||||||
|
|
||||||
if not fileName == "":
|
if not fileName == "":
|
||||||
self.settings.setValue("outputDir", os.path.dirname(fileName))
|
self.settings.setValue("outputDir", os.path.dirname(fileName))
|
||||||
|
|
|
@ -1,11 +1,9 @@
|
||||||
from PyQt4 import QtCore, QtGui, uic
|
from PyQt4 import QtCore, QtGui, uic
|
||||||
from PyQt4.QtCore import pyqtSignal, pyqtSlot
|
from PyQt4.QtCore import pyqtSignal, pyqtSlot
|
||||||
from PIL import Image, ImageDraw, ImageFont
|
from PIL import Image
|
||||||
from PIL.ImageQt import ImageQt
|
from PIL.ImageQt import ImageQt
|
||||||
import core
|
import core
|
||||||
import time
|
|
||||||
from queue import Queue, Empty
|
from queue import Queue, Empty
|
||||||
import numpy
|
|
||||||
import os
|
import os
|
||||||
from copy import copy
|
from copy import copy
|
||||||
|
|
||||||
|
@ -18,6 +16,7 @@ class Worker(QtCore.QObject):
|
||||||
QtCore.QObject.__init__(self)
|
QtCore.QObject.__init__(self)
|
||||||
parent.newTask.connect(self.createPreviewImage)
|
parent.newTask.connect(self.createPreviewImage)
|
||||||
parent.processTask.connect(self.process)
|
parent.processTask.connect(self.process)
|
||||||
|
self.parent = parent
|
||||||
self.core = core.Core()
|
self.core = core.Core()
|
||||||
self.queue = queue
|
self.queue = queue
|
||||||
self.core.settings = parent.settings
|
self.core.settings = parent.settings
|
||||||
|
|
Reference in New Issue