Welcome to Vortx Community Forum, where you can ask questions and receive answers from the staff at Vortx and other members of the community.

If you had a user account on our previous forums website, you will need to register a new account here.

Learn more about...

AspDotNetStorefront
DotFeed

Screen capture functionality not working inside storefront

Hello All,

I need to capture product image and send it to the customer email.

I have made some test solution , by which I can capture the screen of product. It is working fine on test solution but I   write the same code on storefront solution it throws “The handle is invalid” Error. It thrown from g.CopyFromScreen() section of following code:

                 Graphics g = Graphics.FromImage(bitmap);
                 g.CopyFromScreen(SourcePoint, DestinationPoint, SelectionRectangle.Size);

 

Error:

ErrorCode=-2147467259
Message="The handle is invalid"
Source="System.Drawing"

I have researched about it on google and got that this is general access denied Error.

I have opened the storefront solution "run as administrator".

Please let me know how to fix the access related  issue ?

Thanks in advance.

Bikash
asked May 8, 2014 in MultiStore by bikashm (760 points)
I'm not quite understanding what you are trying to do. It looks like you are using some sort of web service to insert a product image into an email? What is the email that you are sending? If it's a stock ASPDNSF email why not simply call the products medium sized image into the emal?

Using web services can cause issues. For the above, and if you are using a service

Check the setting for Allow service to interact with desktop

Hello Dean,

Thanks a lot for your replay.

Please check the following link

http://dalebrookonline.com/p-4679-black-with-gold-print-premium-meat-ticket-86x54mm-pack-of-10.aspx

I need that same functionality, after creating custom image text; Customer can send the product image to their email.

For that I need Screen Capture functionality. I am not using web services anywhere.

Please help me out

Thanks again,

Bikash

How are they currently sending it to thier email?

To capture the image I would use something like this

 

  Bitmap bitmap = new Bitmap(bWidth, bHeight);
  Graphics g = Graphics.FromImage(bitmap);
  //do all your operations on g here.
  bitmap.Save(fileName, imageFormat);

But this is saving to a local drive rather than inserting this into the email. I like the approach you have. Just need to know how its saved then inserted to the email template.

Hello Dean,

Thanks for your time and great suggesion.

Actually , I need to save the edited image into local drive then I will send to customer emailed.

 I would like to fetch the product image section using screen capture and save it to the local drive or server.

I have used following code but it shows the same error :

Rectangle rect = new Rectangle(0, 0, 100, 100);
            Bitmap bmp = new Bitmap(rect.Width, rect.Height, PixelFormat.Format32bppArgb);
            Graphics g = Graphics.FromImage(bmp);

//bold section throws "The handle is invalid" error
 g.CopyFromScreen(rect.Left, rect.Top, 0, 0, bmp.Size, CopyPixelOperation.SourceCopy);

bmp.Save(FilePath, ImageFormat.Jpeg);

Do you please suggest me some code which captures particular section of screen?

Please let me know.

Thanks again,

Bikash

 

Using C# you can use one of these four methods

  • public Image CaptureScreen()
    Creates an Image object containing a screen shot of the entire desktop
  • public Image CaptureWindow(IntPtr handle)
    Creates an Image object containing a screen shot of a specific window
  • public void CaptureWindowToFile(IntPtr handle, string filename, ImageFormat format)
    Captures a screen shot of a specific window, and saves it to a file
  • public void CaptureScreenToFile(string filename, ImageFormat format)
    Captures a screen shot of the entire desktop, and saves it to a file

Example of code

ScreenCapture sc = new ScreenCapture();
// capture entire screen, and save it to a file
Image img = sc.CaptureScreen();
// display image in a Picture control named imageDisplay
this.imageDisplay.Image = img;
// capture this window, and save it
sc.CaptureWindowToFile(this.Handle,"C:\\temp2.gif",ImageFormat.Gif);

Code to the class

using System;
using System.Runtime.InteropServices;
using System.Drawing;
using System.Drawing.Imaging;
namespace ScreenShotDemo
{
    /// <summary>
    /// Provides functions to capture the entire screen, or a particular window, and save it to a file.
    /// </summary>
    public class ScreenCapture
    {
        /// <summary>
        /// Creates an Image object containing a screen shot of the entire desktop
        /// </summary>
        /// <returns></returns>
        public Image CaptureScreen()
        {
            return CaptureWindow( User32.GetDesktopWindow() );
        }
        /// <summary>
        /// Creates an Image object containing a screen shot of a specific window
        /// </summary>
        /// <param name="handle">The handle to the window. (In windows forms, this is obtained by the Handle property)</param>
        /// <returns></returns>
        public Image CaptureWindow(IntPtr handle)
        {
            // get te hDC of the target window
            IntPtr hdcSrc = User32.GetWindowDC(handle);
            // get the size
            User32.RECT windowRect = new User32.RECT();
            User32.GetWindowRect(handle,ref windowRect);
            int width = windowRect.right - windowRect.left;
            int height = windowRect.bottom - windowRect.top;
            // create a device context we can copy to
            IntPtr hdcDest = GDI32.CreateCompatibleDC(hdcSrc);
            // create a bitmap we can copy it to,
            // using GetDeviceCaps to get the width/height
            IntPtr hBitmap = GDI32.CreateCompatibleBitmap(hdcSrc,width,height);
            // select the bitmap object
            IntPtr hOld = GDI32.SelectObject(hdcDest,hBitmap);
            // bitblt over
            GDI32.BitBlt(hdcDest,0,0,width,height,hdcSrc,0,0,GDI32.SRCCOPY);
            // restore selection
            GDI32.SelectObject(hdcDest,hOld);
            // clean up
            GDI32.DeleteDC(hdcDest);
            User32.ReleaseDC(handle,hdcSrc);
            // get a .NET image object for it
            Image img = Image.FromHbitmap(hBitmap);
            // free up the Bitmap object
            GDI32.DeleteObject(hBitmap);
            return img;
        }
        /// <summary>
        /// Captures a screen shot of a specific window, and saves it to a file
        /// </summary>
        /// <param name="handle"></param>
        /// <param name="filename"></param>
        /// <param name="format"></param>
        public void CaptureWindowToFile(IntPtr handle, string filename, ImageFormat format)
        {
            Image img = CaptureWindow(handle);
            img.Save(filename,format);
        }
        /// <summary>
        /// Captures a screen shot of the entire desktop, and saves it to a file
        /// </summary>
        /// <param name="filename"></param>
        /// <param name="format"></param>
        public void CaptureScreenToFile(string filename, ImageFormat format)
        {
            Image img = CaptureScreen();
            img.Save(filename,format);
        }
     
        /// <summary>
        /// Helper class containing Gdi32 API functions
        /// </summary>
        private class GDI32
        {
           
            public const int SRCCOPY = 0x00CC0020; // BitBlt dwRop parameter
            [DllImport("gdi32.dll")]
            public static extern bool BitBlt(IntPtr hObject,int nXDest,int nYDest,
                int nWidth,int nHeight,IntPtr hObjectSource,
                int nXSrc,int nYSrc,int dwRop);
            [DllImport("gdi32.dll")]
            public static extern IntPtr CreateCompatibleBitmap(IntPtr hDC,int nWidth,
                int nHeight);
            [DllImport("gdi32.dll")]
            public static extern IntPtr CreateCompatibleDC(IntPtr hDC);
            [DllImport("gdi32.dll")]
            public static extern bool DeleteDC(IntPtr hDC);
            [DllImport("gdi32.dll")]
            public static extern bool DeleteObject(IntPtr hObject);
            [DllImport("gdi32.dll")]
            public static extern IntPtr SelectObject(IntPtr hDC,IntPtr hObject);
        }

        /// <summary>
        /// Helper class containing User32 API functions
        /// </summary>
        private class User32
        {
            [StructLayout(LayoutKind.Sequential)]
            public struct RECT
            {
                public int left;
                public int top;
                public int right;
                public int bottom;
            }
            [DllImport("user32.dll")]
            public static extern IntPtr GetDesktopWindow();
            [DllImport("user32.dll")]
            public static extern IntPtr GetWindowDC(IntPtr hWnd);
            [DllImport("user32.dll")]
            public static extern IntPtr ReleaseDC(IntPtr hWnd,IntPtr hDC);
            [DllImport("user32.dll")]
            public static extern IntPtr GetWindowRect(IntPtr hWnd,ref RECT rect);
        }
    }
}

 

Another way would be to force the text onto the image into an Iframe and then capturing it this way

1 Answer

0 votes

Whouldn't it be eaiser to get the product image draw that image and then draw cusomtized text instead of trying to take a screen shot in asp.net?

In other words code like this:

Brush b = new SolidBrush(Color.Black);
Font f = new Font("Times New Roman", 12);
System.Drawing.Image imgPhoto = System.Drawing.Image.FromFile(AppLogic.GetImagePath("product", "medium", true) +"TKB44G.jpg");
Bitmap bmp = new Bitmap(imgPhoto.Width, imgPhoto.Height);
Graphics g = Graphics.FromImage(bmp);
g.DrawImage(imgPhoto, new Rectangle(0, 0, phWidth, phHeight), 0, 0, phWidth, phHeight, GraphicsUnit.Pixel);
g.DrawString("string info here", f, b, 95, 130);
bmp.Save(Server.MapPath("tickets\\" + ShoppingCartRecID + "_TKB44G.jpg"), ImageFormat.Jpeg);
bmp.Dispose();
g.Dispose();
imgPhoto.Dispose();

In my example I save the image to disk. But if you wanted you can attache the image strait to the email using the steam class.

answered May 8, 2014 by mmcgeachy (4,310 points)
Nice! What could be even better would be making an adjustment to the customer.dbo so that it stores this within the customer record and then simply call that into the email using the customer ID session.

Hello mmcgeachy,

Thanks for your valuable time and suggestion

I have following question:

Q. How to get the actual image name, height and width?

Q. I have following image

 http://dalebrookonline.com/images/product/large/tkb44g_1_.jpg

I need to remove text “Your Name Here” before replace the text “string info here”.

Please let me know how to do that?

Q. I have Multiple product needs same text change functionality. If I use your code, the style and rectangle x – y coordinate is depending on the individual products.

 Is there any way to create a generic style for products?

Please let me know the answer.

Thanks again,

Bikash

The acctual image height and width come from System.Drawing.Image so in this case imgPhoto.

As to how you would remove the text of "Your name here" create an image that does not have that text and use that as your base image.

Having multiple images drawn is possible it just making a way for the x and y to be dynamic. Which can done via extension/custom fields or appconfigs. You can also do a combination of appconfigs and fields if needed. For example

int x = AppLogic.AppConfigUSInt(ImageFileNameOverride+"x");
int y = AppLogic.AppConfigUSInt(ImageFileNameOverride+"y");

Note that ImageFileNameOverride can help make things more generic so you are only having to create new settings when the image postion and/or the image style changes istead of creating settings each product sku.

Hello Mmcgeachy

Thanks for your valuable time and suggestion.

I have used the following code:

System.Drawing.Image imgPhoto = System.Drawing.Image.FromFile(AppLogic.GetImagePath("product", "medium", true) +"TKB44G.jpg");

 

Q. Please let me how can I fetch the picture name ("TKB44G.jpg") of corresponding product ?

 

I have used the :

int  x = AppLogic.AppConfigUSInt(ImageFileNameOverride+"x");

int y = AppLogic.AppConfigUSInt(ImageFileNameOverride+"y");

 

But compilation error “ name “ImageFileNameOverride” does not exist in current context ”

Q. where I initialize the ImageFileNameOverride ?

Q. How do I align center to the text "string info here" ?

I have used the following code :

StringFormat strFormat = new StringFormat();

strFormat.Alignment = StringAlignment.Center;

g.DrawString("string info here", f, b, 35, 70, strFormat);

But it makes the text into center of the entire screen not the image inselt.

 

 

Thanks again,

Bikash

This is most likely looping through your products in a cart so I going to guess you have a list of product ids. Then it just a matter of lookinng up the other information you may not have. So a sql query like this would do:

using (SqlConnection con = new SqlConnection(DB.GetDBConn()))
{
	con.Open();
	string query = "select SKU, ImageFilenameOverride, SEAltText, SwatchImageMap from product where productid = " + ID;
	using (IDataReader dr = DB.GetRS(query, con))
	{
		if (dr.Read())
		{
			string sku = DB.RSField(dr, "SKU");
			string ImageFilenameOverride = DB.RSField(dr, "ImageFilenameOverride");
			String filename = ImageFileNameOverride;
			if (FN.Length == 0 && EONU == "PRODUCT" && AppLogic.AppConfigBool("UseSKUForProductImageName") && SKU.Trim().Length > 0)
			{
				FN = SKU;
			}
			if (FN.Length == 0)
			{
				FN = ID.ToString();
			}                                
		}
	}
}

I going to guess you just want a horizontal algin so something like having a draw string like this

SizeF size = g.MeasureString("string info here");
int x = Convert.ToInt32((this.ClientRectangle.Width / 2) - (size.Width / 2));
g.DrawString("string info here", f, b, x, 130);
Hello Mmcgeachy,

I have use your horizontal algin code it shows the following error :

"  Keyword 'this' is not valid in a static property, static method, or static field initializer   "

Any suggesion ?

Thanks.

Bikash
In the code try replacing this.ClientRectangle.Width with imgPhoto.Width.

Hello Mmcgeachy,

Thank you very much for your value able time and suggesion.

Now I need to attach the image into a mail while customer checkout the product.

Q. Can u please let me know can i do that mail functionality?

Thanks again,

Bikash

With how things are written so you don't have to rewrite things it is easier to have source code. Look for SendOrderEMail in ASPDNSFCore\AppLogic.cs. Each email goes through AppLogic.SendMail. Given on how you want to do things you want to make a new AppLogic.SendMail that has overloads for the order number so you but that is up to you. 

Once at sendmail I it just a matter of grabing the file and attache the file. Which in code would be something like this:

string filepath = CommonLogic.SafeMapPath(CommonLogic.IIF(AppLogic.IsAdminSite, "../", "") + "images/tickets/" + filename);
System.Net.Mail.Attachment file = new System.Net.Mail.Attachment(filepath);
msg.Attachments.Add(file);

Also if you don't mind hotlinking the images you can just edit XmlPackages\notification.receipt.xml.config to add the images that way.

...