文件IO · 代码纯享版 —— 第3天

0010动圆

#include <stdio.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>

#define LCD_DEV_PATH "/dev/fb0"

int Move_Ball()
{
    // 打开显示器设备文件
    int lcd = open(LCD_DEV_PATH, O_RDWR);
    if (lcd == -1)
    {
        perror("打开显示器失败!");
        return -1;
    }

    // 映射显示器内存
    int *mmap_start_p = (int *)mmap(NULL, 800 * 480 * 4, PROT_READ | PROT_WRITE, MAP_SHARED, lcd, 0);
    if (mmap_start_p == (int *)MAP_FAILED)
    {
        perror("映射失败!");
        return -1;
    }
    // 打开图片文件
    int bmp = open("./a1.bmp", O_RDONLY);
    if (bmp == -1)
    {
        perror("打开图片失败!");
        return -1;
    }

    char rgb[800 * 480 * 3];
    lseek(bmp, 54, SEEK_SET);

    // 读取图片像素点数据
    if (read(bmp, rgb, 800 * 480 * 3) == -1)
    {
        perror("读取图片像素点失败!");
        return -1;
    }

    int x0 = 400;
    int y0 = 240;
    int r = 60;

    // 控制 x 坐标移动方向的标志
    int x_mask = 0;
    // 控制 y 坐标移动方向的标志
    int y_mask = 0;

    while (1)
    {
        for (int y = 0; y < 480; y++)
        {
            for (int x = 0; x < 800; x++)
            {
                // 计算当前像素点在 rgb 数组中的索引
                int index = 3 * (800 * (479 - y) + x);
                // 判断当前像素点是否在圆内
                if ((x - x0) * (x - x0) + (y - y0) * (y - y0) < r * r)
                {
                    // 设置圆内的像素点颜色为浅绿色
                    *(mmap_start_p + 800 * y + x) = 0x00fff68f;
                }
                else
                {
                    // 设置圆外的像素点颜色为图片中对应位置的像素点颜色
                    *(mmap_start_p + 800 * y + x) =
                        rgb[index] |
                        rgb[index + 1] << 8 |
                        rgb[index + 2] << 16;
                }
            }
        }

        // 移动圆心
        if (y0 + r == 479) // 当圆心到达底部边界时,控制 y 坐标移动方向
            y_mask = 0;
        if (y0 - r == 0) // 当圆心到达顶部边界时,控制 y 坐标移动方向
            y_mask = 1;
        if (x0 + r == 799) // 当圆心到达右侧边界时,控制 x 坐标移动方向
            x_mask = 0;
        if (x0 - r == 0) // 当圆心到达左侧边界时,控制 x 坐标移动方向
            x_mask = 1;

        y0 += y_mask == 0 ? -1 : 1; // 根据移动方向更新圆心的 y 坐标
        x0 += x_mask == 0 ? -1 : 1; // 根据移动方向更新圆心的 x 坐标

        // usleep(300); // 延时 0.3 毫秒,但感觉不延时确实好一些
    }

    if (close(lcd) == -1)
    {
        perror("关闭显示器失败!");
        return -1;
    }

    if (close(bmp) == -1)
    {
        perror("关闭图片失败!");
        return -1;
    }

    if (munmap(mmap_start_p, 800 * 480 * 4) == -1)
    {
        perror("释放映射空间失败!");
        return -1;
    }

    return 0;
}

int main()
{
    Move_Ball();
    return 0;
}

  在开发板上观察到的现象:
在这里插入图片描述
看起来掉帧而且还糊,但其实是非常流畅的(GIF就是这样,没啥办法)。

0020图片倍数缩放

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

#define LCD_DEV_PATH "/dev/fb0"
#define MMAP_OFFSET 0

/**
 * 【业务逻辑】:
 *  1. 在函数开始处,打开显示器设备。
 *  2. 检查打开显示器设备是否成功。
 *  3. 进行内存映射,将显示器设备映射到内存中。
 *  4. 检查内存映射是否成功,
 *  5. 清屏显示,将屏幕上的每个像素点的值设置为0,即黑色。
 *  6. 打开图片文件。
 *  7. 检查打开图片文件是否成功。
 *  8. 读取图片的宽度和高度。
 *  9. 检查读取图片宽度和高度是否成功
 *  10. 计算图片每行字节对齐的字节数。
 *  11. 读取图片像素点数据。
 *  12. 检查读取图片像素点数据是否成功。
 *  13. 缩放和显示图片。
 *  14. 关闭显示器设备、释放内存映射、关闭图片文件。
 *  15. 返回0。
 *
 * 【参数说明】:
 *  - 参数1:bmp_path,图片文件路径。
 *  - 参数2:zoomout_times,缩小倍数。
 *
 * 【注意事项】:
 *  - 注意事项1:需要确保LCD_DEV_PATH的正确性。
 *  - 注意事项2:需要确保图片文件存在且可读。
 *  - 注意事项3:需要确保屏幕的宽度和高度与内存映射的大小一致。
 *  - 注意事项4:需要确保图片的宽度和高度与缩放倍数的兼容性。
 *
 * 【总结】:
 *      该函数的业务流程包括打开显示器设备、内存映射、清屏显示、打开图片文件、读取图片宽度和高度、
 *  计算图片每行字节对齐的字节数、读取图片像素点数据、缩放和显示图片、关闭显示器设备、释放内存映射、关闭图片文件。
 */
int Zoom_Display_Bitmap(const char *bmp_path, int zoomout_times);
int Zoom_Display_Bitmap(const char *bmp_path, int zoomout_times)
{
    // 打开显示器设备
    int lcd = open(LCD_DEV_PATH, O_RDWR);
    if (lcd == -1)
    {
        perror("打开显示器失败!");
        return -1;
    }

    // 内存映射
    int *mmap_start_p = (int *)mmap(NULL,
                                    800 * 480 * 4,
                                    PROT_READ | PROT_WRITE,
                                    MAP_SHARED,
                                    lcd,
                                    MMAP_OFFSET);
    if (mmap_start_p == (int *)MAP_FAILED)
    {
        perror("映射失败!");
        return -1;
    }

    // 清屏显示(黑屏)
    for (int i = 0; i < 800 * 480; i++)
    {
        *(mmap_start_p + i) = 0; // 将每个像素点的值设置为0,即黑色
    }

    // 打开图片文件
    int bmp = open(bmp_path, O_RDONLY);
    if (bmp == -1)
    {
        perror("打开图片失败!");
        close(lcd);                          // 关闭显示器设备
        munmap(mmap_start_p, 800 * 480 * 4); // 释放内存映射
        return -1;
    }

    // 读取图片宽度和高度
    int bmp_w, bmp_h;
    lseek(bmp, 18, SEEK_SET);
    if (read(bmp, &bmp_w, sizeof(int)) == -1 || read(bmp, &bmp_h, sizeof(int)) == -1)
    {
        perror("读取图片宽度或高度失败!");
        close(lcd);                          // 关闭显示器设备
        munmap(mmap_start_p, 800 * 480 * 4); // 释放内存映射
        close(bmp);                          // 关闭图片文件
        return -1;
    }

    // 计算图片每行字节对齐的字节数
    int skip = (bmp_w * 3) % 4 == 0 ? 0 : 4 - (bmp_w * 3) % 4;

    // 读取图片像素点数据
    char rgb[bmp_w * bmp_h * 3 + skip * bmp_h];
    lseek(bmp, 54, SEEK_SET);
    if (read(bmp, rgb, bmp_w * bmp_h * 3 + skip * bmp_h) == -1)
    {
        perror("读取图片像素点失败!");
        close(lcd);                          // 关闭显示器设备
        munmap(mmap_start_p, 800 * 480 * 4); // 释放内存映射
        close(bmp);                          // 关闭图片文件
        return -1;
    }

    // 图片缩放和显示
    for (int y = 0, n = 0; y < bmp_h / zoomout_times; y++)
    {
        for (int x = 0; x < bmp_w / zoomout_times; x++, n += 3 * zoomout_times)
        {
            // 计算当前像素点在内存映射中的位置
            // mmap_start_p 是内存映射的起始地址,类型为 int*,每个像素点占用 4 个字节
            // 800 是屏幕的宽度,bmp_h - 1 - y 是当前行在屏幕上的位置,x 是当前列在屏幕上的位置
            // rgb[n]、rgb[n + 1] 和 rgb[n + 2] 分别表示当前像素点的 B、G 和 R 分量
            // 通过移位操作将 B、G 和 R 分量合并成一个 32 位的像素值,并写入内存映射中的相应位置
            *(mmap_start_p + 800 * (bmp_h - 1 - y) + x) = rgb[n] << 0 | rgb[n + 1] << 8 | rgb[n + 2] << 16;
        }

        // 3 * bmp_w % zoomout_times 计算每行多余的像素点的字节数(跳过缩放的像素)
        // 举例:如果是缩小2倍,那么显示一个像素点只需要跳1个像素点
        // 其他倍数,缩小n倍,那么显示一个像素点只需要跳n个像素点
        n += 3 * bmp_w % zoomout_times;
        // skip 是图片每行字节对齐的字节数
        // bmp_w * 3 * (zoomout_times - 1) 计算每行缩放后未显示的像素点的字节数(跳过字节对齐的像素)
        n += skip + bmp_w * 3 * (zoomout_times - 1);
    }

    // 关闭文件和释放内存映射
    close(lcd);                          // 关闭显示器设备
    munmap(mmap_start_p, 800 * 480 * 4); // 释放内存映射
    close(bmp);                          // 关闭图片文件

    return 0;
}

int main(int argc, char const *argv[])
{
    if (argc != 3)
    {
        printf("命令行参数错误!参数不为3\n");
        return -1;
    }
    int zoom_number = atoi(argv[2]);
    Zoom_Display_Bitmap(argv[1], zoom_number);
    return 0;
}

  在开发板上观察到的现象1(缩小2倍):
在这里插入图片描述
  在开发板上观察到的现象2(缩小4倍):
在这里插入图片描述

  在开发板上观察到的现象3(缩小3倍),会发现存在问题,事实上,凡是缩小3的倍数都会出现问题,这个有机会再修复:
在这里插入图片描述

0030获取显存大小

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/fb.h>

int main(int argc, char const *argv[])
{
    // 打开LCD设备文件
    int lcd = open("/dev/fb0", O_RDWR);
    if (lcd == -1)
    {
        perror("打开显示器失败!");
        return -1;
    }

    struct fb_fix_screeninfo fix;

    // 获取LCD硬件信息
    if (ioctl(lcd, FBIOGET_FSCREENINFO, &fix) == -1)
    {
        perror("获取LCD硬件信息失败!");
        return -1;
    }
    else
    {
        printf("获取LCD硬件信息成功,其显存大小是:%d字节\n", fix.smem_len);
    }

    // 关闭LCD设备文件
    if (close(lcd) == -1)
    {
        perror("关闭显示器!");
        return -1;
    }

    return 0;
}

  在secureRTC中看到的运行结果:
在这里插入图片描述
  计算一下,其实相当于3块屏幕,只不过1块是可见区域,另外2块是不可见区域:
在这里插入图片描述

0040获取可见区域的高度和宽度

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/fb.h>

int main(int argc, char const *argv[])
{
    // 打开LCD设备文件
    int lcd = open("/dev/fb0", O_RDWR);
    if (lcd == -1)
    {
        perror("打开显示器失败!");
        return -1;
    }

    struct fb_var_screeninfo var;

    // 获取LCD硬件信息
    if (ioctl(lcd, FBIOGET_VSCREENINFO, &var) == -1)
    {
        perror("获取LCD硬件信息失败!");
        return -1;
    }
    else
    {
        printf("获取LCD硬件信息成功:\nLCD宽:%d\tLCD高:%d\n", var.xres, var.yres);
    }

    // 关闭LCD设备文件
    if (close(lcd) == -1)
    {
        perror("关闭显示器!");
        return -1;
    }
    return 0;
}

在secureRTC中观察到的运行结果:
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值