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!4E8mKrsxj-{s3pLn6rz${Rob1@#u=Jg~~hh6amc_%ikST#Fa5DO8NP4W%_~h zV&#vwhZolW%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.