【问题标题】:Can't resize the changed image? C# WinForms无法调整更改后的图像大小? C# WinForms
【发布时间】:2012-01-23 04:26:20
【问题描述】:

如果我更改图像的颜色然后尝试调整大小,它只会调整原始图像的大小。为什么会发生这种情况,我该如何解决?

这是我的代码:

private PrintDocument printDoc = new PrintDocument();
private PageSettings pgSettings = new PageSettings();
private PrinterSettings prtSettings = new PrinterSettings();

Bitmap myBitmapImage;      // image (bitmap) for some background mountains
Boolean isInvert = false;
Boolean isLOaded = false;
Boolean isGrayscale = false;
Boolean isThreshold = false;
Boolean isResize = false;

OpenFileDialog ofd;
Bitmap bmBack; 

public EditImage()
{
    printDoc.PrintPage += new PrintPageEventHandler(printDoc_PrintPage); 

    InitializeComponent();
    this.SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint | ControlStyles.DoubleBuffer, true);
}

private void EditImage_Load(object sender, EventArgs e)
{

}

private void EditImage_Paint(object sender, PaintEventArgs e)
{
    if (isLOaded == true)
    {
        Graphics gWindow;   // reference to the graphic surface of this window
        Graphics gBack;     // reference to in-memory surface

        bmBack = new Bitmap(Width, Height);     // bitmap for window surface copy

        gWindow = e.Graphics;   // get our current window's surface
        gBack = Graphics.FromImage(bmBack);     // create surfaces from the bitmaps

        gBack.DrawImage(myBitmapImage, 0, 0, Width, Height);

        if (isInvert == true)
        {
            InvertBitmap(bmBack);
        }
        else if (isGrayscale == true)
        {
            GrayscaleBitmap(bmBack);
        }
        else if (isThreshold == true)
        {
            ThresholdBitmap(bmBack);
        }
        else if (isResize == true)
        {
            bmBack = resizeImage(bmBack, 10, 100);
        }

        gWindow.DrawImage(bmBack, 0, 0);
    }
}
private void toolStripMenuItemLoadImage_Click(object sender, EventArgs e)
{
    using (ofd = new OpenFileDialog())
    {
        ofd.Title = "Load Image";

        if (ofd.ShowDialog() == DialogResult.OK)
        {
            myBitmapImage = new Bitmap(ofd.FileName);
            this.Invalidate(); 
        }
    }
    isLOaded = true;
}


private void GrayscaleBitmap(Bitmap bmp)
{
    Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
    System.Drawing.Imaging.BitmapData bmpData = bmp.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite,
        System.Drawing.Imaging.PixelFormat.Format32bppRgb);

    IntPtr ptr = bmpData.Scan0;

    int numPixels = bmpData.Width * bmp.Height;
    int numBytes = numPixels * 4;
    byte[] rgbValues = new byte[numBytes];

    System.Runtime.InteropServices.Marshal.Copy(ptr, rgbValues, 0, numBytes);

    for (int i = 0; i < rgbValues.Length; i += 4)
    {
        byte gray = (byte)(.3 * rgbValues[i + 0]); //blue
        gray += (byte)(.59 * rgbValues[i + 1]); //green
        gray += (byte)(.11 * rgbValues[i + 2]); //red

        rgbValues[i + 0] = gray; //blue
        rgbValues[i + 1] = gray; //green
        rgbValues[i + 2] = gray; //red
    }

    System.Runtime.InteropServices.Marshal.Copy(rgbValues, 0, ptr, numBytes);

    bmp.UnlockBits(bmpData);
}

private  Bitmap resizeImage(Bitmap sourceBMP, int width, int height)
{
    Bitmap result = new Bitmap(width, height);
    using(Graphics g = Graphics.FromImage(result))
    g.DrawImage(sourceBMP, 0, 0, width, height);

    return result;
}

我还有一些方法可以处理用户单击按钮并将布尔值设置为适当的值,以便它调用正确的方法。图像确实会改变颜色 - 正如预期的那样......但是当我点击调整大小时,我希望它调整已经改变颜色的图像版本 - 而不是原始图像......

【问题讨论】:

    标签: c# .net winforms


    【解决方案1】:

    这里有很多问题:

    resizeImage()

    • 您应该处理您在此处创建的 Graphics 对象(将其包装在 using() 语句中)
    • 不要从这里调用 invalidate,这个函数只是调整你的图像大小,你在改变你的图像并且你的 Paint 方法绘制现在已经改变的图像之后就会失效。
    • 如果您不再使用该函数,您还应该考虑在返回该函数之前立即处理它。

    灰度位图()

    • 这看起来是对的,但同样没有理由在这里无效。在调用函数中调用此方法后,您应该使该方法无效。这更有意义。

    EditImage_Paint

    • 不应在 Paint 事件中调用这些函数。而且你不应该在每个 Paint 上创建一个新的 Bitmap 和一个新的 Graphics 类。这比必要的工作多得多。只有当需要根据用户输入更改数据(用户单击按钮以应用灰度效果)时,才应执行这些函数。

    对于您想要做的事情,您最多只需要 2 个位图变量。一种存储原始未修改的位图,以防您想让用户“重置”它或撤消任何效果(大多数效果会导致永久性数据丢失,您无法再次制作灰度图像颜色)。另一个用于存储绘制的位图。用户每次应用效果,都会修改第二张位图,然后调用invalidate。

    您的 Paint 函数应该做的就是绘制第二个位图:

    Bitmap originalBitmap; // load from file, do not modify
    Bitmap currentBitmap; // when user clicks an effect, modify this bitmap and then Invalidate afterward
    
    private void EditImage_Paint(object sender, PaintEventArgs e)
    {
        e.Graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
    
        // Draw the currentBitmap centered on the window
        SizeF clientSize = this.ClientSize;
    
        double zoomRatio = Math.Min(
            clientSize.Width / currentBitmap.Width,
            clientSize.Height / currentBitmap.Height
        );
    
        SizeF zoomedSize = new SizeF(
            (float)(currentBitmap.Width * zoomRatio),
            (float)(currentBitmap.Height * zoomRatio)
        );
    
        PointF imageOffset = new PointF(
            (clientSize.Width - zoomedSize.Width) / 2,
            (clientSize.Height - zoomedSize.Height) / 2
        );
    
        e.Graphics.Clear(Color.White);
        e.Graphics.DrawImage(currentBitmap, imageOffset.X, imageOffset.Y, zoomedSize.Width, zoomedSize.Height);
    }
    

    这模拟了一个简单的缩放效果,将图像放在控件的中心并绘制它以适应窗口。

    【讨论】:

    • 谢谢,所以我已经做了你建议的所有改变......除了我不明白如何修复我的绘画方法......你能给我一个我会如何做的例子吗?
    • 更新了一个你可以做什么的例子。
    • 嗯,似乎“RectangleF clientSize = this.ClientSize;”不起作用...我也不能强制转换值..它说我不能将类型 System.Windows.Forms.Form 隐式转换为 System.Frawing.RectangleF..
    • 糟糕,应该是 SizeF。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-21
    • 1970-01-01
    • 1970-01-01
    • 2018-06-07
    • 2014-09-01
    相关资源
    最近更新 更多