LVGL图像导入和解码

news2025/5/11 21:19:31

LVGL版本:8.1

概述

       在LVGL中,可以导入多种不同类型的图像:

  • 经转换器生成的C语言数组,适用于页面中不常改变的固定图像。
  • 存储系统中的外部图像,比较灵活,可以通过插卡或从网络中获取,但需要配置相应的驱动和解码器,解码过程也需要占用时间和内存。
  • SYMBOL类型的文本,和label组件类似。

       其中第三种比较容易实现,第一种仅需经过官方工具生成二进制数据,再在代码中引用即可。本文重点说明第二种情况即外部图像的使用,并以PNG类型图片为例介绍LVGL图像的解码和显示。

原理框图

       图像的解析和使用可以分以下几层:

        图中的虚线框可有可无,有的仅代表多一层函数,为了更好的理解,在图上加入这些虚线框。

       对于一个通过lv_img_create()函数创建的lv_img_t图像,可以通过设置图像源进行图像导入,LVGL会先查看缓存,如果有命中则直接使用,否则进入解码环节。对于内置图像如SYMBOL和VARIABLE(即C数组)类型,可以直接使用内置的解码器,在编译时会直接合并入程序。对于外部图像格式如jpg和png,则需要添加额外的解码器,并且,由于这些外部图像通常是以文件的形式存放在文件系统中,还需要提供基本的文件操作来读取文件,如Linux可以简单使用POSIX标准的系统调用函数(open、read、write等),事实上,如果没有提供文件系统,用户也可以自定义图像的打开和读取方式,只要符合接口标准即可。

    开启配置

           以PNG类型的图像为例,需要在lv_conf.h配置文件中,打开LV_USE_PNG开关,同时要开启文件系统(根据实际所在系统进行选择),比如在这里我选择的是LV_USE_FS_POSIX,即使用POSIX标准的文件操作函数(read、write等),也是Linux的原生操作。注意这里要求填入一个前缀来区分不同系统,通常使用类似“盘符”的字母(如这里使用了'S'),因为LVGL底层打开源路径时也是比对的路径首字母,配对成功后才会使用对应的驱动来打开。

    //lv_conf.h
    /* 文件系统,如开启,请设置相应的驱动字母(或前缀) */
    #define LV_USE_FS_STDIO '\0'        /*Uses fopen, fread, etc*/
    //#define LV_FS_STDIO_PATH "/home/john/"    /*Set the working directory. If commented it will be "./" */
    
    #define LV_USE_FS_POSIX 'S'        /*Uses open, read, etc*/
    //#define LV_FS_POSIX_PATH "/home/john/"    /*Set the working directory. If commented it will be "./" */
    
    #define LV_USE_FS_WIN32 '\0'        /*Uses CreateFile, ReadFile, etc*/
    //#define LV_FS_WIN32_PATH "C:\\Users\\john\\"    /*Set the working directory. If commented it will be ".\\" */
    
    #define LV_USE_FS_FATFS '\0'        /*Uses f_open, f_read, etc*/
    
    /*PNG decoder library*/
    #define LV_USE_PNG 1

           此外,还可以增加系统的图像缓存数量LV_IMG_CACHE_DEF_SIZE,来减少不必要的解码,提高渲染效率。

    //lv_conf.h
    #define LV_IMG_CACHE_DEF_SIZE 1   //图像缓存数量,只有使用外部解码器的图像,该配置才有意义

     

    图像解码

           通过lv_img_set_src()函数设置图像源来开启LVGL解码和显示的过程,其中图像源src可以是以下类型:

    • 图像路径,通常以一个盘符为首(如'S'或'S:'),后面跟绝对路径,比如是'S/img/abc.png',注意图像要预先导入到设备对应路径上才能读取
    • LVGL规定的SYMBOL类型,也可以通过官方工具生成自定义SYMBOL;
    • C语言数组,包含图像的位置和色彩信息,可以通过官方工具将其它类型的图像转换为LVGL可识别的数据文件,并在使用处进行声明和导入。

           在这里,该函数仅用于设置图像源,并获取图像基本信息,还没有到解码部分。

    //lv_img.c
    void lv_img_set_src(lv_obj_t * obj, const void * src)
    {
        LV_ASSERT_OBJ(obj, MY_CLASS);
    
        lv_obj_invalidate(obj);
    
        lv_img_src_t src_type = lv_img_src_get_type(src);  //获取来源类型
        lv_img_t * img = (lv_img_t *)obj;
    
        /*If the new source type is unknown free the memories of the old source*/
        if(src_type == LV_IMG_SRC_UNKNOWN) {
            LV_LOG_WARN("lv_img_set_src: unknown image type");
            if(img->src_type == LV_IMG_SRC_SYMBOL || img->src_type == LV_IMG_SRC_FILE) {
                lv_mem_free((void *)img->src);
            }
            img->src      = NULL;
            img->src_type = LV_IMG_SRC_UNKNOWN;
            return;
        }
    
        lv_img_header_t header;
        lv_img_decoder_get_info(src, &header);  //通过图片来源获取对应的解码器
    
        /*Save the source*/
        if(src_type == LV_IMG_SRC_VARIABLE) {
            /*If memory was allocated because of the previous `src_type` then free it*/
            if(img->src_type == LV_IMG_SRC_FILE || img->src_type == LV_IMG_SRC_SYMBOL) {
                lv_mem_free((void *)img->src);
            }
            img->src = src;
        }
        else if(src_type == LV_IMG_SRC_FILE || src_type == LV_IMG_SRC_SYMBOL) {
            /*If the new and the old src are the same then it was only a refresh.*/
            if(img->src != src) {
                const void * old_src = NULL;
                /*If memory was allocated because of the previous `src_type` then save its pointer and free after allocation.
                 *It's important to allocate first to be sure the new data will be on a new address.
                 *Else `img_cache` wouldn't see the change in source.*/
                if(img->src_type == LV_IMG_SRC_FILE || img->src_type == LV_IMG_SRC_SYMBOL) {
                    old_src = img->src;
                }
                char * new_str = lv_mem_alloc(strlen(src) + 1);
                LV_ASSERT_MALLOC(new_str);
                if(new_str == NULL) return;
                strcpy(new_str, src);
                img->src = new_str;
    
                if(old_src) lv_mem_free((void *)old_src);
            }
        }
    
        if(src_type == LV_IMG_SRC_SYMBOL) {
            /*`lv_img_dsc_get_info` couldn't set the with and height of a font so set it here*/
            const lv_font_t * font = lv_obj_get_style_text_font(obj, LV_PART_MAIN);
            lv_coord_t letter_space = lv_obj_get_style_text_letter_space(obj, LV_PART_MAIN);
            lv_coord_t line_space = lv_obj_get_style_text_line_space(obj, LV_PART_MAIN);
            lv_point_t size;
            lv_txt_get_size(&size, src, font, letter_space, line_space, LV_COORD_MAX, LV_TEXT_FLAG_NONE);
            header.w = size.x;
            header.h = size.y;
        }
    
        img->src_type = src_type;   //图像类型(变量/符号/文件路径)
        img->w        = header.w;   //图像宽度
        img->h        = header.h;   //图像高度
        img->cf       = header.cf;   //图像色彩信息
        img->pivot.x = header.w / 2;
        img->pivot.y = header.h / 2;
    
        lv_obj_refresh_self_size(obj);
    
        /*Provide enough room for the rotated corners*/
        if(img->angle || img->zoom != LV_IMG_ZOOM_NONE) lv_obj_refresh_ext_draw_size(obj);
    
        lv_obj_invalidate(obj);   //标记无效区域,下次更新才会正式解码图片
    }

           其中lv_img_decoder_get_info()用于获取图像源的基本信息,该函数会首先遍历解码器链表,匹配合适的解码器,然后将图像的宽、高、色彩信息记录下来。

    //lv_img_decoder.c
    lv_res_t lv_img_decoder_get_info(const void * src, lv_img_header_t * header)
    {
        lv_memset_00(header, sizeof(lv_img_header_t));
    
        if(src == NULL) return LV_RES_INV;
    
        lv_img_src_t src_type = lv_img_src_get_type(src);
        if(src_type == LV_IMG_SRC_VARIABLE) {
            const lv_img_dsc_t * img_dsc = src;
            if(img_dsc->data == NULL) return LV_RES_INV;
        }
    
        lv_res_t res = LV_RES_INV;
        lv_img_decoder_t * d;
        _LV_LL_READ(&LV_GC_ROOT(_lv_img_decoder_ll), d) {  //遍历解码器链表,为图像源寻找合适的解码器
            if(d->info_cb) {
                res = d->info_cb(d, src, header);  //调用info回调,获取图像信息,header用于保存这些信息
                if(res == LV_RES_OK) break;   //返回OK,说明解码器配对成功,退出并返回
            }
        }
    
        return res;
    }

           如果定义了LV_USE_PNG,则默认注册LVGL自带的PNG解码器,其中包含获取基本信息的回调函数decoder_info()

    //lv_png.c
    static lv_res_t decoder_info(struct _lv_img_decoder_t * decoder, const void * src, lv_img_header_t * header)
    {
        (void) decoder; /*Unused*/
        lv_img_src_t src_type = lv_img_src_get_type(src);     /* 获取来源类型 */
    
        /* 检查是否是文件路径类型 */
        if(src_type == LV_IMG_SRC_FILE) {
            const char * fn = src;
            if(!strcmp(&fn[strlen(fn) - 3], "png")) {     /* 检查后缀是否为png */
    
                /* Read the width and height from the file. They have a constant location:
                * [16..23]: width
                * [24..27]: height
                */
                uint32_t size[2];
                lv_fs_file_t f;
                lv_fs_res_t res = lv_fs_open(&f, fn, LV_FS_MODE_RD);  //使用对应的驱动打开文件
                if(res != LV_FS_RES_OK) return LV_RES_INV;
                lv_fs_seek(&f, 16, LV_FS_SEEK_SET);
                uint32_t rn;
                lv_fs_read(&f, &size, 8, &rn);
                if(rn != 8) return LV_RES_INV;
                lv_fs_close(&f);
                /*Save the data in the header*/
                header->always_zero = 0;
                header->cf = LV_IMG_CF_RAW_ALPHA;
                /*The width and height are stored in Big endian format so convert them to little endian*/
                header->w = (lv_coord_t) ((size[0] & 0xff000000) >> 24) +  ((size[0] & 0x00ff0000) >> 8);
                header->h = (lv_coord_t) ((size[1] & 0xff000000) >> 24) +  ((size[1] & 0x00ff0000) >> 8);
    
                return LV_RES_OK;
            }
        }
        /*If it's a PNG file in a  C array...*/
        else if(src_type == LV_IMG_SRC_VARIABLE) {
            const lv_img_dsc_t * img_dsc = src;
            header->always_zero = 0;
            header->cf = img_dsc->header.cf;       /*Save the color format*/
            header->w = img_dsc->header.w;         /*Save the color width*/
            header->h = img_dsc->header.h;         /*Save the color height*/
            return LV_RES_OK;
        }
    
        return LV_RES_INV;         /*If didn't succeeded earlier then it's an error*/
    }

           其中lv_fs_open()函数是寻找合适的驱动来打开这个文件,我们在前面定义了LV_USE_FS_POSIX,LVGL在初始化阶段就会自动注册POSIX标准驱动,使用open、read、write等函数打开对应文件。

    //lv_fs_posix.c
    void lv_fs_posix_init(void)
    {
        static lv_fs_drv_t fs_drv; /* 驱动描述子 */
        lv_fs_drv_init(&fs_drv);
    
        fs_drv.letter = LV_USE_FS_POSIX;  //文件系统前缀,可以简单设置为'S'
        fs_drv.open_cb = fs_open;
        fs_drv.close_cb = fs_close;
        fs_drv.read_cb = fs_read;
        fs_drv.write_cb = fs_write;
        fs_drv.seek_cb = fs_seek;
        fs_drv.tell_cb = fs_tell;
    
        fs_drv.dir_close_cb = fs_dir_close;
        fs_drv.dir_open_cb = fs_dir_open;
        fs_drv.dir_read_cb = fs_dir_read;
    
        lv_fs_drv_register(&fs_drv);
    }

           到这里为止仅仅只是把图像源记录下来,直到下次更新周期的绘制阶段,才会正式解析图像。下面直接跳转到图像的绘制函数lv_draw_img_core(),这里仅截取解码图像的代码片段。

    //lv_draw_img.c
    LV_ATTRIBUTE_FAST_MEM static lv_res_t lv_img_draw_core(const lv_area_t * coords, const lv_area_t * clip_area,
                                                           const void * src,
                                                           const lv_draw_img_dsc_t * draw_dsc)
    {
        if(draw_dsc->opa <= LV_OPA_MIN) return LV_RES_OK;
    
        _lv_img_cache_entry_t * cdsc = _lv_img_cache_open(src, draw_dsc->recolor, draw_dsc->frame_id);
    
        if(cdsc == NULL) return LV_RES_INV;
    
        /*......*/
    }

           可以看到,LVGL在绘制图像前先询问缓存,即_lv_img_cache_open()函数,该函数会先遍历缓存链表,查找是否存在匹配的缓存,如匹配直接返回该缓存,否则从链表中找一个存活时间最短的缓存,用新的图像替换掉该旧缓存。

    //lv_img_cache.c
    _lv_img_cache_entry_t * _lv_img_cache_open(const void * src, lv_color_t color, int32_t frame_id)
    {
        _lv_img_cache_entry_t * cached_src = NULL;
    
    #if LV_IMG_CACHE_DEF_SIZE
        if(entry_cnt == 0) {
            LV_LOG_WARN("lv_img_cache_open: the cache size is 0");
            return NULL;
        }
    
        _lv_img_cache_entry_t * cache = LV_GC_ROOT(_lv_img_cache_array);
    
        /*Decrement all lifes. Make the entries older*/
        uint16_t i;
        for(i = 0; i < entry_cnt; i++) {
            if(cache[i].life > INT32_MIN + LV_IMG_CACHE_AGING) {
                cache[i].life -= LV_IMG_CACHE_AGING;
            }
        }
    
        for(i = 0; i < entry_cnt; i++) {
            if(color.full == cache[i].dec_dsc.color.full &&
               frame_id == cache[i].dec_dsc.frame_id &&
               lv_img_cache_match(src, cache[i].dec_dsc.src)) {  //是否命中缓存
                /* 打开一个图像也会增加图像的存活时间,因此在这里对缓存增加一个time_to_open的时间 */
                cached_src = &cache[i];
                cached_src->life += cached_src->dec_dsc.time_to_open * LV_IMG_CACHE_LIFE_GAIN;
                if(cached_src->life > LV_IMG_CACHE_LIFE_LIMIT) cached_src->life = LV_IMG_CACHE_LIFE_LIMIT;
                LV_LOG_TRACE("image source found in the cache");
                break;
            }
        }
    
        /* 命中缓存后直接返回该缓存 */
        if(cached_src) return cached_src;
    
        /* 如果没有命中,则在缓存中寻找一个合适的位置存放新图像 */
        cached_src = &cache[0];
        for(i = 1; i < entry_cnt; i++) {
            if(cache[i].life < cached_src->life) {   //寻找生存时间最短的图像
                cached_src = &cache[i];
            }
        }
    
        /* 找到被替代的缓存后,要先关闭它的解码器 */
        if(cached_src->dec_dsc.src) {
            lv_img_decoder_close(&cached_src->dec_dsc);
            LV_LOG_INFO("image draw: cache miss, close and reuse an entry");
        }
        else {
            LV_LOG_INFO("image draw: cache miss, cached to an empty entry");
        }
    #else
        cached_src = &LV_GC_ROOT(_lv_img_cache_single);
    #endif
        /* 打开一个新的解码器 */
        uint32_t t_start  = lv_tick_get();
        lv_res_t open_res = lv_img_decoder_open(&cached_src->dec_dsc, src, color, frame_id);
        if(open_res == LV_RES_INV) {
            LV_LOG_WARN("Image draw cannot open the image resource");
            lv_memset_00(cached_src, sizeof(_lv_img_cache_entry_t));
            cached_src->life = INT32_MIN; /*Make the empty entry very "weak" to force its us*/
            return NULL;
        }
    
        cached_src->life = 0;   //记录缓存后,设置存活时间从0开始
    
        /* 记录解码它的时间 */
        if(cached_src->dec_dsc.time_to_open == 0) {
            cached_src->dec_dsc.time_to_open = lv_tick_elaps(t_start);
        }
    
        if(cached_src->dec_dsc.time_to_open == 0) cached_src->dec_dsc.time_to_open = 1;
    
        return cached_src;
    }

           当没有命中缓存时,会调用lv_img_decoder_open()函数尝试使用解码器打开该图像,打开成功后,会将图像数据提取出来。

    //lv_img_decoder.c
    lv_res_t lv_img_decoder_open(lv_img_decoder_dsc_t * dsc, const void * src, lv_color_t color, int32_t frame_id)
    {
        lv_memset_00(dsc, sizeof(lv_img_decoder_dsc_t));
    
        if(src == NULL) return LV_RES_INV;
        lv_img_src_t src_type = lv_img_src_get_type(src);
        if(src_type == LV_IMG_SRC_VARIABLE) {
            const lv_img_dsc_t * img_dsc = src;
            if(img_dsc->data == NULL) return LV_RES_INV;
        }
    
        dsc->color    = color;
        dsc->src_type = src_type;
        dsc->frame_id = frame_id;
    
        if(dsc->src_type == LV_IMG_SRC_FILE) {
            size_t fnlen = strlen(src);
            dsc->src = lv_mem_alloc(fnlen + 1);
            LV_ASSERT_MALLOC(dsc->src);
            if(dsc->src == NULL) {
                LV_LOG_WARN("lv_img_decoder_open: out of memory");
                return LV_RES_INV;
            }
            strcpy((char *)dsc->src, src);
        }
        else {
            dsc->src = src;
        }
    
        lv_res_t res = LV_RES_INV;
    
        lv_img_decoder_t * decoder;
        _LV_LL_READ(&LV_GC_ROOT(_lv_img_decoder_ll), decoder) {   //遍历解码器链表
            /* info和open函数是必要的 */
            if(decoder->info_cb == NULL || decoder->open_cb == NULL) continue;
    
            res = decoder->info_cb(decoder, src, &dsc->header);
            if(res != LV_RES_OK) continue;  //返回OK,说明命中解码器
    
            dsc->decoder = decoder;
            res = decoder->open_cb(decoder, dsc);  //使用解码器打开图像文件
    
            /* 如果返回OK,表示成功打开图像文件,则返回 */
            if(res == LV_RES_OK) return res;
    
            /* 准备遍历下一个解码器节点 */
            lv_memset_00(&dsc->header, sizeof(lv_img_header_t));
    
            dsc->error_msg = NULL;
            dsc->img_data  = NULL;
            dsc->user_data = NULL;
            dsc->time_to_open = 0;
        }
    
        if(dsc->src_type == LV_IMG_SRC_FILE)
            lv_mem_free((void *)dsc->src);
    
        return res;
    }

           接下来就是使用对应解码器的open函数来获取图像,这里就不进一步说明了。可以参考官方对于不同格式图像的解码器例程代码。

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

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

    相关文章

    project从入门到精通(五)

    目录 创建资源的基本信息 在project中创建资源工作表 ​编辑信息详解 最大单位 标准费率与加班费率 每次使用成本 成本累算 基准日历 三类资源工作表的总结——不同的资源必须要设置的属性 除了资源名称是必须设置的之外&#xff0c;剩余的资源的可设置选项如下图所…

    第3.2.3节 Android动态调用链路的获取

    3.2.3 Android App动态调用链路 在Android应用中&#xff0c;动态调用链路指的是应用在运行时的调用路径。这通常涉及到方法调用的顺序和调用关系&#xff0c;特别是在应用的复杂逻辑中&#xff0c;理解这些调用链路对于调试和性能优化非常重要。 1&#xff0c;动态调用链路获…

    亿级流量系统架构设计与实战(六)

    微服务架构与网络调用 当某个业务从单体服务架构转变为微服务架构后,多个服务之间会通过网络调用形式形成错综复杂的依赖关系。 在微服务架构中 , 一个微服务正常工作依赖它与其他微服务之间的多级网络调用。 网络是脆弱的 , RPC 请求有较大的概率会遇到超时 、 抖动 、 断…

    浅聊find_package命令的搜索模式(Search Modes)

    背景 find_package应该算是我们使用最多的cmake命令了。但是它是如何找到上游库的.cmake文件的&#xff1f; 根据官方文档&#xff0c;整理下find_package涉及到的搜索模式。 搜索模式 find_package涉及到的搜索模式有两种&#xff1a;模块模式(Module mode)和配置模式(Conf…

    【LLaMA-Factory】使用LoRa微调训练DeepSeek-R1-Distill-Qwen-7B

    【LLaMA-Factory】使用LoRa微调训练DeepSeek-R1-Distill-Qwen-7B 本地环境说明禁用开源驱动nouveau安装nvidia-smi安装Git环境安装Anaconda(conda)环境下载DeepSeek-R1-Distill-Qwen-7B模型安装LLaMA-Factory下载LLaMA-Factory安装LLaMA-Factory依赖修改环境变量安装deepspeedA…

    使用lldb查看Rust不同类型的结构

    目录 前言 正文 标量类型 复合类型——元组 复合类型——数组 函数 &str struct 可变数组vec Iter String Box Rc Arc RefCell Mutex RwLock Channel 总结 前言 笔者发现这个lldb挺好玩的&#xff0c;可以查看不同类型的结构&#xff0c;虽然这好像是C的东…

    【Linux】线程POSIX信号量

    目录 1. 整体学习思维导图 2. 信号量的概念 3. 基本接口 4. 基于环形队列的生产者消费者模型(信号量) 1. 整体学习思维导图 2. 信号量的概念 POSIX信号量和SystemV信号量作用相同&#xff0c;都是用于同步操作&#xff0c;达到无冲突的访问共享资源目的。但 POSIX可以用于线…

    MySQL事务和JDBC中的事务操作

    一、什么是事务 事务是数据库操作的最小逻辑单元&#xff0c;具有"全有或全无"的特性。以银行转账为例&#xff1a; 典型场景&#xff1a; 从A账户扣除1000元 向B账户增加1000元 这两个操作必须作为一个整体执行&#xff0c;要么全部成功&#xff0c;要么全部失败…

    每日脚本学习5.10 - XOR脚本

    xor运算的简介 异或就是对于二进制的数据可以 进行同0异1 简单的演示 &#xff1a; 结果是 这个就是异或 异或的作用 1、比较两数是否相等 2、可以进行加密 加密就是需要key 明文 :0b010110 key : 0b1010001 这个时候就能进行加密 明文 ^ key密文 还有这个加密比…

    【编译原理】总结

    核心 闭包&#xff0c;正则闭包 产生式&#xff08;规则&#xff09; 文法 G[S](&#xff0c;&#xff0c;P&#xff0c;S) 一组规则的集合 &#xff1a;非终结符 &#xff1a;终结符 P&#xff1a;产生式 S&#xff1a;开始符号 推导 归约 规范&#xff08;最右&#xff…

    docker创建一个centOS容器安装软件(以宝塔为例)的详细步骤

    备忘&#xff1a;后续偶尔忘记了docker虚拟机与宿主机的端口映射关系&#xff0c;来这里查看即可&#xff1a; docker run -d \ --name baota \ --privilegedtrue \ -p 8888:8888 \ -p 8880:80 \ -p 8443:443 \ -p 8820:20 \ -p 8821:21 \ -v /home/www:/www/wwwroot \ centos…

    OpenVLA:开源的视觉-语言-动作模型

    1. 简介 让我们先来介绍一下什么是OpenVLA&#xff0c;在这里&#xff1a; https://openvla.github.io/ 可以看到他们的论文、数据、模型。 OpenVLA 是一个拥有 70亿参数的开源 **视觉-语言-动作&#xff08;VLA&#xff09;**模型。它是在 Open X-Embodiment 数据集 中的 97万…

    Matlab/Simulink的一些功能用法笔记(4)

    水一篇帖子 01--MATLAB工作区的保护眼睛颜色设置 默认的工作区颜色为白色 在网上可以搜索一些保护眼睛的RGB颜色参数设置 在MATLAB中按如下设置&#xff1a; ①点击预设 ②点击颜色&#xff0c;点击背景色的三角标符号 ③点击更多颜色&#xff0c;找到RGB选项 ④填写颜色参数…

    Elasticsearch:我们如何在全球范围内实现支付基础设施的现代化?

    作者&#xff1a;来自 Elastic Kelly Manrique SWIFT 和 Elastic 如何应对基础设施复杂性、误报问题以及日益增长的合规要求。 金融服务公司在全球范围内管理实时支付方面面临前所未有的挑战。SWIFT&#xff08;Society for Worldwide Interbank Financial Telecommunication -…

    matlab介绍while函数

    MATLAB 中的 while 语句介绍 在 MATLAB 中&#xff0c;while 语句是一种循环结构&#xff0c;用于在满足特定条件时反复执行一段代码块。与 for 循环不同&#xff0c;while 循环的执行次数是动态的&#xff0c;取决于循环条件是否为真。 语法 while condition% 循环体代码 e…

    如何解决 PowerShell 显示 “此系统上禁用了脚本运行” 的问题

    在 Windows 11 或 10 的 PowerShell 中运行脚本时,你可能会遇到一个错误,提示系统上禁用了脚本运行。这是一种安全功能,而不是系统问题,旨在防止可能有害的脚本自动运行。然而,如果你需要运行脚本来完成某些任务,或者你在系统上做了软件开发或测试的环境,那么你需要在 P…

    深入浅出之STL源码分析4_类模版

    1.引言 我在上面的文章中讲解了vector的基本操作&#xff0c;然后提出了几个问题。 STL之vector基本操作-CSDN博客 1.刚才我提到了我的编译器版本是g 11.4.0&#xff0c;而我们要讲解的是STL&#xff08;标准模板库&#xff09;&#xff0c;那么二者之间的关系是什么&#x…

    初学者入门指南:什么是网络拓扑结构?

    初学者入门指南&#xff1a;什么是网络拓扑结构&#xff1f; 在构建或学习计算机网络时&#xff0c;一个绕不开的核心概念便是“网络拓扑结构”&#xff08;Network Topology&#xff09;。它决定了网络中各个设备如何连接、通信以及如何扩展。理解网络拓扑不仅有助于我们更清…

    Satori:元动作 + 内建搜索机制,让大模型实现超级推理能力

    Satori&#xff1a;元动作 内建搜索机制&#xff0c;让大模型实现超级推理能力 论文大纲一、背景&#xff1a;LLM 推理增强的三类方法1. 基于大规模监督微调&#xff08;SFT&#xff09;的推理增强2. 借助外部机制在推理时进行搜索 (RLHF / 多模型 / 工具)3. 现有局限性总结 二…

    SDC命令详解:使用all_outputs命令进行查询

    相关阅读 SDC命令详解https://blog.csdn.net/weixin_45791458/category_12931432.html all_outputs命令用于创建一个输出端口对象集合&#xff0c;关于设计对象和集合的更详细介绍&#xff0c;可以参考下面的博客。 Synopsys&#xff1a;设计对象https://chenzhang.blog.csdn…