#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <linux/input.h>
#include <string.h>
#include <math.h>
#define LCD_WIDTH 800
#define LCD_HEIGHT 480
#define COLOR_RED 0xFF0000
#define COLOR_GREEN 0x00FF00
#define COLOR_BLUE 0x0000FF
#define COLOR_YELLOW 0xFFFF00
#define COLOR_MAGENTA 0xFF00FF
#define COLOR_CYAN 0x00FFFF
#define COLOR_WHITE 0xFFFFFF
#define COLOR_BLACK 0x000000
#define COLOR_GRAY 0x808080
#define COLOR_ORANGE 0xFFA500
#define COLOR_LIGHT_GRAY 0xC0C0C0
#define COLOR_DARK_GRAY 0x404040
// BMP文件头结构体(简化版,仅解析24位真彩色BMP)
typedef struct {
unsigned short bfType; // 文件类型(必须是0x4D42)
unsigned int bfSize; // 文件大小
unsigned short bfReserved1; // 保留
unsigned short bfReserved2; // 保留
unsigned int bfOffBits; // 图像数据偏移量
unsigned int biSize; // 信息头大小
int biWidth; // 图像宽度
int biHeight; // 图像高度
unsigned short biPlanes; // 平面数(必须是1)
unsigned short biBitCount; // 色深(24位)
unsigned int biCompression;// 压缩方式(0=不压缩)
unsigned int biSizeImage; // 图像数据大小
int biXPelsPerMeter; // 水平分辨率
int biYPelsPerMeter; // 垂直分辨率
unsigned int biClrUsed; // 使用的颜色数
unsigned int biClrImportant;// 重要颜色数
} BMPHeader;
// 全局变量
int colors[] = {COLOR_RED, COLOR_GREEN, COLOR_BLUE, COLOR_YELLOW, COLOR_MAGENTA, COLOR_CYAN, COLOR_WHITE};
int current_color_index = 0;
int current_brush_size = 2;
int *lcd_mem;
int lcd_fd;
int ts_fd;
// 函数声明
void draw_line(int x1, int y1, int x2, int y2, int color, int size);
void draw_char_16x16(int x, int y, unsigned char *font, int color);
void draw_string_16x16(int x, int y, unsigned char *fonts[], int count, int color);
void draw_hints();
void clear_screen();
void draw_circle(int center_x, int center_y, int radius, int color, int fill);
void draw_rect(int x1, int y1, int x2, int y2, int color, int fill);
// 新增:BMP图片绘制函数
int draw_bmp(int x, int y, const char *bmp_path);
// ==================== 16x16点阵字库 ====================
typedef unsigned char uchar;
// "颜色切换"
uchar font_yan[] = {0x00,0x00,0x7C,0x12,0x11,0x12,0x7C,0x00,0x00,0x10,0x08,0x04,0x02,0x01,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
uchar font_se[] = {0x00,0x00,0x3F,0x21,0x21,0x21,0x3F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
uchar font_qie[] = {0x00,0x00,0x00,0x7F,0x00,0x00,0x00,0x00,0x00,0x02,0x02,0x02,0x02,0x02,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
uchar font_huan[] = {0x00,0x00,0x3C,0x42,0x42,0x42,0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
// "笔粗调节"
uchar font_bi[] = {0x00,0x00,0x00,0x7F,0x00,0x00,0x00,0x00,0x00,0x01,0x02,0x04,0x08,0x10,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
uchar font_cu[] = {0x00,0x00,0x1F,0x11,0x11,0x11,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
uchar font_tiao[] = {0x00,0x00,0x7C,0x12,0x11,0x12,0x7C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
uchar font_jie[] = {0x00,0x00,0x3C,0x42,0x42,0x42,0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
// "橡皮擦"
uchar font_xiang[] = {0x00,0x00,0x7C,0x0A,0x09,0x0A,0x7C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
uchar font_pi[] = {0x00,0x00,0x3F,0x20,0x20,0x20,0x3F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
uchar font_ca[] = {0x00,0x00,0x10,0x10,0x7C,0x10,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
// "一键清除"
uchar font_yi[] = {0x00,0x00,0x00,0x7C,0x08,0x08,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
uchar font_jian[] = {0x00,0x00,0x38,0x44,0x44,0x10,0x78,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
uchar font_qing[] = {0x00,0x00,0x3C,0x24,0x24,0x24,0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
uchar font_chu[] = {0x00,0x00,0x1F,0x01,0x01,0x01,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
// ==================== 绘制函数 ====================
// 绘制16x16字符
void draw_char_16x16(int x, int y, uchar *font, int color) {
for (int i = 0; i < 16; i++) {
for (int j = 0; j < 8; j++) {
if (font[i] & (0x80 >> j)) {
if (x + j >= 0 && x + j < LCD_WIDTH && y + i >= 0 && y + i < LCD_HEIGHT) {
lcd_mem[(y + i) * LCD_WIDTH + (x + j)] = color;
}
}
}
for (int j = 0; j < 8; j++) {
if (font[i+16] & (0x80 >> j)) {
if (x + 8 + j >= 0 && x + 8 + j < LCD_WIDTH && y + i >= 0 && y + i < LCD_HEIGHT) {
lcd_mem[(y + i) * LCD_WIDTH + (x + 8 + j)] = color;
}
}
}
}
}
// 绘制16x16字符串
void draw_string_16x16(int x, int y, uchar *fonts[], int count, int color) {
for (int i = 0; i < count; i++) {
draw_char_16x16(x + i * 16, y, fonts[i], color);
}
}
// 绘制圆形
void draw_circle(int center_x, int center_y, int radius, int color, int fill) {
for (int y = -radius; y <= radius; y++) {
for (int x = -radius; x <= radius; x++) {
if (x*x + y*y <= radius*radius) {
int px = center_x + x;
int py = center_y + y;
if (px >= 0 && px < LCD_WIDTH && py >= 0 && py < LCD_HEIGHT) {
if (fill || x*x + y*y >= (radius-1)*(radius-1)) {
lcd_mem[py * LCD_WIDTH + px] = color;
}
}
}
}
}
}
// 绘制矩形
void draw_rect(int x1, int y1, int x2, int y2, int color, int fill) {
if (x1 > x2) { int temp = x1; x1 = x2; x2 = temp; }
if (y1 > y2) { int temp = y1; y1 = y2; y2 = temp; }
for (int y = y1; y <= y2; y++) {
for (int x = x1; x <= x2; x++) {
if (x >= 0 && x < LCD_WIDTH && y >= 0 && y < LCD_HEIGHT) {
if (fill || x == x1 || x == x2 || y == y1 || y == y2) {
lcd_mem[y * LCD_WIDTH + x] = color;
}
}
}
}
}
// 清屏
void clear_screen() {
for (int y = 0; y < LCD_HEIGHT; y++) {
for (int x = 0; x < LCD_WIDTH; x++) {
lcd_mem[y * LCD_WIDTH + x] = COLOR_BLACK;
}
}
}
// 绘制BMP图片(仅支持24位真彩色、无压缩BMP)
int draw_bmp(int x, int y, const char *bmp_path) {
int bmp_fd = open(bmp_path, O_RDONLY);
if (bmp_fd < 0) {
perror("Open BMP failed");
return -1;
}
BMPHeader header;
// 读取BMP头(注意:BMP是小端存储,x86架构可直接读取)
if (read(bmp_fd, &header, sizeof(BMPHeader)) != sizeof(BMPHeader)) {
perror("Read BMP header failed");
close(bmp_fd);
return -1;
}
// 校验BMP合法性
if (header.bfType != 0x4D42 || header.biBitCount != 24 || header.biCompression != 0) {
fprintf(stderr, "Unsupported BMP format\n");
close(bmp_fd);
return -1;
}
// 计算每行像素的字节数(BMP每行字节数必须是4的倍数)
int line_bytes = (header.biWidth * 3 + 3) & ~3;
unsigned char *line_buf = malloc(line_bytes);
if (!line_buf) {
perror("Malloc line buf failed");
close(bmp_fd);
return -1;
}
// 移动文件指针到图像数据起始位置
lseek(bmp_fd, header.bfOffBits, SEEK_SET);
// 绘制BMP(BMP图像是倒序存储,从下到上绘制)
for (int i = 0; i < header.biHeight; i++) {
if (read(bmp_fd, line_buf, line_bytes) != line_bytes) {
perror("Read BMP data failed");
free(line_buf);
close(bmp_fd);
return -1;
}
int draw_y = y + (header.biHeight - 1 - i); // 转换为LCD的Y坐标
if (draw_y < 0 || draw_y >= LCD_HEIGHT) continue;
for (int j = 0; j < header.biWidth; j++) {
int draw_x = x + j;
if (draw_x < 0 || draw_x >= LCD_WIDTH) continue;
// BMP是BGR格式,转换为RGB(LCD是RGB格式)
unsigned char b = line_buf[j*3];
unsigned char g = line_buf[j*3 + 1];
unsigned char r = line_buf[j*3 + 2];
int color = (r << 16) | (g << 8) | b;
lcd_mem[draw_y * LCD_WIDTH + draw_x] = color;
}
}
free(line_buf);
close(bmp_fd);
return 0;
}
// 绘制提示区(加载BMP图标)
void draw_hints() {
// 1. 颜色切换区(0-30行)
for (int i = 0; i < 7; i++) {
for (int y = 0; y < 30; y++) {
for (int x = i * 100; x < (i + 1) * 100; x++) {
if (x < LCD_WIDTH) lcd_mem[y * LCD_WIDTH + x] = colors[i];
}
}
}
// 当前颜色指示器
draw_circle(current_color_index * 100 + 50, 15, 8, COLOR_BLACK, 0);
// 文字提示:"颜色切换"
uchar *str_yanse[] = {&font_yan[0], &font_se[0], &font_qie[0], &font_huan[0]};
draw_string_16x16(720, 5, str_yanse, 4, COLOR_BLACK);
draw_string_16x16(718, 7, str_yanse, 4, COLOR_WHITE);
// 2. 笔粗调节区(30-60行)
for (int y = 30; y < 60; y++) {
for (int x = 0; x < LCD_WIDTH; x++) {
lcd_mem[y * LCD_WIDTH + x] = COLOR_DARK_GRAY;
}
}
// 画笔图标
draw_rect(20, 35, 40, 50, COLOR_WHITE, 1);
draw_rect(45, 35, 65, 50, COLOR_LIGHT_GRAY, 1);
draw_line(20, 35, 30, 42, COLOR_BLACK, 1);
draw_line(20, 50, 30, 43, COLOR_BLACK, 1);
// 画笔预览条
for (int y = 35; y < 55; y++) {
for (int x = 80; x < 80 + 20 * current_brush_size; x++) {
lcd_mem[y * LCD_WIDTH + x] = COLOR_WHITE;
}
}
// 文字提示:"笔粗调节"
uchar *str_bicu[] = {&font_bi[0], &font_cu[0], &font_tiao[0], &font_jie[0]};
draw_string_16x16(150, 35, str_bicu, 4, COLOR_WHITE);
// 粗细数字指示
draw_rect(300, 35, 315, 50, COLOR_WHITE, 1);
char size_str[2];
sprintf(size_str, "%d", current_brush_size);
if (size_str[0] == '1') {
draw_rect(304, 38, 306, 47, COLOR_BLACK, 1);
} else if (size_str[0] == '2') {
draw_rect(302, 38, 308, 41, COLOR_BLACK, 1);
draw_rect(308, 41, 308, 44, COLOR_BLACK, 1);
draw_rect(302, 44, 308, 47, COLOR_BLACK, 1);
draw_rect(302, 47, 302, 50, COLOR_BLACK, 1);
draw_rect(302, 50, 308, 50, COLOR_BLACK, 1);
}
// 3. 橡皮擦区(60-90行,左侧)
draw_rect(0, 60, 199, 89, COLOR_WHITE, 0);
for (int y = 61; y < 89; y++) {
for (int x = 1; x < 199; x++) {
lcd_mem[y * LCD_WIDTH + x] = COLOR_BLACK;
}
}
// 加载橡皮BMP图标(替换原手绘图标)
draw_bmp(30, 65, "eraser.bmp");
// 文字提示:"橡皮擦"
uchar *str_xiangpi[] = {&font_xiang[0], &font_pi[0], &font_ca[0]};
draw_string_16x16(100, 65, str_xiangpi, 3, COLOR_WHITE);
// 4. 一键清除区(60-90行,右侧)
draw_rect(200, 60, 399, 89, COLOR_BLACK, 0);
for (int y = 61; y < 89; y++) {
for (int x = 201; x < 399; x++) {
lcd_mem[y * LCD_WIDTH + x] = COLOR_WHITE;
}
}
// 加载一键清除BMP图标(替换原手绘图标)
draw_bmp(230, 65, "qingchu.bmp");
// 文字提示:"一键清除"
uchar *str_qingchu[] = {&font_yi[0], &font_jian[0], &font_qing[0], &font_chu[0]};
draw_string_16x16(300, 65, str_qingchu, 4, COLOR_BLACK);
// 5. 分隔线(90行)
for (int x = 0; x < LCD_WIDTH; x++) {
lcd_mem[90 * LCD_WIDTH + x] = COLOR_GRAY;
}
}
// 流畅画线函数
void draw_line(int x1, int y1, int x2, int y2, int color, int size) {
int dx = abs(x2 - x1);
int dy = abs(y2 - y1);
int sx = (x1 < x2) ? 1 : -1;
int sy = (y1 < y2) ? 1 : -1;
int err = dx - dy;
while (1) {
// 圆形画笔
for (int dy_pen = -size; dy_pen <= size; dy_pen++) {
for (int dx_pen = -size; dx_pen <= size; dx_pen++) {
if (dx_pen*dx_pen + dy_pen*dy_pen <= size*size) {
int x = x1 + dx_pen;
int y = y1 + dy_pen;
if (x >= 0 && x < LCD_WIDTH && y >= 91 && y < LCD_HEIGHT) {
lcd_mem[y * LCD_WIDTH + x] = color;
}
}
}
}
if (x1 == x2 && y1 == y2) break;
int e2 = 2 * err;
if (e2 > -dy) { err -= dy; x1 += sx; }
if (e2 < dx) { err += dx; y1 += sy; }
}
}
// 主函数
int main() {
// 打开LCD
lcd_fd = open("/dev/fb0", O_RDWR);
if (lcd_fd < 0) { perror("Open LCD failed"); return -1; }
lcd_mem = (int *)mmap(NULL, LCD_WIDTH*LCD_HEIGHT*4, PROT_READ | PROT_WRITE, MAP_SHARED, lcd_fd, 0);
if (lcd_mem == MAP_FAILED) { perror("MMAP LCD failed"); close(lcd_fd); return -1; }
// 打开触摸屏
ts_fd = open("/dev/input/event0", O_RDONLY);
if (ts_fd < 0) { perror("Open touch failed"); munmap(lcd_mem, LCD_WIDTH*LCD_HEIGHT*4); close(lcd_fd); return -1; }
clear_screen();
draw_hints();
struct input_event ev;
int prev_x=-1, prev_y=-1, curr_x=-1, curr_y=-1;
int is_erasing=0, is_touching=0;
while (1) {
ssize_t ret = read(ts_fd, &ev, sizeof(ev));
if (ret != sizeof(ev)) { perror("Read touch failed"); continue; }
// 更新坐标
if (ev.type == EV_ABS) {
if (ev.code == ABS_X) curr_x = ev.value;
else if (ev.code == ABS_Y) curr_y = ev.value;
}
// 触摸按下/抬起
else if (ev.type == EV_KEY && ev.code == BTN_TOUCH) {
if (ev.value == 1) {
is_touching = 1;
// 颜色切换区
if (curr_y < 30) {
current_color_index = curr_x / 100;
if (current_color_index >=7) current_color_index=6;
draw_hints();
}
// 笔粗调节区
else if (curr_y < 60) {
current_brush_size = (current_brush_size % 5) + 1;
draw_hints();
}
// 橡皮擦区
else if (curr_y < 90 && curr_x < 200) {
is_erasing = 1;
// 视觉反馈
draw_rect(0, 60, 199, 89, COLOR_WHITE, 1);
draw_bmp(30, 65, "eraser.bmp");
uchar *str_xiangpi[] = {&font_xiang[0], &font_pi[0], &font_ca[0]};
draw_string_16x16(100, 65, str_xiangpi, 3, COLOR_BLACK);
usleep(100000);
draw_hints();
}
// 一键清除区
else if (curr_y < 90 && curr_x >=200 && curr_x <400) {
// 视觉反馈
draw_rect(200, 60, 399, 89, COLOR_BLACK, 1);
draw_bmp(230, 65, "qingchu.bmp");
uchar *str_qingchu[] = {&font_yi[0], &font_jian[0], &font_qing[0], &font_chu[0]};
draw_string_16x16(300, 65, str_qingchu, 4, COLOR_WHITE);
usleep(100000);
clear_screen();
draw_hints();
}
prev_x = curr_x; prev_y = curr_y;
} else {
is_touching = 0;
is_erasing = 0;
prev_x=prev_y=curr_x=curr_y=-1;
}
}
// 绘制
if (is_touching && prev_x!=-1 && prev_y!=-1 && curr_x!=-1 && curr_y!=-1) {
if (curr_y >= 91) {
int color = is_erasing ? COLOR_BLACK : colors[current_color_index];
draw_line(prev_x, prev_y, curr_x, curr_y, color, current_brush_size);
prev_x = curr_x; prev_y = curr_y;
}
}
}
// 释放资源
munmap(lcd_mem, LCD_WIDTH*LCD_HEIGHT*4);
close(lcd_fd);
close(ts_fd);
return 0;
},修改代码添加对应功能的文本提示并显示在屏幕上,gec6818开发板
最新发布