ホームページ  >  記事  >  ウェブフロントエンド  >  CSS を使用して画像モザイクの様式化を実現する方法を見てみましょう。

CSS を使用して画像モザイクの様式化を実現する方法を見てみましょう。

青灯夜游
青灯夜游転載
2022-02-28 10:15:042530ブラウズ

CSS を使用して写真にモザイクを追加するにはどうすればよいですか?次の記事では、CSS を上手に使って画像モザイクのスタイルを設定する方法を紹介します。

CSS を使用して画像モザイクの様式化を実現する方法を見てみましょう。

1. 画像レンダリングの概要

CSS には

image-rendering## と呼ばれる興味深い機能があります。 # 、アルゴリズムを使用してズームされた画像をより適切に表示できます。 (推奨される学習: css ビデオ チュートリアル ) QR コードの小さいスクリーンショット (下左、概略図のみでスキャンできません) があるとします。画像は拡大されます。 10 回 ぼかします (右下):

CSS を使用して画像モザイクの様式化を実現する方法を見てみましょう。このとき、拡大画像に

image-rendering:pixelated

機能を追加し、 CSS は、画像の輪郭がより鮮明になるように、ピクセルとして表示するアルゴリズムを渡します。

CSS を使用して画像モザイクの様式化を実現する方法を見てみましょう。この機能は、単色、明確な輪郭、および擬似ベクトルの既視感を作り出すことができます(拡大後の歪みを軽減します)。

豊かな色とより詳細な写真の場合、

image-rendering:pixelated

によりモザイクのような外観が作成されます:

CSS を使用して画像モザイクの様式化を実現する方法を見てみましょう。 これはまだですこの記事のタイトルで実現したいモザイク効果とは程遠いです。現在、効果を表示するには画像を拡大する必要がありますが、元の画像サイズを維持しながら同じサイズのモザイクで画像をカバーしたいと考えています。

ただし

image-rendering

このプロパティは、サイズがスケールされていない要素には効果がありません:

MDN

- このプロパティ

#2. 等サイズ モザイクの実装

等サイズ モザイクの原則は、最初の配置と同じです。写真をぼかし、鮮明化アルゴリズムで処理して、さまざまな小さな正方形を取得します。

image-rendering:pixelated

は「シャープ化」ステップを達成するのに役立ちましたが、「ぼかし」を達成する方法を考える必要があります。

まず第一に、image-rendering

は画像のスケーリング係数に強く関係しているため、フィルターを使用したぼかしの解決策は実現できません。そのため、画像。

ここで言わなければならないのは、WEB 上の写真は Photoshop のスマート オブジェクトによく似ているということです。サイズは任意に変更できます (たとえば、何回も拡大してぼやけるなど)。画像を元に戻すことができます。画像は元のサイズ (歪みなし) に戻ります。

画像を拡大した後に「ぼやけた」情報をどのように保持するかは、解決すべき優先課題です。

賢い友達はすでに

canvas

を使って処理しようと考えているでしょう。結局のところ、

canvas は簡単に画像を取得して描画することができ、描画された画像情報は純粋ですdata. はグラフィックス オブジェクト (Image) ではなく、そのため、拡大してから (元のサイズに) 縮小することで描画された画像データは歪みます (これがまさに私たちが望んでいることです)。 しかし、ここにはいくつかの落とし穴もあります。

外部画像が

image-rendering:pixelated
    アルゴリズムによって処理された後に表示される情報、
  • Canvas 表示レイヤー上にあるものなので取得することは不可能です。 canvas 得られるのは、まだシャープ化されておらずぼやけたネイティブ画像コンテンツです。canvas
  • ズームされていない場合は、
  • canvas## を指定してください # を追加しますimage-rendering:pixelated には意味がありません。 これは、canvas
  • の外側で画像を拡大したり鮮明にしたり、その後
canvas

を記述して図面を縮小したり (繰り返しを継続したり) できないことを意味します。シャープ化された元のサイズの画像。 3. 興味深いキャンバスの伸縮

上記の問題を解決するとき、まず canvas の興味深い機能を見てみましょう。

canvas タグで幅と高さを定義する場合:

<canvas width="100" height="50" ></canvas>

同時に、canvas に別の幅と高さを定義します。スタイル:

canvas {
  width: 200px;
  height: 200px;
}

それでは、canvas はどのサイズで表示されますか?

答えは CSS サイズで表示されますが、キャンバスのコンテンツのサイズは、canvas タグで定義された幅と高さに基づきます。これは、200px * 200px のキャンバスが表示されますが、そのコンテンツは実際には引き伸ばされていることを意味します (幅 2 倍、高さ 4 倍)。

CSS を使用して画像モザイクの様式化を実現する方法を見てみましょう。

注:左边为画布,右边为原图

这也是 canvas 作为可替换元素的一个特性 —— CSS 无法修改其内容。试想一下,如果 CSS 可以动态地修改 canvas 内容的尺寸,意味着 canvas 的内容会被裁剪掉一部分,或者多出来一部分空白区域,这显然是不可取的。所以 canvas 在保留内容完整的前提下,整体伸缩到样式规定尺寸,是合理的浏览器行为。

利用 canvas 的这个特性,我们可以这样来实现等尺寸马赛克:

  • 创建一个画布,通过样式规定好其宽高,并设置 image-rendering: pixelated 特性;
  • 计算图片最佳展示尺寸(以类似 background-size: contain 的形式展示);
  • 将画布的宽高(非样式)设置为样式宽高的 1/N
  • 绘制图像,绘制的图像宽高为最佳展示尺寸的 1/N

如此一来,我们实际绘制了一个尺寸仅为最佳尺寸 1/N 的图像,再通过 canvasN 倍放大又变回了视觉上的最佳尺寸。图像因为走的 canvas 绘制,所以放大回最佳尺寸后会保持模糊,从而满足了 image-rendering 的匹配需求。

注:这里提到的“最佳尺寸”,指的是步骤 2 里“确保完整展示图像”所对应的最佳尺寸,而非图片原生尺寸。

四、代码实现

我们按照上方步骤来书写对应代码,当然我们希望灵活一些,例如上述的 N 可以由用户自定义。另外本章的代码可以在 Github 上获取

4.1 HTML 部分

主要为选择图片的 <input> 控件、画布、方便画布获取图像的 <img alt="CSS を使用して画像モザイクの様式化を実現する方法を見てみましょう。" >、供用户自定义缩放倍数的文本框、执行按钮:

  <input id="file" type="file" accept="image/*" />
  <canvas id="canvas"></canvas>
  <img  id="img-raw" / alt="CSS を使用して画像モザイクの様式化を実現する方法を見てみましょう。" >
  <label for="compress-times">压缩倍数:</label>
  <input id="compress-times" type="number" value="12">
  <button>马赛克化</button>

4.2 CSS 部分

我们需要通过样式规定好画布的外观尺寸,并配置 image-rendering: pixelated 特性。另外 <img alt="CSS を使用して画像モザイクの様式化を実現する方法を見てみましょう。" > 标签只是一个传递用户所选图片到画布的中介,可以直接隐藏:

    canvas {
      display: block;
      border: gray solid 1px;
      width: 600px;
      height: 600px;
      image-rendering: pixelated;
    }

    img {
      display: none;
    }

4.3 JS 部分

    let imgBlobUrl;
    const file = document.getElementById(&#39;file&#39;);
    const img = document.getElementById(&#39;img-raw&#39;);
    const compressTimes = document.getElementById(&#39;compress-times&#39;);
    const defaultCompressTimes = compressTimes.value | 0;
    const canvas = document.getElementById(&#39;canvas&#39;);
    const button = document.querySelector(&#39;button&#39;);

    const boundingRect = canvas.getBoundingClientRect();
    const ctx = canvas.getContext(&#39;2d&#39;);
    const canvas_w = boundingRect.width;
    const canvas_h = boundingRect.height;

    // 以 background-size: contain 形式设置图片尺寸
    function matchImgSizeToCanvas(imgElem = img) {
      let w = imgElem.width;
      let h = imgElem.height;
      if (w > canvas_w || h > canvas_h) {
        let radio = Math.max(h / canvas_h, w / canvas_w);
        radio = Number(radio.toFixed(2));
        imgElem.width = parseInt(w / radio);
        imgElem.height = parseInt(h / radio);
      }
    }

    // 绘制 1/N 大小的图像,画布宽高属性设为样式宽高的 1/N,从而实现画布内容的 N 倍放大
    function run() {
      let ct = parseInt(compressTimes.value) || defaultCompressTimes;
      canvas.width = parseInt(canvas_w / ct);
      canvas.height = parseInt(canvas_h / ct);
      ctx.drawImage(img, 0, 0, parseInt(img.width / ct), parseInt(img.height / ct));
    }

    function cleanCanvas() {
      ctx.clearRect(0, 0, canvas_w, canvas_h);
    }

    function reset() {
      img.removeAttribute(&#39;width&#39;);
      img.removeAttribute(&#39;height&#39;);
      cleanCanvas();
      matchImgSizeToCanvas(img);
      run();
    }

    file.addEventListener(&#39;change&#39;, function (e) {
      window.URL.revokeObjectURL(imgBlobUrl);
      const picFile = this.files[0];
      imgBlobUrl = window.URL.createObjectURL(picFile);
      img.onload = function init() {
        reset();
      }
      img.src = imgBlobUrl;
    }, false);

    button.addEventListener(&#39;click&#39;, reset, false);

执行效果:

CSS を使用して画像モザイクの様式化を実現する方法を見てみましょう。

选中文件/点击按钮后,能按压缩倍数得到对应的像素风格艺术照。

五、Mosaic 插件封装

通过上方示例我们学习了如何利用 canvas 特性来设计等尺寸的马赛克效果,现在我们尝试把该功能封装为一个简易插件,可以让页面上的图片列表一键 Mosaicing。

插件的实现方案也很简单 —— 用户点击按钮时,往图片容器上插入一个和容器等尺寸的画布(尺寸通过样式设置),再绘制覆盖画布的图像,并缩小画布的宽高属性来放大画布内容:

5.1 插件脚本

/** @file mosaic.js **/

class Mosaic {
    constructor(url, container, options = {}) {
        if (typeof container === &#39;string&#39;) {
            container = document.querySelector(container);
        }

        if (!url || !container?.style) {
            console.error(&#39;参数不正确&#39;);
        }

        this.url = url;
        this.options = options;
        this.container = container;

        this.init();
    }
    init() {
        const img = new Image();
        const canvas = document.createElement(&#39;canvas&#39;);
        canvas.style.position = &#39;absolute&#39;;
        canvas.style.zIndex = 999;
        canvas.style.imageRendering = &#39;pixelated&#39;;
        this.img = img;
        this.canvas = canvas;
        this.ctx = canvas.getContext(&#39;2d&#39;);
        const containerBoundingRect = this.container.getBoundingClientRect();
        const container_w = containerBoundingRect.width;
        const container_h = containerBoundingRect.height;

        // 通过样式初始化画布尺寸为容器尺寸
        canvas.style.width = container_w + &#39;px&#39;;
        canvas.style.height = container_h + &#39;px&#39;;

        img.onload = () => {
            this.run(container_w, container_h);
        }

        img.src = this.url;
    }
    run(w, h) {
        // 缩小倍数,可以由参数传入,默认为 12
        const compressTimes = parseInt(this.options.compressTimes) || 12;
        let compress_w = parseInt(w / compressTimes);
        let compress_h = parseInt(h / compressTimes);
        // 修改画布尺寸属性为 1/缩小倍数
        this.canvas.width = compress_w;
        this.canvas.height = compress_h;
        // 绘制图片覆盖缩小后的画布
        this.ctx.drawImage(this.img, 0, 0, compress_w, compress_h);
        this.container.prepend(this.canvas);
        this.img = null;
    }
    remove() {
        this.container.removeChild(this.canvas);
        this.canvas = null;
    }
}

export default Mosaic;

5.2 插件使用页

/** @file plugin-demo.html **/
<head>
  <style>
    ul {
      list-style: none;
      margin: 0;
      padding: 0;
    }

    li {
      float: left;
      line-height: 0;
      margin: 0 20px 20px 0;
    }

    li>img {
      max-height: 180px;
    }

    div {
      display: block;
      clear: both;
    }
  </style>
</head>

<body>
  <ul>
    <li><img  src="./assert/0.png" / alt="CSS を使用して画像モザイクの様式化を実現する方法を見てみましょう。" ></li>
    <li><img  src="./assert/1.png" / alt="CSS を使用して画像モザイクの様式化を実現する方法を見てみましょう。" ></li>
    <li><img  src="./assert/2.png" / alt="CSS を使用して画像モザイクの様式化を実現する方法を見てみましょう。" ></li>
    <li><img  src="./assert/3.png" / alt="CSS を使用して画像モザイクの様式化を実現する方法を見てみましょう。" ></li>
  </ul>
  <div>
    <button id="generate">铺上马赛克</button>
    <button id="remove">移除马赛克</button>
  </div>


  <script type="module">
    import Mosaic from &#39;./mosaic.js&#39;;

    let liElems = document.querySelectorAll(&#39;li&#39;);
    let mosaicList = [];

    document.querySelector(&#39;#generate&#39;).onclick = () => {
      remove();
      for (let i = 0; i < liElems.length; i++) {
        let liElem = liElems[i];
        let url = liElem.querySelector(&#39;img&#39;).src;
        let mosaic = new Mosaic(url, liElem);
        mosaicList.push(mosaic);
      }
    }

    function remove() {
      mosaicList.forEach((mosaic) => {
        mosaic.remove();
      });
      mosaicList.length = 0;
    }

    document.querySelector(&#39;#remove&#39;).onclick = remove;

  </script>
</body>

执行效果:

CSS を使用して画像モザイクの様式化を実現する方法を見てみましょう。

点击“铺上”或“移除”按钮,可以轻松实现/移除列表上各图片的像素风格化。

六、兼容性

image-rendering 的兼容性可以从 caniuse 上查到,目前覆盖率如下:

CSS を使用して画像モザイクの様式化を実現する方法を見てみましょう。

影响较大的主要还是在 IE、UC,以及安卓 4.4.4 版本的浏览器,需要酌情考虑是否在产品上使用此 CSS 特性。


以上便是本文全部内容,相关代码可以在 Github 上获取(地址:https://github.com/VaJoy/BlogDemo3/tree/main/220226-pixelated)。

希望能令你有所收获,共勉~

(学習ビデオ共有: Web フロントエンド入門チュートリアル )

以上がCSS を使用して画像モザイクの様式化を実現する方法を見てみましょう。の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はjuejin.cnで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。