How can I smoothen the (GIF)-output of the mapserver

Camden Daily cdaily at GMAIL.COM
Tue Apr 26 10:32:41 EDT 2005


After playing around with antialiasing a lot, I found that what worked
best for me was to just use a function after I've configured my map
that would use the php image handling functions to draw the image at a
larger size and then scale it down to the original size, antialiasing
as it went.  I found in doing it that way, though, that the text would
get a little blurred out.  So I then decided to render my labels as a
seperate image and just superimpose them over my antialiased map.  The
results have been quite good.

First off, for image handling in php, you'll need to configure php
--with-gd=/path/to/gd.  It's important to make sure that the version
of gd you configure it with is the same version as the one you
compiled mapserver with.  Also, just specifying --with-gd, and not
including the path, will make php revert to using it's own bundled gd
(probably not what you want).  If you have problems with this step,
search the archvies; there's been plenty of discussions about it.

I wrote a function to call at the end of my mapscript like this:
    $image_url = antialias(2);
where 2 is the scale factor.  Increasing the scale makes the image
look better, but also slows it down a bit.

Here's the function.  It should be relatively self-explanatory.  I
posted an older version of this function maybe a month back, but it's
had some bug fixes since then.

///////////////////////////////////////////////////////////////
//
// function antialias()
//
// draws our map at a larger size, then samples it back down to provide
//  antialiasing.  annotation layers and the scalebar are drawn seperately
//  and combined over the resulting image, so that they are not distroted.
//
// using this function, all labels must be drawn as seperate annotation layers.
//
// the .map file should be configured to output as png for transparency.
//
///////////////////////////////////////////////////////////////

function antialias($scale) {
  global $map, $root_directory;
  
  // get the dimensions of the image
  $image_width = $map->width;
  $image_height = $map->height;
  
  // scale the map up
  $map->set("width", $image_width * $scale);
  $map->set("height", $image_height * $scale);
  
  // turn off the scalebar if there is one
  $scalebar_present = false;
  $scalebar = $map->scalebar;
  if ($scalebar->status == MS_EMBED) {
    $scalebar->set("status", MS_OFF);
    $scalebar_present = true; 
  }  

  // loop through our layers, and if it's status is on, loop through
the classes scaling the sizes
  $scaled_symbols = array();
  for ($i=0; $i < $map->numlayers; $i++) {
    $layer = $map->getLayer($i);   
    if ($layer->status == MS_ON AND $layer->type != MS_LAYER_ANNOTATION) {  
      for ($j=0; $j < $layer->numclasses; $j++) {
        $class = $layer->getClass($j);
        for ($k=0; $k < $class->numstyles; $k++) {
          $style = $class->getStyle($k);
          
          // scale the size and offsets 
          $style->set("size", $style->size * $scale);
          $style->set("offsetx", $style->offsetx * $scale);
          $style->set("offsety", $style->offsety * $scale);      
          
          // for symbols with styles them, we need to scale those as well
          $symbol_id = $style->symbol;
          $symbol = $map->getsymbolobjectbyid($symbol_id);
          $already_scaled = false;
          reset($scaled_symbols);
          foreach ($scaled_symbols as $scaled) {
            if ($scaled == $symbol->name) {
              $already_scaled = true;
            } 
          }
          
          if (!$already_scaled) {
            array_push($scaled_symbols, $symbol->name);             
            $points = $scaled_points = $symbol->getstylearray();  
            if (count($points) > 1) {                 
              for ($l=0; $l < count($points); $l++) {
                $scaled_points[$l] = $points[$l] * $scale;
              }                           
              $symbol->setstyle($scaled_points);      
            }       
          }
        }
      }
    }
  }
  
  // loop through and turn off our annotation layers for now, keeping
track of them
  $labels = array();
  for ($i=0; $i < $map->numlayers; $i++) {
    $layer = $map->getLayer($i);
    if ($layer->type == MS_LAYER_ANNOTATION AND $layer->status == MS_ON) {
      array_push($labels, $layer);
      $layer->set("status", MS_OFF);
    }
  }  
    
  // draw our image
  $image = $map->draw();
  $image_url = $image->saveWebImage('MS_PNG', 1, 1, 0);  
  
  // create our image objects
  $old = imagecreatefrompng($root_directory . $image_url);
  $new = imagecreatetruecolor($image_width, $image_height);
  
  // the background color gets dropped from our transparent pngs, so
start by filling our new image with it
  $back_color = $map->imagecolor;
  $back_color = imagecolorallocate($new, $back_color->red,
$back_color->green, $back_color->blue);
  imagefill($new, 0, 0, $back_color);
  
  // resample the image back down to the original size (antialiasing it)  
  imagecopyresampled($new, $old, 0, 0, 0, 0, $image_width,
$image_height, $image_width * $scale, $image_height * $scale);
  
  // scale the map down
  $map->set("width", $image_width);
  $map->set("height", $image_height);
  
  // flip off all layers on the map  
  for ($i=0; $i < $map->numlayers; $i++) {
    $layer = $map->getLayer($i);
    $layer->set("status", MS_OFF); 
  }  
  
  // flip on those annotation layers we turned off earlier
  for ($i=0; $i < count($labels); $i++) {
    $labels[$i]->set("status", MS_ON);
  }
  
  // turn the scalebar back on
  if ($scalebar_present) {
    $scalebar->set("status", MS_EMBED);
  }
  
  // draw our image again, this time with just the annotations
  $label_image = $map->draw();
  $label_url = $label_image->saveWebImage('MS_PNG', 1, 1, 0);    
  
  // merge the text from our new image over the old one
  $old = imagecreatefrompng($root_directory . $label_url);
  imagecopyresampled($new, $old, 0, 0, 0, 0, $image_width,
$image_height, $image_width, $image_height);
  
  // change our filename extention from .png to .jpg
  $image_url = substr($image_url, 0, -3) . "jpg";
  
  // save our new image
  imagejpeg($new, $root_directory . $image_url);
  
  // free up memory
  imagedestroy($im);
  imagedestroy($new);  
  
  // return the location of our new image
  return $image_url;
}

On 4/26/05, Wolfgang Qual <Wolfgang.Qual at muenchen.de> wrote:
> Devinitively! If you could give some examples / how-to's I would be very
> glad. I am curious about it.
> 
> Regards,
> Wolfgang
> 
> Camden Daily schrieb:
> 
> > I believe what you're looking for is antialiasing, in order to make
> > things like lines less pixelated.  Antialiasing is available for text
> > and a few of the symbol types, but I had more luck taking the advise
> > of some on the listserve and using php/mapscript to actually draw the
> > maps at a larger scale and then letting php resample the image down to
> > the final size, antialiasing in the process.
> >
> > If you're interested in some of the details for that method, let me
> > know and I'll post some stuff.
> >
> > -Camden Daily
> > Prudential Preferred Properties
> > http://www.prupref.com
> >
> > On 4/25/05, Wolfgang Qual <Wolfgang.Qual at muenchen.de> wrote:
> >
> >>Hello list,
> >>When I create a mapserver-map, I sometimes have the impression that the
> >>maps look quite square-edged. Especially, if the color contrast of
> >>certain themes is high (b/w.). That's the reason why I am looking for a
> >>way to smoothen the output-GIFs of the mapserver - just something like
> >>the blur-filtering in Photoshop or GIMP...
> >>
> >>Thanks,
> >>
> >>Wolfgang
> >>
> >
> >
> 
> --
> Wolfgang Qual
> Landeshauptstadt München
> Referat für Gesundheit und Umwelt
> RGU-UW 11
> Sg. 1 Gesundheits- und Umweltberichterstattung,
> Energie und Klimaschutz
> Bayerstr. 28a, 80335 München
> Tel.: +49 (0)89 233-477 17
> Fax.: +49 (0)89 233-477 05
> E-Mail: wolfgang.qual at muenchen.de
>



More information about the mapserver-users mailing list