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

时间:2014-11-24 15:53:13

标签: css image svg transform

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

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

我找到了一些CSS透视图,但它使用了X,Y,Z,当我真的只需要在预定义的非平行边框“框”中拟合(扭曲)图像。

1 个答案:

答案 0 :(得分:1)

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

如果您想要浏览它,我会在下面提供示例代码。但是,除了好奇之外,我不会推荐它。从我的测试来看,代码目前只在Chrome(可能还有相关的浏览器)中提供了所需的结果。 Internet Explorer会扭曲图像,但略有不同。实际上我在I.E.中使用稍微不同的代码,但在Chrome中没有。 Firefox不支持使用<feImage>过滤器元素从SVG导入片段,因此测试用例失败;如果您将地图渐变创建为单独的图像文件,它应该可以工作。还有简单的渲染质量,因为你使用像素操作扭曲了图像。

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代码中声明它们,许多浏览器(I.E.是例外)也将支持SVG元素的3D变换。但是,SVG不支持transform-origin属性;最好将其保留为默认值(SVG坐标系原点,与SVG1.1变换相同),并使用其他变换来获得所需的效果。


对于那些好奇的人说明摘要:

  1. 两个渐变,蒙版,矩形和前三个滤镜元素都只是一种创建二维黑色到红色渐变的方法(右上角为红色,左侧和下方为黑色)。这就是IE存在问题的地方 - 不同的元素尺寸不正确,因此大部分图像都是黑色的。我必须将color-interpolation属性设置为linearRGB,以便红色通道根据数值平滑增加,而不是经过伽马校正。如上所述,您可以将地图渐变创建为单独的图像文件,并使用单个<feImage>元素将其导入过滤器,然后Firefox也会支持这种效果。

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

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

  4. 然后将此图像复制到<use>元素中,并应用过滤器。另外一组变换用于缩放图像并调整整体倾斜(倾斜),使透视变形看起来相当居中。