抖音上炫代碼的不少嘹屯,有些真的讓人嘆為觀止,作為一個androider从撼,當我看到下面這段舞蹈的時候州弟,終于忍不住了,想要通過android實現(xiàn)一樣的效果低零。
這么好玩的東西婆翔,為啥就沒有大佬做呢,原因可能有兩個掏婶,一是真的難啃奴,二是出力不討好,難以達到最終效果气堕,一番嘗試后纺腊,技術問題都解決了畔咧,但并沒有達到電腦端美感,手機屏幕還是太小了揖膜。誓沸。
這是電腦端的靜態(tài)圖
這是手機端的
猜猜下面這張是誰
下面開始分析代碼,首先根據(jù)圖片像素灰度轉為ascii字符壹粟,這在網上有現(xiàn)成的java代碼拜隧,android上只需要改一點api就可以,代碼如下
public static Bitmap createAsciiPic(final String path, Context context) {
final String base = "#8XOHLTI)i=+;:,.";// 字符串由復雜到簡單
// final String base = "#,.0123456789:;@ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";// 字符串由復雜到簡單
StringBuilder text = new StringBuilder();
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics dm = new DisplayMetrics();
wm.getDefaultDisplay().getMetrics(dm);
int width = dm.widthPixels;
int height = dm.heightPixels;
Bitmap image = BitmapFactory.decodeFile(path); //讀取圖片
int width0 = image.getWidth();
int height0 = image.getHeight();
int width1, height1;
int scale = 7;
if (width0 <= width / scale) {
width1 = width0;
height1 = height0;
} else {
width1 = width / scale;
height1 = width1 * height0 / width0;
}
image = scale(path, width1, height1); //讀取圖片
//輸出到指定文件中
for (int y = 0; y < image.getHeight(); y += 2) {
for (int x = 0; x < image.getWidth(); x++) {
final int pixel = image.getPixel(x, y);
final int r = (pixel & 0xff0000) >> 16, g = (pixel & 0xff00) >> 8, b = pixel & 0xff;
final float gray = 0.299f * r + 0.578f * g + 0.114f * b;
final int index = Math.round(gray * (base.length() + 1) / 255);
String s = index >= base.length() ? " " : String.valueOf(base.charAt(index));
text.append(s);
}
text.append("\n");
}
return textAsBitmap(text, context);
// return image;
}
這樣處理完得到的ascii文本趁仙,但我們需要的是ascii圖片洪添,那我們需要怎么做呢,截屏雀费?請讀者思考10秒鐘干奢,想想自己的解決方案。我這里通過TextPanit和staticLayout實現(xiàn)的盏袄,也可以new一個TextView忿峻,寫入文本,然后把Textview的緩沖區(qū)轉換為圖片辕羽,但是這種staticLayout的方式更底層逛尚,更有效,代碼如下
public static Bitmap textAsBitmap(StringBuilder text, Context context) {
TextPaint textPaint = new TextPaint();
// textPaint.setARGB(0x31, 0x31, 0x31, 0);
textPaint.setColor(Color.BLACK);
textPaint.setAntiAlias(true);
textPaint.setTypeface(Typeface.MONOSPACE);
textPaint.setTextSize(12);
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics dm = new DisplayMetrics();
wm.getDefaultDisplay().getMetrics(dm);
int width = dm.widthPixels; //
StaticLayout layout = new StaticLayout(text, textPaint, width,
Layout.Alignment.ALIGN_CENTER, 1f, 0.0f, true);
Bitmap bitmap = Bitmap.createBitmap(layout.getWidth() + 20,
layout.getHeight() + 20, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
canvas.translate(10, 10);
canvas.drawColor(Color.WHITE);
// canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);//繪制透明色
layout.draw(canvas);
Log.d("textAsBitmap",
String.format("1:%d %d", layout.getWidth(), layout.getHeight()));
return bitmap;
}
相對于電腦端有無邊無際的txt編輯框刁愿,android里text是有字數(shù)限制的绰寞,所以原始圖片如果像素過多的話就要進行尺寸壓縮。而且textPaint的這個設置特別重要textPaint.setTypeface(Typeface.MONOSPACE);字體對效果的影響太大了铣口,失之毫厘謬以千里滤钱,這是一個大坑,說多了都是時間枷踏。
我在項目里集成了一個圖片選擇庫菩暗,可以直接把拍的照片轉化為ascii圖,碰到一個問題就是拍照圖片拿到后都會自動旋轉90度旭蠕,很是困惑,雖然找到了處理方法旷坦,但系統(tǒng)為啥要作旋轉處理掏熬,還請知道的大神告知原因。處理代碼如下
/**
* 讀取照片旋轉角度
*
* @param path 照片路徑
* @return 角度
*/
public static int readPictureDegree(String path) {
int degree = 0;
try {
ExifInterface exifInterface = new ExifInterface(path);
int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
switch (orientation) {
case ExifInterface.ORIENTATION_ROTATE_90:
degree = 90;
break;
case ExifInterface.ORIENTATION_ROTATE_180:
degree = 180;
break;
case ExifInterface.ORIENTATION_ROTATE_270:
degree = 270;
break;
}
} catch (IOException e) {
e.printStackTrace();
}
return degree;
}
public static String amendRotatePhoto(String originpath, Context context) {
// 取得圖片旋轉角度
int angle = readPictureDegree(originpath);
// 把原圖壓縮后得到Bitmap對象
if (angle != 0) {
Bitmap bmp = getCompressPhoto(originpath);
Bitmap bitmap = rotaingImageView(angle, bmp);
return savePhotoToSD(bitmap, context);
} else {
return originpath;
}
}
public static Bitmap rotaingImageView(int angle, Bitmap bitmap) {
Bitmap returnBm = null;
// 根據(jù)旋轉角度秒梅,生成旋轉矩陣
Matrix matrix = new Matrix();
matrix.postRotate(angle);
try {
// 將原始圖片按照旋轉矩陣進行旋轉旗芬,并得到新的圖片
returnBm = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
} catch (OutOfMemoryError e) {
}
if (returnBm == null) {
returnBm = bitmap;
}
if (bitmap != returnBm) {
bitmap.recycle();
}
return returnBm;
}
這些代碼都在文末的項目里。
按說拿到ascii圖后捆蜀,想要把整個視頻轉換成ascii字符視頻就很簡單了疮丛。只要把視頻逐幀抽成圖片幔嫂,圖片轉換后,再合成為視頻播放出來誊薄,但我視頻庫用的不多履恩,希望有能力的朋友可以幫助完成最后一步。
最后呢蔫,也希望朋友們能把一些有趣的想法實踐到android項目中來切心,讓搬磚之余,有更多的樂趣片吊。
github地址https://github.com/meiniepan/Pic2Ascii