Previous iTool Developer's Guide: Creating a File Writer Next

Creating a New File Writer

The process of creating an visualization type is outlined in the following sections:

Creating the Class Structure Definition

When any IDL object is created, IDL looks for an IDL class structure definition that specifies the instance data fields needed by an instance of the object, along with the data types of those fields. The object class structure must have been defined before any objects of the type are created. In practice, when the IDL OBJ_NEW function attempts to create an instance of a specified object class, it executes a procedure named ObjectClass__define (where ObjectClass is the name of the object), which is expected to define an IDL structure variable with the correct name and structure fields. For additional information on how IDL creates object instances, see The Object Lifecycle.


Note
The class structure definition is generally the last routine in the .pro file that defines an object class.

Subclassing from the IDLitWriter Class

The IDLitWriter class is the base class for all iTool file writers. In almost all cases, new file writers will be subclassed either from the IDLitWriter class or from a class that is a subclass of IDLitWriter.

See IDLitWriter for details on the methods properties available to classes that subclass from IDLitWriter.

Example Class Structure Definition

The following is the class structure definition for the ExampleWriter file writer class. This procedure should be the last procedure in a file named examplewriter__define.pro.

PRO ExampleWriter__Define  
  
   struct = { ExampleWriter,          $  
      INHERITS IDLitWriter $  
   }  
  
END  
Discussion

The purpose of the structure definition routine is to define a named IDL structure with structure fields that will contain the visualization object instance data. The structure name should be the same as the visualization's class name - in this case, ExampleWriter.

Like many iTool file writer classes, ExampleWriter is created as a subclass of the IDLitWriter class. File writer classes that subclass from the IDLitWriter class inherit all of the standard iTool file writer features, as described in Subclassing from the IDLitWriter Class.

The ExampleWriter class has no instance data of its own. For a more complex example, see Example: TIFF File Writer.

Creating an Init Method

The file writer class Init method handles any initialization required by the file writer object, and should do the following:

Definition of the Init Function

Begin by defining the argument and keyword list for your Init method. The argument and keyword list defines positional parameters (arguments) accepted by your method, defines any keywords that will be handled directly by your method, and specifies whether keywords not explicitly handled by your method will be passed through to other routines called by your method via IDL's keyword inheritance mechanism. The Init method for a file writer generally looks something like this:

FUNCTION MyWriter::Init, MYKEYWORD1 = mykeyword1, $  
   MYKEYWORD2 = mykeyword2, ..., _REF_EXTRA = _extra  

where MyWriter is the name of your file writer class and the MYKEYWORD parameters are keywords handled explicitly by your Init function.


Note
Always use keyword inheritance (the _REF_EXTRA keyword) to pass keyword parameters through to any called routines. (See Keyword Inheritance for details on IDL's keyword inheritance mechanism.)

Superclass Initialization

The file writer class Init method should call the Init method of any required superclass. For example, if your file writer is based on an existing file writer class, you would call that class' Init method:

self->SomeFileWriterClass::Init(_EXTRA = _extra)  

where SomeFileWriterClass is the class definition file for the file writer on which your new file writer is based.


Note
Your file writer class may have multiple superclasses. In general, each superclass' Init method should be invoked by your class' Init method.

Error Checking

Rather than simply calling the superclass Init method, it is a good idea to check whether the call to the superclass Init method succeeded. The following statement checks the value returned by the superclass Init method; if the returned value is 0 (indicating failure), the current Init method also immediately returns with a value of 0:

IF ( self->SomeFileWriterClass::Init(_EXTRA = _extra) EQ 0) THEN $  
   RETURN, 0  

This convention is used in all file writer classes included with IDL. RSI strongly suggests that you include similar checks in your own class definition files.

Keywords to the Init Method

Properties of the file writer class can be set in the Init method by specifying the property names and values as IDL keyword-value pairs. In addition to any keywords implemented directly in the Init method of the superclass on which you base your class, the properties of the IDLitWriter class, IDLitComponent class, and IDLitIMessaging class are available to any file writer class. See "IDLitReader Properties", "IDLitComponent Properties", and IDLitIMessaging Properties.


Note
Always use keyword inheritance (the _EXTRA keyword) to pass keyword parameters through to the superclass. (See Keyword Inheritance for details on IDL's keyword inheritance mechanism.)

Standard Base Class

While you can create your new file writer class from any existing file writer class, in many cases, file writer classes you create will be subclassed directly from the base class IDLitWriter:

IF ( self->IDLitWriter::Init(Extensions, TYPES = types, $  
   _EXTRA = _extra) EQ 0) $  
   THEN RETURN, 0  

where Extensions is a string or array of strings specifying the filename extensions readable by your file writer and types is a string or array of strings specifying the iTool data types for which this writer is available. (See iTool Data Types for details on iTool data types.)


Note
The value of the Extensions argument is used only to display the proper filename filter when a File Save dialog is displayed - it is not a check for the proper filetype.

The IDLitWriter class provides the base iTool file writer functionality used in the tools created by RSI. See Subclassing from the IDLitWriter Class for details.

Return Value

If all of the routines and methods used in the Init method execute successfully, it should indicate successful initialization by returning 1. Other file writer classes that subclass from your file writer class may check this return value, as your routine should check the value returned by any superclass Init methods called.

Registering Properties

File writer objects can register properties with the iTool. Registered properties show up in the property sheet interface shown in the system preferences browser (described in Properties of the iTools System), and can be modified interactively by users. The iTool property interface is described in detail in Property Management.

Register a property by calling the RegisterProperty method of the IDLitComponent class:

self->RegisterProperty, PropertyIdentifier [, TypeCode] $  
   [, ATTRIBUTE = value]  

where PropertyIdentifier is a string that uniquely identifies the property, TypeCode is an integer between 0 and 9 specifying the property data type, and ATTRIBUTE is a property attribute. See Registering Properties for details.


Note
A file writer need not register any properties at all, if the write operation is simple. Many of the standard iTool image file writer work without registering any properties.

Setting Property Attributes

If a property has already been registered, perhaps by a superclass of your file writer class, you can change the registered attribute values using the SetPropertyAttribute method of the IDLitComponent class:

self->SetPropertyAttribute, Identifier  

where Identifier is the name of the keyword to the GetProperty and SetProperty methods used to retrieve or change the value of this property. (The Identifier is specified in the call to RegisterProperty either via the PropertyName argument or the IDENTIFIER keyword.) See Property Attributes for additional details.

Passing Through Caller-Supplied Property Settings

If you have included the _REF_EXTRA keyword in your function definition, you can use IDL's keyword inheritance mechanism to pass any "extra" keyword values included in the call to the Init method through to other routines. One of the things this allows you to do is specify property settings when the Init method is called; simply include each property's keyword/value pair when calling the Init method, and include the following in the body of the Init method:

IF (N_ELEMENTS(_extra) GT 0) THEN $  
   self->MyWriter::SetProperty,  _EXTRA = _extra  

where MyWriter is the name of your file writer class. This line has the effect of passing any "extra" keyword values to your file writer class' SetProperty method, where they can either be handled directly or passed through to the SetProperty methods of the superclasses of your class. See Creating a SetProperty Method for details.

Example Init Method

FUNCTION ExampleWriter::Init, _REF_EXTRA = _extra  
  
   IF (self->IDLitWriter::Init('ppm', TYPE='IDLIMAGE', $  
      NAME='Portable Pixmap (PPM) File', $  
      DESCRIPTION="PPM File Writer", $  
      _EXTRA = _extra) EQ 0) THEN $  
      RETURN, 0  
  
   RETURN, 1  
  
END  
Discussion

The ExampleWriter class is based on the IDLitWriter class (discussed in Subclassing from the IDLitWriter Class). As a result, all of the standard features of an iTool file writer class are already present. We don't define any keyword values to be handled explicitly in the Init method, but we do use the keyword inheritance mechanism to pass keyword values through to methods called within the Init method. The ExampleWriter Init method does the following things:

  1. Calls the Init method of the superclass, IDLitWriter. We specify a list of accepted filename extensions (only ppm, in this case) via the Extensions argument, and set the TYPES keyword. We include a description of the writer via the DESCRIPTION keyword. Finally, we use the _EXTRA keyword inheritance mechanism to pass through any keywords provided when the ExampleWriter Init method is called.
  2.  

  3. Returns the integer 1, indicating successful initialization.

Creating a Cleanup Method

The file writer class Cleanup method handles any cleanup required by the file writer object, and should do the following:

  • destroy any pointers or objects created by the file writer
  •  

  • call the superclass' Cleanup method

Calling the superclass' cleanup method will destroy any objects created when the superclass was initialized.


Note
If your file writer class is based on the IDLitWriter class, and does not create any pointers or objects of its own, the Cleanup method is not strictly required. It is always safest, however, to create a Cleanup method that calls the superclass' Cleanup method.

See IDLitWriter::Cleanup for additional details.

Example Cleanup Method

PRO ExampleWriter::Cleanup  
  
   ; Clean up superclass  
   self->IDLitWriter::Cleanup  
  
END  
Discussion

Since our file writer object does not have any instance data of its own, the Cleanup method simply calls the superclass Cleanup method.

Creating a GetProperty Method

The file writer class GetProperty method retrieves property values from the file writer object instance or from instance data of other associated objects. It should retrieve the requested property value, either from the file writer object's instance data or by calling another class' GetProperty method.


Note
Any property registered with a call to the RegisterProperty method must be listed as a keyword to the GetProperty method either of the visualization class or one of its superclasses.


Note
A file writer need not register any properties at all, if the write operation is simple. Many of the standard iTool image file writers work without registering any properties.

See IDLitWriter::GetProperty for additional details.

Example GetProperty Method

PRO ExampleWriter::GetProperty, _REF_EXTRA = _extra  
  
   IF (N_ELEMENTS(_extra) GT 0) THEN $  
       self->IDLitWriter::GetProperty, _EXTRA = _extra  
  
END  
Discussion

The GetProperty method first defines the keywords it will accept. There must be a keyword for each property of the file writer. Since the file writer we are creating has no properties of its own, there are no keywords explicitly defined. Note the use of the keyword inheritance mechanism to allow us to get properties from the ExampleWriter class' superclasses without knowing the names of the properties.

Since our ExampleWriter class has no properties of its own, we simply call the superclass' GetProperty method, passing in all of the keywords stored in the _extra structure.

Creating a SetProperty Method

The file writer SetProperty method stores property values in the file writer object's instance data. It should set the specified property value, either by storing the value directly in the visualization object's instance data or by calling another class' SetProperty method.


Note
Any property registered with a call to the RegisterProperty method must be listed as a keyword to the SetProperty method either of the visualization class or one of its superclasses.


Note
A file writer need not register any properties at all, if the write operation is simple. Many of the standard iTool image file writer work without registering any properties.

See IDLitWriter::SetProperty for additional details.

Example SetProperty Method

PRO ExampleWriter::SetProperty, _REF_EXTRA = _extra  
  
   IF (N_ELEMENTS(_extra) GT 0) THEN $  
      self->IDLitWriter::SetProperty, _EXTRA = _extra  
  
END  
Discussion

The SetProperty method first defines the keywords it will accept. There must be a keyword for each property of the visualization type. Since the file writer we are creating has no properties of its own, there are no keywords explicitly defined. Note the use of the keyword inheritance mechanism to allow us to set properties from the ExampleWriter class' superclasses without knowing the names of the properties.

Using the N_ELEMENTS function, we check to see whether any properties were specified via the keyword inheritance mechanism. If any keywords were specified, we call the superclass' SetProperty method, passing in all of the keywords stored in the _extra structure.

Creating a SetData Method

The file writer SetData method does the work of the file writer, extracting data from the selected iTool data object and writing the data to a file using some method. If the process is successful, the SetData method must return 1 for success.

In our example, we write the selected data to a Portable Pixmap (PPM) file. As a result, we do some additional checking to ensure that the data that the user has selected can be displayed as an image.

See IDLitWriter::SetData for additional details.

Example SetData Method

FUNCTION ExampleWriter::SetData, oImageData  
     
   ; Prompt user for a file in which to save the data  
   strFilename = self->GetFilename()  
   IF (strFilename EQ '') THEN $  
      RETURN, 0 ; failure  
  
   ; Check validity of the input data object  
   IF (~ OBJ_VALID(oImageData)) THEN BEGIN  
      self->ErrorMessage, ['Invalid image data object'], $  
         TITLE = 'Error', SEVERITY = 2  
      RETURN, 0 ; failure  
   ENDIF  
  
   ; Check the iTool data type of the selected data object.  
   ; If the data is not of a type that can be written to an  
   ; image file, display an error message.  
   oData = oImageData->GetByType("IDLIMAGE", COUNT = count)  
   IF (count EQ 0) THEN $      ; no image, image pixels?  
      oData = oImageData->GetByType("IDLIMAGEPIXELS", $  
         COUNT = count)  
   IF (count EQ 0) THEN $      ; no image, array 2d?  
      oData = oImageData->GetByType("IDLARRAY2D", COUNT = count)  
   IF (count EQ 0) THEN BEGIN  
      self->ErrorMessage, $  
         ["Invalid data provided to file writer."], $  
         TITLE="Error", SEVERITY = 2  
      RETURN, 0 ; failure  
   END  
   
   ; Turn a 1-D object array into a scalar object.  
   oData = oData[0]  
     
   ; Determine whether the data is an image.  
   isImage = OBJ_ISA(oData, "IDLitDataIDLImage")  
  
   ; If data is an image, get image pixels, otherwise  
   ; turn data into an image.  
   IF (isImage NE 0) THEN BEGIN  
      result = oData->GetData(image, 'ImagePixels')  
   ENDIF ELSE BEGIN  
      result = oData->GetData(image)  
   ENDELSE  
  
   ; Check the result of the GetData method.  
   IF (result EQ 0) THEN BEGIN  
      self->ErrorMessage, ['Error retrieving image data'], $  
         TITLE = 'Error', SEVERITY = 2  
      RETURN, 0 ; failure  
   ENDIF  
  
   ; Get number of dimensions of image array.  
   ndim = SIZE(image, /N_DIMENSIONS)  
  
   ; Write to a PPM file. Use REVERSE to make image appear  
   ; with correct orientation.  
   WRITE_PPM, strFilename, REVERSE(image, ndim)  
  
   ; Return 1 for success.  
   RETURN, 1  
  
END  
Discussion

The SetData method accepts an IDLitData object (oImageData) as its input parameter. Before processing the input data, the method prompts the user for a file in which to save the image, using the GetFilename method of the IDLitWriter object.

After securing a filename, the method proceeds to check the input data object. First it checks to make sure that the input object is valid. Then it attempts to retrieve data of an appropriate iTool data type from the data object; in this example, the method tries to extract an data of one of the following types using the GetByType method of the IDLitData class:

  • IDLIMAGE
  •  

  • IDLIMAGEPIXELS
  •  

  • IDLARRAY2D

If no data of any of these types is found, the method displays an error message and exits.

Once the method has obtained an appropriate data object, it checks to determine whether the data object is an IDLitDataIDLImage object; if so, it attempts to retrieve the image pixels from the data object; otherwise it simply retrieves the data array. The data retrieved by the GetData method is stored in the variable image. The method then checks the return value from the GetData method to determine whether the returned value is valid.

Using the valid image data, the method determines the number of dimensions and then uses the WRITE_PPM procedure to create an image file. The image data must be processed by the REVERSE function in order to make it appear in the output file with the correct orientation.

  IDL Online Help (June 16, 2005)