Skip to content

文字适应纹理

作者:Yuan Tang
更新于:5 个月前
字数统计:1.1k 字
阅读时长:4 分钟

目前有一个需求,需要文字适应背景图片的纹理,且能实现文字内容颜色自定义转换的功能。

咋一看该功能不好实现,一般情况下可以找设计师给 UI 图,但是无法适配纹理。因此还是需要回到前端自己实现,不过可以参考一下UI的实现思路——滤镜。

前端的滤镜第一时间先考虑到 filter ,但是找遍 filter 所有属性值都无法实现。因此继续往下思考,想到了 SVG 的滤镜。

SVG的滤镜效果更强大,可以说 CSS 的 filter 滤镜是 SVG 滤镜的子集,尝试一下。

SVG滤镜

首先写一个 svg 标签,标签内放置一个图片 image 和一个文本 text ,代码如下:

html
<svg viewBox="0 0 600 330">
    <Image
       href="./cat.png"
       x="0"
       y="0"
       width="100%"
       height="100%"
       preserveAspectRatio="none">
   </Image>
   <text
       x="50%"
       y="50%"
       font-size="10em"
       font-weight="bold"
       text-anchor="middle"
       alignment-baseline="middle"
       fill="#000">
     Logo
   </text>
</svg>

其中设置了图片标签的 x 轴和 y 轴位置、宽高缩放设置,设置了文本的 x 轴和 y 轴位置、字体大小和粗细、横轴纵轴对齐方式、字体颜色。

现在需要添加纹理,由于是让文字适配背景,因此要给文字添加滤镜。滤镜添加在 svg 内,通过 defsfilter 标签实现,为 filter 设置唯一值 id ,然后为 text 绑定。代码如下:

html
<svg viewBox="0 0 600 330">
    <defs> 
       <filter id="conform"></filter> 
    </defs> 
    <Image
       href="./cat.png"
       x="0"
       y="0"
       width="100%"
       height="100%"
       preserveAspectRatio="none">
   </Image>
   <text
       x="50%"
       y="50%"
       font-size="10em"
       font-weight="bold"
       text-anchor="middle"
       alignment-baseline="middle"
       fill="#000"
       filter="url(#conform)"> 
     Logo
   </text>
</svg>

现在刷新页面后文本内容不见了,这是必然的,因为 filter 内没设置任何东西,所以无效果,后续一步步来。

文字效果

首先,想要实现文字适配图片纹理,首先得要有一个图片滤镜,设置图片的路径以及其 x 轴和 y 轴起始坐标。最后通过 result 导出一个名称 ORIGIN_IMAGE 给后续的滤镜使用。

html
<feImage href="./cat.png"
    result="ORIGIN_IMAGE"
    x="0"
    y="0"
    width="100%"
    height="100%"
    preserveAspectRatio="none">
</feImage>

然后图片不需要太多颜色,设置为灰度图,通过 in 引入上一个滤镜的名称,再通过 result 导出名称 GRAY_IMAGE 给下一个滤镜使用。

html
<feColorMatrix in="ORIGIN_IMAGE"
    type="saturate"
    values="0"
    result="GRAY_IMAGE">
</feColorMatrix>

接着为文字设置置换滤镜,其本质就是改变文本里的每一个像素点。 in 引入原始图像 SourceGraphic (也就是 text 文本)和灰度图像 GRAY_IMAGE ,以灰度图作为参考,通过一个算法来实现偏移。该算法用大白话来说就是当参考点越黑,他就越往右下偏移;参考点越白他就越往左上偏移;不黑不白则不偏移。再通过 result 导出名称 TEXTURED_TEXT 给下一个滤镜使用。

html
<feDisplacementMap in="SourceGraphic"
     in2="GRAY_IMAGE"
     scale="15"
     xChannelSelector="R"
     yChannelSelector="R"
     result="TEXTURED_TEXT">
</feDisplacementMap>

紧接着要让文字和图片纹理贴合,需要 in 引入 TEXTURED_TEXT 把图像在写一遍,让图像和文本融合。再通过 result 导出名称 BG 给下一个滤镜使用。

html
<feImage href="./cat.png"
    in="TEXTURED_TEXT"
    x="0"
    y="0"
    width="100%"
    height="100%"
    preserveAspectRatio="none"
    result="BG">
</feImage>

再然后为滤镜添加不透明度,导出名称 OPACITY_TEXT

html
<feColorMatrix in="TEXTURED_TEXT"
   type="matrix"
   values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 9 0"
   result="OPACITY_TEXT">
</feColorMatrix>

最后得到不透明度的背景和融合成功的文本,把二者结合起来即可。

html
<feBlend in="BG"
   in2="OPACITY_TEXT"
   mode="multiply"
   result="BLENDED_TEXT">
</feBlend>

总体代码

html
<template>
    <svg viewBox="0 0 600 330">
        <defs>
            <filter id="conform">
                <feImage href="./cat.png"
                    result="ORIGIN_IMAGE"
                    x="0"
                    y="0"
                    width="100%"
                    height="100%"
                    preserveAspectRatio="none">
                </feImage>
                <feColorMatrix in="ORIGIN_IMAGE"
                    type="saturate"
                    values="0"
                    result="GRAY_IMAGE"></feColorMatrix>
                <feDisplacementMap in="SourceGraphic"
                    in2="GRAY_IMAGE"
                    scale="15"
                    xChannelSelector="R"
                    yChannelSelector="R"
                    result="TEXTURED_TEXT"></feDisplacementMap>
                <feImage href="./cat.png"
                    in="TEXTURED_TEXT"
                    x="0"
                    y="0"
                    width="100%"
                    height="100%"
                    preserveAspectRatio="none"
                    result="BG">
                </feImage>
                <feColorMatrix in="TEXTURED_TEXT"
                    type="matrix"
                    values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 9 0"
                    result="OPACITY_TEXT"></feColorMatrix>
                <feBlend in="BG"
                    in2="OPACITY_TEXT"
                    mode="multiply"
                    result="BLENDED_TEXT"></feBlend>
            </filter>
        </defs>
        <Image href="./cat.png"
            x="0"
            y="0"
            width="100%"
            height="100%"
            preserveAspectRatio="none">
        </Image>
        <text x="50%"
            y="50%"
            font-size="10em"
            font-weight="bold"
            text-anchor="middle"
            alignment-baseline="middle"
            fill="orange"
            filter="url(#conform)">
            Logo
        </text>
    </svg>
</template>

功能拓展

效果实现后,可以来点功能拓展,比如文本自定义、文本颜色自定义、背景图修改等。这些可以尝试一下。

Contributors

Yuan Tang