Articles

SpatialEcology.Com

 You are here: Home > Articles

Accessing raster cell values programmatically: the problem of mismatched data types.

This article relates to an automation error message that is sometimes generated when using raster datasets with scripts or extensions written in Visual Basic. That error message is: "Variable uses an automation type not supported in Visual Basic"

In order to understand why this error arises it is necessary to delve into the technical aspects of how raster data is stored. As we know, raster data is essentially a collection of numbers, arranged in a grided fashion, that represents some aspect of the world. There are a number of raster data formats that can be used to store these number: the three common ones used by ArcGIS are Grids, GeoTiffs, and ERDAS Imagine files. What is not at all apparent is that within these files, there are many different data types that can be used to store the numbers themselves. ArcGIS employs the following 14 data types:

Constant Value Description
PT_U1 0 Pixel values are 1 bit.
PT_U2 1 Pixel values are 2 bits.
PT_U4 2 Pixel values are 4 bits.
PT_UCHAR 3 Pixel values are unsigned 8 bit integers.
PT_CHAR 4 Pixel values are 8 bit integers.
PT_USHORT 5 Pixel values are unsigned 16 bit integers.
PT_SHORT 6 Pixel values are 16 bit integers.
PT_ULONG 7 Pixel values are unsigned 32 bit integers.
PT_LONG 8 Pixel values are 32 bit integers.
PT_FLOAT 9 Pixel values are single precision floating point.
PT_DOUBLE 10 Pixel values are double precision floating point.
PT_COMPLEX 11 Pixel values are complex.
PT_DCOMPLEX 12 Pixel values are double precision complex.

Table 1. Data types used to store numbers in raster datasets.

The reason there are a number of data types to choose from is because the data type affects file size and speed of processing. For example, one bit can have one of two values: 0 or 1. If we are storing boolean data (True/False) in theory only one bit/cell is needed to store that information. If we were to use the PT_LONG data type to store True/False data, 31 of 32 bits available to us per cell would be unused: this would increase the file size and slow down any processing of that grid (it takes longer to read a 32 bit value than a 1 bit value).

For a most operations on raster datasets (e.g. using ArcObjects), we can ignore the data type because ArcObjects deals with it automatically. However, in cases where we might want to directly access the raster values in order to perform a custom analysis we face the problem that not all of these data types are available to us in the Visual Basic development environment (this problem applies to other languages too). In Visual Basic 6 we have the following data types to work with:

Data type Storage size Range
Byte 1 byte 0 to 255
Boolean 2 bytes True or False
Integer 2 bytes -32,768 to 32,767
Long (long integer) 4 bytes -2,147,483,648 to 2,147,483,647
Single (single-precision floating-point) 4 bytes -3.402823E38 to -1.401298E-45 for negative values; 1.401298E-45 to 3.402823E38 for positive values
Double (double-precision floating-point) 8 bytes -1.79769313486232E308 to -4.94065645841247E-324 for negative values; 4.94065645841247E-324 to 1.79769313486232E308 for positive values
Currency (scaled integer) 8 bytes -922,337,203,685,477.5808 to 922,337,203,685,477.5807
Decimal 14 bytes +/-79,228,162,514,264,337,593,543,950,335 with no decimal point; +/-7.9228162514264337593543950335 with 28 places to the right of the decimal; smallest non-zero number is +/-0.0000000000000000000000000001
Date 8 bytes January 1, 100 to December 31, 9999
Object 4 bytes Any Object reference
String (variable-length) 10 bytes + string length 0 to approximately 2 billion
String (fixed-length) Length of string 1 to approximately 65,400
Variant (with numbers) 16 bytes Any numeric value up to the range of a Double
Variant (with characters) 22 bytes + string length Same range as for variable-length String

Table 2. Data types used to store numbers in Visual Basic 6

In order to compare this table to Table 1 it is necessary to know that there are 8 bits in 1 byte. It is also important to realize that data types come in a signed and unsigned variety. Taking Visual Basics 2 byte integer as an example (2 bytes = 16 bits), we can deduce that the range of values it could be used to represent is 0 to 2^16 (2 to the power of 16) which is 0 to 65536. But if we use the first bit to record whether that number is positive or negative, the range of values then becomes +/- 2^15, or -32768 to 32767.

If you compare Table 1 to Table 2 you will notice that there are some raster data types in Table 1 that do not have an equivalent data type in Table 2. The following are the raster data types that have an equivalent in Visual Basic 6:

PT_UCHAR = Byte (unsigned 1 byte)
PT_SHORT = Integer (signed 2 bytes)
PT_LONG = Long Integer (signed 4 bytes)
PT_DOUBLE = Double (signed 8 bytes)

Thus, if you were using a method that attempted to set a variable in VB to hold a raster value (e.g. using the IPixelBlock.GetVal method) you would have to ensure that the VB variable matched the raster data type, and that the raster data type was one of the above four types. If you do not, you will either generate the error message shown at the top of the screen, or you could incorrectly assign a data type (i.e. you are programmatically able to set a PT_CHAR cell value to a Byte variable, but you get a bizarre result if you do - do not do this!).

The situation is slightly improved in Visual Basic .NET, which has a greater number of data types as shown below:

Visual Basic type Abbrev Common language runtime type structure Nominal storage allocation Value range
Boolean bln System.Boolean 2 bytes True or False.
Byte byt System.Byte 1 byte 0 through 255 (unsigned).
Char cha System.Char 2 bytes 0 through 65535 (unsigned).
Date dtm System.DateTime 8 bytes 0:00:00 on January 1, 0001 through 11:59:59 PM on December 31, 9999.
Decimal dec System.Decimal 16 bytes 0 through +/-79,228,162,514,264,337,593,543,950,335 with no decimal point; 0 through +/-7.9228162514264337593543950335 with 28 places to the right of the decimal; smallest nonzero number is +/-0.0000000000000000000000000001 (+/-1E-28).
Double (double-precision floating-point) dbl System.Double 8 bytes -1.79769313486231570E+308 through -4.94065645841246544E-324 for negative values; 4.94065645841246544E-324 through 1.79769313486231570E+308 for positive values.
Integer or Int32 int System.Int32 4 bytes -2,147,483,648 through 2,147,483,647.
Long or Int64 (long integer) lng System.Int64 8 bytes -9,223,372,036,854,775,808 through 9,223,372,036,854,775,807.
Object obj System.Object (class) 4 bytes Any type can be stored in a variable of type Object.
Short or Int16 shr System.Int16 2 bytes -32,768 through 32,767.
Single (single-precision floating-point) sng System.Single 4 bytes -3.4028235E+38 through -1.401298E-45 for negative values; 1.401298E-45 through 3.4028235E+38 for positive values.
String (variable-length) str System.String (class) Depends on implementing platform 0 to approximately 2 billion Unicode characters.
User-Defined Type (structure)   (inherits from System.ValueType) Depends on implementing platform Each member of the structure has a range determined by its data type and independent of the ranges of the other members.

Table 3. Data types used to store numbers in Visual Basic .NET

In this case the following raster data types can be directly accessed:

PT_UCHAR = Byte (unsigned 1 byte)
PT_USHORT = Char (unsigned 2 byte) ***
PT_SHORT = Int16 (signed 2 bytes)
PT_DOUBLE = Double (signed 8 bytes)
PT_LONG = Int32 (signed 4 bytes)

What is the solution to this problem?

The solution I developed was to write a program that converts raster data types into one of the four data types that can be directly accessed by VB6. The tool is available for free in HawthsTools2 and is called Convert Raster Data Type.

Author: Hawthorne Beyer (hawthorne@spatialecology.com)

  Home   |   Hawth's Tools   |   Articles   |   Services