Monthly Archives: October 2011

在ArcGIS Web API应用程序中使用灰度地图

  上个月底,ArcGIS Online发布了一款全新风格的底图服务Light Gray Basemap。该底图服务尽可能少地使用了色彩,标注和要素内容,目的是突出地图的主题内容,把重点展示给最终用户。美化的底图固然好看,但有时我们不能为了使用地图而去使用地图,忽略了我们真正想要表达的意思,很多时候,都会回归到以简为美的原点。使用这种底图服务,我们可以很轻松的将注意力集中在业务数据上。
AGOL_LE_2_basemap_types

  可以看到,只有在右上角的Light Gray Canvas底图上,四个要素点才清晰可见。
  其实Google Maps API中就一直能够设置显示风格,以适应我们的需求。虽然ArcGIS Online已经推出了灰度底图服务,但对于自己的底图服务(尤其是国内数据用户)来说,如何能够风格化显示呢?以ArcGIS API for Silverlight为例来说明。
  缓存地图服务所对应的ArcGISTiledMapServiceLayer类中,暴露出了TileLoaded事件(继承自TiledLayer)。这个事件会在每一个切片加载完成时触发,并且事件参数中可以获得ImageSource属性,它就是切片本身,随后地图控件会对这些切片进行拼接,从而形成完整的地图。我们的工作,就是在这个事件中,对切片上的每个像素做色彩处理,从而达到风格化地图服务的效果。在Silverlight中,我们可以利用WritableBitmap来完成这项工作,代码如下,具体原理可自己参详:

   1: private void ArcGISTiledMapServiceLayer_TileLoaded(object sender, TiledLayer.TileLoadEventArgs e)

   2:         {

   3:             WriteableBitmap wb = new WriteableBitmap(e.ImageSource as BitmapSource);

   4:             for (int y = 0; y < wb.PixelHeight; y++)

   5:             {

   6:                 for (int x = 0; x < wb.PixelWidth; x++)

   7:                 {

   8:                     int pixel = wb.Pixels[y * wb.PixelWidth + x];

   9:                     byte[] dd = BitConverter.GetBytes(pixel);

  10:                     double R = dd[2];

  11:                     double G = dd[1];

  12:                     double B = dd[0];

  13:                     byte gray = (byte)(0.333 * R + 0.333 * G + 0.333 * B);

  14:                     dd[0] = dd[1] = dd[2] = gray;

  15:  

  16:                     wb.Pixels[y * wb.PixelWidth + x] = BitConverter.ToInt32(dd, 0);

  17:                 }

  18:             }

  19:             e.ImageSource = wb;

  20:         }

  下图是加载ArcGIS Online上StreetMap时的效果:
image  细心的朋友可能会发现,这个Silverlight程序并没有运行在浏览器中。这的确是一个OOB的程序,因为TileLoaded事件要求Silverlight程序必须获得提升权限才行。但是WPF和Windows Phone程序可以直接使用上述代码。
  那么在Silverlight应用中还能否显示风格化的地图服务呢?答案是肯定的。Map控件有一个Effect属性(继承自UIElement),系统提供了 BlurEffect,DropShadowEffect两个现成的效果。我们可以通过HLSL(High Level Shading Language)语言来自定义一些效果,比如灰度,通过PixelShader类应用到UIElement上,从而达到显示灰度地图的目的(此时Map控件中的所有图层都将变为灰色)。有兴趣的朋友可以动手实践一下,Windows Presentation Foundation Pixel Shader Effects Library这个项目中可以找到很多现成的效果。
  再来看看ArcGIS API for Javascript/Flex,两个API甚至都没有类似的TileLoaded事件可用。即使有,在Javascript中处理图片的颜色也是一项有难度的工作。不过不用担心,Portable Basemap Server从1.0.6版本开始,提供了风格化地图服务的功能,有灰度图和反色图两个选项,无需任何代码,即可在所有的ArcGIS REST客户端程序中,使用风格化的地图了:)
Untitled-1