在 LCD 上显示 png 图片-I.MX6U嵌入式Linux C应用编程学习笔记基于正点原子阿尔法开发板

news2024/9/17 7:37:02

在 LCD 上显示 png 图片

在这里插入图片描述

PNG 简介

无损压缩:PNG 使用 LZ77 派生算法进行无损压缩,确保图像质量不受损,且压缩比高

体积小:通过高压缩比,PNG 文件体积小,适合网络传输

索引彩色模式:PNG-8 格式采用8位调色板,将RGB图像转换为索引彩色图像,减少数据量

优化的网络传输显示:PNG 支持流式浏览,允许图像在未完全下载前显示基本内容,适合网络通信

支持透明效果:PNG 提供256级透明度,使图像边缘与背景平滑融合,这是GIF和JPEG不具备的特性

libpng 简介

libpng 是用于处理 PNG 图像的库

功能:支持对 PNG 图像文件进行解码和编码

性质:免费、开源的 C 语言函数库

对比:与 libjpeg 类似

zlib 移植

zlib 简介

  • zlib 是一个包含数据压缩算法的函数库,是免费、开源的 C 语言库

  • libpng 依赖:libpng 依赖于 zlib 库,因此在移植 libpng 之前需要先移植 zlib

下载源码包

  • 下载链接: https://www.zlib.net/fossils/

  • 选择 1.2.10 版本的 zlib

编译源码

  • 将下载的 zlib-1.2.10.tar.gz 压缩文件拷贝到 Ubuntu 系统的用户家目录下

  • tar -xzf zlib-1.2.10.tar.gz

    • 解压之后就会得到 zlib-1.2.10 文件夹,这就是 zlib 的源代码目录
  • 先在 tools 目录下创建一个名为 zlib 的文件夹,作为 zlib 库的安装目录

  • 配置

    • 先对交叉编译工具的环境进行初始化

      • source /opt/fsl-imx-x11/4.1.15-2.1.0/environment-setup-cortexa7hf-neon-poky-linux-gnueabi
    • 对 zlib 工程进行配置

      • ./configure --prefix=/home/alientek/tools/zlib/

      • –prefix 选项指定 zlib 库的安装目录

  • 编译

    • make
  • 安装

    • make install

安装目录下的文件夹介绍

  • 头文件目录 include

  • 库文件目录 lib

移植到开发板

  • 将出厂系统中原有的 zlib 库文件删除

    • rm -rf /usr/lib/libz.* /lib/libz.*
  • 将编译得到的 zlib 库文件拷贝到开发板/usr/lib 目录,拷贝库文件时,需要注意符号
    链接的问题,不能破坏原有的符号链接

    • 开发板/usr/lib 目录下的 zlib 库文件

libpng 移植

下载源码包

  • 下载链接: https://github.com/glennrp/libpng/releases

编译源码

  • 将下载的 libpng-1.6.35.tar.gz 压缩包文件拷贝到 Ubuntu 系统

  • 解压:tar -xzf libpng-1.6.35.tar.gz

  • 解压之后得到 libpng-1.6.35 文件夹,这便是 libpng 的源码目录

  • 在编译 libpng 之前,先在 tools 目录下创建一个名为 png 的文件夹,作为 libpng 库的安装目录

  • 配置

    • 先对交叉编译工具的环境进行初始化

      • source /opt/fsl-imx-x11/4.1.15-2.1.0/environment-setup-cortexa7hf-neon-poky-linux-gnueabi
    • 得告知编译器 zlib 库的安装目录,将 zlib 库安装目录下的 include 和 lib 路径导出到环境变量

      • export LDFLAGS=“ L D F L A G S − L / h o m e / d t / t o o l s / z l i b / l i b " e x p o r t C F L A G S = " {LDFLAGS} -L/home/dt/tools/zlib/lib" export CFLAGS=" LDFLAGSL/home/dt/tools/zlib/lib"exportCFLAGS="{CFLAGS} -I/home/dt/tools/zlib/include”
        export CPPFLAGS=“${CPPFLAGS} -I/home/dt/tools/zlib/include”
    • 对 libpng 源码工程进行配置

      • ./configure --prefix=/home/alientek/tools/png --host=arm-poky-linux-gnueabi

      • –prefix 选项指定 zlib 库的安装目录

  • 编译

    • make
  • 安装

    • make install

安装目录下的文件夹介绍

  • 同样包含了 bin、include、lib 这些目录

移植到开发板

  • 将开发板出厂系统中已经移植好的
    libpng 库文件删除

    • rm -rf /lib/libpng* /usr/lib/libpng*
  • 将编译得到的 libpng 库文件拷贝到开发板/usr/lib 目录

    • 开发板/usr/lib 目录下的 libpng 相关库文件

libpng 使用说明

libpng 还包含编码功能,但本文不作介绍。libpng 官方提供了详细使用文档

  • PDF 文档:http://www.libpng.org/pub/png/libpng-1.4.0-manual.pdf

  • TXT 文档:
    http://www.libpng.org/pub/png/libpng-manual.txt

libpng 的数据结构

  • 头文件:使用 libpng 需要包含头文件 <png.h>,其中包含 API 和数据结构的声明

  • 关键数据结构:libpng 有两个重要的数据结构体:png_struct 和 png_info

  • png_struct

    • 用于 libpng 函数内部

    • 作为传递给每个 libpng 函数调用的第一个变量

    • 用户需要创建并初始化这个对象,但通常不会直接使用

  • png_info

    • 描述 PNG 图像的信息

    • 旧版本中,用户可以直接访问 png_info 成员,如图像宽、高、像素深度等

    • 新版本中,建议通过 png_get_XXX 和 png_set_XXX 接口来访问和修改 png_info 成员,以避免问题

创建和初始化 png_struct 对象

  • 使用 png_create_read_struct() 创建一个用于 PNG 解码的 png_struct 对象

    • png_structp png_create_read_struct(png_const_charp user_png_ver, png_voidp error_ptr, png_error_ptr error_fn,
      png_error_ptr warn_fn);

    • 第一个参数 user_png_ver 通常设置为 PNG_LIBPNG_VER_STRING(png.h 头文件中定义的一个宏),包含 libpng 的版本信息

      • #define PNG_LIBPNG_VER_STRING “1.6.35”
    • error_ptr、error_fn、warn_fn 参数用于自定义错误处理和警告处理函数,也可设置为 NULL,使用 libpng 默认的处理函数

    • 返回一个指向 png_struct 对象的指针(png_structp)

    • 如果创建失败,返回 NULL,通过判断返回值是否为 NULL 来确认函数执行是否成功

    • 示例:
      png_structp png_ptr = NULL;
      png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
      if (!png_ptr)
      return -1;

  • 使用 png_create_write_struct() 创建一个用于 PNG 编码的 png_struct 对象

创建和初始化 png_info 对象

  • 创建 png_info 对象

    • 使用 png_create_info_struct() 函数创建 png_info 对象

    • png_infop png_create_info_struct(png_const_structrp png_ptr);

    • 需要传入一个 png_struct 对象的指针,内部会建立 png_struct 和 png_info 对象之间的关联

    • 返回一个指向 png_info 对象的指针(png_infop)

    • 如果创建成功,返回指向 png_info 对象的指针。
      如果创建失败,返回 NULL,调用者可通过判断返回值是否为 NULL 来确认函数调用是否成功

  • 当销毁 png_struct 对象时,也可以销毁 png_info 对象

    • 示例:
      png_infop info_ptr = NULL;
      info_ptr = png_create_info_struct(png_ptr);
      if (NULL == info_ptr) {
      png_destroy_read_struct(&png_ptr, NULL, NULL);
      return -1;
      }

    • png_destroy_read_struct()函数用于销毁 png_struct 对象的函数

设置错误返回点

  • 错误处理函数

    • 调用 png_create_read_struct() 时,可以指定一个自定义的错误处理函数

    • 如果未指定自定义错误处理函数,libpng 会使用默认的错误处理函数

  • 默认错误处理函数

    • 默认的错误处理函数会执行一个跳转动作,跳转到程序中的某个位置,这个位置称为错误返回点
  • 错误返回点

    • 当 libpng 遇到错误时,若使用默认错误处理函数,它会跳转到错误返回点

    • 错误返回点是程序中预先设定的一个位置,通常用于执行清理工作,如释放和销毁 png_struct 和 png_info 对象,避免内存泄漏

  • 避免直接终止

    • 发生错误时,不直接终止程序,而是跳转到错误返回点执行必要的清理工作
  • 设置错误返回点的方法

    • 使用 setjmp 和 longjmp 库函数来设置错误返回点

      • 函数跳转

        • 在 C 语言中,goto 语句用于函数内部跳转,但不能跨越函数

        • 使用 setjmp 和 longjmp 库函数可以实现跨越函数的跳转

      • setjmp 函数

        • setjmp(jmp_buf env) 用于设置跳转点,保存当前进程环境信息到 env 参数中
      • longjmp 函数

        • longjmp(jmp_buf env, int val) 用于执行跳转,跳转到 setjmp 设置的跳转点

        • longjmp 调用后,类似于第二次调用 setjmp 返回

          • 返回值区分

            • setjmp 初次调用返回 0

            • longjmp 调用后,setjmp 返回 val 参数指定的值,用于区分不同的起跳位置

        • val 参数设置

          • 通常 longjmp 调用时,val 参数不为 0,以区分 setjmp 的初次返回和后续“伪”返回
      • 编程举例

        • 代码

          • #include <stdio.h>
            #include <stdlib.h>
            #include <setjmp.h>

static jmp_buf buf;

static void hello(void)
{
printf(“hello world!\n”);
longjmp(buf,1);
printf(“Nice to meet you!\n”);
}

int main(void)
{
if(0 == setjmp(buf)) {
printf(“First return\n”);
hello();
}
else
printf(“Second return\n”);

exit(0);

}

		- 验证

			-  

- libpng 设置错误返回点

	- 错误处理机制:

libpng 库使用 setjmp/longjmp 组合处理错误跳转

	- 错误返回点设置:

使用 setjmp() 为 libpng 设置错误返回点

	- 错误处理流程:

当 libpng 遇到错误时,默认错误处理函数调用 longjmp() 进行跳转。
需要在代码中设置错误返回点,以便在错误发生时进行处理

		- /*  设置错误返回点   */

if (setjmp(png_jmpbuf(png_ptr))) {
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
return -1;
}

指定数据源

  • 需要指定进行解码的 PNG 图像,数据源可以是文件输入流、内存中的数据流等,这里以文件输入流为例

  • png_init_io() 函数

    • ibpng 提供 png_init_io() 函数来指定数据源,数据源以文件输入流的方式提供

    • png_init_io(png_structrp png_ptr, png_FILE_p fp);

    • 第一个参数是 png_ptr,指向 png_struct 对象

    • 第二个参数 fp 是 png_FILE_p 类型指针,即标准 I/O 中的 FILE * 指针

  • 打开文件

    • 使用 fopen() 函数打开 PNG 文件,得到指向该文件的 FILE * 类型指针

    • 示例:
      FILE png_file = NULL;
      /
      打开 png 文件 /
      png_file = fopen(“image.png”, “r”); //以只读方式打开
      if (NULL == png_file) {
      perror(“fopen error”);
      return -1;
      }
      /
      指定数据源 */
      png_init_io(png_ptr, png_file);

读取 png 图像数据并解码

  • 读取和解码 PNG 文件

    • 从 PNG 文件中读取数据并解码,将解码后的图像数据存放在内存中供用户读取
  • 处理方式

    • High-level 接口:封装了 low-level 接口,使用方便,只需一个函数,但灵活性不高

    • Low-level 接口:灵活性高,但需要用户调用多个 API

  • high-level 接口

    • High-level 接口使用条件

      • 内存空间足够大,可一次性存放解码后的数据

      • 数据输出格式为 libpng 预定义的格式

        • libpng 预定义的数据转换类型
    • High-level 接口限制

      • 预定义的转换类型,不包括背景颜色设置、伽马变换、抖动和填充物
    • High-level 接口函数

      • png_read_png(png_structrp png_ptr, png_inforp info_ptr, int transforms, png_voidp params);

        • png_ptr:指向 png_struct 对象的指针

        • info_ptr:指向 png_info 对象的指针

        • transforms:整型参数,代表 libpng 预定义的转换类型

      • 函数调用示例

        • png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_STRIP_ALPHA, NULL);
    • High-level 接口调用顺序

      • 调用 png_read_info 获取 PNG 图像信息

      • 根据 transforms 设置数据输出格式

      • 调用 png_read_image 解码并存放数据

      • 调用 png_read_end 结束解码

  • low-level 接口

    • 使用 low-level 接口,需要用户将函数 png_read_png()所做的事情一步一步执行

    • 1、读取 PNG 图像信息

      • 调用 png_read_info() 获取 PNG 图像信息并存入 png_info 对象

      • png_read_info(png_ptr, info_ptr);

    • 2、查询图像信息

      • 使用 libpng 提供的 API 查询图像的宽度、高度、位深度和颜色类型

      • unsigned int width = png_get_image_width(png_ptr, info_ptr); //获取 png 图像的宽度
        unsigned int height = png_get_image_height(png_ptr, info_ptr); //获取 png 图像的高度
        unsigned char depth = png_get_bit_depth(png_ptr, info_ptr); //获取 png 图像的位深度
        unsigned char color_type = png_get_color_type(png_ptr, info_ptr); //获取 png 图像的颜色类型

      • color type 在 png.h 头文件中定义,如上所示:

    • 3、设置解码输出参数

      • 根据需要调用 png_set_xxxxx 函数设置数据输出格式,例如:

      • unsigned char depth = png_get_bit_depth(png_ptr, info_ptr);
        unsigned char color_type = png_get_color_type(png_ptr, info_ptr);
        if (16 == depth)
        png_set_strip_16(png_ptr); //将 16 位深度转为 8 位深度
        if (8 > depth)
        png_set_expand(png_ptr); //如果位深小于 8,则扩展为 24-bit RGB
        if (PNG_COLOR_TYPE_GRAY_ALPHA == color_type)
        png_set_gray_to_rgb(png_ptr); //如果是灰度图,则转为 RGB

      • 查看函数信息

        • 在 libpng 的头文件 png.h 中可以查看每个函数的注释信息和参数列表

        • 具体使用方法和更多转换函数请参考 libpng 的使用手册

      • 自定义转换函数

        • libpng 提供了多种转换函数,但不支持所有可能的输出格式(如 YUV565、RGB565、YUYV)

        • 用户可以设置自定义转换函数来解决这些问题

      • 注册自定义转换函数

        • 使用 png_set_read_user_transform_fn() 注册自定义转换函数

        • 使用 png_set_user_transform_info() 提供自定义转换函数所需的用户数据结构和输出数据详细信息(如颜色深度和颜色通道)

        • 有关自定义转换函数和其他详细信息,可以查阅 libpng 的使用帮助文档

    • 4、更新 PNG 数据信息

      • 调用 png_read_update_info() 更新 png_info 对象中的图像信息

      • png_read_update_info(png_ptr, info_ptr);

    • 5、读取并解码 PNG 数据

      • 解码 PNG 数据

        • 调用 png_read_image() 一次性解码整个 PNG 文件的数据并存入用户提供的内存区域

          • png_read_image(png_ptr, row_pointers);

          • 参数 png_ptr 指向 png_struct 对象

          • 第二个参数 row_pointers 是一个 png_bytepp 类型的指针变量,也就是 unsigned char **(指针数组)

            • png_bytep row_pointers[height];
          • 无返回值

        • 需要提供足够大的内存空间来保存解码后的数据,并通过 row_pointers 数组传入每一行的指针

      • 内存分配

        • 调用 png_read_image() 一次性解码整个 PNG 文件的数据并存入用户提供的内存区域

          • png_bytep row_pointers[height] = {0};
            size_t rowbytes = png_get_rowbytes(png_ptr, info_ptr);//获取每一行数据的字节大小
            int row;
            /* 为每一行数据分配一个缓冲区 */
            for (row = 0; row < height; row++)
            row_pointers[row] = png_malloc(png_ptr, rowbytes);
            png_read_image(png_ptr, row_pointers);

          • 使用 png_malloc() 为每一行数据分配缓冲区

          • png_malloc() 是 libpng 提供的 API,等价于 malloc()

        • 也可以调用 png_read_rows()一次解码 1 行或多行数据、并将解码
          后的数据存放在用于提供的内存区域中

          • ize_t rowbytes = png_get_rowbytes(png_ptr, info_ptr);//获取每一行数据的字节大小
            png_bytep row_buf = png_malloc(png_ptr, rowbytes); //分配分缓冲、用于存储一行数据
            int row;
            for (row = 0; row < height; row++) {
            png_read_rows(png_ptr, &row_buf, NULL, 1);//每次读取、解码一行数据(最后一个数字 1 表示每次 1 行)
            /* 对这一行数据进行处理: 譬如刷入 LCD 显存进行显示 */
            do_something();
            }

          • png_read_rows 会自动跳转处理下一行数据

      • 内存管理差异

        • 在 low-level 接口中,需要手动分配内存区域

        • 在 high-level 接口中,调用 png_read_png() 时 libpng 会自动分配缓冲区

    • 6、结束解码

      • 调用 png_read_end() 结束读取和解码过程

      • png_read_end(png_ptr, info_ptr);

读取解码后的数据

  • 解码后处理

    • 解码完成后,可以获取解码后的数据进行进一步处理或直接显示到 LCD 上
  • Low-Level 方式

    • 缓冲区由调用者分配,直接从缓冲区中获取数据即可
  • High-Level 方式

    • 缓冲区由 png_read_png() 函数内部分配,并与 png_struct 对象关联

    • 使用 png_get_rows() 函数获取指向每一行数据缓冲区的指针数组

    • png_bytepp row_pointers = NULL;
      row_pointers = png_get_rows(png_ptr, info_ptr);//获取到指向每一行数据缓冲区的指针数组

  • 内存管理

    • 在销毁 png_struct 对象时,由 png_read_png() 分配的缓冲区会被自动释放,归还给操作系统

结束销毁对象

  • 调用 png_destroy_read_struct()销毁 png_struct 对象

    • void png_destroy_read_struct(png_structpp png_ptr_ptr, png_infopp info_ptr_ptr, png_infopp end_info_ptr_ptr);
  • 使用方法

    • png_destroy_read_struct(png_ptr, info_ptr, NULL);

libpng 应用编程

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

static int width;                       //LCD X分辨率
static int height;                      //LCD Y分辨率
static unsigned short *screen_base = NULL;        //映射后的显存基地址
static unsigned long line_length;       //LCD一行的长度(字节为单位)
static unsigned int bpp;    //像素深度bpp

static int show_png_image(const char *path)
{
    png_structp png_ptr = NULL;
    png_infop info_ptr = NULL;
    FILE *png_file = NULL;
    unsigned short *fb_line_buf = NULL; //行缓冲区:用于存储写入到LCD显存的一行数据
    unsigned int min_h, min_w;
    unsigned int valid_bytes;
    unsigned int image_h, image_w;
    png_bytepp row_pointers = NULL;
    int i, j, k;

    /* 打开png文件 */
    png_file = fopen(path, "r");    //以只读方式打开
    if (NULL == png_file) {
        perror("fopen error");
        return -1;
    }

    /* 分配和初始化png_ptr、info_ptr */
    png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
    if (!png_ptr) {
        fclose(png_file);
        return -1;
    }

    info_ptr = png_create_info_struct(png_ptr);
    if (!info_ptr) {
        png_destroy_read_struct(&png_ptr, NULL, NULL);
        fclose(png_file);
        return -1;
    }

    /* 设置错误返回点 */
    if (setjmp(png_jmpbuf(png_ptr))) {
        png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
        fclose(png_file);
        return -1;
    }

    /* 指定数据源 */
    png_init_io(png_ptr, png_file);

    /* 读取png文件 */
    png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_STRIP_ALPHA, NULL);
    image_h = png_get_image_height(png_ptr, info_ptr);
    image_w = png_get_image_width(png_ptr, info_ptr);
    printf("分辨率: %d*%d\n", image_w, image_h);

    /* 判断是不是RGB888 */
    if ((8 != png_get_bit_depth(png_ptr, info_ptr)) &&
        (PNG_COLOR_TYPE_RGB != png_get_color_type(png_ptr, info_ptr))) {
        printf("Error: Not 8bit depth or not RGB color");
        png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
        fclose(png_file);
        return -1;
    }

    /* 判断图像和LCD屏那个的分辨率更低 */
    if (image_w > width)
        min_w = width;
    else
        min_w = image_w;

    if (image_h > height)
        min_h = height;
    else
        min_h = image_h;

    valid_bytes = min_w * bpp / 8;

    /* 读取解码后的数据 */
    fb_line_buf = malloc(valid_bytes);
    row_pointers = png_get_rows(png_ptr, info_ptr);//获取数据

    unsigned int temp = min_w * 3;  //RGB888 一个像素3个bit位
    for(i = 0; i < min_h; i++) {

        // RGB888转为RGB565
        for(j = k = 0; j < temp; j += 3, k++)
            fb_line_buf[k] = ((row_pointers[i][j] & 0xF8) << 8) |
                ((row_pointers[i][j+1] & 0xFC) << 3) |
                ((row_pointers[i][j+2] & 0xF8) >> 3);

        memcpy(screen_base, fb_line_buf, valid_bytes);//将一行数据刷入显存
        screen_base += width;   //定位到显存下一行
    }

    /* 结束、销毁/释放内存 */
    png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
    free(fb_line_buf);
    fclose(png_file);
    return 0;
}

int main(int argc, char *argv[])
{
    struct fb_fix_screeninfo fb_fix;
    struct fb_var_screeninfo fb_var;
    unsigned int screen_size;
    int fd;

    /* 传参校验 */
    if (2 != argc) {
        fprintf(stderr, "usage: %s <png_file>\n", argv[0]);
        exit(-1);
    }

    /* 打开framebuffer设备 */
    if (0 > (fd = open("/dev/fb0", O_RDWR))) {
        perror("open error");
        exit(EXIT_FAILURE);
    }

    /* 获取参数信息 */
    ioctl(fd, FBIOGET_VSCREENINFO, &fb_var);
    ioctl(fd, FBIOGET_FSCREENINFO, &fb_fix);

    line_length = fb_fix.line_length;
    bpp = fb_var.bits_per_pixel;
    screen_size = line_length * fb_var.yres;
    width = fb_var.xres;
    height = fb_var.yres;

    /* 将显示缓冲区映射到进程地址空间 */
    screen_base = mmap(NULL, screen_size, PROT_WRITE, MAP_SHARED, fd, 0);
    if (MAP_FAILED == (void *)screen_base) {
        perror("mmap error");
        close(fd);
        exit(EXIT_FAILURE);
    }

    /* 显示BMP图片 */
    memset(screen_base, 0xFF, screen_size);//屏幕刷白
    show_png_image(argv[1]);

    /* 退出 */
    munmap(screen_base, screen_size);  //取消映射
    close(fd);  //关闭文件
    exit(EXIT_SUCCESS);    //退出进程
}

编写流程和上面介绍的libpng 使用说明一致

  • 使用的是 high-level
    接口处理方式

  • 解码得到的数据是 RGB888 格式,需要转换为 RGB565 格式

  • 转换后的数据刷入显存中进行显示

编译代码

  • ${CC} -o testApp testApp.c -I/home/alientek/tools/png/include -L/home/alientek/tools/png/lib -L/home/alientek/tools/zlib/lib -
    lpng -lz

执行测试

  • 看到打印出了一些警告信息,原因是新版本的 libpng 增强了检查,发出了警告;不影响
    我们的使用,可以忽略

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1947783.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Unity UGUI 之 RectTransform

本文仅作学习笔记与交流&#xff0c;不作任何商业用途 本文包括但不限于unity官方手册&#xff0c;唐老狮&#xff0c;麦扣教程知识&#xff0c;引用会标记&#xff0c;如有不足还请斧正 Unity - Manual: Rect Transform 1.Rect Transform是什么 2.轴心与锚点的映射关系 首先…

获取后端返回的图形验证码

如果后端返回的直接就是一个图形&#xff0c;有以下几种方式展示 一、直接在img标签里面的src里面调用接口 <img :src"dialogSrc" class"photo" alt"验证码图片" click"changeDialog">let orgUrl "/api/captcha" …

论文解读:DiAD之SG网络

目录 一、SG网络功能介绍二、SG网络代码实现 一、SG网络功能介绍 DiAD论文最主要的创新点就是使用SG网络解决多类别异常检测中的语义信息丢失问题&#xff0c;那么它是怎么实现的保留原始图像语义信息的同时重建异常区域&#xff1f; 与稳定扩散去噪网络的连接&#xff1a; S…

机器学习(二十):偏差和方差问题

一、判断偏差和方差 以多项式回归为例&#xff0c;红点为训练集数据&#xff0c;绿点为交叉验证数据。 下图的模型&#xff0c;训练集误差大&#xff0c;交叉验证集误差大&#xff0c;这代表偏差很大 下图的模型&#xff0c;训练集误差小&#xff0c;交叉验证集误差小&#x…

Linux网络:传输层协议TCP(二)三次挥手四次握手详解

目录 一、TCP的连接管理机制 1.1三次握手 1.2四次挥手 二、理解 TIME_WAIT 状态 2.1解决TIME_WAIT 状态引起的 bind 失败的方法 三、理解CLOSE_WAIT状态 一、TCP的连接管理机制 在正常情况下, TCP 要经过三次握手建立连接, 四次挥手断开连接 1.1三次握手 三次握手顾名思…

vue import from

vue import from 导入文件&#xff0c;从XXXX路径&#xff1b;引入文件 import xxxx from “./minins/resize” import xxxx from “./minins/resize.js” vue.config.js 定义 : resolve(src)&#xff1b;就是指src 目录 import xxxx from “/utils/auth” im…

vue3知识

目录 基础vue开发前的准备vue项目目录结构模板语法属性绑定条件渲染列表渲染通过key管理状态事件处理事件传参事件修饰符数组变化侦测计算属性Class绑定style绑定侦听器表单输入绑定模板引用组件组成组件嵌套关系组件注册方式组件传递数据Props(父传子)组件传递多种数据类型组件…

怎么批量加密U盘?U盘批量加密的方法有哪些?

加密U盘是保护U盘数据安全的重要方法。而当需要加密的U盘数量较多时&#xff0c;我们需要批量加密U盘。那么&#xff0c;U盘怎么批量加密呢&#xff1f;下面我们就来了解一下。 U盘内存卡批量只读加密专家 U盘内存卡批量只读加密专家是一款专业的U盘加密软件&#xff0c;适用于…

什么牌子的充电宝又好又耐用?认准这几个充电宝品牌!错过就吃亏

在 2024 年&#xff0c;充电宝已然成为我们生活中不可或缺的电子配件。但面对市场上琳琅满目的充电宝产品&#xff0c;如何挑选出一款适合自己的&#xff0c;却让许多人感到困惑。充电宝要怎么挑&#xff1f;这可不是一个简单的问题。不同的使用场景、不同的设备需求&#xff0…

02 MySQL数据库管理

目录 1.数据库的结构 sql语言主要由以下几部分组成 2. 数据库与表的创建和管理 1&#xff0c;创建数据库 2&#xff0c;创建表并添加数据 3&#xff0c;添加一条数据 4&#xff0c;查询数据 5&#xff0c;更新数据 6&#xff0c;删除数据 3.用户权限管理 1.创建用户 …

3万多有分类的成语词典ACCESS\EXCEL数据库

今天最后发一个成语词典的数据库了&#xff0c;因为成语词典的数据库太多了导致我自己都有些糊涂了&#xff0c;今天这份数据库应该说是最好的成语词典了&#xff0c;不但包含了3级分类&#xff0c;而且还有级别&#xff08;不要太较真&#xff09;字段。 数据库包含多个表&…

利用 Databend 生态构建现代数据湖工作流

数据是洞察力的基石&#xff0c;越来越多的企业开始建设以数据资产为中心的存储和分析一体化方案&#xff0c;这要求 Data Infra 架构能够提供可扩展、灵活且统一的数据工作流。现代数据湖架构同时兼顾数据湖的可扩展性和数据仓库的性能&#xff0c;满足对大规模数据处理的需求…

视频文件怎么压缩到最小 视频文件怎么压缩到最小内存 4个简单的方法工具分享简单步骤

如何压缩大视频文件以减小其大小&#xff1f;在分享或存储大视频文件时&#xff0c;有效压缩是关键&#xff0c;以降低文件大小且不显著牺牲视觉和听觉质量。视频文件的大小直接影响传输、分享和存储的成本与便捷性。掌握压缩视频的技能对于数字内容处理至关重要&#xff0c;能…

【Android】linux

android系统就是跑在linux上的系统。Linux层里面包含系统和硬件驱动等一些本地代码的环境。 linux的目录 mount: 用于查看哪个模块输入只读&#xff0c;一般显示为&#xff1a; [rootlocalhost ~]# mount /dev/cciss/c0d0p2 on / type ext3 (rw) proc on /proc type proc (…

SpringBoot 实现图形验证码

一、最终结果展示 二、前端代码 2.1 index.html <!DOCTYPE html> <html lang"en"><head><meta charset"utf-8"><title>验证码</title><style>#inputCaptcha {height: 30px;vertical-align: middle;}#verifica…

(leetcode学习)236. 二叉树的最近公共祖先

给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。 百度百科中最近公共祖先的定义为&#xff1a;“对于有根树 T 的两个节点 p、q&#xff0c;最近公共祖先表示为一个节点 x&#xff0c;满足 x 是 p、q 的祖先且 x 的深度尽可能大&#xff08;一个节点也可以是它自己的祖…

Q238. 除自身以外数组的乘积

思路 一开始想到的是按位乘 看了题解&#xff0c;思路是存i左边的乘积和 与 i右边的乘积和 代码一&#xff1a; 需要三次循环,需要额外空间 left和right数组 代码&#xff1a; public int[] productExceptSelf(int[] nums) {int[] left new int[nums.length];int[] right …

python题解

空间三角形 输入在三维空间的三角形三个顶点A&#xff0c;B&#xff0c;C的坐标&#xff08;x,y,z&#xff09;&#xff0c;计算并输出三角形面积。不考虑不能构成三角形的特殊情况。 格式 输入格式&#xff1a; 依次输入三个顶点A&#xff0c;B&#xff0c;C的坐标&#xff…

CISSP,信息安全圈公认的高含金量证书

在数字化和信息化迅速发展的时代&#xff0c;信息安全的重要性愈发突出。 网络攻击、数据泄露和隐私问题频发&#xff0c;使得企业和组织对信息安全专业人士的需求不断增加。 CISSP&#xff08;Certified Information Systems Security Professional&#xff09;作为信息安全领…

文字描边效果

文字描边效果可以通过text-shadow来实现&#xff0c;也可以通过-webkit-text-stroke来实现 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, i…