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!



Using ENVI and IDL Agents with Your Own API Keys

Using ENVI and IDL Agents with Your Own API Keys

6/22/2026

Earlier this year, we introduced the ENVI® Agent and IDL® Agent to bring intelligent, AI-driven automation to your geospatial and data science workflows. If you missed the launch, you can catch up on the full breakdown by watching our release webinar. Both agents are built upon GitHub Copilot, a powerful AI orchestration... Read More >

What We're Looking Forward to at Esri UC 2026

What We're Looking Forward to at Esri UC 2026

6/16/2026

Every year, the Esri User Conference brings together thousands of geospatial professionals to explore new technologies, share ideas, and learn how organizations are solving complex challenges with GIS. For many members of the NV5 team, attending Esri UC is an annual tradition. Some have attended for more than 15 years. Others will be... Read More >

New ENVI Agent, IDL Agent, and GeoAgent Quick Guides

New ENVI Agent, IDL Agent, and GeoAgent Quick Guides

6/9/2026

The recent release of ENVI® Agent, IDL® Agent, and GeoAgent™ revolutionize how users interact with geospatial software. These agentic AI applications act as partners to plan, simplify, and execute complex workflows. Knowing where to start can be challenging for new users. To this end, we developed three new quick guides to... Read More >

Introducing NISAR Data Support

Introducing NISAR Data Support

6/5/2026

The release of ENVI® SARscape 6.3 in April 2026 includes preliminary support for NASA-ISRO SAR (NISAR) data. The NISAR mission is a joint Earth-observing satellite project between NASA and the Indian Space Research Organization designed to monitor changes in the planet’s land and ice surfaces using advanced radar imaging. It... Read More >

Monitoring Illegal Mining in the Amazon: Turning Persistent Data Into Actionable Insight

Monitoring Illegal Mining in the Amazon: Turning Persistent Data Into Actionable Insight

5/28/2026

Illegal mining over decades has constituted one of the most persistent and complex socio-environmental problems in the Brazilian Amazon. In recent years, with the increasingly intensive use of mechanized extraction, the associated environmental impacts—such as deforestation, intense soil disturbance, river siltation, and mercury... Read More >

1345678910Last
6227 Rate this article:
No rating

Using the Clipboard, Static Methods and ZLIB compression in IDL 8.3

Jim Pendleton

When the Exelis Professional Services Group is contracted to author "large" applications for clients, we often have the luxury of building full installers that we use to place a variety of resource files and directories onto disk, along with the main functionality of an application or toolset.

In this environment, the ROUTINE_FILEPATH  function is a huge help for bootstrapping the application so it can find its resource files relative to its installation directory.

For smaller projects, however, it is often more convenient if all the resources, such as bitmap button images, can be bundled into a single file, in particular a compiled IDL SAVE file. This reduces the complexity of installation and testing.

Various routines exist for turning, say, bitmap images into IDL source code. I will show a version below that employs the new IDL 8.3 function for lossless, in-memory ZLIB compression of the image data. It also uses the new Clipboard static class so you can paste the generated code into a text editor with a single button click.

Finally, we'll investigate a utility for automatically generating an entire class of static methods which store a directory of images, greatly simplifying their accessibility.

The routine listed below takes as input an image in the form of a BYTARR along with a string that will be applied as the name of a new IDL function. It generates PRO code and places it into the system's clipboard as ASCII text. You can then paste the generated code directly into an editor window, which you will compile and execute.

PRO ImageToCode, image, functionName
 d = SIZE(image, /DIMENSIONS)
 z = ZLIB_COMPRESS(image)
 b64 = IDL_BASE64(z)
 l = LIST()
 l.Add, 'FUNCTION ' + functionName
 dims = STRJOIN(STRTRIM(D, 2), ',')
 l.Add, 'lines = LIST()'
 FOR i = 0L, STRLEN(b64) - 1, 66 DO $
    l.Add, "lines.ADD, '" + STRMID(b64, I, 66) + "'"
 l.Add, 's = IDL_BASE64(STRJOIN(lines.ToArray(/NO_COPY), ""))'
 l.Add, 'd = ZLIB_UNCOMPRESS(s)'
 l.Add, 'RETURN, REFORM(d, ' + dims + ')'
 l.Add, 'END'
 Clipboard.Set, l.ToArray(/NO_COPY)
END

In order to make the output code for the image data we first call the ZLIB_COMPRESS function to create an in-memory version of the image bitmap, using lossless compression. To simplify the code we will make an initial assumption that the input image is a 24-bit (RGB) image in a BYTARR.

Because we want to create IDL source code from this, we convert the binary data produced by ZLIB_COMPRESS into an ASCII format with the IDL_BASE64 function. This is a useful trick for encoding any type of binary data that needs to be exchanged in an ASCII format, for example via standard JSON objects passed to and from an ENVI Services Engine instance.

In order to make the output PRO code more legible, the output string from IDL_BASE64 is broken up over multiple lines, each with a maximum length of 80 characters. 

The new function code we create performs the inverse operations, converting the string back to binary via IDL_BASE64, then regenerating the BYTARR binary data via the ZLIB_UNCOMPRESS function.  Notice that the REFORM function call is required because the ZLIB compression doesn't encode the dimensionality of the original input data.

Try this:

 

IDL> f = filepath('colorbar24.png', subdir=['resource','bitmaps'])
IDL> imagetocode, read_image(f), 'cbimage'

 

Simply open an editor window and paste the contents of the system clipboard to it.  The imagetocode routine has populated the clipboard with the text of the routine. 

The output should look like this:

FUNCTION cbimage
lines = LIST()
lines.ADD, 'eJz6//8/w/9RPGLwuct3/udUTf2PLDZ32Y7/IIwsBlIDUossZuNX9H8gzQfpAamhFK'
lines.ADD, 'O7D4Yb+lf9r+lZ9b+ic9X/kraV/wtaVv7PaVz5P6Nuxf/UmhX/EytX/I8tW/4/snj5'
lines.ADD, '/9DC5f8D85b/981e9t8zc9l/17Rl/x2Tl/63TVz63zJu6aj5o+aPmj9qPknmj2L6Yw'
lines.ADD, 'AAAAD//wMA32owCw=='
s = IDL_BASE64(STRJOIN(lines.ToArray(/NO_COPY), ""))
d = ZLIB_UNCOMPRESS(s)
RETURN, REFORM(d, 4,24,24)
END

Of course the translation routine could have been designed to write its output to a file directly, but where would the fun be in that?

Save and compile the new file, cbimage.pro.

Display the output by executing the function in the context of the IMAGE function.

IDL> image(cbimage())

Now for some additional fun, the algorithm can be adapted easily to create an entire class of static methods.

For example, I may want to extend this functionality to create a single static class that contains all the bitmaps in the IDL distribution's resource\bitmaps directory. Using this mechanism, I would no longer need to include the files in that directory in my application distribution. I would simply include my object class, whether in source code or in the form of compiled code in a SAVE file.  I can simply reference each bitmap via the static class method name.

PRO ImagesToStaticClass, directory, className
files = FILE_SEARCH(FILEPATH('*', ROOT = directory))
l = LIST()
FOREACH file, files DO BEGIN
  CATCH, errorNumber
  IF (errorNumber NE 0) THEN BEGIN
    CATCH, /CANCEL
    CONTINUE
  ENDIF
  image = READ_IMAGE(file, r, g, b)

  CATCH, /CANCEL
  IF (N_ELEMENTS(image) LT 2) THEN CONTINUE
  s = SIZE(image, /STRUCTURE)
  IF (s.N_DIMENSIONS eq 2) THEN BEGIN
    newImage = BYTARR(3, s.Dimensions[0], s.Dimensions[1])
    newImage[0, *, *] = r[image]
    newImage[1, *, *] = g[image]
    newimage[2, *, *] = b[image]
    image = TEMPORARY(newimage)
  ENDIF

  image = TRANSPOSE(TEMPORARY(image), [1, 2, 0])
  d = SIZE(image, /DIMENSIONS)
  baseName = FILE_BASENAME(file)
  methodName = IDL_VALIDNAME(STRMID(baseName, 0, $
    STRPOS(baseName, '.', /REVERSE_SEARCH)))
  IF (methodName eq '') THEN CONTINUE
  z = IDL_BASE64(ZLIB_COMPRESS(image))
  l.Add, 'FUNCTION ' + className + '::' + methodName
  l.Add, 'COMPILE_OPT STATIC'
  dims = STRJOIN(STRTRIM(D, 2), ',')
  l.Add, 'lines = LIST()'
  FOR i = 0L, STRLEN(z) - 1, 66 DO $
    l.Add, "lines.ADD, '" + STRMID(Z, I, 66) + "'"
  l.Add, 's = IDL_BASE64(STRJOIN(lines.ToArray(/NO_COPY), ""))'
  l.Add, 'd = ZLIB_UNCOMPRESS(s)'
  l.Add, 'RETURN, REFORM(d, ' + dims + ')'
  l.Add, 'END'
ENDFOREACH
l.Add, 'PRO ' + className + '__DEFINE'
l.Add, '!null = {' + className + ', INHERITS IDL_Object}'
l.Add, 'END'
Clipboard.Set, l.ToArray(/NO_COPY)
END

Copy, save, and compile the source shown above.

Execute the routine giving it the name of a directory containing image files and the name of the object class to generate.  For example,

IDL> imagestostaticclass, FILEPATH('', SUBDIR=['resource','bitmaps']), 'IDLBitmaps'

Paste the routine's output to an editor file and save it as idlbitmaps__define.pro, then compile it.

To create an "open folder" bitmap widget button, for example, I can simply specify a call to the static method whose name corresponds to the original image file name, modulo a call to IDL_VALIDNAME.

IDL> tlb = WIDGET_BASE()
IDL> b = WIDGET_BUTTON(tlb, VALUE=IDLBitmaps.Open(), /BITMAP)
IDL> WIDGET_CONTROL, tlb, /REALIZE

Many of the bitmap files in IDL's resource directory are palletized, single plane images each with an associated color look-up table. For the sake of expediency and code simplicity at the expense of code size in ASCII characters, they're converted by the utility from single-plane images to RGB format before compressing them.

Notice that the utility skips any files which cannot be read successfully by the READ_IMAGE function. Other than that there is no robust error checking, an exercise left for the reader.

The routine returns the images dimensioned [x,y,3], the format required by WIDGET_BUTTON.

Please login or register to post comments.