Android平台下的图片/视频转Ascii码图片/视频 (二)

2023-05-16

    忙里偷闲又来写一篇文章,最近在更新一些好玩的图片算法,当然也没落下优化ascii码的图像效果,这次我将更换一种计算ascii码的方式,这样能更好的添加一些效果,并且更加清楚的讲解一下原理。

    在上一篇文章里,有很多人留言给我说,为什么那个图片缩放比为7,改成6或者5为什么生成的图片就不正常了,这一点在我刚开始看类似的参考文献时也比较费解,不过在我多次的尝试时,发现7这个比例是最好的,至于原因,我讲出来想必你们肯定会失望了,因为我想说的是12号字符#8XOHLTI)i=+;:,.这几个在staticlayout里绘制出来以后大概占用7像素,想想,一个像素替换成了一个ascii码,如果图片缩放为屏幕宽的1/7,替换成字符以后,又会变成正好占满屏幕宽的ascii码图片。所以当改成缩放比为6,或者5以下时,由于一行像素替换成字符时,staticlayout再生成屏幕宽的图片时,因为一个字符占用7像素,所以在未到达换行符\n时会提前换行,导致生成的图片不正确。

    因为我也不喜欢猜或者试出来的方式来搞效果,因此我又想出了另一种方法生成ascii码图片,我选取了笔画具有代表性的汉字:"一七刀九上工土开天月”,当然我方法预留了可以使用其他字的地方,然后我对这些字进行以下处理:

  • 首先用Canvas绘制出这些字 使用Paint.FontMetrics fontMetrics = paint.getFontMetrics();测量出字绘制出来以后黑色的像素块float distance = (fontMetrics.bottom - fontMetrics.top) / 2 - fontMetrics.bottom;这个distance变量为绘制中心距离绘制baseline的距离,(这个地方不懂的具体可以百度android drawtext)
final String base = "一七刀九上工土开天月";// 随机字符串  当然如果你想更改成别的字符串也行,不过字符串的每个字最好涵盖各个复杂程度的字符
//            final String base = "#8XOHLTI)i=+; :,.";// 随机字符串
            float maxCharWidth = 0;
            Map<Character, Integer> blackMap = new HashMap<>();
//        final String base = "#8XOHLTI)i=+;:,.";// 随机字符串
            Paint paint = new Paint();
            paint.setStyle(Paint.Style.FILL);
            paint.setColor(Color.BLACK);
            paint.setStrokeWidth(0.1f);
            paint.setTextAlign(Paint.Align.CENTER);
            paint.setTextSize(10);
            Paint.FontMetrics fontMetrics = paint.getFontMetrics();
            float distance = (fontMetrics.bottom - fontMetrics.top) / 2 - fontMetrics.bottom;
            for (int i = 0; i < base.length(); i++) {
                float width = paint.measureText(base.charAt(i) + "");
                Bitmap bitmap = Bitmap.createBitmap(((int) width), ((int) (fontMetrics.bottom - fontMetrics.top)), Bitmap.Config.ARGB_8888);
                Canvas canvas = new Canvas(bitmap);
                canvas.drawColor(Color.WHITE);
                canvas.drawText(base.charAt(i) + "", 0, 1, bitmap.getWidth() / 2, bitmap.getHeight() / 2 + distance, paint);
                int[] pixels = new int[bitmap.getWidth() * bitmap.getHeight()];
                bitmap.getPixels(pixels, 0, bitmap.getWidth(), 0, 0, bitmap.getWidth(), bitmap.getHeight());
                int gray = 0;
                for (int pixel : pixels) {
                    if (pixel != -1) {
                        gray++;
                    }
                }
                blackMap.put(base.charAt(i), gray);
                int charWidth = bitmap.getWidth();
                int charHeight = bitmap.getHeight();
                if (maxCharWidth < Math.max(charWidth, charHeight)) {
                    maxCharWidth = Math.max(charWidth, charHeight);
                }
                bitmap.recycle();
            }
//            maxCharWidth *= (5 / 6f);
            Character[] characters = new Character[base.length()];
            for (int i = 0; i < characters.length; i++) {
                characters[i] = base.charAt(i);
            }
            Arrays.sort(characters, new Comparator<Character>() {
                @Override
                public int compare(Character o1, Character o2) {
                    return blackMap.get(o2) - blackMap.get(o1);
                }
            });

这里就是遍历每一个字符,绘制出来以后,保存所有字符最大的宽高,以此来像活字印刷一样,一个字符作为一个替换的像素群块,比如我以10字号大小来绘制每一个字符,对每一个汉字绘制出来以后需要用到多少个像素点(用像素点的多少来代表汉字的复杂程度),遍历计算完,发现最大宽高为8像素,然后我对base String进行排序,汉字复杂程度降序排列,如果过于亮的地方就用笔画少的字替换没毛病吧?

  • 紧接着对原图像进行缩放,使他的宽为屏幕宽,这样生成的图片不会过大,也不会过小导致效果不好看。
    (这里就不贴缩放代码了,想必各位android老铁缩放图片比我熟练)
  • 紧接着就到了重头戏了,刚才我第一步算出来了每一个待替换字符绘制出来的最大宽高,然后就以这个宽高一个块一个块像国际象棋格子一样的,替换掉同样大小的原图像素块,这里bitmap只能重新创建一个,因为是decode的bitmap,原来的像素数组不可修改。然后两层for循环遍历每一个分割的小块,计算出原图像这个小块左上角的像素点的灰度值,计算出这个灰度值在0到255内的哪个地方,因为如果带替换的字符为9个,那么就要分割成10份,要给空字符做为替换过于明亮的地方。(这里我就不求每一个原图像小块,比如10x10,内所有的像素点的灰度值了,java的效率你懂得,其实用一个像素来代表这个小像素块足够了),比如这个像素的灰度值为10,在0到255里,属于10个部分中的第一部分,是比较暗的部分,那么我就用10个可替换汉字中笔画最多的汉字来替换(当然在最开始提供可替换字符时,最好不要提供笔画过于多的汉字,因为这样会导致生成的图片过于胡一片)。
for (int y = 0; y < image.getHeight(); y += maxCharWidth) {
                for (int x = 0; x < image.getWidth(); x += maxCharWidth) {
//                    Log.i("icv", "绘制x=" + (x + 6f) + " y=" + (y + 6));
                    final int pixel = image.getPixel(x, y);
                    final int r = (pixel & 0xff0000) >> 16, g = (pixel & 0xff00) >> 8, b = pixel & 0xff;
                    final int gray = (int) (0.299f * r + 0.578f * g + 0.114f * b);
                    final int index = Math.round(gray * (characters.length + 1) / 255);
                    paint.setColor(Color.rgb(gray, gray, gray));
                    outCanvas.drawText(index >= characters.length ? " " : String.valueOf(characters[index]), x + maxCharWidth / 2f, y + maxCharWidth / 2f + distance, paint);
                }
            }
  • 还有一个神来之笔的步骤:如果你想生成彩色的字符,那么就把原图像盖在下面,让目前生成的字符画作为模板,让下面的颜色投过来,话不多说,上代码:
          if (isColorful) {
                for (int y = 0; y < outImage.getHeight(); y++) {
                    for (int x = 0; x < outImage.getWidth(); x++) {
                        if (outImage.getPixel(x, y) != Color.WHITE) {
                            outImage.setPixel(x, y, image.getPixel(x, y));
                        }
                    }
                }
            }
            image.recycle();

最后放一个效果图吧:
大公主黑白.png
大公主彩色.png
抖音

系列文章:
Android平台下的图片/视频转Ascii码图片/视频 (一)
Android平台下的图片/视频转Ascii码图片/视频 (二)

项目地址:https://github.com/LineCutFeng/PlayPicdio

参考文献:
无参考

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Android平台下的图片/视频转Ascii码图片/视频 (二) 的相关文章

  • MongoDB 查询包含某字符串的记录

    34 key 34 regex 广东
  • Anaconda使用conda连接网络出现错误(CondaHTTPError: HTTP 000 CONNECTION FAILED for url)

    进入 HOMEPATH 目录 编辑其中的 condarc 文件 删除 default 将 https 改成 http 转载自 Anaconda使用conda连接网络出现错误 CondaHTTPError HTTP 000 CONNECTIO
  • Win10 EFI启动文件被删的修复办法

    首先确保EFI分区存在 没有的话可以进入PE创建 首先是不成功的办法 xff1a 用PE里的EFI分区修复 xff0c 成功把Win7变成了EFI启动 xff08 以前梦寐以求的 xff09 xff0c 但是Win10一直修复失败 xff0
  • 关于UITabBarController的UITabBar隐藏问题

    最开始的时候我用的 void hideTabBar if self tabBarController tabBar hidden 61 61 YES return UIView contentView if self tabBarContr
  • NSAttributedString宽高计算小技巧

    通常对于CoreText之类自己实现绘制的控件来说 xff0c 计算富文本的宽高其实需要依赖CTFramesetterSuggestFrameSizeWithConstraints这个方法 但有些时候 xff0c 我们可能只是使用UILab
  • 拦截器获取HttpServletRequest里body数据

    一 问题 通过在拦截器中获取request中的json数据 xff0c 我们可以实现对参数进行校验和改写 问题是参数只能在拦截器里获取一次 xff0c 往后在controller层就无法获取数据 xff0c 提示body为空 在网上查找资料
  • iOS开发小技巧之--WeakSelf宏的进化

    我们都知道在防止如block的循环引用时 xff0c 会使用 weak关键字做如下定义 xff1a span class hljs keyword weak span typeof span class hljs keyword self
  • 用JavaScriptCore做android和iOS都兼容的JS-NativeSDK

    最近在给公司做一个JS Native的SDK xff0c 就是用于JS和原生之间的交互 使用场景上主要还是webView xff0c 那么原先的url拦截的方式已经不再考虑 xff0c 我们使用了iOS7之后的JavaScriptCore
  • 关于Xcode8 iOS10下模拟器NSLog不输出的问题

    昨天升级了Xcode8beta版 xff0c 兴高采烈的打开工程启动模拟器后发现自己的NSLog输出在console中看不到了 xff0c 查阅Xcode8 release note后发现官方的中有这么一段 When debugging a
  • ShareSDK 3.4.0 isWXAppInstalled 返回NO

    升级到3 4 0版本的ShareSDK之后 xff0c 发现 WXApi isWXAppInstalled 方法一直返回false xff0c 无法正常使用 初步怀疑是ShareSDK自己的bug 查找资料后发现 xff0c 解决方案居然是
  • iOS网络诊断功能 ping traceroute

    最近工作中总是遇到需要排查移动客户端网络状况的情况 xff0c 可能由于某些地区网络运营商的问题 xff0c 导致客户端某些功能不正常 xff0c 现在的做法也是非常麻烦的 xff1a 某用户反馈某一功能不能用由运营联系到该用户运营指导该用
  • macOS10.12下如何丝滑的使用appium?

    appium是一个自动化测试的跨平台解决方案 xff0c 这篇文章针对最新版的xcode 8 2和mac OS 10 12给出基本完成的部署过程 xff0c 值得一看 实际操作过程中 xff0c 有几个地方需要注意 xff1a 不要忘记启动
  • iOS如何在页面销毁时优雅的cancel网络请求

    大家都知道 xff0c 当一个网络请求发出去之后 xff0c 如果不管不顾 xff0c 有可能出现以下情况 xff1a 进入某个页面 xff0c 做了某种操作 xff08 退出页面 切换某个tab等等 xff09 导致之前的请求变成无用请求
  • glibc源码解读——malloc

    通过宏定义的展开 xff0c 找到malloc的函数地址 xff1a define C SYMBOL NAME name name define ASM LINE SEP void libc malloc size t bytes libc
  • 音视频开发入门基础知识(视频入门篇)

    RTSP实时音视频开发实战课程 xff1a lt RTSP实时音视频开发实战 gt 音视频开发入门基础知识 xff08 音频入门篇 xff09 目录 一 前言 二 视频采集和显示 三 视频常见的格式 四 RGB转YUV和YUV转RGB 五
  • Rust 类型、泛型和特征

    Rust 创建泛型 generic function rs fn give me lt T gt value T let 61 value fn main let a 61 34 generics 34 let b 61 1024 give
  • Vmware虚拟机硬盘扩容: Linux下虚拟机硬盘空间扩展及挂载配置

    都是自己使用过程中的小经验 xff0c 分享给大家 希望能互相帮助 进入正题 xff1a 大家是不是会遇到最初分配linux虚拟机硬盘后期不够用的情况 xff0c xff08 因为是我之前用友善之臂的虚拟机配ARM板学习 xff0c 只有2
  • 数据结构之冒泡排序

    文字描述 xff08 以升序为例 依次比较数组中相邻两个元素大小 xff0c 若a i gt a 43 1 xff0c 则交换两个元素 xff0c 两两都比较一遍称为一轮冒泡 xff0c 结果是让最大的元素排至最后重复以上步骤 xff0c
  • 十进制转八进制的方法

    include lt stdio h gt int main int n printf 34 请输入一个十进制的数 xff1a 34 scanf 34 d 34 amp n int i 61 0 int arr 100 while n 61
  • Nodejs之目录介绍及app.js说明

    随时随地阅读更多技术实战干货 xff0c 获取项目源码 学习资料 xff0c 请关注源代码社区公众号 ydmsq666 转自 xff1a https www cnblogs com Chen xy p 4466351 html nodejs

随机推荐

  • 源码学习笔记之Openssl

    目录 xff1a apps apps c apps h app rand c asn1pars c build info ca cert srl ca key pem ca req pem ca c CA pl in cert pem ci
  • Segmentation Fault错误原因总结

    一 什么是 Segmentation fault in Linux 所谓的段错误就是指访问的内存超过了系统所给这个程序的内存空间 通常这个值是由gdtr来保存的 他是一个48位的寄存器 其中的32位是保存由它指向的gdt表 后13位保存相应
  • 树莓派使用MobaXterm实现SSH和VNC

    树莓派使用MobaXterm实现SSH和VNC terminal推荐 xff1a MobaXterm 一 开机SSH无线连接 前提 xff1a 树莓派和PC在同一局域网下 xff0c 通过路由器获得树莓派ip 打开ssh boot目录新建文
  • 【Qt】QtCreator远程部署、调试程序

    1 添加远程设备 1 QtCreator 工具 gt 选项 gt 设备 gt 添加 2 设备设置向导选择 gt Generic Linux Device gt 开启向导 3 填写 标识配置的名称 随便写 设备IP 用户名 gt 下一步 4
  • Debian备份与还原

    备份 xff1a sudo su cd tar cvpzf backup tgz exclude 61 proc exclude 61 lost 43 found exclude 61 backup tgz exclude 61 mnt e
  • 微信开放平台-第三方平台开发配置及常见的问题

    目录 概述 参考文档 开源项目 amp 工具 第三方平台设置 问题及解决方法 概述 本实例 xff1a 第三方平台 43 微信公众号 xff08 服务号 xff09 微信开放平台 第三方平台 xff0c 为广大公众号和小程序提供运营服务和行
  • 【Python包管理系列1】python打包发布到PyPI全过程(入门版)

    文章目录 目的准备知识PyPIPyPAsetuptoolsbuildtwine 实战过程总结 目的 如果发布一个python包到pypi上 xff0c 共他人使用 xff0c 本文试图讲清楚 准备知识 PyPI 官网地址 xff1a htt
  • Web自动化测试(二)—— Selenium-API操作

    其他Web测试知识参考 xff1a Web自动化测试 目录 一 元素定位 1 如何进行元素定位 xff1f 2 浏览器开发者工具 2 1 如何使用浏览器开发者工具 二 元素定位方式 1 id定位 2 name定位 3 class name定
  • Java中字符串中子串的查找共有四种方法(indexof())

    亲测可用 xff0c 若有疑问请私信 indexOf 方法返回一个整数值 xff0c 指出 String 对象内子字符串的开始位置 如果没有找到子字符串 xff0c 则返回 1 如果 startindex 是负数 xff0c 则 start
  • 使用rust构建一个js引擎

    转载于 https my oschina net lilugirl2005 blog 3067895
  • Linux下使用acme.sh 配置https 免费证书

    acme sh 简单来说acme sh 实现了 acme 协议 可以从 let s encrypt 生成免费的证书 acme sh 有以下特点 xff1a 一个纯粹用Shell xff08 Unix shell xff09 语言编写的ACM
  • iOS 性能优化之内存优化

    近四年没更CSDN了 xff0c 感慨万千 近年来在搞一款比较大的APP xff0c 项目中代码量100w 43 xff0c 里面使用的三方库 其他领域的二进制包比较多 xff1b 以前这些三方 二进制都挤在同一个工程目录下 xff0c 导
  • 内核升级和降级

    查看已安装的内核 sudo dpkg get selections grep linux 不一样的系统版本升级内核要装的东西对应也不一样 xff0c 需要根据 get selections 安装对应的内核组件 使用apt get 即可完成安
  • Docker: Debian安装Docker

    Debian安装Docker 内容由 网络搜罗整理而来 xff0c 记录与共享 一 APT安装 官方Debian存储库中提供的Docker安装包可能不是最新版本 为了确保我们获得最新版本 xff0c 我们将从官方Docker存储库安装Doc
  • CodeBlocks快捷键

    原文地址 xff1a https blog csdn net lxt lucia article details 79572829 一 汇总 1 编辑部分 xff1a 按住Ctrl xff0c 滚动鼠标滚轮 xff0c 放大或缩小字体 Ct
  • ubuntu 操作系统的目录结构

    Ubuntu 系统的目录众多 xff0c 但是所有的目录都是在 目录下面的 xff0c 并且 Ubuntu 系统是不分 C 盘 D 盘等的 那么 Ubuntu 系统的这些目录具体有哪些呢 xff1f 他们的作用分别是什么呢 xff1f 下面
  • ubuntu安装和查看已安装

    说明 xff1a 由于图形化界面方法 xff08 如Add Remove 和Synaptic Package Manageer xff09 比较简单 xff0c 所以这里主要总结在终端通过命令行方式进行的软件包安装 卸载和删除的方法 一 U
  • CloudKitty安装指导

    安装以下几个模块 xff1a cloudkitty api API service cloudkitty processor Processing service collecting and rating cloudkitty dbsyn
  • Release file for http://xxx/ubuntu/dists/bionic-updates/InRelease is not valid yet报错解决

    参考 https blog 51cto com 5437315 2420097 中说明的原因 原因 xff1a 系统时间与网络时间 xff08 仓库 xff09 的不同导致更新错误 按照这个原因解释 xff0c 我查看了自己虚拟机内ubun
  • Android平台下的图片/视频转Ascii码图片/视频 (二)

    忙里偷闲又来写一篇文章 xff0c 最近在更新一些好玩的图片算法 xff0c 当然也没落下优化ascii码的图像效果 xff0c 这次我将更换一种计算ascii码的方式 xff0c 这样能更好的添加一些效果 xff0c 并且更加清楚的讲解一