OSM Map On Garmin/DEM Subfile Format

From OpenStreetMap Wiki
Jump to navigation Jump to search

OSM Map On Garmin

A reverse-engineering of Garmin's DEM Subfile format

The DEM Subfile contains the digital elevation model for a Garmin map. The data is used for hillshading and elevation profiles in MapSource and on Garmin devices.

DEM Header

Common Header

The structure of the common header is the same in all subfiles.

Byte Offset Length (bytes) Description
0x000 2 Header length. So far only '0x29' (and '0x25') have been seen.
0x002 10 Type GARMIN DEM
0x00C 1 0x01 ?
0x00D 1 0x00
0x00E 2 Creation year
0x010 1 Creation month
0x011 1 Creation day
0x012 1 Creation hour
0x013 1 Creation minute
0x014 1 Creation second

DEM-specific Header

Byte Offset Length (bytes) Description
0x015 4 Seems to be flags for interpreting the DEM data. First bit defines whether elevation is given in meter (0) or feet (1). On most maps any other bits are zero.
0x019 2 number of zoom levels (can be different from the number of map levels)
0x01B 4 00 00 00 00
0x01F 2 size of record in data block 3 (always 0x3c ?)
0x021 4 points to the begin of data block 3
0x025 4 Only present for header length 0x29. All zero so far.

DEM-data

The following example is drawn from an "empty" DEM file generated by GMapTool for a map with five levels. Each zoom level contains 2 data blocks.

Data block 1

The records in this block seem to correspond to a rectangle of the map ("tile") and describe the records in data block 2. The record length varies according to values in data block 3. It can be 3 ("empty" DEM only?) up to 8 bytes.

Length (bytes) Description
1, 2 or 3 Offset in data block 2 relative to start of block; zero for the first and "empty" blocks.
1 or 2 base height
1 or 2 difference between maximum height and base height
0 or 1 unknown; 0x00 or 0x02 seen so far

In the empty DEM file, the records are filled with

00 00 00 02

The "base height" seems to contain the elevation at least for "empty" blocks describing areas without data (e.g. sea): Sea areas are often shown with a height of -8888m in Basecamp/Mapsource. This corresponds to -29,160ft = 0x8e18, a value which is often found in this section.

The tiles are ordered row by row starting in north-western corner and ending in south-eastern corner of covered area. For a level with 4 tiles you would get the following indices:

00 01 02 03
04 05 06 07
08 09 0A 0B
0C 0D 0E 0F
Data block 2

There is a block for each map level. In the empty DEM file, however, these blocks are empty (length zero).

Otherwise it contains the real elevation data per tile. This data has to be compressed since the length of data per tile varies heavy. The data may also be normalized. Perhaps to the height difference given in data block 1?

Data block 3

This block describes the position and structure of data blocks 1 and 2. There is one record (60 bytes) per zoom level (see DEM header).

Byte Offset Example bytes Description
0x00 00 00 index of the record (starting with zero)
0x02 40 00 00 00 number of pixel/tile (x-axis)
0x06 40 00 00 00 number of pixel/tile (y-axis)
0x0A 02 00 00 00 unknown; values in latitude direction or information about resolution of elevation data?
0x0E 02 00 00 00 unknown; values in longitude direction or information about resolution of elevation data?
0x12 00 00 ?
0x14 00 00 00 00 number of tiles in x direction - 1 (Columns)
0x18 00 00 00 00 number of tiles in y direction - 1 (Rows)
0x1c 10 00 Describe the structure of records in data block 1.

The lowest two bits are the "offset size": 00 = 1 byte; 01 = 2 byte; 10 = 3 byte; 11 = 4 byte (last was not seen so far) The third bit defines size of "base height" field. If set this field is 2 bytes long, otherwise just 1. The forth bit defines size of "height difference" field. If set this field is 2 bytes long, otherwise just 1. If the fifth bit is set there will be an extra byte in the records.

0x1e 04 00 Size of record in data block 1. Values up to 8 have been seen.
0x20 25 00 00 00 pointer to the start of corresponding data block 1
0x24 29 00 00 00 pointer to the start of corresponding data block 2
0x28 00 2d b2 05 western boundary (4 bytes!)
0x2c 00 e7 d5 24 northern boundary (4 bytes!)
0x30 00 d1 8f 00 Distance between pixel (n-s direction)?
0x34 00 05 a2 00 Distance between pixel (w-e direction)?
0x38 00 00 minimum height. This is the minimum of all base heigth given in records of data block 1.
0x3a 00 00 maximum height. There is at least one record where base height + height difference = maximum height.

Remarks: The elevation data is formed from discrete points which are referenced as pixel in the above table.

Further findings about the DEM format,based on reverse engineering,can be found at DEM Explorer

Another step to exploring the DEM format, based on a lot of trial and error, can be found at Garmin-DEM-Build. There is my algorithm to build your on DEM-File-Encoder and a ready to use C#-program.