Qt-Web混合开发-CEF加载网页简单示例(12)

Qt-Web混合开发-CEF加载网页简单示例💙🍓

文章目录

  • Qt-Web混合开发-CEF加载网页简单示例💙🍓
    • 1、概述🐛🦆
    • 2、实现效果😅🙏
    • 3、实现功能🐮🐴
    • 4、Qt部分关键代码💳🛣️🍐
    • 5、Web部分关键代码👊👎😷🦠
    • 6、源代码🐍🉐

更多精彩内容
👉个人内容分类汇总 👈
👉Qt - Web混合开发👈

1、概述🐛🦆

  • Qt版本:V5.12.5
  • 编译器:MSVC2017-64
  • CEF版本:91.0.4472.164

CEF(Chromium Embedded Framework)是一种用于嵌入式浏览器的框架,它可以让开发者在自己的应用程序中嵌入一个完整的浏览器窗口,提供与Web页面交互的能力,使用CEF可以快速开发出精美的界面。以下是使用CEF的一些优点:

  1. 灵活性:CEF提供了许多API和插件,使开发者可以自由地定制和扩展浏览器功能,以满足自己的需求。
  2. 多平台支持:CEF支持多种操作系统,包括Windows、Linux和Mac OS X等,使开发者可以在不同平台上使用相同的代码。
  3. 轻量级:CEF可以嵌入到任何C/C++应用程序中,无需安装额外的软件和插件,因此可以减少应用程序的大小和依赖性。
  4. 安全性:使用CEF可以避免一些安全漏洞,例如XSS(跨站脚本)和CSRF(跨站请求伪造)等。
  5. 性能:CEF使用Chromium作为底层引擎,具有优秀的性能和稳定性,可以提供快速的Web浏览体验。

在实际应用中,CEF被广泛用于各种场景,例如游戏客户端、桌面应用程序、图形界面设计等。它可以让开发者在自己的应用程序中嵌入Web浏览器,为用户提供更丰富的Web应用体验和功能。

一些使用了CEF的国内互联网大厂和软件:

  1. 腾讯:腾讯的QQ浏览器就是基于CEF开发的。同时,腾讯的部分游戏客户端、视频客户端等也使用了CEF。
  2. 百度:百度的部分软件,例如网盘客户端、输入法等,也使用了CEF。
  3. 360公司:360公司的部分软件,例如浏览器、安全卫士等,也使用了CEF。
  4. 哔哩哔哩:哔哩哔哩的客户端也使用了CEF,它可以让用户在客户端中观看B站的视频。
  5. 网易:网易的部分游戏客户端和音乐客户端也使用了CEF。

2、实现效果😅🙏

在这里插入图片描述

3、实现功能🐮🐴

  1. QT使用QCefView+CEF实现加载网页功能,相较于QWebEngineView更加稳定,强大;
  2. 演示了如何加载本地html文件和在线网页;
  3. 自动将依赖文件(html、CEF动态库)安装到可执行程序路径下;
  4. 详细注释了使用到的 Chrome命令;

4、Qt部分关键代码💳🛣️🍐

  • pro文件
#---------------------------------------------------------------------------------------
# @功能:       Qt使用cef加载网页简单示例
# @编译器:     Desktop Qt 5.12.5 MSVC2017 64bit(也支持其它编译器)
# @Qt IDE:    D:/Qt/Qt5.12.5/Tools/QtCreator/share/qtcreator
#
# @开发者     mhf
# @邮箱       1603291350@qq.com
# @时间       2023-02-05 12:08:27
# @备注       在父工程中定义依赖库的路径CefPath,如果直接编译当前工程,则需要指定CefPath
#---------------------------------------------------------------------------------------
QT       += core gui

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
CONFIG += c++11
DEFINES += QT_DEPRECATED_WARNINGS

SOURCES += \
    main.cpp \
    widget.cpp

HEADERS += \
    widget.h

FORMS += \
    widget.ui

# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target

#  定义程序版本号
VERSION = 1.0.0
DEFINES += APP_VERSION=\\\"$$VERSION\\\"

# 程序输出路径
contains(QT_ARCH, i386){        # 使用32位编译器
    CONFIG(release, debug|release){
        DESTDIR = $$PWD/../bin
    }else:CONFIG(debug, debug|release){
        DESTDIR = $$PWD/../bind
    }
}else{
    CONFIG(release, debug|release){
        DESTDIR = $$PWD/../bin64
    }else:CONFIG(debug, debug|release){
        DESTDIR = $$PWD/../bin64d
    }
}

# CEF 库的路径, 如果路径为空则不编译当前工程
win32{
    CefPath = E:/lib/QCefView
}
unix:!macx{
}

# 导入库头文件的路径
INCLUDEPATH += $$CefPath/include
DEPENDPATH += $$CefPath/include

# Debug和release的库路径不同
CONFIG(release, debug|release){
    cefDLL.files = $$CefPath/bin/*
    LIBS += -L$$CefPath/lib/ -lQCefView
}else:CONFIG(debug, debug|release){
    cefDLL.files = $$CefPath/bind/*
    LIBS += -L$$CefPath/libd/ -lQCefView
}

# 自动安装依赖文件和库文件
cefDLL.path = $$DESTDIR
webFile.path = $$DESTDIR
webFile.files = $$PWD/hello.html

# msvc需要配置【Custom Process Step: nmake install】或者【Custom Process Step: D:\Qt\Qt5.12.5\Tools\QtCreator\bin\jom.exe install】才生效,或者自己手动拷贝
# Debug和Release需要分别配置
# 执行之前先qmake,如果不想每次手动qmake,可以点击【工具】->【选项】->【构建和运行】->【qmake】->勾选【Run qmake every build】
!exists($$webFile.path/hello.html): INSTALLS += webFile      # 将hello.html拷贝到path路径下
!exists($$cefDLL.path/QCefView.dll): INSTALLS += cefDLL      # 将CEF库文件拷贝到path路径下

# msvc >= 2017  编译器使用utf-8编码
msvc {
    greaterThan(QMAKE_MSC_VER, 1900){       # msvc编译器版本大于2015
        QMAKE_CFLAGS += /utf-8
        QMAKE_CXXFLAGS += /utf-8
    }else{
        message(msvc2015及以下版本在代码中使用【pragma execution_character_set("utf-8")】指定编码)
    }
}

  • widget.h
#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>

#include "QCefSetting.h"
#include "QCefView.h"

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();

private:
    Ui::Widget *ui;
    QCefView* cefViewWidget = nullptr;
};
#endif // WIDGET_H

  • widget.cpp
#include "widget.h"
#include "ui_widget.h"

#include <qdir.h>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    this->setWindowTitle(QString("Qt使用cef加载网页简单示例 - V%1").arg(APP_VERSION));  // 设置窗口标题

    // 构建web资源的路径
#if 1        // 在线显示网页
    QString uri = "https://www.baidu.com";
#else        // 显示本地html
    QDir dir = QCoreApplication::applicationDirPath();
    QString uri = QString("file://") + QDir::toNativeSeparators(dir.filePath("hello.html"));
#endif

    // 每个QCefView的生成设置
    QCefSetting setting;
    // 设置背景色
    setting.setBackgroundColor(QColor::fromRgb(255, 255, 255));

    // 创建QCefView小部件并将其添加到布局容器
    cefViewWidget = new QCefView(uri, &setting, this);
    ui->gridLayout->addWidget(cefViewWidget);
}

Widget::~Widget()
{
    delete ui;
}


  • main.cpp
#include "widget.h"

#include <QApplication>
#include <QCefContext.h>

void initCefConfig(QCefConfig& config)
{
    config.setUserAgent("QCefViewTest");                        // 设置用户代理
    config.setLogLevel(QCefConfig::LOGSEVERITY_DEFAULT);        // 设置日志级别
    config.setBridgeObjectName("CallBridge");                   // 设置网桥对象名称
    config.setRemoteDebuggingPort(9000);                        // 设置远程调试端口
    config.setBackgroundColor(QColor::fromRgba(qRgba(255, 0, 0, 0)));  // 设置网页的背景色

    config.addCommandLineSwitch("enable-media-stream");
    config.addCommandLineSwitch("use-mock-keychain");
    config.addCommandLineSwitch("allow-file-access-from-files");
    config.addCommandLineSwitch("disable-spell-checking");
    config.addCommandLineSwitch("disable-site-isolation-trials");
    config.addCommandLineSwitch("enable-aggressive-domstorage-flushing");
    // 将具有值的开关添加到用于初始化CEF的命令行参数中
    config.addCommandLineSwitchWithValue("renderer-process-limit", "1");
    config.addCommandLineSwitchWithValue("disable-features", "BlinkGenPropertyTrees,TranslateUI,site-per-process");
}

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);


    // 使用config初始化QCefContext实例
    QCefConfig config;
    initCefConfig(config);
    QCefContext cefContext(&a, argc, argv, &config);
    // 获取可执行程序所在的路径,然后添加 bin 目录到库的搜索路径中

    Widget w;
    w.show();
    return a.exec();
}

Chrome命令说明

  • enable-media-stream

    用于启用媒体流(Media Stream)功能。Media Stream 是 HTML5 中的一项新特性,

    它允许浏览器通过 WebRTC(Web Real-Time Communication)技术实现音频、视频、屏幕共享等功能,为实时通信提供了强大的支持。

    例如,通过 Media Stream,可以实现浏览器端的视频会议、语音聊天、桌面共享等功能。

    默认情况下,Chromium 浏览器已经启用了 Media Stream 功能,因此一般情况下不需要添加 enable-media-stream 参数。

    但如果您在使用 Chromium 浏览器时遇到了一些与媒体流相关的问题,例如无法共享屏幕或摄像头等,可能需要检查该参数是否被正确设置。

  • use-mock-keychain

    use-mock-keychain 是 macOS 中的一个命令行参数,用于在模拟环境下使用 Keychain,而不是使用真实的 Keychain。Keychain 是 macOS 中的一项安全功能,用于存储和管理用户的密码、证书和其他敏感信息。

    应用程序可以通过 Keychain API 访问这些信息,从而实现自动登录、自动填充表单等功能。在模拟环境下,如果不想使用真实的 Keychain,可以通过添加 use-mock-keychain 参数来使用模拟环境中的 Keychain。

    在使用该参数时,需要注意以下几点:

    仅在模拟环境下使用该参数。在实际的生产环境中,应当使用真实的 Keychain。

    使用模拟 Keychain 时,存储的密码和其他敏感信息仅存储在内存中,不会写入到硬盘中,因此不会在多次启动应用程序之间保留。

    模拟 Keychain 中存储的信息不会被其他应用程序访问,因此仅适用于单个应用程序的测试和开发场景。

  • allow-file-access-from-files

    用于允许浏览器访问本地文件系统。默认情况下,Chromium 浏览器禁止通过 file:// 协议访问本地文件系统中的文件,以防止恶意脚本窃取本地文件信息。但在某些情况下,用户可能需要使用 file:// 协议访问本地文件系统,例如在本地开发网页或调试 JavaScript 代码时。

    通过添加 allow-file-access-from-files 参数,可以在 Chromium 浏览器中启用对 file:// 协议的访问权限。需要注意的是,在启用该参数时,浏览器的安全性可能会受到一定程度的降低,因为恶意脚本可能会通过 file:// 协议访问本地文件系统中的敏感信息。

    因此建议仅在必要情况下使用该参数,并在使用时加强对本地文件系统的保护和监控。

  • disable-spell-checking

    用于禁用拼写检查功能。拼写检查是浏览器的一项功能,用于检查用户在输入表单、文本框等地方输入的文本是否存在拼写错误,并给出相应的纠正建议。

    如果用户需要输入一些特殊的术语、专业名词等,拼写检查可能会对输入造成干扰。

    因此,如果您使用 Chromium 浏览器时需要输入一些特殊的术语、专业名词等,可能会通过添加 disable-spell-checking 参数来禁用拼写检查功能,以避免输入干扰。

    但需要注意的是,禁用拼写检查功能可能会导致输入错误的单词无法被及时发现和纠正,因此建议仅在必要情况下使用该参数。

  • disable-site-isolation-trials

    用于禁用站点隔离试验功能。站点隔离是一项安全功能,它能够将不同站点的网页内容隔离开来,防止恶意网站通过跨站点脚本攻击(XSS)等方式盗取用户的敏感信息。

    站点隔离试验是一种用于测试站点隔离功能的实验性功能,它可能会导致某些网页无法正常加载或出现其他问题。

    因此,如果您使用 Chromium 浏览器时遇到了一些网页加载问题,可能可以通过添加 disable-site-isolation-trials 参数来禁用站点隔离试验功能,以解决这些问题。

    不过需要注意的是,禁用站点隔离试验功能可能会降低浏览器的安全性,因此建议仅在必要情况下使用该参数。

  • enable-aggressive-domstorage-flushing

    用于启用 DOM 存储数据的积极刷新。

    DOM 存储是一种浏览器提供的机制,用于在客户端存储数据,包括 localStorage 和 sessionStorage。

    默认情况下,当页面的 DOM 存储发生更改时,浏览器会在适当的时候将这些更改写入到磁盘中。

    但是,由于写操作可能会影响性能,因此浏览器不会立即将更改写入磁盘,而是将多个更改缓冲在内存中,直到达到一定的阈值才一次性写入磁盘。

    通过添加 enable-aggressive-domstorage-flushing 参数,可以启用 DOM 存储数据的积极刷新,即每次发生更改时立即将更改写入磁盘,以确保数据的及时保存。

    需要注意的是,启用该参数可能会影响浏览器的性能,因为频繁的磁盘写入操作会增加系统的负载。因此建议仅在必要情况下使用该参数,并在使用时加强对系统资源的监控和管理。

  • renderer-process-limit

    用于限制每个站点(域名)可以使用的渲染进程数量。

    在 Chromium 浏览器中,每个站点可以使用多个渲染进程,以提高浏览器的性能和稳定性。

    但是,如果某个站点占用了过多的渲染进程,可能会导致其他站点无法正常渲染,甚至导致浏览器崩溃。

    通过添加 renderer-process-limit 参数,可以限制每个站点可以使用的渲染进程数量,以确保每个站点都能够合理地使用系统资源。

    需要注意的是,该参数的默认值为 0,表示不限制渲染进程数量,因此需要手动设置该参数的值,才能实现对渲染进程数量的限制。

    建议在使用该参数时,根据系统资源和浏览器的实际情况,适当地调整渲染进程数量的限制。

  • disable-features

    用于禁用某些浏览器功能。Chromium 浏览器中提供了许多功能和特性,有些用户可能不需要或者不喜欢某些功能,因此可以通过添加 disable-features 参数来禁用这些功能。

    该参数的语法为:–disable-features=[,,…]

    其中, 是要禁用的功能的名称,多个功能名称之间使用逗号分隔。

    例如,要禁用 Chromium 浏览器中的 JavaScript,可以使用以下命令:
    chrome --disable-features=JavaScript

    需要注意的是,禁用某些功能可能会影响浏览器的功能和性能,因此建议仅在必要情况下使用该参数,并根据实际情况选择要禁用的功能。

  • 更多可用命令可用看

    https://bitbucket.org/chromiumembedded/cef/src/master/libcef/common/cef_switches.cc

    https://bitbucket.org/chromiumembedded/cef/src/master/tests/shared/common/client_switches.cc

    https://peter.sh/experiments/chromium-command-line-switches/

5、Web部分关键代码👊👎😷🦠

  • hello.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>本地Html文件</title>
</head>
<body>

<h1 align="center" style="font-size:80px; color:red;">hello </h1>
<p align="center" style="font-size:70px; color:blue;">world</p>

</body>
</html>

6、源代码🐍🉐

  • gitee
  • github

. ஓ๑⸜💗⸝‍๑ஓ
 ᕬ ᕬ   ∧ ∧
(˵ㅇ◡ㅇ˵) (ᓀ ֊ ᓂ˵ )
(つ☕O O🍵⊂)

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

2023/4/2总结

题解 线段树OR树状数组 - Virtual Judge (vjudge.net) 正如这道题目一样&#xff0c;我的心情也如此。 1.这道题是线段树问题&#xff0c;更改学生值即可&#xff0c;不需要用到懒惰标记。 2.再去按照区间查找即可。&#xff08;多组输入&#xff0c;拿20多次提交换来的&am…

2023大数据开发就业前景怎么样?

大数据开发就业班正在火热招生中。 大数据开发做什么&#xff1f; 大数据开发分两类&#xff0c;编写Hadoop、Spark的应用程序和对大数据处理系统本身进行开发。大数据开发工程师主要负责公司大数据平台的开发和维护、相关工具平台的架构设计与产品开发、网络日志大…

【算法基础】(一)基础算法 --- 位运算

✨个人主页&#xff1a;bit me ✨当前专栏&#xff1a;算法基础 &#x1f525;专栏简介&#xff1a;该专栏主要更新一些基础算法题&#xff0c;有参加蓝桥杯等算法题竞赛或者正在刷题的铁汁们可以关注一下&#xff0c;互相监督打卡学习 &#x1f339; &#x1f339; &#x1f3…

C语言函数大全--d开头的函数

C语言函数大全 本篇介绍C语言函数大全–d开头的函数 1. detectgraph 1.1 函数说明 函数声明函数功能void detectgraph(int *graphdriver, int *graphmode);通过检测硬件确定图形驱动程序和模式 1.2 演示示例 #include <graphics.h> #include <stdlib.h> #incl…

【Java 并发编程】一文读懂线程、协程、守护线程

一文读懂线程、协程、守护线程1. 线程的调度1.1 协同式线程调度1.2 抢占式线程调度1.3 设置线程的优先级2. 线程的实现模型和协程2.1 内核线程实现2.2 用户线程实现2.3 混合实现2.4 Java 线程的实现2.5 协程2.5.1 出现的原因2.5.2 什么是协程2.5.3 Java19 虚拟线程 - 协程的复苏…

Activiti7与Spring、Spring Boot整合开发

Activiti整合Spring 一、Activiti与Spring整合开发 1.1 Activiti与Spring整合的配置 1)、在pom.xml文件引入坐标 如下 <properties><slf4j.version>1.6.6</slf4j.version><log4j.version>1.2.12</log4j.version> </properties> <d…

【源码教程案例】AI绘画与安全在未来主要方向有哪些?

AI绘画在未来有许多潜在的发展方向,以下是一些可能的重点领域 高质量图像生成:随着生成模型的不断改进,未来的AI绘画可能会产生更高质量、更真实的图像,以满足各种应用场景的需求。 个性化创作:AI绘画可以通过用户的个性化偏好和需求来定制艺术作品。这种定制可能包括颜…

【gitlab部署】centos8安装gitlab(搭建属于自己的代码服务器)

这里写目录标题部署篇序言要求检查系统是否安装OpenSSH防火墙问题准备gitlab.rb 配置坑点一忘记root密码重置使用篇gitlab转换成中文git关闭注册入口创建用户部署篇 序言 在团队开发过程中&#xff0c;想要拥有高效的开发效率&#xff0c;选择一个好的代码开发工具是必不可少的…

JUnit5用户手册~并行执行

两种运行模式 SAME_THREAD&#xff1a;默认的&#xff0c;测试方法在同一个线程CONCURRENT&#xff1a;并行执行&#xff0c;除非有资源锁junit-platform.properties配置参数配置所有测试方法都并行 junit.jupiter.execution.parallel.enabled true junit.jupiter.execution.…

Kafka3.0.0版本——生产者分区及分区策略

目录一、生产者分区优点二、生产者发送消息的分区策略2.1、默认的分区器2.2、指定分区(partition)值2.3、没有指明分区(partition)值&#xff0c;但有key 的情况2.4、 既没有分区(partition)值&#xff0c;又没有key 值的情况三、指定分区(partition)值的代码示例四、没有指明分…

vscode折叠展开快捷键

1.折叠所有代码 (按住ctrl 分别点击k和0) ctrlk,ctrl0 2.展开所有代码 (按住ctrl 分别点击k和j) ctrlk,ctrlj 3. 折叠鼠标竖线所在位置的节点以及当前节点下的子节点&#xff08;递归折叠&#xff09; ctrlk,ctrl[ 4. 展开鼠标竖线所在位置的节点以及当前节点下的子节点&#…

OpenFeign 源码解读:动态代理+负载均衡实现

OpenFeign使用EnableFeignClients开启服务&#xff0c;该注解标有Import(FeignClientsRegistrar.class)&#xff0c;该ImportBeanDefinitionRegistrar会利用扫描路径的方式扫描java文件中带有的FeignClient(...)的接口&#xff0c;关于这种扫描注解的方式&#xff0c;我仿照写了…

软件测试 - 测试用例常见面试题

1.测试用例的要素测试用例是为了实施测试而向被测试的系统提供的一组集合, 这组集合包含 : 测试环境, 操作步骤, 测试数据, 预期结果等要素.例如 : 在 B 站输入框输入一个空格, 检查结果测试用例标题 : 输入框输入空格测试环境 : Windows 系统, 谷歌浏览器-版本 111.0.5563.65&…

固态硬盘需要分区吗 固态硬盘怎么分区

磁盘分区是在磁盘中划分几个逻辑部分&#xff0c;来更充分的利用磁盘空间&#xff0c;对保存的数据进行分类储存&#xff0c;方便使用。今天小编给大家介绍一下&#xff0c;固态硬盘需要分区吗&#xff0c;固态硬盘怎么分区。 一、固态硬盘需要分区吗 固态硬盘是需要分区的&a…

Redis:redis通用命令;redis常见数据结构;redis客户端;redis的序列化

一、redis命令 1.redis通用命令 Redis 通用命令是一些 Redis 下可以作用在常用数据结构上的常用命令和一些基础的命令 常见的命令有&#xff1a; keys 查看符合模板的所有key&#xff0c;不建议在生产环境设备上使用&#xff0c;因为keys会模式匹配所有符合条件的key&#…

js常见的9种报错记录一下

js常见报错语法错误(SyntaxError)类型错误(TypeError)引用错误(ReferenceError)范围错误(RangeError)运行时错误(RuntimeError)网络错误&#xff08;NetworkError&#xff09;内部错误&#xff08;InternalError&#xff09;URI错误&#xff08;URIError&#xff09;eval错误&a…

electron+vue3全家桶+vite项目搭建【五】集成Pinia全局状态管理

文章目录引入1.引入依赖2.集成Pinia3.使用pinia4.测试效果引入 在vue2的体系中&#xff0c;vuex是官方推荐的状态管理工具&#xff0c;而vue3的体系中&#xff0c;官网同样推荐了一款状态管理工具&#xff0c;他就是 Pinia Pinia官网 demo项目地址 1.引入依赖 npm install…

docker 安装运行 nacos2.0.3

目录 1、拉取镜像 2、挂载目录 mkdir -p /opt/nacos/logs/ #新建logs目录mkdir -p /opt/nacos/conf/ #新建配置目录vim /opt/nacos/conf/application.properties #修改配置文件 3、application.properties内容 4、初始化nacos的脚…

Vue的简单介绍

一、简介 Vue (发音为 /vjuː/&#xff0c;类似 view) 是一款用于构建用户界面的 JavaScript 框架。它基于标准 HTML、CSS 和 JavaScript 构建&#xff0c;并提供了一套声明式的、组件化的编程模型&#xff0c;帮助你高效地开发用户界面。无论是简单还是复杂的界面&#xff0c;…

生成式 AI 背后的共同框架:Stable Diffusion、DALL-E、Imagen

前言 如果你对这篇文章感兴趣&#xff0c;可以点击「【访客必读 - 指引页】一文囊括主页内所有高质量博客」&#xff0c;查看完整博客分类与对应链接。 框架 这些生成式 AI 的整体功能为&#xff1a;输入「文字」&#xff0c;返回「图像」&#xff0c;即 Text-to-image Gener…