diff --git a/src/objectliterals.exports b/src/objectliterals.exports
index cf5e830f3f..a6ce462790 100644
--- a/src/objectliterals.exports
+++ b/src/objectliterals.exports
@@ -92,6 +92,16 @@
@exportObjectLiteralProperty ol.source.DebugTileSourceOptions.projection ol.Projection|undefined
@exportObjectLiteralProperty ol.source.DebugTileSourceOptions.tileGrid ol.tilegrid.TileGrid|undefined
+@exportObjectLiteral ol.source.SingleImageWMSOptions
+@exportObjectLiteralProperty ol.source.SingleImageWMSOptions.attributions Array.
|undefined
+@exportObjectLiteralProperty ol.source.SingleImageWMSOptions.crossOrigin null|string|undefined
+@exportObjectLiteralProperty ol.source.SingleImageWMSOptions.extent ol.Extent|undefined
+@exportObjectLiteralProperty ol.source.SingleImageWMSOptions.params Object.
+@exportObjectLiteralProperty ol.source.SingleImageWMSOptions.projection ol.Projection|undefined
+@exportObjectLiteralProperty ol.source.SingleImageWMSOptions.resolutions Array.|undefined
+@exportObjectLiteralProperty ol.source.SingleImageWMSOptions.url string|undefined
+@exportObjectLiteralProperty ol.source.SingleImageWMSOptions.version string|undefined
+
@exportObjectLiteral ol.source.StamenOptions
@exportObjectLiteralProperty ol.source.StamenOptions.flavor string|undefined
@exportObjectLiteralProperty ol.source.StamenOptions.provider string
diff --git a/src/ol/source/singleimagewms.exports b/src/ol/source/singleimagewms.exports
new file mode 100644
index 0000000000..4d79ecdabc
--- /dev/null
+++ b/src/ol/source/singleimagewms.exports
@@ -0,0 +1 @@
+@exportSymbol ol.source.SingleImageWMS
diff --git a/src/ol/source/singleimagewmssource.js b/src/ol/source/singleimagewmssource.js
new file mode 100644
index 0000000000..ec8ce0c329
--- /dev/null
+++ b/src/ol/source/singleimagewmssource.js
@@ -0,0 +1,99 @@
+goog.provide('ol.source.SingleImageWMS');
+
+goog.require('ol.Extent');
+goog.require('ol.Image');
+goog.require('ol.ImageUrlFunction');
+goog.require('ol.Projection');
+goog.require('ol.Size');
+goog.require('ol.source.ImageSource');
+
+
+
+/**
+ * @constructor
+ * @extends {ol.source.ImageSource}
+ * @param {ol.source.SingleImageWMSOptions} options Options.
+ */
+ol.source.SingleImageWMS = function(options) {
+
+ var projection = ol.Projection.createProjection(
+ options.projection, 'EPSG:3857');
+ var projectionExtent = projection.getExtent();
+
+ var extent = goog.isDef(options.extent) ?
+ options.extent : projectionExtent;
+
+ var version = goog.isDef(options.version) ?
+ options.version : '1.3';
+
+ var baseParams = {
+ 'SERVICE': 'WMS',
+ 'VERSION': version,
+ 'REQUEST': 'GetMap',
+ 'STYLES': '',
+ 'FORMAT': 'image/png',
+ 'TRANSPARENT': true
+ };
+ baseParams[version >= '1.3' ? 'CRS' : 'SRS'] = projection.getCode();
+ goog.object.extend(baseParams, options.params);
+
+ var imageUrlFunction;
+ if (options.url) {
+ var url = goog.uri.utils.appendParamsFromMap(
+ options.url, baseParams);
+ imageUrlFunction = ol.ImageUrlFunction.createBboxParam(url);
+ } else {
+ imageUrlFunction =
+ ol.ImageUrlFunction.nullImageUrlFunction;
+ }
+
+ goog.base(this, {
+ attributions: options.attributions,
+ crossOrigin: options.crossOrigin,
+ extent: extent,
+ projection: projection,
+ resolutions: options.resolutions,
+ imageUrlFunction: imageUrlFunction
+ });
+
+ /**
+ * @private
+ * @type {ol.Image}
+ */
+ this.image_ = null;
+
+ /**
+ * FIXME configurable?
+ * @private
+ * @type {number}
+ */
+ this.ratio_ = 1.5;
+
+};
+goog.inherits(ol.source.SingleImageWMS, ol.source.ImageSource);
+
+
+/**
+ * @inheritDoc
+ */
+ol.source.SingleImageWMS.prototype.getImage =
+ function(extent, resolution) {
+ resolution = this.findNearestResolution(resolution);
+
+ var image = this.image_;
+ if (!goog.isNull(image) &&
+ image.getResolution() == resolution &&
+ image.getExtent().containsExtent(extent)) {
+ return image;
+ }
+
+ extent = new ol.Extent(extent.minX, extent.minY,
+ extent.maxX, extent.maxY);
+ extent.scale(this.ratio_);
+ var width = extent.getWidth() / resolution;
+ var height = extent.getHeight() / resolution;
+ var size = new ol.Size(width, height);
+
+ this.image_ = this.createImage(extent, resolution, size);
+ return this.image_;
+};