//编译后的程序需与图片放置于同一文件夹,开始、退出界面图片在上一级目录,具体路径请自行配置
#include
#include
#include //mmap(); munmap();
#include
#include
#include
#include
#include
#include
#include
#include //SIGCHLD变量头文件
#include
#define HEIGHT 480 //屏幕分辨率
#define LENGTH 800
#define DAEMON 120
#define PICDIR "/usr/lcd/gal" //图片路径
#define PICNUM 9 //BMP图片数目
#define THNUM 4 //线程数
#define BEGIN "../pic0.bmp" //开始界面图片路径
#define END "../pic9.bmp" //退出界面图片路径
#define LCD "/dev/fb0" //LCD设备路径
#define KEY "/dev/event1" //键盘设备路径
#define UPS SIGRTMIN+1 //上一张
#define DOWNS SIGRTMIN+2 //下一张
#define BEGINS SIGRTMIN+3 //开始
#define QUITS SIGRTMIN+4 //退出
#define RETURN SIGRTMIN+4 //返回
#define ESC 1 //各个按键的键值
#define HOME 2
#define POWER 3
#define ENTER 96
#define UP 103
#define DOWN 108
#define LEFT 105
#define RIGHT 106
struct input_event key_value;
int isEnter = 0; //标记是否打开程序
int isOpen = 0; //标记是否打开图片
int pageSum = 0; //标记总页数
int page = 1; //标记当前页号,从1开始
int choice = 0; //标记选中哪一张图片(0-1-2-3)
FILE* bmp[PICNUM];
FILE* bmpEND;
FILE* bmpBEG;
int* fb_mem;
char buff[LENGTH * HEIGHT * 3];
pid_t pptpid;
int pptfd[2];
void DrawLCD(FILE* bmps, int x1, int x2, int y1, int y2, int z1, int z2) { //按给定参数绘制图片
/* x1:x起始位置; x2:x结束位置; y1:y起始位置; y2:y结束位置; z1:行偏移位置; z2:列偏移位置
* 函数作用:从(x1, y1)到(x2, y2)绘制图片bmps
* 横向每(z1 + 1)个像素并为一个,纵向每(z2 + 1)行并为一行, z1、z2需配合x1、x2、y1和y2 */
int x = 0;
int y = 0;
int i = 0;
fseek(bmps, 54, SEEK_SET);
fread(buff, LENGTH * HEIGHT * 3, 1, bmps);
for (y = y2; y >= y1; y--) {
for (x = x1; x <= x2; x++) {
*(fb_mem + y * LENGTH + x) = (buff[i] << 0 | buff[i + 1] << 8 | buff[i + 2] << 16);
i += 3 * (z1 + 1);
}
i += z2 * (3 * LENGTH);
}
}
void toPage() { //按页号将四张图片输出为一张
if (((page - 1) * 4) > PICNUM || page <= 0) { //超出图库范围则报错
perror("Page Out Of Range\n");
return;
} else {
//Read((0,0)~(399,239))
DrawLCD(bmp[4 * (page - 1)], 0, LENGTH / 2 - 1, 0, HEIGHT / 2 - 1, 1, 1); //(0, 0) -> (LENGTH / 2 - 1, HEIGHT / 2 - 1), 偏移像素1,偏移行数1
//Read((400,239)~(799,239))
if ((4 * (page - 1) + 1) < PICNUM) {
DrawLCD(bmp[4 * (page - 1) + 1], LENGTH / 2, LENGTH - 1, 0, HEIGHT / 2 - 1, 1, 1); //(LENGTH / 2, 0) -> (LENGTH - 1, HEIGHT / 2 - 1), 偏移像素1,偏移行数1
} else {
int x = 0;
int y = 0;
for (y = (HEIGHT / 2 - 1); y >= 0; y--) {
for (x = LENGTH / 2; x < LENGTH; x++) {
*(fb_mem + y * LENGTH + x) = 0xb5b5b5;
}
}
}
//Read((0,240)~(399,479))
if ((4 * (page - 1) + 2) < PICNUM) {
DrawLCD(bmp[4 * (page - 1) + 2], 0, LENGTH / 2 - 1, HEIGHT / 2, HEIGHT - 1, 1, 1);
} else {
int x = 0;
int y = 0;
for (y = (HEIGHT - 1); y >= (HEIGHT / 2); y--) {
for (x = 0; x < LENGTH / 2; x++) {
*(fb_mem + y * LENGTH + x) = 0xaaaaaa;
}
}
}
//Read((400,479)~(799,239))
if ((4 * (page - 1) + 3) < PICNUM) {
DrawLCD(bmp[4 * (page - 1) + 3], LENGTH / 2, LENGTH - 1, HEIGHT / 2, HEIGHT - 1, 1, 1);
} else {
int x = 0;
int y = 0;
for (y = (HEIGHT - 1); y >= (HEIGHT / 2); y--) {
for (x = LENGTH / 2; x < LENGTH; x++) {
*(fb_mem + y * LENGTH + x) = 0x969696;
}
}
}
}
}
void HeightLight() { //为选中的图片绘制红框
if (choice >=0 && choice <= 3) {
int i = 0;
int offL = choice % 2;
int offH = choice / 2;
toPage(bmp);
for (i = (LENGTH / 2) * offL; i < (LENGTH / 2) * (offL + 1); i++) {
//四条横线
*(fb_mem + ((HEIGHT / 2) * offH) * LENGTH + i) = 0xff0000;
*(fb_mem + ((HEIGHT / 2) * offH + 1) * LENGTH + i) = 0xff0000;
*(fb_mem + ((HEIGHT / 2) * (offH + 1) - 2) * LENGTH + i) = 0xff0000;
*(fb_mem + ((HEIGHT / 2) * (offH + 1) - 1) * LENGTH + i) = 0xff0000;
}
for (i = (HEIGHT / 2) * offH + 2; i < ((HEIGHT / 2) * (offH + 1) - 2); i++) {
//四条竖线
*(fb_mem + i * LENGTH + (LENGTH / 2) * offL) = 0xff0000;
*(fb_mem + i * LENGTH + (LENGTH / 2) * offL + 1) = 0xff0000;
*(fb_mem + i * LENGTH + (LENGTH / 2) * (offL + 1) - 1) = 0xff0000;
*(fb_mem + i * LENGTH + (LENGTH / 2) * (offL + 1) - 2) = 0xff0000;
}
}
}
void getFile(DIR* dir) { //读取图片文件
if (dir != NULL && bmp != NULL) {
int i = 0;
if (dir != NULL) {
struct dirent* d_p;
while ((d_p = readdir(dir)) != NULL && i < PICNUM) {
if(strstr(d_p->d_name,".bmp")) {
bmp[i] = fopen(d_p->d_name, "r");
if (bmp[i] == NULL) {
perror("Read Pic Failed!\n");
_exit(0);
}
i++;
}
}
}
}
}
void key_Return() { //返回小图模式
if (isEnter == 1 && isOpen == 1) {
kill(pptpid, SIGINT);
toPage();
HeightLight();
isOpen = 0;
}
}
void key_Enter() { //进入主程序
if (isEnter == 0) {
//Enter
toPage();
HeightLight();
isEnter = 1;
}
}
void key_Back() { //退出程序
kill(pptpid, SIGINT);
DrawLCD(bmpEND, 0, LENGTH - 1, 0, HEIGHT - 1, 0, 0);
kill(DAEMON, QUITS);
isEnter = 0;
sleep(3);
}
void getNext(int sig) {
if (sig == RETURN) {
char buff[2];
read(pptfd[0], buff, 2);
page = buff[0];
choice = buff[1];
}
}
void pptQuit(int sig) {
if (sig == SIGINT) {
char buff[2];
buff[0] = page;
buff[1] = choice;
write(pptfd[1], buff, 2);
kill(getppid(), RETURN);
exit(0);
}
}
void* Thread(void* p) {
int arg = (int)p;
int num = arg / 10;
int method = arg % 10;
int x = 0;
int y = 0;
int pos = (3 - num) * (HEIGHT / 4) * 3 * LENGTH;
if (method == 0) { //下向上
for (y = (num + 1) * (HEIGHT / 4) - 1; y >= num * (HEIGHT / 4); y--) {
for (x = 0; x <= LENGTH - 1; x++) {
*(fb_mem + y * LENGTH + x) = (buff[pos] << 0 | buff[pos + 1] << 8 | buff[pos + 2] << 16);
pos += 3;
}
usleep(3000);
}
} else if (method == 1) { //左向右
for (x = num * (LENGTH / 4); x <= (num + 1) * (LENGTH / 4) - 1; x++) {
pos = 3 * x;
for (y = HEIGHT - 1; y >= 0; y--) {
*(fb_mem + y * LENGTH + x) = (buff[pos] << 0 | buff[pos + 1] << 8 | buff[pos + 2] << 16);
pos += 3 * LENGTH;
}
usleep(3000);
}
} else if (method == 2) { //上向下
pos = ((4 - num) * (HEIGHT / 4) - 1) * 3 * LENGTH; //偏移到每块的顶行
for (y = num * (HEIGHT / 4); y <= (num + 1) * (HEIGHT / 4) - 1; y++) {
for (x = 0; x <= LENGTH - 1; x++) {
*(fb_mem + y * LENGTH + x) = (buff[pos] << 0 | buff[pos + 1] << 8 | buff[pos + 2] << 16); //扫描并显示一行
pos += 3;
}
pos = pos - 6 * LENGTH; //回退两行,即刷新刚才一行的下边一行
//不回退的话就会显示刚才一行的上一行
usleep(3000);
}
} else if (method == 3) { //右向左
for (x = (num + 1) * (LENGTH / 4) - 1; x >= num * (LENGTH / 4); x--) {
pos = 3 * x;
for (y = HEIGHT - 1; y >= 0; y--) {
*(fb_mem + y * LENGTH + x) = (buff[pos] << 0 | buff[pos + 1] << 8 | buff[pos + 2] << 16);
pos += 3 * LENGTH;
}
usleep(3000);
}
}
pthread_exit(NULL);
}
void DrawInWindows(FILE* bmps, int method) {
fseek(bmps, 54, SEEK_SET);
fread(buff, LENGTH * HEIGHT * 3, 1, bmps);
method = method % 10;
// method = 3;
pthread_t pth[THNUM];
int i = 0;
for (i = 0; i < THNUM; i++) {
pthread_create(&pth[i], NULL, Thread, (void*)(i * 10 + method));
}
for (i = 0; i < THNUM; i++) {
pthread_join(pth[i], NULL);
}
}
void key_Open() { //打开选中的图片
if (isEnter == 1 && isOpen == 0 && choice >=0 && choice <= 3) {
//OPEN
int method = 0;
DrawInWindows(bmp[4 * (page - 1) + choice], method);
pipe(pptfd);
pptpid = fork();
if (pptpid == 0) {
close(pptfd[0]);
signal(SIGINT, pptQuit);
int current = 4 * (page - 1) + choice;
while (1) {
method = (method + 1) % 4;
sleep(3);
current = (current + 1) % PICNUM;
page = current / 4 + 1;
choice = current % 4;
DrawInWindows(bmp[current], method);
}
} else if (pptpid != 0) {
close(pptfd[1]);
isOpen = 1;
signal(RETURN, getNext);
}
}
}
void key_PageUp() { //上一页
if (isEnter == 1 && isOpen == 0) {
if (page <= 1) { //已是第一页
page = pageSum; //跳到最后一页
} else {
page--;
}
while (4 * (page - 1) + choice >= PICNUM) {
choice--;
}
toPage();
HeightLight();
}
}
void key_PageDown() { //下一页
if (isEnter == 1 && isOpen == 0) {
if (page >= pageSum) {
page = 1;
} else {
page++;
}
while (4 * (page - 1) + choice >= PICNUM) {
choice--;
}
toPage();
HeightLight();
}
}
void key_Up() { //上一张
if (isEnter == 1 && isOpen == 0) {
char flag = 'n';
if (choice <= 0) {
choice = 3;
flag = 'y';
} else {
choice--;
flag = 'y';
}
while (4 * (page - 1) + choice >= PICNUM) {
choice--;
flag = 'n';
}
if (flag == 'y') {
kill(DAEMON, UPS);
HeightLight();
}
}
}
void key_Down() { //下一张
if (isEnter == 1 && isOpen == 0 && 4 * (page - 1) + choice < PICNUM) {
char flag = 'n';
if (choice >= 3) {
choice = 0;
flag = 'y';
} else {
choice++;
flag = 'y';
}
while (4 * (page - 1) + choice >= PICNUM) {
choice--;
flag = 'n';
}
if (flag == 'y') {
kill(DAEMON, DOWNS);
HeightLight();
}
}
}
int main(int argc ,char **argv) {
if ((PICNUM % 4) == 0) {
pageSum = PICNUM / 4;
} else {
pageSum = PICNUM / 4 + 1;
}
int flag = 1; //循环标记
int ret = 0;
int lcdid = open(LCD, O_RDWR);
int fd = open(KEY, O_RDONLY);
bmpBEG = fopen(BEGIN, "r"); //进入、退出界面
bmpEND = fopen(END, "r");
if(fd <= 2 || lcdid <= 2) {
perror(" open !");
return -1;
} else {
int x = 0;
int y = 0;
int i = 0;
DIR* dir = opendir(PICDIR);
if (dir != NULL) {
getFile(dir);
fb_mem = mmap(NULL, LENGTH * HEIGHT * 4, PROT_READ | PROT_WRITE, MAP_SHARED, lcdid, 0);
if (fb_mem != NULL) {
DrawLCD(bmpBEG, 0, LENGTH - 1, 0, HEIGHT - 1, 0, 0);
kill(DAEMON, BEGINS); //开启
while (flag == 1) {
ret = read(fd, &key_value, sizeof(struct input_event));
if( ret != sizeof(struct input_event)) {
perror(" the file Ending!");
return -1;
}
if(key_value.type == EV_KEY) { //按照键值进行分支跳转,请根据实际情况修改
if (key_value.value == 1) { //按下时相应
switch(key_value.code) {
case ESC: { //返回小图模式
key_Return();
break;
}
case HOME: { //进入主程序
key_Enter();
break;
}
case POWER: { //退出程序
key_Back();
flag = 0;
break;
}
case ENTER: { //打开选中的图片
key_Open();
break;
}
case UP: { //上一页
key_PageUp();
break;
}
case DOWN: { //下一页
key_PageDown();
break;
}
case LEFT: { //上一张图片
key_Up();
break;
}
case RIGHT: { //下一张图片
key_Down();
break;
}
default: {
perror("Key Code Error!\n");
}
}
}
}
}
munmap(fb_mem, LENGTH * HEIGHT * 4);
}
}
ret = close(fd);
if(ret < 0) {
perror(" close ! ");
return -1;
}
}
return 0;
}
电子音乐相册的相册部分,配合移植后的MoboPlayer可以实现音乐电子相册的功能。