css - 如何将 SVG(或 CSS)中的图像转换为非平行四边形形状?

标签 css image svg transform

我希望能够创建一个 SVG,它在背景中有一个(正常)图像,在某个地方有一个不同的较小图像,它的 4 个“边缘”移动以创建一个非矩形形状。类似于扭曲图像以创建透视图。

在 SVG 中可以吗?如果不是,是否有可能在 CSS 中以一种在页面的非固定元素中可见的方式?

我发现了一些 CSS 透视图,但它使用了 X、Y、Z,当我真的只需要在预定义的非平行边“盒子”中调整(扭曲)图像时。

最佳答案

从理论上讲,有一种方法可以使用 SVG 1.1 创建您需要的失真类型。它依赖于 <feDisplacementMap> filter element .

如果您想探索它,我在下面提供了示例代码。但是,除了好奇之外,我不会推荐它。根据我的测试,该代码目前仅在 Chrome(以及可能相关的浏览器)中给出了预期的结果。 Internet Explorer 会扭曲图像,但略有不同。实际上,我让它在 I.E. 中使用略有不同的代码,但在 Chrome 中却没有。 Firefox 不支持使用 <feImage>过滤元素以从 SVG 导入片段,因此测试用例失败;如果您将 map 渐变创建为单独的图像文件,它应该可以工作。渲染质量也很差,因为您使用像素操作扭曲了图像。

linearGradient {
  color-interpolation:linearRGB;
}
<svg height="400px" width="400px">
  <defs>
    <linearGradient id="red-grad" x2="0" y2="100%">
      <stop offset="0" stop-color="#F00" />
      <stop offset="1" stop-color="#000" />
    </linearGradient>
    <linearGradient id="mask-grad" x2="100%" y2="0">
      <stop offset="0" stop-opacity="0" stop-color="white" />
      <stop offset="1" stop-opacity="1" stop-color="white" />
    </linearGradient>
    
    <mask id="mask">
      <rect fill="url(#mask-grad)" 
            height="100%" width="100%"/>
    </mask>
    <rect id="red-rect" fill="url(#red-grad)" mask="url(#mask)"
          height="100%" width="100%"/>
    
    <filter id="perspective" primitiveUnits="objectBoundingBox"
            x="-50%" y="-50%" width="200%" height="200%">
      <feImage xlink:href="#red-rect" result="red" />
      <feFlood flood-color="black" result="black" />
      <feComposite operator="over" in="red" in2="black" 
                   result="map"/>
      <feDisplacementMap in="SourceGraphic" in2="map"
                         yChannelSelector="R"
                         xChannelSelector="G"
                         scale="1.1" />
    </filter>
  </defs>
<g style="opacity:0.5">
  <image id="pic" height="100%" width="100%" xlink:href="http://upload.wikimedia.org/wikipedia/commons/thumb/2/24/Iglesia_de_Santiago_Tlatelolco%2C_M%C3%A9xico_D.F.%2C_M%C3%A9xico%2C_2013-10-16%2C_DD_38.JPG/320px-Iglesia_de_Santiago_Tlatelolco%2C_M%C3%A9xico_D.F.%2C_M%C3%A9xico%2C_2013-10-16%2C_DD_38.JPG"
  />
</g>
<g transform="scale(0.7 0.5)skewY(4)">
  <use y="25%" xlink:href="#pic" filter="url(#perspective)" />
</g>
</svg>
<p>Image by <a href="http://commons.wikimedia.org/wiki/File:Iglesia_de_Santiago_Tlatelolco,_M%C3%A9xico_D.F.,_M%C3%A9xico,_2013-10-16,_DD_38.JPG">Diego Dielso, via Wikimedia Commons.</a></p>

相反,正如 Robert Longson 在评论中建议的那样,最好的方法是使用 3D transforms来营造透视效果。大多数浏览器(最新版本)现在支持对 HTML 图像进行 3D 转换,尽管您需要使用 -webkit- 前缀复制声明。

如果您在 CSS 代码中声明,许多浏览器(IE 除外)也将支持 SVG 元素的 3D 转换。然而,transform-origin SVG 不支持属性;最好保留默认值(SVG 坐标系原点,与 SVG1.1 变换相同),并使用其他变换来获得您想要的效果。


片段的解释,对于那些好奇的人:

  1. 两个渐变、 mask 、矩形和前三个滤镜元素都只是创建二维黑色到红色渐变(右上角为红色,左侧和底部为黑色。这就是 IE 的问题所在——不同元素的大小不正确,所以大部分图像最终都是黑色的。我必须将 color-interpolation 属性设置为 linearRGB,以便红色 channel 的值平滑增加基于数值,而不是进行 Gamma 校正。如上所述,您可以将 map 渐变创建为单独的图像文件,并将其导入到具有单个 <feImage> 元素的滤镜中,然后 Firefox 也支持该效果.

  2. feDisplacementMap过滤器元素获取 in 中的每个像素图形,并根据in2中对应像素的颜色值进行移动图形(黑色和红色渐变)。 y 位移设置为使用贴图的红色值,而 x 位移使用绿色值(对于整个红黑渐变将为零)。

  3. 第一个图像元素是半透明背景。

  4. 此图像随后被复制到 <use> 中元素,并应用过滤器。一组额外的变换用于缩放图像并调整整体倾斜(倾斜),以便透视失真看起来相当居中。

关于css - 如何将 SVG(或 CSS)中的图像转换为非平行四边形形状?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27108793/

相关文章:

java - 如何将 Java 字符串插入到 HTML 表格中

html - 为什么没有显式宽度的表格单元格样式元素不会拉伸(stretch)以填充表格/表格行样式父项的剩余宽度?

image - Photoshop Action 对图像进行一定比例的填充

image - ffmpeg 转换图像<->视频会导致伪影

Java:ImageIcon - 图像文件更新,但 Java 框架中的图像图标不更新

xaml - 在 Windows Forms/WPF 中使用 SVG 的库?

html - 如何并排放置 svg 和按钮并垂直对齐它们?

javascript - d3 选择 .attr ('x1' ) 返回 r.getAttribute 不是函数

html - 我怎样才能底部对齐一个可以增长的 div 并导致它的容器滚动

html - 使 float 元素保持其位置