antialias() function

Camden Daily cdaily at GMAIL.COM
Tue Apr 5 17:57:26 EDT 2005


I've written a nice php/mapscript antialiasing function and thought
I'd post it if anybody is looking to add antialiasing.  It uses the
method of drawing the map at a larger size, then uses php mapscript to
sample the image back down.  It scales all of the symbols, etc up and
down as necessary.  It also renders any annotation layers and the
scalebar seperately and then combines that over the antialiased map so
the text isn't blurred.  Therefore, you won't have to go through and
manually scale all of your .map entries or worry about scaling your
click points or anything.  It's pretty self contained.

The .map file needs to output the image as png initially, so that the
background is transparent. PHP needs to be compiled --with-gd. It's
called like this: $image_url = antialias(2); where the two denotes to
draw the original map at twice the size, then scale it down.  The
scale can be increased for higher image quality, but it will of course
take longer.

-Camden

///////////////////////////////////////////////////////////////
//
// 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_ON) {
    $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
  for ($i=0; $i < $map->numlayers; $i++) {
    $layer = $map->getLayer($i);
    if ($layer->status == MS_ON) {
      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 and points in them, we need to
scale those as well
          $symbol_id = $style->symbol;
          $symbol = $map->getsymbolobjectbyid($symbol_id);
          // symbol style
          $points = $scaled_points = $symbol->getstylearray;
          for ($l=0; $l<count($points); $l) {
            $scaled_points[$l] = $points[$l] * $scale;
          }
          $symbol->setstyle($scaled_points);
          // symbol points
          $points = $scaled_points = $symbol->getpointsarray;
          for ($l=0; $l<count($points); $l) {
            $scaled_points[$l] = $points[$l] * $scale;
          }
          $symbol->setpoints($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;
}



More information about the mapserver-users mailing list