7个月前,我们开始学习C#和WPF,并且,由于所有想要进行图像处理的新手,我们都遇到了这个问题:
为什么会有位图和位图源?每种都有什么优势?
在我们的项目中,我们必须根据数据生成位图。速度对我们非常重要。
我们从Bitmap开始,因为它比较容易(经验丰富的方法:get/setpixel),并且有很多示例,有据可查。但是后来我们发现了WPF中转换问题以打印位图。
所以我们尝试使用BitmapSource,由于像素格式不同,这并不容易。但是我们最终成功了。
我们比较了每一代的速度。使用SetPixel(Bitmap)的速度比使用字节数组(BitmapSource)的速度要慢得多,但是使用字节数组意味着复杂:步幅,像素格式...
因此,可以肯定的是,我们选择了BitmapSource。但是随后我们想序列化一些BitmapSource。 BitmapSource不可序列化。因此,使用[OnSerializing] [OnDeserialized],我们将BitmapSource转换为Bitmap(可序列化)。
我们的结论是:
位图的优点:
BitmapSource的优点:
您是否看到其他几点?
为了说明问题,对于像我们这样的新手,这里有一些我们需要的有用方法:
转换 :
public static System.Windows.Media.Imaging.BitmapSource BitmapToBitmapSource(System.Drawing.Bitmap source)
{
using (MemoryStream memory = new MemoryStream())
{
source.Save(memory, ImageFormat.Png);
memory.Position = 0;
BitmapImage bitmapImage = new BitmapImage();
bitmapImage.BeginInit();
bitmapImage.StreamSource = memory;
bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
bitmapImage.EndInit();
return bitmapImage;
}
}
public static System.Drawing.Bitmap BitmapFromSource(BitmapSource source)
{
using (MemoryStream outStream = new MemoryStream())
{
BitmapEncoder enc = new PngBitmapEncoder();
enc.Frames.Add(BitmapFrame.Create(source));
enc.Save(outStream);
System.Drawing.Bitmap bitmap = new System.Drawing.Bitmap(outStream);
// return bitmap; <-- leads to problems, stream is closed/closing ...
return new Bitmap(bitmap);
}
}
不带锁的图像打开:
public static BitmapImage LoadImage(string uri)
{
BitmapImage monImage = null;
if (uri != null)
{
BitmapImage image = new BitmapImage();
using (FileStream stream = File.OpenRead(uri))
{
image.BeginInit();
image.CacheOption = BitmapCacheOption.OnLoad;
image.StreamSource = stream;
image.EndInit();
}
monImage = image;
}
return monImage;
}
调整BitmapSource的大小:
public static BitmapImage BitmapImageFromBitmapSourceResized(BitmapSource bitmapSource, int newWidth)
{
BmpBitmapEncoder encoder = new BmpBitmapEncoder();
MemoryStream memoryStream = new MemoryStream();
BitmapImage bImg = new BitmapImage();
encoder.Frames.Add(BitmapFrame.Create(bitmapSource));
encoder.Save(memoryStream);
bImg.BeginInit();
bImg.StreamSource = new MemoryStream(memoryStream.ToArray());
bImg.DecodePixelWidth = newWidth;
bImg.EndInit();
memoryStream.Close();
return bImg;
}
一代 :
public static int GetBytesPerPixel(BitmapSource bmp)
{
return (bmp.Format.BitsPerPixel + 7) / 8;
}
public static int GetStrideFromeBitmapSource(BitmapSource bmp)
{
return 4 * ((bmp.PixelWidth * GetBytesPerPixel(bmp) + 3) / 4);
}
public static byte[] GetBytesFromBitmapSource(BitmapSource bmp)
{
int height = bmp.PixelHeight;
int stride = GetStrideFromeBitmapSource(bmp);
byte[] pixels = new byte[height * stride];
bmp.CopyPixels(pixels, stride, 0);
return pixels;
}
public static int GetWidth(int stride, int bytesPerPixel)
{
int width = (int)(
(float)stride
/ (float)bytesPerPixel
);
return width;
}
public static int GetHeight(byte[] bits, int stride)
{
int height = (int)(
(float)bits.Length
/ (float)stride
);
return height;
}
public static void SetPixelRgb24(ref byte[] bits, int x, int y, int stride, Color c)
{
bits[x * 3 + y * stride] = c.R;
bits[x * 3 + y * stride + 1] = c.G;
bits[x * 3 + y * stride + 2] = c.B;
}
public static void SetPixelBgra32(ref byte[] bits, int x, int y, int stride, Couleur c)
{
bits[x * 4 + y * stride + 0] = c.B;
bits[x * 4 + y * stride + 1] = c.G;
bits[x * 4 + y * stride + 2] = c.R;
bits[x * 4 + y * stride + 3] = c.A;
}
public static int GetAverageValueOfPixel(ref byte[] bits, int x, int y, int stride, int bytesPerPixel)
{
int sum = 0;
for (var i = 0; i < bytesPerPixel; i++)
sum += bits[x * bytesPerPixel + y * stride + i];
return (int)
(
sum
* (255f / (255f * bytesPerPixel))
);
}
快照到BitmapSource:
public static BitmapSource SnapShotToBitmap(this UIElement source, double zoomX, double zoomY)
{
try
{
DataObject dataObject = new DataObject();
double actualHeight = source.RenderSize.Height;
double actualWidth = source.RenderSize.Width;
if (actualHeight == 0)
actualHeight = 1;
if (actualWidth == 0)
actualWidth = 1;
double renderHeight = actualHeight * zoomY;
double renderWidth = actualWidth * zoomX;
RenderTargetBitmap renderTarget = new RenderTargetBitmap((int)renderWidth, (int)renderHeight, 96, 96, PixelFormats.Pbgra32);
VisualBrush sourceBrush = new VisualBrush(source);
DrawingVisual drawingVisual = new DrawingVisual();
DrawingContext drawingContext = drawingVisual.RenderOpen();
using (drawingContext)
{
drawingContext.PushTransform(new ScaleTransform(zoomX, zoomY));
drawingContext.DrawRectangle(sourceBrush, null, new Rect(new Point(0, 0), new Point(actualWidth, actualHeight)));
}
renderTarget.Render(drawingVisual);
return renderTarget;
}
catch (Exception e)
{
throw new Exception(e);
}
}
最佳答案
我只想说Bitmap实际上提供了一种通过LockBits method of Bitmap进行像素操纵的超快方法。如果要通过手动设置像素来创建位图,这是最快的方法之一。请注意,BitmapSource使用WIC,而Bitmap使用GDI +。因此,加载或复制像素数据数组应该没有任何区别(或最好是边际),并且Bitmapsource或Bitmap都不是好处。
我还要在Bitmaps方面添加支持,因为它是一个非常老的结构,许多库都接受Bitmap进行编辑。
我对BitmapSource看到的唯一好处是,它是WPF中图像的源,并且可以方便地使用。
关于c# - 位图源与位图,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/24885977/