3

I'm having some difficulties while parsing a binary STL file with Python (2.7.1 32-bit and Windows 7 64). The file is a about 450k in size, but my parser suddenly stops working after parsing 244 triangles out of ~8600 with en exception of struct.unpack:

Exception unpack requires a string argument of length 12

The cursor position in the file is line 33, row 929. But the line contains about 3400 characters. So it doesn't seem to be newline problem.

This is the code:

import struct

normals = []
points = []
triangles = []
bytecount = []

fb = [] # debug list

def unpack (f, sig, l):
    s = f.read (l)
    fb.append(s)
    return struct.unpack(sig, s)

def read_triangle(f):
    n = unpack(f,"<3f", 12)
    p1 = unpack(f,"<3f", 12)
    p2 = unpack(f,"<3f", 12)
    p3 = unpack(f,"<3f", 12)
    b = unpack(f,"<h", 2)

    normals.append(n)
    l = len(points)
    points.append(p1)
    points.append(p2)
    points.append(p3)
    triangles.append((l, l+1, l+2))
    bytecount.append(b[0])


def read_length(f):
    length = struct.unpack("@i", f.read(4))
    return length[0]

def read_header(f):
    f.seek(f.tell()+80)

def write_as_ascii(outfilename):
    f = open(outfilename, "w")
    f.write ("solid "+outfilename+"\n")
    for n  in range(len(triangles)):
        f.write ("facet normal {} {} {}\n".format(normals[n][0],normals[n][1],normals[n][2]))
        f.write ("outer loop\n")
        f.write ("vertex {} {} {}\n".format(points[triangles[n][0]][0],points[triangles[n][0]][1],points[triangles[n][0]][2]))
        f.write ("vertex {} {} {}\n".format(points[triangles[n][1]][0],points[triangles[n][1]][1],points[triangles[n][1]][2]))
        f.write ("vertex {} {} {}\n".format(points[triangles[n][2]][0],points[triangles[n][2]][1],points[triangles[n][2]][2]))
        f.write ("endloop\n")
        f.write ("endfacet\n")
    f.write ("endsolid "+outfilename+"\n")
    f.close()

def main():
    infilename = r"cupHemis46_28.stl"
    outfilename = r"cupHemis46_28_ascii_test.stl"

    try:
        f = open ( infilename, "r")

        read_header(f)
        l = read_length(f)
        try:
            while True:
                read_triangle(f)
        except Exception, e:
            print "Exception",e[0]
        print len(normals), len(points), len(triangles), l
        write_as_ascii(outfilename)

    except Exception, e:
        print e


if __name__ == '__main__':
    main()

The unpack function (not from struct) collects all the strings which will be written to a file. When I compare both file they seem equal, up to the file position where unpack stops working. I opened the binary file with Notepad++, the next character is a "SUB".

Are there any restrictions of unpack that I'm not aware of regarding file size or limitation in characters or something? Is there something wrong with my code? Thanks in advance.

3
  • Then I recommend this hard to find wikipedia page en.wikipedia.org/wiki/STL_%28file_format%29. It's not a good file format, but almost every 3D viewer software or visualization toolkit knows and handles it which result in a wide distribution. Commented Sep 27, 2011 at 14:41
  • can you explain where you are calling f.read() twice? is it in the read_length function? Or have you already edited the code from what it once was. I have tried running this and get the same error Commented Mar 18, 2013 at 18:29
  • I think I already edited the code, see the log for my question for changes. The answer to my question was the second part of Marcelo Cantos reply, my original code opened the file in ascii and found an eof pretty early. If you open it in binary mode (see answer below), it works. Commented Mar 18, 2013 at 19:15

1 Answer 1

10

Your unpack function calls f.read twice. I suspect you've walked off the end of the file.

You'll also have trouble with reading the file in text mode on Windows. Any incidental occurrences of \r\n will be read in as \n. Make the following change to avoid this problem.

f = open(infilename, "rb")
Sign up to request clarification or add additional context in comments.

3 Comments

You're right, but it a c&p mistake on my side. I'll edit the code. Even if read the data twice I should be able to parse 4000 triangles out of 8000, not 250
The second part worked, I didn't open the file in binary mode. Thank you very much.
Good to hear! I was scratching my head, then I remembered that in Windows, a ^Z (ASCII 27) in the stream is interpreted as EOF. You must have hit one fairly early.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.