返回介绍

Color Manipulation

发布于 2022-11-30 23:36:02 字数 7816 浏览 0 评论 0 收藏 0

Demonstrates color manipulation with a raster source.

一个允许自由操作像素值的栅格资源对象。本示例中,对于传入瓦片资源,使用另一个栅格资源对象,在渲染之前进行逐像素调整 RGB 值。 此栅格操作,从 RGB 空间中获取像素值,转换为 HCL 颜色空间,根据上边的色调、色度、亮度等控件的值进行调整, 最后将像素转回 RGB 空间并且进行渲染。
PS:简单理解就是:RasterSource 这个对象,可以对于传入的栅格图层的瓦片进行像素级的颜色调整。比如可以把普通矢量图转为蓝黑色、墨绿色等。
可以查看此示例(简单并且优化):openlayers 修改天地图底图颜色

main.js

import 'ol/ol.css';
import ImageLayer from 'ol/layer/Image';
import Map from 'ol/Map';
import View from 'ol/View';
import {Raster as RasterSource, Stamen} from 'ol/source';

/**
 * Color manipulation functions below are adapted from
 * https://github.com/d3/d3-color.
 */
const Xn = 0.95047;
const Yn = 1;
const Zn = 1.08883;
const t0 = 4 / 29;
const t1 = 6 / 29;
const t2 = 3 * t1 * t1;
const t3 = t1 * t1 * t1;
const twoPi = 2 * Math.PI;

/**
 * Convert an RGB pixel into an HCL pixel.
 * @param {Array<number>} pixel A pixel in RGB space.
 * @return {Array<number>} A pixel in HCL space.
 */
function rgb2hcl(pixel) {
  const red = rgb2xyz(pixel[0]);
  const green = rgb2xyz(pixel[1]);
  const blue = rgb2xyz(pixel[2]);

  const x = xyz2lab(
    (0.4124564 * red + 0.3575761 * green + 0.1804375 * blue) / Xn
  );
  const y = xyz2lab(
    (0.2126729 * red + 0.7151522 * green + 0.072175 * blue) / Yn
  );
  const z = xyz2lab(
    (0.0193339 * red + 0.119192 * green + 0.9503041 * blue) / Zn
  );

  const l = 116 * y - 16;
  const a = 500 * (x - y);
  const b = 200 * (y - z);

  const c = Math.sqrt(a * a + b * b);
  let h = Math.atan2(b, a);
  if (h < 0) {
    h += twoPi;
  }

  pixel[0] = h;
  pixel[1] = c;
  pixel[2] = l;

  return pixel;
}

/**
 * Convert an HCL pixel into an RGB pixel.
 * @param {Array<number>} pixel A pixel in HCL space.
 * @return {Array<number>} A pixel in RGB space.
 */
function hcl2rgb(pixel) {
  const h = pixel[0];
  const c = pixel[1];
  const l = pixel[2];

  const a = Math.cos(h) * c;
  const b = Math.sin(h) * c;

  let y = (l + 16) / 116;
  let x = isNaN(a) ? y : y + a / 500;
  let z = isNaN(b) ? y : y - b / 200;

  y = Yn * lab2xyz(y);
  x = Xn * lab2xyz(x);
  z = Zn * lab2xyz(z);

  pixel[0] = xyz2rgb(3.2404542 * x - 1.5371385 * y - 0.4985314 * z);
  pixel[1] = xyz2rgb(-0.969266 * x + 1.8760108 * y + 0.041556 * z);
  pixel[2] = xyz2rgb(0.0556434 * x - 0.2040259 * y + 1.0572252 * z);

  return pixel;
}

function xyz2lab(t) {
  return t > t3 ? Math.pow(t, 1 / 3) : t / t2 + t0;
}

function lab2xyz(t) {
  return t > t1 ? t * t * t : t2 * (t - t0);
}

function rgb2xyz(x) {
  return (x /= 255) <= 0.04045 ? x / 12.92 : Math.pow((x + 0.055) / 1.055, 2.4);
}

function xyz2rgb(x) {
  return (
    255 * (x <= 0.0031308 ? 12.92 * x : 1.055 * Math.pow(x, 1 / 2.4) - 0.055)
  );
}

const raster = new RasterSource({
  sources: [
    new Stamen({
      layer: 'watercolor',
    }),
  ],
  operation: function (pixels, data) {
    const hcl = rgb2hcl(pixels[0]);

    let h = hcl[0] + (Math.PI * data.hue) / 180;
    if (h < 0) {
      h += twoPi;
    } else if (h > twoPi) {
      h -= twoPi;
    }
    hcl[0] = h;

    hcl[1] *= data.chroma / 100;
    hcl[2] *= data.lightness / 100;

    return hcl2rgb(hcl);
  },
  lib: {
    rgb2hcl: rgb2hcl,
    hcl2rgb: hcl2rgb,
    rgb2xyz: rgb2xyz,
    lab2xyz: lab2xyz,
    xyz2lab: xyz2lab,
    xyz2rgb: xyz2rgb,
    Xn: Xn,
    Yn: Yn,
    Zn: Zn,
    t0: t0,
    t1: t1,
    t2: t2,
    t3: t3,
    twoPi: twoPi,
  },
});

const controls = {};

raster.on('beforeoperations', function (event) {
  const data = event.data;
  for (const id in controls) {
    data[id] = Number(controls[id].value);
  }
});

const map = new Map({
  layers: [
    new ImageLayer({
      source: raster,
    }),
  ],
  target: 'map',
  view: new View({
    center: [0, 2500000],
    zoom: 2,
    maxZoom: 18,
  }),
});

const controlIds = ['hue', 'chroma', 'lightness'];
controlIds.forEach(function (id) {
  const control = document.getElementById(id);
  const output = document.getElementById(id + 'Out');
  const listener = function () {
    output.innerText = control.value;
    raster.changed();
  };
  control.addEventListener('input', listener);
  control.addEventListener('change', listener);
  output.innerText = control.value;
  controls[id] = control;
});

index.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <title>Color Manipulation</title>
    <!-- Pointer events polyfill for old browsers, see https://caniuse.com/#feat=pointer -->
    <script src="https://unpkg.com/elm-pep"></script>
    <!-- The line below is only needed for old environments like Internet Explorer and Android 4.x -->
    <script src="./resources/polyfill.min.js?features=fetch,requestAnimationFrame,Element.prototype.classList,URL,TextDecoder,Number.isInteger"></script>
    <style>
      .map {
        width: 100%;
        height:400px;
      }
      table.controls td {
        padding: 2px 5px;
      }
      table.controls td:nth-child(3) {
        text-align: right;
        min-width: 4.5em;
      }
    </style>
  </head>
  <body>
    <div id="map" class="map"></div>
    <table class="controls">
      <tr>
        <td><label for="hue">hue</label></td>
        <td><input id="hue" type="range" min="-180" max="180" value="0"/></td>
        <td><span id="hueOut"></span> °&nbsp;</td>
      </tr>
      <tr>
        <td><label for="chroma">chroma</label></td>
        <td><input id="chroma" type="range" min="0" max="100" value="100"/></td>
        <td><span id="chromaOut"></span> %</td>
      </tr>
      <tr>
        <td><label for="lightness">lightness</label></td>
        <td><input id="lightness" type="range" min="0" max="100" value="100"/></td>
        <td><span id="lightnessOut"></span> %</td>
      </tr>
    </table>
    <script src="main.js"></script>
  </body>
</html>

package.json

{
  "name": "color-manipulation",
  "dependencies": {
    "ol": "7.1.0"
  },
  "devDependencies": {
    "parcel": "^2.0.0-beta.1"
  },
  "scripts": {
    "start": "parcel index.html",
    "build": "parcel build --public-url . index.html"
  }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文