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());
}
}
}

最新文章

  1. C# 对象锁——Monitor
  2. 如何理解和熟练运用js中的call及apply?
  3. SpringMVC从入门到精通之第四章
  4. Unity 依赖注入知识点
  5. wp8 入门到精通 定时更新瓷贴
  6. iOS开发实用干货——强化你的Xcode控制台
  7. Android开发笔记:SQLite导入导出数据
  8. phread_con_wait和pthread_mutex_lock实现的生产者消费者模型
  9. Round Numbers
  10. 每天一个JavaScript实例-递归实现反转数组字符串
  11. MySQL连接及基本信息查看命令小结
  12. iOS 防止UIButton重复点击
  13. 第四节: EF调用存储过程的通用写法和DBFirst模式子类调用的特有写法
  14. 自定义View之一圆形图片
  15. 剑指offer-复杂链表的复制
  16. asp.net core web项目目录解读
  17. Unity Remote远程调试
  18. Hive静态分区和动态分区
  19. 8.Layout布局应用
  20. 【转载】Mysql主从复制、和MySQL集群(主主复制)

热门文章

  1. tinyxml2
  2. .NetCore——中小企业架构及通用权限管理系统开篇
  3. windows下Python开发错误记录以及解决方法
  4. 有些需要禁用的PHP危险函数(disable_functions)
  5. unity 动画 音频播放
  6. 关于typedef和struct
  7. Blazor之ABC
  8. yum安装PHP升级到7.1版本
  9. 运营的Python指南 - Python 操作Excel
  10. NOIP模拟13