FunUsePro Posted July 15, 2006 Posted July 15, 2006 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 Quote
Cags Posted July 15, 2006 Posted July 15, 2006 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. Quote Anybody looking for a graduate programmer (Midlands, England)?
FunUsePro Posted July 15, 2006 Author Posted July 15, 2006 that would explain why drawimage isn't working, ty for that info. So anyone know how to draw an image in a non-parallelogram area? Quote
Leaders snarfblam Posted July 15, 2006 Leaders Posted July 15, 2006 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. Quote [sIGPIC]e[/sIGPIC]
FunUsePro Posted July 15, 2006 Author Posted July 15, 2006 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 Quote
FunUsePro Posted July 20, 2006 Author Posted July 20, 2006 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? Quote
pbjorge12 Posted July 24, 2006 Posted July 24, 2006 Is it possible for you to post the code for the faster Trapazoid Draw function as well? It would be really helpful! Quote
FunUsePro Posted July 24, 2006 Author Posted July 24, 2006 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; } } Quote
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.