图像未绘制在正确的位置
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 Resolution
和 PixelFormat
.
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 Resolution
和 PixelFormat
.