winforms 未在正确的点绘制图像

m3eecexj  于 2022-11-16  发布在  其他
关注(0)|答案(2)|浏览(128)
Bitmap image = ReadBitmap("image.png");
Bitmap imageCopy = new Bitmap(image);
Bitmap canvas = new Bitmap(imageCopy.Width+100, imageCopy.Height);

// From this bitmap, the graphics can be obtained, because it has the right PixelFormat
using(Graphics g = Graphics.FromImage(canvas))
{
    // Draw the original bitmap onto the graphics of the new bitmap
    g.DrawImage(image, 0, 0);
}

// Use tempBitmap as you would have used originalBmp
InputPictureBox.Image = image;
OutputPictureBox.Image = canvas;

我还没有理解这个c#代码的输出。
原始图像没有放在正确的位置。它应该在(0, 0)。另外,我需要一个黑色的背景。
那么,这是怎么回事?如何纠正这一点?

zdwk9cvp

zdwk9cvp1#

您正在加载映像,然后使用以下内容创建此源的副本:
Bitmap bitmap = new Bitmap();
当您以这种方式创建映像的副本时,您会牺牲/更改一些细节:

Dpi Resolution:如果没有另外指定,则将分辨率设置为UI分辨率.96dpi作为标准;使用的系统也会影响此值(Windows 7和Windows 10可能会提供不同的值)
PixelFormat:如果没有直接从Image源复制或显式指定,则PixelFormat设置为PixelFormat.Format32bppArgb

听你说的,你可能想要这样的东西:

var imageSource = Image.FromStream(new MemoryStream(File.ReadAllBytes(@"[SomeImageOfLena]"))), true, false)
var imageCopy = new Bitmap(imageSource.Width + 100, imageSource.Height, imageSource.PixelFormat))

imageCopy.SetResolution(imageSource.HorizontalResolution, imageSource.VerticalResolution);
using (var g = Graphics.FromImage(imageCopy)) {
    g.Clear(Color.Black);
    g.CompositingMode = CompositingMode.SourceCopy;
    g.InterpolationMode = InterpolationMode.HighQualityBicubic;
    g.DrawImage(imageSource, (imageCopy.Width - imageSource.Width) / 2, 0);

    pictureBox1.Image?.Dispose();
    pictureBox2.Image?.Dispose();
    pictureBox1.Image = imageSource;
    pictureBox2.Image = imageCopy;
}

这就是结果:
(The上/下框架黑色实际上是Picturebox背景色)

如果原始图像Dpi分辨率与使用new Bitmap()创建图像副本时使用的基本Dpi分辨率不同,则结果可能与预期不同。
这是在相同情况下,150、96和72 Dpi的源图像所发生的情况:

另一个重要的细节是Image对象的IDisposable特性。
当你创建一个,你必须Dispose()它;显式调用Dispose方法,或隐式将Image构造函数包含在Using statement中。
此外,可能不要分配直接从FileStream加载的Image对象。
GDI+将锁定该文件,您将无法复制、移动或删除它。
使用该文件时,与图像关联的所有资源也将被锁定。
使用new Bitmap()(如果您不关心上述细节)或Image.Clone()进行复制,这将保留图像Dpi ResolutionPixelFormat

o8x7eapl

o8x7eapl2#

我不完全清楚您实际需要做什么。但无论如何,这里是一个WPF友好的示例,说明如何在另一个图像内的特定位置绘制图像。
请注意,如果您只想以不同的大小显示图像和/或在其周围添加黑色边框,则有更简单的方法可以做到这一点,而不必创建第二个图像,例如,只需在已经具有所需边框样式的面板中布局图像。
请注意,我使用的是System.Windows.Media命名空间中的类,因为WPF使用的是这个命名空间。(某些类名冲突,并且Microsoft的.Net框架缺少在这些类型之间转换对象的内置方法),因此通常只需要简单地决定是使用其中一组绘图工具还是使用另一组绘图工具。每一种都有自己的优点和缺点,在这里解释太长了。

// using System.Windows.Media;
// using System.Windows.Media.Imaging;
private void DrawTwoImages()
{
    // For InputPictureBox
    var file = new Uri("C:\\image.png");
    var inputImage = new BitmapImage(file);
        // If your image is stored in a Resource Dictionary, instead use:
        //     var inputImage = (BitmapImage) Resources["image.png"];
    InputPicture.Source = inputImage;

    // imageCopy isn't actually needed for this example.
    // But since you had it in yours, here is how it's done, anyway.
    var imageCopy = inputImage.Clone();

    // Parameters for setting up our output picture
    int leftMargin   = 50;
    int topMargin    = 5;
    int rightMargin  = 50;
    int bottomMargin = 5;
    int width  = inputImage.PixelWidth  + leftMargin + rightMargin;
    int height = inputImage.PixelHeight + topMargin  + bottomMargin;
    var backgroundColor = Brushes.Black;
    var borderColor = (Pen) null; 

    // Use a DrawingVisual and DrawingContext for drawing
    DrawingVisual dv = new DrawingVisual();
    using (DrawingContext dc = dv.RenderOpen())
    {
        // Draw the black background
        dc.DrawRectangle(backgroundColor, borderColor, new Rect(0, 0, width, height));

        // Copy input image onto output image at desired position
        dc.DrawImage(inputImage, new Rect(leftMargin, topMargin,
                     inputImage.PixelWidth, inputImage.PixelHeight));
    }

    // For displaying output image
    var rtb = new RenderTargetBitmap( width, height, 96, 96, PixelFormats.Pbgra32 );
    rtb.Render(dv);
    OutputPicture.Source = rtb;
}

相关问题