[mapserver-dev] Coloring height rasters

Administrator jnovak at novacell.com
Fri Nov 29 02:17:45 EST 2002


I've had a chance to digest the GDAL rendering changes you've made for
3.7 and I think I understand what's going on in mapdrawgdal.c.

Unfortunately for me, neither the raw changes you've made nor the SCALE
implementation completely address what I'm trying to do.  A blend of
both is what I'm looking for.

To illustrate, I've attached a snippet that's the core rendering routine
that I've been using to get the desired effect:

		for( i = dst_yoff; i < dst_yoff + dst_ysize; i++ )
			for( j = dst_xoff; j < dst_xoff + dst_xsize; j++
				typedef struct
					unsigned char	red;
					unsigned char	green;
					unsigned char	blue;
					unsigned char	alpha;
				} tempPixel;

				float		fPixel		=
(float) ((short *) pabyRaw1)[k++];
				tempPixel	thePixel
= { 0,0,0,0 };
				int		zRatio		= (int)
(1023.0f * (fPixel - fMinZ) / (fMaxZ - fMinZ));

				if( fPixel <= 0.0f )
				  thePixel.red			= 0;
= 0;
				  thePixel.blue			= 128;
				else if ( zRatio < 256 )
				  thePixel.red			= 0;
= zRatio & 0xFF;
				  thePixel.blue			= 255;
				else if ( zRatio < 512 )
				  thePixel.red			= 0;
= 255;
				  thePixel.blue			= 255 -
zRatio & 0xFF;
				else if ( zRatio < 768 )
				  thePixel.red			= zRatio
& 0xFF;
= 255;
				  thePixel.blue			= 0;
				  thePixel.red			= 255;
= 255 - zRatio & 0xFF;
				  thePixel.blue			= 0;

				gdImg->tpixels[i][j]		=
thePixel.red << 16 | thePixel.green << 8 | thePixel.blue |
thePixel.alpha << 24;

This is simplistic and inflexible but it gets the job done for me.

I'm sure you'll recognize this as very similar to what's going on in
LoadGDALImage with two major differences.  First, I'm using samples
deeper than 8 bits, like RAWDATA, but I'm computing 24 bit values and
shoving them directly into tpixels so I can use GD for alpha, etc with
later layer rendering.

RAWDATA looks like the source data is rendered directly as the target
image, but I have not followed the path all the way so I'm a bit fuzzy
on all the implications of this mode.

I could add a COLORRAMP keyword that LoadGDALImage looks for as it does
for SCALE.  It could include (a) parameter(s) that specif(ies)(y) the
name of an external routine to invoke to process the data.  I can always
add a subroutine to perform my crunching for the short term when this
keyword is seen.

This leaves the issue of where to get the z min/max values.  I have not
thought much about this but I'm going to investigate your suggestion
about some sort of external routine that returns the range.  It may also
be useful to have this routine return other parameters for computing the
final values, but I have not considered ways to parameterize the

Another possibility would be to just pass a pointer to the GDAL buffer
as well as a pointer to tpixels or perhaps the gdImg pointer and let the
external code crunch the data.  Having this amount of processing in
script seems deadly wrt performance, though.  I can easily see how I
could call through COM on win32 to compiled code to do this quickly, but
I'm at a loss as to the implications on other platforms.  There's always
CORBA, but that seems like a lot of infrastructure and I believe it's an
add on and not present by default as COM is on Win32, so it may not be
very useful.

As to the color ramp legend, perhaps an approach similar to the scale
bar would prove useful.  Divide the height range into a number of
buckets, perhaps pick the center value of the bucket, and compute its
color value, and use that as the color entry on the legend.  So you get
N buckets having a color and a legend underneath showing that bucket's
"center" value.

John Novak

-----Original Message-----
From: Frank Warmerdam [mailto:warmerdam at pobox.com] 
Sent: Sunday, November 24, 2002 6:56 PM
To: Administrator; mapserver-dev at lists.gis.umn.edu
Subject: Re: [mapserver-dev] Coloring height rasters

Administrator wrote:
> Frank,
> If you have the capability to process raw data, and the capability to 
> quantize that data into a set of 255 user specified colors, you're 
> already touching every pixel in the raw data.  A color ramp shader 
> such as I'm simply performs a different quantization and outputs 24 
> bit values for each pixel.
> I definitely agree that this is not the pinnacle of optimal code, but 
> I can have the shader use the full range of 24 bit color across the 
> heights appearing in the rectangle of interest.  Maximum detail based 
> on the height minimum and maximum.


You are correct that the current MapServer code (with the recent
addition of the SCALE processing keyword) can scale the data to 0-255.
Then you could use 256 CLASS statements to set a color for each of those
values. Ideally there would be a further mechanism to specify the 256
entry color table more compactly ... perhaps as a set of interpolation
points, but that isn't strictly necessary.

> This, of course, begs the question of just where the height minimum 
> and maximums come from.
> Which, conveniently, leads to my next question.  There's already a 
> very fine tile based scheme that sits on top of the shape file data 
> base format, I believe.  It seems that it would not be terribly 
> difficult for someone, namely me, to extend the row schema for each 
> tile such that it includes the min and max heights for the tile.
> An appropriate tile index query could then supply the shader with the 
> height extrema for each tile in the final image so that the correct 
> ratio of height delta to pixel RGB value could be efficiently computed

> for rendering.  This means you may not get the broadest range of 
> values for a particular rectangle, but if the tile index has 
> appropriate granularity it should suffice.

This could be done, but would require an extra pass over the tile index
to collect the raster min/max values before actually drawing any of the
raster tiles.  I am not especially enthusiastic about this complication
to the code.

I suppose this could be done outside of the mapserver code base itself
if your application is MapScript based, and then you could set the layer
scaling range before calling drawMap.  That would be sweet.  Note that
there is no harm in adding extra columns in the tile index.  They will
be ignored by MapServer.

The real issue, to my mind, is that you will have a hard time generating
a proper color ramp legend showing the "real values" along a color bar.

> Maybe I could implement the range color table while I'm at it...

How do you mean?  A special way of specifing color tables from ranges
within the mapfile?

Best regards,

I set the clouds in motion - turn up   | Frank Warmerdam,
warmerdam at pobox.com
light and sound - activate the windows | http://pobox.com/~warmerdam
and watch the world go round - Rush    | Geospatial Programmer for Rent

More information about the mapserver-dev mailing list