程式設計師的浪漫:三十行程式碼實現用她的名字作幅畫

語言: CN / TW / HK

hello,各位小夥伴們大家早上|中文|晚上|凌晨好,相信看這篇文章的有很多新朋友,估計也有少量的老朋友,首先做個簡短的自我介紹,我是一灰灰,碼農界的資深搬運工;今天呢,沒有站在我身邊的捧哏老師,那就只好給大夥來個單口的灌水博文了

大街上鋪天蓋地的520促銷優惠買一贈一的宣傳語,宣告了初夏的第一個特殊節日,可好巧不巧的是到了5.21號這天我才發現,居然又到了520啊,然後再一看手機,臥槽,居然過了。。。這特麼回家還不得跪我那斥巨資200大洋買的機械鍵盤了

趕緊發動一下高達249IQ的大腦,思考一下有什麼補救的措施,是時候解開封印已舊的人肉爬蟲技能,看看票圈晒圖的朋友們,能不能提供有價值的靈光一現

功夫終負有心人,果不其然毫無收穫;老老實實的發揮一下職業特長,碼農可以整些什麼浪漫的活 呢?

寫個html頁面,陪她去看流星雨  用她的照片組個帶音樂、能自動播放的PPT  黑個商場大螢幕,附上她的美圖秀秀 + 愛你一萬年  AI自動寫個 xxx 愛你一萬年 的藏頭詩  寫個無介面的APP,偷偷裝在她的手機上,設定定時彈出一朵鮮花(不怕被打的話恐怖圖片也可以 )

可選擇的不少,接下來就剩下一個小問題了,5.21號送出5.20號的小禮物能被原諒麼?(請看到這裡的美少女麼摸著自己的良心,在評論區大聲告訴我”能“ 好麼)

話接上文,就算有再多得小仙女告訴我能,講道理我也不敢信啊,接下來免費給各位看官分享一個價值99¥的idea,用她的名字做一幅畫(如下),然後深情的告訴她,全是手繪,這麼大的工作量,delay個一兩天不很正常麼(請大聲告訴我,是不是很機智)

放大有驚喜

接下來,老司機教你如何使用三十行用她(他它)的名字畫出她的藝術畫

寫了這麼多居然還沒有進入主題,這文章灌水得我自己都有點看不過去了:sweat:,言歸正傳,接下來我們看下,如何實現用她的名字來作畫呢?

1. 作戰思路

目標有了,接下來就是定方案了,大家都知道計算機的世界是由0和1組成,那麼圖片的世界又是由什麼組成呢?

我已經聽到聰明機智的小夥伴內心的答案了,對,沒錯, 就是一個一個帶有顏色的畫素塊

那麼我們要做的是什麼呢?答案已經呼之欲出了,各位少俠小仙女麼,請大聲告訴我好麼

咳咳,說正經的,就是將將這一個一個畫素塊,然後用她(他它)的名字替換就行了

2. 戰前準備

俗話說兵馬未動,糧草先行,正式開幹之前,先做一些必要的準備

一張美麗動人的圖片 先將背景處理一下,保留關鍵的人物資訊,減少噪音 不會ps的小夥伴,可以直接使用 https://www.remove.bg/zh 三秒完成摳圖

如有侵權,聯絡即刪,只要不賠錢,要啥都行

選擇開動的技術棧,民主選擇 java, php, golang, js, python?

既然如此,那我們遵循自願原則,就決定是你了 -- 爪蛙(JAVA)

3. 開戰

感謝各位小夥伴選擇java 我的本命技能,那我們來看一下如何來實現我們的目的,正如把大象塞入冰箱只需要三步一樣,需要實現的步驟也很簡單

步驟拆解:

讀取圖片 並建立一個等大的畫板 遍歷圖片的每個畫素點,讀取畫素點的RGB 在畫板對應的位置上渲染文字 儲存畫板,大功告成

實現原始碼:

public static Color int2color(int color) {

int a = (0xff000000 & color) >>> 24;

int r = (0x00ff0000 & color) >> 16;

int g = (0x0000ff00 & color) >> 8;

int b = (0x000000ff & color);

return new Color(r, g, b, a);

}



public void renderCharPhoto(String imgPath, String name, String saveFile) throws Exception {

// 第一步,載圖片

BufferedImage img = ImageIO.read(new File(imgPath));

int w = img.getWidth(), h = img.getHeight();



// 第二步,建立等大的畫板

BufferedImage output = new BufferedImage(w, h, img.getType());

Graphics2D g2d = output.createGraphics();

g2d.setFont(new Font("宋體", Font.PLAIN, 1));

int index = 0;

for (int x = 0; x < w; x++) {

for (int y = 0; y < h; y++) {

// 第三步,遍歷每個畫素點,並獲取對應的rgb

char ch = name.charAt((index++) % name.length());

g2d.setColor(int2color(img.getRGB(x, y)));

// 第四步,寫上他她它的名字

g2d.drawString(String.valueOf(ch), x, y);

}

}



// 第五步,儲存圖片

g2d.dispose();

ImageIO.write(output, "png", new File(saveFile));

}

就這麼簡單,趕緊跑一下試試效果

輸出圖片

好像有什麼地方不對勁,這和原圖沒啥兩樣啊,那麼問題出在哪呢?一個畫素點上的文字,我的鈦合金四眼看不見啊,那可以怎麼辦呢?

有道理,把圖片放大,不就ok了麼,那麼將上面的畫板調整一下,放大24倍,設定字型大小20,給字與字之間留點空隙

public void renderCharPhoto(String imgPath, String name, String saveFile) throws Exception {

BufferedImage img = ImageIO.read(new File(imgPath));

int w = img.getWidth(), h = img.getHeight();



BufferedImage output = new BufferedImage(w * 24, h * 24, img.getType());

Graphics2D g2d = output.createGraphics();

g2d.setFont(new Font("宋體", Font.PLAIN, 20));

int index = 0;

for (int x = 0; x < w; x++) {

for (int y = 0; y < h; y++) {

char ch = name.charAt((index++) % name.length());

g2d.setColor(int2color(img.getRGB(x, y)));

g2d.drawString(String.valueOf(ch), x * 24 + 2, y * 24 + 2);

}

}



g2d.dispose();

ImageIO.write(output, "png", new File(saveFile));

}

輸出效果圖

這標準的宋體好像暴露了什麼,要是告訴他(她它)這是手繪的,能信麼?

為了更逼真一點,換個手繪字型試一試,網上搜索一下,從這裡 https://www.diyiziti.com/Builder/446 下載了一個 瀟灑手寫體 資源

然後再調整一下上面程式碼中的字型設定

public void renderCharPhoto(String imgPath, String name, String saveFile) throws Exception {

BufferedImage img = ImageIO.read(new File(imgPath));

int w = img.getWidth(), h = img.getHeight();



BufferedImage output = new BufferedImage(w * 24, h * 24, img.getType());

Graphics2D g2d = output.createGraphics();



// 使用自定義的字型

try (InputStream inputStream = Files.newInputStream(Paths.get("D://MobileFile/瀟灑手寫體.ttf"))) {

Font font = Font.createFont(Font.TRUETYPE_FONT, inputStream);

g2d.setFont(font.deriveFont(Font.PLAIN, 20));

}

int index = 0;

for (int x = 0; x < w; x++) {

for (int y = 0; y < h; y++) {

char ch = name.charAt((index++) % name.length());

g2d.setColor(int2color(img.getRGB(x, y)));

g2d.drawString(String.valueOf(ch), x * 24 + 2, y * 24 + 2);

}

}



g2d.dispose();

ImageIO.write(output, "png", new File(saveFile));

}

最終效果圖

如果對方很熟悉你的字型怎麼辦?

解決辦法也有,應用商店搜尋一下"造字",還可以順便給自己打造一個獨一無二的字型

棒,這下感覺無懈可擊了啊,只要把上面的圖片找個列印店,彩繪一下,完事了啊;拿走,不謝

如果不幸的是,當你有個機智的物件時,那麼她/他/它多半會給你靈魂一問,你是如何做到,字和間距都分毫不差的?

最後叨叨了這麼久,忽然想到一個問題,看到這裡的單身小夥伴們,話說你們是出於啥心裡繼續看完的,520這個節日,和你們這些單身狗有什麼關係呢:smirk:

4. 戰後福利

上面三十行程式碼手把手教你實現了一個 (糊弄)女票的方法,基本功能還是很完整的,當然如此貼心的一灰灰我,也給各位小夥伴提供了更友好的方式,如直接從網上載入圖片、字型

public void testCharPicture() throws Exception {

prefix = "/tmp/";

String img = "http://hbimg.b0.upaiyun.com/2b79e7e15883d8f8bbae0b1d1efd6cf2c0c1ed1b10753-cusHEA_fw236";

ImgPixelWrapper.build()

.setSourceImg(img)

.setChars("小黃人")

// 字型檔案下載地址: https://www.diyiziti.com/Builder/446

.setFontName("https://font.js.live/front/font/download?id=446")

.setBlockSize(24)

.setFontSize(22)

.setBgPredicate(color -> {

// 指定背景色,不渲染文字

if (color == 0) return true;

Color rc = ColorUtil.int2color(color);

// 將白色當作背景色

return rc.getRed() >= 245 && rc.getGreen() >= 245 && rc.getBlue() >= 245;

})

.setPixelType(PixelStyleEnum.CHAR_SEQ_SCALE_UP)

.build().asFile(prefix + "/char_pic_xhr.jpg");

System.out.println("---- over ---");

}

對應的原始碼:https://github.com/liuyueyi/quick-media

引入方式也很簡單

<artifactId>image-plugin</artifactId>

<groupId>com.github.liuyueyi.media</groupId>

<version>2.6.4</version>

是不是很貼心,是不是很感動,是不是應該點個贊、給個評論支援,加個收藏下次備用呢

一灰灰的聯絡方式

盡信書則不如無書,以上內容,純屬一家之言,因個人能力有限,難免有疏漏和錯誤之處,如發現bug或者有更好的建議,歡迎批評指正,不吝感激

個人站點:https://blog.hhui.top 微博地址:  小灰灰Blog [1] QQ:一灰灰/3302797840 微信公眾號: 一灰灰blog

QrCode