编译器:MinGW GCC 9.3.0
,编译命令 -Wall -Wl,--stack=998244353 -std=c++14 -O2
由于在 Devcpp 上配置 OpenCV 过于麻烦,且 OpenCV 难以学习,我便通过 了解BMP格式 + fread读取字节直接在无 OpenCV 的 Devcpp 中用数组存储了 BMP 图像(从 title.bmp
输入),并进行了颜色的近似转换,输出到了大小相同的 BMP 中(fout.bmp
),同时输出了该 BMP 的 8进制txt(test.txt
),以及对应的mcfunction(title.mcfunction
)。
注:只支持24位 BMP 或一些32位 BMP 。
按照字节顺序分别存到对应位置即可。
用 fread()
可以按照字节读入所有,不过返回的值不一定是正确的串长,所以正确的串长应该是上图中第 3~6 个字节表示的 BMP 大小。
编译器所限,目前可以转换的最大图片为 5000 X 5000
(宽和高都不应超过)。
我在 list.txt
中记录了 MC 中 38 种颜色较纯的方块的 I D \tt ID ID 以及 R G B \tt RGB RGB 颜色参数。
list.txt
文件第一行为方块数量,目前为 38 。后面每一行为一个字符串加上三个 0~255 的整数,分别表示:方块ID、R、G、B 。
以下 list.txt
只适用于 MC java edition 1.17 及以上(因为有“铜块”):
38
white_concrete 255 255 255
orange_concrete 226 97 0
magenta_concrete 171 47 161
light_blue_concrete 31 139 201
yellow_concrete 241 176 13
lime_concrete 95 171 19
pink_concrete 215 101 144
gray_concrete 51 55 59
light_gray_concrete 125 125 115
cyan_concrete 13 119 136
purple_concrete 101 26 158
blue_concrete 40 42 144
brown_concrete 97 58 26
green_concrete 71 90 31
red_concrete 144 27 27
black_concrete 2 3 7
gold_block 254 231 77
diamond_block 112 251 240
emerald_block 65 243 132
waxed_copper_block 214 123 91
waxed_oxidized_copper 110 197 159
purpur_block 186 149 186
terracotta 155 96 69
white_terracotta 208 177 160
orange_terracotta 166 86 34
magenta_terracotta 147 82 106
light_blue_terracotta 113 107 136
yellow_terracotta 187 133 27
lime_terracotta 98 114 45
pink_terracotta 165 74 78
gray_terracotta 55 36 27
light_gray_terracotta 131 102 92
cyan_terracotta 84 89 89
purple_terracotta 121 69 86
blue_terracotta 70 54 88
brown_terracotta 73 45 27
green_terracotta 71 78 33
red_terracotta 136 51 37
适合 1.17 版本前的 list.txt
(用两种海晶石近似替换了铜块):
38
white_concrete 255 255 255
orange_concrete 226 97 0
magenta_concrete 171 47 161
light_blue_concrete 31 139 201
yellow_concrete 241 176 13
lime_concrete 95 171 19
pink_concrete 215 101 144
gray_concrete 51 55 59
light_gray_concrete 125 125 115
cyan_concrete 13 119 136
purple_concrete 101 26 158
blue_concrete 40 42 144
brown_concrete 97 58 26
green_concrete 71 90 31
red_concrete 144 27 27
black_concrete 2 3 7
gold_block 254 231 77
diamond_block 112 251 240
emerald_block 65 243 132
purpur_block 186 149 186
terracotta 155 96 69
white_terracotta 208 177 160
orange_terracotta 166 86 34
magenta_terracotta 147 82 106
light_blue_terracotta 113 107 136
yellow_terracotta 187 133 27
lime_terracotta 98 114 45
pink_terracotta 165 74 78
gray_terracotta 55 36 27
light_gray_terracotta 131 102 92
cyan_terracotta 84 89 89
purple_terracotta 121 69 86
blue_terracotta 70 54 88
brown_terracotta 73 45 27
green_terracotta 71 78 33
red_terracotta 136 51 37
prismarine_bricks 105 182 171
dark_prismarine 51 86 72
然后对于原图中的一个像素,将其映射到 RGB 颜色立方体中的一个坐标点,找到 38 种方块中与该像素欧几里得距离最短的方块,就可以比较近似地转换颜色。
程序一开始需要在 stdin
中输入三个数,分别是图片面向西边时的右下角 X、Y、Z 坐标,
然后,把每个像素对应的方块通过 setblock
的指令形式输出到 fout.mcfunction
就好了。
代码有彩蛋
#include
#include
#define MAXN 5005 // max Hight - 1
#define MAXM 5005 // max Width - 1
#define UINT unsigned int
#define UCHA unsigned char
//--------- OI part ---------
#include
#include
#include
#include
#include
#include
#include
#include
#define LL long long
#define ENDL putchar('\n')
#define DB double
#define lowbit(x) (-(x) & (x))
#define FI first
#define SE second
LL read() {
LL f = 1,x = 0;int s = getchar();
while(s < '0' || s > '9') {if(s<0)return -1;if(s=='-')f=-f;s = getchar();}
while(s >= '0' && s <= '9') {x = (x<<1) + (x<<3) + (s^48);s = getchar();}
return f*x;
}
void putpos(LL x) {if(!x)return ;putpos(x/10);putchar((x%10)^48);}
void putnum(LL x) {
if(!x) {putchar('0');return ;}
if(x<0) putchar('-'),x = -x;
return putpos(x);
}
void AIput(LL x,int c) {putnum(x);putchar(c);}
//-----------------------------
using namespace std;
void SetFont(int size = 30) { // Useless function
CONSOLE_FONT_INFOEX cfi;
cfi.cbSize = sizeof cfi;
cfi.dwFontSize.X = 4;
cfi.dwFontSize.Y = 8;
SetCurrentConsoleFontEx(GetStdHandle(STD_OUTPUT_HANDLE), FALSE, &cfi);
}
void putbit(char c) {
for(int i = (1<<7);i > 0;i >>= 1) {
putchar((c&i) ? '1':'0');
}
putchar(' ');
return ;
}
UINT n,m,s,o,k;
const int CMAXN = MAXN*MAXM+100;
UCHA a[CMAXN];
struct PT{
UCHA B,G,R,A;
PT(){B=G=R=A=0;}
bool isblack() {return !B && !G && !R;}
int Y() {return (0.299*R)+(0.587*G)+(0.114*B);}
int S() {
int mx = max(B,max(G,R));
if(mx == 0) return 0;
return (mx-min(B,min(G,R)))*255/mx;
}
}mt[MAXN][MAXM],blc[200];
int rsb[MAXN][MAXM],cntb;
LL dis(PT a,PT b) {
LL yd = 0;//a.S()-b.S(); // 模式开关!!!把 "0;//" 去掉可添加"颜色饱和度"作为参数
return yd*yd+(a.R-b.R)*1ll*(a.R-b.R) + (a.G-b.G)*1ll*(a.G-b.G) + (a.B-b.B)*1ll*(a.B-b.B);
}
char nameid[200][100];
int xx0,yy0,zz0;
int main() {
xx0 = read(); yy0 = read(); zz0 = read(); // Input initial 3-dimensional coordinate
freopen("title.bmp","r",stdin); // "title" is replaceable
fread(a,1,CMAXN,stdin);
UCHA tpe[2] = {a[0],a[1]};
UINT SIZE = ((UINT)a[5]<<24) | ((UINT)a[4]<<16) | ((UINT)a[3]<<8) | ((UINT)a[2]);
UINT len = SIZE;
cerr<<"SIZE:"<<len<<endl;
freopen("test.txt","w",stdout); // output BMP with 8-base numbers
for(UINT i = 0;i < len;i ++) printf("%02x%s",a[i],i%2 ? " ":"");
UINT pos = ((UINT)a[13]<<24) | ((UINT)a[12]<<16) | ((UINT)a[11]<<8) | ((UINT)a[10]);
UINT header = ((UINT)a[17]<<24) | ((UINT)a[16]<<16) | ((UINT)a[15]<<8) | ((UINT)a[14]);
m = ((UINT)a[21]<<24) | ((UINT)a[20]<<16) | ((UINT)a[19]<<8) | ((UINT)a[18]); // Width
n = ((UINT)a[25]<<24) | ((UINT)a[24]<<16) | ((UINT)a[23]<<8) | ((UINT)a[22]); // Hight
// a[26] = 1 , a[27] = 0
UINT tp = ((UINT)a[29]<<8) | ((UINT)a[28]); // Color type , a[29] = 0
// a[30~33] = 0, meaning no compress
UINT picsize = ((UINT)a[37]<<24) | ((UINT)a[36]<<16) | ((UINT)a[35]<<8) | ((UINT)a[34]);
// a[38~53] = 0
UINT ad = 54,el = (4 - (tp>>3)*m%4)%4;
cerr<<"color_type:"<<tp<<" tail_size:"<<el<<endl;
for(UINT i = 1;i <= n;i ++) {
for(UINT j = 1;j <= m;j ++) {
mt[i][j].B = a[ad ++];
mt[i][j].G = a[ad ++];
mt[i][j].R = a[ad ++];
if(tp == 32) mt[i][j].A = a[ad ++];
}
ad += el;
}
// printf("size: %d, %d x %d\n",SIZE,n,m);
// for(UINT i = n;i > 0;i --) {
// for(UINT j = 1;j <= m;j ++) {
// if(mt[i][j].isblack()) printf(" ");
// else printf("##");
// }
// ENDL;
// }
freopen("list.txt","r",stdin);
cntb = read();
for(UINT i = 0;i < cntb;i ++) {
scanf("%s",nameid[i]);
blc[i].R = read();
blc[i].G = read();
blc[i].B = read();
}
blc[cntb].R = blc[cntb].G = blc[cntb].B = 0;
ad = 54;
freopen("title.mcfunction","w",stdout); // "title" is replaceable
a[28] = 24u;
el = (4-3*m%4)%4;
// printf("fill %d %d %d %d %d %d air\n",xx0,yy0,zz0,xx0+m-1,yy0+n-1,zz0); // X and Y
printf("fill %d %d %d %d %d %d air\n",xx0,yy0+1,zz0,xx0,yy0+n,zz0-m+1); // Y and Z
for(int i = 1;i <= n;i ++,ad += el) {
for(int j = 1;j <= m;j ++,ad += 3) {
if(mt[i][j].isblack()) continue;
LL ds = dis(mt[i][j],blc[0]);
UINT bli = 0;
for(UINT k = 1;k < cntb;k ++) {
LL d2 = dis(mt[i][j],blc[k]);
if(d2 < ds) {
ds = d2; bli = k;
}
}
rsb[i][j] = bli;
a[ad] = blc[bli].B;
a[ad+1] = blc[bli].G;
a[ad+2] = blc[bli].R;
// printf("setblock %d %d %d %s\n",xx0+j-1,yy0+i-1,zz0,nameid[bli]); // X and Y
printf("setblock %d %d %d %s\n",xx0,yy0+i,zz0-m+j,nameid[bli]); // Y and Z
}
for(UINT j = 0;j < el;j ++) a[ad+j] = 0;
}
picsize = ad-54; len = ad;
a[34] = picsize & 255; picsize >>= 8;
a[35] = picsize & 255; picsize >>= 8;
a[36] = picsize & 255; picsize >>= 8;
a[37] = picsize & 255;
// cerr<
freopen("fout.bmp","w",stdout); // preview
fwrite(a,1,len,stdout);
return 0;
}