用 Java 生成 ASCII 字元畫

ImportNew - PyPer發表於2015-03-24

ASCII碼藝術是一種技術,它利用ASCII標 準中的可列印字元來產生視覺藝術效果。在歷史上它有其存在的目的,當時的印表機還無法列印圖片,並且當時在郵件中嵌入影像還無法實現,所以它也用於郵件 中。本文中,我將為你呈現一個非常簡單的ASCII碼藝術產生器,它由Java語言編寫,並可以配置字型和對比度。因為該產生器是我在週末用幾個小時建立 的,所以它還不完美,但卻是一個有趣的實驗。在下面你可以看到實現程式碼,並且我將解釋它的工作原理。

演算法

這個演算法很簡單。首先,我們將ASCII碼藝術品中要用到的每一個字元轉化成一張圖片,並快取它。然後,我們遍歷原始影像,對於每個字元大小的圖片塊,找出 能最佳匹配它的字元。為了實現這一步,我們首先對原始影像做一些預處理:我們先將影像轉換為灰度圖,然後讓其通過一個閾值濾波器,此時就得到了一個黑白對比圖,我們可以將其與每個字元對比並計算差值。接著,對每個圖片塊選取最相似的字元,一直進行下去,直到整個影像都轉換完成。此外,我們還可以根據需要調 整閾值大小來影響對比度,並增強最終的結果。

為了實現這一點,一個非常簡單的方法是將紅、綠、藍的值都設定成三種顏色的平均值:

紅=綠=藍 =(紅+綠+藍)/ 3

如果這個值低於閾值,我們就將它設定成白色,否則我們將其設定成黑色。最後,我們將影像與每個字元以畫素為單位進行比較並計算出平均誤差。如下面的圖片和程式碼片段所示:

int r1 = (charPixel >> 16) & 0xFF;
int g1 = (charPixel >> 8) & 0xFF;
int b1 = charPixel & 0xFF;

int r2 = (sourcePixel >> 16) & 0xFF;
int g2 = (sourcePixel >> 8) & 0xFF;
int b2 = sourcePixel & 0xFF;

int thresholded = (r2 + g2 + b2) / 3 < THRESHOLD ? 0 : 255;

error = Math.sqrt((r1 - thresholded) * (r1 - thresholded) + 
    (g1 - thresholded) * (g1 - thresholded) + (b1 - thresholded) * (b1 - thresholded));

因為顏色是儲存在單個整數中,所以我們首先提取單個顏色成分並執行上面我解釋的計算。另一個挑戰是準確地測量字元尺寸,並以它們為中心作圖。在試驗了多種方法之後,我最終發現這個方法已經足夠好:

Rectangle rect = new TextLayout(Character.toString((char) i), fm.getFont(), 
    fm.getFontRenderContext()).getOutline(null).getBounds();

g.drawString(character, 0, (int) (rect.getHeight() - rect.getMaxY()));

你可以從GitHub上下載完整的原始碼。

下面是一些使用不同字型尺寸和閾值的例子。

相關文章