Jump to content
Xtreme .Net Talk

Recommended Posts

Posted

Hello again,

 

I posted a thread about a cpu mystery and while I wait to see if I can get more input on that I have a different question.

 

I have looked on google and I can find NO relative information on this.

 

I have an image.

I have a four points,

I want to draw that image stretched out to those four points.

 

i tried using DrawImage under Graphics, passing it four destination points using the order given (upper-left, upper-right, lower-left, lower-right), but I get a "Not Implemented." exception. If i take off the last point and only pass the first 3 points, it works, but omitting the last point makes for inaccurate drawing.

 

Anyone know where I can get some info on this subject?

 

Thanks

Posted
As far as I'm aware the DrawImage overloads that accept a point array can only be used to draw a parrallelagram (i.e. both vertical and both horizontal lines have to be parrallel with each other). If you are attempting to draw a parrallelagram then 3 points will be entirely accurate since the sides in both pairs will be exactly equal in length a 4th point isn't required. If you wish to draw a shape which isn't a parrallelagram, then I believe you are out of luck as far as the DrawImage method goes.
Anybody looking for a graduate programmer (Midlands, England)?
  • Leaders
Posted
I think your best bet might be managed DirectX. It takes a little effort to learn, but it's not that hard and it is a very useful thing to know.
[sIGPIC]e[/sIGPIC]
Posted

thank you for the suggestion.

 

For my current project though I want to keep it simple without having to add DirectX.

 

Anyways, after searching forever I found a vage example of an algorithm in pascal X_X, if (more like once) I get it working properly in c# i'll post it here

Posted

hello,

 

I keep myself busy and have been working on two projects at once (cpu mystery and this one) and just today I finally finished writing the funciton in c#

 

private Bitmap drawTrapezoid(Bitmap bmp, PointF topLeft, PointF topRight, PointF bottomLeft, PointF bottomRight)
       {
           //Get new width and height
           float left = (float)Math.Min(Math.Min(topLeft.X, topRight.X), Math.Min(bottomLeft.X, bottomRight.X));
           float right = (float)Math.Max(Math.Max(topLeft.X, topRight.X), Math.Max(bottomLeft.X, bottomRight.X));
           float top = (float)Math.Min(Math.Min(topLeft.Y, topRight.Y), Math.Min(bottomLeft.Y, bottomRight.Y));
           float bottom = (float)Math.Max(Math.Max(topLeft.Y, topRight.Y), Math.Max(bottomLeft.Y, bottomRight.Y));

           //Translate points to (0, 0)
           PointF origin = new PointF(left, top);
           topLeft.X -= origin.X;
           topLeft.Y -= origin.Y;
           topRight.X -= origin.X;
           topRight.Y -= origin.Y;
           bottomLeft.X -= origin.X;
           bottomLeft.Y -= origin.Y;
           bottomRight.X -= origin.X;
           bottomRight.Y -= origin.Y;

           //Use Graphics class to resize the image
           int newWidth = (int)Math.Round(right - left);
           int newHeight = (int)Math.Round(bottom - top);
           Bitmap inputBmp = new Bitmap(newWidth, newHeight);
           Graphics gg = Graphics.FromImage(inputBmp);
           gg.DrawImage(bmp, new Rectangle(0, 0, newWidth, newHeight), new Rectangle(0, 0, bmp.Width, bmp.Height), GraphicsUnit.Pixel);
           gg.Dispose();


           Bitmap trap = new Bitmap(inputBmp.Width, inputBmp.Height);

           PointF xyA = new PointF(0.0f, 0.0f);
           PointF xyB = new PointF(inputBmp.Width, inputBmp.Height);

           double xFraction, yFraction;
           float xStart, xWidth;
           float yStart, yWidth;


           //Depending on the points, we have to either top to bottom or right to left
           if (topLeft.Y == topRight.Y)
           {
               for (float y = topLeft.Y; y < bottomLeft.Y; y++)
               {
                   yFraction = (y - topLeft.Y) / (bottomLeft.Y - topLeft.Y);
                   xStart = (int)Math.Round((decimal)(topLeft.X + (y - topLeft.Y) * (bottomLeft.X - topLeft.X) / (bottomLeft.Y - topLeft.Y)));
                   xWidth = (int)Math.Round((decimal)((topRight.X - topLeft.X) + (y - topLeft.Y) * ((bottomRight.X - bottomLeft.X) - (topRight.X - topLeft.X)) / (bottomLeft.Y - topLeft.Y)));
                   for (float x = xStart; x < xStart + xWidth; x++)
                   {
                       xFraction = (x - xStart) / (xWidth);
                       float sm = (float)Math.Round(xFraction * (xyB.X - xyA.X));
                       trap.SetPixel((int)x, (int)y, inputBmp.GetPixel((int)sm, (int)y));
                   }
               }
           }
           else
           {
               for (float x = topLeft.X; x < topRight.X; x++)
               {
                   xFraction = (x - topLeft.X) / (topRight.X - topLeft.X);

                   yStart = (int)Math.Round((decimal)(topLeft.Y + (x - topLeft.X) * (topRight.Y - topLeft.Y) / (topRight.X - topLeft.X)));
                   yWidth = (int)Math.Round((decimal)((bottomLeft.Y - topLeft.Y) + (x - topLeft.X) * ((bottomRight.Y - topRight.Y) - (bottomLeft.Y - topLeft.Y)) / (topRight.X - topLeft.X)));
                   for (float y = yStart; y < yStart + yWidth; y++)
                   {
                       yFraction = (y - yStart) / (yWidth);
                       float sm = (float)Math.Round(yFraction * (xyB.Y - xyA.Y));
                       trap.SetPixel((int)x, (int)y, inputBmp.GetPixel((int)x, (int)sm));
                   }
               }
           }         

           inputBmp.Dispose();

           return trap;
       }

 

Note that due to GetPixel/SetPixel this function is horribly slow, with unsafe bitmap processing it's a lot faster, I posted this slow one though cause it has better readability.

 

Code works for making images intro trapezoid-shaped images, but that's about it, it falls short with stranger images, maybe someone here can work off it to make it better.

 

on a quick side note, the function resizes using the Graphics class, does anyone know off hand if the graphics class is faster or slower than doing it with an unsafe class?

Posted

If anyone can make it even faster feel free to share

 

public unsafe class TrapezoidDistort
   {       
       private struct RawData
       {
           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() + ")";
           }
       }

       private static RawData* PixelAt(int x, int y, int width, Byte* pBase)
       {
           return (RawData*)(pBase + y * width + x * sizeof(RawData));
       }

       public static Bitmap drawTrapezoid(Bitmap bmp, PointF[] corners)
       {
           return drawTrapezoid(bmp, corners[0], corners[1], corners[2], corners[3]);
       }

       public static Bitmap drawTrapezoid(Bitmap bmp, PointF topLeft, PointF topRight, PointF bottomLeft, PointF bottomRight)
       {
           if ((topRight.X < topLeft.X) || (bottomRight.X < bottomLeft.X))
           {
               PointF tmpPoint = topRight;
               topRight = topLeft;
               topLeft = tmpPoint;

               tmpPoint = bottomRight;
               bottomRight = bottomLeft;
               bottomLeft = tmpPoint;
           }

           if ((topLeft.Y > bottomLeft.Y) || (topRight.Y > bottomRight.Y))
           {
               PointF tmpPoint = bottomLeft;
               bottomLeft = topLeft;
               topLeft = tmpPoint;

               tmpPoint = bottomRight;
               bottomRight = topRight;
               topRight = tmpPoint;
           }

           //Get new width and height
           float left = (float)Math.Min(Math.Min(topLeft.X, topRight.X), Math.Min(bottomLeft.X, bottomRight.X));
           float right = (float)Math.Max(Math.Max(topLeft.X, topRight.X), Math.Max(bottomLeft.X, bottomRight.X));
           float top = (float)Math.Min(Math.Min(topLeft.Y, topRight.Y), Math.Min(bottomLeft.Y, bottomRight.Y));
           float bottom = (float)Math.Max(Math.Max(topLeft.Y, topRight.Y), Math.Max(bottomLeft.Y, bottomRight.Y));

           //Translate points to (0, 0)
           PointF origin = new PointF(left, top);
           topLeft.X -= origin.X;
           topLeft.Y -= origin.Y;
           topRight.X -= origin.X;
           topRight.Y -= origin.Y;
           bottomLeft.X -= origin.X;
           bottomLeft.Y -= origin.Y;
           bottomRight.X -= origin.X;
           bottomRight.Y -= origin.Y;

           //Use Graphics class to resize the image
           int newWidth = (int)Math.Round(Math.Abs(right - left));
           int newHeight = (int)Math.Round(Math.Abs(bottom - top));
           if (newWidth == 0 || newHeight == 0)
               return new Bitmap(1, 1);
           Bitmap inputBmp = new Bitmap(newWidth, newHeight);
           Graphics gg = Graphics.FromImage(inputBmp);
           gg.SmoothingMode = SmoothingMode.HighSpeed;
           gg.DrawImage(bmp, new Rectangle(0, 0, newWidth, newHeight), new Rectangle(0, 0, bmp.Width, bmp.Height), GraphicsUnit.Pixel);
           gg.Dispose();

           Bitmap trap = new Bitmap(inputBmp.Width, inputBmp.Height);

           //Lock Images so it's possible to access their raw data
           //Input Vars
           int width = 0;
           BitmapData bitmapData = null;
           Byte* pBase = null;

           //Output Vars
           BitmapData outData = null;
           Byte* outBase = null;

           //Input size
           GraphicsUnit unit = GraphicsUnit.Pixel;
           RectangleF bounds = inputBmp.GetBounds(ref unit);
           Size size = new Size((int)bounds.Width, (int)bounds.Height);

           //Lock input image
           Rectangle bounds2 = new Rectangle((int)bounds.X,
               (int)bounds.Y,
               (int)bounds.Width,
               (int)bounds.Height);
           width = (int)bounds.Width * sizeof(RawData);
           if (width % 4 != 0)
           {
               width = 4 * (width / 4 + 1);
           }

           bitmapData = inputBmp.LockBits(bounds2, ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
           pBase = (Byte*)bitmapData.Scan0.ToPointer();

           //Lock output image (no need to calculate bounds since both images are the same size)
           outData = trap.LockBits(bounds2, ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
           outBase = (Byte*)outData.Scan0.ToPointer();


           //Points representing the real top-left corner of them image and the real bottom-right
           PointF xyA = new PointF(0.0f, 0.0f);
           PointF xyB = new PointF(inputBmp.Width, inputBmp.Height);

           double xFraction, yFraction;
           float xStart, xWidth;
           float yStart, yWidth;

           RawData* getPixel;
           RawData* setPixel;

           //Depending on the points, we have to either go top to bottom or right to left
           if (topLeft.Y == topRight.Y)
           {
               for (float y = topLeft.Y; y < bottomLeft.Y; y++)
               {
                   yFraction = (y - topLeft.Y) / (bottomLeft.Y - topLeft.Y);
                   xStart = (int)Math.Round((decimal)(topLeft.X + (y - topLeft.Y) * (bottomLeft.X - topLeft.X) / (bottomLeft.Y - topLeft.Y)));
                   xWidth = (int)Math.Round((decimal)((topRight.X - topLeft.X) + (y - topLeft.Y) * ((bottomRight.X - bottomLeft.X) - (topRight.X - topLeft.X)) / (bottomLeft.Y - topLeft.Y)));
                   for (float x = xStart; x < xStart + xWidth; x++)
                   {
                       xFraction = (x - xStart) / (xWidth);
                       float sm = (float)Math.Round(xFraction * (xyB.X - xyA.X));

                       getPixel = PixelAt((int)sm, (int)y, width, pBase);
                       setPixel = PixelAt((int)x, (int)y, width, outBase);
                       setPixel->alpha = 255;
                       setPixel->red = getPixel->red;
                       setPixel->green = getPixel->green;
                       setPixel->blue = getPixel->blue;
                       //trap.SetPixel((int)x, (int)y, inputBmp.GetPixel((int)sm, (int)y));
                   }
               }
           }
           else
           {
               for (float x = topLeft.X; x < topRight.X; x++)
               {
                   xFraction = (x - topLeft.X) / (topRight.X - topLeft.X);

                   yStart = (int)Math.Round((decimal)(topLeft.Y + (x - topLeft.X) * (topRight.Y - topLeft.Y) / (topRight.X - topLeft.X)));
                   yWidth = (int)Math.Round((decimal)((bottomLeft.Y - topLeft.Y) + (x - topLeft.X) * ((bottomRight.Y - topRight.Y) - (bottomLeft.Y - topLeft.Y)) / (topRight.X - topLeft.X)));
                   for (float y = yStart; y < yStart + yWidth; y++)
                   {
                       yFraction = (y - yStart) / (yWidth);
                       float sm = (float)Math.Round(yFraction * (xyB.Y - xyA.Y));
                       getPixel = PixelAt((int)x, (int)sm, width, pBase);
                       setPixel = PixelAt((int)x, (int)y, width, outBase);
                       setPixel->alpha = 255;
                       setPixel->red = getPixel->red;
                       setPixel->green = getPixel->green;
                       setPixel->blue = getPixel->blue;
                       //trap.SetPixel((int)x, (int)y, inputBmp.GetPixel((int)x, (int)sm));
                   }
               }
           }

           //Unlock input image and clear
           inputBmp.UnlockBits(bitmapData);
           bitmapData = null;
           pBase = null;
           inputBmp.Dispose();

           //Unlock output image
           trap.UnlockBits(outData);
           outData = null;
           pBase = null;

           return trap;
       }
   }

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...