【问题标题】:GDI Resize Image & Guarantee HeightGDI 调整图像大小和保证高度
【发布时间】:2016-04-26 07:10:17
【问题描述】:

我正在从另一个游戏的标准自上而下图块动态创建等距图块。但是,问题在于图像调整大小通常会导致两侧“丢失”一些像素。我知道它们并没有真正丢失,并且代码工作正常,但我对 GDI 了解不足,无法知道要搜索哪些设置/教程。

我把这个: 变成这个:

它从 32x32 变为 48x24,这是正确的比例。然而,在左侧和底部,草距离图像边缘还差一个像素。我不想手动修复这个问题,因为我会为数百个图块做这个,所以我想找到一种方法来在代码中修复这个问题。最后,问题在于图块之间会出现微小的 1 像素间隙。

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

【问题讨论】:

    标签: c# image-processing gdi+


    【解决方案1】:

    您可能需要考虑计算旋转对象的宽度和高度。

    例如:

        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)));
        }
    

    【讨论】:

    • 这会返回一个与等距比例不匹配的尺寸。基于完美正方形的等距图像的宽度应大 50%,高度应短 25%。它实质上是将图像在 z 轴上旋转 45 度(向右/向左旋转),然后沿 x 轴旋转 -45 度(将图像顶部向后倾斜)。您的方法返回 39x39。我的正常旋转实际上工作正常。我知道图像应该是 48x24,它只是“向后倾斜”部分的问题,我通过将高度缩小 50% 来做到这一点。我不确定我是否遗漏了您的解决方案中的其他内容。
    • 你是对的。我给出了一个解决方案来获得 2D 旋转的界限。我没有正确阅读问题。也许这个帖子会对你有所帮助:stackoverflow.com/questions/2163829/…
    • 在 GDI 中使用四元数数学进行 3D 旋转的 3D 库示例。 codeproject.com/Articles/36868/… 用于 3D 库示例。
    • 非常感谢。如果我得到解决方案,我会花一些时间来研究这些并更新。
    猜你喜欢
    • 2013-11-28
    • 1970-01-01
    • 2011-02-21
    • 1970-01-01
    • 2015-05-22
    • 2013-04-28
    • 1970-01-01
    • 2016-03-30
    • 2013-09-14
    相关资源
    最近更新 更多