图像未绘制在正确的位置

Image is not drawn at the correct spot

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)。 另外,我需要黑色背景。

那么,这是怎么回事,如何解决这个问题?

我不是很清楚你到底需要做什么。但无论如何,这是一个 WPF 友好示例,说明如何在另一个图像内的特定位置绘制图像。

请注意,如果您只想以不同尺寸显示图像 and/or 在其周围放置黑色边框,有更简单的方法可以做到这一点,而无需创建第二张图像,例如就像在已经具有您想要的边框样式的面板中布置图像一样。

请注意,我正在使用 System.Windows.Media 命名空间中的 classes,因为 WPF 就是使用它。这些不容易与来自 System.Drawing 命名空间的旧 classes 混合(一些 class 名称冲突,并且 Microsoft 的 .Net 框架缺少在这些类型之间转换对象的内置方法), 所以通常需要简单地决定是使用一套还是另一套绘图工具。我假设您一直在尝试使用 System.Drawing。每个都有自己的优点和缺点,在这里解释起来会花费太多时间。

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

您正在加载图像,然后使用以下方法创建此源的副本:
Bitmap bitmap = new Bitmap();

当您以这种方式创建图像副本时,您 sacrifice/alter 一些细节:
Dpi Resolution:如无特殊说明,分辨率设置为UI分辨率。 96 Dpi,作为标准;不同的屏幕分辨率和缩放比例可能会有所不同。使用的系统也会影响此值(Windows 7 和 Windows 10 将 probably/possibly 提供不同的值)
PixelFormat:如果不是直接从Image源复制或明确指定,则PixelFormat设置为PixelFormat.Format32bppArgb

从你所说的来看,你可能想要这样的东西:

using (Bitmap imageSource = (Bitmap)Image.FromFile(@"[SomeImageOfLena]"))
using (Bitmap imageCopy = new Bitmap(imageSource.Width + 100, imageSource.Height, imageSource.PixelFormat))
{
    imageCopy.SetResolution(imageSource.HorizontalResolution, imageSource.VerticalResolution);
    using (Graphics 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 = (Image)imageSource.Clone();
        pictureBox2.Image = (Image)imageCopy.Clone();
    }
}

这是结果:
(upper/lower边框黑色实际上是Picturebox背景色)


当原始图像 Dpi 分辨率与使用 new Bitmap() 创建图像副本时使用的基本 Dpi 分辨率不同时,您的结果可能与预期不同。

这是同一场景下 150、96 和 72 Dpi 的源图像所发生的情况:


另一个重要的细节是 IDisposable Image 对象的性质。
创建一个时,您必须 Dispose() of it; explicitly, calling the Dispose method, or implicitly, enclosing the Image contructor in a Using statement.

此外,可能不要分配直接从 FileStream 加载的 Image 对象。
GDI+ 将锁定文件,您将无法复制、移动或删除它。
使用该文件,与图像相关的所有资源也将被锁定。

使用 new Bitmap() 制作副本(如果您不关心上述细节),或使用 Image.Clone() 制作副本,这将保留图像 Dpi ResolutionPixelFormat.