程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#基礎知識 >> 根據灰度值填充字符-單文件單線程版

根據灰度值填充字符-單文件單線程版

編輯: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的關系。。。特意看了下,還有好多種的。。。)
  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved