GDI Resize Image&保证高度

时间:2016-01-20 12:25:53

标签: c# image-processing gdi+

我正在从另一款游戏的标准自顶向下瓷砖动态创建等距瓷砖。但问题是,图像调整大小通常会导致两侧的某些像素“丢失”。我知道他们并没有真正丢失并且代码工作正常但我对GDI知之甚少,无法知道要搜索的设置/教程。

我接受这个:enter image description here并将其转换为:enter image description here

从32x32到48x24,这是正确的比例。然而,在左侧和底部,草是到达图像边缘的一个像素。我不想手动修复此问题,因为我将为数百个磁贴执行此操作,因此我想在代码中找到解决此问题的方法。最后,问题是瓷砖最终会在它们之间留下微小的一个像素间隙。

除了仅检查每个图像的边缘颜色并手动添加它们(如果它们缺失/透明)之外,我能用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;
}

1 个答案:

答案 0 :(得分: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)));
    }