diff --git a/examples/wms-image-custom-proj.js b/examples/wms-image-custom-proj.js index 80262a7c03..4548247b84 100644 --- a/examples/wms-image-custom-proj.js +++ b/examples/wms-image-custom-proj.js @@ -28,6 +28,7 @@ var layers = [ 'LAYERS': 'ch.swisstopo.pixelkarte-farbe-pk1000.noscale', 'FORMAT': 'image/jpeg' }, + serverType: 'mapserver', extent: extent }) }), @@ -42,6 +43,7 @@ var layers = [ 'National parks / geo.admin.ch' })], params: {'LAYERS': 'ch.bafu.schutzgebiete-paerke_nationaler_bedeutung'}, + serverType: 'mapserver', extent: extent }) }) diff --git a/examples/wms-image.js b/examples/wms-image.js index f6c753779e..dd495aac46 100644 --- a/examples/wms-image.js +++ b/examples/wms-image.js @@ -15,6 +15,7 @@ var layers = [ source: new ol.source.ImageWMS({ url: 'http://demo.opengeo.org/geoserver/wms', params: {'LAYERS': 'topp:states'}, + serverType: 'geoserver', extent: [-13884991, 2870341, -7455066, 6338219] }) }) diff --git a/examples/wms-no-proj.js b/examples/wms-no-proj.js index 09e7da57a8..260961b6b6 100644 --- a/examples/wms-no-proj.js +++ b/examples/wms-no-proj.js @@ -37,6 +37,7 @@ var layers = [ })], crossOrigin: 'anonymous', params: {'LAYERS': 'ch.bafu.schutzgebiete-paerke_nationaler_bedeutung'}, + serverType: 'mapserver', url: 'http://wms.geo.admin.ch/' }) }) diff --git a/src/objectliterals.jsdoc b/src/objectliterals.jsdoc index df4e7c4e28..3fb309839e 100644 --- a/src/objectliterals.jsdoc +++ b/src/objectliterals.jsdoc @@ -514,6 +514,11 @@ * @property {number|undefined} displayDpi The display resolution. Default is `96`. * @property {number|undefined} metersPerUnit The meters-per-unit value. Default is `1`. * @property {ol.Extent|undefined} extent Extent. + * @property {boolean|undefined} hidpi Use the `ol.Map#devicePixelRatio` value when + * requesting the image from the remote server. Default is `true`. + * @property {ol.source.wms.ServerType|undefined} serverType The type of the remote WMS + * server: `mapserver`, `geoserver` or `qgis`. Only needed if `hidpi` is `true`. + * Default is `undefined`. * @property {boolean|undefined} useOverlay If `true`, will use * `GETDYNAMICMAPOVERLAYIMAGE`. * @property {ol.proj.ProjectionLike} projection Projection. @@ -560,6 +565,8 @@ * @property {null|string|undefined} crossOrigin crossOrigin setting for image * requests. * @property {ol.Extent|undefined} extent Extent. + * @property {boolean|undefined} hidpi Use the `ol.Map#devicePixelRatio` value when + * requesting the image from the remote server. Default is `true`. * @property {Object.} params WMS request parameters. At least a * `LAYERS` param is required. `STYLES` is `` by default. `VERSION` is * `1.3.0` by default. `WIDTH`, `HEIGHT`, `BBOX` and `CRS` (`SRS` for WMS diff --git a/src/ol/image.js b/src/ol/image.js index adea4b9d16..ba5d6dcc52 100644 --- a/src/ol/image.js +++ b/src/ol/image.js @@ -28,11 +28,13 @@ ol.ImageState = { * @extends {goog.events.EventTarget} * @param {ol.Extent} extent Extent. * @param {number} resolution Resolution. + * @param {number} pixelRatio Pixel ratio. * @param {string} src Image source URI. * @param {?string} crossOrigin Cross origin. * @param {Array.} attributions Attributions. */ -ol.Image = function(extent, resolution, src, crossOrigin, attributions) { +ol.Image = + function(extent, resolution, pixelRatio, src, crossOrigin, attributions) { goog.base(this); @@ -54,6 +56,12 @@ ol.Image = function(extent, resolution, src, crossOrigin, attributions) { */ this.src_ = src; + /** + * @private + * @type {number} + */ + this.pixelRatio_ = pixelRatio; + /** * @private * @type {number} @@ -137,6 +145,14 @@ ol.Image.prototype.getImageElement = function(opt_context) { }; +/** + * @return {number} PixelRatio. + */ +ol.Image.prototype.getPixelRatio = function() { + return this.pixelRatio_; +}; + + /** * @return {number} Resolution. */ diff --git a/src/ol/renderer/canvas/canvasimagelayerrenderer.js b/src/ol/renderer/canvas/canvasimagelayerrenderer.js index dc6a94d298..69a41c6eb5 100644 --- a/src/ol/renderer/canvas/canvasimagelayerrenderer.js +++ b/src/ol/renderer/canvas/canvasimagelayerrenderer.js @@ -78,8 +78,8 @@ ol.renderer.canvas.ImageLayer.prototype.prepareFrame = var hints = frameState.viewHints; if (!hints[ol.ViewHint.ANIMATING] && !hints[ol.ViewHint.INTERACTING]) { - image = imageSource.getImage( - frameState.extent, viewResolution, view2DState.projection); + image = imageSource.getImage(frameState.extent, viewResolution, + frameState.devicePixelRatio, view2DState.projection); if (!goog.isNull(image)) { var imageState = image.getState(); if (imageState == ol.ImageState.IDLE) { @@ -95,7 +95,7 @@ ol.renderer.canvas.ImageLayer.prototype.prepareFrame = if (!goog.isNull(this.image_)) { image = this.image_; var imageExtent = image.getExtent(); - var imageResolution = image.getResolution(); + var imageResolution = image.getResolution() / image.getPixelRatio(); var devicePixelRatio = frameState.devicePixelRatio; ol.vec.Mat4.makeTransform2D(this.imageTransform_, devicePixelRatio * frameState.size[0] / 2, diff --git a/src/ol/renderer/dom/domimagelayerrenderer.js b/src/ol/renderer/dom/domimagelayerrenderer.js index 47d7845b7a..3e82b6bac3 100644 --- a/src/ol/renderer/dom/domimagelayerrenderer.js +++ b/src/ol/renderer/dom/domimagelayerrenderer.js @@ -66,8 +66,8 @@ ol.renderer.dom.ImageLayer.prototype.prepareFrame = var hints = frameState.viewHints; if (!hints[ol.ViewHint.ANIMATING] && !hints[ol.ViewHint.INTERACTING]) { - var image_ = imageSource.getImage( - frameState.extent, viewResolution, view2DState.projection); + var image_ = imageSource.getImage(frameState.extent, viewResolution, + frameState.devicePixelRatio, view2DState.projection); if (!goog.isNull(image_)) { var imageState = image_.getState(); if (imageState == ol.ImageState.IDLE) { diff --git a/src/ol/renderer/webgl/webglimagelayerrenderer.js b/src/ol/renderer/webgl/webglimagelayerrenderer.js index 9915739da3..7a3485febc 100644 --- a/src/ol/renderer/webgl/webglimagelayerrenderer.js +++ b/src/ol/renderer/webgl/webglimagelayerrenderer.js @@ -95,8 +95,8 @@ ol.renderer.webgl.ImageLayer.prototype.prepareFrame = var hints = frameState.viewHints; if (!hints[ol.ViewHint.ANIMATING] && !hints[ol.ViewHint.INTERACTING]) { - var image_ = imageSource.getImage( - frameState.extent, viewResolution, view2DState.projection); + var image_ = imageSource.getImage(frameState.extent, viewResolution, + frameState.devicePixelRatio, view2DState.projection); if (!goog.isNull(image_)) { var imageState = image_.getState(); if (imageState == ol.ImageState.IDLE) { diff --git a/src/ol/source/imagesource.js b/src/ol/source/imagesource.js index 31b9c1d384..2fbcb87bb1 100644 --- a/src/ol/source/imagesource.js +++ b/src/ol/source/imagesource.js @@ -78,17 +78,18 @@ goog.inherits(ol.source.Image, ol.source.Source); * @protected * @param {ol.Extent} extent Extent. * @param {number} resolution Resolution. + * @param {number} pixelRatio Pixel ratio. * @param {ol.Size} size Size. * @param {ol.proj.Projection} projection Projection. * @return {ol.Image} Single image. */ ol.source.Image.prototype.createImage = - function(extent, resolution, size, projection) { + function(extent, resolution, pixelRatio, size, projection) { var image = null; var imageUrl = this.imageUrlFunction(extent, size, projection); if (goog.isDef(imageUrl)) { image = new ol.Image( - extent, resolution, imageUrl, this.crossOrigin_, + extent, resolution, pixelRatio, imageUrl, this.crossOrigin_, this.getAttributions()); } return image; @@ -113,6 +114,7 @@ ol.source.Image.prototype.findNearestResolution = /** * @param {ol.Extent} extent Extent. * @param {number} resolution Resolution. + * @param {number} pixelRatio Pixel ratio. * @param {ol.proj.Projection} projection Projection. * @return {ol.Image} Single image. */ diff --git a/src/ol/source/imagestaticsource.js b/src/ol/source/imagestaticsource.js index 43ce4f62bd..38e534035c 100644 --- a/src/ol/source/imagestaticsource.js +++ b/src/ol/source/imagestaticsource.js @@ -38,7 +38,7 @@ ol.source.ImageStatic = function(options) { * @type {ol.Image} */ this.image_ = this.createImage( - imageExtent, imageResolution, imageSize, projection); + imageExtent, imageResolution, 1, imageSize, projection); }; goog.inherits(ol.source.ImageStatic, ol.source.Image); @@ -48,7 +48,7 @@ goog.inherits(ol.source.ImageStatic, ol.source.Image); * @inheritDoc */ ol.source.ImageStatic.prototype.getImage = - function(extent, resolution, projection) { + function(extent, resolution, pixelRatio, projection) { if (ol.extent.intersects(extent, this.image_.getExtent())) { return this.image_; } diff --git a/src/ol/source/imagewmssource.js b/src/ol/source/imagewmssource.js index 3a123f93b8..89b228408c 100644 --- a/src/ol/source/imagewmssource.js +++ b/src/ol/source/imagewmssource.js @@ -38,6 +38,18 @@ ol.source.ImageWMS = function(options) { imageUrlFunction: imageUrlFunction }); + /** + * @private + * @type {ol.source.wms.ServerType|undefined} + */ + this.serverType_ = options.serverType; + + /** + * @private + * @type {boolean} + */ + this.hidpi_ = goog.isDef(options.hidpi) ? options.hidpi : true; + /** * @private * @type {ol.Image} @@ -48,8 +60,7 @@ ol.source.ImageWMS = function(options) { * @private * @type {number} */ - this.ratio_ = goog.isDef(options.ratio) ? - options.ratio : 1.5; + this.ratio_ = goog.isDef(options.ratio) ? options.ratio : 1.5; }; goog.inherits(ol.source.ImageWMS, ol.source.Image); @@ -69,12 +80,14 @@ ol.source.ImageWMS.prototype.getParams = function() { * @inheritDoc */ ol.source.ImageWMS.prototype.getImage = - function(extent, resolution, projection) { + function(extent, resolution, pixelRatio, projection) { resolution = this.findNearestResolution(resolution); + pixelRatio = this.hidpi_ ? pixelRatio : 1; var image = this.image_; if (!goog.isNull(image) && image.getResolution() == resolution && + image.getPixelRatio() == pixelRatio && ol.extent.containsExtent(image.getExtent(), extent)) { return image; } @@ -83,9 +96,15 @@ ol.source.ImageWMS.prototype.getImage = ol.extent.scaleFromCenter(extent, this.ratio_); var width = (extent[2] - extent[0]) / resolution; var height = (extent[3] - extent[1]) / resolution; - var size = [width, height]; + var size = [width * pixelRatio, height * pixelRatio]; - this.image_ = this.createImage(extent, resolution, size, projection); + if (goog.isDef(this.serverType_) && pixelRatio > 1) { + var param = ol.source.wms.getDpiParam(this.serverType_, pixelRatio); + goog.object.extend(this.params_, param); + } + + this.image_ = this.createImage( + extent, resolution, pixelRatio, size, projection); return this.image_; }; diff --git a/src/ol/source/mapguidesource.js b/src/ol/source/mapguidesource.js index 8389f17f10..cd831e629d 100644 --- a/src/ol/source/mapguidesource.js +++ b/src/ol/source/mapguidesource.js @@ -31,6 +31,12 @@ ol.source.MapGuide = function(options) { imageUrlFunction: imageUrlFunction }); + /** + * @private + * @type {boolean} + */ + this.hidpi_ = goog.isDef(options.hidpi) ? options.hidpi : true; + /** * @private * @type {number} @@ -72,12 +78,14 @@ goog.inherits(ol.source.MapGuide, ol.source.Image); * @inheritDoc */ ol.source.MapGuide.prototype.getImage = - function(extent, resolution, projection) { + function(extent, resolution, pixelRatio, projection) { resolution = this.findNearestResolution(resolution); + pixelRatio = this.hidpi_ ? pixelRatio : 1; var image = this.image_; if (!goog.isNull(image) && image.getResolution() == resolution && + image.getPixelRatio() == pixelRatio && ol.extent.containsExtent(image.getExtent(), extent)) { return image; } @@ -88,9 +96,10 @@ ol.source.MapGuide.prototype.getImage = } var width = (extent[2] - extent[0]) / resolution; var height = (extent[3] - extent[1]) / resolution; - var size = [width, height]; + var size = [width * pixelRatio, height * pixelRatio]; - this.image_ = this.createImage(extent, resolution, size, projection); + this.image_ = this.createImage( + extent, resolution, pixelRatio, size, projection); return this.image_; }; diff --git a/src/ol/source/wmssource.js b/src/ol/source/wmssource.js index 9fdd7a80ad..47e8968d1e 100644 --- a/src/ol/source/wmssource.js +++ b/src/ol/source/wmssource.js @@ -1,9 +1,20 @@ goog.provide('ol.source.wms'); +goog.require('goog.asserts'); goog.require('goog.object'); goog.require('goog.uri.utils'); +/** + * @enum {string} + */ +ol.source.wms.ServerType = { + MAPSERVER: 'mapserver', + GEOSERVER: 'geoserver', + QGIS: 'qgis' +}; + + /** * @param {string} baseUrl WMS base URL. * @param {Object.} params Request parameters. @@ -12,8 +23,7 @@ goog.require('goog.uri.utils'); * @param {ol.proj.Projection} projection Projection. * @return {string} WMS GetMap request URL. */ -ol.source.wms.getUrl = - function(baseUrl, params, extent, size, projection) { +ol.source.wms.getUrl = function(baseUrl, params, extent, size, projection) { var baseParams = { 'SERVICE': 'WMS', 'VERSION': '1.3.0', @@ -40,3 +50,23 @@ ol.source.wms.getUrl = return goog.uri.utils.appendParamsFromMap(baseUrl, baseParams); }; + + +/** + * @param {ol.source.wms.ServerType} serverType Server name. + * @param {number} pixelRatio Pixel ratio. + * @return {Object.} + */ +ol.source.wms.getDpiParam = function(serverType, pixelRatio) { + var param = {}; + if (serverType == ol.source.wms.ServerType.MAPSERVER) { + param['MAP_RESOLUTION'] = 90 * pixelRatio; + } else if (serverType == ol.source.wms.ServerType.GEOSERVER) { + param['FORMAT_OPTION'] = 'dpi:' + 90 * pixelRatio; + } else if (serverType == ol.source.wms.ServerType.QGIS) { + param['DPI'] = 90 * pixelRatio; + } else { + goog.asserts.fail(); + } + return param; +};