C# 透视效果

最近在写一款软件,其中一个功能就是透视,在网上搜索了很久,翻阅了很多资料。第一份资料呈现给我的就是【猴健居士】写的一篇关于【C# 图片自由变换 任意扭曲】,我很想去实现那种效果,只是才疏学浅,无法明白其思路,即使有贴出来了代码,我也没有做到,很惭愧。

而网上其他的方式多半是与【OpenCV】结合,这种很简单,却让我头大,这对于我来说无意是接触一种新的语言,奈何时间不会那么充裕。

最终我还是决定,以C#自身的情况,来实现这种效果,我自己是无法办到的,就想到了第一次看到的那个文章,的确是用C#语言写的。只是我无法还原,于是找到了这个朋友,希望他可以帮忙。

那朋友知道的来意后,帮了我,点出了我的问题,并告诉了这段代码的存在什么问题。我在得知后,很高兴,也很感谢,先能实现再说,具体有什么问题,在实现后,应该会逐步克服。

现在贴出我在得到代码后的变动。

1、之前代码会有黑色背景,我改动过避免了这种情况,毕竟有些图片带着透明效果的

2、在循环中增加了continue,可以缩短图片的转换时间,对于有透明效果的图片很明显。

3、代码了用了重载和函数,增加了使用型

4、去掉了一部分代码,我不知道那些代码会达到什么效果,只是在代码中意义不大,暂时放弃了。

图片效果如下

我用一个类Perspective 来实现完成透视的效果,代码如下:

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;

namespace ImageFile
{
    /// <summary>
    /// 透视
    /// </summary>
    public class Perspective
    {
        private int roundup(double a) { if (AafAbs(a - round(a)) < 1e-9) return round(a); else if ((int)a > a) return (int)a; else return (int)a + 1; }
        private int rounddown(double a) { if (AafAbs(a - round(a)) < 1e-9) return round(a); else if ((int)a < a) return (int)a; else return (int)a - 1; }
        private int round(double a) { return (int)(a + 0.5); }
        private byte byterange(double a) { int b = round(a); if (b <= 0) return 0; else if (b >= 255) return 255; else return (byte)b; }
        private double AafAbs(double a) { return (((a) < 0) ? (-(a)) : (a)); }
        private double aaf_min(double a, double b) { if (a < b) return a; else return b; }
        private double aaf_max(double a, double b) { if (a > b) return a; else return b; }

private AafPnt[] pixelgrid;
        private AafPnt[] polyoverlap;
        private AafPnt[] polysorted;
        private AafPnt[] corners;

private int outstartx;
        private int outstarty;
        private int outwidth;
        private int outheight;

private Bitmap prepImg;
        private List<double> xDouList;
        private List<double> yDouList;

int polyoverlapsize;
        int polysortedsize;

int[] ja = new int[] { 1, 2, 3, 0 };

public Perspective() {
       
        }

public Perspective(double[] xcorner, double[] ycorner)
        {
            xDouList = xcorner.ToList();
            yDouList = ycorner.ToList();
        }
        public Perspective(Bitmap src,double[] xcorner, double[] ycorner)
        {
            prepImg = src;
            xDouList = xcorner.ToList();
            yDouList = ycorner.ToList();
        }
        public Bitmap CreateTransform()
        {
            return CreateTransform(prepImg);
        }

public Bitmap CreateTransform(Bitmap src)
        {
            return CreateTransform(src, xDouList, yDouList);
        }

public Bitmap CreateTransform(Bitmap src, List<double> xcorner, List<double> ycorner)
        {
            int right = 0, bottom = 0;

//主要是根据新图片的坐标,计算出图片的宽和高,构造目标图片的Bitmap的
            double offx = xcorner[0];
            double offy = ycorner[0];
            for (int i = 1; i < 4; i++)
            {
                if (xcorner[i] < offx) offx = xcorner[i];
                if (ycorner[i] < offy) offy = ycorner[i];
            }

for (int i = 0; i < 4; i++)
            {
                xcorner[i] -= offx;
                ycorner[i] -= offy;
                if (roundup(xcorner[i]) > right) right = roundup(xcorner[i]);
                if (roundup(ycorner[i]) > bottom) bottom = roundup(ycorner[i]);
            }
            Bitmap dst = new Bitmap(right, bottom);
            Transform(src, dst, xcorner, ycorner);
            return dst;
        }

private void Transform(Bitmap src, Bitmap dst, List<double> xcorner, List<double> ycorner)
        {
            //Make sure the coordinates are valid
            if (xcorner.Count != 4 || ycorner.Count != 4) {
                return;
            }
            //Load the src bitmaps information
            //create the intial arrays
            //根据原图片生成一个比原图宽高多一个单位的图片,
            //这个矩阵就是用来记录转换后各个像素点左上角的坐标
            pixelgrid = new AafPnt[(src.Width + 1) * (src.Height + 1)];
            polyoverlap = new AafPnt[16];
            polysorted = new AafPnt[16];
            corners = new AafPnt[4];

//Load the corners array
            double[] dx = { 0.0, 1.0, 1.0, 0.0 };
            double[] dy = { 0.0, 0.0, 1.0, 1.0 };
            for (int i = 0; i < 4; i++)
            {
                corners[i].x = dx[i];
                corners[i].y = dy[i];
            }

//Find the rectangle of dst to draw to
            outstartx = rounddown(xcorner[0]);
            outstarty = rounddown(ycorner[0]);
            outwidth = 0;
            outheight = 0;
            //这里计算出变换后起始点的坐标
            for (int i = 1; i < 4; i++)
            {
                if (rounddown(xcorner[i]) < outstartx) outstartx = rounddown(xcorner[i]);
                if (rounddown(ycorner[i]) < outstarty) outstarty = rounddown(ycorner[i]);
            }
            for (int i = 0; i < 4; i++)
            {
                if (roundup(xcorner[i] - outstartx) > outwidth) outwidth = roundup(xcorner[i] - outstartx);
                if (roundup(ycorner[i] - outstarty) > outheight) outheight = roundup(ycorner[i] - outstarty);
            }

//fill out pixelgrid array
            //计算出理想目标图片中各个“像素格”中的左上角的坐标
            if (CreateGrid(src, xcorner, ycorner))
            {
                //Do the transformation
                //进行转换
                DoTransform(src, dst);
            }
        }

private bool CreateGrid(Bitmap src, List<double> xcorner, List<double> ycorner)
        {
            //mmm geometry
            double[] sideradius = new double[4];
            double[] sidecos = new double[4];
            double[] sidesin = new double[4];

//First we find the radius, cos, and sin of each side of the polygon created by xcorner and ycorner
            int j;
            for (int i = 0; i < 4; i++)
            {
                j = ja[i];
                sideradius[i] = Math.Sqrt((xcorner[i] - xcorner[j]) * (xcorner[i] - xcorner[j]) + (ycorner[i] - ycorner[j]) * (ycorner[i] - ycorner[j]));
                sidecos[i] = (xcorner[j] - xcorner[i]) / sideradius[i];
                sidesin[i] = (ycorner[j] - ycorner[i]) / sideradius[i];
            }

//Next we create two lines in Ax + By = C form
            for (int x = 0; x < src.Width + 1; x++)
            {
                double topdist = ((double)x / (src.Width)) * sideradius[0];//每个像素点变换后的坐标点
                double ptxtop = xcorner[0] + topdist * sidecos[0];
                double ptytop = ycorner[0] + topdist * sidesin[0];

double botdist = (1.0 - (double)x / (src.Width)) * sideradius[2];
                double ptxbot = xcorner[2] + botdist * sidecos[2];
                double ptybot = ycorner[2] + botdist * sidesin[2];

double Ah = ptybot - ptytop;
                double Bh = ptxtop - ptxbot;
                double Ch = Ah * ptxtop + Bh * ptytop;//叉乘

for (int y = 0; y < src.Height + 1; y++)
                {
                    double leftdist = (1.0 - (double)y / (src.Height)) * sideradius[3];
                    double ptxleft = xcorner[3] + leftdist * sidecos[3];
                    double ptyleft = ycorner[3] + leftdist * sidesin[3];

double rightdist = ((double)y / (src.Height)) * sideradius[1];
                    double ptxright = xcorner[1] + rightdist * sidecos[1];
                    double ptyright = ycorner[1] + rightdist * sidesin[1];

double Av = ptyright - ptyleft;
                    double Bv = ptxleft - ptxright;
                    double Cv = Av * ptxleft + Bv * ptyleft;

//Find where the lines intersect and store that point in the pixelgrid array
                    double det = Ah * Bv - Av * Bh;
                    if (AafAbs(det) < 1e-9)
                    {
                        return false;
                    }
                    else
                    {
                        int ind = x + y * (src.Width + 1);
                        pixelgrid[ind].x = (Bv * Ch - Bh * Cv) / det;
                        pixelgrid[ind].y = (Ah * Cv - Av * Ch) / det;
                    }
                }
            }
            //Yayy we didn‘t fail
            return true;
        }

private void DoTransform(Bitmap src, Bitmap dst)
        {

//Get source bitmap‘s information
            if (src == null) return;

//Create the source dib array and the dstdib array
            aaf_dblrgbquad[] dbldstdib = new aaf_dblrgbquad[outwidth * outheight];
            for (int i = 0; i < dbldstdib.Length; i++)
                dbldstdib[i] = new aaf_dblrgbquad();

//Create polygon arrays
            AafPnt[] p = new AafPnt[4];
            AafPnt[] poffset = new AafPnt[4];
            //Loop through the source‘s pixels
            //遍历原图(实质上是pixelgrid)各个点
            for (int x = 0; x < src.Width; x++)
            {
                for (int y = 0; y < src.Height; y++)
                {
                    //取当前点 下一点 右一点 斜右下角点 四点才组成一个四边形
                    //这个四边形是原图像的一个像素点
                    //Construct the source pixel‘s rotated polygon from pixelgrid
                    p[0] = pixelgrid[x + y * (src.Width + 1)];
                    p[1] = pixelgrid[(x + 1) + y * (src.Width + 1)];
                    p[2] = pixelgrid[(x + 1) + (y + 1) * (src.Width + 1)];
                    p[3] = pixelgrid[x + (y + 1) * (src.Width + 1)];

//Find the scan area on the destination‘s pixels
                    int mindx = int.MaxValue;
                    int mindy = int.MaxValue;
                    int maxdx = int.MinValue;
                    int maxdy = int.MinValue;
                    for (int i = 0; i < 4; i++)
                    {
                        if (rounddown(p[i].x) < mindx) mindx = rounddown(p[i].x);
                        if (roundup(p[i].x) > maxdx) maxdx = roundup(p[i].x);
                        if (rounddown(p[i].y) < mindy) mindy = rounddown(p[i].y);
                        if (roundup(p[i].y) > maxdy) maxdy = roundup(p[i].y);
                    }

int SrcIndex = x + y * src.Width;
                    //遍历四边形包含了目标图几个像素点
                    //按照相交面积占整个像素的的百分比,把颜色按照该比例存放一个目标像素点颜色的数组中
                    //这里计算出来的颜色只是初步颜色,还没到最终结果
                    //loop through the scan area to find where source(x, y) overlaps with the destination pixels
                    for (int xx = mindx - 1; xx <= maxdx; xx++)
                    {
                        if (xx < 0 || xx >= dst.Width)
                            continue;
                        for (int yy = mindy - 1; yy <= maxdy; yy++)
                        {
                            if (yy < 0 || yy >= dst.Height)
                                continue;

//offset p and by (xx,yy) and put that into poffset
                            for (int i = 0; i < 4; i++)
                            {
                                poffset[i].x = p[i].x - xx;
                                poffset[i].y = p[i].y - yy;
                            }

//FIND THE OVERLAP *a whole lot of code pays off here*
                            //这里则是计算出覆盖了面积占当前像素的百分比
                            double dbloverlap = PixOverlap(poffset);
                            //按照百分比来为目标像素点累加颜色
                            //因为一个目标像素点有可能有几个原来像素的覆盖了
                            if (dbloverlap > 0)
                            {
                                int dstindex = xx + yy * outwidth;
                                int srcWidth = src.Width;
                                Color srcColor = new Color();
                                if (SrcIndex == 0)
                                {
                                    srcColor = src.GetPixel(0, 0);
                                }
                                else
                                {
                                    srcColor = src.GetPixel(SrcIndex % src.Width, SrcIndex / src.Width);
                                }
                                if (srcColor.Name != "0")
                                {
                                    //Add the rgb and alpha values in proportion to the overlap area
                                    dbldstdib[dstindex].Red += (double)((srcColor.R) * dbloverlap);
                                    dbldstdib[dstindex].Blue += (double)(srcColor.B) * dbloverlap;
                                    dbldstdib[dstindex].Green += (double)(srcColor.G) * dbloverlap;
                                    dbldstdib[dstindex].Alpha += dbloverlap;
                                }
                                else
                                {
                                    continue;
                                }
                            }
                            else {
                                continue;
                            }
                        }
                    }
                }
            }
            //Free memory no longer needed
            //Create final destination bits
            Color c = new Color();
            //这里是实际上真正像素点的颜色,并且填到了目标图片中去
            //Write to dstdib with the information stored in dbldstdib
            for (int x = 0; x < outwidth; x++)
            {
                if (x + outstartx >= dst.Width)
                    continue;
                for (int y = 0; y < outheight; y++)
                {
                    if (y + outstarty >= dst.Height) {
                        continue;
                    }
                       
                    int offindex = x + y * outwidth;
                    int dstindex = x + outstartx + (y + outstarty) * dst.Width;

int dstIndexX = dstindex / dst.Width;
                    int dstIndexY = dstindex % dst.Width;
                    if (dbldstdib[offindex].Alpha==0)
                    {
                        continue;
                    }
                    else{
                       
                        if (dbldstdib[offindex].Alpha > 1)
                        {
                            //handles wrap around for non-convex transformations
                            c = Color.FromArgb(byterange(dbldstdib[offindex].Red / dbldstdib[offindex].Alpha), byterange(dbldstdib[offindex].Green / dbldstdib[offindex].Alpha), byterange(dbldstdib[offindex].Blue / dbldstdib[offindex].Alpha));
                        }
                        else
                        {
                            //Color dstColor = dst.GetPixel(dstIndexX, dstIndexY);
                            c = Color.FromArgb(byterange(dbldstdib[offindex].Red + (1 - dbldstdib[offindex].Alpha) * c.R), byterange(dbldstdib[offindex].Green + (1 - dbldstdib[offindex].Alpha) * c.G), byterange(dbldstdib[offindex].Blue + (1 - dbldstdib[offindex].Alpha) * c.B));
                        }
                    }
                   
                    dst.SetPixel(dstIndexY, dstIndexX, c);
                }
            }
        }

double PixOverlap(AafPnt[] p)
        {
            polyoverlapsize = 0;
            polysortedsize = 0;

double minx, maxx, miny, maxy;
            int j;

double z;

for (int i = 0; i < 4; i++)
            {
                //Search for source points within the destination quadrolateral
                if (p[i].x >= 0 && p[i].x <= 1 && p[i].y >= 0 && p[i].y <= 1)
                    polyoverlap[polyoverlapsize++] = p[i];

//Search for destination points within the source quadrolateral
                if (PtinConvexPolygon(p, corners[i]))
                    polyoverlap[polyoverlapsize++] = corners[i];

//Search for line intersections
                j = ja[i];
                minx = aaf_min(p[i].x, p[j].x);
                miny = aaf_min(p[i].y, p[j].y);
                maxx = aaf_max(p[i].x, p[j].x);
                maxy = aaf_max(p[i].y, p[j].y);

if (minx < 0.0 && 0.0 < maxx)
                {//Cross left
                    z = p[i].y - p[i].x * (p[i].y - p[j].y) / (p[i].x - p[j].x);
                    if (z >= 0.0 && z <= 1.0)
                    {
                        polyoverlap[polyoverlapsize].x = 0.0;
                        polyoverlap[polyoverlapsize++].y = z;
                    }
                }
                if (minx < 1.0 && 1.0 < maxx)
                {//Cross right
                    z = p[i].y + (1 - p[i].x) * (p[i].y - p[j].y) / (p[i].x - p[j].x);
                    if (z >= 0.0 && z <= 1.0)
                    {
                        polyoverlap[polyoverlapsize].x = 1.0;
                        polyoverlap[polyoverlapsize++].y = z;
                    }
                }
                if (miny < 0.0 && 0.0 < maxy)
                {//Cross bottom
                    z = p[i].x - p[i].y * (p[i].x - p[j].x) / (p[i].y - p[j].y);
                    if (z >= 0.0 && z <= 1.0)
                    {
                        polyoverlap[polyoverlapsize].x = z;
                        polyoverlap[polyoverlapsize++].y = 0.0;
                    }
                }
                if (miny < 1.0 && 1.0 < maxy)
                {//Cross top
                    z = p[i].x + (1 - p[i].y) * (p[i].x - p[j].x) / (p[i].y - p[j].y);
                    if (z >= 0.0 && z <= 1.0)
                    {
                        polyoverlap[polyoverlapsize].x = z;
                        polyoverlap[polyoverlapsize++].y = 1.0;
                    }
                }
            }

//Sort the points and return the area
            SortPoints();
            return Area();
        }

private double Area()
        {
            double ret = 0.0;
            //Loop through each triangle with respect to (0, 0) and add the cross multiplication
            for (int i = 0; i + 1 < polysortedsize; i++)
                ret += polysorted[i].x * polysorted[i + 1].y - polysorted[i + 1].x * polysorted[i].y;
            //Take the absolute value over 2
            return AafAbs(ret) / 2.0;
        }

private void SortPoints()
        {
            //Why even bother?
            if (polyoverlapsize < 3)
                return;

//polyoverlap is a triangle, points cannot be out of order
            if (polyoverlapsize == 3)
            {
                polysortedsize = polyoverlapsize - 1;
                polysorted[0].x = polyoverlap[1].x - polyoverlap[0].x;
                polysorted[0].y = polyoverlap[1].y - polyoverlap[0].y;
                polysorted[1].x = polyoverlap[2].x - polyoverlap[0].x;
                polysorted[1].y = polyoverlap[2].y - polyoverlap[0].y;
                return;
            }

aaf_indll root = new aaf_indll();
            root.next = null;

//begin sorting the points.  Note that the first element is left out and all other elements are offset by it‘s values
            for (int i = 1; i < polyoverlapsize; i++)
            {
                polyoverlap[i].x = polyoverlap[i].x - polyoverlap[0].x;
                polyoverlap[i].y = polyoverlap[i].y - polyoverlap[0].y;

aaf_indll node = root;
                //Loop until the point polyoverlap[i] is can be sorted (counter) clockwiswe (I‘m not sure which way it‘s sorted)
                while (true)
                {
                    if (node.next != null)
                    {
                        if (polyoverlap[i].x * polyoverlap[node.next.ind].y - polyoverlap[node.next.ind].x * polyoverlap[i].y < 0)
                        {
                            //Insert point before this element
                            aaf_indll temp = node.next;
                            node.next = new aaf_indll();
                            node.next.ind = i;
                            node.next.next = temp;
                            break;
                        }
                    }
                    else
                    {
                        //Add point to the end of list
                        node.next = new aaf_indll();
                        node.next.ind = i;
                        node.next.next = null;
                        break;
                    }
                    node = node.next;
                }
            }

//We can leave out the first point because it‘s offset position is going to be (0, 0)
            polysortedsize = 0;

aaf_indll node2 = root;
            aaf_indll temp2;

//Add the sorted points to polysorted and clean up memory
            while (node2 != null)
            {
                temp2 = node2;
                node2 = node2.next;
                if (node2 != null)
                    polysorted[polysortedsize++] = polyoverlap[node2.ind];

}
        }

private bool PtinConvexPolygon(AafPnt[] p, AafPnt pt)
        {
            int dir = 0;
            int j;

//Basically what we are doing is seeing if pt is on the same side of each face of the polygon through cross multiplication
            for (int i = 0; i < 4; i++)
            {
                j = ja[i];
                double cross = (p[i].x - pt.x) * (p[j].y - pt.y) - (p[j].x - pt.x) * (p[i].y - pt.y);

if (cross == 0)
                    continue;

if (cross > 0)
                {
                    if (dir == -1)
                        return false;

dir = 1;
                }
                else
                {
                    if (dir == 1)
                        return false;

dir = -1;
                }
            }
            return true;
        }
    }

public delegate bool Aaf_callback(double paraDouble);

struct AafPnt
    {
        public double x, y;
        public AafPnt(double x, double y)
        {
            this.x = x < 0 ? 0 : x;
            this.y = y < 0 ? 0 : y;
        }
    }

class aaf_dblrgbquad
    {
        public double Red { get; set; }
        public double Green { get; set; }
        public double Blue { get; set; }
        public double Alpha { get; set; }
    }
    class aaf_indll
    {
        public aaf_indll next;
        public int ind;
    }
}

这里是调用代码,参数xcorner和ycorner  对应的是矩形4个角的坐标,按顺序是左上、右上、右下、左下。

/// <summary>
        /// 透视
        /// 2016-12-15
        /// </summary>
        /// <param name="p_Bitmap"></param>
        /// <param name="xcorner"></param>
        /// <param name="ycorner"></param>
        /// <returns></returns>
        public static Bitmap PrepImage(Bitmap p_Bitmap, double[] xcorner, double[] ycorner)
        {
            Perspective pimg = new Perspective(p_Bitmap, xcorner, ycorner);
            return pimg.CreateTransform();
        }

如果在窗体上直接打印,记得加上 下面这句代码

g.Clear(this.BackColor);

目前代码优化到此,不排除我还会继续优化,之后会再贴出来与大家分享!也很感谢猴健居士

时间: 2024-08-01 07:39:41

C# 透视效果的相关文章

弹性菜单 加了 透视效果 运动 小案例

/**弹性菜单 加了透视效果,类似滚动歌词的效果 *运动过程中,背景色和颜色都会改变,实现原理见 滚动歌词篇 * 小bug 当设置字体为 微软雅黑时,运动过程中菜单中的字体会有小抖动,修复方法,left值不能直接赋值,先存起来**/ 1 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" 2 "http://www.w3.org/TR/html4/strict.dtd"> 3 4 <html xmln

Windows Phone开发(19):三维透视效果

三维效果也可以叫透视效果,所以,我干脆叫三维透视效果.理论知识少讲,直接用例开场吧,因为这个三维效果其实很简单,比上一节中的变换更省事,不信?一起来做一做练习吧. 练习一:把对象沿Y轴旋转45度. 默认情况下,旋转中心都是在中心位置上,如Y轴中心.而至于旋转的角度,哪个方向是正值,哪个方向是负值,嘿,你自己动手试一下就知道了,我相信你能理解的,不然,Hello Kitty嘲笑你的. 好的,由于是第一个练习,我们先来说说X.Y.Z三个坐标轴到底在哪,X轴不用说了,就横着放的那个了,Y轴呢,当然是竖

【Win 10 应用开发】透视效果

所谓透视效果,就是在平面坐标空间上模拟出“好像”三维的效果.要是老周没有记错的话,以前在写WP8相关的内容时写过,UWP中的透视方法也保留了以前的Do法,其实这玩意儿是从 Silverlight 沿袭下来的.不过,UWP添加了一些三维变换相关的东东,这个老周以后会跟大伙儿聊,今天咱们还是先了解透视效果. UiElement这个可视化对象的公共基类公开了一个Projection属性,可以用于设置对象的透视参数,它的类型是 Projection,可是,Projection 是抽象类,是不能拿来用的,

【UWP通用应用开发】编辑文本、绘制图形、3D透视效果及绘制时钟实战

编辑文本及键盘输入 相信大家都会使用TextBox,但如果要让文本在TextBox中换行该怎么做呢?将TextWrapping属性设置为Wrap,将AcceptsReturn属性设置为True就好咯. PasswordBox很明显就是一个密码框了,和其他的控件相比其有2个特殊之处,一个是其可以用MaxLength来控制最大的长度,一个是用PasswordChanged来捕捉密码的改名.显然比如QQ密码的MaxLength就是16位了,而PasswordChanged可以用来监测比如用户设置的密码

XAML UI 的3D 透视效果

<StackPanel Margin="35" Background="Gray">         <StackPanel.Projection>             <PlaneProjection RotationX="-35" RotationY="-35" RotationZ="15"/>         </StackPanel.Projection

【转载】如何正确使用cnblogsCSS定制

转自:http://www.cnblogs.com/rvalue/p/7265386.html 用过cnblogs的估计都知道cnblogs提供了相对比较开放的个性化选项,其中最为突出的估计就是页面CSS定制了.但是没学过Web前端的人可能并不会用这个东西... 所以我打算在此分享一些定制CSS过程中使用的奇技淫巧一些方法来帮助大家定制blog qwq 以后如果想到新的主意或者更好的表述的话估计还会回来更新一波...本博文不定期更新吧w 博主并非专业Web开发,所以可能有些语言不够严谨或者不够准

CSS3略谈(中二)

一.3D转换:三维变换使用基于二维变换的相同属性,可以让我们基于三个坐标方向对元素进行变换.和二维变形一样,三维变形可以使用transform属性来设置 1. 3D移动 l   方法:translate3d(x,y,z) 使元素在这三个纬度中移动,也可以分开写,如:translateX(length),translateY(length), translateZ(length) l   示例: div:hover{ /*Y轴移动+100px*/ /*transform:translateY(10

使用CSS3实现一个3D相册

CSS3系列我已经写过两篇文章,感兴趣的同学可以先看一下CSS3初体验之奇技淫巧,CSS3 3D立方体效果-transform也不过如此 第一篇主要列出了一些常用或经典的CSS3技巧和方法:第二篇是一个用CSS3实现的立方体实例,详细讲解了3D旋转和transform等属性. 本文再来利用CSS3属性来编写一个实例,话不多说,先直接看看效果.3D相册实例DEMO 因为前面已经讲解过一些属性的用法,此篇文章不再赘述,只记录这个实例的编码过程.项目代码已上传至github,项目代码github地址

纯CSS3实现的一些酷炫效果

纯CSS3实现的一些酷炫效果 之前在网上看到一些用纯CSS3实现的酷炫效果,以为实现起来比较困难,于是想看看具体是怎么实现的. 一.笑脸猫动画 实现效果如下: 这个实现起来确实比较麻烦,很多地方需要花时间,有耐心地调整. 1.先看下页面结构: <body> <div class="container"> <!-- 脸 --> <div class="face"> <!-- 头发 --> <div cl