|
|
Comments and Discussions
|
|
 |

|
it is not working properly in IE 8
|
|
|
|
|
|
|

|
This is excellent Post, can you please let me know whether same thing is possible for other browsers like firefox and chrome etc
|
|
|
|

|
All of a sudden, the code just stopped working properly. The resulting image is the proper height, but instead of giving the entire web page as an image, it just gives the first screen full, with the balance of the image height being black.
While stepping through the code, it appears that myDoc.body.setAttribute("scrollTop", (screenHeight - 5) * i, 0); just stopped working. The IE window does not visibly scroll around the way it used to.
This just started happening after I installed an update to Adobe Flash and/or Reader (I did both of them, so don't know which one caused the problem).
Does anybody have an idea why that would stop working?
Thanks...
|
|
|
|

|
Can anyone explain the black picture issue? Has it been solved? I tried various settings of percentages with no luck. Thanks...
|
|
|
|

|
Hi Douglas,
Great article! one question though... Can this be used in a ASP page or only WinForms ?
Thanks,
|
|
|
|

|
Hi guys, running this app i only get black pics, in size of the web page (e.g. at google and so on...)
IE6
iwan
|
|
|
|

|
//Get Browser Window Height
int heightsize = (int)myDoc.body.getAttribute("scrollHeight", 0);
int widthsize = (int)myDoc.body.getAttribute("scrollWidth", 0);
//Get Screen Height
int screenHeight = (int)myDoc.body.getAttribute("clientHeight", 0);
int screenWidth = (int)myDoc.body.getAttribute("clientWidth", 0);
in the above code heightsize =screenHeight and widthsize =screenWidth
I am using IE8. Beacuse of this, the code doesn't recognize the scroll bars. only a part of the webpage is created as a image.
modified on Wednesday, March 9, 2011 5:10 AM
|
|
|
|
|

|
i use the code in a web page.It runs my localhost but in server i get error.My server is windows server 2003 ,iis 6.0.
i get the following error in the row :
SHDocVw.ShellWindows shellWindows = new SHDocVw.ShellWindowsClass();
Error:
Retrieving the COM class factory for component with CLSID {9BA05972-F6A8-11CF-A442-00A0C90A8F39} failed due to the following error: 80070002.
|
|
|
|

|
I'm trying to use the code in WatiN to capture IE9, but only get black images. Any ideas?
Cheers,
Daaron
|
|
|
|

|
IE9 seems to have broken at least some aspects of the MSHTML API for Ie9. Is there any documentation or information available about the API?
|
|
|
|

|
Hi all,
I have used this code in my application to capture the image of the web page. It works fine in IE6, IE7 and IE8. But in IE 9 beta I am getting blank image. Kindly anybody help me to solve this problem.
Thank you,
Jyoti
|
|
|
|

|
Excellent, its very usefull.. Thanks for posting.Uma S
|
|
|
|

|
Implemented the code in WPF and after calling it via a timer to refresh the page I can say I am leaking memory. So if you have any ideas on how to catch this leak please let me know.
Thanks,
|
|
|
|
|

|
Cool code Douglas, it's helped me a lot.
However I've found a way to do the same kind of thing just using the .NET web browser control instead of the ActiveX references:
I just use the PrintWindow reference and then the following code will get back the image of the web browser document:
Bitmap myImage = new Bitmap(this.picBack.Width, this.picBack.Height, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
using (Graphics g = Graphics.FromImage(myImage))
{
IntPtr hdc = g.GetHdc();
PrintWindow(mWebBrowserMain.Handle, hdc, 0);
g.ReleaseHdc(hdc);
g.Flush();
this.picBack.Image = myImage;
}
|
|
|
|

|
When i run this project. It is giving me image but image is whole black and webpage is something different
|
|
|
|

|
Thanks Douglas, this article is very helpful. But I have a question need suggestions: how can we make the same with Firefox (if can, this project will be very powerful)?
Any suggestion is appreciate.
Regards,
Danh.
|
|
|
|

|
Helpful,
Thank you.
|
|
|
|

|
Wow!
Let me say this, this was the most amazing and fun filled article i found on code project.
I hope the comments section comes back to life, so that the article can get more improvements.
If anyone is there reading this, i would like to know is there a way to determine whether the IE is minimized or not, so that instead of getting a black image, the app can just show a message, like maximize IE to get a screen shot.
I would once again like to thank the author Douglas M.Weems for such a beautiful article.
|
|
|
|

|
I see lots of this code around which calls Print or PrintWindow to a Bitmap based HDC. Is it possible to get an enhanced metafile from a WebBrowser object with vector contents. So far all I'm able to get is a BitBlt record wrapped in an EMF using OleDraw or IViewObject::Draw.
-Jason
|
|
|
|

|
Hi,
Thanks for the code! I was able to successfully do a screen shot of my browser window. However this seems to identical to User32.GetDesktopWindow() that I had also used. I dont want anything but the actual browser window (just like ALT+PrintScreen) Is there a way to modify variables/function parameters or use a different dll function to just capture the window without anything else in background? Please advise, thanks so much!
|
|
|
|

|
as title, always got the same value which equals the client height and width.
cannot scroll:
http://www.google.com/mail
http://www.google.com/reader
can be scrolled:
http://www.google.com/nwshp?tab=mn
http://www.google.com/calendar/render?tab=oc
Do you have any idea?
|
|
|
|

|
There is a vertical line on the picture if browser window has horizontal scrollbar.
|
|
|
|

|
Copy These Lines to Form1.cs ...
/* ---------------------------------------------------------------------------
*
* Copyright (c) Doug Weems.
*
* You may use this code for fun and knowledge.
* You can compile and use the application as is or copy out what you need.
* This code makes for a really useful tool.
*
* ---------------------------------------------------------------------------
*/
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Text;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.IO;
using System.Drawing.Imaging;
using SHDocVw;
using mshtml;
namespace IEWindowCapture
{
/// <summary>
/// This is the working code for "IE Complete Web Window Image Capture". IECWWIC for short.
/// Just kidding. Call it, "WebPageToImage".
/// This tool will pick up one open IE window and capture the entire web page to a single jpeg.
/// It is best if you only are running the IE instance that you are interested in.
/// The quality and size of the image can be adjusted and standard resolution screen sizes and web page name
/// can be added to the image.
/// Author: Doug Weems
/// </summary>
public class frmMain : System.Windows.Forms.Form
{
private System.Windows.Forms.GroupBox grpWebCapture;
private System.Windows.Forms.LinkLabel lnkOpenCapture;
private System.Windows.Forms.CheckBox chkShowGuides;
private System.Windows.Forms.GroupBox groupBox1;
private System.Windows.Forms.ComboBox cmbResolution;
private System.Windows.Forms.Label lblResolution;
private System.Windows.Forms.Label lblQuality;
private System.Windows.Forms.ComboBox cmbQuality;
private System.Windows.Forms.CheckBox chkWriteURL;
private System.Windows.Forms.Button button1;
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.Container components = null;
public frmMain()
{
InitializeComponent();
}
/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
System.Resources.ResourceManager resources = new System.Resources.ResourceManager(typeof(frmMain));
this.grpWebCapture = new System.Windows.Forms.GroupBox();
this.lnkOpenCapture = new System.Windows.Forms.LinkLabel();
this.chkShowGuides = new System.Windows.Forms.CheckBox();
this.groupBox1 = new System.Windows.Forms.GroupBox();
this.cmbResolution = new System.Windows.Forms.ComboBox();
this.lblResolution = new System.Windows.Forms.Label();
this.lblQuality = new System.Windows.Forms.Label();
this.cmbQuality = new System.Windows.Forms.ComboBox();
this.chkWriteURL = new System.Windows.Forms.CheckBox();
this.button1 = new System.Windows.Forms.Button();
this.grpWebCapture.SuspendLayout();
this.groupBox1.SuspendLayout();
this.SuspendLayout();
//
// grpWebCapture
//
this.grpWebCapture.Controls.Add(this.lnkOpenCapture);
this.grpWebCapture.Controls.Add(this.chkShowGuides);
this.grpWebCapture.Controls.Add(this.groupBox1);
this.grpWebCapture.Controls.Add(this.chkWriteURL);
this.grpWebCapture.Controls.Add(this.button1);
this.grpWebCapture.Location = new System.Drawing.Point(28, 12);
this.grpWebCapture.Name = "grpWebCapture";
this.grpWebCapture.Size = new System.Drawing.Size(256, 208);
this.grpWebCapture.TabIndex = 41;
this.grpWebCapture.TabStop = false;
this.grpWebCapture.Text = "Capture Web Page";
//
// lnkOpenCapture
//
this.lnkOpenCapture.Location = new System.Drawing.Point(16, 136);
this.lnkOpenCapture.Name = "lnkOpenCapture";
this.lnkOpenCapture.Size = new System.Drawing.Size(128, 16);
this.lnkOpenCapture.TabIndex = 36;
this.lnkOpenCapture.TabStop = true;
this.lnkOpenCapture.Text = "Open Capture Directory";
this.lnkOpenCapture.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.lnkOpenCapture_LinkClicked);
//
// chkShowGuides
//
this.chkShowGuides.Location = new System.Drawing.Point(16, 112);
this.chkShowGuides.Name = "chkShowGuides";
this.chkShowGuides.Size = new System.Drawing.Size(200, 16);
this.chkShowGuides.TabIndex = 34;
this.chkShowGuides.Text = "draw Standard Resolution Guides";
//
// groupBox1
//
this.groupBox1.Controls.Add(this.cmbResolution);
this.groupBox1.Controls.Add(this.lblResolution);
this.groupBox1.Controls.Add(this.lblQuality);
this.groupBox1.Controls.Add(this.cmbQuality);
this.groupBox1.ForeColor = System.Drawing.Color.Black;
this.groupBox1.Location = new System.Drawing.Point(16, 16);
this.groupBox1.Name = "groupBox1";
this.groupBox1.Size = new System.Drawing.Size(200, 80);
this.groupBox1.TabIndex = 39;
this.groupBox1.TabStop = false;
this.groupBox1.Text = "Reduce File Size by reducing Quality and/or Resolution";
//
// cmbResolution
//
this.cmbResolution.Items.AddRange(new object[] {
"100",
"90",
"80",
"70",
"60",
"50",
"40"});
this.cmbResolution.Location = new System.Drawing.Point(120, 32);
this.cmbResolution.Name = "cmbResolution";
this.cmbResolution.Size = new System.Drawing.Size(48, 21);
this.cmbResolution.TabIndex = 31;
this.cmbResolution.Text = "90";
//
// lblResolution
//
this.lblResolution.Location = new System.Drawing.Point(24, 32);
this.lblResolution.Name = "lblResolution";
this.lblResolution.Size = new System.Drawing.Size(88, 16);
this.lblResolution.TabIndex = 35;
this.lblResolution.Text = "% Capture Size";
this.lblResolution.TextAlign = System.Drawing.ContentAlignment.TopRight;
//
// lblQuality
//
this.lblQuality.Location = new System.Drawing.Point(24, 56);
this.lblQuality.Name = "lblQuality";
this.lblQuality.Size = new System.Drawing.Size(88, 16);
this.lblQuality.TabIndex = 38;
this.lblQuality.Text = "Quality";
this.lblQuality.TextAlign = System.Drawing.ContentAlignment.TopRight;
//
// cmbQuality
//
this.cmbQuality.Items.AddRange(new object[] {
"100",
"90",
"80",
"70",
"50",
"30",
"10"});
this.cmbQuality.Location = new System.Drawing.Point(120, 56);
this.cmbQuality.Name = "cmbQuality";
this.cmbQuality.Size = new System.Drawing.Size(48, 21);
this.cmbQuality.TabIndex = 37;
this.cmbQuality.Text = "70";
//
// chkWriteURL
//
this.chkWriteURL.Location = new System.Drawing.Point(16, 96);
this.chkWriteURL.Name = "chkWriteURL";
this.chkWriteURL.Size = new System.Drawing.Size(176, 16);
this.chkWriteURL.TabIndex = 32;
this.chkWriteURL.Text = "write URL name on Image";
//
// button1
//
this.button1.Cursor = System.Windows.Forms.Cursors.Hand;
this.button1.ForeColor = System.Drawing.Color.White;
this.button1.Image = ((System.Drawing.Image)(resources.GetObject("button1.Image")));
this.button1.Location = new System.Drawing.Point(176, 144);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(48, 40);
this.button1.TabIndex = 29;
this.button1.TextAlign = System.Drawing.ContentAlignment.TopCenter;
this.button1.Click += new System.EventHandler(this.button1_Click);
//
// frmMain
//
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(304, 238);
this.Controls.Add(this.grpWebCapture);
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
this.Name = "frmMain";
this.Text = "Capture";
this.grpWebCapture.ResumeLayout(false);
this.groupBox1.ResumeLayout(false);
this.ResumeLayout(false);
}
#endregion
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.Run(new frmMain());
}
//We need some system dll functions.
[DllImport("user32.dll", CharSet=CharSet.Auto)]
public static extern IntPtr FindWindowEx(IntPtr parent /*HWND*/, IntPtr next /*HWND*/, string sClassName, IntPtr sWindowTitle);
[DllImport("user32.dll", ExactSpelling=true, CharSet=CharSet.Auto)]
public static extern IntPtr GetWindow(IntPtr hWnd, int uCmd);
[DllImport("user32.Dll")]
public static extern void GetClassName(int h, StringBuilder s, int nMaxCount);
[DllImport("user32.dll")]
private static extern bool PrintWindow(IntPtr hwnd, IntPtr hdcBlt, uint nFlags);
public const int GW_CHILD = 5;
public const int GW_HWNDNEXT = 2;
int heightsize;
int widthsize;
int screenHeight;
int screenWidth;
public bool IsDTDDocument(object document)
{
// XHtml declare flag string
string DocTypeContent = @"-//W3C//DTD";
mshtml.IHTMLDocument3 document3 = (mshtml.IHTMLDocument3)document;
mshtml.IHTMLDOMChildrenCollection domChilds = (mshtml.IHTMLDOMChildrenCollection)document3.childNodes;
mshtml.IHTMLDOMNode domNode = (mshtml.IHTMLDOMNode)domChilds.item(0);
return domNode.nodeValue.ToString().Contains(DocTypeContent);
}
private void button1_Click(object sender, System.EventArgs e)
{
//TODO In Next Version:
//Add cursor capture
//Add file naming option
//Add visible screen capture
//Make captured image a DDB not a DIB bitmap.
Cursor.Current = Cursors.WaitCursor;
SHDocVw.WebBrowser m_browser = null;
SHDocVw.ShellWindows shellWindows = new SHDocVw.ShellWindowsClass();
//Find first availble browser window.
//Application can easily be modified to loop through and capture all open windows.
string filename;
foreach (SHDocVw.WebBrowser ie in shellWindows)
{
filename = Path.GetFileNameWithoutExtension(ie.FullName).ToLower();
if (filename.Equals("iexplore"))
{
m_browser = ie;
break;
}
}
if (m_browser == null)
{
MessageBox.Show("No Browser Open");
return;
}
//Assign Browser Document
mshtml.IHTMLDocument2 myDoc = (mshtml.IHTMLDocument2)m_browser.Document;
mshtml.IHTMLDocument3 doc3 = (mshtml.IHTMLDocument3)myDoc;
//URL Location
string myLocalLink = myDoc.url;
int URLExtraHeight = 0;
int URLExtraLeft = 0;
//Adjustment variable for capture size.
if (chkWriteURL.Checked == true)
URLExtraHeight = 25;
//TrimHeight and TrimLeft trims off some captured IE graphics.
int trimHeight = 3;
int trimLeft = 3;
//Use UrlExtra height to carry trimHeight.
URLExtraHeight = URLExtraHeight - trimHeight;
URLExtraLeft = URLExtraLeft - trimLeft;
if (!IsDTDDocument(myDoc))
{
myDoc.body.setAttribute("scroll", "yes", 0);
//Get Browser Window Height
heightsize = (int)myDoc.body.getAttribute("scrollHeight", 0);
widthsize = (int)myDoc.body.getAttribute("scrollWidth", 0);
//Get Screen Height
screenHeight = (int)myDoc.body.getAttribute("clientHeight", 0);
screenWidth = (int)myDoc.body.getAttribute("clientWidth", 0);
}
else
{
doc3.documentElement.setAttribute("scroll", "Yes", 0);
//Get Browser Window Height
heightsize = (int)doc3.documentElement.getAttribute("scrollHeight", 0);
widthsize = (int)doc3.documentElement.getAttribute("scrollWidth", 0);
//Get Screen Height
screenHeight = (int)doc3.documentElement.getAttribute("clientHeight", 0);
screenWidth = (int)doc3.documentElement.getAttribute("clientWidth", 0);
}
//Get bitmap to hold screen fragment.
Bitmap bm = new Bitmap(screenWidth, screenHeight, System.Drawing.Imaging.PixelFormat.Format16bppRgb555);
//Create a target bitmap to draw into.
Bitmap bm2 = new Bitmap(widthsize + URLExtraLeft, heightsize + URLExtraHeight - trimHeight, System.Drawing.Imaging.PixelFormat.Format16bppRgb555);
Graphics g2 = Graphics.FromImage(bm2);
Graphics g = null;
IntPtr hdc;
Image screenfrag = null;
int brwTop = 0;
int brwLeft = 0;
int myPage = 0;
IntPtr myIntptr = (IntPtr)m_browser.HWND;
//Get inner browser window.
int hwndInt = myIntptr.ToInt32();
IntPtr hwnd = myIntptr;
hwnd = GetWindow(hwnd, GW_CHILD);
StringBuilder sbc = new StringBuilder(256);
//Get Browser "Document" Handle
while (hwndInt != 0) {
hwndInt = hwnd.ToInt32();
GetClassName(hwndInt, sbc, 256);
if(sbc.ToString().IndexOf("Shell DocObject View", 0) > -1) //IE6
{
hwnd = FindWindowEx(hwnd, IntPtr.Zero, "Internet Explorer_Server", IntPtr.Zero);
break;
}
if (sbc.ToString().IndexOf("TabWindowClass", 0) > -1) //IE7
{
hwnd = FindWindowEx(hwnd, IntPtr.Zero, "Shell DocObject View", IntPtr.Zero);
hwnd = FindWindowEx(hwnd, IntPtr.Zero, "Internet Explorer_Server", IntPtr.Zero);
break;
}
if (sbc.ToString().IndexOf("Frame Tab", 0) > -1) // IE8
{
hwnd = FindWindowEx(hwnd, IntPtr.Zero, "TabWindowClass", IntPtr.Zero);
hwnd = FindWindowEx(hwnd, IntPtr.Zero, "Shell DocObject View", IntPtr.Zero);
hwnd = FindWindowEx(hwnd, IntPtr.Zero, "Internet Explorer_Server", IntPtr.Zero);
break;
}
hwnd = GetWindow(hwnd, GW_HWNDNEXT);
}
//Get Screen Height (for bottom up screen drawing)
while ((myPage * screenHeight) < heightsize)
{
if (!IsDTDDocument(myDoc))
myDoc.body.setAttribute("scrollTop", (screenHeight - 5) * myPage, 0);
else
doc3.documentElement.setAttribute("scrollTop", (screenHeight - 5) * myPage, 0);
++myPage;
}
//Rollback the page count by one
--myPage;
int myPageWidth = 0;
while ((myPageWidth * screenWidth) < widthsize)
{
if (!IsDTDDocument(myDoc))
myDoc.body.setAttribute("scrollLeft", (screenWidth - 5) * myPageWidth, 0);
else
doc3.documentElement.setAttribute("scrollLeft", (screenWidth - 5) * myPageWidth, 0);
if (!IsDTDDocument(myDoc))
brwLeft = (int)myDoc.body.getAttribute("scrollLeft", 0);
else
brwLeft = (int)doc3.documentElement.getAttribute("scrollLeft", 0);
for (int i = myPage; i >= 0; --i)
{
//Shoot visible window
g = Graphics.FromImage(bm);
hdc = g.GetHdc();
if (!IsDTDDocument(myDoc))
myDoc.body.setAttribute("scrollTop", (screenHeight - 5) * i, 0);
else
doc3.documentElement.setAttribute("scrollTop", (screenHeight - 5) * i, 0);
if (!IsDTDDocument(myDoc))
brwTop = (int)myDoc.body.getAttribute("scrollTop", 0);
else
brwTop = (int)doc3.documentElement.getAttribute("scrollTop", 0);
PrintWindow(hwnd, hdc, 0);
g.ReleaseHdc(hdc);
g.Flush();
screenfrag = Image.FromHbitmap(bm.GetHbitmap());
g2.DrawImage(screenfrag, brwLeft + URLExtraLeft, brwTop + URLExtraHeight);
}
++myPageWidth;
}
//Draw Standard Resolution Guides
if(chkShowGuides.Checked == true)
{
// Create pen.
int myWidth = 1;
Pen myPen = new Pen(Color.Navy, myWidth);
Pen myShadowPen = new Pen(Color.NavajoWhite, myWidth);
// Create coordinates of points that define line.
float x1 = -(float)myWidth - 1 + URLExtraLeft;
float y1 = -(float)myWidth - 1 + URLExtraHeight;
float x600 = 600.0F + (float)myWidth+1;
float y480 = 480.0F + (float)myWidth+1;
float x2 = 800.0F + (float)myWidth+1;
float y2 = 600.0F + (float)myWidth+1;
float x3 = 1024.0F + (float)myWidth+1;
float y3 = 768.0F + (float)myWidth+1;
float x1280 = 1280.0F + (float)myWidth+1;
float y1024 = 1024.0F + (float)myWidth+1;
// Draw line to screen.
g2.DrawRectangle(myPen, x1, y1, x600+myWidth, y480+myWidth);
g2.DrawRectangle(myPen, x1, y1, x2+myWidth, y2+myWidth);
g2.DrawRectangle(myPen, x1, y1, x3+myWidth, y3+myWidth);
g2.DrawRectangle(myPen, x1, y1, x1280+myWidth, y1024+myWidth);
// Create font and brush.
Font drawFont = new Font("Arial", 12);
SolidBrush drawBrush = new SolidBrush(Color.Navy);
SolidBrush drawBrush2 = new SolidBrush(Color.NavajoWhite);
// Set format of string.
StringFormat drawFormat = new StringFormat();
drawFormat.FormatFlags = StringFormatFlags.FitBlackBox;
// Draw string to screen.
g2.DrawString("600 x 480", drawFont, drawBrush, 5, y480 - 20 + URLExtraHeight, drawFormat);
g2.DrawString("800 x 600", drawFont, drawBrush, 5, y2 - 20 + URLExtraHeight, drawFormat);
g2.DrawString("1024 x 768", drawFont, drawBrush, 5, y3 - 20 + URLExtraHeight, drawFormat);
g2.DrawString("1280 x 1024", drawFont, drawBrush, 5, y1024 - 20 + URLExtraHeight, drawFormat);
}
//Write URL
if (chkWriteURL.Checked == true)
{ //Backfill URL paint location
SolidBrush whiteBrush = new SolidBrush(Color.White);
Rectangle fillRect = new Rectangle(0, 0, widthsize, URLExtraHeight+2);
Region fillRegion = new Region(fillRect);
g2.FillRegion(whiteBrush, fillRegion);
SolidBrush drawBrushURL = new SolidBrush(Color.Black);
Font drawFont = new Font("Arial", 12);
StringFormat drawFormat = new StringFormat();
drawFormat.FormatFlags = StringFormatFlags.FitBlackBox;
g2.DrawString(myLocalLink, drawFont, drawBrushURL, 0, 0, drawFormat);
}
//Reduce Resolution Size
double myResolution = Convert.ToDouble(cmbResolution.Text) * 0.01;
int finalWidth = (int)((widthsize + URLExtraLeft) * myResolution);
int finalHeight = (int)((heightsize + URLExtraHeight) * myResolution);
Bitmap finalImage = new Bitmap(finalWidth, finalHeight, System.Drawing.Imaging.PixelFormat.Format16bppRgb555);
Graphics gFinal = Graphics.FromImage((Image)finalImage);
gFinal.DrawImage( bm2, 0, 0, finalWidth, finalHeight);
//Get Time Stamp
DateTime myTime = DateTime.Now;
String format = "MM.dd.hh.mm.ss";
//Create Directory to save image to.
Directory.CreateDirectory("C:\\IECapture");
//Write Image.
EncoderParameters eps = new EncoderParameters(1);
long myQuality = Convert.ToInt64(cmbQuality.Text);
eps.Param[0] = new EncoderParameter( System.Drawing.Imaging.Encoder.Quality, myQuality);
ImageCodecInfo ici = GetEncoderInfo("image/jpeg");
finalImage.Save(@"c:\\IECapture\Captured_" + myTime.ToString(format) + ".jpg", ici, eps);
//Clean Up.
myDoc = null;
g.Dispose();
g2.Dispose();
gFinal.Dispose();
bm.Dispose();
bm2.Dispose();
finalImage.Dispose();
Cursor.Current = Cursors.Default;
}
private static ImageCodecInfo GetEncoderInfo(String mimeType)
{
int j;
ImageCodecInfo[] encoders;
encoders = ImageCodecInfo.GetImageEncoders();
for(j = 0; j < encoders.Length; ++j)
{
if(encoders[j].MimeType == mimeType)
return encoders[j];
}
return null;
}
private void lnkOpenCapture_LinkClicked(object sender, System.Windows.Forms.LinkLabelLinkClickedEventArgs e)
{
Process.Start("explorer.exe", "C:\\IECapture");
}
}
}
|
|
|
|

|
//Get Browser Window Height
int heightsize = getAttribute("scrollHeight", myDoc, doc3);
int widthsize = getAttribute("scrollWidth", myDoc, doc3);
//Get Screen Height
int screenHeight = getAttribute("clientHeight", myDoc, doc3);
int screenWidth = getAttribute("clientWidth", myDoc, doc3);
the heightsize and screenHeight returns the same value
the widthsize and screenWidth returns the same value
so the loop does not count the number of pages
//Get Screen Height (for bottom up screen drawing)
while ((myPage * screenHeight) < heightsize)
{
setAttribute("scrollTop", (screenHeight - 5) * myPage, myDoc, doc3);
++myPage;
}
//Rollback the page count by one
--myPage;
Please let us know the problem ASAP
ff
|
|
|
|

|
You cannot have the browser window minimized when taking the screenshot. Just thought I would share this in case someone else is making the same mistake.
|
|
|
|

|
Building on an earlier comment by Daniel Landers, I was able to make this app run with with IE versions 6,7, and 8. Here is the modification to the code to make it work. Find the comment to Get browser "Document" handle and replace the code between that and the "Get Screen Height (for bottom up screen drawing)" comment with the code below.
while (hwndInt != 0)
{
hwndInt = hwnd.ToInt32();
GetClassName(hwndInt, sbc, 256);
if(sbc.ToString().IndexOf("Shell DocObject View", 0) > -1) {
hwnd = FindWindowEx(hwnd, IntPtr.Zero, "Internet Explorer_Server", IntPtr.Zero);
break;
}
if (sbc.ToString().IndexOf("TabWindowClass", 0) > -1) {
hwnd = FindWindowEx(hwnd, IntPtr.Zero, "Shell DocObject View", IntPtr.Zero);
hwnd = FindWindowEx(hwnd, IntPtr.Zero, "Internet Explorer_Server", IntPtr.Zero);
break;
}
if (sbc.ToString().IndexOf("Frame Tab", 0) > -1) {
hwnd = FindWindowEx(hwnd, IntPtr.Zero, "TabWindowClass", IntPtr.Zero);
hwnd = FindWindowEx(hwnd, IntPtr.Zero, "Shell DocObject View", IntPtr.Zero);
hwnd = FindWindowEx(hwnd, IntPtr.Zero, "Internet Explorer_Server", IntPtr.Zero);
break;
}
hwnd = GetWindow(hwnd, GW_HWNDNEXT);
}
|
|
|
|

|
Navid Akhtar showed a solution for the Black Image problem in his comment titled "Capturing entire web page like msn.com" unfortunately he ended his comment with "Similarly update other location where we are trying to get/set attributes." This may have left some people with the code still not working for pages that have a Strict DTD set.
So to Recap what Navid said, the problem with Black images is that pages with a Strict DTD set have a different structure for accessing the document attributes. Instead of myDoc.body.getAttribute("attributeName") you have to create an object as an IHTMLDocument3 object and access the attributes with thes new object named "doc3" in the example as doc3.documentElement.getAttribute("attributeName").
So Here's a more complete set of code for performing this:
Step 1: This code corresponds to the bottom of the third code section in the article or line 289 of Form1.cs in the provided source code.
mshtml.IHTMLDocument2 myDoc = (mshtml.IHTMLDocument2)m_browser.Document;
mshtml.IHTMLDocument3 doc3 = (mshtml.IHTMLDocument3)myDoc ;
Step 2: Add the following Function to your code. I'm adding it to the bottom to not interfere with the line numbers I'll be mentioning later. This code is from Navid Akhtar's comment. I adjusted ths function to return false for documents with a Transitional DTD. Pages with a Transitional DTD work the same as those without a DTD.
public bool IsDTDDocument(object document)
{
bool retVal = false;
string DocTypeContent = @"-//W3C//DTD";
mshtml.IHTMLDocument3 document3 = (mshtml.IHTMLDocument3)document;
mshtml.IHTMLDOMChildrenCollection domChilds = (mshtml.IHTMLDOMChildrenCollection)document3.childNodes;
mshtml.IHTMLDOMNode domNode = (mshtml.IHTMLDOMNode)domChilds.item(0);
if (domNode.nodeValue.ToString().Contains(DocTypeContent) && !domNode.nodeValue.ToString().Contains("Transitional"))
retVal = true;
return retVal;
}
Step 3: I've created two more Functions to handle getting and setting attributes so we don't have to have a bunch of if ... else statements throughout the code. Again, I've added these to the end of the class.
public void setAttribute(string attribute, int value, mshtml.IHTMLDocument2 myDoc, mshtml.IHTMLDocument3 doc3)
{
if (!IsDTDDocument(myDoc))
myDoc.body.setAttribute(attribute, value, 0);
else
doc3.documentElement.setAttribute(attribute, value, 0);
}
public int getAttribute(string attribute, mshtml.IHTMLDocument2 myDoc, mshtml.IHTMLDocument3 doc3)
{
int retVal = 0;
if (!IsDTDDocument(myDoc))
retVal = (int)myDoc.body.getAttribute(attribute, 0);
else
retVal = (int)doc3.documentElement.getAttribute(attribute, 0);
return retVal;
}
Step 4. We go in and change all of the calls to get or set attributes to use the new functions.
change Line 310 - 318
From:
myDoc.body.setAttribute("scroll", "yes", 0);
int heightsize = (int)myDoc.body.getAttribute("scrollHeight", 0);
int widthsize = (int)myDoc.body.getAttribute("scrollWidth", 0);
int screenHeight = (int)myDoc.body.getAttribute("clientHeight", 0);
int screenWidth = (int)myDoc.body.getAttribute("clientWidth", 0);
To:
setAttribute("scroll", 1, myDoc, doc3);
int heightsize = getAttribute("scrollHeight", myDoc, doc3);
int widthsize = getAttribute("scrollWidth", myDoc, doc3);
int screenHeight = getAttribute("clientHeight", myDoc, doc3);
int screenWidth = getAttribute("clientWidth", myDoc, doc3);
Change Line 357
From:
myDoc.body.setAttribute("scrollTop", (screenHeight - 5) * myPage, 0);
To:
setAttribute("scrollTop", (screenHeight - 5) * myPage, myDoc, doc3);
Change Lines 367 - 381
From:
myDoc.body.setAttribute("scrollLeft", (screenWidth - 5) * myPageWidth, 0);
brwLeft = (int)myDoc.body.getAttribute("scrollLeft", 0);
for (int i = myPage; i >= 0; --i)
{
g = Graphics.FromImage(bm);
hdc = g.GetHdc();
myDoc.body.setAttribute("scrollTop", (screenHeight - 5) * i, 0);
brwTop = (int)myDoc.body.getAttribute("scrollTop", 0);
PrintWindow(hwnd, hdc, 0);
g.ReleaseHdc(hdc);
g.Flush();
screenfrag = Image.FromHbitmap(bm.GetHbitmap());
g2.DrawImage(screenfrag, brwLeft + URLExtraLeft, brwTop + URLExtraHeight);
}
To:
setAttribute("scrollLeft", (screenWidth - 5) * myPageWidth, myDoc, doc3);
brwLeft = getAttribute("scrollLeft", myDoc, doc3);
for (int i = myPage; i >= 0; --i)
{
g = Graphics.FromImage(bm);
hdc = g.GetHdc();
setAttribute("scrollTop", (screenHeight - 5) * i, myDoc, doc3);
brwTop = getAttribute("scrollTop", myDoc, Doc3);
PrintWindow(hwnd, hdc, 0);
g.ReleaseHdc(hdc);
g.Flush();
screenfrag = Image.FromHbitmap(bm.GetHbitmap());
g2.DrawImage(screenfrag, brwLeft + URLExtraLeft, brwTop + URLExtraHeight);
}
This should make the code in this article work for all pages whether Strict DTD or not.
modified on Thursday, March 19, 2009 1:24 PM
|
|
|
|

|
I worked with code and its working fine in XP/sp2. but its giving problem with Vista may be due to
use of shellWindows class . We cannot use shell windows class in vista in protected mode.
If I disable UAC then its works fine.
Anyone tell me how it can be it work for Vista.
Best Regards
Bishwajeet
|
|
|
|

|
Do you have any sugestions about doing the same for word document page.
Please, help me...
|
|
|
|

|
In your code you are using the same color depth any time.
But the screenshots will be not perfekt, if there is i.e. an colour-gradient on the screen.
Add to following code to adjust the color depth:
int colourDepth = Screen.PrimaryScreen.BitsPerPixel;
PixelFormat format;
switch (colourDepth)
{
case 8:
case 16:
format = PixelFormat.Format16bppRgb565;
break;
case 24:
format = PixelFormat.Format24bppRgb;
break;
case 32:
format = PixelFormat.Format32bppArgb;
break;
default:
format = PixelFormat.Format32bppArgb;
break;
}
Bitmap bm = new Bitmap(captureWidth, captureHeight, format);
|
|
|
|

|
CRect rect;
GetClientRect(rect);
rect.NormalizeRect();
if(rect.IsRectEmpty() || rect.IsRectNull())
return;
CClientDC dcScrn(this);
CDC memDc;
if(!memDc.CreateCompatibleDC(&dcScrn))
return;
CBitmap bitmap;
if( !bitmap.CreateCompatibleBitmap(&dcScrn,rect.Width(),
rect.Height()))
return;
CBitmap* pOldBitmap = memDc.SelectObject(&bitmap);
memDc.BitBlt(0,0,rect.Width(),rect.Height(),&dcScrn,rect.left ,
rect.top ,SRCCOPY );
if(OpenClipboard())
{
EmptyClipboard();
SetClipboardData(CF_BITMAP,bitmap.GetSafeHandle());
CloseClipboard();
}
memDc.SelectObject(pOldBitmap);
|
|
|
|

|
Hi i got a problem in using the code. I put in inside a loop where it will open and close the page to get the pages but in the long time run the open and closing of the page will become slow. and a message will say that it close because of out of memory. how can i fix this one?
|
|
|
|

|
This does EXACTLY what I needed it to do!
I would ask one little favor: Can it be updated to not dither (or antialias) the images? Some of the fine details are lost by the dithering process and they end up fuzzy, especially small-font text.
(I've tried all supplied resolutions and sizes, but to no avail.)
----------------------------------------------------------------------
Also:
For those of you who are experiencing black images,
I simply solved it by first running the image capture, then
bring IE to the foreground, and then run the web page capture from the taskbar.
|
|
|
|

|
Hi,
We are getting images in IE7.0 but getting black images in IE6.0. If you have any work around for this it would be appreciated. (we have to get images in both IE6 and IE7)
Thanks,
Kris.
|
|
|
|

|
Hi Thanks for article and source.
Could you please suggest me,
INstead of open browsers, Images can be captured by giving URL or a text file having URL's.
Could you please give any sugestion on it. Because I am not familier with 'C' programming.
Thanks,
Avinash
|
|
|
|

|
Hi Its really a very nice and helpful article. It works fine for some web sites. But do not capture the entire web page on many sites e.g. msn.com. I spent many hour to fix this issue and finally i came to know that this issue comes when a web page references a "dtd" file in doc type tag to ensure that internet explorer will use thestandard CSS box model. To resolve this issue i modified the code as following. 1- Declare IHTMLDocument3 object along with IHTMLDocument2 as follwing. //Assign Browser Document mshtml.IHTMLDocument2 myDoc = (mshtml.IHTMLDocument2)m_browser.Document; mshtml.IHTMLDocument3 doc3 = (mshtml.IHTMLDocument3)myDoc ; 2- Following function tells whether the current page is referencing a dtd file or not. public bool IsDTDDocument(object document) { // XHtml declare flag string string DocTypeContent = @"-//W3C//DTD"; mshtml.IHTMLDocument3 document3 = (mshtml.IHTMLDocument3)document; mshtml.IHTMLDOMChildrenCollection domChilds = (mshtml.IHTMLDOMChildrenCollection)document3.childNodes; mshtml.IHTMLDOMNode domNode = (mshtml.IHTMLDOMNode)domChilds.item(0); return domNode.nodeValue.ToString().Contains(DocTypeContent); } 3- If page do not referencing a dtd file then use the original code to get or set attributes otherwise use doc3.documentElement to get/set attributes as shown in following sample code. if (!IsDTDDocument(myDoc)) { myDoc.body.setAttribute("scroll", "Yes", 0); //Get Browser Window Height heightsize = (int)myDoc.body.getAttribute("scrollHeight", 0); widthsize = (int)myDoc.body.getAttribute("scrollWidth", 0); //Get Screen Height screenHeight = (int)myDoc.body.getAttribute("clientHeight", 0); screenWidth = (int)myDoc.body.getAttribute("clientWidth", 0); } else { doc3.documentElement.setAttribute("scroll", "Yes", 0); //Get Browser Window Height heightsize = (int)doc3.documentElement.getAttribute("scrollHeight", 0); widthsize = (int)doc3.documentElement.getAttribute("scrollWidth", 0); //Get Screen Height screenHeight = (int)doc3.documentElement.getAttribute("clientHeight", 0); screenWidth = (int)doc3.documentElement.getAttribute("clientWidth", 0); } Similarly update other locations where we are trying to get/set attributes. In this way we can capture entire web page from all web sites.
|
|
|
|

|
Doug,
How would you convert what you have in the IE web page capture project and port it over to a window's service which would try to detect specific Urls being type and then create the capture and send it off as an attachment via email?
|
|
|
|

|
hi, great article. Jut a couple of problems. When i installed the app on my laptop is comes up with:
See the end of this message for details on invoking
just-in-time (JIT) debugging instead of this dialog box.
************** Exception Text **************
System.IO.FileNotFoundException: The system cannot find the file specified.
at IEWindowCapture.frmMain.button1_Click(Object sender, EventArgs e)
at System.Windows.Forms.Control.OnClick(EventArgs e)
at System.Windows.Forms.Button.OnClick(EventArgs e)
at System.Windows.Forms.Button.OnMouseUp(MouseEventArgs mevent)
at System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks)
at System.Windows.Forms.Control.WndProc(Message& m)
at System.Windows.Forms.ButtonBase.WndProc(Message& m)
at System.Windows.Forms.Button.WndProc(Message& m)
at System.Windows.Forms.ControlNativeWindow.OnMessage(Message& m)
at System.Windows.Forms.ControlNativeWindow.WndProc(Message& m)
at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
************** Loaded Assemblies **************
mscorlib
Assembly Version: 1.0.5000.0
Win32 Version: 1.1.4322.2407
CodeBase: file:///c:/windows/microsoft.net/framework/v1.1.4322/mscorlib.dll
----------------------------------------
IEWindowCapture
Assembly Version: 1.0.1999.29727
Win32 Version: 1.0.1999.29727
CodeBase: file:///C:/Program%20Files/IECapture/IEWindowCapture.exe
----------------------------------------
System.Windows.Forms
Assembly Version: 1.0.5000.0
Win32 Version: 1.1.4322.2032
CodeBase: file:///c:/windows/assembly/gac/system.windows.forms/1.0.5000.0__b77a5c561934e089/system.windows.forms.dll
----------------------------------------
System
Assembly Version: 1.0.5000.0
Win32 Version: 1.1.4322.2407
CodeBase: file:///c:/windows/assembly/gac/system/1.0.5000.0__b77a5c561934e089/system.dll
----------------------------------------
System.Drawing
Assembly Version: 1.0.5000.0
Win32 Version: 1.1.4322.2032
CodeBase: file:///c:/windows/assembly/gac/system.drawing/1.0.5000.0__b03f5f7f11d50a3a/system.drawing.dll
----------------------------------------
Interop.SHDocVw
Assembly Version: 1.1.0.0
Win32 Version: 1.1.0.0
CodeBase: file:///C:/Program%20Files/IECapture/Interop.SHDocVw.DLL
----------------------------------------
Microsoft.mshtml
Assembly Version: 7.0.3300.0
Win32 Version: 7.0.3300.0
CodeBase: file:///c:/windows/assembly/gac/microsoft.mshtml/7.0.3300.0__b03f5f7f11d50a3a/microsoft.mshtml.dll
----------------------------------------
************** JIT Debugging **************
To enable just in time (JIT) debugging, the config file for this
application or machine (machine.config) must have the
jitDebugging value set in the system.windows.forms section.
The application must also be compiled with debugging
enabled.
For example:
<configuration>
<system.windows.forms jitDebugging="true" />
</configuration>
When JIT debugging is enabled, any unhandled exception
will be sent to the JIT debugger registered on the machine
rather than being handled by this dialog.
The second problem is that whn i run the program from the csproj file it comes up with:
SHDocVw.ShellWindows ShellWindow = new SHDocVw.ShellWindowsClass();
in yellow highlight and it says it cannot find the specified file.
third problem is when i tried importing just the main capture form into a new solution it works butit comes up with black images with date and time as the name.
I really need your help.
again, great article but grrrrrrrrrrrrrrrrr
modified on Thursday, April 17, 2008 11:10 AM
|
|
|
|

|
Do you have any idea why this could have happened?
|
|
|
|

|
i am using IE7.0.
when i run this application; it will give me black image.
I haven't change any code;
It's urgent for me!!!
Please suggest me.
Regards,
Vachan Chahan
|
|
|
|

|
Hi, I downloaded the demo project, its creating a black background image in c:\iecapture direcory with current date and time. My Ie is at www.google.com. Am I doing anythig wrong here.
Bala
|
|
|
|

|
Dear everybody,
I am looking for a code in C++ or C# that will save entire web contents in any folder in hard disk. Same like File-->Save as option in Internet explorer.
Any idea how to accomplish this.
I will be really thankful if anybody can guide me in this regard.
Thanks.
|
|
|
|

|
I have figured out how to show and hide sidebar from BHO using ShowBrowserBar call. Does anyone knows how to update the url in the sidebar from the BHO?
|
|
|
|

|
Hi,
It is very nice artical . Now I have one question ..
How can i convert a PDF to JPG image page by page. Also I wish to save the images with the page number as file name.
For Eg:
If the PDF has 5 Pages. The first page should be converted as jpg and saved in the name as 1.jpg, for the second page 2.jpg................5.jpg
Is it possible to create this without using any third party tools/DLL. I wish to cretae this application using C#.NET 2.0
Plz help me.
Thanks in advance
Know is Drop, Unknown is Ocean
|
|
|
|

|
Hi.. It is very nice artical .throught this artical i got what i needed !! Thanks to writter of this artical. Now I have one question .. How can i get image of html/mht link by page by page i.e page size will be -11*8.5 Plz any body know then plz share with me. Thanks. Jagdish Vasani
|
|
|
|
 |
|
|
General News Suggestion Question Bug Answer Joke Rant Admin
|
Capture whole web pages as a single image using C#.
| Type | Article |
| Licence | |
| First Posted | 22 Jun 2005 |
| Views | 526,148 |
| Bookmarked | 221 times |
|
|