Welcome to the Harris Geospatial product documentation center. Here you will find reference guides, help documents, and product libraries.

  >  Docs Center  >  ENVI API  >  Write a Custom Open Procedure


Write a Custom Open Procedure

Write a Custom Open Procedure

You can write a procedure that opens a data file when an ENVI header is not available, or when you want to pass custom metadata into your spatial and spectral readers. You can also add the procedure to the File > Open As > Custom menu.

The procedure must have the following declaration statement:

PRO MyFile, filename, UVALUE = uvalue, R_FID = r_fid


  • MyFile is the name of the custom open procedure.
  • filename is a string containing the fully-qualified URI to the file on disk that is opened.
    • When opening a custom file from the Open As > Custom menu, this argument is not passed in, and you must have a call to DIALOG_PICKFILE in the custom open procedure to select a file. In this case, you are not required to pass the argument back out, but it is recommended to ensure that the correct filename is displayed in ENVI. If the procedure does not pass out a valid filename, ENVI determines the filename from the returned file ID (R_FID).
    • When opening a custom file using the CUSTOM_TYPE keyword to ENVI::OpenRaster, the filename set as the URI argument to ENVI::OpenRaster will be passed into the custom open procedure as the filename argument. In this case, you are not required to have a call to DIALOG_PICKFILE.
    • To write a custom open procedure that can be called from the user interface menu or programmatically, add the following logic to the beginning of the procedure:
    • IF (N_elements(filename) EQ 0) THEN $
         file = DIALOG_PICKFILE(/READ)
  • UVALUE is an optional keyword that is passed into the procedure. It contains the UVALUE set in ENVI::AddCustomReader or the UVALUE passed into ENVI::OpenRaster.
  • R_FID is the file ID returned from the procedure's call to ENVI_SETUP_HEAD. It is passed out of the procedure.

Write an Init Procedure

You can also write a procedure called filename_CUSTOM_READER_INIT, where filename is the name of the custom open procedure. Using the example above, the init procedure would be named MyFile_CUSTOM_READER_INIT.

It should contain the following code:

  e.AddCustomReader, <etc.>

When ENVI starts, it will automatically detect the custom open procedure and add it to the File > Open As > Custom menu. The init procedure calls the ENVI::AddCustomReader method. See the ENVI::AddCustomReader topic for a list of arguments and keywords.


The code example below opens a custom data file that contains a combination of required and custom metadata, which is embedded in the file itself as opposed to a separate header file.

The main procedure in this example reads the following required metadata:

  • Number of bands
  • Number of samples
  • Number of lines
  • Interleave type (BSQ, BIL, or BIP)

It also reads the following custom metadata and adds it to a structure named info:

  • Scale factor
  • Minimum data value
  • Data type

The procedure passes the info structure into the POINTER_INFO keyword in ENVI_SETUP_HEAD. The spatial and spectral readers within the open procedure get the info structure from ENVI_FILE_QUERY. The structure tag/value pairs that you set will also be available on the ENVIRasterMetadata object after the file is opened.

Data values for the custom raster file are computed as follows:

Minimum data value + scale factor * data type

This example contains an _init procedure that adds two options to the ENVI menu:

  • File > Open As > Custom > Open Custom File to Float
  • File > Open As > Custom > Open Custom File to Double

The main procedure determines which menu option was selected by getting the UVALUE from the widget event. The procedure then obtains the necessary information for opening the file, which is passed directly into ENVI_SETUP_HEAD. The main procedure also defines the spatial and spectral readers.


Metadata for the custom file is in the form of an embedded header, whose bytes are organized as follows:

  • Byte 0: Byte order
    • 0: No byte swapping
    • 1: Byte swapping
  • Bytes 1-15: ASCII characters, ENVIEmbeddedHDR. If these bytes are anything else, the file is a different type and the reader should stop execution.
  • Bytes 16-23: Number of samples (64-bit long integer)
  • Bytes 24-31: Number of lines (64-bit long integer)
  • Bytes 32-39: Number of bands (64-bit long integer)
  • Byte 40: Interleave type
    • 0: Band sequential (BSQ)
    • 1: Band interleaved by line (BIL)
    • 2: Band interleaved by pixel (BIP)
  • Bytes 41-48: Scale factor (double-precision)
  • Bytes 49-56: Minimum data value (double-precision)
  • Byte 57: IDL data type code (refer to the IDL Help)
  • Bytes 58-59: The number of bytes of the file description string (integer)
  • Bytes 60+: User-defined description (ASCII)

Example Code

  e.AddCustomReader, 'Open Custom File to Float', $
     'example_custom_metadata', $
     PATH = 'Example Custom Format', UVALUE = 'float'
  e.AddCustomReader, 'Open Custom File to Double', $
     'example_custom_metadata', $
     PATH = 'Example Custom Format', UVALUE = 'double'
PRO example_custom_metadata, file, UVALUE = uvalue, R_FID = r_fid
  IF (N_elements(filename) EQ 0) THEN $
  ; Open the file and read the embedded header
  OPENR, unit, file, /GET_LUN
  byteOrder = BYTE(0)
  headerString = string('', FORMAT = '(A15)')
  READU, unit, byteOrder, headerString
  ; If header string does not read 'ENVIEmbeddedHDR' then the file is not
  ; the file type defined in this example.
  IF (headerString NE 'ENVIEmbeddedHDR') THEN RETURN
  ns = LONG64(0)
  nl = LONG64(0)
  nb = LONG64(0)
  interleave = BYTE(0)
  scaleFactor = DOUBLE(0)
  minValue = DOUBLE(0)
  storageType = BYTE(0)
  descriptionLen = 0s
  READU, unit, ns, nl, nb, interleave, scaleFactor, minValue, $
     storageType, descriptionLen
  IF (descriptionLen GT 0) THEN BEGIN
     format = STRCOMPRESS('(A'+STRING(descriptionLen)+')', /REMOVE_ALL)
     description = STRING('', FORMAT=format)
     READU, unit, description
  description = ''
  ; Use the UVALUE to determine which button was clicked. 
  ; This determines whether the data will be opened as float or double.
  IF (uvalue EQ 'float') THEN dataType = 4 ELSE dataType = 5
  info = {scaleFactor:scaleFactor, $
     minValue:minValue, $
  headerOffset = 60+descriptionLen
  ; Define the spatial and spectral read routines. The spectral
  ; read routine is optional.
  readProcedures = ['example_custom_metadata_spatial', $
     DATA_TYPE = dataType, $
     DESCRIP = description, $
     FNAME = file, $
     INTERLEAVE = interleave, $
     NB = nb, $
     NL = nl, $
     NS = ns, $
     OFFSET = headerOffset, $
     POINTER_INFO = info, $
     R_FID = r_fid, $
     READ_PROCEDURE = readProcedures, $

© 2018 Harris Geospatial Solutions, Inc. |  Legal
My Account    |    Store    |    Contact Us