Merge pull request #35 from djfun/newgui-bugfixes

Newgui bugfixes
This commit is contained in:
Brianna 2017-06-25 10:40:48 -04:00 committed by GitHub
commit 55423ca4aa
12 changed files with 163 additions and 93 deletions

View File

@ -1,4 +1,4 @@
from PyQt5 import QtGui, QtCore, QtWidgets
from PyQt5 import uic, QtGui, QtCore, QtWidgets
from PIL import Image
import os
@ -114,6 +114,9 @@ class Component(QtCore.QObject):
except:
return (255, 255, 255)
def loadUi(self, filename):
return uic.loadUi(os.path.join(self.core.componentsPath, filename))
'''
### Reference methods for creating a new component
### (Inherit from this class and define these)

View File

@ -1,5 +1,5 @@
from PIL import Image, ImageDraw
from PyQt5 import uic, QtGui, QtCore, QtWidgets
from PyQt5 import QtGui, QtCore, QtWidgets
from PyQt5.QtGui import QColor
from PIL.ImageQt import ImageQt
import os
@ -13,8 +13,7 @@ class Component(__base__.Component):
def widget(self, parent):
self.parent = parent
page = uic.loadUi(os.path.join(
os.path.dirname(os.path.realpath(__file__)), 'color.ui'))
page = self.loadUi('color.ui')
self.color1 = (0, 0, 0)
self.color2 = (133, 133, 133)
@ -177,7 +176,7 @@ class Component(__base__.Component):
self.sizeWidth, self.sizeHeight
)
painter.end()
imBytes = image.bits().asstring(image.numBytes())
imBytes = image.bits().asstring(image.byteCount())
return Image.frombytes('RGBA', (width, height), imBytes)
def loadPreset(self, pr, presetName=None):

View File

@ -1,5 +1,5 @@
from PIL import Image, ImageDraw
from PyQt5 import uic, QtGui, QtCore, QtWidgets
from PyQt5 import QtGui, QtCore, QtWidgets
import os
from . import __base__
@ -12,8 +12,7 @@ class Component(__base__.Component):
def widget(self, parent):
self.parent = parent
self.settings = parent.settings
page = uic.loadUi(os.path.join(
os.path.dirname(os.path.realpath(__file__)), 'image.ui'))
page = self.loadUi('image.ui')
self.imagePath = ''
self.x = 0
self.y = 0

View File

@ -1,6 +1,6 @@
import numpy
from PIL import Image, ImageDraw
from PyQt5 import uic, QtGui, QtCore, QtWidgets
from PyQt5 import QtGui, QtCore, QtWidgets
from PyQt5.QtGui import QColor
import os
from . import __base__
@ -17,8 +17,7 @@ class Component(__base__.Component):
self.parent = parent
self.visColor = (255, 255, 255)
page = uic.loadUi(os.path.join(
os.path.dirname(os.path.realpath(__file__)), 'original.ui'))
page = self.loadUi('original.ui')
page.comboBox_visLayout.addItem("Classic")
page.comboBox_visLayout.addItem("Split")
page.comboBox_visLayout.addItem("Bottom")

View File

@ -1,6 +1,6 @@
from PIL import Image, ImageDraw
from PyQt5.QtGui import QPainter, QColor, QFont
from PyQt5 import uic, QtGui, QtCore, QtWidgets
from PyQt5 import QtGui, QtCore, QtWidgets
from PIL.ImageQt import ImageQt
import os
import io
@ -29,8 +29,7 @@ class Component(__base__.Component):
self.xPosition = width / 2 - fm.width(self.title)/2
self.yPosition = height / 2 * 1.036
page = uic.loadUi(os.path.join(
os.path.dirname(os.path.realpath(__file__)), 'text.ui'))
page = self.loadUi('text.ui')
page.comboBox_textAlign.addItem("Left")
page.comboBox_textAlign.addItem("Middle")
page.comboBox_textAlign.addItem("Right")

View File

@ -1,6 +1,7 @@
from PIL import Image, ImageDraw
from PyQt5 import uic, QtGui, QtCore, QtWidgets
from PyQt5 import QtGui, QtCore, QtWidgets
import os
import math
import subprocess
import threading
from queue import PriorityQueue
@ -79,9 +80,20 @@ class Video:
self.frameNo += 1
# If we run out of frames, use the last good frame and loop.
if len(self.currentFrame) == 0:
self.frameBuffer.put((self.frameNo-1, self.lastFrame))
continue
try:
if len(self.currentFrame) == 0:
self.frameBuffer.put((self.frameNo-1, self.lastFrame))
continue
except AttributeError as e:
self.parent.showMessage(
msg='%s couldn\'t be loaded. '
'This is a fatal error.' % os.path.basename(
self.videoPath
),
detail=str(e)
)
self.parent.stopVideo()
break
self.currentFrame = pipe.stdout.read(self.chunkSize)
if len(self.currentFrame) != 0:
@ -97,10 +109,7 @@ class Component(__base__.Component):
def widget(self, parent):
self.parent = parent
self.settings = parent.settings
page = uic.loadUi(os.path.join(
os.path.dirname(os.path.realpath(__file__)),
'video.ui'
))
page = self.loadUi('video.ui')
self.videoPath = ''
self.x = 0
self.y = 0
@ -243,28 +252,32 @@ def scale(scale, width, height, returntype=None):
width = (float(width) / 100.0) * float(scale)
height = (float(height) / 100.0) * float(scale)
if returntype == str:
return (str(int(width)), str(int(height)))
return (str(math.ceil(width)), str(math.ceil(height)))
elif returntype == int:
return (int(width), int(height))
return (math.ceil(width), math.ceil(height))
else:
return (width, height)
def finalizeFrame(self, imageData, width, height):
if self.distort:
try:
try:
if self.distort:
image = Image.frombytes(
'RGBA',
(width, height),
imageData)
except ValueError:
print('#### ignored invalid data caused by distortion ####')
image = self.blankFrame(width, height)
else:
image = Image.frombytes(
'RGBA',
scale(self.scale, width, height, int),
imageData)
else:
image = Image.frombytes(
'RGBA',
scale(self.scale, width, height, int),
imageData)
except ValueError:
print(
'### BAD VIDEO SELECTED ###\n'
'Video will not export with these settings'
)
return self.blankFrame(width, height)
if self.scale != 100 \
or self.xPosition != 0 or self.yPosition != 0:

View File

@ -29,6 +29,7 @@ class Core():
else:
# unfrozen
self.wd = os.path.dirname(os.path.realpath(__file__))
self.componentsPath = os.path.join(self.wd, 'components')
self.loadEncoderOptions()
self.videoFormats = Core.appendUppercase([
@ -66,14 +67,12 @@ class Core():
def findComponents(self):
def findComponents():
srcPath = os.path.join(self.wd, 'components')
if os.path.exists(srcPath):
for f in sorted(os.listdir(srcPath)):
name, ext = os.path.splitext(f)
if name.startswith("__"):
continue
elif ext == '.py':
yield name
for f in sorted(os.listdir(self.componentsPath)):
name, ext = os.path.splitext(f)
if name.startswith("__"):
continue
elif ext == '.py':
yield name
self.modules = [
import_module('components.%s' % name)
for name in findComponents()
@ -93,10 +92,12 @@ class Core():
return None
component = self.modules[moduleIndex].Component(
moduleIndex, compPos, self)
moduleIndex, compPos, self
)
self.selectedComponents.insert(
compPos,
component)
component
)
self.componentListChanged()
# init component's widget for loading/saving presets
@ -177,6 +178,7 @@ class Core():
for i, tup in enumerate(data['Components']):
name, vers, preset = tup
clearThis = False
modified = False
# add loaded named presets to savedPresets dict
if 'preset' in preset and preset['preset'] is not None:
@ -186,6 +188,7 @@ class Core():
origSaveValueStore = self.getPreset(filepath2)
if origSaveValueStore:
self.savedPresets[nam] = dict(origSaveValueStore)
modified = not origSaveValueStore == preset
else:
# saved preset was renamed or deleted
clearThis = True
@ -217,7 +220,7 @@ class Core():
if clearThis:
self.clearPreset(i)
if hasattr(loader, 'updateComponentTitle'):
loader.updateComponentTitle(i)
loader.updateComponentTitle(i, modified)
except:
errcode = 1
data = sys.exc_info()

View File

@ -7,6 +7,15 @@ import preview_thread
import video_thread
def disableWhenEncoding(func):
def decorator(*args):
if args[0].encoding:
return
else:
return func(*args)
return decorator
def LoadDefaultSettings(self):
self.resolutions = [
'1920x1080',

View File

@ -12,7 +12,7 @@ import core
import preview_thread
import video_thread
from presetmanager import PresetManager
from main import LoadDefaultSettings
from main import LoadDefaultSettings, disableWhenEncoding
class PreviewWindow(QtWidgets.QLabel):
@ -54,6 +54,7 @@ class MainWindow(QtWidgets.QMainWindow):
self.pages = [] # widgets of component settings
self.lastAutosave = time.time()
self.encoding = False
# Create data directory, load/create settings
self.dataDir = self.core.dataDir
@ -149,16 +150,18 @@ class MainWindow(QtWidgets.QMainWindow):
for i, comp in enumerate(self.core.modules):
action = self.compMenu.addAction(comp.Component.__doc__)
action.triggered.connect(
lambda _, item=i: self.core.insertComponent(0, item, self))
lambda _, item=i: self.core.insertComponent(0, item, self)
)
self.window.pushButton_addComponent.setMenu(self.compMenu)
componentList.dropEvent = self.dragComponent
componentList.itemSelectionChanged.connect(
self.changeComponentWidget)
self.changeComponentWidget
)
self.window.pushButton_removeComponent.clicked.connect(
lambda _: self.removeComponent())
lambda: self.removeComponent()
)
componentList.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
componentList.customContextMenuRequested.connect(
@ -173,7 +176,8 @@ class MainWindow(QtWidgets.QMainWindow):
currentRes = i
window.comboBox_resolution.setCurrentIndex(currentRes)
window.comboBox_resolution.currentIndexChanged.connect(
self.updateResolution)
self.updateResolution
)
self.window.pushButton_listMoveUp.clicked.connect(
lambda: self.moveComponent(-1)
@ -185,14 +189,17 @@ class MainWindow(QtWidgets.QMainWindow):
# Configure the Projects Menu
self.projectMenu = QMenu()
self.window.menuButton_newProject = self.projectMenu.addAction(
"New Project")
"New Project"
)
self.window.menuButton_newProject.triggered.connect(
self.createNewProject)
lambda: self.createNewProject()
)
self.window.menuButton_openProject = self.projectMenu.addAction(
"Open Project")
"Open Project"
)
self.window.menuButton_openProject.triggered.connect(
self.openOpenProjectDialog)
lambda: self.openOpenProjectDialog()
)
action = self.projectMenu.addAction("Save Project")
action.triggered.connect(self.saveCurrentProject)
@ -207,6 +214,7 @@ class MainWindow(QtWidgets.QMainWindow):
self.openPresetManager
)
self.updateWindowTitle()
window.show()
if project and project != self.autosavePath:
@ -282,10 +290,15 @@ class MainWindow(QtWidgets.QMainWindow):
def updateWindowTitle(self):
appName = 'Audio Visualizer'
if self.currentProject:
appName += ' - %s' % \
os.path.splitext(
os.path.basename(self.currentProject))[0]
try:
if self.currentProject:
appName += ' - %s' % \
os.path.splitext(
os.path.basename(self.currentProject))[0]
if self.autosaveExists(identical=False):
appName += '*'
except AttributeError:
pass
self.window.setWindowTitle(appName)
@QtCore.pyqtSlot(int, dict)
@ -345,7 +358,7 @@ class MainWindow(QtWidgets.QMainWindow):
if not self.currentProject:
if os.path.exists(self.autosavePath):
os.remove(self.autosavePath)
elif force or time.time() - self.lastAutosave >= 2.0:
elif force or time.time() - self.lastAutosave >= 0.1:
self.core.createProjectFile(self.autosavePath)
self.lastAutosave = time.time()
@ -391,7 +404,7 @@ class MainWindow(QtWidgets.QMainWindow):
"Video Files (%s);; All Files (*)" % " ".join(
self.core.videoFormats))
if not fileName == "":
if fileName:
self.settings.setValue("outputDir", os.path.dirname(fileName))
self.window.lineEdit_outputFile.setText(fileName)
@ -402,33 +415,50 @@ class MainWindow(QtWidgets.QMainWindow):
def createAudioVisualisation(self):
# create output video if mandatory settings are filled in
if self.window.lineEdit_audioFile.text() and \
self.window.lineEdit_outputFile.text():
self.canceled = False
self.progressBarUpdated(-1)
self.videoThread = QtCore.QThread(self)
self.videoWorker = video_thread.Worker(self)
self.videoWorker.moveToThread(self.videoThread)
self.videoWorker.videoCreated.connect(self.videoCreated)
self.videoWorker.progressBarUpdate.connect(self.progressBarUpdated)
self.videoWorker.progressBarSetText.connect(
self.progressBarSetText)
self.videoWorker.imageCreated.connect(self.showPreviewImage)
self.videoWorker.encoding.connect(self.changeEncodingStatus)
self.videoThread.start()
outputPath = self.window.lineEdit_outputFile.text()
audioFile = self.window.lineEdit_audioFile.text()
outputPath = self.window.lineEdit_outputFile.text()
if audioFile and outputPath and self.core.selectedComponents:
if not os.path.dirname(outputPath):
outputPath = os.path.join(
os.path.expanduser("~"), outputPath)
self.videoTask.emit(
self.window.lineEdit_audioFile.text(),
outputPath,
self.core.selectedComponents)
if outputPath and os.path.isdir(outputPath):
self.showMessage(
msg='Chosen filename matches a directory, which '
'cannot be overwritten. Please choose a different '
'filename or move the directory.'
)
return
else:
self.showMessage(
msg="You must select an audio file and output filename.")
if not audioFile or not outputPath:
self.showMessage(
msg="You must select an audio file and output filename."
)
elif not self.core.selectedComponents:
self.showMessage(
msg="Not enough components."
)
return
self.canceled = False
self.progressBarUpdated(-1)
self.videoThread = QtCore.QThread(self)
self.videoWorker = video_thread.Worker(self)
self.videoWorker.moveToThread(self.videoThread)
self.videoWorker.videoCreated.connect(self.videoCreated)
self.videoWorker.progressBarUpdate.connect(self.progressBarUpdated)
self.videoWorker.progressBarSetText.connect(
self.progressBarSetText)
self.videoWorker.imageCreated.connect(self.showPreviewImage)
self.videoWorker.encoding.connect(self.changeEncodingStatus)
self.videoThread.start()
self.videoTask.emit(
audioFile,
outputPath,
self.core.selectedComponents)
def changeEncodingStatus(self, status):
self.encoding = status
if status:
self.window.pushButton_createVideo.setEnabled(False)
self.window.pushButton_Cancel.setEnabled(True)
@ -490,6 +520,7 @@ class MainWindow(QtWidgets.QMainWindow):
self.newTask.emit(self.core.selectedComponents)
# self.processTask.emit()
self.autosave(force)
self.updateWindowTitle()
def showPreviewImage(self, image):
self.previewWindow.changePixmap(image)
@ -595,6 +626,7 @@ class MainWindow(QtWidgets.QMainWindow):
self.window.stackedWidget.removeWidget(widget)
self.pages = []
@disableWhenEncoding
def createNewProject(self):
self.openSaveChangesDialog('starting a new project')
@ -602,11 +634,11 @@ class MainWindow(QtWidgets.QMainWindow):
self.currentProject = None
self.settings.setValue("currentProject", None)
self.drawPreview(True)
self.updateWindowTitle()
def saveCurrentProject(self):
if self.currentProject:
self.core.createProjectFile(self.currentProject)
self.updateWindowTitle()
else:
self.openSaveProjectDialog()
@ -638,9 +670,10 @@ class MainWindow(QtWidgets.QMainWindow):
self.settings.setValue("projectDir", os.path.dirname(filename))
self.settings.setValue("currentProject", filename)
self.currentProject = filename
self.updateWindowTitle()
self.core.createProjectFile(filename)
self.updateWindowTitle()
@disableWhenEncoding
def openOpenProjectDialog(self):
filename, _ = QtWidgets.QFileDialog.getOpenFileName(
self.window, "Open Project File",
@ -651,7 +684,6 @@ class MainWindow(QtWidgets.QMainWindow):
def openProject(self, filepath, prompt=True):
if not filepath or not os.path.exists(filepath) \
or not filepath.endswith('.avp'):
self.updateWindowTitle()
return
self.clear()
@ -660,7 +692,6 @@ class MainWindow(QtWidgets.QMainWindow):
self.openSaveChangesDialog('opening another project')
self.currentProject = filepath
self.updateWindowTitle()
self.settings.setValue("currentProject", filepath)
self.settings.setValue("projectDir", os.path.dirname(filepath))
# actually load the project using core method
@ -668,6 +699,7 @@ class MainWindow(QtWidgets.QMainWindow):
if self.window.listWidget_componentList.count() == 0:
self.drawPreview()
self.autosave(True)
self.updateWindowTitle()
def showMessage(self, **kwargs):
parent = kwargs['parent'] if 'parent' in kwargs else self.window

View File

@ -123,7 +123,8 @@ class PresetManager(QtWidgets.QDialog):
def clearPreset(self, compI=None):
'''Functions on mainwindow level from the context menu'''
compI = self.parent.window.listWidget_componentList.currentRow()
self.core.clearPreset(compI, self.parent)
self.core.clearPreset(compI)
self.parent.updateComponentTitle(compI, False)
def openSavePresetDialog(self):
'''Functions on mainwindow level from the context menu'''

View File

@ -49,8 +49,18 @@ class Worker(QtCore.QObject):
components = nextPreviewInformation["components"]
for component in reversed(components):
frame = Image.alpha_composite(
frame, component.previewRender(self))
try:
frame = Image.alpha_composite(
frame, component.previewRender(self)
)
except ValueError as e:
self.parent.showMessage(
msg="Bad frame returned by %s's previewRender method. "
"This is a fatal error." %
str(component),
detail=str(e)
)
quit(1)
self._image = ImageQt(frame)
self.imageCreated.emit(QtGui.QImage(self._image))

View File

@ -2,7 +2,6 @@ from PyQt5 import QtCore, QtGui, uic
from PyQt5.QtCore import pyqtSignal, pyqtSlot
from PIL import Image, ImageDraw, ImageFont
from PIL.ImageQt import ImageQt
import core
import numpy
import subprocess as sp
import sys
@ -13,6 +12,8 @@ import time
from copy import copy
import signal
import core
class Worker(QtCore.QObject):
@ -87,8 +88,10 @@ class Worker(QtCore.QObject):
self.encoding.emit(True)
self.components = components
self.outputFile = outputFile
self.bgI = 0 # tracked video frame
self.reset()
self.bgI = 0 # tracked video frame
self.width = int(self.core.settings.value('outputWidth'))
self.height = int(self.core.settings.value('outputHeight'))
progressBarValue = 0
@ -171,7 +174,7 @@ class Worker(QtCore.QObject):
self.staticComponents = {}
numComps = len(self.components)
for compNo, comp in enumerate(self.components):
pStr = "Analyzing audio..."
pStr = "Starting components..."
self.progressBarSetText.emit(pStr)
properties = None
properties = comp.preFrameRender(