Image帮助类
快速读取图像文件的高度和宽度
WPF
引用库System.Windows.Media,常用于WPF程序。
using PresentationCore;
using System.Windows.Media;
/// <summary>
/// 快速读取图像文件的高度和宽度
/// </summary>
/// <param name="fileName"></param>
/// <returns></returns>
public static string GetImageSize(string fileName)
{
try
{
using (var stream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read))
{
var frame = System.Windows.Media.Imaging.BitmapFrame.Create(stream, System.Windows.Media.Imaging.BitmapCreateOptions.DelayCreation, System.Windows.Media.Imaging.BitmapCacheOption.None);
var width = frame.PixelWidth;
var height = frame.PixelHeight;
return $"{width}*{height}";
}
}
catch (Exception ex)
{
Console.WriteLine("图片格式异常:" + ex.Message);
return string.Empty;
}
}
Winform
Bitmap.FromFile
using (var image = Bitmap.FromFile(filePath))
{
int width = image.Width;
int height = image.Height;
}
三方库 MetadataExtractor
GuGet引入第三方库 MetadataExtractor

var metadata = ImageMetadataReader.ReadMetadata(filePath);
foreach (var directory in metadata)
{
foreach (var tag in directory.Tags)
{
Console.WriteLine($"[{directory.Name}]{tag.Name} = {tag.Description}");
}
}
获取宽与高
var meta = ImageMetadataReader.ReadMetadata(filePath);
// JPG
var jpg = meta.OfType<MetadataExtractor.Formats.Jpeg.JpegDirectory>().FirstOrDefault();
if (jpg != null)
{
var width = jpg.GetImageWidth();
var height = jpg.GetImageHeight();
Console.WriteLine($"{i} {width} * {height}");
}
// PNG
var png = meta.OfType<MetadataExtractor.Formats.Png.PngDirectory>().FirstOrDefault();
if (png != null)
{
var width = png.GetString(BmpHeaderDirectory.TagImageWidth);
var height = png.GetString(BmpHeaderDirectory.TagImageHeight);
Console.WriteLine($"{i} {width} * {height}");
}
// BMP
var bmp = meta.OfType<MetadataExtractor.Formats.Bmp.BmpHeaderDirectory>().FirstOrDefault();
if (bmp != null)
{
var width = bmp.GetString(BmpHeaderDirectory.TagImageWidth);
var height = bmp.GetString(BmpHeaderDirectory.TagImageHeight);
Console.WriteLine($"{i} {width} * {height}");
}
其他格式的获取方式类似,Tiff、WebP等。
自定义
一般文件的开头存储有相关信息,可以把图片当成文件进行处理,根据相关协议进行解析。

/// <summary>
/// 快速获取图片的大小
/// </summary>
/// <param name="filePath">图片路径</param>
/// <returns></returns>
public static Size GetImageSize(string filePath)
{
Size rslt = new Size();
string type = "UNKNOWN";
if (!File.Exists(filePath))
{
return rslt;
}
using (var stream = File.OpenRead(filePath))
{
using (var reader = new BinaryReader(stream, Encoding.UTF7, false))
{
var c1 = reader.ReadChar();
var c2 = reader.ReadChar();
var c3 = reader.ReadChar();
if (c1 == 0xFF && c2 == 0xD8)
{
type = "JPG";
while (c3 == 0xFF)
{
int marker = reader.Read();
var data = reader.ReadBytes(2);
int len = BigEndianByte2Int(data);
if (marker == 192 || marker == 193 || marker == 194)
{
reader.BaseStream.Position += 1;
data = reader.ReadBytes(2);
rslt.Height = BigEndianByte2Int(data);
data = reader.ReadBytes(2);
rslt.Width = BigEndianByte2Int(data);
break;
}
reader.BaseStream.Position += len - 2;
c3 = reader.ReadChar();
}
}
else if (c2 == 'P' && c3 == 'N')
{
type = "PNG";
reader.BaseStream.Position += 15;
var data = reader.ReadBytes(2);
rslt.Width = BigEndianByte2Int(data);
reader.BaseStream.Position += 2;
data = reader.ReadBytes(2);
rslt.Height = BigEndianByte2Int(data);
}
else if (c1 == 'B' && c2 == 'M')
{
type = "BMP";
reader.BaseStream.Position += 15;
var data = reader.ReadBytes(2);
rslt.Width = LittleEndianByte2Int(data);
reader.BaseStream.Position += 2;
data = reader.ReadBytes(2);
rslt.Height = LittleEndianByte2Int(data);
}
else if (c1 == 'G' && c2 == 'I' && c3 == 'F')
{
type = "GIF";
reader.BaseStream.Position += 3;
var data = reader.ReadBytes(2);
rslt.Width = LittleEndianByte2Int(data);
data = reader.ReadBytes(2);
rslt.Height = LittleEndianByte2Int(data);
}
else if (c1 == 'R' && c2 == 'I' && c3 == 'F')
{
type = "WebP";
reader.BaseStream.Position += 23;
var data = reader.ReadBytes(2);
rslt.Width = LittleEndianByte2Int(data);
data = reader.ReadBytes(2);
rslt.Height = LittleEndianByte2Int(data);
}
else
{
var data = File2Bytes(filePath);
Console.WriteLine(Byte2HexStringX2(true, data));
}
}
}
Console.WriteLine($"{type} {rslt.Width}(Width) * {rslt.Height}(Height)");
return rslt;
}
其中,字节转换可以参考其他博客的BigEndianByte2Int,Byte2HexStringX2
耗时对比
循环运行100次,各自所需时间如图所示,自定义时间是最短的,毫秒级别。

图片生成指定质量的流
/// <summary>
/// 图片生成指定质量的流
/// </summary>
/// <param name="encoder">图片编码</param>
/// <param name="quality">图片质量</param>
/// <returns></returns>
public Stream ToStream(ImageCodecInfo encoder, int quality)
{
var myEncoder = Encoder.Quality;
var myEncoderParameters = new EncoderParameters(1);
var myEncoderParam = new EncoderParameter(myEncoder, quality);
myEncoderParameters.Param[0] = myEncoderParam;
var rslt = new MemoryStream();
_bitmap.Save(rslt, encoder, myEncoderParameters);
return rslt;
}
图片一般帮助类
/// <summary>
/// 图片一般帮助类
/// </summary>
public partial class ImageHelper : IDisposable
{
readonly string _fileName;
Bitmap _bitmap;
/// <summary>
/// 图片所指位图
/// </summary>
public Bitmap SourceBitmap
{
get { return _bitmap; }
}
public ImageHelper(string fileName)
{
if (string.IsNullOrEmpty(fileName))
{
throw new ArgumentNullException(fileName, "fileName is NULL!");
}
if (!File.Exists(fileName))
{
throw new NotImplementedException("the image is not exist!!");
}
_fileName = fileName;
_bitmap = new Bitmap(fileName);
}
public ImageHelper(Image img)
{
_bitmap = (Bitmap)img;
_fileName = string.Empty;
}
public ImageHelper(Stream stream)
{
_bitmap = (Bitmap)Image.FromStream(stream);
_fileName = string.Empty;
}
public byte[] ToBytes(string extension)
{
return ToBytes(GetFormat(extension));
}
public byte[] ToBytes(ImageFormat imageFormat)
{
using var ms = new MemoryStream();
_bitmap.Save(ms, imageFormat);
return ms.ToArray();
}
public void DrawRectangles(Color color, RectangleF[] rects)
{
if (rects == null)
{
return;
}
var pen = new Pen(color, 5);
using Graphics g = Graphics.FromImage(_bitmap);
g.DrawRectangles(pen, rects);
}
public void DrawRectangle(Color color, Rectangle rect)
{
var pen = new Pen(color, 5);
using Graphics g = Graphics.FromImage(_bitmap);
g.DrawRectangle(pen, rect);
}
public Color StringToColor(string colorName)
{
if (colorName.StartsWith("#"))
{
colorName = colorName.Replace("#", string.Empty);
}
if (int.TryParse(colorName, System.Globalization.NumberStyles.HexNumber, null, out int value))
{
return Color.FromArgb(
//Convert.ToByte((value >> 24) & 255), // a
Convert.ToByte((value >> 16) & 255), // R
Convert.ToByte((value >> 8) & 255), // G
Convert.ToByte((value >> 0) & 255) // B
);
}
return Color.Red;
}
/// <summary>
/// 取文件名后缀(小写)
/// </summary>
/// <param name="name">文件名</param>
/// <returns>返回小写后缀,不带“.”</returns>
public string GetFileExt(string name)
{
return name.Split('.').Last().ToLower();
}
#region Dispose
// 是否释放
private bool _isDisposed = false;
// 锁对象
private static readonly object _clockObj = new object();
~ImageHelper()
{
Dispose(false);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
// 释放相关资源
protected virtual void Dispose(bool disposing)
{
//不需要多次释放
if (_isDisposed) return;
//由于Dispose方法可能被多线程调用,所以加锁以确保线程安全
lock (_clockObj)
{
if (disposing)
{
if (!string.IsNullOrWhiteSpace(_fileName) && File.Exists(_fileName))
{
File.Delete(_fileName);
}
}
if (_bitmap != null)
{
_bitmap.Dispose();
_bitmap = null;
}
_isDisposed = true;
}
}
#endregion
}
图片缩略
/// <summary>
/// 图片伸缩(百分比)
/// </summary>
/// <param name="stretchWidth">伸缩的宽度(%)</param>
/// <param name="stretchHeight">伸缩的高度(%)</param>
public void StretchImage(int stretchWidth, int stretchHeight)
{
if (stretchHeight == _bitmap.Height && stretchWidth == _bitmap.Width)
{
return;
}
int width = _bitmap.Width;
int height = _bitmap.Height;
Bitmap bitmap = new Bitmap(width * stretchWidth / 100, height * stretchHeight / 100);
Graphics gSave = Graphics.FromImage(bitmap);
Point[] p = new Point[3];
p[0].X = 0;
p[1].X = width * stretchWidth / 100;
p[2].X = 0;
p[0].Y = 0;
p[1].Y = 0;
p[2].Y = height * stretchHeight / 100;
gSave.Clear(Color.White);
gSave.DrawImage(_bitmap, p);
gSave.Dispose();
_bitmap.Dispose();
_bitmap = bitmap;
}
/// <summary>
/// 图片缩略(像素)
/// </summary>
/// <param name="thumbWidth">伸缩的宽度(像素)</param>
/// <param name="thumbHeight">伸缩的高度(像素)</param>
public void ThumbImage(int thumbWidth, int thumbHeight)
{
if (thumbHeight == _bitmap.Height && thumbWidth == _bitmap.Width)
{
return;
}
Bitmap bitmap = new Bitmap(thumbWidth, thumbHeight);
Graphics gSave = Graphics.FromImage(bitmap);
Point[] p = new Point[3];
p[0].X = 0;
p[1].X = thumbWidth;
p[2].X = 0;
p[0].Y = 0;
p[1].Y = 0;
p[2].Y = thumbHeight;
gSave.Clear(Color.White);
gSave.DrawImage(_bitmap, p);
gSave.Dispose();
_bitmap.Dispose();
_bitmap = bitmap;
}
调整图片质量
/// <summary>
/// 调整图片质量
/// </summary>
/// <param name="encoder">图片编码</param>
/// <param name="quality">图片质量</param>
/// <returns></returns>
public void QualityImage(ImageCodecInfo encoder, int quality)
{
var myEncoder = Encoder.Quality;
var myEncoderParameters = new EncoderParameters(1);
var myEncoderParam = new EncoderParameter(myEncoder, quality);
myEncoderParameters.Param[0] = myEncoderParam;
var stream = new MemoryStream();
_bitmap.Save(stream, encoder, myEncoderParameters);
var bitmap = (Bitmap)Image.FromStream(stream);
_bitmap.Dispose();
_bitmap = bitmap;
}
图片转换
/// <summary>
/// 图片转换(后拉伸)
/// </summary>
/// <param name="rotateAngle">旋转度数</param>
/// <param name="stretchWidth">水平伸缩</param>
/// <param name="stretchHeight">竖直伸缩</param>
/// <param name="tiltWidth">水平倾斜</param>
/// <param name="tiltHeight">竖直倾斜</param>
/// <returns></returns>
public void DistortImage1(int rotateAngle, int stretchWidth, int stretchHeight, int tiltWidth, int tiltHeight)
{
TiltWidthImage(tiltWidth);
TiltHeightImage(tiltHeight);
RotateAngle(rotateAngle);
StretchImage(stretchWidth, stretchHeight);
}
/// <summary>
/// 图片转换(先缩小)
/// </summary>
/// <param name="rotateAngle">旋转度数</param>
/// <param name="stretchWidth">水平伸缩</param>
/// <param name="stretchHeight">竖直伸缩</param>
/// <param name="tiltWidth">水平倾斜</param>
/// <param name="tiltHeight">竖直倾斜</param>
/// <returns></returns>
public void DistortImage2(int rotateAngle, int stretchWidth, int stretchHeight, int tiltWidth, int tiltHeight)
{
StretchImage(stretchWidth, stretchHeight);
TiltWidthImage(tiltWidth);
TiltHeightImage(tiltHeight);
RotateAngle(rotateAngle);
}
/// <summary>
/// 图片水平倾斜
/// </summary>
/// <param name="tiltWidth">水平偏移长度</param>
public void TiltWidthImage(int tiltWidth)
{
if (tiltWidth == 0)
{
return;
}
int width = _bitmap.Width;
int height = _bitmap.Height;
Bitmap bitmap = new Bitmap(width + Math.Abs(tiltWidth), height);
Graphics gSave = Graphics.FromImage(bitmap);
Point[] p = new Point[3];
if (tiltWidth > 0)
{
p[0].X = Math.Abs(tiltWidth);
p[1].X = width + Math.Abs(tiltWidth);
p[2].X = 0;
}
else
{
p[0].X = 0;
p[1].X = _bitmap.Width;
p[2].X = Math.Abs(tiltWidth);
}
p[0].Y = 0;
p[1].Y = 0;
p[2].Y = height;
gSave.Clear(Color.White);
gSave.DrawImage(_bitmap, p);
gSave.Dispose();
_bitmap.Dispose();
_bitmap = bitmap;
}
/// <summary>
/// 图片竖直倾斜
/// </summary>
/// <param name="tiltHeight">竖直偏移长度</param>
public void TiltHeightImage(int tiltHeight)
{
if (tiltHeight == 0)
{
return;
}
int width = _bitmap.Width;
int height = _bitmap.Height;
Bitmap bitmap = new Bitmap(width, height + Math.Abs(tiltHeight));
Graphics gSave = Graphics.FromImage(bitmap);
Point[] p = new Point[3];
p[0].X = 0;
p[1].X = width;
p[2].X = 0;
if (tiltHeight > 0)
{
p[0].Y = Math.Abs(tiltHeight);
p[1].Y = 0;
p[2].Y = height + Math.Abs(tiltHeight);
}
else
{
p[0].Y = 0;
p[1].Y = Math.Abs(tiltHeight);
p[2].Y = height;
}
gSave.Clear(Color.White);
gSave.DrawImage(_bitmap, p);
gSave.Dispose();
_bitmap.Dispose();
_bitmap = bitmap;
}
图片裁切
/// <summary>
/// 图片裁切
/// </summary>
/// <param name="StartX">开始坐标X</param>
/// <param name="StartY">开始坐标Y</param>
/// <param name="iWidth">宽度</param>
/// <param name="iHeight">高度</param>
/// <returns>剪裁后的Bitmap</returns>
public void CutImg(int StartX, int StartY, int iWidth, int iHeight)
{
if (_bitmap == null) return;
if (iWidth == 0 || iHeight == 0) return;
int w = _bitmap.Width;
int h = _bitmap.Height;
if (StartX >= w || StartY >= h) return;
if (StartX + iWidth > w) { iWidth = w - StartX; }
if (StartY + iHeight > h) { iHeight = h - StartY; }
Bitmap bmpOut = new Bitmap(iWidth, iHeight, PixelFormat.Format24bppRgb);
using (Graphics g = Graphics.FromImage(bmpOut))
{
g.DrawImage(_bitmap, new Rectangle(0, 0, iWidth, iHeight), new Rectangle(StartX, StartY, iWidth, iHeight), GraphicsUnit.Pixel);
}
_bitmap.Dispose();
_bitmap = bmpOut;
}
若不限制 iWidth,iHeight 的大小,可以任意放缩指定大小。
图片旋转
/// <summary>
/// 图片旋转
/// </summary>
/// <param name="angle">旋转度数</param>
public void RotateAngle(int angle)
{
angle = angle % 360;
if (angle == 0)
{
return;
}
//原图的宽和高
int srcWidth = _bitmap.Width;
int srcHeight = _bitmap.Height;
//图像旋转之后所占区域宽和高
Rectangle rotateRec = GetRotateRectangle(srcWidth, srcHeight, angle);
int rotateWidth = rotateRec.Width;
int rotateHeight = rotateRec.Height;
//目标位图
Bitmap destImage = null;
Graphics graphics = null;
try
{
//定义画布,宽高为图像旋转后的宽高
destImage = new Bitmap(rotateWidth, rotateHeight);
//graphics根据destImage创建,因此其原点此时在destImage左上角
graphics = Graphics.FromImage(destImage);
//要让graphics围绕某矩形中心点旋转N度,分三步
//第一步,将graphics坐标原点移到矩形中心点,假设其中点坐标(x,y)
//第二步,graphics旋转相应的角度(沿当前原点)
//第三步,移回(-x,-y)
//获取画布中心点
Point centerPoint = new Point(rotateWidth / 2, rotateHeight / 2);
//将graphics坐标原点移到中心点
graphics.TranslateTransform(centerPoint.X, centerPoint.Y);
//graphics旋转相应的角度(绕当前原点)
graphics.RotateTransform(angle);
//恢复graphics在水平和垂直方向的平移(沿当前原点)
graphics.TranslateTransform(-centerPoint.X, -centerPoint.Y);
//此时已经完成了graphics的旋转
graphics.Clear(Color.White);
//计算:如果要将源图像画到画布上且中心与画布中心重合,需要的偏移量
Point Offset = new Point((rotateWidth - srcWidth) / 2, (rotateHeight - srcHeight) / 2);
//将源图片画到rect里(rotateRec的中心)
graphics.DrawImage(_bitmap, new Rectangle(Offset.X, Offset.Y, srcWidth, srcHeight));
//重至绘图的所有变换
graphics.ResetTransform();
graphics.Save();
}
catch (Exception ex)
{
string err = ex.Message;
}
finally
{
if (graphics != null)
graphics.Dispose();
}
_bitmap.Dispose();
_bitmap = destImage;
}
private Rectangle GetRotateRectangle(int width, int height, float angle)
{
double radian = angle * Math.PI / 180; ;
double cos = Math.Cos(radian);
double sin = Math.Sin(radian);
//只需要考虑到第四象限和第三象限的情况取大值(中间用绝对值就可以包括第一和第二象限)
int newWidth = (int)(Math.Max(Math.Abs(width * cos - height * sin), Math.Abs(width * cos + height * sin)));
int newHeight = (int)(Math.Max(Math.Abs(width * sin - height * cos), Math.Abs(width * sin + height * cos)));
return new Rectangle(0, 0, newWidth, newHeight);
}
得到图片格式
/// <summary>
/// 得到图片格式
/// </summary>
/// <param name="name">文件名称</param>
/// <returns>ImageFormat</returns>
public ImageFormat GetFormat(string name)
{
string ext = GetFileExt(name);
switch (ext)
{
case "ico":
return ImageFormat.Icon;
case "bmp":
return ImageFormat.Bmp;
case "png":
return ImageFormat.Png;
case "gif":
return ImageFormat.Gif;
default:
return ImageFormat.Jpeg;
}
}
获取图片编码信息
/// <summary>
/// 获取图片编码信息
/// </summary>
/// <param name="imageFormat">图片格式</param>
/// <returns></returns>
public ImageCodecInfo GetEncoder(ImageFormat imageFormat)
{
var codecs = ImageCodecInfo.GetImageEncoders();
foreach (var item in codecs)
{
if (item.FormatID == imageFormat.Guid)
{
return item;
}
}
return null;
}
图片新尺寸调整
/// <summary>
/// 计算新尺寸(保持纵横比)
/// </summary>
/// <param name="srcWidth">原始宽度</param>
/// <param name="srcHeight">原始高度</param>
/// <param name="dstWidth">目标宽度</param>
/// <param name="dstHeight">目标高度</param>
/// <returns></returns>
public Size ResizeImage(int srcWidth, int srcHeight, int dstWidth, int dstHeight)
{
if (dstWidth <= 0)
dstWidth = srcWidth;
if (dstHeight <= 0)
dstHeight = srcHeight;
decimal MAX_WIDTH = dstWidth;
decimal MAX_HEIGHT = dstHeight;
decimal ASPECT_RATIO = MAX_WIDTH / MAX_HEIGHT;
int newWidth, newHeight;
decimal originalWidth = srcWidth;
decimal originalHeight = srcHeight;
if (originalWidth > MAX_WIDTH || originalHeight > MAX_HEIGHT)
{
decimal factor;
if (originalWidth / originalHeight > ASPECT_RATIO)
{
factor = originalWidth / MAX_WIDTH;
newWidth = Convert.ToInt32(originalWidth / factor);
newHeight = Convert.ToInt32(originalHeight / factor);
}
else
{
factor = originalHeight / MAX_HEIGHT;
newWidth = Convert.ToInt32(originalWidth / factor);
newHeight = Convert.ToInt32(originalHeight / factor);
}
}
else
{
newWidth = srcWidth;
newHeight = srcHeight;
}
return new Size(newWidth, newHeight);
}
图片保存
/// <summary>
/// BitmapImage保存为png
/// </summary>
/// <param name="bitmapImage">BitmapImage</param>
/// <param name="filePath">保存绝对路径</param>
private void SaveBitmapIamge(BitmapImage bitmapImage, string filePath)
{
var encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(bitmapImage));
using (var fs = new FileStream(filePath, FileMode.OpenOrCreate))
{
encoder.Save(fs);
}
}
创建位图
/// <summary>
/// 创建可显示的位图
/// </summary>
/// <param name="data"></param>
/// <returns></returns>
public static BitmapImage GenerateBitmapImage(byte[] data)
{
if (data == null || data.Length == 0)
{
return NoPicture;
}
BitmapImage bitmap = new BitmapImage();
bitmap.BeginInit();
bitmap.CacheOption = BitmapCacheOption.OnLoad;
//bitmap.CreateOptions = BitmapCreateOptions.DelayCreation;
using (MemoryStream ms = new MemoryStream(data))
{
bitmap.StreamSource = ms;
bitmap.EndInit();
bitmap.Freeze();
}
return bitmap;
}
彩色图像转换灰度图
/// <summary>
/// 将源图像灰度化,并转化为8位灰度图像。
/// </summary>
/// <param name="original"> 源图像。 </param>
/// <returns> 8位灰度图像。 </returns>
public static Bitmap RgbToGrayScale(Bitmap original)
{
if (original != null)
{
// 将源图像内存区域锁定
Rectangle rect = new Rectangle(0, 0, original.Width, original.Height);
BitmapData bmpData = original.LockBits(rect, ImageLockMode.ReadOnly,
PixelFormat.Format24bppRgb);
// 获取图像参数
int width = bmpData.Width;
int height = bmpData.Height;
int stride = bmpData.Stride; // 扫描线的宽度,比实际图片要大
int offset = stride - width * 3; // 显示宽度与扫描线宽度的间隙
IntPtr ptr = bmpData.Scan0; // 获取bmpData的内存起始位置的指针
int scanBytesLength = stride * height; // 用stride宽度,表示这是内存区域的大小
// 分别设置两个位置指针,指向源数组和目标数组
int posScan = 0, posDst = 0;
byte[] rgbValues = new byte[scanBytesLength]; // 为目标数组分配内存
Marshal.Copy(ptr, rgbValues, 0, scanBytesLength); // 将图像数据拷贝到rgbValues中
// 分配灰度数组
byte[] grayValues = new byte[width * height]; // 不含未用空间。
// 计算灰度数组
byte blue, green, red;
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
blue = rgbValues[posScan];
green = rgbValues[posScan + 1];
red = rgbValues[posScan + 2];
grayValues[posDst] = (byte)((blue + green + red) / 3);//(blue*0.299 + green*0.587 + red*0.114)
posScan += 3;
posDst++;
}
// 跳过图像数据每行未用空间的字节,length = stride - width * bytePerPixel
posScan += offset;
}
// 内存解锁
Marshal.Copy(rgbValues, 0, ptr, scanBytesLength);
original.UnlockBits(bmpData); // 解锁内存区域
// 构建8位灰度位图
Bitmap retBitmap = BuiltGrayBitmap(grayValues, width, height);
return retBitmap;
}
else
{
return null;
}
}
彩色图像数组转换灰度图数组
public static byte[] ConvertRgbToGrayscale(byte[] rgbData)
{
// 检查数据长度是否为3的倍数
if (rgbData.Length % 3 != 0)
throw new ArgumentException("Invalid RGB data length");
int pixelCount = rgbData.Length / 3;
byte[] grayscale = new byte[pixelCount];
for (int i = 0; i < rgbData.Length; i += 3)
{
// 获取RGB分量
byte r = rgbData[i];
byte g = rgbData[i + 1];
byte b = rgbData[i + 2];
// 使用BT.601标准亮度公式计算灰度值
grayscale[i / 3] = (byte)(0.299f * r + 0.587f * g + 0.114f * b);
}
return grayscale;
}
图像数组直接旋转
// bmp.RotateFlip(RotateFlipType.Rotate270FlipNone);
// data =
var arr = BitmapFactory.RotateFlipNone(data, width, height, 270);
/// <summary>
/// 数据按度数旋转(不翻转)
/// </summary>
/// <param name="data"></param>
/// <param name="width"></param>
/// <param name="height"></param>
/// <returns>仅支持90/180/270度旋转</returns>
public static byte[] RotateFlipNone(byte[] data, int width, int height, int angle)
{
if (angle == 0) return data;
byte[] rotated = new byte[data.Length];
if (angle == 90)
{
for (int i = 0; i < data.Length; i++)
{
int y = i / width;
int x = i % width;
// 正确坐标变换:newIndex = x * height + (height - y - 1) 原图宽高互换
int newIndex = x * height + (height - y - 1);
rotated[newIndex] = data[i];
}
}
else if (angle == 180)
{
for (int i = 0; i < data.Length; i++)
{
int y = i / width; // 原图行坐标
int x = i % width; // 原图列坐标
// 计算新索引:(height - y - 1) * width + (width - x - 1)
int newIndex = (height - y - 1) * width + (width - x - 1);
rotated[newIndex] = data[i];
}
}
else if (angle == 270)
{
for (int i = 0; i < data.Length; i++)
{
int y = i / width;
int x = i % width;
// 正确坐标变换:newIndex = (width - x - 1) * height + y
int newIndex = (width - x - 1) * height + y;
rotated[newIndex] = data[i];
}
}
return rotated;
}
图片上添加字符串
AddScoreTextToImage(srcImg, dstImg, {30,90}, 50);
// 图片上添加字符串,并显示不同颜色、大小、位置
public static void AddScoreTextToImage(string srcPath, string dstPath, List<int> scores, int accept, int fontSize = 20, int posX = 10, int posY = 10)
{
var len = scores.Count;
var interval = ',';
using (var bmp = new Bitmap(srcPath))
{
var tmp = new Bitmap(bmp.Width, bmp.Height, PixelFormat.Format32bppRgb);
using (var g = Graphics.FromImage(tmp))
{
g.DrawImage(bmp, 0, 0);
g.TextRenderingHint = TextRenderingHint.AntiAlias;
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
var font = new Font("Arial", fontSize, FontStyle.Bold);
float offset = 0;
for (int i = 0; i < len; i++)
{
var text = scores[i].ToString();
if (i != len - 1)
{
text += interval;
}
var position = new PointF(posX + offset, posY);
var score = scores[i];
if (score > accept) // 显示绿色
{
using (var brush = new SolidBrush(Color.Green))
{
g.DrawString(text, font, brush, position);
}
}
else
{
using (var brush = new SolidBrush(Color.Red))
{
g.DrawString(text, font, brush, position);
}
}
float width = 0;
foreach (var ch in text)
{
width += MeasureCharWidth(ch, font);
}
offset += width;
}
}
tmp.Save(dstPath, bmp.RawFormat);
tmp.Dispose();
}
}
private static float MeasureCharWidth(char c, Font font)
{
if (DicCharWidth.TryGetValue(c, out var width))
{
return width;
}
using (var bmp = new Bitmap(1, 1))
using (var g = Graphics.FromImage(bmp))
{
g.TextRenderingHint = TextRenderingHint.AntiAliasGridFit;
var format = new StringFormat(StringFormat.GenericTypographic);
format.FormatFlags |= StringFormatFlags.MeasureTrailingSpaces;
// 测量单个字符
width = g.MeasureString(c.ToString(), font, int.MaxValue, format).Width;
DicCharWidth.TryAdd(c, width);
}
return width;
}
private static readonly ConcurrentDictionary<char, float> DicCharWidth = new ConcurrentDictionary<char, float>();

浙公网安备 33010602011771号