X

NV5 Geospatial Blog

Each month, NV5 Geospatial posts new blog content across a variety of categories. Browse our latest posts below to learn about important geospatial information or use the search bar to find a specific topic or author. Stay informed of the latest blog posts, events, and technologies by joining our email list!



10717 Rate this article:
No rating

Creating tiled TIFF files with IDL code

Anonym

The code example shown at the bottom, writes a TIFF image using tiled image format instead of the normal TIFF image format. Standard TIFF images use strips that span all the way across the X dimension, and is only split in the Y dimension. According to the TIFF specification document, section 15:

For low-resolution to medium-resolution images, the standard TIFF method of breaking the image into strips is adequate. However high-resolution images can be accessed more efficiently—and compression tends to work better—if the image is broken into roughly square tiles instead of horizontally-wide but vertically narrow strips.

 

This is a quick test to check the data type support:

IDL> data = double(dist(800,600))

IDL> tiff6_write, 'test.tif', data & help, read_tiff('test.tif')

<Expression>    DOUBLE   = Array[800, 600]

IDL> tiff6_write, 'test.tif', float(data) & help, read_tiff('test.tif')

<Expression>    FLOAT    = Array[800, 600]

IDL> tiff6_write, 'test.tif', ulong(data) & help, read_tiff('test.tif')

<Expression>    ULONG    = Array[800, 600]

IDL> tiff6_write, 'test.tif', long(data) & help, read_tiff('test.tif')

<Expression>    LONG     = Array[800, 600]

IDL> tiff6_write, 'test.tif', uint(data) & help, read_tiff('test.tif')

<Expression>    UINT     = Array[800, 600]

IDL> tiff6_write, 'test.tif', fix(data) & help, read_tiff('test.tif')

<Expression>    INT      = Array[800, 600]

IDL> tiff6_write, 'test.tif', byte(data) & help, read_tiff('test.tif')

<Expression>   BYTE      = Array[800, 600]

 

This is the code used to produce the tiled TIFF files:

 

function tiff6_Ifd, tag, type, count,valueOffset

 compile_opt idl2,logical_predicate

 typelen = [1,1,1,2,4,8,1,1,2,4,8,4,8]

 ifd = { tiff6ifd, tag: 0us, type: 0us, count: 0ul, valueOffset: 0ul }

 ifd.tag = tag

 ifd.type = type

 ifd.count = count

 len = typelen[type]*count

 if len le 4 then begin

   case type of

     3: ifd.valueOffset= ulong([uint(valueOffset), 0us],0)

     4: ifd.valueOffset= ulong(valueOffset)

     8: ifd.valueOffset= ulong([fix(valueOffset), 0s],0)

     9: ifd.valueOffset= ulong(long(valueOffset),0)

     11: ifd.valueOffset= ulong(float(valueOffset),0)

     else: if max(type eq [1,2,6,7]) then begin

          ifd.valueOffset = ulong([byte(valueOffset), 0b,0b,0b],0)

       endif else message, 'Unsupported type: '+strtrim(type,2)

   endcase

 endif else begin

   ifd.valueOffset = ulong(valueOffset)

   if arg_present(valueOffset) then begin

     valueOffset += len

   endif

 endelse

 return, ifd

end

 

pro tiff6_write, filename, data

 compile_opt idl2,logical_predicate

 ;header

 byteord = byte(1us,0) ? 'II' : 'MM'

 header = { byteord: byteord, magic: 42us, ifdOffset: 8ul }

 numIfd = 18us

 

 ;determine length and type

 sz = size(data, /struct)

 sz.dimensions >= 1

 h = hash('BYTE',[1,1,1],'INT',[8,2,2],'UINT',[3,2,1],'LONG',[9,4,2], $

   'ULONG',[4,4,1],'FLOAT',[11,4,3],'DOUBLE',[12,8,3])

 if h.HasKey(sz.type_name)then begin

   info = (orderedhash(list('type','len','frmt'), $

     list(h[sz.type_name],/extract))).ToStruct()

 endif else message, 'Unsupported type: '+sz.type_name

 

 ;strings need to be 0 terminated and even length

 software = [byte('IDL 8.3'),0b]

 datetime = [byte(string(systime(/julian), format= $

   '(c(cyi4.4,":",cmoi2.2,":",cdi2.2,"",cHi2.2,":",cmi2.2,":",csi2.2))')),0b]

 

 ;compute tile info

 tileSize = 128

 tileByteSize = info.len*tileSize^2

 n = sz.dimensions/tileSize + (sz.dimensions mod tileSize ne 0)

 ntiles = n[0]*n[1]

 

 ptr = 8 + 2 + numIfd*12 + 4

 

 ;fill in fields

 ifds = list()

 ifds.Add, tiff6_ifd(256, 4, 1, sz.dimensions[0]) ; width

 ifds.Add, tiff6_ifd(257, 4, 1, sz.dimensions[1]) ; length

 ifds.Add, tiff6_ifd(258, 3, 1, info.len*8) ; bits

 ifds.Add, tiff6_ifd(259, 3, 1, 1) ; compression

 ifds.Add, tiff6_ifd(262, 3, 1, 1) ; photometric interpretation

 ifds.Add, tiff6_ifd(274, 3, 1, 1) ; orientation

 ifds.Add, tiff6_ifd(277, 3, 1, 1) ; samples per pixel

 ifds.Add, tiff6_ifd(282, 5, 1, ptr) ; xresolution

 ifds.Add, tiff6_ifd(283, 5, 1, ptr) ; yresolution

 ifds.Add, tiff6_ifd(284, 3, 1, 1) ; planar configuration

 ifds.Add, tiff6_ifd(296, 3, 1, 2) ; resolution unit

 ifds.Add, tiff6_ifd(305, 2, n_elements(software), ptr) ; software

 ifds.Add, tiff6_ifd(306, 2, n_elements(datetime), ptr) ; datetime

 ifds.Add, tiff6_ifd(322, 4, 1, tileSize) ; tile width

 ifds.Add, tiff6_ifd(323, 4, 1, tileSize) ; tile length

 ifds.Add, tiff6_ifd(324, 4, ntiles, ptr) ; tile offsets

 ifds.Add, tiff6_ifd(325, 4, ntiles, ptr) ; tile byte counts

 ifds.Add, tiff6_ifd(339, 3, 1, info.frmt) ; sample format

 

 ;fields that require more data

 aux = list()

 aux.Add, ulong([100,1])

 aux.Add, ulong([100,1])

 aux.Add, software

 aux.Add, datetime

 aux.Add, ulindgen(ntiles, start=ptr, increment=tileByteSize)

 tmp = replicate(tileByteSize, ntiles)

 aux.Add, tmp

 

 if numifd ne n_elements(ifds) then message, 'IFD size mismatch'

 ;write to file

 openw, lun, filename,/get_lun

 writeu, lun, header

 writeu, lun, numIfd

 writeu, lun, ifds.ToArray()

 writeu, lun, 0ul ; next IFD, formulti image

 foreach x, aux do writeu, lun, x

 tmp = make_array([tileSize,tileSize], type=size(data,/type))

 for j=0, n[1]-1 do begin

   ys = j*tileSize

   ye = (j*tileSize + tileSize-1) < (sz.dimensions[1]-1)

   for i=0, n[0]-1 do begin

     xs = i*tileSize

     xe = (i*tileSize +tileSize-1) < (sz.dimensions[0]-1)

     tmp[0,0] = data[xs:xe,ys:ye]

     writeu, lun, tmp

   endfor

 endfor

 free_lun, lun

end

Please login or register to post comments.
«July 2025»
SunMonTueWedThuFriSat
293012345
6789101112
13141516171819
20212223242526
272829303112
3456789
Digital Number, Radiance, and...

Number of views (172263)

Push Broom and Whisk Broom Sensors

Number of views (154474)

The Many Band Combinations of Landsat 8

Number of views (121617)

What Type of Loop Should I Use?

Number of views (80285)

Mapping Coastal Erosion Using LiDAR

Number of views (59015)