C# GDI+ ScaleTransform 在 picturebox 上正常,但保存的图像是原始图像

C# GDI+ ScaleTransform ok on picturebox but image saved is original

您好,我有一个问题,当我使用 ScaleTransform(zoomFactor,zoomFactor) 时,保存在磁盘上的图像始终是原始版本,而在屏幕上的 picturebox 中,图像与 zoomFactor 成比例地扭曲。 为什么会这样?我不应该在磁盘写入映像上应用 e.Graphics 的最终结果吗?

我的代码如下,是矩阵版本。但是我也使用了 ScaleTransform 而不是矩阵。结果总是一样的:

                g=e.Graphics;//inside picturebox_paint()
                g.ScaleTransform(ratio * zoomFac, ratio * zoomFac);
                e.Graphics.DrawImage((Bitmap)bmp, 0, 0);
                int seed = Convert.ToInt32(Regex.Match(Guid.NewGuid().ToString(), @"\d+").Value);
                String destinationFile = @"C:\tmp\photoid\" + new Random(seed).Next() + "_conv.jpg";
//Here I get always the original image back!!!!
                bmp.Save(destinationFile);

我也使用了以下成语,但结果相同:

            //Matrix matrix = new Matrix();
            //matrix.Scale(zoomFac, zoomFac);
            //e.Graphics.Transform = matrix;                                            

自从我弄乱 GDI 以来已经有一段时间了,但我认为您需要在此处复制回位图。

g.DrawImage(bmp, scaledwidth, scaledheight);

在bmp.Save

之前尝试类似的东西

编辑 很抱歉没有看到您正在复制回位图。也许指定输出矩形的重载就是您所需要的。尝试具有目标 Rect 的 DrawImage 重载。 https://msdn.microsoft.com/en-us/library/ms142040(v=vs.110).aspx

您需要让 PictureBox 将它在屏幕上显示的内容绘制成 位图,然后您可以保存它!

因为它是 Image 将以原始形式保存,而你在 Paint 事件中所做的任何事情,实际上绘制到 PictureBox 的表面都将被保存.

所以要保存所有内容,即 Image,可能是 BackgroundImage 以及您在 Paint 事件中绘制的所有内容,您会调用 DrawToBitmap somehwere。

Somewhere 表示某处 else,不在 Paint 事件中,因为它将调用 Paint事件创建新的 Bitmap,导致无限循环..

要调用它,您需要这样做:

Bitmap bmpSave = new Bitmap(pictureBox1.ClientSize.Width, pictureBox1.ClientSize.Height);
pictureBox1.DrawToBitmap(bmpSave, pictureBox1.ClientRectangle);

但这也许不是你真正想要的?也许你真的想修改Image?在这种情况下,不要 使用 Paint 事件!

而是做这样的事情:

Bitmap bmpSave = new Bitmap(yourNewWidth, yourNewHeight);
using (Graphics g = Graphics.FromImage(bmpSave))
{
    g.ScaleTransform(ratio * zoomFac, ratio * zoomFac);
    g.DrawImage((Bitmap)pictureBox1.Image, 0, 0);  // 
    pictureBox1.Image = bmpSave;
    bmpSave.Save(...);
}

您可以从触发缩放的地方调用它。

请注意,每次从以前的缩放版本重复缩放会相当快地降低质量。为此,请始终从原始版本的保存版本进行缩放!!

顺便说一句:使用 Matrix 进行缩放并没有真正对 ScaleTransform 产生影响。

但是如果你想直接缩放为什么不使用需要 two RectanglesDrawImage 重载?这是最常见的解决方案,如果你想要缩放并可能另外绘制其他东西..:[=​​36=]

int newWidth = 100; int newHeight = 100; string yourFileName = "D:\xyz123.jpg";

Bitmap bmpSave = new Bitmap(pictureBox1.ClientSize.Width, pictureBox1.ClientSize.Height);
Rectangle newRectangle = new Rectangle(0, 0, newWidth, newHeight);
Rectangle oldRectangle = new Rectangle(Point.Empty, pictureBox1.Image.Size);
using (Graphics g = Graphics.FromImage(bmpSave))
{
    g.DrawImage((Bitmap)pictureBox1.Image, newRectangle, oldRectangle, GraphicsUnit.Pixel);
    bmpSave.Save(yourFileName, ImageFormat.Jpeg);
} 

还有缩放 Bitmap 构造函数:

Bitmap bmp = new Bitmap(pictureBox1.Image, newWidth, newHeight);

如果您只想缩放 Image,我会推荐它。与其他解决方案一样,它不会更改显示的 Image,直到您将其分配回 PictureBox..:[=​​36=]

pictureBox1.Image = bmp ;

不要忘记处理旧图像..