0

I want to generate binary vtk file.

I write a code that can first generate correct ascii vtk file, then do some modification on that, let it can generate correct binary vtk file.

I face the problem when convert first acsii to binary, see the if switch in follow code.

#include <fstream>
int main()
{
    std::ofstream fout;
    bool is_binary = true;
    fout.open("new.vtu");
    fout << "<?xml version=\"1.0\"?>\n";
    fout << "<VTKFile type=\"UnstructuredGrid\" version=\"0.1\" byte_order=\"LittleEndian\" compressor=\"vtkZLibDataCompressor\">\n";
    fout << "<UnstructuredGrid>\n";
    fout << "<Piece NumberOfPoints=\"4\" NumberOfCells=\"2\">\n";
    fout << "<PointData Scalars=\"\" Vectors=\"\">\n";

    if (is_binary)
    {
        fout << "<DataArray type=\"Float64\" Name=\"solution\" NumberOfComponents=\"3\" format=\"binary\">\n";
        double x[] = {56.25, 6.25, 0, 100, 6.25, 0, 56.25, 0, 0, 100, 0, 0};
        for (int i = 0; i < 12; i++)
        {
            double value = x[i];
            fout.write((char *)(&value), sizeof(double));
        }
        fout << "\n";
    }
    else
    {
        fout << "<DataArray type=\"Float64\" Name=\"solution\" NumberOfComponents=\"3\" format=\"ascii\">\n";
        fout << "56.25 6.25 0\n";
        fout << "100 6.25 0\n";
        fout << "56.25 0 0\n";
        fout << "100 0 0\n";
    }

    fout << "</DataArray>\n";
    fout << "</PointData>\n";
    fout << "<Points>\n";
    fout << "<DataArray type=\"Float64\" NumberOfComponents=\"3\" format=\"ascii\">\n";
    fout << "7.5 2.5 0\n";
    fout << "10 2.5 0\n";
    fout << "7.5 0 0\n";
    fout << "10 0 0\n";
    fout << "</DataArray>\n";
    fout << "</Points>\n";
    fout << "<Cells>\n";
    fout << "<DataArray type=\"Int32\" Name = \"connectivity\" format=\"ascii\">\n";
    fout << "0 2 1\n";
    fout << "1 2 3\n";
    fout << "</DataArray>\n";
    fout << "<DataArray type=\"Int32\" Name = \"offsets\" format=\"ascii\">\n";
    fout << "3\n";
    fout << "6\n";
    fout << "</DataArray>\n";
    fout << "<DataArray type=\"Int8\" Name = \"types\" format=\"ascii\">\n";
    fout << "5\n";
    fout << "5\n";
    fout << "5\n";
    fout << "5\n";
    fout << "</DataArray>\n";
    fout << "</Cells>\n";
    fout << "</Piece>\n";
    fout << "</UnstructuredGrid>\n";
    fout << "</VTKFile>\n";
    fout.close();
    return 0;
}

if is_binary = false, the code can generate correct vtk file, but if is_binary = true, the code can not generate correct vtk file.

If I open the vtk file with paraview, it complains that:

Error parsing the XMKL in stream at line 7, column 0, bute index 311: not well-formed(invalid token)

Visit also can not open my file.

the code is compiled with g++ main.cpp, and my machine is little endian.

I have already see many topic

Can any one help me? But I still can not figure out what I am doing wrong.

Thanks for your time.

append

Thanks for sir Botje give the suggestion the base64 encoding should be used.

Now I have using the base64 encoding, but there still exist the bug.

The base64.h is copied from https://github.com/superwills/NibbleAndAHalf/blob/master/NibbleAndAHalf/base64.h

#include <fstream>
#include <iostream>
#include "base64.h"
int main()
{
    std::ofstream fout;
    bool is_binary = true;
    fout.open("new.vtu",  std::ios::binary);
    fout << "<?xml version=\"1.0\"?>\n";
    fout << "<VTKFile type=\"UnstructuredGrid\" version=\"0.1\" byte_order=\"LittleEndian\" compressor=\"vtkZLibDataCompressor\">\n";
    fout << "<UnstructuredGrid>\n";
    fout << "<Piece NumberOfPoints=\"4\" NumberOfCells=\"2\">\n";
    fout << "<PointData Scalars=\"\" Vectors=\"\">\n";

    if (is_binary)
    {
        fout << "<DataArray type=\"Float64\" Name=\"solution\" NumberOfComponents=\"3\" format=\"binary\">\n";
        double x[] = {56.25, 6.25, 0, 100, 6.25, 0, 56.25, 0, 0, 100, 0, 0};
        int result_size;
        char *encoding = base64((char *)x, sizeof(double) * 12, &result_size);
        std::cout << result_size << std::endl;
        fout.write(encoding, result_size);
        free(encoding);
    }
    else
    {
        fout << "<DataArray type=\"Float64\" Name=\"solution\" NumberOfComponents=\"3\" format=\"ascii\">\n";
        fout << "56.25 6.25 0\n";
        fout << "100 6.25 0\n";
        fout << "56.25 0 0\n";
        fout << "100 0 0\n";
    }

    fout << "</DataArray>\n";
    fout << "</PointData>\n";
    fout << "<Points>\n";
    fout << "<DataArray type=\"Float64\" NumberOfComponents=\"3\" format=\"ascii\">\n";
    fout << "7.5 2.5 0\n";
    fout << "10 2.5 0\n";
    fout << "7.5 0 0\n";
    fout << "10 0 0\n";
    fout << "</DataArray>\n";
    fout << "</Points>\n";
    fout << "<Cells>\n";
    fout << "<DataArray type=\"Int32\" Name = \"connectivity\" format=\"ascii\">\n";
    fout << "0 2 1\n";
    fout << "1 2 3\n";
    fout << "</DataArray>\n";
    fout << "<DataArray type=\"Int32\" Name = \"offsets\" format=\"ascii\">\n";
    fout << "3\n";
    fout << "6\n";
    fout << "</DataArray>\n";
    fout << "<DataArray type=\"Int8\" Name = \"types\" format=\"ascii\">\n";
    fout << "5\n";
    fout << "5\n";
    fout << "5\n";
    fout << "5\n";
    fout << "</DataArray>\n";
    fout << "</Cells>\n";
    fout << "</Piece>\n";
    fout << "</UnstructuredGrid>\n";
    fout << "</VTKFile>\n";
    fout.close();
    return 0;
}

Xu Hui
  • 1,213
  • 1
  • 11
  • 24

1 Answers1

2

You cannot dump binary garbage in an XML file and expect it to work!

A quick Google search on vtk file format tells me that you need to base64-encode your floats into XML-safe characters first for format="binary".

You can find many (header-only) base64 libraries on the internet, and I'm sure StackOverflow has a couple ready-to-steal implementations.

Botje
  • 26,269
  • 3
  • 31
  • 41
  • Sir, thanks for your advice. Now I have a look at the base64 encoding, and I modified my code. I still find the file still not in the correct format. Could you please give me another help? Sorry for my stupidity. – Xu Hui Oct 26 '20 at 09:17
  • What is "the bug" now, then? I don't think your XML reader is complaining about invalid bytes anymore. – Botje Oct 26 '20 at 09:27
  • Sir, now the error is `Can not read point data array "solution" for PointData in piece 0. The data array in the element may be too short`. – Xu Hui Oct 26 '20 at 09:35
  • Shrug. No idea. Does the file pass regular XML VTK validation? – Botje Oct 26 '20 at 10:02
  • I do not know how to pass the validation, I just generate the file and open it by paraview. then above bug happens. – Xu Hui Oct 26 '20 at 10:03
  • 1
    Try a different tool and see if it gives you more detail. – Botje Oct 26 '20 at 10:05