OME Files in C++: Invalid OME-XML document

Hi!

I am working on a C++ library that integrates the ome-files library.
In order to write my pixel data to an ome.tiff file, I’m closely following the example code from the tutorial: https://docs.openmicroscopy.org/ome-files-cpp/0.5.0/ome-files/manual/html/_downloads/metadata-formatwriter.cpp

Reading the tiff files works fine, and writing them also results in a correct ome.tiff file which I can open and view with ImageJ. However, when closing the writer, I get the following error message: Caught exception: Invalid OME-XML document. Also, when I use ImageJ to see the metadata, the DimensionOrder is messed up.

Any help on this would be very much appreciated!

Cheers

Hi @luco, is your code available anywhere to view?
If you run the xmlvalid tool (https://docs.openmicroscopy.org/bio-formats/6.5.1/users/comlinetools/xml-validation.html) what validation errors are you seeing?

Hi @dgault. Thanks for your response!
I cannot share the full git repo ATM, but let me show you what my code looks like:

shared_ptr<OMEXMLMetadata> createMetadata(HistData &data){

    auto meta = make_shared<OMEXMLMetadata>();
    std::vector<shared_ptr<CoreMetadata>> seriesList;
    shared_ptr<CoreMetadata> core(make_shared<CoreMetadata>());

    seriesList.clear();

    core->sizeX = sqrt(data.dataRows);
    core->sizeY = sqrt(data.dataRows);
    core->sizeZ = 1U;
    core->sizeC.clear(); // defaults to 1 channel with 1 subchannel; clear this
    core->sizeC.push_back(1U); // replace with single black/white channel
    core->sizeT = data.dataCols;
    core->pixelType = ome::xml::model::enums::PixelType::UINT16;
    core->interleaved = false;
    core->bitsPerPixel = 12U;
    core->dimensionOrder = DimensionOrder::XYZTC;

    seriesList.push_back(core);

    fillMetadata(*meta, seriesList);
    return meta;
  }

void writePixelData(FormatWriter& writer, std::ostream& stream, HistData &data){
    // Total number of images (series)
    dimension_size_type ic = writer.getMetadataRetrieve()->getImageCount();
    stream << "Image count: " << ic << '\n';

    // Loop over images
    for (dimension_size_type i = 0 ; i < ic; ++i)
      {
        // Change the current series to this index
        writer.setSeries(i);

        // Get meta data and print to console
        int resX = writer.getMetadataRetrieve()->getPixelsSizeX(i);
        int resY = writer.getMetadataRetrieve()->getPixelsSizeY(i);
        int resT = writer.getMetadataRetrieve()->getPixelsSizeT(i);
        std::cout << "\tSizeX = " << resX << std::endl;
        std::cout << "\tSizeY = " << resY << std::endl;
        std::cout << "\tSizeZ = " <<  writer.getMetadataRetrieve()->getPixelsSizeZ(i) << std::endl;
        std::cout << "\tSizeT = " <<  writer.getMetadataRetrieve()->getPixelsSizeT(i) << std::endl;
        std::cout << "\tChannelCount = " <<  writer.getMetadataRetrieve()->getChannelCount(i) << std::endl;

          // Total number of planes.
        dimension_size_type pc = 1U;
        pc *= writer.getMetadataRetrieve()->getPixelsSizeZ(i);
        pc *= writer.getMetadataRetrieve()->getPixelsSizeT(i);
        pc *= writer.getMetadataRetrieve()->getChannelCount(i);
        stream << "\tPlane count: " << pc << '\n';

        // Loop over planes (for this image index)
        for (dimension_size_type p = 0 ; p < pc; ++p)
        {
            // Pixel buffer
            shared_ptr<PixelBuffer<PixelProperties<PixelType::UINT16>::std_type>>
              buffer(make_shared<PixelBuffer<PixelProperties<PixelType::UINT16>::std_type>>
                     (boost::extents[resX][resY][1][1][1][1][1][1][1],
                      PixelType::UINT16, ome::files::ENDIAN_LITTLE,
                      PixelBufferBase::make_storage_order(DimensionOrder::XYZTC, false)));


            // Fill pixel buffer with pixel data from HistData object
            for (dimension_size_type x = 0; x < resX; ++x)
                for (dimension_size_type y = 0; y < resY; ++y)
                {
                    dimension_size_type idx_data = x + y*resX;

                    PixelBufferBase::indices_type idx;
                    std::fill(idx.begin(), idx.end(), 0);
                    idx[DIM_SPATIAL_X] = x;
                    idx[DIM_SPATIAL_Y] = y;
                    buffer->at(idx) = data.data[idx_data][p];
                  }

          VariantPixelBuffer varBuffer(buffer);
            stream << "PixelBuffer PixelType is " << buffer->pixelType() << '\n';
            stream << "VariantPixelBuffer PixelType is " << varBuffer.pixelType() << '\n';
            stream << std::flush;

            // Write the the entire pixel buffer to the plane.
            writer.saveBytes(p, varBuffer);
            stream << "Wrote " << buffer->num_elements() << ' '
                   << buffer->pixelType() << " pixels in plane number " << p << "\n";
          }
      }
  }

in the file calling these functions:

void histWriteOMETiff_0_2(HistData &data, FILE *file, const char *filepath)
{
    ome::common::setLogLevel(ome::logging::trivial::warning);

    try {
        // Portable path
        path filename(filepath);

        // Create minimal metadata for the file to be written.
        auto meta = createMetadata(data);

        //addExtendedMetadata(meta);

        // Create TIFF writer
        auto writer = make_shared<OMETIFFWriter>();

        // Set writer options before opening a file
        auto retrieve = static_pointer_cast<MetadataRetrieve>(meta);
        writer->setMetadataRetrieve(retrieve);
        writer->setInterleaved(false);


        // Open the file
        writer->setId(filename);

        // Write pixel data
        writePixelData(*writer, std::cout, data);

        // Explicitly close writer
       
        writer->close(false);
    }
    catch (const std::exception& e)
    {
        std::cerr << "Caught exception: " << e.what() << '\n';
        std::exit(1);
    }
    catch (...)
    {
        std::cerr << "Caught unknown exception\n";
        std::exit(1);
    }
}

The output from xmlvalid:
Parsing schema path

Error parsing schema path from /Users/lukascodispoti/Documents/UZH/flim-control/buffers/test5_v0-2_Circular.ome.tiff

org.xml.sax.SAXParseException: Content is not allowed in prolog.

at org.apache.xerces.util.ErrorHandlerWrapper.createSAXParseException(Unknown Source) ~[bioformats_package.jar:6.5.1]

at org.apache.xerces.util.ErrorHandlerWrapper.fatalError(Unknown Source) ~[bioformats_package.jar:6.5.1]

at org.apache.xerces.impl.XMLErrorReporter.reportError(Unknown Source) ~[bioformats_package.jar:6.5.1]

at org.apache.xerces.impl.XMLErrorReporter.reportError(Unknown Source) ~[bioformats_package.jar:6.5.1]

at org.apache.xerces.impl.XMLScanner.reportFatalError(Unknown Source) ~[bioformats_package.jar:6.5.1]

at org.apache.xerces.impl.XMLDocumentScannerImpl$PrologDispatcher.dispatch(Unknown Source) ~[bioformats_package.jar:6.5.1]

at org.apache.xerces.impl.XMLDocumentFragmentScannerImpl.scanDocument(Unknown Source) ~[bioformats_package.jar:6.5.1]

at org.apache.xerces.parsers.XML11Configuration.parse(Unknown Source) ~[bioformats_package.jar:6.5.1]

at org.apache.xerces.parsers.XML11Configuration.parse(Unknown Source) ~[bioformats_package.jar:6.5.1]

at org.apache.xerces.parsers.XMLParser.parse(Unknown Source) ~[bioformats_package.jar:6.5.1]

at org.apache.xerces.parsers.AbstractSAXParser.parse(Unknown Source) ~[bioformats_package.jar:6.5.1]

at org.apache.xerces.jaxp.SAXParserImpl$JAXPSAXParser.parse(Unknown Source) ~[bioformats_package.jar:6.5.1]

at org.apache.xerces.jaxp.SAXParserImpl.parse(Unknown Source) ~[bioformats_package.jar:6.5.1]

at java.xml/javax.xml.parsers.SAXParser.parse(SAXParser.java:197) ~[na:na]

at loci.common.xml.XMLTools.validateXML(XMLTools.java:811) ~[bioformats_package.jar:6.5.1]

at loci.common.xml.XMLTools.validateXML(XMLTools.java:785) ~[bioformats_package.jar:6.5.1]

at loci.formats.tools.XMLValidate.validate(XMLValidate.java:67) ~[bioformats_package.jar:6.5.1]

at loci.formats.tools.XMLValidate.validate(XMLValidate.java:104) ~[bioformats_package.jar:6.5.1]

at loci.formats.tools.XMLValidate.main(XMLValidate.java:125) ~[bioformats_package.jar:6.5.1]

Thanks again!

Thanks for code snippets. The exception from the xmlvalid tool is an odd one, it leads me to think it may be due to and encoding issue or the xml somehow becoming malformed rather than missing metadata.

If you run the bfconvert tool like below is it able to complete or does it just give you the same stack trace as xmlvalid?
bfconvert -nopix -omexml path/to/myFile.ome.tiff

If it does not provide the XML can you open a small sample file and copy the first few lines of the XML from within the file, i suspect the first 2 lines as below may be enough:

<?xml version="1.0" encoding="UTF-8"?>

<OME xmlns="http://www.openmicroscopy.org/Schemas/OME/2016-06" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.openmicroscopy.org/Schemas/OME/2016-06 http://www.openmicroscopy.org/Schemas/OME/2016-06/ome.xsd">

Hi @dgault. Thanks for the support! It’s good to know that there is someone out there.

I believe that there was something wrong with the build that I was using.

After downloading the 0.6.0 release and building it myself, my code works like a charm.

Cheers!

1 Like