diff --git a/externs/olx.js b/externs/olx.js
index da432b6c26..467d2eb6ea 100644
--- a/externs/olx.js
+++ b/externs/olx.js
@@ -4500,7 +4500,8 @@ olx.source.ImageVectorOptions.prototype.style;
/**
* @typedef {{sources: Array.
,
- * operations: (Array.|undefined)}}
+ * operations: (Array.|undefined),
+ * operationType: (ol.raster.OperationType|undefined)}}
* @api
*/
olx.source.RasterOptions;
@@ -4515,7 +4516,7 @@ olx.source.RasterOptions.prototype.sources;
/**
- * Pixel operations. Operations will be called with pixels from input sources
+ * Pixel operations. Operations will be called with data from input sources
* and the final output will be assigned to the raster source.
* @type {Array.|undefined}
* @api
@@ -4523,6 +4524,17 @@ olx.source.RasterOptions.prototype.sources;
olx.source.RasterOptions.prototype.operations;
+/**
+ * Operation type. Supported values are `'pixel'` and `'image'`. By default,
+ * `'pixel'` operations are assumed, and operations will be called with an
+ * array of pixels from input sources. If set to `'image'`, operations will
+ * be called with an array of ImageData objects from input sources.
+ * @type {ol.raster.OperationType|undefined}
+ * @api
+ */
+olx.source.RasterOptions.prototype.operationType;
+
+
/**
* @typedef {{attributions: (Array.|undefined),
* crossOrigin: (null|string|undefined),
diff --git a/src/ol/raster/operation.js b/src/ol/raster/operation.js
index b0430fba6b..b88d99c8af 100644
--- a/src/ol/raster/operation.js
+++ b/src/ol/raster/operation.js
@@ -1,23 +1,39 @@
goog.provide('ol.raster.IdentityOp');
goog.provide('ol.raster.Operation');
+goog.provide('ol.raster.OperationType');
/**
- * A function that takes an array of {@link ol.raster.Pixel} as inputs, performs
- * some operation on them, and returns an array of {@link ol.raster.Pixel} as
- * outputs.
+ * Raster operation type. Supported values are `'pixel'` and `'image'`.
+ * @enum {string}
+ * @api
+ */
+ol.raster.OperationType = {
+ PIXEL: 'pixel',
+ IMAGE: 'image'
+};
+
+
+/**
+ * A function that takes an array of input data, performs some operation, and
+ * returns an array of ouput data. For `'pixel'` type operations, functions
+ * will be called with an array of {@link ol.raster.Pixel} data and should
+ * return an array of the same. For `'image'` type operations, functions will
+ * be called with an array of {@link ImageData
+ * https://developer.mozilla.org/en-US/docs/Web/API/ImageData} and should return
+ * an array of the same.
*
- * @typedef {function(Array.): Array.}
+ * @typedef {function((Array.|Array.)):
+ * (Array.|Array.)}
* @api
*/
ol.raster.Operation;
/**
- * The identity operation for pixels. Returns the supplied input pixels as
- * outputs.
- * @param {Array.} inputs Input pixels.
- * @return {Array.} The input pixels as output.
+ * The identity operation. Returns the supplied input data as output.
+ * @param {(Array.|Array.)} inputs Input data.
+ * @return {(Array.|Array.)} The output data.
*/
ol.raster.IdentityOp = function(inputs) {
return inputs;
diff --git a/src/ol/source/rastersource.js b/src/ol/source/rastersource.js
index 596e67ee1c..e51e013743 100644
--- a/src/ol/source/rastersource.js
+++ b/src/ol/source/rastersource.js
@@ -13,6 +13,7 @@ goog.require('ol.extent');
goog.require('ol.layer.Image');
goog.require('ol.layer.Tile');
goog.require('ol.raster.IdentityOp');
+goog.require('ol.raster.OperationType');
goog.require('ol.renderer.canvas.ImageLayer');
goog.require('ol.renderer.canvas.TileLayer');
goog.require('ol.source.Image');
@@ -41,6 +42,13 @@ ol.source.Raster = function(options) {
this.operations_ = goog.isDef(options.operations) ?
options.operations : [ol.raster.IdentityOp];
+ /**
+ * @private
+ * @type {ol.raster.OperationType}
+ */
+ this.operationType_ = goog.isDef(options.operationType) ?
+ options.operationType : ol.raster.OperationType.PIXEL;
+
/**
* @private
* @type {Array.}
@@ -215,29 +223,36 @@ ol.source.Raster.prototype.composeFrame_ = function(frameState) {
this.renderers_[i], frameState, frameState.layerStatesArray[i]);
}
- var targetImageData = context.getImageData(0, 0, canvas.width, canvas.height);
- var target = targetImageData.data;
-
-
var resolution = frameState.viewState.resolution / frameState.pixelRatio;
this.dispatchEvent(new ol.source.RasterEvent(
ol.source.RasterEventType.BEFOREOPERATIONS, resolution));
- var source, pixel;
- for (var j = 0, jj = target.length; j < jj; j += 4) {
- for (var k = 0; k < len; ++k) {
- source = imageDatas[k].data;
- pixel = pixels[k];
- pixel[0] = source[j];
- pixel[1] = source[j + 1];
- pixel[2] = source[j + 2];
- pixel[3] = source[j + 3];
+ var targetImageData = null;
+ if (this.operationType_ === ol.raster.OperationType.PIXEL) {
+ targetImageData = context.getImageData(0, 0, canvas.width,
+ canvas.height);
+ var target = targetImageData.data;
+
+ var source, pixel;
+ for (var j = 0, jj = target.length; j < jj; j += 4) {
+ for (var k = 0; k < len; ++k) {
+ source = imageDatas[k].data;
+ pixel = pixels[k];
+ pixel[0] = source[j];
+ pixel[1] = source[j + 1];
+ pixel[2] = source[j + 2];
+ pixel[3] = source[j + 3];
+ }
+ pixel = this.runPixelOperations_(pixels)[0];
+ target[j] = pixel[0];
+ target[j + 1] = pixel[1];
+ target[j + 2] = pixel[2];
+ target[j + 3] = pixel[3];
}
- pixel = this.runOperations_(pixels)[0];
- target[j] = pixel[0];
- target[j + 1] = pixel[1];
- target[j + 2] = pixel[2];
- target[j + 3] = pixel[3];
+ } else if (this.operationType_ === ol.raster.OperationType.IMAGE) {
+ targetImageData = this.runImageOperations_(imageDatas)[0];
+ } else {
+ goog.asserts.fail('unsupported operation type: ' + this.operationType_);
}
this.dispatchEvent(new ol.source.RasterEvent(
@@ -255,7 +270,7 @@ ol.source.Raster.prototype.composeFrame_ = function(frameState) {
* @return {Array.} The modified pixels.
* @private
*/
-ol.source.Raster.prototype.runOperations_ = function(pixels) {
+ol.source.Raster.prototype.runPixelOperations_ = function(pixels) {
for (var i = 0, ii = this.operations_.length; i < ii; ++i) {
pixels = this.operations_[i](pixels);
}
@@ -263,6 +278,20 @@ ol.source.Raster.prototype.runOperations_ = function(pixels) {
};
+/**
+ * Run image operations.
+ * @param {Array.} imageDatas The input image data.
+ * @return {Array.} The output image data.
+ * @private
+ */
+ol.source.Raster.prototype.runImageOperations_ = function(imageDatas) {
+ for (var i = 0, ii = this.operations_.length; i < ii; ++i) {
+ imageDatas = this.operations_[i](imageDatas);
+ }
+ return imageDatas;
+};
+
+
/**
* Get image data from a renderer.
* @param {ol.renderer.canvas.Layer} renderer Layer renderer.