Io image raw

Io_image_raw is a basic example plugin. This wiki page is intended as a walkthrough of the code in order to help you better understand the SDK.

When installed, the Io_image_raw plugin adds a saver/loader functionality for RAW image files.

Code Walkthrough

Class Declarations

We want to be able to examine the image files, so here we declare an Interface for opaque image access called CRawImage that inherits from Image_(lx-image.hpp)#Color_Image. Of note is a pointer back to the active RAW loader. We use this pointer in all of our basic methods. We have the CRawLoader loader class load the image in question and then retrieve its width and height objects(which we get when we load the image), in effect retrieving its size. We do the same for our img_Format function, except this time with the file format of the image. The loader is again used in img_GetPixel to provide important information regarding the scan line size and channels that helps us perform the purpose of the function of the function, which is to access one pixel. We also use the loader in ing_GetLine, which gets one line of the image, to load a scanline from the image directly into the buffer. This is a clever way of performing the intended function of the method, which is to load one line of the image.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
 class CRawImage : public CLxImpl_Image
 {
 public:
        CRawLoader              *rawLoader;
        ILxUnknownID             inst_ifc;
        FILE                    *open_file;
        CLxUser_ThreadService    threadSvc;

        virtual                 ~CRawImage();

        virtual void             img_Size (
                                        unsigned int    *w,
                                        unsigned int    *h);

        virtual LXtPixelFormat   img_Format (void);

        virtual LxResult         img_GetPixel (
                                        unsigned int     x,
                                        unsigned int     y,
                                        LXtPixelFormat   type,
                                        void            *pixel);

        virtual const void *     img_GetLine (
                                        unsigned int     y,
                                        LXtPixelFormat   type,
                                        void            *buf);
 };

We want to create a loader, so we inherit from Io_(lx-io.hpp)#.2814.29_SDK:_LXtLoadAccess_struct. Factories are objects that allow attributes to be read and new server instances to be spawned. In this case, we declare it to be able to create an image interface for opaque image I/O.

Right above the factory declaration is a file pointer. The first method that must be run is our load_Recognize function, which checks if the file we are examining is a valid data type. Before anything else, though, we take the file we are loading(passed in as an argument) and set the aforementioned file pointer to it. The RAW image format is a bit unusual as there is no known data signature we can compare against so we instead call the GetImportOptions, which retrieves certain values regarding the parameters of the image file, and compare those parameters against the parameters of the file we have. The GetImportOptions additionally sets other object values that we will call in later functions. If the parameters match, the file is valid.

The next seven functions return certain values related to the image, such as image height and header size, which we set in the load_Recognize function(and some through the GetImportOptions function, which we called in the load_Recognize function).

Our LoadInstance function takes the file the file pointer points at and creates an instance of the image there.

Our LoadObject method is the function that actually loads the file. It creates an object, in this case an image, and fills it line by line with data from the file.

Once we are finally finished, our cleanup function closes the file that the file pointer points to.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
class CRawLoader : public CLxImpl_Loader1
{
        LXtImageTarget1          img_target;
        FILE                    *open_file;

        /*
         * Factory to create image interface for opaque image I/O.
         */
        CLxPolymorph<CRawImage>  raw_factory;

        /*
         * Import options from the Image I/O panel.
         */
        unsigned                 width;
        unsigned                 height;
        unsigned                 channels;
        bool                     interleaved;
        unsigned                 depth;
        bool                     byteOrderPC;
        unsigned                 headerSize;

        void                     GetImportOptions ();

        size_t                   scanlineSize;

    public:
                                 CRawLoader ();

        LxResult                 load_Recognize  (LXtLoadAccess1 *) LXx_OVERRIDE;

        const LXtImageTarget1*   load_GetImageTarget () const
        {
                return &img_target;
        }

        FILE *                   load_GetOpenFile () const
        {
                return open_file;
        }

        unsigned                 load_GetChannels () const
        {
                return channels;
        }

        unsigned                 load_GetDepth () const
        {
                return depth;
        }

        bool                     load_GetByteOrderPC () const
        {
                return byteOrderPC;
        }

        unsigned                 load_GetHeaderSize () const
        {
                return headerSize;
        }

        size_t                   load_GetScanlineSize () const
        {
                return scanlineSize;
        }

        LxResult                 load_LoadInstance (
                                        LXtLoadAccess1  *load,
                                        void            **ppvObj) LXx_OVERRIDE;

        LxResult                 load_LoadObject (
                                        LXtLoadAccess1  *load,
                                        ILxUnknownID     dest) LXx_OVERRIDE;

        LxResult                 load_Cleanup    (LXtLoadAccess1 *load) LXx_OVERRIDE;

        static LXtTagInfoDesc    descInfo[];
};

We want to create a Saver_Object.

Normally a Saver class has a Verify method as well as a Save method but here we opt to only implement a Save method as in our Save method we verify that the file we are loading is valid. The Save method, other than verifying that the file is valid, only saves the file.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
 class CRawSaver : public CLxImpl_Saver
 {
    public:
        virtual LxResult         sav_Save (
                                        ILxUnknownID     source,
                                        const char      *filename,
                                        ILxUnknownID     monitor) LXx_OVERRIDE;

        static LXtTagInfoDesc    descInfo[];
 };

./Server_Tags

Servers tags are examined when the server is initialized, and give information about the server. We set the tags in this case by taking descinfo[] arrays and associating the relevant data with the corresponding flags.

Here, the tags indicate that the saver class above saves objects of the image class with the file extension RAW.

1
2
3
4
5
6
 LXtTagInfoDesc  CRawSaver::descInfo[] = {
        { LXsSAV_OUTCLASS,      LXa_IMAGE       },
        { LXsSAV_DOSTYPE,       "RAW"           },
        { LXsSRV_USERNAME,      "Raw Image"     },
        { 0 }
 };

./Initialize_(index)

Intialize is called when we add the plugin to modo, and is the utility that exports the server. The LXx_ADD_SERVER method is simply a wrapper that is identical to normal method of adding a server, with the arguments being (interface_to_be_added, class_you_depend_on, server_name).

Here we indicate that we intend to add two servers to modo. One of them is of the type saver, depends on the class CRawSaver, and is called raw_RGB. The other does the same, but with Loader1, CRawLoader, and raw_RGB respectively.

1
2
3
4
5
6
        void
 initialize ()
 {
        LXx_ADD_SERVER (Saver,  CRawSaver,  "raw_RGB");
        LXx_ADD_SERVER (Loader1, CRawLoader, "raw_RGB");
 }

Helper Functions

This function uses the Queries_(lxu-queries.hpp) to query the user for an int value and returns that value. It is called in GetImportOptions to determine what parameters the user wants for the image file.

1
2
3
4
5
        static int
 GetUserInt (const char *prefKey, int defaultValue = 0)
 {
    ...
 }

Implementations

This method queries the user for the values of certain parameters of the image. It also sets certain objects inside the CRawLoader that are examined by other functions.

1
2
3
4
5
        void
 CRawLoader::GetImportOptions ()
 {
       ...
 }

The constructor indicates that the loader will be using the Image_Interface.

1
2
3
4
 CRawLoader::CRawLoader ()
 {
        raw_factory.AddInterface (new CLxIfc_Image<CRawImage>);
 }

Recognize method scans the file to check if the file we are examining is a valid data type. Before anything else, though, we take the file we are loading(passed in as an argument) and set a file pointer that we reference in another function. The RAW image format is a bit unusual as there is no known data signature we can compare against so we instead call the GetImportOptions, which retrieves certain values regarding the parameters of the image file, and compare those parameters against the parameters of the file we have. The GetImportOptions additionally sets other object values that we will call in later functions. If the parameters match, the file is valid.

1
2
3
4
5
6
        LxResult
CRawLoader::load_Recognize (
        LXtLoadAccess1          *load)
{
       ...
}

This function takes the image from the file that other functions in the class had been referencing and creates an instance of it.

1
2
3
4
5
        LxResult
 CRawLoader::load_LoadInstance (LXtLoadAccess1 *load, void **ppvObj)
 {
        ...
 }

The load-object method gets an object to fill with data, in this case an image. Using a user wrapper for the image we proceed to fill it from the file line by line. An optional monitor is used to check for user abort. This method is essentially the ‘meat’ of the CRawLoader, as it actually loads the object in the file we had been accessing into a file.

1
2
3
4
5
6
7
        LxResult
 CRawLoader::load_LoadObject (
        LXtLoadAccess1          *load,
        ILxUnknownID             dest)
 {
        ...
 }

Cleanup is called after a failed recognize or after load-object completes, regardless of the outcome. It closes the open file that we had been loading from and clears the pointer we had been using to access it.

1
2
3
4
5
6
        LxResult
 CRawLoader::load_Cleanup (
        LXtLoadAccess1          *load)
 {
     ...
 }

These next four functions are utilities that retrieve information that deal with the image in question

First off, we have the CRawLoader loader class load the image in question and then retrieve its width and height objects(which we get when we load the image), in effect retrieving its size.

1
2
3
4
5
        void
CRawImage::img_Size (unsigned int *w, unsigned int *h)
{
        ...
}

We do the same for our img_Format function, except this time with the file format of the image.

1
2
3
4
5
        LXtPixelFormat
CRawImage::img_Format (void)
{
        ...
}

The loader is again used in img_GetPixel to provide important information regarding the scan line size and channels that helps us perform the purpose of the function of the function, which is to access one pixel.

1
2
3
4
5
6
7
8
9
        LxResult
CRawImage::img_GetPixel (
        unsigned int     x,
        unsigned int     y,
        LXtPixelFormat   type,
        void            *pixel)
{
      ...
}

We also use the loader in ing_GetLine, which gets one line of the image, to load a scanline from the image directly into the buffer. This is a clever way of performing the intended function of the method, which is to load one line of the image.

1
2
3
4
5
6
7
8
        const void *
CRawImage::img_GetLine (
        unsigned int     y,
        LXtPixelFormat   type,
        void            *buf)
{
       ...
}

To begin, this method verifies that the file we are saving is valid. Next we perform the reverse of the load-object method. We extract pixels from the image (just to be different, although by line would be faster) and write them to the file, in effect saving it.

1
2
3
4
5
6
7
8
        LxResult
CRawSaver::sav_Save (
        ILxUnknownID             source,
        const char              *filename,
        ILxUnknownID             monitor)
{
       ...
}