ortegren
ortegren

Reputation: 11

Using raster operations on OSM source in OpenLayers 5

      var osmSource = new ol.source.OSM({
        transition: 0
      });
      var rasterSource = new ol.source.Raster({
          sources: [osmSource],
          operation: function(pixels,data) {
                var pixel = pixels[0];

                var r = pixel[0];
                var g = pixel[1];
                var b = pixel[2];

                // CIE luminance for the RGB
                var v = 0.2126 * r + 0.7152 * g + 0.0722 * b;

                pixel[0] = v; // Red
                pixel[1] = v; // Green
                pixel[2] = v; // Blue
                //pixel[3] = 255;

                return pixel;
            }
      });
      var mapLayer = new ol.layer.Image({
          source: rasterSource
      });

      var map = new ol.Map({
        layers: [mapLayer],
        target: 'map',
        view: new ol.View({
          center: [1331819, 7906244],
          zoom: 12
        })
      });
 <link rel="stylesheet" href="https://cdn.rawgit.com/openlayers/openlayers.github.io/master/en/v5.3.0/css/ol.css" type="text/css">
<script src="https://cdn.rawgit.com/openlayers/openlayers.github.io/master/en/v5.3.0/build/ol.js"></script>
<div id="map" class="map"></div>

I'm trying to manipulate the color of pixels in tiles loaded from a tile source (in this case OSM) and implemented a simple test case with a conversion to a gray scale map, but for me it doesn't really work.

I have read the examples for OpenLayers v5.3 for using the Raster source to perform pixel wise operations.

  var osmSource = new ol.source.OSM();
  var rasterSource = new ol.source.Raster({
      sources: [osmSource],
      operation: function(pixels,data) {
            var pixel = pixels[0];

            var r = pixel[0];
            var g = pixel[1];
            var b = pixel[2];

            // CIE luminance for the RGB
            var v = 0.2126 * r + 0.7152 * g + 0.0722 * b;

            pixel[0] = v; // Red
            pixel[1] = v; // Green
            pixel[2] = v; // Blue
            //pixel[3] = 255;

            return pixel;
        }
  });
  var mapLayer = new ol.layer.Image({
      source: rasterSource
  });

  var map = new ol.Map({
    layers: [mapLayer],
    target: 'map',
    view: new ol.View({
      center: [1331819, 7906244],
      zoom: 12
    })
  });

Yes, I can get gray scale tiles, but sometimes they seem to be an intermediate version or something. Sometimes the loaded tiles are completely white, sometimes something in between white and the final image and when you zoom in, sometimes you just get the resized version of the previous zoom level.

Here is my full example:

https://apertum.se/iairvirodvlp/maptest_grey.htm

Upvotes: 0

Views: 1388

Answers (1)

Mike
Mike

Reputation: 17962

I cannot see any major problem with your demo, but the raster operation is going to exaggerate the effect of slow loading OSM sources which happens frequently when the OSM tile servers are busy. A much more efficient way of achieving grayscale is to use a global composite operation on the canvas at the postcompose event of a normal tile layer

osmLayer.on('postcompose', function (evt) {
    evt.context.globalCompositeOperation = 'color';
    evt.context.fillStyle = '#888';
    evt.context.fillRect(0, 0, evt.context.canvas.width, evt.context.canvas.height);
    evt.context.globalCompositeOperation = 'source-over';
});

      var osmSource = new ol.source.OSM({
          transition: 0
      });
      var mapLayer = new ol.layer.Tile({
          source: osmSource
      });

      mapLayer.on('postcompose', function (evt) {
          evt.context.globalCompositeOperation = 'color';
          // check browser supports globalCompositeOperation
          if (evt.context.globalCompositeOperation == 'color') {
              evt.context.fillStyle = 'rgba(255,255,255,' + grayInput.value/100 + ')';
              evt.context.fillRect(0, 0, evt.context.canvas.width, evt.context.canvas.height);
          }
          evt.context.globalCompositeOperation = 'overlay';
          // check browser supports globalCompositeOperation
          if (evt.context.globalCompositeOperation == 'overlay') {
              evt.context.fillStyle = 'rgb(' + [background,background,background].toString() + ')';
              evt.context.fillRect(0, 0, evt.context.canvas.width, evt.context.canvas.height);
          }
          evt.context.globalCompositeOperation = 'source-over';
      });

      var intensityInput = document.getElementById('intensity');
      var background = 255 - intensityInput.value;

      intensityInput.onchange = function() {
          background = 255 - intensityInput.value;
          map.render();
      };

      var grayInput = document.getElementById('gray');

      grayInput.onchange = function() {
          map.render();
      };

      var map = new ol.Map({
        layers: [mapLayer],
        target: 'map',
        view: new ol.View({
          center: [1331819, 7906244],
          zoom: 12
        })
      });
html, body, .map {
    margin: 0;
    padding: 0;
    width: 100%;
    height: 100%;
}
.map {
    margin: 0;
    padding: 0;
    width: 100%;
    height: 80%;
}
 <link rel="stylesheet" href="https://cdn.rawgit.com/openlayers/openlayers.github.io/master/en/v5.3.0/css/ol.css" type="text/css">
<script src="https://cdn.rawgit.com/openlayers/openlayers.github.io/master/en/v5.3.0/build/ol.js"></script>
<div id="map" class="map"></div>
<b>Gray:</b><input id="gray" type="range" min="0" max="100" step="1" value="50">
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<b>Intensity:</b><input id="intensity" type="range" min="0" max="255" step="1" value="128">

Upvotes: 1

Related Questions