Maya Python - 将zip文件嵌入到maya文件中?

时间:2016-01-20 21:05:12

标签: python zip embed maya

这是另一个堆栈线程的建议,我终于回过头来了。这是关于如何将工具嵌入到maya文件中的讨论的一部分。

  

您可以将整个内容编写为python包,压缩它,然后将zip文件的二进制内容填充到fileInfo中。当您需要编码时,在用户的$ MAYA_APP_DIR中查找它;如果没有zip,请将fileInfo的内容作为zip写入磁盘,然后将zip插入sys.path

来源讨论是: python copy scripts into scriptMaya Python Create and Use Zipped Package?

到目前为止编程工作正常,但我认为我遇到了麻烦。当我尝试这个时:

with open("..directory/myZip.zip","rb") as file:
    cmds.fileInfo("myZip", file.read())

..然后我..

print cmds.fileInfo("myZip",q=1)

我得到了

  

[u'PK \ 003 \ 004 \ 024' ]

这是将zip文件作为文本文档读取时第一行乱码的错误翻译。

如何将我的zip文件作为二进制文件嵌入到我的maya文件中?

====================

更新: Maya不喜欢直接读取utf-8编码的zip文件来写入文件。我找到了各种方法使它成为可以写入的可接受的字符串,但是解码回文件似乎不起作用。我现在看到Theodox的建议是将它写成二进制文件并将其放在fileInfo节点中。

如何编码,存储然后解码以便稍后写入文件?

如果我要使用例如转换为二进制文件:

' '.join(format(ord(x), 'b') for x in line)

我需要使用哪些代码将其转换回原始的utf-8压缩信息?

3 个答案:

答案 0 :(得分:2)

您可以在此处找到相关代码:

http://tech-artists.org/forum/showthread.php?4161-Maya-API-Singleton-Nodes&highlight=mayapersist

相关位是

  import base64
  encoded = base64.b64encode(value)
  decoded = base64.b64decode(encoded)

基本上它是相同的想法,除了使用base64模块而不是binascii。任何将任意字符流转换为ascii-safe表示的方法都可以正常工作,只要你使用可逆方法:你需要注意的潜在问题是数据块中的一个字符,它看起来像是一个关闭引用 - 一个开放的引用int fileInfo将在MA文件中混乱。

此示例使用YAML执行任意键值对,但该部分与存储二进制内容无关。我已经将这种技术应用于相当大的数据(如果我记得的话,最高可达640k),但我不知道它是否有可以藏在Maya中的上限

答案 1 :(得分:0)

找到答案。堆栈溢出的好脚本。我不得不编码到' string_escape'这是我在试图找出整个角色情况时发现的东西。但无论如何,你打开zip,编码为' string_escape',将其写入fileInfo,然后在获取将其写回zip之前,将其解码回来。

Convert binary to ASCII and vice versa

import maya.cmds as cmds
import binascii

def text_to_bits(text, encoding='utf-8', errors='surrogatepass'):
    bits = bin(int(binascii.hexlify(text.encode(encoding, errors)), 16))[2:]
    return bits.zfill(8 * ((len(bits) + 7) // 8))

def text_from_bits(bits, encoding='utf-8', errors='surrogatepass'):
    n = int(bits, 2)
    return int2bytes(n).decode(encoding, errors)

def int2bytes(i):
    hex_string = '%x' % i
    n = len(hex_string)
    return binascii.unhexlify(hex_string.zfill(n + (n & 1)))

然后你可以

with open("..\maya\scripts/test.zip","rb") as thing:
    texty = text_to_bits(thing.read().encode('string_escape'))
    cmds.fileInfo("binaryZip",texty)

...后

with open("..\maya\scripts/test_2.zip","wb") as thing:
    texty = cmds.fileInfo("binaryZip",q=1)
    thing.write( text_from_bits( texty ).decode('string_escape') )

这似乎有效..到目前为止..

答案 2 :(得分:0)

想想我会为想要采用这种方法的人发布最终产品。我尝试进行一些损坏检查,以便在机器之间传递坏的zip。这就是所有检查哈希的目的。

def writeTimeFull(tl):
    import TimeFull
    #reload(TimeFull)
    with open(TimeFull.__file__.replace(".pyc",".py"),"r") as file:
        cmds.scriptNode( tl.scriptConnection[1][0], e=1, bs=file.read() )
    cmds.expression("spark_timeliner_activator",
                    e=1,s='if (Spark_Timeliner.ShowTimeliner == 1)\n'
                          '{\n'
                          '\tsetAttr Spark_Timeliner.ShowTimeliner 0;\n'
                          '\tpython \"Timeliner.InitTimeliner()\";\n'
                          '}',
                    o="Spark_Timeliner",ae=1,uc=all)

def checkHash(zipPath,hash1,hash2,hash3):
    check = False
    hashes = [hash1,hash2,hash3]
    for ii, hash in enumerate(hashes):
        if hash == hashes[(ii+1)%3]:
            hashes[(ii+2)%3] = hashes[ii]
            check = True
    if check:
        if md5(zipPath) == hashes[0]:
            return [zipPath,hashes[0],hashes[1],hashes[2]]
    else:
        cmds.warning("Hash checks and/or zip are corrupted. Attain toolbox_fix.zip, put it in scripts folder and restart.")
        return []

#this writes the zip file to the local users space
def saveOutZip(filename):
    if os.path.isfile(filename):
        if not os.path.isfile(filename.replace('_pkg','_'+__version__)):
            os.rename(filename,filename.replace('_pkg','_'+__version__))
    with open(filename,"w") as zipFile:
        zipInfo = cmds.fileInfo("zipInfo1",q=1)[0]
        zipHash_1 = cmds.fileInfo("zipHash1",q=1)[0]
        zipHash_2 = cmds.fileInfo("zipHash2",q=1)[0]
        zipHash_3 = cmds.fileInfo("zipHash3",q=1)[0]
        zipFile.write( base64.b64decode(zipInfo) )
        if checkHash(filename,zipHash_1,zipHash_2,zipHash_3):
            cmds.fileInfo("zipInfo2",zipInfo)
            return filename
    with open(filename,"w") as zipFile:
        zipInfo = cmds.fileInfo("zipInfo2",q=1)[0]
        zipHash_1 = cmds.fileInfo("zipHash1",q=1)[0]
        zipHash_2 = cmds.fileInfo("zipHash2",q=1)[0]
        zipHash_3 = cmds.fileInfo("zipHash3",q=1)[0]
        zipFile.write( base64.b64decode(zipInfo) )
        if checkHash(filename,zipHash_1,zipHash_2,zipHash_3):
            cmds.fileInfo("zipInfo1",zipInfo)
            return filename
    return False

#this writes the local zip to this file
def loadInZip(filename):
    zipResults = []
    for ii in range(0,10):
        with open(filename,"r") as theRead:
            zipResults.append([base64.b64encode(theRead.read())]+checkHash(filename,md5(filename),md5(filename),md5(filename)))
        if ii>0 and zipResults[ii]==zipResults[ii-1]:
            cmds.fileInfo("zipInfo1",zipResults[ii][0])
            cmds.fileInfo("zipInfo2",zipResults[ii-1][0])
            cmds.fileInfo("zipHash1",zipResults[ii][2])
            cmds.fileInfo("zipHash2",zipResults[ii][3])
            cmds.fileInfo("zipHash3",zipResults[ii][4])
            return True

#file check
#http://stackoverflow.com/questions/3431825/generating-a-md5-checksum-of-a-file
def md5(fname):
    import hashlib
    hash = hashlib.md5()
    with open(fname, "rb") as f:
        for chunk in iter(lambda: f.read(4096), b""):
            hash.update(chunk)
    return hash.hexdigest()

filename = path+'/toolbox_pkg.zip'
zipPaths = [path+'/toolbox_update.zip',
            path+'/toolbox_fix.zip',
            path+'/toolbox_'+__version__+'.zip',
            filename]
zipPaths_exist = [os.path.isfile(zipPath) for zipPath in zipPaths ]

if any(zipPaths_exist[:2]):
    if zipPaths_exist[0]:
        cmds.warning('Timeliner update present. Forcing file to update version')
        if zipPaths_exist[2]:
            os.remove(zipPaths[3])
        elif os.path.isfile(zipPaths[3]):
            os.rename(zipPaths[3], zipPaths[2])
        os.rename(zipPaths[0],zipPaths[3])
        if zipPaths_exist[1]:
            os.remove(zipPaths[1])
    else:
        cmds.warning('Timeliner fix present. Replacing file to the fix version.')
        if os.path.isfile(zipPaths[3]):
            os.remove(zipPaths[3])
        os.rename(zipPaths[1],zipPaths[3])
    loadInZip(filename)

if not cmds.fileInfo("zipInfo1",q=1) and not cmds.fileInfo("zipInfo2",q=1):
    loadInZip(filename)

if not os.path.isfile(filename):
    saveOutZip(filename)

sys.path.append(filename)
import Timeliner
Timeliner.InitTimeliner(theVers=__version__)

if not any(zipPaths[:2]):
    if __version__ > Timeliner.__version__:
        cmds.warning('Saving out newer version of timeliner to local machine. Restart Maya to access latest version.')
        saveOutZip(filename)
    elif __version__ < Timeliner.__version__:
        cmds.warning('Timeliner on machine is newer than file version. Saving machine version over timeliner in file.')
        loadInZip(filename)
        __version__ = Timeliner.__version__

if __name__ != "__main__":
    tl = getTimeliner()
    writeTimeFull(tl)