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!



Comparing Amplitude and Coherence Time Series With ICEYE US GTR Data and ENVI SARscape

Comparing Amplitude and Coherence Time Series With ICEYE US GTR Data and ENVI SARscape

12/3/2025

Large commercial SAR satellite constellations have opened a new era for persistent Earth monitoring, giving analysts the ability to move beyond simple two-image comparisons into robust time series analysis. By acquiring SAR data with near-identical geometry every 24 hours, Ground Track Repeat (GTR) missions minimize geometric decorrelation,... Read More >

Empowering D&I Analysts to Maximize the Value of SAR

Empowering D&I Analysts to Maximize the Value of SAR

12/1/2025

Defense and intelligence (D&I) analysts rely on high-resolution imagery with frequent revisit times to effectively monitor operational areas. While optical imagery is valuable, it faces limitations from cloud cover, smoke, and in some cases, infrequent revisit times. These challenges can hinder timely and accurate data collection and... Read More >

Easily Share Workflows With the Analytics Repository

Easily Share Workflows With the Analytics Repository

10/27/2025

With the recent release of ENVI® 6.2 and the Analytics Repository, it’s now easier than ever to create and share image processing workflows across your organization. With that in mind, we wrote this blog to: Introduce the Analytics Repository Describe how you can use ENVI’s interactive workflows to... Read More >

Deploy, Share, Repeat: AI Meets the Analytics Repository

Deploy, Share, Repeat: AI Meets the Analytics Repository

10/13/2025

The upcoming release of ENVI® Deep Learning 4.0 makes it easier than ever to import, deploy, and share AI models, including industry-standard ONNX models, using the integrated Analytics Repository. Whether you're building deep learning models in PyTorch, TensorFlow, or using ENVI’s native model creation tools, ENVI... Read More >

Blazing a trail: SaraniaSat-led Team Shapes the Future of Space-Based Analytics

Blazing a trail: SaraniaSat-led Team Shapes the Future of Space-Based Analytics

10/13/2025

On July 24, 2025, a unique international partnership of SaraniaSat, NV5 Geospatial Software, BruhnBruhn Innovation (BBI), Netnod, and Hewlett Packard Enterprise (HPE) achieved something unprecedented: a true demonstration of cloud-native computing onboard the International Space Station (ISS) (Fig. 1). Figure 1. Hewlett... Read More >

1345678910Last
12116 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.