From 9a8b9d8adee6fe501b0ef21e7385811077000870 Mon Sep 17 00:00:00 2001
From: mike-000 <49240900+mike-000@users.noreply.github.com>
Date: Wed, 6 May 2020 21:56:11 +0100
Subject: [PATCH] add Image source imageSmoothing option
Add Image smoothing checkbox to example
Test imageSmoothing option
---
examples/reprojection-image.html | 1 +
examples/reprojection-image.js | 30 +++++++++++------
.../image-disable-smoothing/expected.png | Bin 0 -> 3031 bytes
.../cases/image-disable-smoothing/main.js | 29 ++++++++++++++++
.../expected.png | Bin 0 -> 3596 bytes
.../reproj-image-disable-smoothing/main.js | 31 ++++++++++++++++++
src/ol/renderer/canvas/ImageLayer.js | 2 ++
src/ol/reproj/Image.js | 14 ++++++--
src/ol/source/Image.js | 19 ++++++++++-
src/ol/source/ImageArcGISRest.js | 2 ++
src/ol/source/ImageCanvas.js | 2 ++
src/ol/source/ImageMapGuide.js | 2 ++
src/ol/source/ImageStatic.js | 2 ++
src/ol/source/ImageWMS.js | 2 ++
src/ol/source/Source.js | 7 ++++
src/ol/source/Tile.js | 7 ----
16 files changed, 130 insertions(+), 20 deletions(-)
create mode 100644 rendering/cases/image-disable-smoothing/expected.png
create mode 100644 rendering/cases/image-disable-smoothing/main.js
create mode 100644 rendering/cases/reproj-image-disable-smoothing/expected.png
create mode 100644 rendering/cases/reproj-image-disable-smoothing/main.js
diff --git a/examples/reprojection-image.html b/examples/reprojection-image.html
index 6cd557afa4..5a3aa14249 100644
--- a/examples/reprojection-image.html
+++ b/examples/reprojection-image.html
@@ -7,3 +7,4 @@ docs: >
tags: "reprojection, projection, proj4js, image, imagestatic"
---
+Image smoothing
diff --git a/examples/reprojection-image.js b/examples/reprojection-image.js
index 2d6c815b03..24879205cd 100644
--- a/examples/reprojection-image.js
+++ b/examples/reprojection-image.js
@@ -18,22 +18,14 @@ proj4.defs(
register(proj4);
const imageExtent = [0, 0, 700000, 1300000];
+const imageLayer = new ImageLayer();
const map = new Map({
layers: [
new TileLayer({
source: new OSM(),
}),
- new ImageLayer({
- source: new Static({
- url:
- 'https://upload.wikimedia.org/wikipedia/commons/thumb/1/18/' +
- 'British_National_Grid.svg/2000px-British_National_Grid.svg.png',
- crossOrigin: '',
- projection: 'EPSG:27700',
- imageExtent: imageExtent,
- }),
- }),
+ imageLayer,
],
target: 'map',
view: new View({
@@ -41,3 +33,21 @@ const map = new Map({
zoom: 4,
}),
});
+
+const imageSmoothing = document.getElementById('imageSmoothing');
+
+function setSource() {
+ const source = new Static({
+ url:
+ 'https://upload.wikimedia.org/wikipedia/commons/thumb/1/18/' +
+ 'British_National_Grid.svg/2000px-British_National_Grid.svg.png',
+ crossOrigin: '',
+ projection: 'EPSG:27700',
+ imageExtent: imageExtent,
+ imageSmoothing: imageSmoothing.checked,
+ });
+ imageLayer.setSource(source);
+}
+setSource();
+
+imageSmoothing.addEventListener('change', setSource);
diff --git a/rendering/cases/image-disable-smoothing/expected.png b/rendering/cases/image-disable-smoothing/expected.png
new file mode 100644
index 0000000000000000000000000000000000000000..8735dd9d861594991c7b3ac65dcd4a206b105dc1
GIT binary patch
literal 3031
zcmeAS@N?(olHy`uVBq!ia0y~yU<5K58911L)MWvCLlCbx$lZxy-8q?;Kn_c~qpu?a
z!^VE@KZ&eBK4*bPWHAE+-(e7DJf6QIg@J)P$J50zq$2L^9skqMQYG6z-mAH=%y&0a
zxZ_$Mfuf5G+IAUC5h``lP~9qc{DS7(|Hh(QcZeOnc=q7Vibsm)A3yobl(+8w$J%M<
z`S$v@^>ogUp#wl{@m{WhtCV||Nr&9xW4N7W5qvmAHSTOymNc~
z*KZeo@2{+X(f!?S{_f8o=RP-WI32Ll;VIKyix9mDJDi^~?RQrwY(K@SCGK&j_CDK(
zyZ84=RsDJK@6KBDJl?-g_xiW*+wt}0o%eNLcQ3Tx_wVAJ)An_hFRqHm$yPmno_}WV
zw?o;^+wFJRetDQJf97t@SQJvW~H5K~du=R-tkv^*|FqBD@JKQ@NoQfoz1D020Y&P+k!O)CjW3
z;|^3kL?o73!tp5+)FP0LNKTbHzyWs{$VR9MAgix4xIsKJ2)vfR|Hrordw18%@B01p
z?#}SKPp2*{um4f;?x_4ei!bY6?`!}5j`!}5o4q?{@8A1#4_kpGil^rAtbdO!Xpf%!
z@CzIP=%FyG0Vx5(Lup?<^N-gTHmmnPzxV5Dw6njwz3i_4+kY3E*HtCI__p?T@%uer
z&Rv+jzoPiX-Rbw|{(f~no^P%!&%34adriKd+&$lBJ!4E8mK(Wp#na9UNK0?{2d*
zt~^orN=^n>rsxj-{s3pLn6rz${Rob1@#u=Jg~~hh6amc_%ikST#Fa5DO8NP4W%_~h
zVvwhZolW%YXN9Z@csPc{a1HPx8Ebef}L!?dPM{i~m=A%X#sq@8I3v&+f^{Edj;P
zQO<9x_@{E$1eQ;dl!25bg>}b)VR^XO1XP?_9E|%4EMD|q`583>OH@!Xbnd+bFdix<
zfb*UDjn#G`dLLZxdZraXO0c6pWr1_m
zd(SZG|22k9QOqZ@cokNgHmn)tjD`UP>EOm)>;G&z?`_QIFJagMY>YE_y85}Sb4q9e
E00~l77ytkO
literal 0
HcmV?d00001
diff --git a/rendering/cases/image-disable-smoothing/main.js b/rendering/cases/image-disable-smoothing/main.js
new file mode 100644
index 0000000000..aef17f42d2
--- /dev/null
+++ b/rendering/cases/image-disable-smoothing/main.js
@@ -0,0 +1,29 @@
+import ImageLayer from '../../../src/ol/layer/Image.js';
+import Map from '../../../src/ol/Map.js';
+import Static from '../../../src/ol/source/ImageStatic.js';
+import View from '../../../src/ol/View.js';
+import {fromLonLat, transformExtent} from '../../../src/ol/proj.js';
+
+const source = new Static({
+ url: '/data/tiles/osm/5/5/12.png',
+ imageExtent: transformExtent([-123, 37, -122, 38], 'EPSG:4326', 'EPSG:3857'),
+ imageSmoothing: false,
+});
+
+new Map({
+ pixelRatio: 1,
+ target: 'map',
+ layers: [
+ new ImageLayer({
+ source: source,
+ }),
+ ],
+ view: new View({
+ center: fromLonLat([-122.416667, 37.783333]),
+ zoom: 12,
+ }),
+});
+
+render({
+ tolerance: 0.001,
+});
diff --git a/rendering/cases/reproj-image-disable-smoothing/expected.png b/rendering/cases/reproj-image-disable-smoothing/expected.png
new file mode 100644
index 0000000000000000000000000000000000000000..d2050f0742977c9b7d74bb140fcb4d93882a3775
GIT binary patch
literal 3596
zcmeAS@N?(olHy`uVBq!ia0y~yU<5K58911L)MWvCLlCbx$lZxy-8q?;Kn_c~qpu?a
z!^VE@KZ&eBK4*bPWHAE+-(e7DJf6QI1!&SjPZ!6KinzCT&v%DEmu&m^@8w;QT`!ld
z-Znum>eeL(B^Id;GdCZmE=AFL)+p!RKoiH~uX;WQd*460+ahL9jLp*EV-I)A+r2(K
zy?EX2rJpBHxAs53b?@}^-S_rbuB`sQ{JnVW{(`+P?*Bg<`}gqGMUx*-Ui9-tanTQ@
zM^Aoi$gry_mOLP(CB7o&On97ih+e?X8U1$Z?fOa}#=RJ}4Q;1bwZuP9z0Nn4J4El<
z;`1jTc5{Fj=F=J1EG%j~b+qQ`R_CWoQ@bICf*EI18M0TzEGROJuY4P@)8T27-LE+^
z`#L}jyw=^>DSzPKz3xTf_V2F5{(Jj$k@o)GK_xX6G2frg->*|u{AbyVd+OU?>-~F`
zbg_B;d-1!!Uaz&P5&Zb=?CnLf=ih1JN#F&!a>5RfgSb`Rf$V1Lw5}0sJjMD--l)M8
zKr^p@syvu^3#$WA2(qfD6%oY`Y
zSG_p-*1dGQ{#~tIzi-}M)Lt%kt@iKq_1*spAJ+-i^;_FnY3=&BeI~h1Pidc9MDMEe;kxnScS^Lil6~jq703M
zKXUD$ROWF9tOy!Y7kZ&F^`Tk@WTrwPSP?9yhL^?nE;8<^`sjS|;la3zdslydwQv8=
z1us7Cec!dNzG5%meb1UN-Ths5weK(QTD^aNRLRf1r(OH^Rfd#5|MYgz?(p{_w!i;L
zra&?sGzy@>g&L-qsUMu?zw$%N08~w=v4xqhzgK{vECTNnmVo!;8d)W%!HfNXaw*Iemt8!EDmyi1P>#9F&|LrRO=S}mX
zpW%(?-hC@Cf35fTS#*-PZZ>8o$1+&hJK4
zAE;4(=0z4blYhQA`!u%lIIRR$*TAY6)YNXg>lUO=`tl50Y2Pgw3$2gf)euUGKiadd
z3{*fF%J1EYtw>LD3x`&b@R|`N)f+Be4KDu9xaaF(t1xC#Xg+YqoRfyFlDK`|P||iiPd^
z>d&U@$Uw5OVZA#rzz%Q=LLww>^YSW>I}cBH{#50Lrv5Yc1A#&E!Rbg1D9E?oe6vzc
zsQgD!Qr*czK(oMYhw>{xPwx?c1Zu8X^(vs&eRF2SZz_NU-qAm@pjaJl&HxtaSKjWe
zi7P4ju#4}%dvC?xtmQ9Wd|2@A!PnP|4*$Ko=<(ylyCy$Ayr_BaUZp)&=KoG=-MU{L
zx#jyOP)Ytn0=WePu3=XfBPvgMXLwx;O~DnV;G_jEQy(S+n`rO`4!DS4e-2T%*6<*z
zVn`YG;Ho8}Fz;7HuO{|bA*$XFhQQ_$N~&)Re~zd{?ApLhE~Enc!z*z04Q>(~J}v;S
z$f0J$%>_5Cz~wplo-TODF7R>x35G>mc@&~fk5Z#SK%G<|b-VJH{HuFDdCA|JrGPy+
N22WQ%mvv4FO#m#jL)riU
literal 0
HcmV?d00001
diff --git a/rendering/cases/reproj-image-disable-smoothing/main.js b/rendering/cases/reproj-image-disable-smoothing/main.js
new file mode 100644
index 0000000000..5383d316ca
--- /dev/null
+++ b/rendering/cases/reproj-image-disable-smoothing/main.js
@@ -0,0 +1,31 @@
+import ImageLayer from '../../../src/ol/layer/Image.js';
+import Map from '../../../src/ol/Map.js';
+import Static from '../../../src/ol/source/ImageStatic.js';
+import View from '../../../src/ol/View.js';
+import {get as getProjection, transformExtent} from '../../../src/ol/proj.js';
+
+const source = new Static({
+ url: '/data/tiles/osm/5/5/12.png',
+ imageExtent: transformExtent([-123, 37, -122, 38], 'EPSG:4326', 'EPSG:3857'),
+ imageSmoothing: false,
+ projection: getProjection('EPSG:3857'),
+});
+
+new Map({
+ pixelRatio: 1,
+ target: 'map',
+ layers: [
+ new ImageLayer({
+ source: source,
+ }),
+ ],
+ view: new View({
+ center: [-122.416667, 37.783333],
+ zoom: 12,
+ projection: 'EPSG:4326',
+ }),
+});
+
+render({
+ tolerance: 0.001,
+});
diff --git a/src/ol/renderer/canvas/ImageLayer.js b/src/ol/renderer/canvas/ImageLayer.js
index 7cf79ca989..72e6933b90 100644
--- a/src/ol/renderer/canvas/ImageLayer.js
+++ b/src/ol/renderer/canvas/ImageLayer.js
@@ -4,6 +4,7 @@
import CanvasLayerRenderer from './Layer.js';
import ViewHint from '../../ViewHint.js';
import {ENABLE_RASTER_REPROJECTION} from '../../reproj/common.js';
+import {assign} from '../../obj.js';
import {compose as composeTransform, makeInverse} from '../../transform.js';
import {containsExtent, intersects} from '../../extent.js';
import {createTransformString} from '../../render/canvas.js';
@@ -180,6 +181,7 @@ class CanvasImageLayerRenderer extends CanvasLayerRenderer {
const dw = img.width * transform[0];
const dh = img.height * transform[3];
+ assign(context, this.getLayer().getSource().getContextOptions());
this.preRender(context, frameState);
if (dw >= 0.5 && dh >= 0.5) {
const opacity = layerState.opacity;
diff --git a/src/ol/reproj/Image.js b/src/ol/reproj/Image.js
index af44175bc2..bbb6e8b1e6 100644
--- a/src/ol/reproj/Image.js
+++ b/src/ol/reproj/Image.js
@@ -32,6 +32,7 @@ class ReprojImage extends ImageBase {
* @param {number} pixelRatio Pixel ratio.
* @param {FunctionType} getImageFunction
* Function returning source images (extent, resolution, pixelRatio).
+ * @param {object=} opt_contextOptions Properties to set on the canvas context.
*/
constructor(
sourceProj,
@@ -39,7 +40,8 @@ class ReprojImage extends ImageBase {
targetExtent,
targetResolution,
pixelRatio,
- getImageFunction
+ getImageFunction,
+ opt_contextOptions
) {
const maxSourceExtent = sourceProj.getExtent();
const maxTargetExtent = targetProj.getExtent();
@@ -120,6 +122,12 @@ class ReprojImage extends ImageBase {
*/
this.sourcePixelRatio_ = sourcePixelRatio;
+ /**
+ * @private
+ * @type {object}
+ */
+ this.contextOptions_ = opt_contextOptions;
+
/**
* @private
* @type {HTMLCanvasElement}
@@ -181,7 +189,9 @@ class ReprojImage extends ImageBase {
image: this.sourceImage_.getImage(),
},
],
- 0
+ 0,
+ undefined,
+ this.contextOptions_
);
}
this.state = sourceState;
diff --git a/src/ol/source/Image.js b/src/ol/source/Image.js
index dd50c89271..2c62214b1b 100644
--- a/src/ol/source/Image.js
+++ b/src/ol/source/Image.js
@@ -6,6 +6,7 @@ import ImageState from '../ImageState.js';
import ReprojImage from '../reproj/Image.js';
import Source from './Source.js';
import {ENABLE_RASTER_REPROJECTION} from '../reproj/common.js';
+import {IMAGE_SMOOTHING_DISABLED} from './common.js';
import {abstract} from '../util.js';
import {equals} from '../extent.js';
import {equivalent} from '../proj.js';
@@ -62,6 +63,7 @@ export class ImageSourceEvent extends Event {
/**
* @typedef {Object} Options
* @property {import("./Source.js").AttributionLike} [attributions]
+ * @property {boolean} [imageSmoothing=true] Enable image smoothing.
* @property {import("../proj.js").ProjectionLike} [projection]
* @property {Array} [resolutions]
* @property {import("./State.js").default} [state]
@@ -105,6 +107,13 @@ class ImageSource extends Source {
* @type {number}
*/
this.reprojectedRevision_ = 0;
+
+ /**
+ * @private
+ * @type {object|undefined}
+ */
+ this.contextOptions_ =
+ options.imageSmoothing === false ? IMAGE_SMOOTHING_DISABLED : undefined;
}
/**
@@ -114,6 +123,13 @@ class ImageSource extends Source {
return this.resolutions_;
}
+ /**
+ * @return {Object|undefined} Context options.
+ */
+ getContextOptions() {
+ return this.contextOptions_;
+ }
+
/**
* @protected
* @param {number} resolution Resolution.
@@ -173,7 +189,8 @@ class ImageSource extends Source {
pixelRatio,
sourceProjection
);
- }.bind(this)
+ }.bind(this),
+ this.contextOptions_
);
this.reprojectedRevision_ = this.getRevision();
diff --git a/src/ol/source/ImageArcGISRest.js b/src/ol/source/ImageArcGISRest.js
index b4c74c2ba2..21c60cabb7 100644
--- a/src/ol/source/ImageArcGISRest.js
+++ b/src/ol/source/ImageArcGISRest.js
@@ -20,6 +20,7 @@ import {containsExtent, getHeight, getWidth} from '../extent.js';
* the remote server.
* @property {import("../Image.js").LoadFunction} [imageLoadFunction] Optional function to load an image given
* a URL.
+ * @property {boolean} [imageSmoothing=true] Enable image smoothing.
* @property {Object} [params] ArcGIS Rest parameters. This field is optional. Service
* defaults will be used for any fields not specified. `FORMAT` is `PNG32` by default. `F` is
* `IMAGE` by default. `TRANSPARENT` is `true` by default. `BBOX`, `SIZE`, `BBOXSR`, and `IMAGESR`
@@ -56,6 +57,7 @@ class ImageArcGISRest extends ImageSource {
super({
attributions: options.attributions,
+ imageSmoothing: options.imageSmoothing,
projection: options.projection,
resolutions: options.resolutions,
});
diff --git a/src/ol/source/ImageCanvas.js b/src/ol/source/ImageCanvas.js
index 576b77060e..bc73fe22b2 100644
--- a/src/ol/source/ImageCanvas.js
+++ b/src/ol/source/ImageCanvas.js
@@ -36,6 +36,7 @@ import {
* the value returned by the function is later changed then
* `changed` should be called on the source for the source to
* invalidate the current cached image. See: {@link module:ol/Observable~Observable#changed}
+ * @property {boolean} [imageSmoothing=true] Enable image smoothing.
* @property {import("../proj.js").ProjectionLike} [projection] Projection. Default is the view projection.
* @property {number} [ratio=1.5] Ratio. 1 means canvases are the size of the map viewport, 2 means twice the
* width and height of the map viewport, and so on. Must be `1` or higher.
@@ -58,6 +59,7 @@ class ImageCanvasSource extends ImageSource {
super({
attributions: options.attributions,
+ imageSmoothing: options.imageSmoothing,
projection: options.projection,
resolutions: options.resolutions,
state: options.state,
diff --git a/src/ol/source/ImageMapGuide.js b/src/ol/source/ImageMapGuide.js
index 98afc1eb4c..e4a0ff56af 100644
--- a/src/ol/source/ImageMapGuide.js
+++ b/src/ol/source/ImageMapGuide.js
@@ -32,6 +32,7 @@ import {
* @property {Array} [resolutions] Resolutions.
* If specified, requests will be made for these resolutions only.
* @property {import("../Image.js").LoadFunction} [imageLoadFunction] Optional function to load an image given a URL.
+ * @property {boolean} [imageSmoothing=true] Enable image smoothing.
* @property {Object} [params] Additional parameters.
*/
@@ -48,6 +49,7 @@ class ImageMapGuide extends ImageSource {
*/
constructor(options) {
super({
+ imageSmoothing: options.imageSmoothing,
projection: options.projection,
resolutions: options.resolutions,
});
diff --git a/src/ol/source/ImageStatic.js b/src/ol/source/ImageStatic.js
index c8aa5a1924..fc9276b618 100644
--- a/src/ol/source/ImageStatic.js
+++ b/src/ol/source/ImageStatic.js
@@ -19,6 +19,7 @@ import {get as getProjection} from '../proj.js';
* @property {import("../extent.js").Extent} [imageExtent] Extent of the image in map coordinates.
* This is the [left, bottom, right, top] map coordinates of your image.
* @property {import("../Image.js").LoadFunction} [imageLoadFunction] Optional function to load an image given a URL.
+ * @property {boolean} [imageSmoothing=true] Enable image smoothing.
* @property {import("../proj.js").ProjectionLike} [projection] Projection. Default is the view projection.
* @property {import("../size.js").Size} [imageSize] Size of the image in pixels. Usually the image size is auto-detected, so this
* only needs to be set if auto-detection fails for some reason.
@@ -45,6 +46,7 @@ class Static extends ImageSource {
super({
attributions: options.attributions,
+ imageSmoothing: options.imageSmoothing,
projection: getProjection(options.projection),
});
diff --git a/src/ol/source/ImageWMS.js b/src/ol/source/ImageWMS.js
index a74d02ec81..93cadb954b 100644
--- a/src/ol/source/ImageWMS.js
+++ b/src/ol/source/ImageWMS.js
@@ -39,6 +39,7 @@ const GETFEATUREINFO_IMAGE_SIZE = [101, 101];
* @property {import("./WMSServerType.js").default|string} [serverType] The type of
* the remote WMS server: `mapserver`, `geoserver` or `qgis`. Only needed if `hidpi` is `true`.
* @property {import("../Image.js").LoadFunction} [imageLoadFunction] Optional function to load an image given a URL.
+ * @property {boolean} [imageSmoothing=true] Enable image smoothing.
* @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`
@@ -68,6 +69,7 @@ class ImageWMS extends ImageSource {
super({
attributions: options.attributions,
+ imageSmoothing: options.imageSmoothing,
projection: options.projection,
resolutions: options.resolutions,
});
diff --git a/src/ol/source/Source.js b/src/ol/source/Source.js
index 5655054a2b..af2898cfec 100644
--- a/src/ol/source/Source.js
+++ b/src/ol/source/Source.js
@@ -140,6 +140,13 @@ class Source extends BaseObject {
return this.wrapX_;
}
+ /**
+ * @return {Object|undefined} Context options.
+ */
+ getContextOptions() {
+ return undefined;
+ }
+
/**
* Refreshes the source. The source will be cleared, and data from the server will be reloaded.
* @api
diff --git a/src/ol/source/Tile.js b/src/ol/source/Tile.js
index f2eb329882..901386fa8a 100644
--- a/src/ol/source/Tile.js
+++ b/src/ol/source/Tile.js
@@ -173,13 +173,6 @@ class TileSource extends Source {
return covered;
}
- /**
- * @return {Object|undefined} Context options.
- */
- getContextOptions() {
- return undefined;
- }
-
/**
* @param {import("../proj/Projection.js").default} projection Projection.
* @return {number} Gutter.