1. Android實(shí)現(xiàn)圖片轉(zhuǎn)字符畫效果

        共 3284字,需瀏覽 7分鐘

         ·

        2021-11-18 07:56


        作者:kinton
        來源:https://www.jianshu.com/p/16ef3bf9ac5c


        開門見山!先上效果圖:



        原圖



        轉(zhuǎn)換字符畫

        字符稍微密集了一點(diǎn),不過放大來看大家應(yīng)該能夠看到確確實(shí)實(shí)是字符畫。
        那我們在安卓端是如何實(shí)現(xiàn)?
        Android開發(fā)中對(duì)圖片的操作,顯示一般都是通過Bitmap進(jìn)行的,我們可以通過圖片路徑獲取Bitmap對(duì)象:

        1static?public?Bitmap?getBitmapByUri(Context?context,?Uri?uri)?{
        2????????Bitmap?bit?=?null;
        3????????try?{
        4????????????bit?=?BitmapFactory.decodeStream(context.getContentResolver().openInputStream(uri));
        5????????}?catch?(Exception?ex)?{
        6????????????Log.i("utils",?""?+?ex.getMessage());
        7????????}
        8????????return?bit;
        9????}

        一個(gè)圖片的每一個(gè)像素其實(shí)都是一個(gè)值,這個(gè)值代表著這個(gè)像素的顏色,我們可以通過位運(yùn)算來獲取這個(gè)像素的ARGB值。
        在安卓開發(fā)中要獲取一個(gè)圖片的每一個(gè)像素值其實(shí)很簡單:

        1//按照參數(shù)范圍獲取像素?cái)?shù)組
        2bitmap.getPixels(...);
        3//或者獲取單個(gè)位置像素
        4bitmap.getPixel(x,y);

        當(dāng)我們獲取到了像素值,轉(zhuǎn)換成ARGB值后,我們獲取帶了RGB三個(gè)值,要如何判斷什么顏色用什么字?要知道調(diào)色輪盤的顏色數(shù)不勝數(shù):



        截取自iconfont的調(diào)色板

        這么多的顏色我們應(yīng)該用什么樣的標(biāo)準(zhǔn)給這么多顏色歸類?灰度值是個(gè)很好的辦法,什么是灰度值?灰度值的范圍只有0到255,計(jì)算方式一般是RGB三個(gè)值的平均值(也可以通過對(duì)RGB值進(jìn)行加權(quán)計(jì)算不同的灰度),在很多圖像處理里面的圖片灰度化步驟用的就是這種方法。



        灰度化示例(轉(zhuǎn)自百度百科圖片)

        原理跟思路清楚了,我們實(shí)現(xiàn)下把Bitmap轉(zhuǎn)化成灰度值數(shù)組的方法:

         1?static?public?int[][]?getBitmap2GaryArray(Bitmap?bitmap)?{
        2????????int?width?=?bitmap.getWidth();????????????//獲取位圖的寬
        3????????int?height?=?bitmap.getHeight();????????//獲取位圖的高
        4????????int[][]?datas?=?new?int[width][height];????//通過位圖的大小創(chuàng)建像素點(diǎn)數(shù)組
        5????????//也可以使用getPixels方法來獲取像素?cái)?shù)組
        6????????//bitmap.getPixels(datas,?0,?width,?0,?0,?width,?height);
        7????????int?alpha?=?0xFF?<24;
        8????????bitmap.getPixels();
        9????????for?(int?i?=?0;?i?width;?i++)?{
        10????????????for?(int?j?=?0;?j?height;?j++)?{
        11????????????????int?grey?=?bitmap.getPixel(i,?j);
        12????????????????int?red?=?(grey?&?0x00ff0000)?>>?16;?//取高兩位
        13????????????????int?green?=?(grey?&?0x0000ff00)?>>?8;?//取中兩位
        14????????????????int?blue?=?grey?&?0x000000ff;?//取低兩位
        15
        16????????????????grey?=?(int)?((float)?red?*?0.4?+?(float)?green?*?0.3?+?(float)?blue?*?0.3);
        17????????????????datas[i][j]?=?grey;
        18????????????}
        19????????}
        20????????return?datas;
        21????}

        在獲取像素前我們還需要多做一步,為了防止圖片過大(類似2K圖/4K圖),我們需要在獲取像素前做一次統(tǒng)一標(biāo)準(zhǔn)化的壓縮,我設(shè)置為寬為200,高等比例壓縮。

         1...
        2//寬為200時(shí),計(jì)算壓縮比例是多少
        3float?xScale?=?(float)?200?/?bitmap.getWidth();
        4bitmap?=?BitmapUtils.compressBitmap(bitmap,?xScale,?xScale);
        5...
        6
        7static?public?Bitmap?compressBitmap(Bitmap?bitmap,?float?sx,?float?sy)?{
        8????????Matrix?matrix?=?new?Matrix();
        9????????matrix.setScale(sx,?sy);
        10????????Log.i("utils_compressBitmap",?""?+?sx?+?","?+?sy);
        11????????Bitmap?bit?=?Bitmap.createBitmap(bitmap,?0,?0,?bitmap.getWidth(),
        12????????????????bitmap.getHeight(),?matrix,?true);
        13
        14????????Log.i("utils_compressBitmap",?""?+?bit.getWidth()?+?","?+?bit.getHeight());
        15????????//記得把不用的bitmap進(jìn)行回收,以防止OOM
        16????????bitmap.recycle();
        17????????return?bit;
        18????}

        當(dāng)我們通過壓縮好的圖片獲取到了它的灰度值數(shù)組,現(xiàn)在我們就可以根據(jù)灰度值轉(zhuǎn)換為對(duì)應(yīng)的文字了,我給了灰度值15個(gè)等級(jí),根據(jù)顏色的深度給對(duì)應(yīng)的中文字:(0是黑色,255是白色)

        1static?String[]?arr?=?{"餮",?"淼",?"圓",?"困",?"品",?"回",?"田",?"凸",?"口",?"王",?"天",?"干",?"工",?"十",?"一"};

        我們制定好字符等級(jí),那么要怎么根據(jù)數(shù)組制作圖片呢?
        上面說過圖片的操作在Android中一般都在Bitmap進(jìn)行的,所以我們要想繪制一張新的圖片,那么就創(chuàng)建一個(gè)新的Bitmap對(duì)象,繪制的事情交給萬能的畫布就好了,畫布帶有文字繪制接口完美的符合我們需求:

         1static?public?Bitmap?array2Bitmap(int[][]?garyDatas,?int?width,?int?height)?{
        2????????//繪制一個(gè)字對(duì)應(yīng)一個(gè)像素,所以新繪制的Bitmap的大小應(yīng)該乘上字體大小
        3????????Bitmap?whiteBgBitmap?=?Bitmap.createBitmap(width?*?6?+?20,?height?*?6?+?20,?Bitmap.Config.ARGB_8888);
        4????????//在Bitmap上創(chuàng)建畫布
        5????????Canvas?canvas?=?new?Canvas(whiteBgBitmap);
        6????????//繪制白色背景
        7????????canvas.drawARGB(255,?255,?255,?255);
        8????????//初始化畫筆
        9????????Paint?mPaint?=?new?Paint();
        10????????mPaint.setStrokeWidth(1);
        11????????mPaint.setColor(Color.BLACK);
        12????????mPaint.setTextSize(6);
        13
        14????????int?x?=?0;
        15?????????//遍歷灰度值數(shù)組
        16????????for?(int?xIndex?=?10;?x?6)?{
        17????????????int?y?=?0;
        18????????????for?(int?yIndex?=?10;?y?6)?{
        19????????????????//獲取灰度值對(duì)應(yīng)的字符
        20????????????????int?charIndex?=?garyDatas[x][y]?/?18;
        21????????????????String?_char?=?arr[charIndex];
        22????????????????//在對(duì)應(yīng)的坐標(biāo)繪制字符
        23????????????????canvas.drawText(_char,?xIndex,?yIndex,?mPaint);
        24????????????????y++;
        25????????????}
        26????????????x++;
        27????????}
        28????????return?whiteBgBitmap;
        29????}

        繪制完成后輸出Bitmap,下一步是把Bitmap保存為本地圖片,關(guān)鍵代碼如下:

         1...
        2File?photo?=?new?File(Environment.getExternalStorageDirectory()?+?"/"?+?dirName,?String.format("CharPic_%d.jpg",System.currentTimeMillis()));
        3
        4File?dir?=?new?File(photo.getParent());
        5if(!dir.exists()){
        6??????dir.mkdirs();
        7?}
        8photo.createNewFile();
        9saveBitmapToJPG(bmp,?photo);
        10...
        11
        12static?private?void?saveBitmapToJPG(Bitmap?bitmap,?File?photo)?throws?IOException?{
        13????????OutputStream?stream?=?new?FileOutputStream(photo);
        14????????bitmap.compress(Bitmap.CompressFormat.JPEG,?80,?stream);
        15????????stream.close();
        16????????bitmap.recycle();
        17????}

        下一步我們?yōu)榱嗽谙到y(tǒng)相冊更好的找到我們的圖片,我們可以把圖片發(fā)送一個(gè)廣播來通知系統(tǒng)相冊:

        1Intent?mediaScanIntent?=?new?Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
        2Uri?contentUri?=?Uri.fromFile(photo);
        3mediaScanIntent.setData(contentUri);
        4context.sendBroadcast(mediaScanIntent);

        以上就是圖片轉(zhuǎn)成字符畫的全部代碼與講解。可能有的人會(huì)問這樣的功能,除了酷炫,有趣,牛逼之外,做出來有什么用?我只能問得好!乍一看好像用處不大,但是基于這個(gè)功能我們可以做短視頻轉(zhuǎn)換字符畫視頻。下一篇我將會(huì)講一下如何把視頻轉(zhuǎn)換成字符畫視頻,本篇的內(nèi)容到此為止,如有問題,歡迎提出,如有錯(cuò)誤,歡迎指正,謝謝。

        奉上完整的源碼(已完成視頻轉(zhuǎn)換跟圖片轉(zhuǎn)換功能),覺得有趣的請(qǐng)star一下唄。
        完整項(xiàng)目源碼地址:https://github.com/452kinton/CharacterDance




        ? 耗時(shí)2年,Android進(jìn)階三部曲第三部《Android進(jìn)階指北》出版!

        ? 『BATcoder』做了多年安卓還沒編譯過源碼?一個(gè)視頻帶你玩轉(zhuǎn)!

        ? 『BATcoder』我去!安裝Ubuntu還有坑?

        ? 重生!進(jìn)階三部曲第一部《Android進(jìn)階之光》第2版 出版!


        ?BATcoder技術(shù)群,讓一部分人先進(jìn)大廠

        大家,我是劉望舒,騰訊TVP,著有三本業(yè)內(nèi)知名暢銷書,連續(xù)四年蟬聯(lián)電子工業(yè)出版社年度優(yōu)秀作者,百度百科收錄的資深技術(shù)專家。


        想要加入?BATcoder技術(shù)群,公號(hào)回復(fù)BAT?即可。

        為了防止失聯(lián),歡迎關(guān)注我的小號(hào)

        ??微信改了推送機(jī)制,真愛請(qǐng)星標(biāo)本公號(hào)??
        瀏覽 72
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評(píng)論
        圖片
        表情
        推薦
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
          
          

            1. 精品夜夜澡人妻无码AV | 17c.c-起草蜜桃视频 | 99在线观看免费视频 | 麻豆免费 成人 传媒 | 91淫荡视频 |