创建拉伸画布视图的方法

Posted

技术标签:

【中文标题】创建拉伸画布视图的方法【英文标题】:Ways to create stretched canvas view 【发布时间】:2014-01-29 13:14:27 【问题描述】:

这是我想要达到的目标,

纯图像,

创建的图像,

我看到很多应用程序都在这样做(http://fineartamerica.com/ 就是其中之一),但我想知道如何做到这一点?我应该使用哪种方法、算法或编程语言?

我用 css3 试过了,但没有得到切实的结果,也不是跨浏览器的解决方案,

-webkit-transform: 透视(800px) 旋转(78deg);

我正在寻找服务器端解决方案。

【问题讨论】:

您希望支持哪些浏览器? @apaul34208,实际上是最现代的浏览器,但 + ie8 会很棒。我无法实现的实际问题是图像可以是任何大小,不确定。 【参考方案1】:

这就是你要找的http://css-tricks.com/creating-a-3d-cube-image-gallery/ 吗?

编辑:

根据上面的网址,我制作了一个fiddle,它与您在图片中的内容非常接近

不幸的是,为了实现这一点,我不得不使用 2 张图片

html 标记有点简单。 1 个用于正面的容器。右侧1个

<div class="cube">
    <div class="cube-face  cube-face-front"></div>
    <div class="cube-face  cube-face-right"></div>
</div>

那么在CSS里面有些部分比较重要

右侧移动和旋转

left: 600px; /* Moved left 100% of image */

outline: 1px solid transparent; /* Used to smoothen edges in Firefox */

transform: rotateY(25deg) translate3d(0px, 0px, 0px);
-webkit-transform: rotateY(25deg) translate3d(0px, 0px, 0px);
-ms-transform: rotateY(25deg) translate3d(0px, 0px, 0px);

正面在 Z 轴上的平移量与右侧旋转的量相同

transform: translate3d(0, 0, 25px);
-webkit-transform: translate3d(0, 0, 25px);
-ms-transform: translate3d(0, 0, 25px);

希望对你有帮助

在编写 CSS3 动画(效果)时尽量使用所有前缀(-o-、-moz-、-webkit、-ms-)

编辑 2:

忘记了影子。我使用了box-shadow generator 并在每一侧应用了阴影。

-webkit-box-shadow: 7px 8px 17px 0px rgba(50, 50, 50, 0.75);
-moz-box-shadow:    7px 8px 17px 0px rgba(50, 50, 50, 0.75);
box-shadow:         7px 8px 17px 0px rgba(50, 50, 50, 0.75);

更新fiddle

编辑 3:

已修复为仅使用 1 张图片http://jsfiddle.net/S4eBd/3/

我所做的是利用背景位置

正面收到background-position: left top;

右侧收到background-position: right top;

确保 'holder' 容器小于图像,% 大于右侧

【讨论】:

其实我不希望它变成立方体,但是是 3d。这是一个很好的教程。但我已经玩了一个小时,但我无法像拉伸一样转换它(参见我的示例图像)。你有什么想法吗,我怎样才能把它转换成我的示例图像,谢谢。 我用过这段代码,但我得到了镜像效果。我需要像画布 3D 框架一样的画廊环绕效果。所以请帮助我如何从给定的代码中获得这种效果。例如i.stack.imgur.com/PSDze.jpg【参考方案2】:

我编写了一个应用程序,可以执行您想要的操作,但事实证明您提供的示例图像存在一些问题。以您的示例为指导,您可以看到此应用程序的输出看起来非常接近。

Ex.1) 格式化右侧边缘背后的逻辑是取原始图像右侧的 10%,然后将其围绕 Y 轴反射,将其压缩到 5%,然后将其扭曲。在某些情况下,它看起来不错。

当您使用这样的图像时会出现问题:

脚被拉入反射的图像中。当你用画廊包装一个真正的预涂画布时,也会发生类似的问题。你要么失去绘画的外边框,要么得到白色的边。

所以,在查看了您提到的 http://fineartamerica.com 链接之后,我还包括了他们在那里所做的修改版本。不同之处在于图像周围有一个白色遮罩以及如下图所示的阴影。这样,就有 2 个代码库可供试验。

例子:

好的,这是相当多的代码。如果您要在 asp.net 中的服务器端使用它,请将其包装在它自己的 dll 中并引用它。有一些不安全的代码,否则 asp.net 可能会对你咆哮。

关于代码

我使用了我在网上找到的几个不同的部分,并用它们创建了一个可用的类。最重要的是,http://www.vcskicks.com/image-distortion.php 的来源提供了有关使用 GDI+ 对图像应用四边形扭曲的大量信息。 代码中散落着一些神奇的数字,因为我最感兴趣的是重新创建您请求的结果。我只是没有时间制作一个完全可配置的控件。 gallery wrap 版本比 matted 慢得多。 可以复制或修改 GetCanvasedImageGetMattedImage 函数以创建您自己的自定义图像格式。 SHADOW_DEPTH 常量是硬编码的,当在包裹或乱码输出之间切换和/或更改 MAX_LENGTH 值时必须手动调整。显然这些都可以变成变量。 MAX_LENGTH 值用于将 宽度或高度限制为最大值。它只是将其应用于最长的边缘。 只需将这两个类复制到一个项目、一个单独的命名空间或一个单独的程序集中。然后,传入图片的路径,并获取格式化的图片作为返回值。
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;

namespace WindowsFormsApplication1 
    public class ImageFormatter 
        public ImageFormatter() 
        

        private const int MAX_LENGTH = 500;     // Constrain size to the longest edge
        private const int SHADOW_DEPTH = 30;    // This number has to be adjusted to taste 
                                                // for each change in MAX_LENGTH
        private const double PIOver2 = Math.PI / 2.0;

        /// <summary>
        /// Creates a 3D representation of a 2D image, as if stretched around stretcher bars.
        /// </summary>
        public Image GetCanvasedImage(string srcImgPath) 

            Image src = SizeSourceImage(Bitmap.FromFile(srcImgPath));
            Bitmap output = new Bitmap(src, src.Width + (int)(src.Width * .125f), src.Height + (int)(src.Height * .125f));

            using (Bitmap side = new Bitmap((int)(src.Width * .10f), src.Height))
            using (GraphicsPath outline = new GraphicsPath())
            using (Graphics destGraphics = Graphics.FromImage(output)) 

                // Set graphics options
                destGraphics.Clear(Color.White);
                destGraphics.InterpolationMode = InterpolationMode.Bicubic;
                destGraphics.PixelOffsetMode = PixelOffsetMode.HighSpeed;
                destGraphics.SmoothingMode = SmoothingMode.AntiAlias;

                Rectangle shadowRect = new Rectangle(
                    (int)(src.Width * .02),
                    (int)(src.Height * .03),
                    src.Width + (int)(src.Width * .07),
                    src.Height + (int)(src.Height * .03)
                );

                // Counter-clockwise points of front rectangle
                Point[] destPoints = new Point[]  
                        new Point(0, (int)(src.Height * .02f)), 
                        new Point(src.Width, 0), 
                        new Point(src.Width, src.Height),
                        new Point(0, src.Height - (int)(src.Height * .02f))
                    ;

                outline.AddPolygon(destPoints);

                // Draw the drop shadow first
                DrawRectangleDropShadow(
                    destGraphics,
                    shadowRect,
                    Color.FromArgb(25, 25, 25),
                    SHADOW_DEPTH,
                    128
                );

                // Draw front rectangle warped
                destGraphics.DrawImage(ImageFormatter.Distort(
                    (Bitmap)src,
                    destPoints[0],
                    destPoints[1],
                    destPoints[3],
                    destPoints[2],
                    3
                ), 0, 0);

                // Create the inverted right-side graphic
                src.RotateFlip(RotateFlipType.Rotate180FlipY);

                using (Graphics sideGraphics = Graphics.FromImage(side)) 
                    sideGraphics.DrawImage(
                        src, 
                        new Rectangle(0, 0, side.Width, side.Height),
                        new Rectangle(new Point(0, 0), new Size(side.Width, side.Height)),
                        GraphicsUnit.Pixel);
                

                destPoints = new Point[]  
                    new Point(src.Width, 0), 
                    new Point(src.Width + (int)(side.Width * .5f), (int)(side.Height * .03f)), 
                    new Point(src.Width + (int)(side.Width * .5f), src.Height - (int)(side.Height * .03f)), 
                    new Point(src.Width, src.Height)
                ;

                // Draw side rectangle warped
                destGraphics.DrawImage(ImageFormatter.Distort(
                    (Bitmap)side,
                    destPoints[0],
                    destPoints[1],
                    destPoints[3],
                    destPoints[2],
                    3
                ), 0, 0);

                outline.AddPolygon(destPoints);

                // Draw outline
                GraphicsPath p = new GraphicsPath(FillMode.Alternate);
                destGraphics.DrawPath(Pens.Black, outline);
            

            return output;
        

        /// <summary>
        /// Creates a matted representation of an image with accompanying drop shadow
        /// </summary>
        public Image GetMattedImage(string srcImgPath) 

            Image src = SizeSourceImage(Bitmap.FromFile(srcImgPath));
            int borderWidth = (int)(src.Width * .05f);

            Rectangle imageRect = new Rectangle(
                0, 
                0, 
                src.Width + borderWidth * 2, 
                src.Height + borderWidth * 2
            );

            Rectangle outputRect = new Rectangle(
                0,
                0,
                src.Width + borderWidth * 2 + (int)(src.Height * .10f), 
                src.Height + borderWidth * 2 + (int)(src.Height * .10f)
            );

            Rectangle shadowRect = imageRect;
            shadowRect.Inflate(8, 8);
            shadowRect.Offset(5, 5);

            Bitmap output = new Bitmap(outputRect.Width, outputRect.Height);

            using (GraphicsPath outline = new GraphicsPath())
            using (Graphics destGraphics = Graphics.FromImage(output)) 

                // Set graphics options
                destGraphics.Clear(Color.White);
                destGraphics.InterpolationMode = InterpolationMode.Bicubic;
                destGraphics.PixelOffsetMode = PixelOffsetMode.HighSpeed;
                destGraphics.SmoothingMode = SmoothingMode.AntiAlias;

                // Draw shadow
                DrawRectangleDropShadow(
                    destGraphics,
                    shadowRect,
                    Color.FromArgb(25, 25, 25),
                    SHADOW_DEPTH,
                    128
                );

                // Draw image
                destGraphics.FillRectangle(Brushes.White, imageRect);
                destGraphics.DrawImage(src, borderWidth, borderWidth);
                destGraphics.DrawRectangle(Pens.Black, imageRect);

                // Draw outline
                //destGraphics.DrawPath(Pens.Black, outline);
            

            return output;
        

        private Image SizeSourceImage(Image src) 
            int newWidth = 0;
            int newHeight = 0;

            if (src.Width >= src.Height) 
                if (src.Width <= MAX_LENGTH)
                    return src;

                double ratio = (double)src.Height / src.Width;
                newWidth = MAX_LENGTH;
                newHeight = (int)(MAX_LENGTH * ratio);
            
            else 
                if (src.Height <= MAX_LENGTH)
                    return src;

                double ratio = (double)src.Width / src.Height;
                newHeight = MAX_LENGTH;
                newWidth = (int)(MAX_LENGTH * ratio);
            

            double edgeWidth = newWidth * .05;

            Image resized = new Bitmap(src, new Size(newWidth, newHeight));
            Graphics g = Graphics.FromImage(resized);

            return new Bitmap(src, new Size(newWidth, newHeight));
        

        private struct Vector 
            public PointF Origin;
            public float Direction;

            public Vector(PointF origin, float direction) 
                this.Origin = origin;
                this.Direction = direction;
            
        

        public static Bitmap Distort(Bitmap sourceBitmap, PointF topleft, PointF topright, PointF bottomleft, PointF bottomright) 
            return Distort(sourceBitmap, topleft, topright, bottomleft, bottomright, 2);
        

        public static Bitmap Distort(Bitmap sourceBitmap, PointF topleft, PointF topright, PointF bottomleft, PointF bottomright, int interpolation = 0) 
            double sourceWidth = sourceBitmap.Width;
            double sourceHeight = sourceBitmap.Height;

            //Find dimensions of new image
            PointF[] pointarray = new PointF[]  topleft, topright, bottomright, bottomleft ;

            int width = int.MinValue;
            int height = int.MinValue;

            foreach (PointF p in pointarray) 
                width = (int)Math.Max(width, p.X);
                height = (int)Math.Max(height, p.Y);
            

            Bitmap bitmap = new Bitmap(width, height);

            //For faster image processing
            FastBitmap newBmp = new FastBitmap(bitmap);
            FastBitmap sourceBmp = new FastBitmap(sourceBitmap);

            newBmp.LockImage();
            sourceBmp.LockImage();

            //Key points
            PointF tl = (PointF)topleft;
            PointF tr = (PointF)topright;
            PointF br = (PointF)bottomright;
            PointF bl = (PointF)bottomleft;

            // sides
            float ab = GetAngle(tl, tr);
            float cd = GetAngle(br, bl);
            float ad = GetAngle(tl, bl);
            float bc = GetAngle(tr, br);

            //Get corner intersections
            PointF o = GetIntersection(new Vector(tr, ab), new Vector(br, cd));
            PointF n = GetIntersection(new Vector(tl, ad), new Vector(tr, bc));

            if (interpolation <= 0) 
                interpolation = 1;

            int middleX = (int)(interpolation / 2.0);

            //Array of surronding pixels used for interpolation
            double[, ,] source = new double[interpolation, interpolation, 4];

            for (int y = 0; y < height; y++) 
                for (int x = 0; x < width; x++) 
                    PointF P = new PointF(x, y);

                    float po = ab; //Default value
                    float pn = bc;

                    if (o != PointF.Empty) //If intersection found, get coefficient
                        po = GetAngle(o, P);

                    if (n != PointF.Empty) //If intersection found, get coefficient
                        pn = GetAngle(n, P);

                    //Get intersections
                    PointF l = GetIntersection(new Vector(P, po), new Vector(tl, ad));
                    if (l == PointF.Empty) 
                        l = tl;

                    PointF m = GetIntersection(new Vector(P, po), new Vector(br, bc));
                    if (m == PointF.Empty)
                        m = br;

                    PointF j = GetIntersection(new Vector(P, pn), new Vector(tr, ab));
                    if (j == PointF.Empty) 
                        j = tr;

                    PointF k = GetIntersection(new Vector(P, pn), new Vector(bl, cd));
                    if (k == PointF.Empty) 
                        k = bl;

                    double jp = GetDistance(j, P);
                    double lp = GetDistance(l, P);
                    double jk = GetDistance(j, k);
                    double lm = GetDistance(l, m);

                    //set direction
                    if (lm < GetDistance(m, P)) 
                        lp = -lp;
                    if (jk < GetDistance(k, P)) 
                        jp = -jp;

                    //interpolation

                    //find the pixels which surround the point
                    double yP0 = sourceHeight * jp / jk;
                    double xP0 = sourceWidth * lp / lm;

                    //top left coordinates of surrounding pixels
                    if (xP0 < 0) 
                        xP0--;
                    if (yP0 < 0) 
                        yP0--;

                    int left = (int)xP0;
                    int top = (int)yP0;

                    if ((left < -1 || left > sourceWidth) && (top < -1 || top > sourceHeight)) 
                        continue;

                    //weights
                    double xFrac = xP0 - (double)left;
                    double xFracRec = 1.0 - xFrac;
                    double yFrac = yP0 - (double)top;
                    double yFracRec = 1.0 - yFrac;

                    //get source pixel colors, or white if out of range (to interpolate into the background color)
                    int x0;
                    int y0;
                    Color color;

                    for (int sx = 0; sx < interpolation; sx++) 
                        for (int sy = 0; sy < interpolation; sy++) 
                            x0 = left + sx;
                            y0 = top + sy;

                            if (x0 > 0 && y0 > 0 &&
                                x0 < sourceWidth && y0 < sourceHeight) 
                                color = sourceBmp.GetPixel(x0, y0);

                                source[sx, sy, 0] = color.R;
                                source[sx, sy, 1] = color.G;
                                source[sx, sy, 2] = color.B;
                                source[sx, sy, 3] = 255.0f;
                            
                            else 
                                // set full transparency in this case
                                source[sx, sy, 0] = 0;
                                source[sx, sy, 1] = 0;
                                source[sx, sy, 2] = 0;
                                source[sx, sy, 3] = 0;
                            
                        
                    

                    //interpolate on x
                    for (int sy = 0; sy < interpolation; sy++) 
                        //check transparency
                        if (source[middleX, sy, 3] != 0 && source[0, sy, 3] == 0) 
                            //copy colors from 1, sy
                            source[0, sy, 0] = source[1, sy, 0];
                            source[0, sy, 1] = source[1, sy, 1];
                            source[0, sy, 2] = source[1, sy, 2];
                            source[0, sy, 3] = source[1, sy, 3];
                        
                        else 
                            //compute colors by interpolation
                            source[0, sy, 0] = source[0, sy, 0] * xFracRec + source[middleX, sy, 0] * xFrac;
                            source[0, sy, 1] = source[0, sy, 1] * xFracRec + source[middleX, sy, 1] * xFrac;
                            source[0, sy, 2] = source[0, sy, 2] * xFracRec + source[middleX, sy, 2] * xFrac;
                            source[0, sy, 3] = source[0, sy, 3] * xFracRec + source[middleX, sy, 3] * xFrac;
                        

                        //interpolate transparency
                        source[0, sy, 3] = source[0, sy, 3] * xFracRec + source[middleX, sy, 3] * xFrac;
                    

                    //now interpolate on y

                    //check transparency
                    if (source[0, middleX, 3] != 0 && source[0, 0, 3] == 0) 
                        //copy colors from 0, 1
                        source[0, 0, 0] = source[0, middleX, 0];
                        source[0, 0, 1] = source[0, middleX, 1];
                        source[0, 0, 2] = source[0, middleX, 2];
                        source[0, 0, 3] = source[0, middleX, 3];
                    
                    else 
                        source[0, 0, 0] = source[0, 0, 0] * yFracRec + source[0, middleX, 0] * yFrac;
                        source[0, 0, 1] = source[0, 0, 1] * yFracRec + source[0, middleX, 1] * yFrac;
                        source[0, 0, 2] = source[0, 0, 2] * yFracRec + source[0, middleX, 2] * yFrac;
                        source[0, 0, 3] = source[0, 0, 3] * yFracRec + source[0, middleX, 3] * yFrac;
                    

                    //interpolate transparency
                    source[0, 0, 3] = source[0, 0, 3] * yFracRec + source[0, middleX, 3] * yFrac;

                    //store to bitmap
                    if (source[0, 0, 3] != 0) //pixel has color
                        newBmp.SetPixel(x, y, Color.FromArgb((int)source[0, 0, 3], (int)source[0, 0, 0], (int)source[0, 0, 1], (int)source[0, 0, 2]));
                
            

            sourceBmp.UnlockImage();
            newBmp.UnlockImage();

            return bitmap;
        

        private static double GetDistance(PointF A, PointF B) 
            float a = A.X - B.X;
            float b = A.Y - B.Y;
            return Math.Sqrt((double)(a * a + b * b));
        

        private static PointF GetIntersection(Vector vector1, Vector vector2) //Vector[] pointAngularCoeff)
        
            if (vector1.Origin.X == vector2.Origin.X && vector1.Origin.Y == vector2.Origin.Y)
                return vector1.Origin;

            if (vector1.Direction == vector2.Direction) return PointF.Empty; //Parallel, no intersection

            float newX = float.Epsilon;
            float newY = float.Epsilon;

            if (float.IsInfinity(vector1.Direction)) 
                newX = vector1.Origin.X;
                newY = vector2.Origin.Y + vector2.Direction * (-vector2.Origin.X + vector1.Origin.X);
            

            if (float.IsInfinity(vector2.Direction)) 
                newX = vector2.Origin.X;
                newY = vector1.Origin.Y + vector1.Direction * (-vector1.Origin.X + vector2.Origin.X);
            

            if (newX == float.Epsilon) 
                float q1 = vector1.Origin.Y - vector1.Direction * vector1.Origin.X;
                float q2 = vector2.Origin.Y - vector2.Direction * vector2.Origin.X;
                newX = (q1 - q2) / (vector2.Direction - vector1.Direction);
                newY = vector1.Direction * newX + q1;
            

            if (float.IsInfinity(newX) || float.IsInfinity(newY))
                return PointF.Empty; //no intersection found
            else 
                return new PointF(newX, newY);
            
        

        private static float GetAngle(PointF from, PointF to) 
            double angle = GetAngleRad(from, to);
            double t = angle % Math.PI;

            if (Math.Abs(t - PIOver2) < 0.0000001) //t == PIOver2 (avoid loss of precision bug)
            
                return float.PositiveInfinity;
            
            else 
                if (Math.Abs(t + PIOver2) < 0.0000001) //t == -PIOver2 (avoid loss of precision bug)
                    return float.NegativeInfinity;
                else
                    return (float)Math.Tan(angle);
            
        

        private static double GetAngleRad(PointF from, PointF to) 
            if (to.Y == from.Y) 
                if (from.X > to.X)
                    return Math.PI;
                else
                    return 0;
            
            else if (to.X == from.X) 
                if (to.Y < from.Y)
                    return -PIOver2;
                else
                    return PIOver2;
            
            else 
                double m = Math.Atan(((to.Y - from.Y) / (to.X - from.X)));

                if (to.X < 0)
                    if (m > 0)
                        return m + PIOver2;
                    else
                        return m - Math.PI;
                else
                    return m;
            
        

        private static void DrawRectangleDropShadow(Graphics tg, Rectangle rc, Color shadowColor, int depth, int maxOpacity) 
            //calculate the opacities
            Color darkShadow = Color.FromArgb(maxOpacity, shadowColor);
            Color lightShadow = Color.FromArgb(0, shadowColor);

            //Create a shape for the path gradient brush
            using (GraphicsPath gp = new GraphicsPath()) 
            using (Bitmap patternbm = new Bitmap(2 * depth, 2 * depth))
            using (Graphics g = Graphics.FromImage(patternbm)) 
                gp.AddEllipse(0, 0, 2 * depth, 2 * depth);

                //Create the brush that will draw a softshadow circle
                using (PathGradientBrush pgb = new PathGradientBrush(gp)) 
                    pgb.CenterColor = darkShadow;
                    pgb.SurroundColors = new Color[]  lightShadow ;
                    g.FillEllipse(pgb, 0, 0, 2 * depth, 2 * depth);


                    SolidBrush sb = new SolidBrush(Color.FromArgb(maxOpacity, shadowColor));
                    tg.FillRectangle(sb, rc.Left + depth, rc.Top + depth, rc.Width - (2 * depth), rc.Height - (2 * depth));
                    sb.Dispose();

                    //top left corner
                    tg.DrawImage(patternbm, new Rectangle(rc.Left, rc.Top, depth, depth), 0, 0, depth, depth, GraphicsUnit.Pixel);
                    //top side
                    tg.DrawImage(patternbm, new Rectangle(rc.Left + depth, rc.Top, rc.Width - (2 * depth), depth), depth, 0, 1, depth, GraphicsUnit.Pixel);
                    //top right corner
                    tg.DrawImage(patternbm, new Rectangle(rc.Right - depth, rc.Top, depth, depth), depth, 0, depth, depth, GraphicsUnit.Pixel);
                    //right side
                    tg.DrawImage(patternbm, new Rectangle(rc.Right - depth, rc.Top + depth, depth, rc.Height - (2 * depth)), depth, depth, depth, 1, GraphicsUnit.Pixel);
                    //bottom left corner
                    tg.DrawImage(patternbm, new Rectangle(rc.Right - depth, rc.Bottom - depth, depth, depth), depth, depth, depth, depth, GraphicsUnit.Pixel);
                    //bottom side
                    tg.DrawImage(patternbm, new Rectangle(rc.Left + depth, rc.Bottom - depth, rc.Width - (2 * depth), depth), depth, depth, 1, depth, GraphicsUnit.Pixel);
                    //bottom left corner
                    tg.DrawImage(patternbm, new Rectangle(rc.Left, rc.Bottom - depth, depth, depth), 0, depth, depth, depth, GraphicsUnit.Pixel);
                    //left side
                    tg.DrawImage(patternbm, new Rectangle(rc.Left, rc.Top + depth, depth, rc.Height - (2 * depth)), 0, depth, depth, 1, GraphicsUnit.Pixel);
                
            
        
    

    unsafe public class FastBitmap 
        public FastBitmap(Bitmap inputBitmap) 
            workingBitmap = inputBitmap;
        

        private int width = 0;
        private Bitmap workingBitmap = null;
        private BitmapData bitmapData = null;
        private Byte* pBase = null;

        [StructLayout(LayoutKind.Sequential)]
        private struct PixelData 
            public byte blue;
            public byte green;
            public byte red;
            public byte alpha;

            public override string ToString() 
                return "(" + alpha.ToString() + ", " + red.ToString() + ", " + green.ToString() + ", " + blue.ToString() + ")";
            
        

        public void LockImage() 
            //Size
            Rectangle bounds = new Rectangle(Point.Empty, workingBitmap.Size);
            width = (int)(bounds.Width * sizeof(PixelData));

            if (width % 4 != 0)
                width = 4 * (width / 4 + 1);

            //Lock Image
            bitmapData = workingBitmap.LockBits(bounds, ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
            pBase = (Byte*)bitmapData.Scan0.ToPointer();
        

        private PixelData* pixelData = null;

        public Color GetPixel(int x, int y) 
            pixelData = (PixelData*)(pBase + y * width + x * sizeof(PixelData));
            return Color.FromArgb(pixelData->alpha, pixelData->red, pixelData->green, pixelData->blue);
        

        public Color GetPixelNext() 
            pixelData++;
            return Color.FromArgb(pixelData->alpha, pixelData->red, pixelData->green, pixelData->blue);
        

        public void SetPixel(int x, int y, Color color) 
            PixelData* data = (PixelData*)(pBase + y * width + x * sizeof(PixelData));
            data->alpha = color.A;
            data->green = color.G;
            data->blue = color.B;
            data->red = color.R;
        

        public void UnlockImage() 
            workingBitmap.UnlockBits(bitmapData);
            bitmapData = null;
            pBase = null;
        

    

用法:

    private void button1_Click(object sender, EventArgs e) 
        ImageFormatter formatter = new ImageFormatter();
        Image output = formatter.GetCanvasedImage(
            @"C:\Development\input.jpg"
        );

        output.Save(
            @"C:\Development\output.jpg",
            System.Drawing.Imaging.ImageFormat.Jpeg);
    

祝你好运!我希望这会有所帮助。

【讨论】:

嘿,谢谢您的代表。供参考。我只是用一双新鲜的眼睛看着这个,我注意到的一件事是你的例子的轮廓边框颜色不像我的那样是黑色的。这可能就是为什么我的边缘看起来并不总是那么清晰的原因。 .net 中的抗锯齿选项非常有限。保重。 您好,我又遇到了问题,希望您能帮助我,您的解决方案很棒,但是在每张图片上,图片底部都会出现线条,您能帮我解决这个问题吗?谢谢 在设置MAX_LENGTH 后使用SHADOW_DEPTH 属性。这个想法是只看到用于绘制阴影矩形的PathGradientBrush 的软边缘。一旦你得到这些值,你就可以制作许多相同长度的图像。 我明白了,你用矩形制作了阴影,当我玩透视角时,阴影矩形仍然存在。那么我不能像图像一样创建一个阴影多边形,而不是一个矩形吗? 您可以通过使用shadowRect 声明中的幻数来获得它。它们只是近似于阴影的偏移量。尝试将其向右移动一些。但是,是的,如果您使用锐角,则需要更改阴影策略。您还可以使用绘制阴影的PathGradientBrush 来获得不同的效果。

以上是关于创建拉伸画布视图的方法的主要内容,如果未能解决你的问题,请参考以下文章

如何添加视图(以及缩小或拉伸其他)iOS

iOS 自动布局 - 当您想让视图拉伸到其父级的完整大小时,正确的方法是啥?

iOS - 在堆栈视图中拉伸的图像

在 Android 上的 onDraw 之外更新视图的画布

在按钮顶部拉伸图像以推动视图控制器

调用ondraw后重置画布,然后再在android中调用它