利用ArcGIS Server SOI 创建水印地图

ArcGIS Server 10.3.1中新出了一个功能叫SOI,其本质上是一个拦截器,可以对地图服务进行拦截,更改返回的地图信息,具体各种官方术语看官方文档。

开发和部署SOI需要安装ArcObject sdk 10.3.1 和 ArcGIS Server 10.3.1。安装步骤详见百度等等搜索引擎,下面进入主题。

1、首先打开VS2013(其他版本不清楚,因为本人安装的是2013),然后新建ArcGIS的模板项目,如图


2、新建之后会生成一个.cs文件,我这里是打算做一个给地图添加水印的功能,CS文件为WaterMarkSOI.cs

    [ComVisible(true)]
    [Guid("2a0f1bb6-62f3-4b5a-b287-d01530162aca")]
    [ClassInterface(ClassInterfaceType.None)]
    //这里说的是如果用来给地图服务做扩展,就用MapServer,如果用影像服务就用ImageServer,
    //ArcGIS Server给我们自带了一个MapServer,那我就选择用MapServer,其他就不改了
    [ServerObjectInterceptor("MapServer",//use "MapServer" if SOI extends a Map service and "ImageServer" if it extends an Image service.
        Description = "",
        DisplayName = "WaterMarkSOI",
        Properties = "")]

3、WaterMarkSOI类实现了接口IRESTRequestHandler,该接口有两个方法GetSchema()、HandleRESTRequest(string Capabilities, string resourceName, string operationName, string operationInput, string outputFormat, string requestProperties, out string responseProperties),我想后面调用的就是REST服务,所以就对该接口的方法进行实现。

水印功能无须获取图层之类的进行操作,所以可以直接在HandleRESTRequest方法中实现即可,其他方法可以不予理会。

restRequestHandler.HandleRESTRequest(Capabilities, resourceName,operationName,operationInput,outputFormat,requestProperties, out responseProperties)的返回实际就是response,下面我们查看一下完整的代码。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;


using System.Collections.Specialized;


using System.Runtime.InteropServices;


using ESRI.ArcGIS.esriSystem;
using ESRI.ArcGIS.Server;
using ESRI.ArcGIS.Geometry;
using ESRI.ArcGIS.Geodatabase;
using ESRI.ArcGIS.Carto;
using ESRI.ArcGIS.SOESupport;


using System.Drawing;


//TODO: sign the project (project properties > signing tab > sign the assembly)
//      this is strongly suggested if the dll will be registered using regasm.exe <your>.dll /codebase




namespace WaterMarkSOI
{
    [ComVisible(true)]
    [Guid("2a0f1bb6-62f3-4b5a-b287-d01530162aca")]
    [ClassInterface(ClassInterfaceType.None)]
    //这里说的是如果用来给地图服务做扩展,就用MapServer,如果用影像服务就用ImageServer,
    //ArcGIS Server给我们自带了一个MapServer,那我就选择用MapServer,其他就不改了
    [ServerObjectInterceptor("MapServer",//use "MapServer" if SOI extends a Map service and "ImageServer" if it extends an Image service.
        Description = "",
        DisplayName = "WaterMarkSOI",
        Properties = "")]
    public class WaterMarkSOI : IServerObjectExtension, IRESTRequestHandler, IWebRequestHandler, IRequestHandler2, IRequestHandler
    {
        private string _soiName;
        private IServerObjectHelper _soHelper;
        private ServerLogger _serverLog;
        private Dictionary<String, IServerObjectExtension> _extensionCache = new Dictionary<String, IServerObjectExtension>();
        IServerEnvironment2 _serverEnvironment;
        //定义一个输出目录,Init方法中对变量进行初始化
        private string _outputDirectory = string.Empty;


        public WaterMarkSOI()
        {
            _soiName = this.GetType().Name;
        }


        public void Init(IServerObjectHelper pSOH)
        {
            try
            {
                _soHelper = pSOH;
                _serverLog = new ServerLogger();


                try
                {
                    var se4 = ServerEnvironment as IServerEnvironmentEx;
                    var dirInfos = se4.GetServerDirectoryInfos();
                    dirInfos.Reset();
                    object dirInfo = dirInfos.Next();
                    while (dirInfo != null)
                    {
                        var dinfo2 = dirInfo as IServerDirectoryInfo2;
                        if (null != dinfo2 && dinfo2.Type == esriServerDirectoryType.esriSDTypeOutput)
                        {
                            _outputDirectory = dinfo2.Path;
                            break;
                        }
                        dirInfo = dirInfos.Next();
                    }
                }
                catch (Exception ignore)
                {
                    _outputDirectory = string.Empty;
                }


                _outputDirectory = _outputDirectory.Trim();
                if (string.IsNullOrEmpty(_outputDirectory))
                {
                    _serverLog.LogMessage(ServerLogger.msgType.error, _soiName + ".init()", 500, "OutputDirectory is empty or missing. Reset to default.");
                    _outputDirectory = "C:\\arcgisserver\\directories\\arcgisoutput";
                }


                _serverLog.LogMessage(ServerLogger.msgType.infoDetailed, _soiName + ".init()", 500, "OutputDirectory is " + _outputDirectory);
                _serverLog.LogMessage(ServerLogger.msgType.infoStandard, _soiName + ".init()", 200, "Initialized " + _soiName + " SOI.");
            }
            catch (Exception e)
            {
                _serverLog.LogMessage(ServerLogger.msgType.error, _soiName + ".HandleRESTRequest()", 500, "Exception " + e.GetType().Name + " " + e.Message + " " + e.StackTrace);
                throw;
            }
        }


        public void Shutdown()
        {
            _serverLog.LogMessage(ServerLogger.msgType.infoStandard, _soiName + ".init()", 200, "Shutting down " + _soiName + " SOI.");
        }


        #region REST interceptors


        public string GetSchema()
        {
            IRESTRequestHandler restRequestHandler = FindRequestHandlerDelegate<IRESTRequestHandler>();
            if (restRequestHandler == null)
                return null;


            return restRequestHandler.GetSchema();
        }


        public byte[] HandleRESTRequest(string Capabilities, string resourceName, string operationName,
            string operationInput, string outputFormat, string requestProperties, out string responseProperties)
        {
            responseProperties = null;
            _serverLog.LogMessage(ServerLogger.msgType.infoStandard, _soiName + ".HandleRESTRequest()",
                200, "Request received in Sample Object Interceptor for handleRESTRequest");


            /*
            * Add code to manipulate REST requests here
            */


            // Find the correct delegate to forward the request too
            IRESTRequestHandler restRequestHandler = FindRequestHandlerDelegate<IRESTRequestHandler>();
            if (restRequestHandler == null)
                return null;
            //定义一个变量response等于restRequestHandler.HandleRESTRequest
            var response= restRequestHandler.HandleRESTRequest(
                    Capabilities, resourceName, operationName, operationInput,
                    outputFormat, requestProperties, out responseProperties);


            //如果想知道operationName有多少种方式,可以查询AO的帮助文档,搜索Server,
            //搜索结果中有一个Extending ArcGIS for Server->Developing server object interceptors
            //然后就可以看到一行字:
            //This sample illustrates how to filter access to individual operations available on the map server. 
            //Three operations – "find", "identify", and "export" – are checked against the incoming request’s user’s role.
            //打开一个服务的REST链接,最下面有这样一句:Supported Operations:   Export Map   Identify   Find   Return Updates   Generate KML
            //具体每个操作对应的字符串就不再去找了
            //我们还可以在\DeveloperKit10.3\samples\ArcObjectsNET的目录中找到一些实例代码,其中水印就是示例代码之一,我们将实例代码可以拷过来使用
            if (operationName.Equals("export", StringComparison.CurrentCultureIgnoreCase))
            {
                Image sourceImage = null;
                if (outputFormat.Equals("image", StringComparison.CurrentCultureIgnoreCase))
                {
                    sourceImage = Image.FromStream(new System.IO.MemoryStream(response));


                    var watermarker = new ApplyWatermark();
                    //我们把水印文字改一下,改成自己想要的文字
                    var watermarkedImage = watermarker.Mark(sourceImage, "用SOI生成水印文字");
                    var newResponse = new System.IO.MemoryStream();
                    watermarkedImage.Save(newResponse, sourceImage.RawFormat);


                    return newResponse.GetBuffer();
                }
                else if (outputFormat.Equals("json", StringComparison.CurrentCultureIgnoreCase))
                {


                    var responseString = System.Text.Encoding.UTF8.GetString(response);
                    var jo = new JsonObject(responseString);
                    string hrefString = null;
                    if (!jo.TryGetString("href", out hrefString))
                    {
                        //这里只是一个小demo,就不整复杂了,这个位置我把他注释掉,不需要抛出异常
                        //throw new RESTErrorException("Export operation returned invalid response");
                    }




                    if (string.IsNullOrEmpty(hrefString))
                    {
                        //这个位置也注释,不需要抛出异常
                        //throw new RESTErrorException("Export operation returned invalid response");
                    }
                        
                    // 生成输出文件
                    var outputImageFileLocation = GetOutputImageFileLocation(hrefString);


                    // debug logging  调试日志
                    //_serverLog.LogMessage(ServerLogger.msgType.error, "debug", 0, "output is " + outputImageFileLocation);


                    var watermarker = new ApplyWatermark();
                    Image watermarkedImage;


                    System.Drawing.Imaging.ImageFormat sourceImageFormat;
                    using (sourceImage = Image.FromFile(outputImageFileLocation))
                    {
                        sourceImageFormat = sourceImage.RawFormat;
                        watermarkedImage = watermarker.Mark(sourceImage, "(c) SuperMap Inc.");
                    }


                    // 确保调用Dispose之前保存sourceImage
                    watermarkedImage.Save(outputImageFileLocation, sourceImageFormat);
                    watermarkedImage.Dispose();//Save方法在前


                    // 返回修改后的response
                    return response;
                }
                else if (outputFormat.Equals("kmz", StringComparison.CurrentCultureIgnoreCase))
                {
                    // Note: Watermark can be added for the kmz format too. In this example we didn't
                    // implement it.
                    //throw new RESTErrorException("Kmz format is not supported");
                }
                else
                {
                    //throw new RESTErrorException("Invalid operation parameters");
                }
            }//if operationName==export
            return response;
        }


        #endregion


        #region SOAP interceptors


        public byte[] HandleStringWebRequest(esriHttpMethod httpMethod, string requestURL,
            string queryString, string Capabilities, string requestData,
            out string responseContentType, out esriWebResponseDataType respDataType)
        {
            _serverLog.LogMessage(ServerLogger.msgType.infoStandard, _soiName + ".HandleStringWebRequest()",
                200, "Request received in Sample Object Interceptor for HandleStringWebRequest");


            /*
             * Add code to manipulate requests here
             */


            IWebRequestHandler webRequestHandler = FindRequestHandlerDelegate<IWebRequestHandler>();
            if (webRequestHandler != null)
            {
                return webRequestHandler.HandleStringWebRequest(
                        httpMethod, requestURL, queryString, Capabilities, requestData, out responseContentType, out respDataType);
            }


            responseContentType = null;
            respDataType = esriWebResponseDataType.esriWRDTPayload;
            //Insert error response here.
            return null;
        }


        public byte[] HandleBinaryRequest(ref byte[] request)
        {
            _serverLog.LogMessage(ServerLogger.msgType.infoStandard, _soiName + ".HandleBinaryRequest()",
                  200, "Request received in Sample Object Interceptor for HandleBinaryRequest");


            /*
             * Add code to manipulate requests here
             */


            IRequestHandler requestHandler = FindRequestHandlerDelegate<IRequestHandler>();
            if (requestHandler != null)
            {
                return requestHandler.HandleBinaryRequest(request);
            }


            //Insert error response here.
            return null;
        }


        public byte[] HandleBinaryRequest2(string Capabilities, ref byte[] request)
        {
            _serverLog.LogMessage(ServerLogger.msgType.infoStandard, _soiName + ".HandleBinaryRequest2()",
                  200, "Request received in Sample Object Interceptor for HandleBinaryRequest2");


            /*
             * Add code to manipulate requests here
             */


            IRequestHandler2 requestHandler = FindRequestHandlerDelegate<IRequestHandler2>();
            if (requestHandler != null)
            {
                return requestHandler.HandleBinaryRequest2(Capabilities, request);
            }


            //Insert error response here.
            return null;
        }


        public string HandleStringRequest(string Capabilities, string request)
        {
            _serverLog.LogMessage(ServerLogger.msgType.infoStandard, _soiName + ".HandleStringRequest()",
                   200, "Request received in Sample Object Interceptor for HandleStringRequest");


            /*
             * Add code to manipulate requests here
             */


            IRequestHandler requestHandler = FindRequestHandlerDelegate<IRequestHandler>();
            if (requestHandler != null)
            {
                return requestHandler.HandleStringRequest(Capabilities, request);
            }


            //Insert error response here.
            return null;
        }


        #endregion


        #region Utility code


        private IServerEnvironment2 ServerEnvironment
        {
            get
            {
                if (_serverEnvironment == null)
                {
                    UID uid = new UIDClass();
                    uid.Value = "{32D4C328-E473-4615-922C-63C108F55E60}";


                    // CoCreate an EnvironmentManager and retrieve the IServerEnvironment
                    IEnvironmentManager environmentManager = new EnvironmentManager() as IEnvironmentManager;
                    _serverEnvironment = environmentManager.GetEnvironment(uid) as IServerEnvironment2;
                }


                return _serverEnvironment;
            }
        }


        private THandlerInterface FindRequestHandlerDelegate<THandlerInterface>() where THandlerInterface : class
        {
            try
            {
                IPropertySet props = ServerEnvironment.Properties;
                String extensionName;
                try
                {
                    extensionName = (String)props.GetProperty("ExtensionName");
                }
                catch (Exception /*e*/)
                {
                    extensionName = null;
                }


                if (String.IsNullOrEmpty(extensionName))
                {
                    return (_soHelper.ServerObject as THandlerInterface);
                }


                // Get the extension reference from cache if available
                if (_extensionCache.ContainsKey(extensionName))
                {
                    return (_extensionCache[extensionName] as THandlerInterface);
                }


                // This request is to be made on a specific extension
                // so we find the extension from the extension manager
                IServerObjectExtensionManager extnMgr = _soHelper.ServerObject as IServerObjectExtensionManager;
                IServerObjectExtension soe = extnMgr.FindExtensionByTypeName(extensionName);
                return (soe as THandlerInterface);
            }
            catch (Exception e)
            {
                _serverLog.LogMessage(ServerLogger.msgType.error,
                                    _soiName + ".FindRequestHandlerDelegate()", 500, e.ToString());
                throw;
            }
        }
        #endregion


        private String GetOutputImageFileLocation(String virtualPath)
        {
            /*
             * Sample output returned by MapServer SO
             * 
             * example : /rest/directories/arcgisoutput/SampleWorldCities_MapServer/
             * _ags_map26c62f8c2c0c4965b53e87e300e1912f.png
             */
            var virtualPathParts = virtualPath.Split('/');
            String imageFileLocation = _outputDirectory;


            // build the physical path to the image file
            bool buildPath = false;
            foreach (String virtualPathPart in virtualPathParts)
            {
                if (buildPath)
                {
                    imageFileLocation += "\\" + virtualPathPart;
                }
                if (virtualPathPart.Equals("arcgisoutput", StringComparison.CurrentCultureIgnoreCase))
                {
                    buildPath = true;
                }
            }


            return imageFileLocation;
        }
    }
}

4、运行生成项目即可生成WaterMarkSOI.soe文件,具体路径可以通过输出窗口查看

5、打开Server,添加soe文件到扩展模块中,具体操作如下


6、效果图如下:


源码下载地址:http://download.csdn.net/detail/u010520626/9462545


ApplyWatermark.cs类的代码如下

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;


namespace WaterMarkSOI
{


    public class ApplyWatermark
    {
        public Color Color { get; set; }


        public Font Font { get; set; }


        public string WatermarkText { get; set; }


        public ContentAlignment TextAlignment { get; set; }


        /// <summary>
        /// Creates an instance of Watermarker class.
        /// </summary>
        public ApplyWatermark ()
        {
            Color = Color.Aquamarine;
            Font = new Font(FontFamily.GenericSansSerif, 16);
            WatermarkText = "(c) ESRI Inc.";
            TextAlignment = ContentAlignment.BottomLeft;
        }


        public Image Mark( Image image, string waterMarkText )
        {
            WatermarkText = waterMarkText;


            Bitmap originalBmp = (Bitmap)image;


            // avoid "A Graphics object cannot be created from an image that has an indexed pixel format." exception
            Bitmap tempBitmap = new Bitmap(originalBmp.Width, originalBmp.Height);
            // From this bitmap, the graphics can be obtained, because it has the right PixelFormat
            Graphics g = Graphics.FromImage(tempBitmap);


            using (Graphics graphics = Graphics.FromImage(tempBitmap))
            {
                // Draw the original bitmap onto the graphics of the new bitmap
                g.DrawImage(originalBmp, 0, 0);
                var size =
                    graphics.MeasureString(WatermarkText, Font);
                var brush =
                    new SolidBrush(Color.FromArgb(255, Color));
                graphics.DrawString
                    (WatermarkText, Font, brush,
                    GetTextPosition(image, size));
            }


            return tempBitmap as Image;
        }


        public Image Mark ( Image image )
        {
            return Mark(image, WatermarkText);
        }


        private PointF GetTextPosition ( Image image, SizeF size )
        {
            PointF point = default(PointF);
            switch (TextAlignment)
            {
                case ContentAlignment.BottomCenter:
                    point = new PointF((image.Width - size.Width) / 2,
                        (image.Height - size.Height));
                    break;
                case ContentAlignment.BottomLeft:
                    point = new PointF(0, (image.Height - size.Height));
                    break;
                case ContentAlignment.BottomRight:
                    point = new PointF((image.Width - size.Width),
                        (image.Height - size.Height));
                    break;
                case ContentAlignment.MiddleCenter:
                    point = new PointF((image.Width - size.Width) / 2,
                        (image.Height - size.Height) / 2);
                    break;
                case ContentAlignment.MiddleLeft:
                    point = new PointF(0, (image.Height - size.Height) / 2);
                    break;
                case ContentAlignment.MiddleRight:
                    point = new PointF((image.Width - size.Width),
                        (image.Height - size.Height) / 2);
                    break;
                case ContentAlignment.TopCenter:
                    point = new PointF((image.Width - size.Width) / 2, 0);
                    break;
                case ContentAlignment.TopLeft:
                    point = new PointF(0, 0);
                    break;
                case ContentAlignment.TopRight:
                    point = new PointF((image.Width - size.Width), 0);
                    break;
            }
            return point;
        }
    }
}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章