/// <summary> /// Request GetTile /// </summary> private void GetTile(NameValueCollection requestParams, Stream responseOutputStream, ref string responseContentType) { #region Verify the request if (requestParams["LAYERS"] == null) { WmtsException(WmtsExceptionCode.NotApplicable, "Required parameter LAYER not specified.", responseOutputStream, ref responseContentType); return; } if (requestParams["STYLES"] == null) { WmtsException(WmtsExceptionCode.NotApplicable, "Required parameter STYLE not specified.", responseOutputStream, ref responseContentType); return; } if (requestParams["TILEMATRIXSET"] == null) { WmtsException(WmtsExceptionCode.NotApplicable, "Required parameter TILEMATRIXSET not specified.", responseOutputStream, ref responseContentType); return; } if (requestParams["TILEMATRIX"] == null) { WmtsException(WmtsExceptionCode.NotApplicable, "Required parameter TILEMATRIX not specified.", responseOutputStream, ref responseContentType); return; } if (requestParams["TILEROW"] == null) { WmtsException(WmtsExceptionCode.NotApplicable, "Required parameter TILEROW not specified.", responseOutputStream, ref responseContentType); return; } if (requestParams["TILECOL"] == null) { WmtsException(WmtsExceptionCode.NotApplicable, "Required parameter TILECOL not specified.", responseOutputStream, ref responseContentType); return; } if (requestParams["FORMAT"] == null) { WmtsException(WmtsExceptionCode.NotApplicable, "Required parameter FORMAT not specified.", responseOutputStream, ref responseContentType); return; } #endregion #region Render Settings Color backColor = Color.FromArgb(0, 0, 0, 0); if (_map.CosmeticRaster.Visible) { //Cosmetic layer all broken, this does not allow its use. WmtsException(WmtsExceptionCode.NotApplicable, "WMTS not support this settings rendering.", responseOutputStream, ref responseContentType); return; } //Render for inscriptions. var wmsFeatureRender = new WmsFeatureRender(_map.RenderingSettings); ImageCodecInfo imageEncoder = getEncoderInfo(requestParams["FORMAT"]); if (imageEncoder == null) { WmtsException(WmtsExceptionCode.NotApplicable, "Wrong mime-type in FORMAT parameter.", responseOutputStream, ref responseContentType); return; } int tileRow = 0; int tileCol = 0; if (!int.TryParse(requestParams["TILEROW"], out tileRow)) { WmtsException(WmtsExceptionCode.InvalidDimensionValue, "Parameter TILEROW has wrong value.", responseOutputStream, ref responseContentType); return; } if (!int.TryParse(requestParams["TILECOL"], out tileCol)) { WmsException(WmsExceptionCode.InvalidDimensionValue, "Parameter TILECOL has wrong value.", responseOutputStream, ref responseContentType); return; } string tileMatrixName = "EPSG:3857:0"; if (requestParams["TILEMATRIX"] != null) tileMatrixName = requestParams["TILEMATRIX"]; Tile tile = new Tile(_map, (uint)tileRow, (uint)tileCol); tile.ScaleDenominator = _description.GetScaleDenominator(_description.ZoomLevel[tileMatrixName]); tile.PixelSize = _description.GetPixelSize(_description.ZoomLevel[tileMatrixName]); tile.ZoomLevel = (uint)_description.ZoomLevel[tileMatrixName]; int width = tile.Width, height = tile.Height; BoundingRectangle originalBbox = tile.BBox; if (originalBbox == null) { WmtsException(WmtsExceptionCode.NotApplicable, "Wrong Tile parameters.", responseOutputStream, ref responseContentType); return; } #endregion //Selected by default. bool[] _defaultVisibility = new bool[_map.Layers.Count()]; int j = 0; foreach (LayerBase layer in _map.Layers) { _defaultVisibility[j] = layer.Visible; layer.Visible = false; //Turning off all the layers. j++; } lock (_syncRoot) { LayerBase[] useLayers = null; int[] indexLayers = null; #region Checking layers of inquiry if (!string.IsNullOrEmpty(requestParams["LAYER"])) { #region Getting layers of inquiry string[] layers = requestParams["LAYER"].Split(new[] { ',' }); if (_description.LayerLimit > 0) { if (layers.Length == 0 && _map.Layers.Count > _description.LayerLimit || layers.Length > _description.LayerLimit) { WmtsException(WmtsExceptionCode.OperationNotSupported, "The number of layers in the query exceeds the limit of layers in the WMTS.", responseOutputStream, ref responseContentType); return; } } #endregion useLayers = new LayerBase[layers.Length]; indexLayers = new int[layers.Length]; for (int i = 0; i < layers.Length; i++) { var layer = layers[i]; var findLayer = false; for (int k = 0; k < _map.Layers.Count; k++) if (string.Equals(_map.Layers[k].Alias, layer, StringComparison.InvariantCultureIgnoreCase)) { useLayers[i] = _map.Layers[k]; indexLayers[i] = k; findLayer = true; break; } if (!findLayer) { WmtsException(WmtsExceptionCode.LayerNotDefined, "Layer \"" + layer + "\" not found.", responseOutputStream, ref responseContentType); return; } } Array.Sort(indexLayers, useLayers); } #endregion BoundingRectangle bboxWithGutters = (BoundingRectangle)originalBbox.Clone(); bboxWithGutters.Grow((double)GutterSize * originalBbox.Width / (double)width); try { using (Image bmp = GetImage(width, height, backColor, useLayers, bboxWithGutters)) { EncoderParameters encoderParams = new EncoderParameters(1); encoderParams.Param[0] = new EncoderParameter( System.Drawing.Imaging.Encoder.Quality, (long)_imageQuality); using (MemoryStream ms = new MemoryStream()) { bmp.Save(ms, imageEncoder, encoderParams); byte[] buffer = ms.ToArray(); responseContentType = imageEncoder.MimeType; responseOutputStream.Write(buffer, 0, buffer.Length); } } } catch(Exception except) { WmtsException(WmtsExceptionCode.NotApplicable, except.Message, responseOutputStream, ref responseContentType); return; } for (j = 0; j < _map.Layers.Count(); j++) //Restore it as it was. _map.Layers[j].Visible = _defaultVisibility[j]; } }
/// <summary> /// Gets image /// </summary> /// <param name="width"></param> /// <param name="height"></param> /// <param name="backColor"></param> /// <param name="useLayers"></param> /// <param name="bboxWithGutters"></param> /// <returns></returns> protected Image GetImage(int width, int height, Color backColor, LayerBase[] useLayers, BoundingRectangle bboxWithGutters) { #region Проверка на занятость ресурсов // проверяем заняты ли ресурсы if (_drawingRequestSemaphore != null) if (!_drawingRequestSemaphore.WaitOne(_drawingResourcesTimeOut)) throw new Exception( "There are currently no resources on the server needed to generate the map image."); #endregion try { bool cacheable = true; string allLayerKey = ""; foreach (var layer in useLayers.OrderBy(x=>x.Alias)) { cacheable &= layer.Cacheable; allLayerKey += layer.Alias; } if (cacheable) { Image res = GetImage(bboxWithGutters, allLayerKey); if (!ReferenceEquals(res,null)) { return res; } } //Рендер для надписей. var wmsFeatureRender = new WmsFeatureRender(_map.RenderingSettings); using (Image bmpWithGutters = new Bitmap(width + _gutterSize * 2, height + _gutterSize * 2)) { // рисуем фон using (Graphics g = Graphics.FromImage(bmpWithGutters)) g.Clear(backColor); int i = 0; //Проверка, что вообще есть что отображать. if (!ReferenceEquals(useLayers, null) && (useLayers.Length > 0)) do { IFeatureRenderer _oldFeatureRender = null; try { //Начинаем рисовать новый слой. wmsFeatureRender.BeginLayerRender(); //Делаем слой видимым. Все остальные слои мы отключили выше. useLayers[i].Visible = true; //Настройка слоя перед рендерингом. if (useLayers[i] is FeatureLayer) OnPrepareRenderFeatureLayer(new PrepareRenderFeatureLayerArgs((FeatureLayer)useLayers[i])); //Устанавливаем свой рендер, что бы перекрыть отрисовку названий if (useLayers[i] is FeatureLayer) { _oldFeatureRender = (useLayers[i] as FeatureLayer).FeatureRenderer; (useLayers[i] as FeatureLayer).FeatureRenderer = wmsFeatureRender; } byte[] titleInfo = null; //Смотрим в кэше. using (Image bmpLayer = GetImageFromChach(useLayers[i], out titleInfo, bboxWithGutters)) { if (!ReferenceEquals(bmpLayer, null)) { //Добавляем данные о названиях в wmsFeatureRender. wmsFeatureRender.AddTitleInfo(titleInfo); //Копируем картинку в результирующий тайл. CopyImage(bmpLayer, bmpWithGutters); continue; } } //Если промах по кэш using ( Image bmpLayer = new Bitmap(width + _gutterSize * 2, height + _gutterSize * 2, PixelFormat.Format32bppArgb)) { //Загружаем данные (почему это делается вне WMS сам не понимаю). OnBeforeRenderNewImage(new RenderNewImageEventArgs(bboxWithGutters,useLayers[i])); //MapAround загрузит только видимые слои, по этому не заморачиваемся на загрузки слоев по отдельности. // рисуем карту //MapAround отрендерит только видимые слои. //Также он попытается отрендерить косметический слой, по этой причине мы проверяем выше, что бы он не был задан. _map.Render(bmpLayer, bboxWithGutters); //Копируем результат на результирующий растр. CopyImage(bmpLayer, bmpWithGutters); // Кладем в кэш растр слоя + информацию о названиях. SetImageToChach(useLayers[i], bmpLayer, wmsFeatureRender.CurrentTitleInfo, bboxWithGutters); } } finally { i++; //Делаем слой не видимым. useLayers[i - 1].Visible = false; if (useLayers[i - 1] is FeatureLayer) { //Меняем рендер на старый (useLayers[i - 1] as FeatureLayer).FeatureRenderer = _oldFeatureRender; } } } while (i < useLayers.Length); //После того как получили все слои запроса рендерим названия. wmsFeatureRender.RenderTitle(bmpWithGutters, bboxWithGutters); //Подготавливаем и отправляем результат. Image bmp = new Bitmap(width, height); CopyImageClipped(bmp, bmpWithGutters, width, height); if (cacheable) { SetImage(bboxWithGutters,bmp,allLayerKey); } return bmp; } } finally { // освобождаем ресурсы, связанные с рисованием карты if (_drawingRequestSemaphore != null) _drawingRequestSemaphore.Release(); } }