zoukankan      html  css  js  c++  java
  • CEF 自定义用户协议(scheme)实现以二进制流的方式显示图片、视频、音频

    转载:https://www.cnblogs.com/sinceret/p/10417941.html

    转载:https://stackoverflow.com/questions/48811756/registering-custom-backend-scheme-is-not-working-in-cef

    转载:https://www.twblogs.net/a/5c308e03bd9eee35b3a4d59a/zh-cn

    转载:http://www.voidcn.com/article/p-ffanxazs-bpp.html

    转载:https://magpcss.org/ceforum/viewtopic.php?f=6&t=13266

    转载:https://github.com/gabyx/ExecutionGraph/tree/3ff8b340d3ae1c87976104f0bbbda4c048e7eb2b(Github上Demo)

    转载:https://blog.csdn.net/ming19951224/article/details/81807159(解决思路参考)

    转载:https://blog.csdn.net/cdx1170776994/article/details/76571535

    转载:https://blog.csdn.net/zhangpeng_linux/article/details/85858814

    转载:https://www.cnblogs.com/himax/p/how_to_intercept_response_in_cef_using_csharp.html

    在谷歌浏览器中点击设置,地址栏里出现的不是普通网址,而是chrome://settings/,这个地址就是谷歌浏览器的自定义scheme,cef也提供了自定义协议手段。

    scheme就是一种协议,比如http://helloworld.com中的http就是scheme,不过它是内置的。client://helloworld.com中的client就是一个自定义scheme。

    当javascript通过XMLHttpRequest请求地址client://helloworld.com时,我们c++中实现的处理器,就会收到这个请求。

    XMLHttpRequest可以通过post方法将二进制数据如arraybuffer发送到browser进程。
    1.当javascript需要传递大量二进制数据给browser进程的c++代码时,可以使用POST方法,
    2.当javascript需要从browser进程的c++代码拿到大量二进制数据时,可以使用GET方法。

    1.CEF注册custom scheme 来接受http请求

     在cef中我们可以通过以下接口来注册scheme

    bool CefRegisterSchemeHandlerFactory(
        const CefString& scheme_name,
        const CefString& domain_name,
        CefRefPtr<CefSchemeHandlerFactory> factory);

    注册一个自定义http scheme

    CefRegisterSchemeHandlerFactory("http", "test", new MySchemeHandlerFactory());

    这个scheme限定了,scheme为"http",domain为"test",只有当请求为"http://test/"开头时,才会执行自定义c++代码。

    处理器工厂为MySchemeHandlerFactory,是我们自己实现的处理请求的c++代码。

    继承一个工厂类MySchemeHandlerFactory : public CefSchemeHandlerFactory 

    需要包含#include "include/cef_scheme.h"

     .h文件

    #ifndef _MYSCHEMEHANDLERFACTORY_H_
    #define _MYSCHEMEHANDLERFACTORY_H_
    #include "includecef_scheme.h"
    
    
    class MySchemeHandlerFactory : public CefSchemeHandlerFactory
    {
    public:
        virtual CefRefPtr<CefResourceHandler> Create(CefRefPtr<CefBrowser> browser,
            CefRefPtr<CefFrame> frame,
            const CefString& scheme_name,
            CefRefPtr<CefRequest> request)
            OVERRIDE;// Return a new resource handler instance to handle the request.
            
        
    private:
        IMPLEMENT_REFCOUNTING(MySchemeHandlerFactory);
    };
    
    
    
    #endif //_MYSCHEMEHANDLERFACTORY_H_

    .cpp文件

    #include "MySchemeHandlerFactory.h"
    #include "MyResourceHandler.h"
    #include "include/cef_parser.h"
    #include "include/wrapper/cef_helpers.h"
    #include "include/wrapper/cef_stream_resource_handler.h"
    #include <shlwapi.h> 
    #pragma comment(lib, "shlwapi.lib")
    
    CefRefPtr<CefResourceHandler> MySchemeHandlerFactory::Create(CefRefPtr<CefBrowser> browser, 
        CefRefPtr<CefFrame> frame, 
        const CefString& scheme_name, 
        CefRefPtr<CefRequest> request)
    {
        CEF_REQUIRE_IO_THREAD();
    
        CefString url = request->GetURL();
        cef_uri_unescape_rule_t unescape_rule = UU_SPACES;//处理路径中有空格
        CefString& decoded_value = CefURIDecode(url, true, unescape_rule);
    
        CefURLParts urlParts;
        if (CefParseURL(url, urlParts))
        {
            std::wstring filePath = CefURIDecode(CefString(&urlParts.query),true,unescape_rule);//处理有中文路径
            CefRefPtr<CefStreamReader> fileStream = CefStreamReader::CreateForFile(CefString(filePath));
    
            if (fileStream != nullptr)
            {
                // "ext" 获取扩展名 例如:"txt"、"jpg"
                std::wstring ext;
                ext = PathFindExtension(filePath.c_str());
                ext =ext.substr(1, ext.length());
                CefString mimeType(CefGetMimeType(ext));
                //todo: Complete known mime times with web-font extensions
                if (mimeType.empty())
                {
                    //mimeType = "font/" + fileExtension;
                }
    
                return CefRefPtr<CefStreamResourceHandler>(new CefStreamResourceHandler(mimeType, fileStream));//以二进制流的方式把文件返给js并显示到html标签中
            }
        }
    
        return new MyResourceHandler();
    }

    2.继承一个资源类class MyResourceHandler : public CefResourceHandler

    ProcessRequest 处理请求,允许请求返回true;取消请求返回false。当需要返回的数据就绪后(自行请求网络或者文件就绪)或立即调用callback.Continue(),通知cef进入下一步:GetResponseHeaders。

    GetResponseHeaders 设置响应头,在这里可以设置mime-type,响应长度,其它头等。不确定长度设置响应长度为-1。

    ReadResponse 设置响应结果。可以设置响应具体内容,设置已读取长度。cef调用完上一步后会继续调用此方法。根据响应长度和数据就绪情况,调用此方法的次数和策略不同。

    当响应长度为-1时,cef无法根据已读长度确定是否已读取完毕,必需根据返回值false来结束读取。

    当响应长度大于0时,cef根据每次调用得到的已读长度,或返回值false来结束读取。

    如果数据未就绪,可以设置读取长度为0 ,返回true,并在稍后调用callbak.Continue()通知cef调用此方法读取响应内容。

    注意:

    当响应长度为-1时,必需保证此方法至少执行两次,第一次返回true表示数据全部就绪,第二次返回false表示读取结束。

    当响应长度大于0时,设置内容和已读长度,返回true。则此方法只执行一次。

    若实际返回的响应内容,长度大于之前设置的响应总长度,则返回内容将被截取。

    #ifndef _MYRESOURCEHANDLER_H_
    #define _MYRESOURCEHANDLER_H_
    #include <fstream>
    #include <stdio.h>
    #include "includecef_resource_handler.h"
    
    class MyResourceHandler : public CefResourceHandler
    {
    public:
        MyResourceHandler();
    
        virtual bool ProcessRequest(CefRefPtr<CefRequest> request,
            CefRefPtr<CefCallback> callback)OVERRIDE;
    
        virtual void GetResponseHeaders(CefRefPtr<CefResponse> response,
            int64& response_length,
            CefString& redirectUrl) OVERRIDE;
    
        virtual void Cancel() OVERRIDE{
            // Cancel the response...
        }
    
        virtual bool ReadResponse(void* data_out,
            int bytes_to_read,
            int& bytes_read,
            CefRefPtr<CefCallback> callback)
            OVERRIDE;
    
        virtual bool CanGetCookie(const CefCookie& cookie);
        
    
        virtual bool CanSetCookie(const CefCookie& cookie);
        
    private:
        std::string data_;
        IMPLEMENT_REFCOUNTING(MyResourceHandler);
    };
    #endif//_MYRESOURCEHANDLER_H_

    .cpp文件

    #include "MyResourceHandler.h"
    
    MyResourceHandler::MyResourceHandler()
    {
    
    }
    
    
    bool MyResourceHandler::ProcessRequest(CefRefPtr<CefRequest> request,
        CefRefPtr<CefCallback> callback)
        {
        std::string url = request->GetURL();
        
        data_ = "hello cef";//返回到页面中的内容
        callback->Continue();//这个一定要有
        return true;//
    }
    
    void MyResourceHandler::GetResponseHeaders(CefRefPtr<CefResponse> response,
        int64& response_length,
        CefString& redirectUrl) {
    
        response->SetMimeType("text/plain");
        response->SetStatus(200);
        response_length = data_.length();
    }
    
    
    bool MyResourceHandler::ReadResponse(void* data_out,
        int bytes_to_read,
        int& bytes_read,
        CefRefPtr<CefCallback> callback)
        {
        int size = static_cast<int>(data_.length());
        memcpy(data_out, data_.c_str(), size);
        bytes_read = size;
        return true;
    }
    
    bool MyResourceHandler::CanGetCookie(const CefCookie& cookie)
    {
        return false;
    }
    
    bool MyResourceHandler::CanSetCookie(const CefCookie& cookie)
    {
        return false;
    }

    3.在初始化cef那几行代码后面增加一句

    CefRegisterSchemeHandlerFactory("http", "test", new MySchemeHandlerFactory());
    CefSettings cSettings;
        const char* loc = "zh-CN";
    
        cSettings.no_sandbox = true;
        cSettings.multi_threaded_message_loop = true;
        //cSettings.single_process = false;
        cSettings.log_severity = LOGSEVERITY_DISABLE;//设置日志级别,解决安装启动佰卓数安后桌面出现一个debug.log文件(调试阶段可以去掉)
        CefString(&cSettings.locale).FromASCII(loc);
        cef_string_from_ascii(loc, strlen(loc), &cSettings.locale);
    
        // Execute the secondary process, if any.
        CefInitialize(main_args, cSettings, spApp.get(), sandbox_info);
        /***************************************结束初始化cef*******************************************/
        //自定义scheme    
        CefRegisterSchemeHandlerFactory("http", "test", new MySchemeHandlerFactory());

    4.CEF浏览器加载的静态html

     <html>
    <script>
    function do_post()
    {
       //alert('posting');
       var xhr  = new XMLHttpRequest();
       var zurl = "http://test?C:\Users\Administrator\Desktop\梅西.jpg";
       xhr.open("GET", zurl, true);
       xhr.responseType = 'blob';
       xhr.onload = function()
       {
        //console.log(this);
        if (this.status == 200) 
        {
            var blob = this.response;
            var img = document.createElement("img");
            img.onload = function(e) {
                window.URL.revokeObjectURL(img.src); 
            };
            //alert(blob);
            img.src = window.URL.createObjectURL(blob);
            document.body.appendChild(img); 
        }
       }
       xhr.send();
       //alert('posted');
    }
    
    function do_video()
    {
       //alert('posting');
       var xhr  = new XMLHttpRequest();
       var zurl = "http://test?C:\Users\Administrator\Desktop\稻香.mp4";
       xhr.open("GET", zurl, true);
       xhr.responseType = 'blob';
       xhr.onload = function()
       {
        //console.log(this);
        if (this.status == 200) 
        {
            var blob = this.response;
            var video = document.querySelector("video");
            //alert(window.URL.createObjectURL(blob));
            video.src = window.URL.createObjectURL(blob);
      
        }
       }
       xhr.send();
       //alert('posted');
    }
    
    function do_audio()
    {
       //alert('posting');
       var xhr  = new XMLHttpRequest();
       var zurl = "http://test?C:\Users\Administrator\Desktop\千年等一回.mp3";
       xhr.open("GET", zurl, true);
       xhr.responseType = 'blob';
       xhr.onload = function()
       {
        //console.log(this);
        if (this.status == 200) 
        {
            var blob = this.response;
            var audio = document.querySelector("audio");
            //alert(window.URL.createObjectURL(blob));
            audio.src = window.URL.createObjectURL(blob);
      
        }
       }
       xhr.send();
       //alert('posted');
    }
    
    </script>
    <body onLoad="">
    <div>
    <!-- <img src="图片路径、地址" alt="" /> -->
    <input type="button" value="加载图片" onclick="do_post()">
    <input type="button" value="加载视频" onclick="do_video();">
    <input type="button" value="加载音频" onclick="do_audio();">
    </div>
    <video controls="true" ></video> 
    <audio controls="true" ></audio>
    <p>Hello everyone!
    </p>
    </body>
    </html>

  • 相关阅读:
    HackerRank savita-and-friends
    HackerRank training-the-army
    51Nod 1378 夹克老爷的愤怒
    51Nod 1380 夹克老爷的逢三抽一
    Codeforces 566 D. Restructuring Company
    BZOJ 2822: [AHOI2012]树屋阶梯
    Codeforces Gym 101138 G. LCM-er
    51Nod 1250 排列与交换
    BZOJ 1511: [POI2006]OKR-Periods of Words
    BZOJ 1355: [Baltic2009]Radio Transmission
  • 原文地址:https://www.cnblogs.com/chechen/p/10578556.html
Copyright © 2011-2022 走看看