没有在正确的位置绘制图像

时间:2018-07-21 06:45:19

标签: c# winforms image-processing

        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;   

enter image description here

我不了解此C#代码的输出。

原始图像未放置在正确的位置。应该是(0,0)。

我还需要黑色背景。

那么,怎么回事以及如何纠正呢?

2 个答案:

答案 0 :(得分:3)

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

以这种方式创建图像副本时,您会牺牲/更改一些细节:
Dpi Resolution :如果未另行指定,则将分辨率设置为UI分辨率。标准为96 Dpi;不同的屏幕分辨率和缩放比例可能会有所不同。使用中的系统也会影响此值(Windows 7和Windows 10可能/可能会提供不同的值)
PixelFormat :如果未直接从图像源复制或未明确指定,则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();
    }
}

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

enter image description here

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

在相同的情况下,源图像为150、96和72 Dpi时会发生以下情况:

enter image description here

另一个重要的细节是Image对象的IDisposable性质。
创建一个时,您必须Dispose()个它;显式地调用Dispose方法,或隐式地将Image构造器包含在Using statement中。

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

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

答案 1 :(得分:0)

我不清楚您实际上需要做什么。但是无论如何,这是一个WPF友好示例,说明了如何在另一张图像内的特定位置绘制图像。

请注意,如果您要做的只是显示不同大小的图像和/或在其周围放置黑色边框,则有许多更简单的方法可以简单地做到这一点,而不必创建第二个图像,例如只是布局面板中的图像已经具有所需的边框样式。

请注意,我正在使用System.Windows.Media命名空间中的类,因为这是WPF使用的。这些不容易与System.Drawing命名空间中的旧类混合使用(某些类名称冲突,并且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;
}