2016-01-20 70 views
0

我从另一个游戏的标准自上而下的瓷砖动态创建等角拼贴。但问题是,图像调整大小往往会导致两侧像素“缺失”。我知道他们并不是真的错过了,代码运行正常,但我对GDI了解不多,无法知道要搜索哪些设置/教程。GDI调整图像和保证高度

我把这个:enter image description here并把它变成这个:enter image description here

它从32x32到48x24,这是正确的比例。但是,在左侧和底部,草地距离图像边缘不到一个像素。我不想手动解决这个问题,因为我会为数百个tile执行此操作,所以我想找到一种方法在代码中修复此问题。最后,问题在于瓷砖之间的微小单像素间隙。

我可以用GDI做什么,除了检查每个图像的边缘颜色并手动添加它们(如果它们缺失/透明)以外,还能做什么?

这是我用来做到这一点的代码。注释掉的部分是一些我已经搞乱了各种设置:

Bitmap bmp = RotateImage(new Bitmap(fileName), 45); 
bmp = ResizeImage(bmp, bmp.Width, bmp.Height/2); 

private static Bitmap RotateImage(Bitmap rotateMe, float angle) 
{ 
    //First, re-center the image in a larger image that has a margin/frame 
    //to compensate for the rotated image's increased size 

    var bmp = new Bitmap(rotateMe.Width + (rotateMe.Width/2), rotateMe.Height + (rotateMe.Height/2)); 

    using (Graphics g = Graphics.FromImage(bmp)) 
     g.DrawImageUnscaled(rotateMe, (rotateMe.Width/4), (rotateMe.Height/4), bmp.Width, bmp.Height); 

    rotateMe = bmp; 

    //Now, actually rotate the image 
    Bitmap rotatedImage = new Bitmap(rotateMe.Width, rotateMe.Height); 

    using (Graphics g = Graphics.FromImage(rotatedImage)) 
    { 
     g.TranslateTransform(rotateMe.Width/2, rotateMe.Height/2); //set the rotation point as the center into the matrix 
     g.RotateTransform(angle);          //rotate 
     g.TranslateTransform(-rotateMe.Width/2, -rotateMe.Height/2); //restore rotation point into the matrix 
     g.DrawImage(rotateMe, new Point(0, 0));       //draw the image on the new bitmap 
    } 

    return rotatedImage; 
} 
private static Bitmap ResizeImage(System.Drawing.Image image, int width, int height) 
{ 
    var destRect = new Rectangle(0, 0, width, height); 
    var destImage = new Bitmap(width, height); 

    destImage.SetResolution(image.HorizontalResolution, image.VerticalResolution); 

    using (var graphics = Graphics.FromImage(destImage)) 
    { 
     //graphics.CompositingMode = CompositingMode.SourceCopy; 
     //graphics.CompositingQuality = CompositingQuality.HighQuality; 
     //graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; 
     //graphics.SmoothingMode = SmoothingMode.HighQuality; 
     //graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; 
     graphics.InterpolationMode = InterpolationMode.NearestNeighbor; 
     graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; 
     graphics.SmoothingMode = SmoothingMode.AntiAlias; 

     using (var wrapMode = new ImageAttributes()) 
     { 
      wrapMode.SetWrapMode(WrapMode.TileFlipXY); 
      graphics.DrawImage(image, destRect, 0, 0, image.Width, image.Height, GraphicsUnit.Pixel, wrapMode); 
     } 
    } 

    return destImage; 
} 

回答

0

你可能要考虑计算的宽度和你的旋转物体的高度。

例如:

private void button1_Click(object sender, EventArgs e) 
    { 
     var width = (int) numericUpDown2.Value; 
     var height = (int) numericUpDown3.Value; 
     var angle = (float) numericUpDown1.Value; 
     var size = new Size(width, height); 
     var result = RotatedSettings(angle, size); 
     textBox1.Text = String.Format("{0} x {1}", result.Width, result.Height); 
    } 

    private static Size RotatedSettings(float angle, Size size) 
    { 
     // setup corner values in array 
     var corners = new[] 
     { new PointF(0, 0), 
      new PointF(size.Width, 0), 
      new PointF(0, size.Height), 
      new PointF(size.Width, size.Height)}; 

     // rotate corners 
     var xc = corners.Select(p => Rotate(p, (float)angle).X); 
     var yc = corners.Select(p => Rotate(p, (float)angle).Y); 

     // find the new sizes by subtracting highest from lowest result. 
     var widths = xc as IList<float> ?? xc.ToList(); 
     var newWidth = (int)Math.Abs(widths.Max() - widths.Min()); 
     var heights = yc as IList<float> ?? yc.ToList(); 
     var newHeight = (int)Math.Abs(heights.Max() - heights.Min()); 

     // as we rotate the mid point we need to middle midpoint section and add the outcome to size. 
     var midX = ((size.Width/2) - ((double)newWidth/2)); 
     var midY = ((size.Height/2) - ((double)newHeight/2)); 

     return new Size(newWidth + (int)midX, newHeight + (int)midY); 
    } 

    /// <summary> 
    /// Rotates a point around the origin (0,0) 
    /// </summary> 
    private static PointF Rotate(PointF p, float angle) 
    { 
     // convert from angle to radians 
     var theta = Math.PI * angle/180; 
     return new PointF(
      (float)(Math.Cos(theta) * (p.X) - Math.Sin(theta) * (p.Y)), 
      (float)(Math.Sin(theta) * (p.X) + Math.Cos(theta) * (p.Y))); 
    } 
+0

这将返回一个尺寸不等距比例相匹配。基于完美正方形的等距图像应该宽50%,高25%。它基本上是将图像在z轴上旋转45度(向右旋转/向左旋转),然后沿着x轴旋转-45度(将图像的顶部向后倾斜)。您的方法返回39x39。我的正常旋转实际上正常工作。我知道图像应该是48x24,而这只是“后倾”部分的问题,我通过将高度缩小50%来完成。我不确定是否从您的解决方案中错过了其他内容。 – sraboy

+0

你说得对。我给出了一个解决方案来获得2D旋转的界限。我没有正确阅读这个问题。也许这个线程会帮助你更进一步:http://stackoverflow.com/questions/2163829/how-do-i-rotate-a-picture-in-c-sharp –

+0

一个3D库的例子使用四元数学的3D旋转在GDI。 http://www.codeproject.com/Articles/36868/Quaternion-Mathematics-and-D-Library-with-C-and-G为3D图书馆的例子。 –

相关问题