精华内容
下载资源
问答
  • 浏览器实现滚动截屏

    千次阅读 2020-12-03 11:08:11
    首先拿到这个需求的时候,想了一下,实现滚动截屏并不难,难的具体的情况如下, 在IE浏览器的情况下,在前端实现,并且iframe是跨域的,还要自动上传服务器,万事开头难,尝试了HTML2canvas之后发现,它并不能解决...

    工作日志:实现浏览器滚动截屏,并且是指定的iframe在跨域的情况下。

    首先拿到这个需求的时候,想了一下,实现滚动截屏并不难,难的具体的情况如下,
    在IE浏览器的情况下,在前端实现,并且iframe是跨域的,还要自动上传服务器,万事开头难,尝试了HTML2canvas之后发现,它并不能解决跨域问题,而且不同浏览器其图片会有差异,并且最重要的一点,svg图在IE浏览器中截图是空白。
    当然,遇到需求,一定要解决,研究了IE设计接口,终于实现了,整体的思路是,拿到浏览器的接口对象,使用递归遍历,找到指定的iframe,拿到iframe对象,滚动每一屏,拼接起来,最后产生的是一个长图,并且是高清位图,高清的位图占的控件大小非常大,所以使用压缩算法将其大小进行了30倍的压缩。
    压缩后的图片大概在100k-500k之间,那么怎么上传呢,这个比较简单了,在内存里直接使用base64编码图片,将字符串传至服务器当中,服务器拿到字符串可以进行转码存储,至于前端显示,可以把图片直接io传输显示,也可以转base64直接由img标签进行解析。
    既然思路有了,那就说说具体的实现,首先,采用任意编程语言,创建一个浏览器插件工程,这里,我采用studio,首先,捕获IE浏览器窗口句柄,这个十分简单,调用原生api就可以,代码如下:
    BSTR CshotScreenCtrl::shotScreen(void)
    {
    POINT pNow = { 0,0 };
    BSTR base64Data = L"";

    if (GetCursorPos(&pNow))  // 获取鼠标当前位置
    {
    	pNow.x = pNow.x+200 ;
    	pNow.y = pNow.y+200;
    	HWND hwndPointNow = NULL;
    
    	hwndPointNow = WindowFromPoint(pNow)->m_hWnd;  // 获取鼠标所在窗口的句柄
    	if (hwndPointNow)
    	{
    		 string data = GetIHTMLDocument2Interface(hwndPointNow);
    		 CString str = (CA2W)(data.c_str());
    		 base64Data = str.AllocSysString();
    	}
    }
    return base64Data;
    

    }
    GetIHTMLDocument2Interface是获取对应的父窗体的接口对象方法,
    string GetIHTMLDocument2Interface(HWND BrowserWnd)
    {
    string data;
    CoInitialize(NULL);

    HRESULT hr;
    
    // Explicitly load MSAA so we know if it's installed
    HINSTANCE hInst = ::LoadLibrary(_T("OLEACC.DLL"));
    if (hInst)
    {
    	LRESULT lRes; //SendMessageTimeout后的返回值,用于函数pfObjectFromLresult的第1个参数
    	UINT nMsg = ::RegisterWindowMessage(_T("WM_HTML_GETOBJECT"));
    	::SendMessageTimeout(BrowserWnd, nMsg, 0L, 0L, SMTO_ABORTIFHUNG, 1000, (DWORD*)&lRes);
    
    	//获取函数pfObjectFromLresult
    	LPFNOBJECTFROMLRESULT pfObjectFromLresult = (LPFNOBJECTFROMLRESULT)::GetProcAddress(hInst, "ObjectFromLresult");
    	if (pfObjectFromLresult)
    	{
    		CComQIPtr<IHTMLDocument2> spDoc;
    		hr = (*pfObjectFromLresult)(lRes, IID_IHTMLDocument, 0, (void**)&spDoc);
    		if (SUCCEEDED(hr))
    		{
    			//获取文档接口
    			CComPtr<IDispatch> spDisp;
    			spDoc->get_Script(&spDisp);
    			CComQIPtr<IHTMLWindow2> spWin = spDisp;
    	
    			spWin->get_document(&spDoc.p);
    
    			//  Change background color to red
    			//spDoc->put_bgColor(CComVariant("red"));
    			CComQIPtr<IHTMLWindow2> window;
    			spDoc->get_parentWindow(&window);
    			RECT rect;
    			::GetWindowRect(BrowserWnd, &rect);
    			int nWidth = rect.right - rect.left;
    			int nHeigth = rect.bottom - rect.top;
    			//尝试获取iframe的窗体
    			CComQIPtr<IHTMLElement> fBody;
    			spDoc->get_body(&fBody);
    			CComQIPtr<IHTMLFrameBase2> fBase;
    			EnumFrame(spDoc, rect);
    
    			//CaptureToImage(spDoc,rect, BrowserWnd,"C://tempImg//tmp.png");
    			CompressImageQuality(L"C://tempImg//tmp.png", L"C://tempImg//tmpcompress.jpg", 50);
    
    			ReadPhotoFile(L"C://tempImg//tmpcompress.jpg",data);
    
    		} // else document not ready
    	} // else Internet Explorer is not running
    	::FreeLibrary(hInst);
    } // else Active Accessibility is not installed
    
    CoUninitialize();
    return data;
    

    }
    虽然找到了父窗体的接口,但是这里不能直接拿iframe的,因为我们现在是跨域,浏览器可不会让你这么简单的跨域,毕竟如果强行跨域,那你就可以强行跨站脚本攻击了,但是道理是死的,人是活的,我们换种方法,既然我们调用拿的方法拿不到,那我们就自己取找,把父窗口转成容器接口,枚举递归遍历每一个实现的iwebborwser接口的对象,直到找到名字为我们要的那个iframe为止,代码如下:
    void EnumFrame(IHTMLDocument2* pHTML,RECT rect)
    {
    CComQIPtr spContainer(pHTML);
    if (spContainer)
    {
    CComPtr spEnumerator; // 注:参数OLECONTF_EMBEDDINGS // 表示列举容器内的所有嵌入对象

    	HRESULT hr = spContainer->EnumObjects(OLECONTF_EMBEDDINGS, &spEnumerator);
    	if (spEnumerator)
    	{
    		CComPtr<IUnknown> spUnk;
    		while (spEnumerator->Next(1, &spUnk, NULL) == S_OK)
    		{
    			CComQIPtr<IWebBrowser2, &IID_IWebBrowser2> spWB(spUnk);
    			spUnk = NULL;
    			if (spWB)
    			{   
    
    				CComPtr<IDispatch> spDocDisp;
    				hr = spWB->get_Document(&spDocDisp);
    				CComQIPtr<IHTMLDocument2> spHTML(spDocDisp);
    
    				CComQIPtr<IHTMLElement> sBody;
    				spHTML->get_body(&sBody);
    				long sScrollHeight = 0L;
    				CComQIPtr<IHTMLElement2> pBodyElem2(sBody);
    				pBodyElem2->get_scrollHeight(&sScrollHeight);
    
    				CComPtr<IHTMLWindow2> pWnd2;
    				S_OK == spHTML->get_parentWindow(&pWnd2);
    				BSTR frameName;
    				pWnd2->get_name(&frameName);
    				string str1 = (_bstr_t)frameName;
    
    				if ("childIframe" == str1) {
    					long width = 0L;
    					long height = 0L;
    					spWB->get_Width(&width);
    					spWB->get_Height(&height);
    					CaptureToImage(spHTML, rect, NULL, "C://tempImg//tmp.png");
    					break;
    				}else {
    					EnumFrame(spHTML, rect);
    				}
    
    			}
    		}
    	}
    }
    

    }
    到了这里,我们已经拿到iframe,也就是我们要截图的窗体,那么接下来只要调用scrollto,并且计算坐标偏移就可以了,原理十分的简单,至于后面的代码,十分简单,就不贴出来了,到了这一步,我们已经可以跨域拿到iframe里的任何东西啦,想怎么操作就怎么操作,至于压缩算法还有转base64上传的代码百度满天飞,如果你有什么不懂,可以私信,附一张效果图吧。
    在这里插入图片描述

    展开全文
  • python实现滚动截屏功能

    千次阅读 2020-04-10 16:02:47
    不同于移动端的滚动截屏,pc端浏览器之外是不能获得准确的鼠标滚动距离的(或者有我不知道的方法),要实现滚动截屏就不是那么容易了; 现在网上也有一些可以滚动截屏的软件(像FSCapture、qq截屏),...

    本文对应GitHub项目地址

    之前写了像微信一样的区域截屏功能,中提到,我的小工具集里面有滚动截屏的功能,这篇文章将讨论一下具体的实现和公布源码。。。

    实现思路类似某乎上一个关于滚动截屏实现的回答

    不同于移动端的滚动截屏,pc端浏览器之外是不能获得准确的鼠标滚动距离的(或者有我不知道的方法),要实现滚动截屏就不是那么容易了;

    现在网上也有一些可以滚动截屏的软件(像FSCapture、qq截屏),实现方法应该也是先截屏然后根据图片元素拼接的。本文的方法虽有拼接出错的情况,但是能用哇。。h,源码全长四百多行。。。由于是直接从我的小工具集里面整合出来的,有些地方会显得不太合理,当作学习就好,具体思路都差不多

    源码

    import math
    import operator
    import os
    import sys
    import time
    from functools import reduce
    
    from PIL import Image
    from PyQt5.QtCore import QThread, QTimer
    from PyQt5.QtWidgets import QApplication
    from pynput import mouse
    from pynput.mouse import Controller as MouseController
    
    
    class Splicing_shots(object):
        def __init__(self):
            self.init_splicing_shots_thread = Commen_Thread(self.init_splicing_shots)
            self.init_splicing_shots_thread.start()
            self.clear_timer = QTimer()
            self.clear_timer.timeout.connect(self.setup)
    
        def init_splicing_shots(self):
            """后台初始化"""
            self.img = []
            self.img_list = []
            self.images_data_line_list = []
            self.img_width = 0
            self.img_height = 0
            self.compare_row = 50
            self.cut_width = 0
            self.rate = 0.85
            self.roll_speed = 5
            self.min_head = 0
            self.left_border = 0
            self.right_border = 0
            self.head_pos = {}
            self.maybe_errorlist = []
            self.in_rolling = False
            self.arrange = 0
            self.max_arrange = 999
            if not os.path.exists("j_temp"):
                os.mkdir("j_temp")
    
        def setup(self):
            """清理&初始化"""
            if self.clear_timer.isActive():
                self.clear_timer.stop()
                print('clear')
            self.img = []
            self.img_list = []
            self.images_data_line_list = []
            self.img_width = 0
            self.img_height = 0
            self.compare_row = 50
            self.cut_width = 0
            self.rate = 0.85
            self.roll_speed = 3
            self.min_head = 0
            self.left_border = 0
            self.right_border = 0
            self.head_pos = {}
            self.maybe_errorlist = []
            self.in_rolling = False
            self.arrange = 0
            self.max_arrange = 999
            self.clear_timer = QTimer()
            self.clear_timer.timeout.connect(self.setup)
    
        def find_left_side(self):
            """寻找相同的左边界"""
            images_data_list = []
            for img in self.img_list[:2]:
                rotate_img = img.rotate(270, expand=1)
                rotate_img_data = list(rotate_img.convert('L').getdata())
                an_imgdata = []
                for line in range(rotate_img.height - 1):
                    an_imgdata.append(rotate_img_data[line * rotate_img.width:(line + 1) * rotate_img.width])
                images_data_list.append(an_imgdata)
            rotate_height = len(images_data_list[0])
            min_head = rotate_height
            for i in range(1):
                for j in range(1, rotate_height):
                    img1 = images_data_list[i][:j]
                    img2 = images_data_list[i + 1][:j]
                    if img2 != img1:
                        if j == 1:
                            print('没有重复左边界!')
                            return
                        elif j < (min_head + 1):
                            min_head = j - 1
                        break
            self.left_border = min_head
            print('minleft', min_head)
    
        def find_right_size(self):
            """寻找相同的右边界"""
            images_data_list = []
            for img in self.img_list[:2]:
                rotate_img = img.rotate(90, expand=1)
                rotate_img_data = list(rotate_img.convert('L').getdata())
                an_imgdata = []
                for line in range(rotate_img.height - 1):
                    an_imgdata.append(rotate_img_data[line * rotate_img.width:(line + 1) * rotate_img.width])
                images_data_list.append(an_imgdata)
            rotate_height = len(images_data_list[0])
            min_head = rotate_height
            for i in range(1):
                for j in range(1, rotate_height):
                    img1 = images_data_list[i][:j]
                    img2 = images_data_list[i + 1][:j]
                    # print(img2)
                    if img2 != img1:
                        if j == 1:
                            print('没有重复右边界!')
                            self.right_border = self.img_width
                            # print(self.majority_color(self.images_data_line_list[0]))
                            return
                        elif j < (min_head + 1):
                            min_head = j - 1
                        break
            self.right_border = self.img_width - min_head
            print('minright', min_head)
    
        def find_the_same_head_to_remove(self):
            """寻找相同的头部(上边界)"""
            # if self.images_data
            min_head = self.img_height
            for i in range(len(self.img_list) - 1):
                for j in range(1, self.img_height):
                    img1 = self.images_data_line_list[i][:j]
                    img2 = self.images_data_line_list[i + 1][:j]
                    # print(img2)
                    if img2 != img1:
                        if j == 1:
                            print('没有重复头!')
                            # print(self.majority_color(self.images_data_line_list[0]))
                            return
                        elif j < (min_head + 1):
                            min_head = j - 1
                        break
            self.min_head = min_head
            print('minhead', min_head)
    
        def majority_color(self, classList):
            '''返回颜色列表中最多的颜色'''
            count_dict = {}
            for label in classList:
                if label not in count_dict.keys():
                    count_dict[label] = 0
                count_dict[label] += 1
            # print(max(zip(count_dict.values(), count_dict.keys())))
            return max(zip(count_dict.values(), count_dict.keys()))
    
        def isthesameline(self, line1, line2):
            """判断是否两行是否相同"""
            same = 0
            rate = self.rate
            line1_majority_color = self.majority_color(line1)
            line2_majority_color = self.majority_color(line2)
    
            if line2_majority_color[1] != line1_majority_color[1]:
                # print(self.majority_color(line2),self.majority_color(line1))
                return 0
            elif abs(line1_majority_color[0] - line2_majority_color[0]) > self.img_width * (1 - rate) * 0.5:
                return 0
            else:
                majority_color_count, majority_color = line2_majority_color
                # print(majority_color_count,majority_color)
            if majority_color_count > int(self.cut_width * rate):
                return 1
    
            for i in range(self.cut_width):
                if line1[i] == majority_color or line2[i] == majority_color:
                    # print('maj')
                    continue
                else:
                    if abs(line1[i] - line2[i]) < 10:
                        same += 1
            if same >= (self.cut_width - majority_color_count) * rate:
                return 1
            else:
                return 0
    
        def efind_the_pos(self):
            """在滚动的同时后台寻找拼接点"""
            while self.in_rolling or self.arrange < self.max_arrange:  # 如果正在截屏或截屏没有处理完
                print(self.arrange, '  max:', self.max_arrange)
                min_head = self.min_head
                left = self.left_border
                right = self.right_border
                self.cut_width = right - left
                images_data_line_list = self.images_data_line_list
                compare_row = self.compare_row
                i = self.arrange
                try:
                    img1 = images_data_line_list[i]  # 前一张图片
                    img2 = images_data_line_list[i + 1]  # 后一张图片
                except IndexError:
                    time.sleep(0.1)  # 图片索引超出则等待下一张截屏
                    continue
                max_line = [0, 0]
                for k in range(min_head, self.img_height - compare_row):  # 前一张图片从相同头部开始遍历到最后倒数compare_row行
                    if self.in_rolling:  # 如果正在截屏则sleep一下避免过多占用主线程,也没什么用...
                        time.sleep(0.001)
                    sameline = 0
                    chance_count = 0
                    chance = 0
                    for j in range(min_head, min_head + compare_row):  # 后一张图片从相同头部开始逐行遍历compare_row行
                        lin1 = img1[k + sameline][left:right]
                        lin2 = img2[min_head + sameline][left:right]
                        if self.isthesameline(lin1, lin2):  # 如果是行相同,则sameline+1
                            sameline += 1
                            chance_count += 1
                            if chance_count >= 7:  # 每7行增加一个chance,避免误判
                                chance_count = 0
                                chance += 1
                            if sameline > max_line[1]:
                                max_line[0] = k
                                max_line[1] = sameline  # 记录最大行数备用
                        else:  # 否则chance-1直到退出
                            if chance <= 0:
                                break
                            else:
                                chance -= 1
                                sameline += 1
    
                    if sameline >= compare_row - compare_row // 20:
                        self.head_pos[i] = k
                        print(i, k)
                        print(self.head_pos)
                        break
                if i not in self.head_pos.keys():#如果没有找到符合的拼接点,则取最大的配合点,并标记为可能出错的地方
                    if max_line[1] >= 1:
                        self.head_pos[i] = max_line[0]
                        print(self.head_pos)
                        max_line.append(i)
                        self.maybe_errorlist.append(max_line)
                        print('max_line', i, max_line)  # 测试
                self.arrange += 1
    
        def find_the_pos(self):#和上面的efind_the_pos类似
            """寻找拼接点,当图片数少时可以直接截完屏调用"""
            min_head = self.min_head
            left = self.left_border
            right = self.right_border
            self.cut_width = right - left
            images_data_line_list = self.images_data_line_list
            compare_row = self.compare_row
            # print(min_head, self.img_height - compare_row)
            for i in range(len(self.img_list) - 1):
                # print(i)
                img1 = images_data_line_list[i]
                img2 = images_data_line_list[i + 1]
                max_line = [0, 0]  # 测试
                for k in range(min_head, self.img_height - compare_row):
                    sameline = 0
                    chance_count = 0
                    chance = 0
                    for j in range(min_head, min_head + compare_row):
                        lin1 = img1[k + sameline][left:right]
                        lin2 = img2[min_head + sameline][left:right]
                        # print(len(lin2),len(lin1))
                        res = self.isthesameline(lin1, lin2)
                        if res:
                            sameline += 1
                            chance_count += 1
                            if chance_count >= 5:
                                chance_count = 0
                                chance += 1
                            if sameline > max_line[1]:
                                max_line[0] = k
                                max_line[1] = sameline  # 测试
                            # print(i, j, k)
                        else:
                            # print(chance)
                            if chance <= 0:
                                break
                            else:
                                chance -= 1
                                sameline += 1
    
                    if sameline >= compare_row - compare_row // 20:
                        self.head_pos[i] = k
                        print(i, k)
                        print(self.head_pos)
                        break
                if i not in self.head_pos.keys():
                    if max_line[1] >= 1:
                        self.head_pos[i] = max_line[0]
                        print(self.head_pos)
                        max_line.append(i)
                        self.maybe_errorlist.append(max_line)
                        print('max_line', i, max_line)  # 测试
    
        def merge_all(self):
            """根据拼接点拼接所有图片"""
            majority_pos = self.majority_color(self.head_pos.values())
            for i in range(len(self.img_list) - 1):
                if i not in self.head_pos.keys():
                    self.head_pos[i] = majority_pos[1]
                    print(i, '丢失,补', majority_pos)  # 丢失则补为图片拼接点的众数,虽然没有什么用...
            img_width = self.img_width
            img_height = 0
            # head_pos = []
            # for i in len(self.head_pos)
            for i in self.head_pos.keys():
                img_height += self.head_pos[i] - self.min_head
                # print(img_height)
            img_height += self.img_height  # 加最后一张
            newpic = Image.new(self.img_list[0].mode, (img_width, img_height))
            height = 0
            if self.min_head:
                height += self.min_head
                newpic.paste(self.img_list[0].crop((0, 0, img_width, self.min_head)), (0, 0))
            for i in range(len(self.img_list) - 1):
                if self.min_head:
                    newpic.paste(self.img_list[i].crop((0, self.min_head, self.img_width, self.head_pos[i])),
                                 (0, height))
                    height += self.head_pos[i] - self.min_head
                else:
                    newpic.paste(self.img_list[i].crop((0, self.min_head, self.img_width, self.head_pos[i])),
                                 (0, height))
                    height += self.head_pos[i]
            if self.min_head:
                newpic.paste(self.img_list[-1].crop((0, self.min_head, img_width, img_height)), (0, height))
            else:
                newpic.paste(self.img_list[-1], (0, height))
            # name = str(time.strftime("%Y-%m-%d_%H.%M.%S", time.localtime()))
            newpic.save('j_temp/jam_outputfile.png')
            print('saved in j_temp/jam_outputfile.png')
    
        def is_same(self, img1, img2):
            """简单判断两幅图片是否相同,用于停止滚动截屏,速度非常快!"""
            h1 = img1.histogram()
            h2 = img2.histogram()
            result = math.sqrt(reduce(operator.add, list(map(lambda a, b: (a - b) ** 2, h1, h2))) / len(h1))
            if result <= 5:
                return True
            else:
                return False
    
        def auto_roll(self, area):
            """自动滚动截屏,总函数"""
            x, y, w, h = area
            self.img_width = w
            self.img_height = h
            speed = round(1 / self.roll_speed, 2)
            screen = QApplication.primaryScreen()
            controler = MouseController()
            find_left = Commen_Thread(self.find_left_side)
            find_right = Commen_Thread(self.find_right_size)
            find_head = Commen_Thread(self.find_the_same_head_to_remove)
            find_pos = Commen_Thread(self.efind_the_pos)
            threads = [find_left, find_pos, find_right, find_head]
            self.in_rolling = True
            i = 0
            img_height = 0
            controler.position = (area[0] + int(area[2] / 2), area[1] + int(area[3] / 2))
            while self.in_rolling:
                pix = screen.grabWindow(QApplication.desktop().winId(), x, y, w, h)  # 区域截屏获取图像pixmap
                img = Image.fromqpixmap(pix)  # 将qt的pixmap转为pil模块的img对象
                self.img_list.append(img)  # 储存图片的列表
                img_data = list(img.convert('L').getdata())  # 图片灰度化,并把灰度值转为列表
                an_img_line_data = []
                for line in range(h):
                    an_img_line_data.append(img_data[line * w:(line + 1) * w])  # 列表分行储存
                self.images_data_line_list.append(an_img_line_data)
                if i >= 1:
                    if self.is_same(self.img_list[i - 1], self.img_list[i]):  # 每帧检查是否停止(图片是否相同)
                        self.in_rolling = False
                        i += 1
                        break
                    if img_height == 0:  # 图片有两张以上后,启动线程寻找图片边界点
                        img_height = 1
                        find_head.start()
                        find_left.start()
                        find_right.start()
                    if i == 5:  # 图片大于5张才开始寻找拼接点
                        find_pos.start()
                controler.scroll(dx=0, dy=-3)  # 滚动屏幕
                time.sleep(speed)  # 速度控制
                # img.save('j_temp/{0}.png'.format(i))
                i += 1
            print('图片数', i)
            self.max_arrange = i - 1  # 获取图片序列用于控制寻找边界点的结束
            for thread in threads:  # 遍历并等待各线程结束
                thread.wait()
                # print(thread)
            if i <= 2:
                print('过短!一张图还不如直接截呐')
                self.clear_timer.start(0)
                return
            elif i <= 5:
                self.find_the_pos()  # 图片小于5张则截完屏在拼接
            else:
                find_pos.wait()  # 等待拼接点寻找完成
            # self.find_the_pos()
            print('found_pos_done')
            # try:
            self.merge_all()  # 调用图片拼接函数
            # except:
            #     print('拼接出错错误!请重新截屏!')
            #     self.clear_timer.start(10000)
            #     return
            print('可能错误的地方:', self.maybe_errorlist)
            self.clear_timer.start(10000)  # 10s后初始化内存
    
    
    def listen():
        """鼠标监听,截屏中当按下鼠标停止截屏"""
        global listener
        print("listen")
    
        def on_click(x, y, button, pressed):
            if button == mouse.Button.left:
                if roller.in_rolling:
                    roller.in_rolling = False
    
        listener = mouse.Listener(on_click=on_click)
        listener.start()
    
    
    class Commen_Thread(QThread):
        """造的轮子...可用于多线程中不同参数的输入"""
        def __init__(self, action, *args):
            super(QThread, self).__init__()
            self.action = action
            self.args = args
            # print(self.args)
    
        def run(self):
            print('start_thread')
            if self.args:
                if len(self.args) == 1:
                    self.action(self.args[0])
                    print(self.args[0])
                elif len(self.args) == 2:
                    self.action(self.args[0], self.args[1])
            else:
                self.action()
    
    
    if __name__ == '__main__':
        app = QApplication(sys.argv)
        roller = Splicing_shots()
        listen()
        roller.auto_roll((350, 50, 800, 700))#注意选好区域,边界区域过大可能会拼接失败;不能滚动的时候会立即停止!
        sys.exit(app.exec_())
    
    

    具体思路

    前面已经说了,实现滚动截屏的步骤:滚动–>截屏–>寻找拼接点–>拼接

    滚动

    滚动部分主要用了pynput模块的滚动功能,该模块还可以实现全局快捷键,具体方法本文不深究。

    截屏

    由于我的小工具集是采用pyqt作为界面的,就直接用qt的截屏方法了,可以自行改为pil或win32的截屏方法
    截屏中止(滚动中止)采用了双重判定,当前后两张图片相同(到了尽头)时可以自动停止,当按下鼠标左键时也会停止

    寻找拼接点

    寻找拼接点就是比较相邻的图片,寻找下一张图片在前一张图片的相同部分的位置,并记录下来。
    但考虑到有些截屏区域是包含不滚动部分的,即所有图片都有相同的头部或边框,所以截取的图片就不能直接用来寻找拼接点,需要比较多张图片并去除相同部分的影响;
    所以这一部分又可以分几步:把图片灰度化(不然就要比较rgb3个通道,处理时间大大增加)–>把图片的灰度值储存于数组中–>比较前n张图片并找出所有相同的边界点(上、左、右,下由于拼接的时候会覆盖掉就不用识别了)–>排除相同的部分开始寻找拼接的界限(逐行比较)

    更具体的实现已经在代码中标明了,仔细看注释应该可以看懂,可以根据需要改动代码,例如可以完全去除qt库(这个库是真的大!)

    听说还可以用opencv实现图片拼接功能(而且效率upup的),等我研究一下再来改蛤


    忘了回来更新了…
    opencv实现的滚动截屏方法,比暴力拼接不知道快到哪里去了…自行查看
    https://github.com/fandesfyf/roll_screenshot

    本文对应GitHub项目地址开源万岁!
    作者Fandes,转载请标明出处,其实不标明我也不知道…

    展开全文
  • 利用chrome浏览器实现滚动截屏

    千次阅读 2020-04-15 20:08:05
    不知道怎么在浏览器上滚动截屏,搜索之后找到解决方法,在此记录一下。

    不知道怎么在浏览器上滚动截屏,搜索之后找到解决方法,在此记录一下。

    打开Chrome浏览器,进入需要截图的网站页面,加载完毕之后:

    场景一:截取整个页面

    1.打开开发者工具(在页面的任何地方点击鼠标右键,在弹出菜单中选择“检查”选项或者使用快捷键组合:Alt + Command+ I (Mac) 或 Ctrl + Shift + I (Windows))
    2.打开命令行(快捷键组合:Command + Shift + P(Mac) 或 Ctrl + Shift + P (Windows))
    3.在命令行中输入“Screen”,点击“Capture full size screenshot”
    如下图所示:
    在这里插入图片描述

    场景二: 截取页面中的某些元素

    1.打开开发者工具(在页面的任何地方点击鼠标右键,在弹出菜单中选择“检查”选项或者使用快捷键组合:Alt + Command+ I (Mac) 或 Ctrl + Shift + I (Windows))
    2.点击开发者工具左上角的“选取元素”按钮,在网页中点击要截图的元素
    3.打开命令行(快捷键组合:Command + Shift + P(Mac) 或 Ctrl + Shift + P (Windows))
    4.在命令行中输入“Screen”,点击“Capture node screenshot”,即可截取相应元素
    在这里插入图片描述在这里插入图片描述

    展开全文
  • 一、前言  我们平时在浏览网页时,想把碰到好的网页内容或者文章截屏保存,但是网页的长度常常会超出屏幕高度,一般的截屏功能只能截取显示在... 1、选择Chrome浏览器,打开需要截图的网页;  2、页面加载完...

    一、前言

        我们平时在浏览网页时,想把碰到好的网页内容或者文章截屏保存,但是网页的长度常常会超出屏幕高度,一般的截屏功能只能截取显示在屏幕上的内容,那我们该如何方便快捷截取全部内容?今天就分享一个如何利用Chrome浏览器在不安装第三方软件的情况下直接截取网页的方法。

    二、如何利用Chrome浏览器截屏

        1、选择Chrome浏览器,打开需要截图的网页;

        2、页面加载完成后,按下快捷键组合 Ctrl+Shift+I(Windows)/F12 或者 Alt+Command+I(Mac)调出开发者工具,具体如下图所示:

        3、开发者工具中,按下快捷键组合Ctrl+Shift +P(Windows) 或 Command+Shift+P(Mac)来打开命令行,具体如下图所示:

        4、在命令行中输入"Screen",可以看到三个选项,根据不同需求进行选择,具体如下图所示:

        ◆ 整个网页:Capture full size screenshot

        ◆ 节点网页:Capture node screenshot

        ◆ 当前屏幕:Capture screenshot

    三、应用

        1、截取整个网页的内容,进行截屏(Capture full size screenshot)

        2、选择需要的元素节点,进行截屏(Capture node screenshot)

        3、根据当前当前屏幕的大小,进行截屏(Capture screenshot)

    四、总结

        如果你想在网页中截取手机的画面截,可通过快速键 Ctrl + Shift + M(Mac为 Command + Shift + M)来开启模拟工具,切换 iPhone、iPad、Nexus、Galaxy 等装置开启网页的显示情形,再根据上面介绍的截图功能抓取网页在手机显示的画面截图,具体如图所示:

        利用Chrome浏览的开发者工具,完美实现网页全屏截图,不需要安装任何插件,大家快来试试吧。

        ① Ctrl+Shift+I(F12)

        ② Ctrl+Shift+P

        ③ 输入"Screen"

        ④ 选择不用的方式截取:

            ▶ 整个网页(Capture full size screenshot

            ▶ 节点网页(Capture node screenshot

            ▶ 当前屏幕(Capture screenshot

    展开全文
  • 找一个使用java对浏览器进行滚动截屏的方法,可我收了好久也没找到合适的方法,望高人指点
  • Mac 自带的截屏功能只能截取显示在屏幕上的内容,但是网页长度常常会超出屏幕高度,只依靠这个截图软件无法实现一次性的截取整个网页。 对这个问题,最简单粗暴的方法是手动滑动页面来截取多个图片,根据图片顺序...
  • 执行压缩包中的 FSCapture.exe 即可
  • 调出开发者工具:单击右键➡️选择检查 ➡️开发者工具中,按下快捷键组合Ctrl+Shift +P(Windows)或Command+Shift+P(Mac)来打开命令行 ➡️在命令行中输入"Screen",可以看到三个选项,根据不同需求进行选择 ...
  • Chrome浏览器实现滚动截图

    千次阅读 2019-06-21 19:12:07
    打开浏览器,进入需要截图的网页,按F12或者Fn+F12,显示如下图所示 按下Ctrl+Shift +P,输入screen,如图 整个网页:Capture full size screenshot 节点网页:Capture node screenshot 当前屏幕:Capture ...
  •  /// 滚动的方式截取页面中指定的元素如:Div的整个元素截屏  ///  ///  /// 指定需要截屏的元素,例如:document.getElementsByClassName('gridster dashboard-main ready')[0]  ///  publi
  • 相信很多开发者在开发手机端项目的时候,会在浏览器按照不同机型打开查看效果,可是截图只能截取可视区的图片,我想截全屏网页内容怎么办呢?我看很多百度出来的都是说下载安装插件什么的,觉得很麻烦,跟我来,简单...
  • 一、前言 我们平时在浏览网页时,想把碰到好的网页内容或者文章截屏保存,但是网页的长度常常会超出屏幕高度,一般的截屏功能只能截取显示在屏幕上的内容,那... 1、选择Chrome浏览器,打开需要截图的网页; 2、...
  • 一、前言 我们平时在浏览网页时,想把碰到好的网页内容或者文章截屏保存,但是网页的长度常常会超出屏幕高度,一般的截屏功能只能截取显示在屏幕上的内容,那... 1、选择Chrome浏览器,打开需要截图的网页; 2...
  • 选中截屏范围 标题 打开浏览命令输入窗口 标题 输入命令,选择第二项 截图整个网页 标题 最终显示效果(我这里选择的百度,网页没有超出一个屏的长度,不管页面有多长都可以全部截到) 标题标题 ....
  • 主要为大家详细介绍了Android WebView实现网页滚动截图,对整个网页进行截屏,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
  • 地址:http://download.csdn.net/detail/laoziyueguo3/6912911public static BitmapgetBitmapByView(ScrollView scrollView) {int h = 0;Bitmap bitmap = null;// 获取listView实际高度for (int i = 0;...
  • 滚动截屏软件

    2018-08-03 11:40:06
    该软件可实现滚动截图,简单易用,免安装,双击即可使用
  • 今天皮皮丘给大家介绍一款比较火热的iOS长截图神器,大家都知道,iOS系统是没有自带的长截图软件的,只能在Safari...滚动截屏应用的名字叫「滚动截屏」,但这个App的长截图功能是内置收费的,不过没关系,皮皮丘给...
  • Windows滚动截屏软件

    2021-03-23 16:56:22
    能够在windows上实现滚动截屏,解决你的屏幕分辨率不足的问题,让小分辨率也能截屏出大的图片,非常实用有效的工具。
  • 主要介绍了Selenium基于PIL实现拼接滚动截图,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
  • 如题,当网页实际高度大于浏览器显示高度的时候,怎么实现截取整个网页的功能。
  • 如何实现网页版滚动截图

    千次阅读 2019-04-22 14:44:19
    如何实现网页版滚动截图 不是长截图,只截图当前页面的话使用QQ截图(Ctrl+Shift+a)微信截图(Alt+a)即可 方法一 工具:浏览器即可 按键盘上的F12按键,打开浏览器的console菜单 接着,按组合键Ctrl+...
  • Android长截屏(滚动截屏)实现原理

    万次阅读 2015-09-24 01:07:50
    好在国内主流手机厂商均已实现了该功能,接下来聊聊我们长截屏实现原理. 长截屏原理概述: 我们简单的把一个屏幕分成三分,上中下,中间区域最大,中间区域也就是滑动区域;长截屏开始,我们截取顶部的图片保存到集合中...
  • 电脑,滚动截屏软件

    千次阅读 2018-04-30 11:33:11
    先来软件:链接:https://pan.baidu.com/s/1Iy2Vx_y9HgyK_12gHn6DQg 密码:jjck1、解压该软件2、运行该软件双击FSCapture.exe...将鼠标移到矩形框内,点击左键,然后滚动滚轮,就可以实现滚动截屏了。(按照提示来)...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 18,287
精华内容 7,314
关键字:

怎么实现滚动截屏