根据灰度值填充字符-单文件单线程版_C#教程

看到软二的群里,某童鞋发了个自己的java大作业的截图,类似于一个图片,处理后,根据不同的灰度值,填充不同的字符。故,我也用C#来写个玩玩~
首先,图片读入内存,然后- - 有三种处理方式,
第一种是getPixel,然后setPixel。。。
第二种是将图片数据读出,放到byte数组中,然后去读,再copy回去。
第三种是不copy数据,直接在当前图片数据流上操作,然后再解锁就可以了。
由于去年做过类似的工作,所以知道效率问题,第一种。。。速度会很慢(相比较第二种和第三种)。第二种和第三种相差不是很多。但是第三种需要使用unsafe字段。
在这里,我选用第三种进行操作。
界面就不说了。一个按钮,两个pictureBox,一个存原图,一个存字符图。
处理代码如下

复制代码 代码如下:

private void button1_Click(object sender, EventArgs e)
{
//打开文件
OpenFileDialog open = new OpenFileDialog();
open.Filter = "jpeg图片文件|*.jpg";
if (open.ShowDialog() != DialogResult.OK)
return;
string filePath = open.FileName;
//打开图片,显示原始图
Image img = Image.FromFile(filePath);
sourcePicturebox.Image =img ;
//再次读取一次图潘
Bitmap bitmap = new Bitmap(img);
//锁定图片处理区域
Rectangle rect = new Rectangle(0, 0, bitmap.Width, bitmap.Height);
BitmapData bmpData = bitmap.LockBits(rect, ImageLockMode.ReadWrite, bitmap.PixelFormat);
//初始化字符串数组
string[] str = new string[bitmap.Height];
//不安全代码块
unsafe
{
//获取首指针
byte* ptr = (byte*)(bmpData.Scan0);
for (int height = 0; height < bmpData.Height; height++)
{
//由于测试图片是32RGB图,所以,ptr一次移动四位
for (int width = 0; width < bmpData.Width; width++,ptr+=4)
{
str[height] += ((byte)(0.333 * ptr[0] + 0.333 * ptr[1] + 0.333 * ptr[2])) > 128 ? "*" : " ";
}
//为防止图片数据占用不为4的倍数,所以这里用stride,跳过多余的字节
ptr += bmpData.Stride - bmpData.Width * 4;
}
}
//图片解锁
bitmap.UnlockBits(bmpData);
//初始化打印字符参数,以及新建一个空白图片
//空白图片大小。。。。。测试得到的。后续改进
Font font=new System.Drawing.Font ("宋体",20.5f);
Bitmap resultBitmap = new Bitmap(img.Width * 14, img.Height * 14);
Graphics graphics = Graphics.FromImage(resultBitmap);
graphics.Clear(Color.White);
SolidBrush brush=new SolidBrush(Color.Black);
//打印字符,一次一行
for (int i = 0; i < img.Height; i++)
{
graphics.DrawString(str[i], font, brush,0,i*14);
}
//MessageBox.Show(font.GetHeight().ToString());
resultPicturebox.Image = resultBitmap;
//文件保存
SaveFileDialog saveDialog = new SaveFileDialog();
saveDialog.Filter = "jpeg图片文件|*.jpg";
if(saveDialog.ShowDialog()==DialogResult.OK)
resultBitmap.Save(saveDialog.FileName, ImageFormat.Jpeg);
}

实验结果如下
 
实验的结果经过多次调整打印参数,结果还可以。但是,略显紧凑。
***********************************************分隔线******************************************************
小结
由于选的图,是32rgb的,在第一次处理的时候,还有点问题,当成24rgb处理了。。。。出错。。。然后,改后,一开始以为多处的透明分量在低位,结果。。。原来在高位。不过还好最后成功了(其实就试下呗。。。先不处理成字符,而直接改变一个分量为0,然后看效果呗~)

原始图片只有500*500不到,转换后。。。图片为6700+*6700+。。。太大了。。。所以,以后得先处理图片,使其缩小,再进行处理。这里也有二种处理方式,第一是处理原始图像,而是处理那个字符串数组。感觉吧,还是第一种直观些。

然后,后续打印,可以考虑不用string存,而用char[,]来存,这样,又可以用指针了,总觉得指针会快些~
看官可见,上面有一个测试按钮,但是,我没有给出代码,其实那个是用来测试多线程的。打开文件的时候,允许同时选中多个文件,然后操作。这里就用到多线程。但是不知道为何,多线程操作的时候,出来的图片就不对了,如果多线程多了后,还会抛出异常。。。。。就算我就开一个线程,操作一幅图片,也会导致错误的结果。。。所以多线程的代码没有上传,等改好再说吧。

PS.这个改好,估计还要很多天。。。。。毕竟。。。要考试了。。。还是复习去吧。。。前2天在家一点书没看啊。

当然后续改进,不一定就一个多线程,还可以进行字符自定义填充啊(这个简单点)。或者,给个字符串填充额。然后多个灰度级,不同的灰度级给不同的字符填充。再比如。。。可以让它处理所有类型的静态图。。。。(由于那个32RGB的关系。。。特意看了下,还有好多种的。。。)

时间: 2024-10-28 15:26:11

根据灰度值填充字符-单文件单线程版_C#教程的相关文章

C#简单遍历指定文件夹中所有文件的方法_C#教程

本文实例讲述了C#简单遍历指定文件夹中所有文件的方法.分享给大家供大家参考,具体如下: C#遍历指定文件夹中的所有文件: DirectoryInfo TheFolder=new DirectoryInfo(folderFullName); //遍历文件夹 foreach(DirectoryInfo NextFolder in TheFolder.GetDirectories()) this.listBox1.Items.Add(NextFolder.Name); //遍历文件 foreach(F

C#如何自动识别文件的编码_C#教程

前言 C#中识别文件的编码是一个头疼的问题,最近在做导入微信商户后台退款数据时,无论怎么设置编码导出来都是乱码,后来在网上找了这个识别文件编码的代码,感觉不错.最后识别出来是gb2312,看来我还是太渣了,只能吃土了,竟然忘记了这个编码. 下面话不多说,上代码. /// <summary> /// 用于取得一个文本文件的编码方式(Encoding). /// </summary> public class TxtFileEncoder { public TxtFileEncoder

比较有效的使用C#读取文件的代码_C#教程

你平时是怎么读取文件的?使用流读取.是的没错,C#给我们提供了非常强大的类库(又一次吹捧了.NET一番),里面封装了几乎所有我们可以想到的和我们没有想到的类,流是读取文件的一般手段,那么你真的会用它读取文件中的数据了么?真的能读完全么? 通常我们读取一个文件使用如下的步骤: 1.声明并使用File的OpenRead实例化一个文件流对象,就像下面这样        FileStream fs = File.OpenRead(filename); 或者        FileStream fs = 

将ocx文件转换成C#程序引用的DLL文件的办法_C#教程

1.打开VS2008或VS2010命令提示符(此例用VS2008) 将ocx文件拷贝到d:\Program Files\Microsoft Visual Studio 9.0\VC下 2.注册ActiveX控件 regsvr32 IB_USBKEY.ocx 3.编译OCX文件 aximp IB_USBKEY.ocx 生成两个dll文件,项目中引用Ax前缀的文件 4.将生成的两个dll文件拷贝到项目中

C#简单读写txt文件的方法_C#教程

本文实例讲述了C#简单读写txt文件的方法.分享给大家供大家参考,具体如下: //write txt StringBuilder builder = new StringBuilder(); FileStream fs = new FileStream(saveFileName, FileMode.Create); StreamWriter sw = new StreamWriter(fs, Encoding.Default); for (int i = 0; i < ds.Tables[0].

C#中将DataTable转换成CSV文件的方法_C#教程

DataTable用于在.net项目中,用于缓存数据,DataTable表示内存中数据的一个表.CSV文件最早用在简单的数据库里,由于其格式简单,并具备很强的开放性,所以起初被扫图家用作自己图集的标记.CSV文件是个纯文本文件,每一行表示一张图片的许多属性. 在.net项目中运用C#将DataTable转化为CSV文件,现在提供一个较为通用的方法,具体代码如下: /// <summary> /// 将DataTable转换成CSV文件 /// </summary> /// <

在.NET中读取嵌入和使用资源文件的方法_C#教程

Dotnet中嵌入资源(位图.图标或光标等)有两种方式,一是直接把资源文件加入到项目,作为嵌入资源,在代码中通过Assembly的GetManifestResourceStream方法获取资源的Stream.另一种方法是在项目中加入. resx资源文件,在资源文件中添加资源,由ResourceManager类统一管理其中的资源. 下面分别详述这两种方法 一.使用GetManifestResourceStream读取嵌入资源 1.加入资源文件 直接把要嵌入到程序集的资源文件加入到项目中,可以加在项

C# 文件操作函数 创建文件 判断存在_C#教程

文件创建: 复制代码 代码如下: File.Create(Application.StartupPath + "\\AlarmSet.txt");//创建该文件 System.IO.Path.GetFileName(filePath)       //返回带扩展名的文件名 System.IO.Path.GetFileNameWithoutExtension(filePath)     //返回不带扩展名的文件名 System.IO.Path.GetDirectoryName(fileP

C#遍历得到checkboxlist选中值和设置选中项的代码_C#教程

得到选中项的value值并拼接成一个字符串返回 public string GetChecked(CheckBoxList checkList, string separator) { string str = ""; for (int i = 0; i < checkList.Items.Count; i++) { if (checkList.Items[i].Selected) { str += checkList.Items[i].Value + separator; }