CCF-画字符-详细的注释
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.StringTokenizer;
public class Main3 {
static int R, G, B;
static String reset = "\\x1B\\x5B\\x30\\x6D";
public static void main(String[] args) {
//test();
run();
}
public static void test() {
//测试代码
}
public static void run() {
FastIO io = new FastIO();
io.init(System.in);
int width = io.nextInt(), height = io.nextInt();
int pw = io.nextInt(), qh = io.nextInt();
int[][][] image = new int[height][width][3];
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
hexToRGB(io.next());
image[i][j][0] = R;
image[i][j][1] = G;
image[i][j][2] = B;
}
}
int count = pw * qh;//一个小块中像素点的数量
int rAvg = 0, gAvg = 0, bAvg = 0;
int preR = 0, preG = 0, preB = 0;
StringBuilder result = new StringBuilder();
boolean first = true;
for (int i = 0; i < height; i += qh) {
for (int j = 0; j < width; j += pw) {
int rSum = 0, gSum = 0, bSum = 0;
for (int y = i; y < i + qh; y++) {
for (int x = j; x < j + pw; x++) {
rSum += image[y][x][0];
gSum += image[y][x][1];
bSum += image[y][x][2];
}
}
rAvg = rSum / count;
gAvg = gSum / count;
bAvg = bSum / count;
if (first) {
//一行的开始,此时背景色已经是默认色,所以如果该块等于默认色,则什么都不做。
// 只有该块的颜色不等于默认色的时候才输出默认色
if (!(rAvg == 0 && gAvg == 0 && bAvg == 0)) {
changeBackground(rAvg, gAvg, bAvg, result);
}
first = false;
} else if (!(rAvg == preR && gAvg == preG && bAvg == preB)) {
//如果该块的颜色不等于上一块的颜色,且等于默认色输出重置序列
if (rAvg == 0 && gAvg == 0 && bAvg == 0) {
result.append(reset);
} else {
//如果该块的颜色不等于上一块的颜色,且不等于默认色,那么改变输出背景色序列
changeBackground(rAvg, gAvg, bAvg, result);
}
}
result.append("\\x20");
preR = rAvg;
preG = gAvg;
preB = bAvg;
}
//如果该行结束后时的背景色不等于默认色,则输出重置序列
if (!(rAvg == 0 && gAvg == 0 && bAvg == 0)) {
result.append(reset);
}
first = true;
//添加一个换行符
result.append("\\x0A");
}
//只在最后输出结果,而不是每一行就输出一次,这样可以减少IO次数,节约用时
System.out.print(result.toString());
}
/**
* 将颜色的16进制转换成(R,G,B)的形式
* @param hex 颜色的16进制值
*/
public static void hexToRGB(String hex) {
if (hex.length() == 4) {
//#abc->#aabbcc的情况
R = Integer.parseInt(hex.substring(1, 2) + hex.substring(1, 2), 16);
G = Integer.parseInt(hex.substring(2, 3) + hex.substring(2, 3), 16);
B = Integer.parseInt(hex.substring(3, 4) + hex.substring(3, 4), 16);
} else if (hex.length() == 2) {
//#a->#aaaaaa的情况
R = Integer.parseInt(hex.substring(1,2)+hex.substring(1,2), 16);
G = R;
B = R;
} else {
//#aabbcc的情况
R = Integer.parseInt(hex.substring(1, 3), 16);
G = Integer.parseInt(hex.substring(3, 5), 16);
B = Integer.parseInt(hex.substring(5, 7), 16);
}
}
/**
* 改变背景色
*/
public static void changeBackground(int R, int G, int B, StringBuilder hexOut) {
// ESC[48;2
hexOut.append("\\x1B\\x5B\\x34\\x38\\x3B\\x32\\x3B");
getHexOrder(R,hexOut);
// 3B对应字符 ;
hexOut.append("\\x3B");
getHexOrder(G, hexOut);
hexOut.append("\\x3B");
getHexOrder(B, hexOut);
// 6D 对应字符m
hexOut.append("\\x6D");
}
/**
* 获取一个分量每位对应的16进制,并且按照输出的顺序进行拼接
* @param a 颜色int值
*/
public static void getHexOrder(int a, StringBuilder hexOut) {
if (a >= 100) {
//该颜色分量有3位
hexOut.append("\\x");
// 48对应ACSII字符表中的'0' 字符,因为我们最终的输出时一个字符对应的转义序列,而不是10进制的int值的16进制,所以需要加上48
hexOut.append(Integer.toHexString(a / 100+48));
hexOut.append("\\x");
hexOut.append(Integer.toHexString(a / 10 % 10+48));
hexOut.append("\\x");
hexOut.append(Integer.toHexString(a % 10+48));
} else if (a >= 10) {
//颜色分量有2位
hexOut.append("\\x");
hexOut.append(Integer.toHexString(a / 10+48));
hexOut.append("\\x");
hexOut.append(Integer.toHexString(a % 10+48));
}else {
//颜色分量只有一位
hexOut.append("\\x");
hexOut.append(Integer.toHexString(48 + a));
}
}
static class FastIO {
BufferedReader reader;
StringTokenizer tokenizer;
void init(InputStream inputStream) {
reader = new BufferedReader(new InputStreamReader(inputStream));
tokenizer = new StringTokenizer("");
}
//读入一个字符串
String next() {
while (!tokenizer.hasMoreTokens()) {
try {
tokenizer = new StringTokenizer(reader.readLine());
} catch (IOException e) {
e.printStackTrace();
}
}
return tokenizer.nextToken();
}
//读入一整行
String nextLine() {
while (!tokenizer.hasMoreElements()) {
try {
tokenizer = new StringTokenizer(reader.readLine());
} catch (IOException e) {
e.printStackTrace();
}
}
return tokenizer.nextToken("\n");
}
//读入int类型数据
int nextInt() {
return Integer.parseInt(next());
}
//读入double类型数据
double nextDouble() {
return Double.parseDouble(next());
}
}
}
CCF-画字符-详细的注释的更多相关文章
- CCF 201909-3 字符画
CCF 201909-3 字符画 题意: 将n * m的RGB图片压缩成q * p的块,每块为该原像素的平均值,我们暂且称之为像素块(代码注释为字符块) . 输入n行m列的RGB图片: 第一行:图片的 ...
- Qt简单项目--加法计算器(详细代码注释)
Qt的简单案例--加法计算器(详细代码注释) 一.项目结构 二.项目代码 widget.h #ifndef WIDGET_H #define WIDGET_H //预编译指令, 为了避免头文件被重复包 ...
- ccf 201409-3 字符串匹配(toupper,tolower)
ccf 201409-3 字符串匹配(toupper,tolower) 问题描述 给出一个字符串和多行文字,在这些文字中找到字符串出现的那些行.你的程序还需支持大小写敏感选项:当选项打开时,表示同一 ...
- QT学习 之 对话框 (四) 字体对话框、消息对话框、文件对话框、进程对话框(超详细中文注释)
QMessageBox类: 含有Question消息框.Information消息框.Warning消息框和Critical消息框等 通常有两种方式可以来创建标准消息对话框: 一种是采用“基于属性”的 ...
- qt下的时钟程序(简单美丽,继承自QWidget的Clock,用timer调用update刷新,然后使用paintEvent作画就行了,超详细中文注释)good
最近抽空又看了下qt,发现用它来实现一些东西真的很容易比如下面这个例子,绘制了个圆形的时钟,但代码却清晰易懂[例子源自奇趣科技提供的例子]因为清晰,所以就只写注释了,吼吼其实也就这么几行代码头文件 / ...
- opencv 之 icvCreateHidHaarClassifierCascade 分类器信息初始化函数部分详细代码注释。
请看注释.这个函数,是人脸识别主函数,里面出现过的函数之一,作用是初始化分类器的数据,就是一个xml文件的数据初始化. static CvHidHaarClassifierCascade* icvCr ...
- 使用graphics2D给图片上画字符
//读取图片BufferedImage frontImage = ImageIO.read(new File(eCardXMLConfigManager.geteCardXMLConfigManage ...
- 洛谷 P3384 【模板】树链剖分-树链剖分(点权)(路径节点更新、路径求和、子树节点更新、子树求和)模板-备注结合一下以前写的题目,懒得写很详细的注释
P3384 [模板]树链剖分 题目描述 如题,已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作: 操作1: 格式: 1 x y z 表示将树从x到y结点最短路径上所有节 ...
- 微信支付接口--超详细带注释代码--Demo
如果本文对你有用,请爱心点个赞,提高排名,帮助更多的人.谢谢大家!❤ 如果解决不了,可以在文末进群交流. 如果对你有帮助的话麻烦点个[推荐]~最好还可以follow一下我的GitHub~感谢观看! 微 ...
随机推荐
- 基于 HTML5 + WebGL 实现的垃圾分类系统
前言 垃圾分类,一般是指按一定规定或标准将垃圾分类储存.分类投放和分类搬运,从而转变成公共资源的一系列活动的总称.分类的目的是提高垃圾的资源价值和经济价值,力争物尽其用.垃圾在分类储存阶段属于公众的私 ...
- vue系列---snabbdom.js使用及源码分析(九)
一:什么是snabbdom? 在学习Vue或React中,我们了解最多的就是虚拟DOM,虚拟DOM可以看作是一颗模拟了DOM的Javascript树,主要是通过vnode实现一个无状态的组件,当组件状 ...
- task一个任务结束后执行另一个操作
//创建一个任务 Task<int> task = new Task<int>(() => { ; //显示进度条遮照层, this.ShowPrograssBar(); ...
- JAVA基础知识注意事项
JAVA核心技术卷一 (第十版) 下面是需要注意的: 只有方法名和参数类型叫做方法的签名, 不同的返回类型值不能作为方法的签名.(4.6.1) 这是域与局部变量的主要不同点. 必须明确地初始化方法中的 ...
- [考试反思]0819NOIP模拟测试26:荒芜
这么正式的考试,明天应该就是最后一次了吧 然而..今天,我仍然没能抓住机会 RNBrank1:.skyh还是稳.外校gmk拿走第三. 四五六名都是63-64.第七50.第八39.我和三个并列的是第九. ...
- CSPS模拟 96
我菜的一批. 反省一下,我只能在简单场考的好的原因. 过分依赖灵感,不注意积累思路历程和各种套路.没灵感直接崩了 懒得打暴力,主要还是代码能力限制,打暴力真的很费时费力 不打对拍,这个emmm和第二条 ...
- 常用git命令教程
一.新建代码库 # 在当前目录新建一个Git代码库 $ git init # 新建一个目录,将其初始化为Git代码库 $ git init [project-name] # 下载一个项目和它的整个代码 ...
- 带你上手一款下载超 10 万次的 IDEA 插件
作者 | 倪超(银时) 阿里云开发者工具产品专家 本文整理自 11 月 7 日社群分享,每月 2 场高质量分享,点击加入社群. 导读:Cloud Toolkit 是本地 IDE 插件,帮助开发者更高效 ...
- 原生JS实现单向链表
1.前言 用JS实现一个简单的单向链表,并完成相关的功能 2.功能说明 push(value):从链表尾部添加一个新的节点 insertAfer(value,item):向链表中的item节点之后插入 ...
- 主席树学习笔记(静态区间第k大)
题目背景 这是个非常经典的主席树入门题——静态区间第K小 数据已经过加强,请使用主席树.同时请注意常数优化 题目描述 如题,给定N个整数构成的序列,将对于指定的闭区间查询其区间内的第K小值. 输入输出 ...