Creating a New File Reader

An iTool file reader class definition file must (at the least) provide methods to initialize the file reader class, get and set property values, handle changes to the underlying data, clean up when the file reader is destroyed, and define the file reader class structure. Complex file reader types will likely provide additional methods.

The process of creating an file reader 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 (Object Programming).

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

Subclassing from the IDLitReader Class

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

See "IDLitReader" (IDL Reference Guide) for details on the methods and properties available to classes that subclass from IDLitReader.

Hiding Compilation Messages

When IDL compiles an object class, it prints a compilation message similar to the following to the IDL Console:

% Compiled module: EXAMPLEREADER__DEFINE. 

To prevent the compilation message from appearing when the class is compiled, add the following line to the class structure definition:

COMPILE_OPT hidden 

Example Class Structure Definition

The following is the class structure definition for the ExampleReader file reader class. This procedure should be the last procedure in a file named examplereader__define.pro.

PRO ExampleReader__Define 
 
COMPILE_OPT hidden 
 
   struct = { ExampleReader,          $ 
      INHERITS IDLitReader $ 
   } 
 
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, ExampleReader.

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

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

Creating an Init Method

The file reader class Init method handles any initialization required by the file reader 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 function signature for an Init method for a file reader generally looks something like this:

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

where MyReader is the name of your file reader 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 (Application Programming) for details on IDL's keyword inheritance mechanism.)

Superclass Initialization

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

success = self->SomeFileReaderClass::Init(_EXTRA = _extra) 

where SomeFileReaderClass is the class definition file for the file reader on which your new file reader is based. The variable success will contain a 1 if the initialization was successful.

Note
Your file reader 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->SomeFileReaderClass::Init(_EXTRA = _extra) EQ 0) THEN $ 
   RETURN, 0 

This convention is used in all file reader classes included with IDL. We strongly suggest that you include similar checks in your own class definition files.

Keywords to the Init Method

Properties of the file reader 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 IDLitReader class and the IDLitComponent class are available to any file reader class. See IDLitReader Properties and "IDLitComponent Properties" (IDL Reference Guide).

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

Standard Base Class

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

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

where Extensions is a string or array of strings specifying the filename extensions readable by your file reader.

Note
The value of the Extensions argument is used only to display the proper filename filter when an Open dialog is displayed — it is not a check for the proper filetype. The IsA method must check the file to determine whether it is readable by your file reader.

The IDLitReader class provides the base iTool file reader functionality used in the tools created by ITT Visual Information Solutions. See Subclassing from the IDLitReader 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 reader classes that subclass from your file reader class may check this return value, as your routine should check the value returned by any superclass Init methods called.

Registering Properties

File reader 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 reader need not register any properties at all, if the read operation is simple. Many of the standard iTool image file readers work without registering any properties.

Setting Property Attributes

If a property has already been registered, perhaps by a superclass of your file reader 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. This mechanism allows you to 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->MyReader::SetProperty,  _EXTRA = _extra 

where MyReader is the name of your file reader class. This line has the effect of passing any "extra" keyword values to your file reader 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 ExampleReader::Init, _REF_EXTRA = _extra 
 
   IF (self->IDLitReader::Init('ppm', $ 
      DESCRIPTION="PPM File Reader", $ 
      _EXTRA = _extra) EQ 0) THEN $ 
      RETURN, 0 
 
   RETURN, 1 
 
END 

Discussion

The ExampleReader class is based on the IDLitReader class (discussed in Subclassing from the IDLitReader Class). As a result, all of the standard features of an iTool file reader 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 ExampleReader Init method does the following things:

  1. Calls the Init method of the superclass, IDLitReader. We specify a list of accepted filename extensions (only ppm, in this case) via the Extensions argument. We include a description of the reader via the DESCRIPTION keyword. Finally, we use the _EXTRA keyword inheritance mechanism to pass through any keywords provided when the ExampleReader Init method is called.
  2. Returns the integer 1, indicating successful initialization.

Creating a Cleanup Method

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

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

Note
If your file reader class is based on the IDLitReader 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 "IDLitReader::Cleanup" (IDL Reference Guide) for additional details.

Example Cleanup Method

PRO ExampleReader::Cleanup 
 
   ; Clean up superclass 
   self->IDLitReader::Cleanup 
 
END 

Discussion

Since our file reader 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 reader class GetProperty method retrieves property values from the file reader object instance or from instance data of other associated objects. It should retrieve the requested property value, either from the file reader 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 reader need not register any properties at all, if the read operation is simple. Many of the standard iTool image file readers work without registering any properties.

See "IDLitReader::GetProperty" (IDL Reference Guide) for additional details.

Example GetProperty Method

PRO ExampleReader::GetProperty, _REF_EXTRA = _extra 
 
   IF (N_ELEMENTS(_extra) GT 0) THEN $ 
       self->IDLitReader::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 reader. Since the file reader we are creating has no properties of its own, there are no keywords explicitly defined. The keyword inheritance mechanism allows properties to be retrieved from the ExampleReader class' superclasses without knowing the names of the properties.

Since our ExampleReader 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 reader SetProperty method stores property values in the file reader 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 reader need not register any properties at all, if the read operation is simple. Many of the standard iTool image file readers work without registering any properties.

See "IDLitReader::SetProperty" (IDL Reference Guide) for additional details.

Example SetProperty Method

PRO ExampleReader::SetProperty, _REF_EXTRA = _extra 
 
   IF (N_ELEMENTS(_extra) GT 0) THEN $ 
      self->IDLitReader::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 reader we are creating has no properties of its own, no keywords are explicitly defined. The keyword inheritance mechanism allows properties to be set on the ExampleReader 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 an IsA Method

The file reader IsA method must accept a string containing the name of the file to be read as its only parameter, and must determine whether the file is of the proper type to be read by your file reader. If the file is of the correct type, the IsA method must return 1; if the file is not of the correct type, the IsA method should display an error message and return 0.

See "IDLitReader::IsA" (IDL Reference Guide) for additional details.

Example IsA Method

FUNCTION ExampleReader::IsA, strFilename 
 
   iDot = STRPOS(strFilename, '.', /REVERSE_SEARCH) 
 
   IF (iDot GT 0) THEN BEGIN 
      fileSuffix = STRUPCASE(STRMID(strFilename, iDot + 1)) 
      IF (STRUPCASE(fileSuffix) EQ 'PPM') THEN RETURN, 1 
   ENDIF 
 
   self->IDLitIMessaging::ErrorMessage, $ 
      ["The specified file is not a PPM file."], $ 
      SEVERITY = 0, TITLE="Wrong File Type" 
 
   RETURN, 0 
 
END 

Discussion

Note
Our example IsA method will simply check the filename for the presence of the proper filename extension. A more sophisticated IsA method would actually inspect the contents of the specified file.

The IsA method accepts a string that contains a file name. Using the supplied file name, we first search backwards from the end of the name until we locate a dot character. If the filename contains a dot, we extract the string that follows the dot and convert it to upper case. If the extracted string is 'PPM', we return success; if the extracted string is not 'PPM' or if there is no dot in the file name, we issue an error using the IDLitIMessaging::ErrorMessage method and return failure.

Creating a GetData Method

The file reader GetData method does the work of the file reader, first creating an IDL variable or variables to contain the data read from the file, then placing the data into an iTool data object. If this process is successful, the GetData method must place the created data object in the variable supplied as the method's only argument and return 1 for success. If the process is not successful, the GetData method must return 0.

See "IDLitReader::GetData" (IDL Reference Guide) for additional details.

Example GetData Method

FUNCTION ExampleReader::GetData, oImageData 
 
   ; Get the name of the file currently associated with the reader. 
   filename = self->GetFilename() 
 
   ; Read the file. 
   READ_PPM, filename, image 
 
   ; Store image data in Image Data object. 
   oImageData = OBJ_NEW('IDLitDataIDLImage', $ 
      NAME = FILE_BASENAME(fileName)) 
 
   IF OBJ_VALID(oImageData) THEN BEGIN 
      RETURN, oImageData->SetData(image, 'ImagePixels', /NO_COPY) 
   ENDIF 
 
   RETURN, 0 
 
END 

Discussion

The GetData method accepts a single argument, which is a named variable that will contain the data object. Our GetData method's first step is to retrieve the file name of the file on which the method is being called using the GetFilename method. Since our example file reader reads data from PPM files, the file name is then passed to the IDL READ_PPM procedure. An IDLitDataIDLImage object that will hold the image data is created in the named variable specified by the argument to the GetData method (oImageData, in this case); the NAME property set to the filename of the original data file. We check to ensure that the oImageData object was created successfully and add the image data returned by the READ_PPM procedure using the IDLitData::SetData method. Note the use of the NO_COPY keyword to prevent making copies of the image data array, which could be quite large. Finally, we return the value returned by the SetData method (1 for success, 0 for failure), or we return 0 if oImageData is not a valid object.

Note
The type of data object created (IDLitDataIDLImage, in this example) affects how a particular tool will behave when reading the file. If the data type of the object returned by the file reader matches one of the data types specified for a parameter of the visualization being created, the data object is associated with that parameter. See Data Type Matching for additional information.