public static Supported3DFiles CheckFileType(ModelFileData fileData) { byte[] byteBuffer = new byte[100]; if (fileData.HasBytes()) { // Has enough bytes? if (!fileData.ReadBytes(byteBuffer, 0, 0, byteBuffer.Length)) { return(Supported3DFiles.Unsuportted); } // Check if some evil being renamed some PNG file to one of the supported formats. if (byteBuffer[0] == 137 && byteBuffer[1] == 80 && byteBuffer[2] == 78 && byteBuffer[3] == 71 && byteBuffer[4] == 13 && byteBuffer[5] == 10 && byteBuffer[6] == 26 && byteBuffer[7] == 10) { return(Supported3DFiles.Unsuportted); } // Or maybe a JPG. if (byteBuffer[0] == 0xFF && byteBuffer[1] == 0xD8 && byteBuffer[2] == 0xFF) { return(Supported3DFiles.Unsuportted); } } if (fileData.FileName.EndsWith(".stl", StringComparison.InvariantCultureIgnoreCase)) { if (!fileData.HasBytes()) { return(Supported3DFiles.STL_Binary); // Return default STL format. } // If doesnt start with "solid", its always binary. if (!(Encoding.ASCII.GetString(byteBuffer, 0, 5) == "solid")) { return(Supported3DFiles.STL_Binary); } // EXCEPT, that some binary files also start with solid, so check the header and wish bad omen to whoever created such files. string header = Encoding.ASCII.GetString(byteBuffer, 0, 100); for (int i = 0; i < header.Length; i++) { if (Char.IsControl(header[i]) && header[i] != '\r' && header[i] != '\n') { return(Supported3DFiles.STL_Binary); } } return(Supported3DFiles.STL_ASCII); } else if (fileData.FileName.EndsWith(".obj", StringComparison.InvariantCultureIgnoreCase)) { return(Supported3DFiles.OBJ); } if (fileData.FileName.EndsWith(".3mf", StringComparison.InvariantCultureIgnoreCase)) { return(Supported3DFiles._3MF); } else { return(Supported3DFiles.Unsuportted); } }
static Mesh3D ParseSTLBinary(ModelFileData fileData) { // STL Binary Format: https://en.wikipedia.org/wiki/STL_(file_format)#Binary_STL if (!fileData.HasBytes()) { return(null); } byte[] byteBuffer = new byte[4 * 9]; int index = 80; int byteBufferIndex = 0; fileData.ReadBytes(byteBuffer, index, 0, 4); int triangleAmount = (int)System.BitConverter.ToUInt32(byteBuffer, 0); index += 4; if (triangleAmount <= 0 || fileData.BytesLength < 80 + triangleAmount * 50) { return(null); } try { if (triangleAmount <= 0 || triangleAmount > 10000000) { throw new Exception("The STLBinary file has too many triangles."); } SegmentedArray <int> triangles = new SegmentedArray <int>(triangleAmount * 3); SegmentedArray <Mesh3D.Vertexh> vertices = new SegmentedArray <Mesh3D.Vertexh>(triangleAmount * 3); for (int i = 0; i < triangles.Length;) { // Skip reading the facet normal (why STL come with normals???). index += 4 * 3; // Triangle vertices { fileData.ReadBytes(byteBuffer, index, 0, byteBuffer.Length); byteBufferIndex = 0; index += 4 * 9; vertices[i] = new Mesh3D.Vertexh( (Half)System.BitConverter.ToSingle(byteBuffer, byteBufferIndex), (Half)System.BitConverter.ToSingle(byteBuffer, byteBufferIndex += 4), (Half)System.BitConverter.ToSingle(byteBuffer, byteBufferIndex += 4) ); triangles[i] = i++; vertices[i] = new Mesh3D.Vertexh( (Half)System.BitConverter.ToSingle(byteBuffer, byteBufferIndex += 4), (Half)System.BitConverter.ToSingle(byteBuffer, byteBufferIndex += 4), (Half)System.BitConverter.ToSingle(byteBuffer, byteBufferIndex += 4) ); triangles[i] = i++; vertices[i] = new Mesh3D.Vertexh( (Half)System.BitConverter.ToSingle(byteBuffer, byteBufferIndex += 4), (Half)System.BitConverter.ToSingle(byteBuffer, byteBufferIndex += 4), (Half)System.BitConverter.ToSingle(byteBuffer, byteBufferIndex += 4) ); triangles[i] = i++; } // Skip the remaining bytes. index += 2; } return(new Mesh3D(vertices, triangles)); } catch (Exception ex) { logger.Trace(ex, "Exception when processing file: {FileName}, {FileSizeKB}, {FileType}", fileData.FileName, fileData.FileSizeKB, fileData.FileType.ToString()); return(null); } }