编写此代码的目的是复制/粘贴并运行它(并且它应该运行)。我愿意听取所有反馈意见。
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Author: Nishith
# Version: 1.0
#
# Description:
# A quicktime (part 2 ) generator from ready image sequence. User is
# prompted to this path. "First_part_of_image_sequence".mov is created
# in same folder
#
# switch: 1 if works, 0 if does not work
# variable names selected randomly
# This script is as loosely coupled as possible. There can be more scope
# of it being as would be seen as design pattern
import maya.cmds as cmds
import maya.OpenMaya as OpenMaya
import os,subprocess, re
import random
import tempfile
from types import *
import shutil
import unicodedata
import time
import ctypes
class makeQuicktime(object):
def __init__(self):
self.fileExtension = ""
self.backgroundImage = ""
self.thumbnailImage = ""
self.firstImage = ""
self.tempFolder = ""
self.symlinkFolder = ""
self.oneImage = ""
self.myTemp = ""
self.elementName = ""
self.qeName = ""
self.date = ""
self.imageSequence = ""
self.lens = ""
self.frameRange = ""
self.notes = ""
self.qnotes = ""
self.currentFrame = ""
self.imageregex = ""
self.exepath = "D:/mayaslate/"
self.ffmpeg = "ffmpeg.exe"
self.composite = "composite.exe"
self.dll = "vcomp100.dll"
self.kerneldll = "kernel32.dll"
def thirdpartyapp(self):
"""
D:/mayaslate/ has 3 executables. if any is missing admin will put it
"""
if not os.path.isfile(os.path.join (self.exepath ,self.ffmpeg)):
OpenMaya.MGlobal.displayError("% app not present") % self.ffmpeg
if not os.path.isfile(os.path.join (self.exepath ,self.composite)):
OpenMaya.MGlobal.displayError("% app not present") % self.composite
if not os.path.isfile(os.path.join (self.exepath ,self.dll)):
OpenMaya.MGlobal.displayError("% app not present") % self.dll
def setImageRegex(self,imageCountVar): # check length of imageCountVar
"""
@setImageRegex: padding image count.
"""
if (len(imageCountVar) == 5):
irx = "%05d"
elif (len(imageCountVar) == 4):
irx = "%04d"
elif (len(imageCountVar) == 3):
irx = "%03d"
elif (len(imageCountVar) == 2):
irx = "%02d"
elif (len(imageCountVar) == 1):
irx = "%01d"
return irx
def firstImageCount(self,listOfFiles):
"""
file list : @listOfFiles , parameter passed
firstImageCount, returns what should be number on first image
"""
whisper = ""
# nc = unicodedata.normalize('NFKD', listOfFiles[0].split('.')[1]).encode('ascii','ignore')
nc = listOfFiles[0].split('.')[1]
ic = str(int(nc) - 1)
if ((len(nc) - len(ic)) == 0):
whisper = ""
elif ((len(nc) - len(ic)) == 1):
whisper = "0"
elif ((len(nc) - len(ic)) == 2):
whisper = "00"
elif ((len(nc) - len(ic)) == 3):
whisper = "000"
return (whisper + ic)
def cleanDirectory(self,dName):
for filen in os.listdir(dName):
os.remove(dName.replace("\\","/") +"/"+filen)
def makeTempFolder(self, fName):
print 'fName : ',fName,'\n'
# check tmp folder exst , if not flag message exit
# sysTemp = tempfile.gettempdir().replace("\\","/") # get temp folder name
sysTemp = "D:/mayaslate" # get temp folder name
if not os.path.exists(sysTemp):
os.makedirs(sysTemp)
mesg = "% now created " % (sysTemp)
OpenMaya.MGlobal.displayInfo(mesg)
return 1
else:
self.myTemp = os.path.join(sysTemp,fName).replace("\\","/")
if not os.path.exists(self.myTemp): # if already exists then clear it else create it
os.makedirs(self.myTemp)
print 'self.tempFolder : ',self.tempFolder,'\n'
else:
self.cleanDirectory(self.myTemp)
self.tempFolder = self.myTemp
return 0
def selectFolder( self, folderName, fileType):
fName = unicodedata.normalize('NFKD', folderName).encode('ascii','ignore')
if os.path.isdir(fName):
# self.tempFolder = tempfile.gettempdir().replace("\\","/") # get temp folder name
self.tempFolder = "D:/mayaslate" # get temp folder name
self.symlinkFolder = self.tempFolder + "/symlink/" # create symlink folder within temp folder
if not os.path.isdir(self.symlinkFolder):
os.mkdir(self.symlinkFolder)
print '%TEMP%',self.tempFolder,'\n'
# for thumbnail
temp_01 = os.listdir(fName) # get file name from user folder
print 'temp_01 ',temp_01 ,'\n'
sampleFileName = temp_01[random.randint(1,len(temp_01)-1)] # select random image
# fpof = unicodedata.normalize('NFKD', (sampleFileName.split('.')[0])).encode('ascii','ignore')
fpof = sampleFileName.split('.')[0]
print 'fpof ',fpof ,'\n'
retVal = self.makeTempFolder(sampleFileName.split(".")[0]) # make folder with file name in %TEMP%
if (retVal == 0):
# self.fileExtension = unicodedata.normalize('NFKD', sampleFileName.split('.')[2]).encode('ascii','ignore')
self.fileExtension = sampleFileName.split('.')[2]
print 'self.fileExtension : ',self.fileExtension,'\n'
self.backgroundImage = self.tempFolder + "/background.jpg"
self.thumbnailImage = self.tempFolder + "/thumbnail." + self.fileExtension
temp_02 = fName + "/" + sampleFileName
args = ["composite", "-compose", "Clear", "null:", temp_02, "-alpha", "Off", self.backgroundImage]
process = subprocess.Popen(args,stdout=subprocess.PIPE)
ret = process.wait()
if (ret == 0):
args = ["ffmpeg", "-i", temp_02 ,"-vf", "scale=iw/3.5:ih/3.5", "-frames:v", "1", self.thumbnailImage]
process = subprocess.Popen(args, stdout=subprocess.PIPE)
ret = process.wait()
if (ret == 0):
print 'mate'
self.firstImage = self.tempFolder + "/firstImage." + self.fileExtension
self.thumbnailImage = self.thumbnailImage.replace(':', '\:')
temp_03 = "movie='%s' [watermark]; [in][watermark] overlay=(main_w-overlay_w)/2:(main_h-overlay_h)/3 [out]" % self.thumbnailImage
args = ["ffmpeg", "-i", self.backgroundImage , "-vf", temp_03 , self.firstImage]
process = subprocess.Popen(args, stdout=subprocess.PIPE)
ret = process.wait()
if (ret == 0):
print 'pen penultimate'
oldid = os.listdir(fName)
if not isinstance(oldid,NoneType):
fiC = self.firstImageCount(oldid)
self.oneImage = fName + "/" + fpof + "." + fiC + "." + self.fileExtension
print 'self.oneImage : ',self.oneImage ,'\n'
# elementname and notes are gotten from user
self.date = (time.strftime("%d"+"\/ "+"%m"+"\/ "+"%Y"+" \- "+"%H"+"\:"+"%M"+"\:"+"%S"))
self.imageSequence = fpof
self.lens = str(int(cmds.getAttr('shotcamShape.focalLength'))) # get from globals
self.frameRange = (str(int(cmds.getAttr('defaultRenderGlobals.startFrame'))) + " - " + str(int(cmds.getAttr('defaultRenderGlobals.endFrame')))) # get from globals
args = ["ffmpeg", "-i", self.firstImage, "-vf", "[in]drawtext=fontsize=32:fontcolor=White:fontfile='C\:/Windows/Fonts/arial.ttf':text='shotName':x=(w)/2:y=(h)-50,drawtext=fontsize=28:fontcolor=White:fontfile='C\:/Windows/Fonts/arial.ttf':text='Notes \:':x=(w)/5:y=(h)-90,drawtext=fontsize=28:fontcolor=White:fontfile='C\:/Windows/Fonts/arial.ttf':text='"+ self.qnotes +"':x=((w)/5)+250:y=(h)-90,drawtext=fontsize=28:fontcolor=White:fontfile='C\:/Windows/Fonts/arial.ttf':text='Frame Range \:':x=(w)/5:y=(h)-130,drawtext=fontsize=28:fontcolor=White:fontfile='C\:/Windows/Fonts/arial.ttf':text='"+ self.frameRange +"':x=((w)/5)+250:y=(h)-130,drawtext=fontsize=28:fontcolor=White:fontfile='C\:/Windows/Fonts/arial.ttf':text='Lens \:':x=(w)/5:y=(h)-170,drawtext=fontsize=28:fontcolor=White:fontfile='C\:/Windows/Fonts/arial.ttf':text='"+ self.lens +"':x=((w)/5)+250:y=(h)-170,drawtext=fontsize=28:fontcolor=White:fontfile='C\:/Windows/Fonts/arial.ttf':text='Image Sequence \:':x=(w)/5:y=(h)-210,drawtext=fontsize=28:fontcolor=White:fontfile='C\:/Windows/Fonts/arial.ttf':text='"+ self.imageSequence +"':x=((w)/5)+250:y=(h)-210,drawtext=fontsize=28:fontcolor=White:fontfile='C\:/Windows/Fonts/arial.ttf':text='Date \:':x=(w)/5:y=(h)-250,drawtext=fontsize=28:fontcolor=White:fontfile='C\:/Windows/Fonts/arial.ttf':text='"+ self.date +"':x=((w)/5)+250:y=(h)-250,drawtext=fontsize=28:fontcolor=White:fontfile='C\:/Windows/Fonts/arial.ttf':text='Element Name \:':x=(w)/5:y=(h)-290,drawtext=fontsize=28:fontcolor=White:fontfile='C\:/Windows/Fonts/arial.ttf':text='"+ self.qeName +"':x=((w)/5)+250:y=(h)-290,drawtext=fontfile='C\:/Windows/Fonts/arial.ttf':text='FUTUREWORKS':x=130:y=200:fontsize=54:fontcolor=White[out]", self.oneImage ]
process = subprocess.Popen(args, stdout=subprocess.PIPE)
ret = process.wait()
if (ret == 0): # "D:/imagesequence/dpx/brn_055.%04d.dpx"
print 'penultimate\n'
self.imageregex = self.setImageRegex(sampleFileName.split('.')[1])
newList = os.listdir(fName) # get file name from user folder
bunchOfPictures = self.symlinkFolder + fpof + "." + self.imageregex + "." + self.fileExtension
tempBunchOfPictures = self.tempFolder + "/" + fpof + "." + self.imageregex + "." + self.fileExtension
objSym = symlinkHouseKeep()
objSym.createLink( newList , fName, self.symlinkFolder, self.fileExtension , fpof, self.imageregex)
# print 'bunchOfPictures : ',bunchOfPictures ,'\n'
# print 'tempBunchOfPictures : ',tempBunchOfPictures ,'\n'
cnt = 0
for each in os.listdir(self.symlinkFolder):
aaaa = self.symlinkFolder + "/" + each
bbbb = self.tempFolder + "/" + each
args = ["ffmpeg", "-i", aaaa , "-vf", "drawtext=fontfile='C\:/Windows/Fonts/arial.ttf':text='shotcam':x=(w)/2:y=(h)-35:fontsize=24:fontcolor=Yellow,drawtext=fontfile='C\:/Windows/Fonts/arial.ttf':text='Frame \:':x=(w)-600:y=(h)-35:fontsize=24:fontcolor=Yellow,drawtext=fontfile='C\:/Windows/Fonts/arial.ttf':text='" + str(cnt) +"':x=(w)-300:y=(h)-35:fontsize=24:fontcolor=Yellow,drawtext=fontfile='C\:/Windows/Fonts/arial.ttf':text='Focal Length \:':x=(w)-600:y=(h)-65:fontsize=24:fontcolor=Yellow,drawtext=fontfile='C\:/Windows/Fonts/arial.ttf':text='" + self.lens +"':x=(w)-300:y=(h)-65:fontsize=24:fontcolor=Yellow", bbbb ]
process = subprocess.Popen(args, stdout=subprocess.PIPE)
ret = process.wait()
if (ret == 0):
cnt = cnt + 1
continue
print 'ultimate\n'
#************************************************************************************
# since the first image is going to be "0000" until ffmpeg takes any other, following line has the number hard coded to over overwrite 1st image from fname, it is without yellow labels
#************************************************************************************
shutil.copy(self.oneImage,(self.tempFolder + "/" + fpof + ".0000." + self.fileExtension) )
#************************************************************************************
quicktimeFile = fName + "/" + fpof + ".mov"
args = ["ffmpeg", "-i", tempBunchOfPictures , "-vcodec", "png", "-pix_fmt", "rgb32", "-y", quicktimeFile]
process = subprocess.Popen(args, stdout=subprocess.PIPE)
ret = process.wait()
if (ret == 0):
message = "completed quicktime : %s %s" % (quicktimeFile," ... deleting temp folder")
OpenMaya.MGlobal.displayInfo(message)
"""
clean up commands
"""
os.remove(self.oneImage) # when running script perpetually, only first image number is constant delete this image once mov is created
shutil.rmtree(self.myTemp)
shutil.rmtree(self.symlinkFolder)
else:
OpenMaya.MGlobal.displayWarning("nothing in the folder")
else:
OpenMaya.MGlobal.displayWarning("Folder not existing. Create it then run this script")
#************************************************************************************
# userWindow
#************************************************************************************
def userWindow(self):
window = cmds.window( title="maya slate", iconName='ms', widthHeight=(200, 55) )
cmds.columnLayout( adjustableColumn=True )
cmds.text( label='Element Name' )
self.elementName = cmds.optionMenuGrp( 'renderwith', label=' ', columnWidth=(2, 80) )
cmds.menuItem( label='cones' )
cmds.menuItem( label='rmcurves' )
cmds.menuItem( label='mesh' )
cmds.menuItem( label='headmesh' )
cmds.text( label='Notes' )
self.notes = cmds.scrollField( 'notes',editable=True, wordWrap=True, text='addtional info here...' )
cmds.button( label='Close', command=('a.qeName = cmds.optionMenuGrp( a.elementName , query=True, value=True )\na.qnotes = cmds.scrollField(a.notes , query = True, text = True)\ncmds.deleteUI(\"' + window + '\", window=True)\ncmds.fileBrowserDialog( m=4, fc=a.selectFolder, ft=\'directory\', an=\'Where should .mov reside in\')') )
cmds.setParent( '..' )
cmds.showWindow( window )
#************************************************************************************
# symlinkHouseKeep
#************************************************************************************
# type : class
# func : createlink - create symbolic link of all files in folder
# listIm : folderName
# fldr : root folder name
# tmpfldr : sytem temp folder
# xtn : file extension
# fpf : first part of file
#************************************************************************************
class symlinkHouseKeep(object):
def __init__(self):
self.nwidth = ""
self.number = 0
self.kdll = ctypes.windll.LoadLibrary(a.kerneldll)
def givenos(self, nwid , numbr):
x = ""
for i in range(0,nwid - len(numbr )):
x = x + "0"
return x + str(numbr)
def createLink(self, listIm, fldr, tmpfldr, xtn, fpf,imx):
npad = int(re.findall("\d+", imx)[0])
count = 0
for filename in listIm:
inpt = os.path.join(tmpfldr,(fpf + "." + self.givenos(npad ,str(count)) + "." + xtn )).replace("\\","/")
count = count + 1
output = os.path.join(fldr, filename).replace("\\","/")
print 'inpt / output ',inpt , ' / ', output ,'\n'
self.kdll.CreateSymbolicLinkA(inpt , output, 0)
a = makeQuicktime()
if (cmds.file(query=True,sn=True,shn=True) == ""):
OpenMaya.MGlobal.displayError("file not saved/ either empty file or save file!")
else:
a.userWindow()
发布于 2014-08-09 09:36:47
免责声明:我还没有真正尝试运行您的代码,这都是通过检查完成的。不过,我觉得这里有足够的时间.
样式很重要;它使您的代码更易于阅读和理解。Python,并且(除非您跟踪的是另一个有一个风格指南 *),您应该遵循它,例如:
import
s布局不正确(您使用了来自types
的通配符导入,这是不推荐的,特别是因为您只需要NoneType
);lowercase_with_underscores
;以及UppercaseWords
。还有一个文档字符串指南 (顺便说一句,很高兴看到一些文档!);单行文档字符串应该放在一行上。还有更多的指令性风格,特别是当您使用某种自动文档系统(我喜欢谷歌风格),但这是一个很好的最低要求。
至少,我希望在整个过程中使用相同的样式,类和方法文档在类和方法中,包括位置(就在class
/def
行之后)和缩进(与第一行定义相同的级别)。
*如果您正在遵循不同的风格指南,请说明哪一个(并提供一个链接,如果有)。
一般来说,你似乎有很多长的,深嵌套的类和方法。尝试重构以保持每种方法的短、浅和单一用途(请参阅Python的禅宗;import this
)。不是每件事都必须在课堂上,也不是.
我在下面提出了一些更具体的问题。
makeQuicktime
这个类似乎做了许多与其名称无关的事情。考虑将所有文件夹-y的内容移到一个单独的类(或独立的函数)中。
firstImageCount
这似乎是代码中主要用于处理零填充数的几种方法之一,它们都采用不同的方法。写一个,然后从其他人那里调用它!您应该掌握str.format
和其他str
方法,这将使这种填充更加容易(而且,我认为,它比%
格式更清晰、更容易出错)。
另见makeQuicktime.setImageRegex
__,symlinkHouseKeep.givenos
__。
makeTempFolder
您在self.exepath = "D:/mayaslate/"
中定义了__init__
,然后在这里分配sysTemp = "D:/mayaslate"
。如果您更改了文件夹位置,那么现在您必须去两个地方寻找它(或者,更有可能的是,一个地方您会找到它,一个地方您会忘记它,导致错误)。
而不是返回0
或1
,而是使用Python的booleans、True
和False
。
selectFolder
这个方法非常长,并且做一些没有选择文件夹的事情。这应该被分成几个单独的方法,带有描述性的名称。
这一行:
if not isinstance(oldid,NoneType):
通常会写成:
if oldid is not None:
None
是一个单例,通过身份进行测试是合适的。
symlinkHouseKeep
这是一个更好的例子,在长度和焦点,渴望这与你的其他类!但是,属性和参数名称有点神秘,特别是在文档字符串已经消失的情况下。
运行脚本
脚本末尾的行(从a = makeQuicktime()
开始)通常由以下人员来保护:
if __name__ == '__main__':
以防止它们在不直接运行脚本时运行(例如,当您import
脚本时)。
发布于 2014-08-09 10:30:24
您的代码似乎需要Windows来运行,所以我无法亲自执行它。jonrsharpe已经做了相当彻底的分析。一些补充:
在这里:
def setImageRegex(self,imageCountVar):
"""
@setImageRegex: padding image count.
"""
if (len(imageCountVar) == 5):
irx = "%05d"
elif (len(imageCountVar) == 4):
irx = "%04d"
elif (len(imageCountVar) == 3):
irx = "%03d"
elif (len(imageCountVar) == 2):
irx = "%02d"
elif (len(imageCountVar) == 1):
irx = "%01d"
return irx
您正在返回irx,但如果imageCountVar
大于5或空,则可能不会定义。另外,您不需要存储它,您可以只返回它:
if (len(imageCountVar) == 5):
return "%05d"
if (len(imageCountVar) == 4):
return "%04d"
但是这是非常低效率的,因为你正在计算不连续几次变化的东西的长度。所以,你可以:
_len = len(imageCountVar)
if len == 5: # Note you don't need parenthesis
return "%05d"
...
但这既冗长又冗长。更聪明点!只需使用该信息构造字符串即可。
def setImageRegex(self,imageCountVar):
return '%0{}d'.format(len(imageCountVar))
您可能希望或不希望确保它在1,5范围内。即使字符串不是琐碎的,也可以这样缩短它:
def setImageRegex(self,imageCountVar):
return ['stringa_1', 'stringb_2', 'stringc_3'][len(imageCountVar) - 1]
在计算智能时,也可以使用相同的技巧:
wisper = '0' * (len(nc) - len(ic))
你用的空白行太多了。应该谨慎地使用它们来划分程序的逻辑块。例如,见:
print 'self.fileExtension : ',self.fileExtension,'\n'
self.backgroundImage = self.tempFolder + "/background.jpg"
self.thumbnailImage = self.tempFolder + "/thumbnail." + self.fileExtension
temp_02 = fName + "/" + sampleFileName
乍一看,甚至在阅读之前,我都不知道您在做什么,但我不敢相信每一行都是如此重要和不同,而其他行都应该有自己的代码块。而他们确实不是。您正在人为地扩展您的代码,并使其流的可读性降低。这里有一个更糟糕的例子:
ret = process.wait()
if (ret == 0):
args = ["ffmpeg",...
我会完全相反的:
ret = process.wait()
if (ret == 0):
args = ["ffmpeg",...
或者没有空白行,视情况而定。这使我想到另一条评论:
Python不需要为if
的参数添加括号。它的可读性更强:
if ret == 0:
因为更少的符号凌乱着景色。
您正在将注释符号放在第一列中。如果没有语法突出显示,很难将它们区分开来,您应该将它们放在下面:
# We are ready to do stuff:
do_stuff()
do_more_stuff()
cleanup() # This is to tidy up
^ ^
| L One space
L At least two spaces, you can freely use more. See:
# Making an example up:
a = 1 # width parameter
b = 2 # length parameter
tau = 3 # time parameter
另外,您还需要更多的注释来解释流程。对那里发生的事情进行一次文学概述。从来没有太多的评论。
https://codereview.stackexchange.com/questions/59563
复制相似问题