Search code examples
pythonfileserializationbinaryply

Binary PLY file I wrote causes meshlab to crash


I wrote a piece of python code which can serialize a mesh as either an ascii or binary PLY file. I can open the generated ascii files in MeshLab just fine. The generated binary files causes MeshLab to crash, however (it just segfaults). I was not able to open the files in Blender either. I'm having troubles understanding why MeshLab crashes, because as far as I understand, I am adhering to the header that I wrote. Here is the offending code:

def write_ply(mesh, filename, binary=True):
    """
    Output the mesh object as an ASCII .ply file, or as a little endian binary file.
    """
    header = "comment This file was generated by the SurfacePy library\n"
    header += "element vertex {0}\n".format(len(mesh.vertices))
    header += "property float x\nproperty float y\nproperty float z\n"
    header += "element face {0}\n".format(len(mesh.triangles))
    header += "property list uchar int vertex_indices\n"
    header += "end_header\n"
    with open(filename, 'wb') as file:
        if binary==True:
            file.write(__pack_string("ply\nformat binary_little_endian 1.0\n"))
        else:
            file.write(__pack_string("ply\nformat ascii 1.0\n"))
        file.write(__pack_string(header))
        if binary==True:
            for vert in mesh.vertices:
                file.write(struct.pack('<fff', vert.x, vert.y, vert.z))
            for tri in mesh.triangles:
                file.write(struct.pack('<Biii', ord('3'), tri.i1, tri.i3, tri.i2))
        else:
            for vert in mesh.vertices:
                file.write(__pack_string("{0}\n".format(vert)))
            for tri in mesh.triangles:
                file.write(__pack_string("3 {0} {1} {2}\n".format(tri.i1, tri.i3, tri.i2)))


def __pack_string(str):
    """
    Returns a bytes object of a string, in little-endian format.
    """
    chars = [c.encode('utf-8') for c in str]
    fmt = "<{0}".format(''.join(['c' for i in range(0, len(chars))]))
    return __pack(fmt, chars)



def __pack(fmt, args):
    return struct.pack(fmt, *args)

Am I writing the bytes incorrectly?


Solution

  • This one was actually trivial to solve. I was storing the property list count type as uchar, but the integer should have been written directly into the uchar, and not converted from a char as I did.

    So I should do struct.pack('<Biii', 3, ... and NOT struct.pack('<Biii', ord('3'), ...