Difference between revisions of "Io image raw"

From The Foundry MODO SDK wiki
Jump to: navigation, search
Line 8: Line 8:
 
===Class Declarations===
 
===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|CLxImpl_Image]]. Of note is a pointer back to the active RAW loader. We use this pointer in all of our basic methods. In our ing_Size function, which retrieves the size of the image,  we have the loader load the image in question and then retrieve its width and height objects. 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 to load a scanline from the image directly into the buffer.
+
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|CLxImpl_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.
  
 
  class CRawImage : public CLxImpl_Image
 
  class CRawImage : public CLxImpl_Image
Line 39: Line 39:
  
 
We want to create a loader, so we inherit from [[http://sdk.luxology.com/wiki/Io_(lx-io.hpp)#.2814.29_SDK:_LXtLoadAccess_struct|CLxImpl_Loader1]].  Inside the class, we declare a [[Factory_Object|factory]]. 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.  
 
We want to create a loader, so we inherit from [[http://sdk.luxology.com/wiki/Io_(lx-io.hpp)#.2814.29_SDK:_LXtLoadAccess_struct|CLxImpl_Loader1]].  Inside the class, we declare a [[Factory_Object|factory]]. 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.  
The remaining functions, except for the last one, simply retrieve information about the target file or actually load the file.
+
 
Inside the class,  
+
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.
  
 
<pre>
 
<pre>
Line 121: Line 129:
 
};</pre>
 
};</pre>
  
We want to create a [[Saver_Object|saver object]], so we have this class inherit from [[Io_(lx-io.hpp)#Saver|CLxImpl_Saver]]. Inside the class we have the main function, which performs the meat of saving the file, followed by the server tags.
+
We want to create a [[Saver_Object|saver object]], so we have this class inherit from [[Io_(lx-io.hpp)#Saver|CLxImpl_Saver]].
 +
 
 +
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.
  
 
  class CRawSaver : public CLxImpl_Saver
 
  class CRawSaver : public CLxImpl_Saver
Line 135: Line 145:
  
 
===[[Server_Tags|Server Tags]]===
 
===[[Server_Tags|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.
  
 
The tags, here corresponding to the loader, indicate that the [[Overview#nexus_Servers|server]] can load images and provide a file pattern.
 
The tags, here corresponding to the loader, indicate that the [[Overview#nexus_Servers|server]] can load images and provide a file pattern.
Line 169: Line 181:
 
===Helper Functions===
 
===Helper Functions===
  
This function queries the user for an int value and returns that value.
+
This function uses the [[Queries_(lxu-queries.hpp)|query function]] 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.
  
 
         static int
 
         static int
 
  GetUserInt (const char *prefKey, int defaultValue = 0)
 
  GetUserInt (const char *prefKey, int defaultValue = 0)
 
  {
 
  {
        int value = defaultValue;
+
    ...
        CLxReadUserValue ruvUser;
+
        if (ruvUser.Query (prefKey)) {
+
                value = ruvUser.GetInt ();
+
        }
+
+
        return value;
+
 
  }
 
  }
  
 
===Implementations===
 
===Implementations===
  
This method retrieves the options we will be using to import the file
+
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.
  
 
         void
 
         void
 
  CRawLoader::GetImportOptions ()
 
  CRawLoader::GetImportOptions ()
 
  {
 
  {
        width = GetUserInt ("ImageIO.PRAW.width", 1024);
+
      ...
        height = GetUserInt ("ImageIO.PRAW.height", 1024);
+
+
        int channelsIndex = GetUserInt ("ImageIO.PRAW.channels.index", 1);
+
        switch (channelsIndex) {
+
                case 0:
+
                        channels = 1;
+
                        break;
+
                case 1:
+
                        channels = 3;
+
                        break;
+
                case 2:
+
                        channels = 4;
+
                        break;
+
        }
+
+
        interleaved = GetUserInt ("ImageIO.PRAW.channels.index", true) ? true : false;
+
+
        int depthIndex = GetUserInt ("ImageIO.PRAW.depth.index", 0);
+
        switch (depthIndex) {
+
                case 0:
+
                        depth = 8;
+
                        break;
+
                case 1:
+
                        depth = 16;
+
                        break;
+
                case 2:
+
                        depth = 32;
+
                        break;
+
        }
+
+
        byteOrderPC = GetUserInt ("ImageIO.PRAW.byte.order.index", true) ? true : false;
+
+
        headerSize = GetUserInt ("ImageIO.PRAW.header.size", 0);
+
 
  }
 
  }
  
Line 233: Line 206:
 
  }
 
  }
  
Recognize method scans the file to see if it finds the data it can understand. In our case we look for a simple header string.
+
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.
  
 
<pre>
 
<pre>
Line 240: Line 213:
 
         LXtLoadAccess1 *load)
 
         LXtLoadAccess1 *load)
 
{
 
{
        LxResult result = LXe_FAILED;
+
      ...
 
+
        open_file = fopen (load->filename, "rb");
+
        if (open_file) {
+
                /*
+
                * This format is a bit unusual, in that there is no known data
+
                * signature we can compare against, so we instead check that
+
                * the file size is equal to the image size and depth specified
+
                * in the RAW import options, plus the header size.
+
                */
+
                GetImportOptions ();
+
 
+
                /*
+
                * Fetch the file size.
+
                */
+
                FSEEK (open_file, 0, SEEK_END);
+
                size_t length = FTELL (open_file);
+
                FSEEK (open_file, 0, SEEK_SET);
+
 
+
                /*
+
                * Compare against the image size specified by the options.
+
                */
+
                scanlineSize = width * channels * (depth / 8);
+
                size_t optionSize = height * scanlineSize;
+
                if (length == optionSize) {
+
                        /*
+
                        * Determine the specified image format.
+
                        */
+
                        switch (channels) {
+
                                case 1: {
+
                                        img_target.type = (depth == 8) ?
+
                                                LXiIMP_GREY8 : LXiIMP_GREYFP;
+
                                        break;
+
                                }
+
 
+
                                case 3: {
+
                                        img_target.type = (depth == 8) ?
+
                                                LXiIMP_RGB24 : LXiIMP_RGBFP;
+
                                        break;
+
                                }
+
 
+
                                case 4: {
+
                                        img_target.type = (depth == 8) ?
+
                                                LXiIMP_RGBA32 : LXiIMP_RGBAFP;
+
                                        break;
+
                                }
+
                        }
+
 
+
                        /*
+
                        * Use the option width and height.
+
                        */
+
                        img_target.w      = width;
+
                        img_target.h      = height;
+
                        img_target.ncolor = 0;
+
 
+
                        load->found  = lx::LookupGUID (LXa_IMAGE);
+
                        /*
+
                        * Use the opaque image APIs for large images.
+
                        * (Greater than 8K x 8K)
+
                        */
+
                        load->opaque = width * height > 512 * 512;
+
                        load->target = &img_target;
+
 
+
                        result = LXe_OK;
+
                }
+
        }
+
 
+
        return result;
+
 
}
 
}
 
</pre>
 
</pre>
  
This function opens the instance we choose.
+
This function takes the image from the file that other functions in the class had been referencing and creates an instance of it.
  
 
         LxResult
 
         LxResult
 
  CRawLoader::load_LoadInstance (LXtLoadAccess1 *load, void **ppvObj)
 
  CRawLoader::load_LoadInstance (LXtLoadAccess1 *load, void **ppvObj)
 
  {
 
  {
         LxResult result = LXe_OK;
+
         ...
+
        ILxUnknownID inst = raw_factory.Spawn (0);
+
        if (inst) {
+
                open_file = fopen (load->filename, "rb");
+
                if (open_file) {
+
                        CRawImage *rawImage = LXCWxOBJ(inst, CRawImage);
+
+
                        rawImage->rawLoader = this;
+
                        rawImage->inst_ifc = inst;
+
                        rawImage->open_file = open_file;
+
+
                        /*
+
                        * Lose our reference to the open file,
+
                        * since it now persists with the opaque image.
+
                        */
+
                        open_file = 0;
+
+
                        ppvObj[0] = inst;
+
                }
+
        }
+
+
        return result;
+
 
  }
 
  }
  
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.
+
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.
  
 
         LxResult
 
         LxResult
Line 348: Line 232:
 
         ILxUnknownID dest)
 
         ILxUnknownID dest)
 
  {
 
  {
         CLxUser_ImageWrite wimg (dest);
+
         ...
        CLxUser_Monitor mon;
+
        LXtImageByte *buf;
+
        unsigned int y, w, h;
+
        LxResult rc, rd;
+
+
        wimg.Size (&w, &h);
+
        buf = new LXtImageByte[w * channels];
+
        if (!buf)
+
                return LXe_OUTOFMEMORY;
+
+
        if (load->monitor) {
+
                mon.set (load->monitor);
+
                mon.Init (h);
+
        }
+
+
        rc = LXe_OK;
+
        for (y = 0; y < h && LXx_OK (rc); y++) {
+
                if (fread (buf, 1, w * channels, open_file) != w * channels)
+
                        rc = LXe_FAILED;
+
+
                else {
+
                        rd = wimg.SetLine (y, wimg.Format (), buf);
+
                        if (LXx_FAIL (rd))
+
                                rc = rd;
+
                        else if (mon.Step ())
+
                                rc = LXe_ABORT;
+
                }
+
        }
+
+
        delete[] buf;
+
        return rc;
+
 
  }
 
  }
  
Cleanup is called after a failed recognize or after load-object completes, regardless of the outcome.
+
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.
  
 
         LxResult
 
         LxResult
Line 388: Line 241:
 
         LXtLoadAccess1 *load)
 
         LXtLoadAccess1 *load)
 
  {
 
  {
        if (open_file) {
+
    ...
                fclose (open_file);
+
                open_file = 0;
+
        }
+
+
        return LXe_OK;
+
 
  }
 
  }
  
These functions are utilities that retrieve information that deal with the image in question
+
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.
  
 
<pre>
 
<pre>
Line 402: Line 252:
 
CRawImage::img_Size (unsigned int *w, unsigned int *h)
 
CRawImage::img_Size (unsigned int *w, unsigned int *h)
 
{
 
{
         *w = rawLoader->load_GetImageTarget ()->w;
+
         ...
        *h = rawLoader->load_GetImageTarget ()->h;
+
 
}
 
}
 +
</pre>
  
 +
We do the same for our img_Format function, except this time with the file format of the image.
 +
 +
<pre>
 
         LXtPixelFormat
 
         LXtPixelFormat
 
CRawImage::img_Format (void)
 
CRawImage::img_Format (void)
 
{
 
{
         return rawLoader->load_GetImageTarget ()->type;
+
         ...
 
}
 
}
 +
</pre>
  
 +
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.
 +
 +
<pre>
 
         LxResult
 
         LxResult
 
CRawImage::img_GetPixel (
 
CRawImage::img_GetPixel (
Line 419: Line 276:
 
         void *pixel)
 
         void *pixel)
 
{
 
{
        CLxLoc_ThreadMutex mux;
+
      ...
        if (threadSvc.NewMutex (mux)) {
+
}
                size_t scanlineSize = rawLoader->load_GetScanlineSize ();
+
</pre>
  
                mux.Enter ();
+
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.
                FSEEK (open_file, scanlineSize * y, SEEK_SET);
+
                FSEEK (open_file, x * rawLoader->load_GetChannels (), SEEK_CUR);
+
 
+
                if (type == rawLoader->load_GetImageTarget ()->type) {
+
                        fread (pixel, 1, rawLoader->load_GetChannels (), open_file);
+
                }
+
                else {
+
                        unsigned char r, g, b;
+
                        fread (&r, 1, 1, open_file);
+
                        fread (&g, 1, 1, open_file);
+
                        fread (&b, 1, 1, open_file);
+
 
+
                        LXtImageByte *dstPixel = reinterpret_cast<LXtImageByte*>(pixel);
+
                        switch (type) {
+
                                case LXiIMP_RGB24:
+
                                        *dstPixel++ = r;
+
                                        *dstPixel++ = g;
+
                                        *dstPixel++ = b;
+
                                        break;
+
 
+
                                case LXiIMP_RGBA32:
+
                                        *dstPixel++ = r;
+
                                        *dstPixel++ = g;
+
                                        *dstPixel++ = b;
+
                                        *dstPixel = 255;
+
                                        break;
+
 
+
                                case LXiIMP_RGBFP: {
+
                                        LXtImageFloat *dstPixelF =
+
                                                reinterpret_cast<LXtImageFloat*>(pixel);
+
                                        *dstPixelF++ = r / 255.0f;
+
                                        *dstPixelF++ = g / 255.0f;
+
                                        *dstPixelF++ = b / 255.0f;
+
                                        break;
+
                                }
+
 
+
                                case LXiIMP_RGBAFP: {
+
                                        LXtImageFloat *dstPixelF =
+
                                                reinterpret_cast<LXtImageFloat*>(pixel);
+
                                        *dstPixelF++ = r / 255.0f;
+
                                        *dstPixelF++ = g / 255.0f;
+
                                        *dstPixelF++ = b / 255.0f;
+
                                        *dstPixelF = 1.0;
+
                                        break;
+
                                }
+
                        }
+
                }
+
                mux.Leave ();
+
        }
+
 
+
        return LXe_OK;
+
}
+
  
 +
<pre>
 
         const void *
 
         const void *
 
CRawImage::img_GetLine (
 
CRawImage::img_GetLine (
Line 483: Line 289:
 
         void *buf)
 
         void *buf)
 
{
 
{
        CLxLoc_ThreadMutex mux;
+
      ...
        if (threadSvc.NewMutex (mux)) {
+
                size_t scanlineSize = rawLoader->load_GetScanlineSize ();
+
                mux.Enter ();
+
                FSEEK (open_file, scanlineSize * y, SEEK_SET);
+
 
+
                /*
+
                * Read the scanline directly into the buffer.
+
                */
+
                if (type == rawLoader->load_GetImageTarget ()->type) {
+
                        fread (buf, 1, scanlineSize, open_file);
+
                        mux.Leave ();
+
                }
+
                else if (type == LXiIMP_RGBA32) {
+
                        LXtImageByte *nativeBuf = new LXtImageByte[scanlineSize];
+
                        fread (nativeBuf, 1, scanlineSize, open_file);
+
                        mux.Leave ();
+
 
+
                        LXtImageByte *srcIter = nativeBuf;
+
                        LXtImageByte *dstIter = reinterpret_cast<LXtImageByte*>(buf);
+
                        for (unsigned x = 0; x < rawLoader->load_GetImageTarget ()->w; ++x) {
+
                                *dstIter++ = *srcIter++;
+
                                *dstIter++ = *srcIter++;
+
                                *dstIter++ = *srcIter++;
+
                                *dstIter++ = 255;
+
                        }
+
                        delete [] nativeBuf;
+
                }
+
                else {
+
                        mux.Leave ();
+
                }
+
        }
+
 
+
        return buf;
+
 
}
 
}
 
</pre>
 
</pre>
  
This is very much 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.
+
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.
  
 
<pre>
 
<pre>
Line 529: Line 302:
 
         ILxUnknownID monitor)
 
         ILxUnknownID monitor)
 
{
 
{
        CLxUser_Image image (source);
+
      ...
        CLxUser_Monitor mon;
+
        FILE *fp;
+
        unsigned char buf[4];
+
        unsigned int x, y, w, h;
+
 
+
        fp = fopen (filename, "wb");
+
        if (!fp)
+
                return LXe_FAILED;
+
 
+
        if (fwrite ("DEMO Raw RGB", 1, 12, fp) != 12)
+
                return LXe_FAILED;
+
 
+
        image.Size (&w, &h);
+
        buf[0] = w / 256;
+
        buf[1] = w % 256;
+
        buf[2] = h / 256;
+
        buf[3] = h % 256;
+
        if (fwrite (buf, 1, 4, fp) != 4)
+
                return LXe_FAILED;
+
 
+
        if (monitor) {
+
                mon.set (monitor);
+
                mon.Init (h);
+
        }
+
 
+
        for (y = 0; y < h; y++) {
+
                for (x = 0; x < w; x++) {
+
                        image.GetPixel (x, y, LXiIMP_RGBA32, buf);
+
                        if (fwrite (buf, 1, 3, fp) != 3)
+
                                return LXe_FAILED;
+
                }
+
 
+
                if (mon.Step ())
+
                        return LXe_ABORT;
+
        }
+
 
+
        fclose (fp);
+
        return LXe_OK;
+
 
}
 
}
 
</pre>
 
</pre>

Revision as of 17:53, 11 September 2013

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 CLxImpl_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.

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 [[1]]. Inside the class, we declare a factory. 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.

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, so we have this class inherit from CLxImpl_Saver.

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.

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.

The tags, here corresponding to the loader, indicate that the server can load images and provide a file pattern.

LXtTagInfoDesc	 CRawLoader::descInfo[] = {
       { LXsLOD_CLASSLIST,	LXa_IMAGE	},
       { LXsLOD_DOSPATTERN,	"*.raw"		},
       { LXsSRV_USERNAME,	"Raw Image"	},
       { 0 }
};

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

LXtTagInfoDesc	 CRawSaver::descInfo[] = {
       { LXsSAV_OUTCLASS,	LXa_IMAGE	},
       { LXsSAV_DOSTYPE,	"RAW"		},
       { LXsSRV_USERNAME,	"Raw Image"	},
       { 0 }
};

Initialization

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.

       void
initialize ()
{
       LXx_ADD_SERVER (Saver,  CRawSaver,  "raw_RGB");
       LXx_ADD_SERVER (Loader1, CRawLoader, "raw_RGB");
}

Helper Functions

This function uses the query function 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.

       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.

       void
CRawLoader::GetImportOptions ()
{
      ...
}

The constructor indicates that the loader will be using the image interface.

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.

        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.

       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.

       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.

       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.

        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.

        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.

        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.

        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.

        LxResult
CRawSaver::sav_Save (
        ILxUnknownID		 source,
        const char		*filename,
        ILxUnknownID		 monitor)
{
       ...
}