# Importing Files

HOOPS Visualize Desktop can load a variety of different 2D and 3D file formats. If HOOPS Exchange is also licensed, the list of importable file formats is extended even further (See HOOPS Exchange Supported Format). Regardless of which type of file you are loading, HOOPS Visualize Desktop uses a common pattern to load all files. There are four basic steps:

1. Use an import options kit to set the file load options.
2. Load the file. Using a notifier is highly recommended, but not required. All files are loaded asynchronously.
3. Take appropriate action based on the status of the notifier.
4. Respond to any errors or exceptions.

## General Import Example

The following example loads a HOOPS Stream File (HSF). HSF is the native file format for HOOPS Visualize Desktop. An HSF contains all model information as well as its related scene hierarchy that can be used to save and load complete scenes. The data is stored in a compressed format. HSFs are loaded using the `Stream` class. Other file formats use a similar class. For example, to load an STL file, you would use the `STL` class. It is recommended to make use of a notifier during file loading. Notifiers are available for all file types - their purpose is to track loading progress:

        HPS::Stream::ImportNotifier importNotifier;

        try {
            HPS::Stream::ImportOptionsKit importOptionsKit;
            importOptionsKit.SetSegment(mySegmentKey); // set destination segment

            importNotifier = HPS::Stream::File::Import(filename, importOptionsKit);

            // the notifier can be used to check the load progress
            float percent_complete;
            importNotifier.Status(percent_complete);

            // pauses this thread until the HSF is finished loading
            importNotifier.Wait();
        }
        catch (HPS::IOException ioe) {
            // handle exception
            throw;
        }

    HPS.Stream.ImportNotifier notifier = new HPS.Stream.ImportNotifier();

    try
    {
        HPS.Stream.ImportOptionsKit importOptionsKit = new HPS.Stream.ImportOptionsKit();
        importOptionsKit.SetSegment(mySegmentKey); // set destination segment

        notifier = HPS.Stream.File.Import(filename, importOptionsKit);

        // the notifier can be used to check the load progress
        float percent_complete;
        notifier.Status(out percent_complete);

        // pauses this thread until the HSF is finished loading
        notifier.Wait();
    }
    catch (HPS.IOException ioe)
    {
        // handle exception
    }

This snippet demonstrates the use of `Wait()` on your notifier object. Because all notifier classes do their I/O in a separate thread, the potential exists to use the object before it is done loading, especially if you try to interact with it immediately after you call `Import()`. Calling `Wait()` ensures the I/O operation is complete before continuing. If you do not use `Wait()`, you could end up with unexpected behavior.

After the file load is finished, you should test the result of the load operation to ensure there was not an unexpected failure:

        HPS::IOResult ioResult = importNotifier.Status();

        if (ioResult == HPS::IOResult::Success) {
            // good
        }
        else {
            // bad
            throw;
        }

    HPS.IOResult ioResult = notifier.Status();

    if (ioResult == HPS.IOResult.Success)
    {
        // good
    }
    else
    {
        // bad
    }

Assuming the file was loaded correctly, you can get information about the model by querying the associated `HPS::Stream::ImportResultsKit`.

        HPS::Stream::ImportResultsKit importResultsKit = importNotifier.GetResults();

        // get the default camera of the model
        importResultsKit.ShowDefaultCamera(cameraKit);

        // get the segment this model was loaded into
        importResultsKit.ShowSegment(someSegment);

    HPS.Stream.ImportResultsKit importResultsKit = notifier.GetResults();

    // get the default camera of the model
    importResultsKit.ShowDefaultCamera(out cameraKit);

    // get the segment this model was loaded into
    importResultsKit.ShowSegment(out someSegment);

NOTE: For HSF files, any user options contained within will be UTF8 encoded and stored as user data.

IMPORTANT: During the import process, if you did not use the `HPS::Stream::ImportOptionsKit` to specify a destination segment, HOOPS Visualize Desktop will create a root segment and place the model there. In this case, to display the model it is necessary to call `ShowSegment` (as shown in the previous code snippet) in order to get the key of the segment where the model was loaded. After locating the model, it can be included into the tree for rendering. See `HPS::Stream::ImportOptionsKit::SetAlternateRoot`.

This general behavior also applies to portfolios. If a portfolio is not specified using `HPS::Stream::ImportOptionsKit::SetPortfolio`, HOOPS Visualize Desktop will create a portfolio for any definitions that need to be created during the import. The location of the portfolio can be shown by calling `HPS::Stream::ImportResultsKit::ShowPortfolio`.

### Canceling the Import

If the file import is taking too much time, the user changes his mind about loading the file, or your application detects it is running out of memory, you have the ability to cancel a file import.

            importNotifier = HPS::Stream::File::Import(filename, importOptionsKit);

            // cancel the import
            importNotifier.Cancel();

            // wait for the cancellation to finish
            importNotifier.Wait();

            // test for the IOResult
            if (importNotifier.Status() != IOResult::Canceled)
                ; // if you get here, something unexpected happened

    notifier = HPS.Stream.File.Import(filename, importOptionsKit);

    // cancel the import
    notifier.Cancel();

    // wait for the cancellation to finish
    notifier.Wait();

    // test for the IOResult
    if (notifier.Status() != HPS.IOResult.Canceled); // if you get here, something unexpected happened

Canceling is not immediate. Once you cancel, a notice is posted that the import needs to be cancelled. The importer checks periodically to see if the notice has been posted, and when it sees it, it cancels itself.

### Importing From a Buffer

In addition to directly loading an HSF, the `HPS::Stream` class supports importing HSF data from a buffer. This is implemented as an overload to `HPS::Stream::File::Import`.

        try {
            HPS::Stream::ImportOptionsKit importOptionsKit;
            importOptionsKit.SetSegment(mySegmentKey); // set destination segment

            // read from previously exported ByteArrayArray buffers
            HPS::Stream::ImportNotifier notifier = HPS::Stream::File::Import(buffers, importOptionsKit);

            // pauses this thread until the HSF is finished loading
            notifier.Wait();
        }
        catch (HPS::IOException ioe) {
            // handle exception
            throw;
        }

    try
    {

    HPS.Stream.ImportOptionsKit importOptionsKit = new HPS.Stream.ImportOptionsKit();
    importOptionsKit.SetSegment(mySegmentKey); // set destination segment

    // read from previously exported ByteArrayArray buffers
    notifier = HPS.Stream.File.Import(buffers, importOptionsKit);

    // pauses this thread until the HSF is finished loading
    notifier.Wait();
    }
    catch (HPS.IOException ioe)
    {
    // handle exception
    throw;
    }

## Importing Other File Formats

In addition to HSF files, HOOPS Visualize Desktop can also natively import STL, OBJ, and point cloud files. The procedure follows the same pattern as HSF. As before, be sure to set the destination segment in the importer’s options kit:

        // importing STL file
        HPS::STL::ImportOptionsKit stlOptionsKit = STL::ImportOptionsKit::GetDefault();
        stlOptionsKit.SetSegment(mySegmentKey);
        HPS::STL::ImportNotifier stlNotifier = HPS::STL::File::Import(stlFilename, stlOptionsKit);
        stlNotifier.Wait();

        // importing OBJ file
        HPS::OBJ::ImportOptionsKit objOptionsKit;
        objOptionsKit.SetSegment(mySegmentKey);
        HPS::OBJ::ImportNotifier objNotifier = HPS::OBJ::File::Import(objFilename, objOptionsKit);
        objNotifier.Wait();

### Notes on Point Cloud Files

The point cloud importer follows the same pattern. The only real option of note is `HPS::PointCloud::ImportOptionsKit::SetPointColor`. One thing to be aware of is if the point cloud file specifies RGB colors for the points, the point color value you specify is ignored. If the file specifies no color, the color from `SetPointColor` will be set as the vertex color in the containing segment. If the file specifies a grayscale intensity for the point colors, each resolved color will be the supplied color multiplied by the intensity for the given point. If the file specifies colors or intensities then the colors will be inserted as vertex parameters. If the file only contains points, then the color will be set as an attribute on the containing segment.

Point clouds are inserted as vertex-only shells (in batches of 10000 points per shell).

### Notes on MTL

For MTL files, the OBJ importer opens and reads them in order to discover which material properties are present in the file. The file is closed when the import completes or is interrupted by an exception.

### HOOPS Exchange and HOOPS Publish

For information on how to load a file into HOOPS Visualize Desktop using HOOPS Exchange, see the Programming Guide section about Exchange. Integrating with HOOPS Publish is covered here.

## Importing 2D Images

The examples from previous sections have all dealt with loading 3D CAD files. 2D images are loaded slightly differently. First of all, the process uses the `HPS::Image` namespace. Secondly, the result of the file load is an `HPS::ImageKit`. Normally the image is loaded from an external file, although it is possible to use a programmtically-defined or generated image as well. This is the process you would use to load an image to prepare it for use, for example, as a texture:

        HPS::ImageKit imageKit;

        try {
            HPS::Image::ImportOptionsKit iok;
            iok.SetFormat(HPS::Image::Format::Png);
            imageKit = HPS::Image::File::Import(filename, iok);
        }
        catch (HPS::IOException ioe) {
            char const* problem = ioe.what(); // shows cause of the exception
            throw;
        }

    HPS.ImageKit imageKit;

    try
    {
        HPS.Image.ImportOptionsKit iok = new HPS.Image.ImportOptionsKit();
        iok.SetFormat(HPS.Image.Format.Jpeg);
        imageKit = HPS.Image.File.Import(filename, iok);
    }
    catch (HPS.IOException ioe)
    {
        String problem = ioe.Message; // shows cause of the exception
    }

HOOPS Visualize Desktop can load common image formats, including JPG, PNG, and TGA. The full list of supported file formats is provided in the appendix. It is also possible to save 2D images out of an `HPS::ImageKit` in a similar way. Note that the size and export format must be specified within the `HPS::ImageKit` itself.

        HPS::Image::File::Export(filename, myImageKit);

    HPS.Image.File.Export(filename, myImageKit);

### Saving Screenshots

In order to save a screenshot, you can skip the `HPS::ImageKit` entirely and pass a `HPS::WindowKey` as a parameter. If you do not specify the image size, the window size is used. If you do specify the image size, and it does not match the window size, the resulting image will be stretched to match the size you specify. This procedure is as follows:

        HPS::Image::ExportOptionsKit export_options;
        export_options.SetFormat(HPS::Image::Format::Png);
        export_options.SetSize(800, 450);

        HPS::Image::File::Export(filename, myWindowKey, export_options);

    HPS.Image.ExportOptionsKit export_options = new HPS.Image.ExportOptionsKit();
    export_options.SetFormat(HPS.Image.Format.Png);
    export_options.SetSize(800, 450);

    HPS.Image.File.Export(filename, myWindowKey, export_options);

## Import Events

Import events are triggered by HOOPS Visualize Desktop as part of the HSF file loading process. Import events are useful when you need to perform additional processing for individual geometry and attributes. Each event is triggered before HOOPS Visualize Desktop inserts the object into the database so that your logic can decide how to proceed. Each type of import object is represented by a particular `HPS::Stream::ImportEvent`. For example, if HOOPS Visualize Desktop reads a `HPS::CylinderKey` from an HSF file, it will trigger a `HPS::Stream::CylinderImportEvent`. If changes are about to be made to visibility attributes during the HSF file read, a `HPS::Stream::VisibilityImportEvent` will be generated.

You receive these events by setting an `HPS::Stream::ImportEventHandler` for the `HPS::Stream::ImportEvent` type on your `HPS::Stream::ImportOptionsKit`. The `HPS::Stream::ImportEventHandler` class has a virtual function, `HPS::Stream::ImportEventHandler::Handle`, that HOOPS Visualize Desktop will call with the `HPS::Stream::ImportEvent` data. You should override the `Handle` function to inspect or modify the data to suit your needs. Each event is triggered before the database is updated, and your implementation of `Handle` will have the ability to determine whether the import operation should proceed. If `Handle` returns `true`, the operation will proceed, `false` means the operation will be discarded.

The following code sample defines a custom `HPS::Stream::ImportEventHandler` class, which will unset any text ‘bold’ attributes that might be present in the HSF file:

        class NoBoldEvent: public HPS::Stream::ImportEventHandler {
          public:
            bool Handle(HPS::Stream::ImportEvent* e)
            {
                if (e != nullptr) {
                    if (e->GetClassID() == HPS::Object::ClassID<HPS::Stream::TextImportEvent>()) {
                        HPS::Stream::TextImportEvent* text_event = static_cast<HPS::Stream::TextImportEvent*>(e);
                        text_event->text_kit.UnsetBold();
                    }
                    else if (e->GetClassID() == HPS::Object::ClassID<HPS::Stream::TextAttributeImportEvent>()) {
                        HPS::Stream::TextAttributeImportEvent* text_attribute_event =
                            static_cast<HPS::Stream::TextAttributeImportEvent*>(e);
                        text_attribute_event->text_attribute_kit.UnsetBold();
                    }
                }

                return true;
            }
        };

    class NoBoldEvent : HPS.Stream.ImportEventHandler
    {
    	public override bool Handle(HPS.Stream.ImportEvent e)
    	{
    		if (e.GetClassID() == HPS.Object.ClassID<HPS.Stream.TextImportEvent>())
    		{
    			HPS.Stream.TextImportEvent text_event = (HPS.Stream.TextImportEvent)e;
    			text_event.text_kit.UnsetBold();
    		}
    		else if (e.GetClassID() == HPS.Object.ClassID<HPS.Stream.TextAttributeImportEvent>())
    		{
    			HPS.Stream.TextAttributeImportEvent text_attribute_event = (HPS.Stream.TextAttributeImportEvent) e;
    			text_attribute_event.text_attribute_kit.UnsetBold();
    		}

    		return true;
    	}
    };

We then set the custom handler on the `HPS::Stream::ImportOptionsKit` for the two different text import events, prior to importing the HSF File:

        NoBoldEvent no_bold_event;
        HPS::Stream::ImportOptionsKit import_options;
        import_options.SetEventHandler(no_bold_event, HPS::Object::ClassID<HPS::Stream::TextImportEvent>());
        import_options.SetEventHandler(no_bold_event, HPS::Object::ClassID<HPS::Stream::TextAttributeImportEvent>());

    NoBoldEvent no_bold_event = new NoBoldEvent();
    HPS.Stream.ImportOptionsKit	import_options = new HPS.Stream.ImportOptionsKit();
    import_options.SetEventHandler(no_bold_event, HPS.Object.ClassID<HPS.Stream.TextImportEvent>());
    import_options.SetEventHandler(no_bold_event, HPS.Object.ClassID<HPS.Stream.TextAttributeImportEvent>());

### User Data

There are two different ways of storing user data in an HSF file. One form is user data that is stored within the database and is associated with a segment or geometry (See user data), and will be reported to you via an `HPS::Stream::UserDataImportEvent`. The second form is user data that is not associated with the database and will be reported to you via an `HPS::Stream::NonDBUserDataImportEvent`. (Note: HOOPS Visualize Desktop does not currently provide support for exporting non-DB user data, but existing HSF files may contain such user-data.

Conversation saved
HOOPSY BETA

### Hello! I'm HOOPSY

Your multilingual generative AI assistant for documentation. Ask me anything about HOOPS Visualize Desktop in your own language, or choose a sample question below to start a conversation:

What is HOOPS Visualize Desktop?
What are the latest release notes for HOOPS Visualize Desktop?
How do I start evaluating HOOPS Visualize Desktop?
How do I write my first sample application?
How can I get assistance?

HOOPSY may store conversations according to OpenAI's policy. Responses may not always be accurate.

HOOPSY is thinking...