C#实现网页加载后将页面截取成长图片

背景

最近再做一个需求,需要对网页生成预览图,如下图

但是网页千千万,总不能一个个打开,截图吧;于是想着能不能使用代码来实现网页的截图。其实要实现这个功能,无非就是要么实现一个仿真浏览器,要么调用系统浏览器,再进行截图操作。

代码实现

1、启用线程Thread

 void startPrintScreen(ScreenShotParam requestParam){Thread thread = new Thread(new ParameterizedThreadStart(do_PrintScreen));thread.SetApartmentState(ApartmentState.STA);thread.Start(requestParam);if (requestParam.Wait){thread.Join();FileInfo result = new FileInfo(requestParam.SavePath);long minSize = 1 * 1024;// 太小可能是空白圖,重抓int maxRepeat = 2;                while ((!result.Exists || result.Length <= minSize) && maxRepeat > 0){thread = new Thread(new ParameterizedThreadStart(do_PrintScreen));thread.SetApartmentState(ApartmentState.STA);thread.Start(requestParam);thread.Join();maxRepeat--;}}}

2、模拟浏览器WebBrowser

   void do_PrintScreen(object param){try{ScreenShotParam screenShotParam = (ScreenShotParam)param;string requestUrl = screenShotParam.Url;string savePath = screenShotParam.SavePath;WebBrowser wb = new WebBrowser();wb.ScrollBarsEnabled = false;wb.ScriptErrorsSuppressed = true;wb.Navigate(requestUrl);logger.Debug("wb.Navigate");DateTime startTime = DateTime.Now;TimeSpan waitTime = new TimeSpan(0, 0, 0, 10, 0);// 10 secondwhile (wb.ReadyState != WebBrowserReadyState.Complete){Application.DoEvents();if (DateTime.Now - startTime > waitTime){wb.Dispose();logger.Debug("wb.Dispose() timeout");return;}}wb.Width = screenShotParam.Left + screenShotParam.Width + screenShotParam.Left; // wb.Document.Body.ScrollRectangle.Width (避掉左右側的邊線);wb.Height = screenShotParam.Top + screenShotParam.Height; // wb.Document.Body.ScrollRectangle.Height;wb.ScrollBarsEnabled = false;wb.Document.Body.Style = "overflow:hidden";//hide scroll barvar doc = (wb.Document.DomDocument) as mshtml.IHTMLDocument2;var style = doc.createStyleSheet("", 0);style.cssText = @"img { border-style: none; }";Bitmap bitmap = new Bitmap(wb.Width, wb.Height);wb.DrawToBitmap(bitmap, new Rectangle(0, 0, wb.Width, wb.Height));wb.Dispose();logger.Debug("wb.Dispose()");bitmap = CutImage(bitmap, new Rectangle(screenShotParam.Left, screenShotParam.Top, screenShotParam.Width, screenShotParam.Height));bool needResize = screenShotParam.Width > screenShotParam.ResizeMaxWidth || screenShotParam.Height > screenShotParam.ResizeMaxWidth;if (needResize){double greaterLength = bitmap.Width > bitmap.Height ? bitmap.Width : bitmap.Height;double ratio = screenShotParam.ResizeMaxWidth / greaterLength;bitmap = Resize(bitmap, ratio);}bitmap.Save(savePath, System.Drawing.Imaging.ImageFormat.Gif);bitmap.Dispose();logger.Debug("bitmap.Dispose();");logger.Debug("finish");}catch (Exception ex){logger.Info($"exception: {ex.Message}");}}

3、截图操作

  private static Bitmap CutImage(Bitmap source, Rectangle p){// An empty bitmap which will hold the cropped imageBitmap bmp = new Bitmap(p.Width, p.Height);//using (Bitmap bmp = new Bitmap(p.Width, p.Height)){Graphics g = Graphics.FromImage(bmp);// Draw the given area (p) of the source image// at location 0,0 on the empty bitmap (bmp)g.DrawImage(source, 0, 0, p, GraphicsUnit.Pixel);return bmp;}}private static Bitmap Resize(Bitmap originImage, Double times){int width = Convert.ToInt32(originImage.Width * times);int height = Convert.ToInt32(originImage.Height * times);return ResizeProcess(originImage, originImage.Width, originImage.Height, width, height);}

完整代码

  public static string ScreenShotAndSaveAmazonS3(string account, string locale, Guid rule_ID, Guid template_ID){//新的Templatevar url = string.Format("https://xxxx/public/previewtemplate?showTemplateName=0&locale={0}&inputTemplateId={1}&inputThemeId=&Account={2}",locale,template_ID,account);var tempPath = Tools.GetAppSetting("TempPath");//路徑準備var userPath = AmazonS3.GetS3UploadDirectory(account, locale, AmazonS3.S3SubFolder.Template);var fileName = string.Format("{0}.gif", template_ID);var fullFilePath = Path.Combine(userPath.LocalDirectoryPath, fileName);logger.Debug("userPath: {0}, fileName: {1}, fullFilePath: {2}, url:{3}", userPath, fileName, fullFilePath, url);//開始截圖,並暫存在本機var screen = new Screen();screen.ScreenShot(url, fullFilePath);//將截圖,儲存到 Amazon S3//var previewImageUrl = AmazonS3.UploadFile(fullFilePath, userPath.RemotePath + fileName);return string.Empty;}
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;namespace PrintScreen.Common
{public class Screen{protected static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();public void ScreenShot(string url, string path, int width = 400, int height = 300, int left = 50, int top = 50, int resizeMaxWidth = 200, int wait = 1){if (!string.IsNullOrEmpty(url) && !string.IsNullOrEmpty(path)){ScreenShotParam requestParam = new ScreenShotParam{Url = url,SavePath = path,Width = width,Height = height,Left = left,Top = top,ResizeMaxWidth = resizeMaxWidth,Wait = wait != 0};startPrintScreen(requestParam);}}void startPrintScreen(ScreenShotParam requestParam){Thread thread = new Thread(new ParameterizedThreadStart(do_PrintScreen));thread.SetApartmentState(ApartmentState.STA);thread.Start(requestParam);if (requestParam.Wait){thread.Join();FileInfo result = new FileInfo(requestParam.SavePath);long minSize = 1 * 1024;// 太小可能是空白圖,重抓int maxRepeat = 2;                while ((!result.Exists || result.Length <= minSize) && maxRepeat > 0){thread = new Thread(new ParameterizedThreadStart(do_PrintScreen));thread.SetApartmentState(ApartmentState.STA);thread.Start(requestParam);thread.Join();maxRepeat--;}}}void do_PrintScreen(object param){try{ScreenShotParam screenShotParam = (ScreenShotParam)param;string requestUrl = screenShotParam.Url;string savePath = screenShotParam.SavePath;WebBrowser wb = new WebBrowser();wb.ScrollBarsEnabled = false;wb.ScriptErrorsSuppressed = true;wb.Navigate(requestUrl);logger.Debug("wb.Navigate");DateTime startTime = DateTime.Now;TimeSpan waitTime = new TimeSpan(0, 0, 0, 10, 0);// 10 secondwhile (wb.ReadyState != WebBrowserReadyState.Complete){Application.DoEvents();if (DateTime.Now - startTime > waitTime){wb.Dispose();logger.Debug("wb.Dispose() timeout");return;}}wb.Width = screenShotParam.Left + screenShotParam.Width + screenShotParam.Left; // wb.Document.Body.ScrollRectangle.Width (避掉左右側的邊線);wb.Height = screenShotParam.Top + screenShotParam.Height; // wb.Document.Body.ScrollRectangle.Height;wb.ScrollBarsEnabled = false;wb.Document.Body.Style = "overflow:hidden";//hide scroll barvar doc = (wb.Document.DomDocument) as mshtml.IHTMLDocument2;var style = doc.createStyleSheet("", 0);style.cssText = @"img { border-style: none; }";Bitmap bitmap = new Bitmap(wb.Width, wb.Height);wb.DrawToBitmap(bitmap, new Rectangle(0, 0, wb.Width, wb.Height));wb.Dispose();logger.Debug("wb.Dispose()");bitmap = CutImage(bitmap, new Rectangle(screenShotParam.Left, screenShotParam.Top, screenShotParam.Width, screenShotParam.Height));bool needResize = screenShotParam.Width > screenShotParam.ResizeMaxWidth || screenShotParam.Height > screenShotParam.ResizeMaxWidth;if (needResize){double greaterLength = bitmap.Width > bitmap.Height ? bitmap.Width : bitmap.Height;double ratio = screenShotParam.ResizeMaxWidth / greaterLength;bitmap = Resize(bitmap, ratio);}bitmap.Save(savePath, System.Drawing.Imaging.ImageFormat.Gif);bitmap.Dispose();logger.Debug("bitmap.Dispose();");logger.Debug("finish");}catch (Exception ex){logger.Info($"exception: {ex.Message}");}}private static Bitmap CutImage(Bitmap source, Rectangle p){// An empty bitmap which will hold the cropped imageBitmap bmp = new Bitmap(p.Width, p.Height);//using (Bitmap bmp = new Bitmap(p.Width, p.Height)){Graphics g = Graphics.FromImage(bmp);// Draw the given area (p) of the source image// at location 0,0 on the empty bitmap (bmp)g.DrawImage(source, 0, 0, p, GraphicsUnit.Pixel);return bmp;}}private static Bitmap Resize(Bitmap originImage, Double times){int width = Convert.ToInt32(originImage.Width * times);int height = Convert.ToInt32(originImage.Height * times);return ResizeProcess(originImage, originImage.Width, originImage.Height, width, height);}private static Bitmap ResizeProcess(Bitmap originImage, int oriwidth, int oriheight, int width, int height){Bitmap resizedbitmap = new Bitmap(width, height);//using (Bitmap resizedbitmap = new Bitmap(width, height)){Graphics g = Graphics.FromImage(resizedbitmap);g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.High;g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;g.Clear(Color.Transparent);g.DrawImage(originImage, new Rectangle(0, 0, width, height), new Rectangle(0, 0, oriwidth, oriheight), GraphicsUnit.Pixel);return resizedbitmap;}}}class ScreenShotParam{public string Url { get; set; }public string SavePath { get; set; }public int Width { get; set; }public int Height { get; set; }public int Left { get; set; }public int Top { get; set; }/// <summary>/// 長邊縮到指定長度/// </summary>public int ResizeMaxWidth { get; set; }public bool Wait { get; set; }}}

效果

完成,达到预期的效果。

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

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

相关文章

“既然计划没有变化快,那制订计划还有个卵用啊!”

这是头哥侃码的第229篇原创每年年初&#xff0c;我的朋友圈里都会炸出不少在打完鸡血之后&#xff0c;迫不及待向全世界宣告自己 “新年Flag” 的人。有的人&#xff0c;把健身、养生设为目标&#xff0c;什么不暴瘦20斤不换头像呀&#xff0c;什么再也不吃炸鸡啤酒啦&#xff…

图书管理系统jsp代码_【程序源代码】使用Java开发的图书管理系统

关键字&#xff1a;java 管理系统 正文 | 内容01—【概述】使用Java开发的图书管理系统&#xff0c;读者可以注册登录&#xff0c;登录时会判断账号类型再分别跳到各自对应的页面&#xff0c;读者可以查找&#xff0c;借阅&#xff0c;还书&#xff0c;查看历史借阅记录&#x…

整合.NET WebAPI和 Vuejs——在.NET单体应用中使用 Vuejs 和 ElementUI

.NET简介.NET 是一种用于构建多种应用的免费开源开发平台&#xff0c;例如&#xff1a;Web 应用、Web API 和微服务云中的无服务器函数云原生应用移动应用桌面应用1). Windows WPF2). Windows 窗体3). 通用 Windows 平台 (UWP)游戏物联网 (IoT)机器学习控制台应用Windows 服务跨…

【gRPC】 在.Net core中使用gRPC

最近在学习.net core的微服务体系架构。微服务之间的通信常常通过gRPC进行同步通信&#xff0c;但是需要注意的是&#xff0c;大多数微服务之间的通信是通过事件总线进行异步通信。在微软介绍.net微服务体系架构的项目eShop中&#xff0c;微服务之间进行同步通信的场景很多&…

disconf mysql_Docker搭建disconf环境,三部曲之三:细说搭建过程

Docker下的disconf实战全文链接细说搭建过程在前两章中&#xff0c;我们利用远程或本地的镜像&#xff0c;快速体验了本地启动disconf的过程&#xff0c;本章我们一起来分析和梳理整个定制和搭建过程&#xff0c;了解这些后&#xff0c;我们就能根据自己的需要来定制本地的disc…

轻量级 Kubernetes K3s - Github热点

轻量级 Kubernetes k3sstar: 15.5kK3s是完全符合生产要求的Kubernetes发行版, 安装简单&#xff0c;可用于生产&#xff0c;整个二进制文件小于100M&#xff0c;作为单一文件打包部署&#xff0c;优势在于&#xff0c;你只需几秒钟就可以得到一个完全成熟的Kubernetes集群。htt…

java 固定长度队列_如何彻底搞懂 Java 数据结构?|CSDN 博文精选

作者 | 张振华.Jack责编 | 郭芮出品 | CSDN 博客本文和大家一起来重温《Java数据结构》经典之作。Java数据结构要理解Java数据结构&#xff0c;必须能清楚何为数据结构&#xff1f;数据结构&#xff1a;Data_Structure&#xff0c;它是储存数据的一种结构体&#xff0c;在此结构…

IdentityServer4 之 Resource Owner Password Credentials 其实有点尴尬

前言接着IdentityServer4的授权模式继续聊&#xff0c;这篇来说说 Resource Owner Password Credentials授权模式&#xff0c;这种模式在实际应用场景中使用的并不多&#xff0c;只怪其太开放啦&#xff0c;直接在客户端上拿着用户名和密码就去授权服务器获取AccessToken&#…

Xamarin使XRPC实现接口/委托远程调用

在之前的文章中已经介绍如何使用Beetlex.XRCP组件进行接口/委托远程调用&#xff1b;由于组件BeetleX.XRPC.Clients支持.NETStandard2&#xff0c;因此Xamarin同样可以使用它来实现基于接口/委托的数据交互通讯。接下来通过Xamarin实现一个简单的移动程序&#xff0c;并通过XRP…

mysql 拷贝安装_Mysql的安装和主从复制

安装mysql服务步骤一&#xff1a;首先下载mysql的yum源配置 &#xff0c;下载mysql的yum源wget http://dev.mysql.com/get/mysql57-community-release-el7-11.noarch.rpm步骤二&#xff1a;安装mysql的yum源yum -y install mysql57-community-release-el7-11.noarch.rpm步骤三&…

浅谈CLR基础知识

中午的时候&#xff0c;有一个小伙伴问我&#xff0c;CLR到底是进程还是线程&#xff0c;它和自己写的程序是怎么关联的。这一问&#xff0c;直接把我问懞了。下面我尝试用简单的语言来描述这个问题&#xff0c;有的地方无法讲的太细&#xff08;不然内容会太多&#xff09;&am…

Asp.Net Core使用Skywalking实现分布式链路追踪

介绍Skywalking 是 Apache 基金会下面的一个开源 APM 项目&#xff0c;是一套(APM)分布式追踪系统&#xff0c;提供了很多数据存储列如&#xff1a;Mysql&#xff0c;H2&#xff0c;Elasticsearch7 等。其中APM 全称是应用性能监测软件&#xff0c;主要是用来处理以及追踪分布式…

python 里什么时候缩进_python什么时候缩进

Python中的缩进(Indentation)决定了代码的作用域范围。这一点和传统的c/c有很大的不同(传统的c/c使用花括号花括号{}符决定作用域的范围&#xff1b;python使用缩进空格来表示作用域的范围&#xff0c;相同缩进行的代码是处于同一范围)。每行代码中开头的空格数(whitespace)用于…

C# 9 新特性 —— 补充篇

C# 9 新特性 —— 补充篇Intro前面我们分别介绍了一些 C# 9 中的新特性&#xff0c;还有一些我觉得需要了解一下的新特性&#xff0c;写一篇作为补充。Top-Level Statements在以往的代码里&#xff0c;一个应用程序必须要有 Main 方法才能运行&#xff0c;从 C# 9 开始&#xf…

使用Popup窗口创建无限级Web页菜单(5)

代码框架在(4)里面已经全部列出来了&#xff0c;现在工作就是按流程把他们完成。本来实现一个prototype的Menu菜单类只需要最多300行代码&#xff0c;可是后来做了一些操作习惯支持和UI显示上的优化后&#xff0c;代码猛增到了1000多行。不过final版本看起来确实比土不拉叽的pr…

【gRPC】ProtoBuf 语言快速学习指南

继上篇【gRPC】 在.Net core中使用gRPC了解了gRPC的使用&#xff0c;gRPC基于HTTP/2和ProtoBuf&#xff0c;ProtoBuf就非常有必要好好了解一下了&#xff0c;那么ProtoBuf究竟是什么&#xff1f;ProtoBuf Google Protocol Buffer是一种语言无关、平台无关、可扩展的序列化结构数…

vspythonqt混合_PYQT5 vscode联合操作qtdesigner的方法

除了使用pycharm外&#xff0c;还可使用vscode来操作pyqt&#xff0c;方法如下&#xff1a;1. 在vscode中配置相关的pyqt的相关根据自己实际情况修改第一项pyqt的路径2. 创建一个文件夹&#xff0c;右键&#xff0c;最后一项可以创建一个新窗口创建的新窗口后缀为 .ui右键中有以…

TIOBE 1 月榜单:Python年度语言四连冠,C 语言再次第一

喜欢就关注我们吧&#xff01;TIOBE 公布了 2021 年 1 月的编程语言排行榜。TIOBE 本月公布了 2020 年度编程语言&#xff0c;Python 获得四连冠&#xff0c;是过去一年中最受欢迎的编程语言。Python 在 2020 年实现了 2.01&#xff05; 的正增长&#xff1b;C 紧随其后&#x…

A piecture of J2EE Core Patterns

这张图是J2EE Core Patterns里面的一幅图片,在Enterprise Solution Patterns Using Microsoft.Net里面虽然模式的概念与应用大同小异&#xff0c;但是那张表现架构模式整体的图感觉有点不直观,相比之下这幅图显得更清晰一点。 发到这里供大家参考学习&#xff1a;&#xff09…

孙丕恕离开浪潮 仪器厂历时60年成为服务器龙头企业

2020年12月31日浪潮集团有限公司董事会选举邹庆忠为公司董事长&#xff08;法定代表人&#xff09;&#xff1b;孙丕恕不再担任公司董事长&#xff1b;公司不再聘任孙丕恕为首席执行官。另外&#xff0c;经省委研究决定&#xff0c;拟任省直部门&#xff08;单位&#xff09;副…