思路
这是本人第一次写博客,首先我将简述一下实现思路.
1.先获取原图的每个像素点的rgba,然后新建一个和原图同样宽高的Bitmap
2.将背景设为白色,再将要写入的字体设为黑色
3.当像素点不为白色时,将新建的Bitmap当前像素点的rgba替换为原图同像素点的rgba
话不多说,上码
1.获取原图每个像素点的rgba
private List<List<Dictionary<string, byte>>> GetImageRgba(Image img)
{
var result = new List<List<Dictionary<string, byte>>>();
Bitmap map = new Bitmap(img);
for (int i = 0; i < map.Height; i++)
{
var rgbaList = new List<Dictionary<string, byte>>();
for (int j = 0; j < map.Width; j++)
{
//通过Bitmap 的 GetPixel(x,y)获取每个像素点的rgba
var color = map.GetPixel(j, i);
var rgbaDict = new Dictionary<string, byte>();
rgbaDict["r"] = color.R;
rgbaDict["g"] = color.G;
rgbaDict["b"] = color.B;
rgbaDict["a"] = color.A;
rgbaList.Add(rgbaDict);
}
result.Add(rgbaList);
}
return result;
}
2.生成转换后的图片
1.先看方法的声明形参
/// <summary>
/// 生成最终图片
/// </summary>
/// <param name="content">原图每个像素点的rgba结果集</param>
/// <param name="str">要写入的文字</param>
/// <returns></returns>
private Image createImg(List<List<Dictionary<string, byte>>> content,string str)
2.新建一个和原图同样宽高的Bitmap,将背景设为白色
//原图高度
int height = content.Count();
//原图宽度
int width = content[0].Count();
//新建一个宽和高都为原始图片的bitmap
Bitmap map = new Bitmap(width, height);
//新建一个画板
Graphics g = Graphics.FromImage(map);
//设置画板的插补模式
g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBilinear;
//设置画板呈现质量
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
//清除整个绘画面并以指定背景色填充(白色背景)
g.Clear(ColorTranslator.FromHtml("#ffffff"));
3.设置字体大小并以此判断图片可写入字体的行数及列数
//14pt = 18.7px
//5pt = 6px
//7pt = 9px
Font font = new Font("宋体",7, FontStyle.Regular);
//字体高度
int fontH = font.Height;
//单个字体宽度
//7pt = 9px
float fontW = 9.0f;
//字体总宽度
fontW *= str.Length;
//每行最多可容纳多少个str字符
int rowNum = (int)((width - 0f) / fontW);
//行剩余像素点
int rowSyPx = (int)(width - rowNum * fontW);
//行str字符间隔 = 行剩余像素点/(行容纳数-1)
int rowJgPx = rowSyPx / (rowNum-1);
//列可容纳数
int columnNum = height / fontH;
//列剩余像素点
int columnSyPx = height % fontH;
//列间隔像素点 = 列剩余像素点/(列可容纳数-1)
float columnJgPx = (columnSyPx - 0f) / (columnNum-1);
4.将文字写入铺满新建Bitmap中
//将文字铺满图片
//列容纳数 columnNum 外层for循环
for (int i = 0; i < columnNum; i++)
{
//行容纳数 rowNum 内层for循环
for (int j = 0; j < rowNum; j++)
{
//public void DrawString(string s, Font font, Brush brush, PointF point);
//str为 要写入图片的文字
//font为 要写入图片文字的字体大小和family
//SolidBrush 字体的颜色(黑色)
//PointF(x,y) x坐标为 (str总宽度+行间隔宽度)*j y坐标为 (str高度 + 列间隔宽度)*i
g.DrawString(str, font, new SolidBrush(Color.Black), new PointF((rowJgPx + fontW)*j,(columnJgPx+fontH)*i));
}
}
5.当像素点不为白色时,将新建的Bitmap当前像素点的rgba替换为原图同像素点的rgba.
//图片高度 为外层for循环
for (int i = 0; i < map.Height; i++)
{
//图片宽度 为内层for循环
for (int j = 0; j < map.Width; j++)
{
//获取原始图片的rbga Dictionary<string,byte>
var rgba = content[i][j];
//获取自绘图片的rgba
var newRgba = map.GetPixel(j, i);
var R = newRgba.R;
var G = newRgba.G;
var B = newRgba.B;
//因为背景为白色 字体为黑色 所以当像素点的r、g、b都为255时,即为白色时,continue,进入下一个像素点进行判断
//若不为白色,即为当前像素点为文字时,将自绘图片的rgba替换为原图的rgba
//此步骤较为耗时
if (R == 255 && G == 255 && B == 255)
continue;
map.SetPixel(j, i, Color.FromArgb(rgba["a"], rgba["r"], rgba["g"], rgba["b"]));
}
}
6.将Bitmap转换为Image
//然后通过Bitmap.Save(),将图片保存到stream中
//再通过Image.FromStream 将stream转换为Image作为结果return
MemoryStream memoryStream = new MemoryStream();
map.Save(memoryStream, System.Drawing.Imaging.ImageFormat.Png);
return Image.FromStream(memoryStream);
效果图(图中文字为"我爱你")
原图:
生成图:
总结
建议不要做代码的搬运工,本人大三,涉及的知识大部分都是System.Drawing的知识,所以说这个功能并不算难,开发不易,不喜勿喷,谢谢。