C#实现文字绘图功能

思路

这是本人第一次写博客,首先我将简述一下实现思路.
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);

效果图(图中文字为"我爱你")

原图:
Alt
生成图:
Alt

总结

建议不要做代码的搬运工,本人大三,涉及的知识大部分都是System.Drawing的知识,所以说这个功能并不算难,开发不易,不喜勿喷,谢谢。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值