2021-01-08

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 second    while (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 bar    var 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 section)  {   // An empty bitmap which will hold the cropped image   Bitmap bmp = new Bitmap(section.Width, section.Height);   //using (Bitmap bmp = new Bitmap(section.Width, section.Height))   {    Graphics g = Graphics.FromImage(bmp);    // Draw the given area (section) of the source image    // at location 0,0 on the empty bitmap (bmp)    g.DrawImage(source, 0, 0, section, 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)  {      //新的Template   var 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 second    while (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 bar    var 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 section)  {   // An empty bitmap which will hold the cropped image   Bitmap bmp = new Bitmap(section.Width, section.Height);   //using (Bitmap bmp = new Bitmap(section.Width, section.Height))   {    Graphics g = Graphics.FromImage(bmp);    // Draw the given area (section) of the source image    // at location 0,0 on the empty bitmap (bmp)    g.DrawImage(source, 0, 0, section, 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.shaoqun.com/a/506237.html

跨境电商:https://www.ikjzd.com/

周宁:https://www.ikjzd.com/w/1647

塔图:https://www.ikjzd.com/w/2274


背景最近再做一个需求,需要对网页生成预览图,如下图但是网页千千万,总不能一个个打开,截图吧;于是想着能不能使用代码来实现网页的截图。其实要实现这个功能,无非就是要么实现一个仿真浏览器,要么调用系统浏览器,再进行截图操作。代码实现1、启用线程ThreadvoidstartPrintScreen(ScreenShotParamrequestParam){Threadthread=newThread(n
丰趣海淘:丰趣海淘
new old stock:new old stock
蜈支洲岛门票 :蜈支洲岛门票
2020元宵节深圳热闹的地方?深圳世界之窗2020元宵节夜:2020元宵节深圳热闹的地方?深圳世界之窗2020元宵节夜
亚马逊广告又出新功能,支出管理全靠Portfolio:亚马逊广告又出新功能,支出管理全靠Portfolio

No comments:

Post a Comment