|
这次课,我们实现一些漂亮的字符画:

1 图片的读取与显示
首先,可以找一些免费的图片,比如:
https://www.hippopx.com/zh/child-portrait-girl-model-young-beautiful-female-12439

利用EasyX,可以比较容易读取图片数据,在程序中显示图片:

#include <graphics.h>
#include <conio.h>
int main()
{
IMAGE im; // 图像变量
loadimage(&im, _T(&#34;pic1.jpg&#34;)); // 导入图像文件
int width, height; // 图片的宽度、高度,也是屏幕的宽度、高度
width = im.getwidth(); // 获得图像的宽度
height = im.getheight(); // 获得图像的高度
initgraph(width, height); // 新开一个画面
putimage(0, 0, &im); // 显示图片
_getch();
return 0;
}
2 均匀采样的小球画
对图片的行、列进行均匀采样,在对应采样点,以图片的颜色,画一个小球:

#include <graphics.h>
#include <conio.h>
int main()
{
IMAGE im; // 图像变量
loadimage(&im, _T(&#34;pic1.jpg&#34;)); // 导入图像文件
int width, height; // 图片的宽度、高度,也是屏幕的宽度、高度
width = im.getwidth(); // 获得图像的宽度
height = im.getheight(); // 获得图像的高度
DWORD* pMem = GetImageBuffer(&im); // 获得图像内容缓存
int interval = 10; // 图像行、列的采样间隔
initgraph(width, height); // 新开一个画面
setbkcolor(WHITE); // 设置背景颜色为白色
cleardevice(); // 以背景颜色清屏
for (int i = 0; i < height; i = i + interval) // 当行数遍历
{
for (int j = 0; j < width; j = j + interval) // 当列数遍历
{
DWORD c = pMem[i * width + j]; // 获得i行j列图像像素信息
COLORREF col = BGR(pMem[i * width + j]); // 获得i行j列像素的颜色
int R = GetRValue(col); // 红色分量
int G = GetGValue(col); // 绿色分量
int B = GetBValue(col); // 蓝色分量
setfillcolor(RGB(R, G, B)); // 设置填充、线条颜色
setlinecolor(RGB(R, G, B));
int bright = 0.299 * R + 0.587 * B + 0.114 * B; // 获得当前像素的亮度
// 将[0,255]范围的亮度bright,映射为[1,interval]的值,设为半径大小
float radius = interval + (1 - interval) * bright / 255.0;
fillcircle(j, i, 0.9*radius); // 在当前位置,画一个圆球
}
}
_getch();
return 0;
}
3 随机小球画
上一节的小球分布太均匀了,可以引入随机数,对采样点的位置进行随机偏移,生成随机采样的小球画:

#include <graphics.h>
#include <conio.h>
#include <time.h>
int main()
{
srand(time(0)); // 初始化随机种子
IMAGE im; // 图像变量
loadimage(&im, _T(&#34;pic1.jpg&#34;)); // 导入图像文件
int width, height; // 图片的宽度、高度,也是屏幕的宽度、高度
width = im.getwidth(); // 获得图像的宽度
height = im.getheight(); // 获得图像的高度
DWORD* pMem = GetImageBuffer(&im); // 获得图像内容缓存
int interval = 8; // 图像行、列的采样间隔
initgraph(width, height); // 新开一个画面
setbkcolor(WHITE); // 设置背景颜色为白色
cleardevice(); // 以背景颜色清屏
int i = 0, j; // 行、列循环变量
while (i < height) // 当行数小于height时
{
j = 0; // 列数初始化为0
while (j < width) // 当列数小于width时
{
DWORD c = pMem[i * width + j]; // 获得i行j列图像像素信息
COLORREF col = BGR(pMem[i * width + j]); // 获得i行j列像素的颜色
int R = GetRValue(col); // 红色分量
int G = GetGValue(col); // 绿色分量
int B = GetBValue(col); // 蓝色分量
setfillcolor(RGB(R, G, B)); // 设置填充、线条颜色
setlinecolor(RGB(R, G, B));
int bright = 0.299 * R + 0.587 * B + 0.114 * B; // 获得当前像素的亮度
// 将[0,255]范围的亮度bright,映射为[1,interval]的值,设为半径大小
float radius = interval + (1 - interval) * bright / 255.0;
fillcircle(j, i, radius); // 在当前位置,画一个圆球
j = j + 2* radius + rand() % 3; // 列号向右平移一定距离
}
i = i + 1.2 * interval + rand() % 2; // 行号向下,有一定随机性
}
_getch();
return 0;
}
4 字符小球画
和这一章字符串的主题结合,将小球用一个字符&#39;o&#39;来替代,可以绘制出一个字符小球画:

#include <graphics.h>
#include <conio.h>
#include <time.h>
int main()
{
srand(time(0)); // 初始化随机种子
IMAGE im; // 图像变量
loadimage(&im, _T(&#34;pic1.jpg&#34;)); // 导入图像文件
int width, height; // 图片的宽度、高度,也是屏幕的宽度、高度
width = im.getwidth(); // 获得图像的宽度
height = im.getheight(); // 获得图像的高度
DWORD* pMem = GetImageBuffer(&im); // 获得图像内容缓存
int interval = 6; // 图像行、列的采样间隔
initgraph(width, height); // 新开一个画面
setbkcolor(WHITE); // 设置背景颜色为白色
setbkmode(TRANSPARENT); // 文字字体透明
cleardevice(); // 以背景颜色清屏
char ch = &#39;o&#39;; // 要显示的字符
int i = 0, j; // 行、列循环变量
while (i < height) // 当行数小于height时
{
j = 0; // 列数初始化为0
while (j < width) // 当列数小于width时
{
DWORD c = pMem[i * width + j]; // 获得i行j列图像像素信息
COLORREF col = BGR(pMem[i * width + j]); // 获得i行j列像素的颜色
int R = GetRValue(col); // 红色分量
int G = GetGValue(col); // 绿色分量
int B = GetBValue(col); // 蓝色分量
int bright = 0.299 * R + 0.587 * B + 0.114 * B; // 获得当前像素的亮度
// 将[0,255]范围的亮度bright,映射为[1,2*interval]的值,设为文字大小
float chSize = 2 * interval + (1 - 2 * interval) * bright / 255.0;
settextcolor(RGB(R, G, B));// 设定文字颜色为当前位置的图像像素颜色
settextstyle(1.5 * chSize, 0, _T(&#34;Comic Sans MS&#34;)); // 设置文字大小、字体
outtextxy(j, i, ch); // 在当前位置,输出当前字符
j = j + textwidth(ch) + rand() % 2; // 列号向右平移当前字符的宽度
}
i = i + 1.2 * interval + rand() % 2; // 行号向下,有一定随机性
}
_getch();
return 0;
}
5 任意字符串画
将单个字符扩展为字符串,比如&#34;Learning C with a ball &#34;,实现任意字符串画:

#include <graphics.h>
#include <conio.h>
#include <time.h>
#include <string.h>
int main()
{
srand(time(0)); // 初始化随机种子
IMAGE im; // 图像变量
loadimage(&im, _T(&#34;pic1.jpg&#34;)); // 导入图像文件
int width, height; // 图片的宽度、高度,也是屏幕的宽度、高度
width = im.getwidth(); // 获得图像的宽度
height = im.getheight(); // 获得图像的高度
DWORD* pMem = GetImageBuffer(&im); // 获得图像内容缓存
char str[] = &#34;Learning C with a ball &#34;; // 要输出的字符串
int strIndex = 0; // 从字符串中取字符的数组下标
int interval = 8; // 图像行、列的采样间隔
initgraph(width, height); // 新开一个画面
setbkcolor(WHITE); // 设置背景颜色为白色
setbkmode(TRANSPARENT); // 文字字体透明
cleardevice(); // 以背景颜色清屏
int i = 0, j; // 行、列循环变量
while (i < height) // 当行数小于height时
{
j = 0; // 列数初始化为0
while (j < width) // 当列数小于width时
{
DWORD c = pMem[i * width + j]; // 获得i行j列图像像素信息
COLORREF col = BGR(pMem[i * width + j]); // 获得i行j列像素的颜色
int R = GetRValue(col); // 红色分量
int G = GetGValue(col); // 绿色分量
int B = GetBValue(col); // 蓝色分量
int bright = 0.299 * R + 0.587 * B + 0.114 * B; // 获得当前像素的亮度
// 将[0,255]范围的亮度bright,映射为[1,2*interval]的值,设为文字大小
float chSize = 2*interval + (1 - 2*interval) * bright / 255.0;
char ch = str[strIndex]; // 获得字符串str第strIndex个字符
strIndex++; // 字符串序号加1
if (strIndex >= strlen(str)) // 到了字符串末尾后,序号归0
strIndex = 0;
settextcolor(RGB(R, G, B));// 设定文字颜色为当前位置的图像像素颜色
settextstyle(1.5 * chSize, 0, _T(&#34;Comic Sans MS&#34;)); // 设置文字大小、字体
outtextxy(j, i, ch); // 在当前位置,输出当前字符
j = j + textwidth(ch) ; // 列号向右平移当前字符的宽度
if (ch == &#39; &#39;) // 如果是空格,列号额外增加1或2
j = j + 1 + rand() % 2;
}
i = i + 1.2 * interval + rand() % 2; // 行号向下,有一定随机性
}
_getch();
return 0;
}
到这里,读者可以拿任意的图片,生成任意字符串画了。比如,也可以用“Stay hungry. Stay foolish. ”生成一张乔布斯的画像:

视频教程在这:

字符画的自动生成 C语言
https://www.zhihu.com/video/1576129731170332672
更多趣味学编程教学,可以参考童老师的图书: |
|