Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/276.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 创建拉伸画布视图的方法_C#_Asp.net_Image_Css_Image Processing - Fatal编程技术网

C# 创建拉伸画布视图的方法

C# 创建拉伸画布视图的方法,c#,asp.net,image,css,image-processing,C#,Asp.net,Image,Css,Image Processing,这就是我想要实现的 纯粹的形象, 创造形象, 我看到很多应用程序都在这样做(这是其中之一),但我想知道如何做到这一点?我应该使用什么样的方法、算法或编程语言 我尝试过使用css3 bu,但没有实际效果,而且它也不是一个跨浏览器的解决方案 -webkit变换:透视(800px)旋转(78度) 我正在寻找服务器端解决方案。这就是您想要的吗 编辑: 基于上面的url,我做了一个与图片中的内容非常接近的链接 为了实现这一点,不幸的是,我不得不使用2个图像 HTML标记有点简单。1个用于正面的容器。右

这就是我想要实现的

纯粹的形象,

创造形象,

我看到很多应用程序都在这样做(这是其中之一),但我想知道如何做到这一点?我应该使用什么样的方法、算法或编程语言

我尝试过使用css3 bu,但没有实际效果,而且它也不是一个跨浏览器的解决方案

-webkit变换:透视(800px)旋转(78度)


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

这就是您想要的吗

编辑:

基于上面的url,我做了一个与图片中的内容非常接近的链接

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

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

<div class="cube">
    <div class="cube-face  cube-face-front"></div>
    <div class="cube-face  cube-face-right"></div>
</div>
前侧在Z轴上的平移量与右侧的旋转量相同

transform: translate3d(0, 0, 25px);
-webkit-transform: translate3d(0, 0, 25px);
-ms-transform: translate3d(0, 0, 25px);
希望这有帮助

  • 在编写CSS3动画(效果)时,请尝试始终使用所有前缀(-o-,-moz-,-webkit,-ms-)
编辑2:

忘了阴影。我使用了一个阴影,并在每一侧应用了一个阴影

-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);
更新

编辑3:

修复为仅使用1个图像

我所做的就是利用背景位置

正面接收<代码>背景位置:左上

右侧接收<代码>背景位置:右上


确保“holder”容器比图像小,图像右侧比图像大%s

我编写了一个应用程序,可以满足您的要求,但结果表明您提供的示例图像存在一些问题。以您的示例为指导,您可以看到该应用程序的输出非常接近

<div class="cube">
    <div class="cube-face  cube-face-front"></div>
    <div class="cube-face  cube-face-right"></div>
</div>
Ex.1)格式化右侧边缘背后的逻辑是获取原始图像的右侧10%,然后围绕Y轴反射,将其压缩到5%,然后扭曲。在某些情况下,它看起来很好

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

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

所以,在看了你提到的链接之后,我还包括了他们在那里做的修改版本。不同之处在于,图像周围有一个白色蒙版,同时还有如下图所示的阴影。这样,就有两个代码库可以进行实验

示例:

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

关于代码
  • 我使用了在web上找到的一些不同的片段,并使用它们创建了一个可用的类。最重要的是,来自的源提供了关于使用GDI+将四边形扭曲应用于图像的大量信息
  • 代码中到处都是神奇的数字,因为我最感兴趣的是重新创建您请求的结果。我只是没有时间做一个完全可配置的控件
  • gallery wrap版本比matted版本慢得多
  • 可以复制或修改
    GetCanvaseImage
    GetMattedImage
    函数以创建自己的自定义图像格式
  • SHADOW_DEPTH
    常量是硬编码的,在包装或蒙版输出之间切换和/或更改最大长度值时必须手动调整。显然,这些都可以变成变量
  • MAX_LENGTH
    值用于将宽度或高度约束为最大值。它只应用于最长的边
  • 只需将这两个类复制到一个项目、一个单独的命名空间或一个单独的程序集中。然后,传入一个指向图像的路径,并获取一个格式化图像作为返回值

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

您希望支持哪些浏览器?@apaul34208,实际上是最现代的浏览器,但是+ie8会很好。我无法获得的实际问题是图像的大小是任意的,这是不确定的。实际上我不希望它是立方体,但确实是三维的。这是一个很好的教程。但我已经玩了一个小时,但我无法像streched那样转换它(参见我的示例图像)。你们有一个想法,我如何转换它看起来像我的示例图像,无论如何谢谢。我用了这个代码,但我得到了镜像效果的图像。我需要像画布3D框架一样的英勇包裹效果。所以请帮助我如何从给定的代码中获得这种效果。嘿,谢谢你的代表。仅供参考。我只是用一双新鲜的眼睛看了看,我注意到一件事,你的例子的轮廓边框颜色不像我的黑色。这可能就是为什么我的边缘看起来并不总是那么清晰的原因。在.net中,抗锯齿选项非常有限。注意。你好,我又有问题了,希望你能帮助我,你的解决方案很好,但在每张图片的底部都有一条线,你能帮我解决这个问题吗?设置了
MAX\u LENGTH
后,感谢使用
SHADOW\u DEPTH
属性进行显示。这样做的目的是只看到用于绘制阴影矩形的
PathGradientBrush
的软边。一旦你把这些值取对了,你就可以制作很多相同长度的图像。我明白了,你用一个矩形做了阴影,当我玩透视角度时,阴影矩形仍然存在。所以我不能创建一个像图像一样的阴影多边形,而不是一个矩形吗?通过在
shadowRect
声明中使用神奇的数字,您可能可以按您想要的方式获得它。它们只是近似于阴影的偏移量。试着把它移到右边一些。但是是的,如果你用一个锐角,你需要改变阴影策略。你也可以玩
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);
    }