??????????????????????????????????????? 將控件保存為圖片
???????????????????????????????????????????????? 周銀輝
?
這里分別提供win form?和 wpf 兩種方式
對于.net 2.0 我們可以簡單地利用?BitBlt 函數來實現,非常簡單,代碼如下:
????public?static?class?ControlToImageConverter
????{
????????private?const?Int32?SRCCOPY?=?0xCC0020;
????????[DllImport("gdi32.dll")]
????????internal?static?extern?bool?BitBlt(
????????????IntPtr?hdcDest,?//?handle?to?destination?DC
????????????int?nXDest,?//?x-coord?of?destination?upper-left?corner
????????????int?nYDest,?//?y-coord?of?destination?upper-left?corner
????????????int?nWidth,?//?width?of?destination?rectangle
????????????int?nHeight,?//?height?of?destination?rectangle
????????????IntPtr?hdcSrc,?//?handle?to?source?DC
????????????int?nXSrc,?//?x-coordinate?of?source?upper-left?corner
????????????int?nYSrc,?//?y-coordinate?of?source?upper-left?corner
????????????Int32?dwRop?//?raster?operation?code
????????????);
????????public?static?Bitmap?GetImageOfControl(Control?control)
????????{
????????????var?w?=?control.Size.Width;
????????????var?h?=?control.Size.Height;
????????????Graphics?gOfCtrl?=?control.CreateGraphics();
????????????var?bmp?=?new?Bitmap(w,?h,?gOfCtrl);
????????????Graphics?gOfBmp?=?Graphics.FromImage(bmp);
????????????IntPtr?dc1?=?gOfCtrl.GetHdc();
????????????IntPtr?dc2?=?gOfBmp.GetHdc();
????????????BitBlt(dc2,?0,?0,?w,?h,?dc1,?0,?0,?SRCCOPY);
????????????gOfCtrl.ReleaseHdc(dc1);
????????????gOfBmp.ReleaseHdc(dc2);
????????????gOfCtrl.Dispose();
????????????gOfBmp.Dispose();
????????????return?bmp;
????????}
????}
????{
????????private?const?Int32?SRCCOPY?=?0xCC0020;
????????[DllImport("gdi32.dll")]
????????internal?static?extern?bool?BitBlt(
????????????IntPtr?hdcDest,?//?handle?to?destination?DC
????????????int?nXDest,?//?x-coord?of?destination?upper-left?corner
????????????int?nYDest,?//?y-coord?of?destination?upper-left?corner
????????????int?nWidth,?//?width?of?destination?rectangle
????????????int?nHeight,?//?height?of?destination?rectangle
????????????IntPtr?hdcSrc,?//?handle?to?source?DC
????????????int?nXSrc,?//?x-coordinate?of?source?upper-left?corner
????????????int?nYSrc,?//?y-coordinate?of?source?upper-left?corner
????????????Int32?dwRop?//?raster?operation?code
????????????);
????????public?static?Bitmap?GetImageOfControl(Control?control)
????????{
????????????var?w?=?control.Size.Width;
????????????var?h?=?control.Size.Height;
????????????Graphics?gOfCtrl?=?control.CreateGraphics();
????????????var?bmp?=?new?Bitmap(w,?h,?gOfCtrl);
????????????Graphics?gOfBmp?=?Graphics.FromImage(bmp);
????????????IntPtr?dc1?=?gOfCtrl.GetHdc();
????????????IntPtr?dc2?=?gOfBmp.GetHdc();
????????????BitBlt(dc2,?0,?0,?w,?h,?dc1,?0,?0,?SRCCOPY);
????????????gOfCtrl.ReleaseHdc(dc1);
????????????gOfBmp.ReleaseHdc(dc2);
????????????gOfCtrl.Dispose();
????????????gOfBmp.Dispose();
????????????return?bmp;
????????}
????}
?
其中 SRCCOPY?=?0xCC0020, 表示將源直接拷貝到目標。
?
對于WPF,無法獲得控件的hdc, 所以不能使用bitblt函數了,但幸運的是,其提供了一個RenderTargetBitmap的類型,可以將控件繪制到改類型的類型是示例上,比如:
?
var?renderBitmap?=?
?????????new?RenderTargetBitmap(w,?h,?96d,96d,?PixelFormats.Pbgra32);
renderBitmap.Render(controlToConvert);
?????????new?RenderTargetBitmap(w,?h,?96d,96d,?PixelFormats.Pbgra32);
renderBitmap.Render(controlToConvert);
?
其可以直接作為Image控件的源以便顯示,如果要將其保存下來(保存到流中),則需要用到BitmapEncoder, 將上面的位圖添加到encoder的幀中,然后調用save方法便可。
包裝好的代碼如下:
?


????internal?enum?ImageType
????{
????????Bmp,
????????Gif,
????????Jpeg,
????????Png,
????????Tiff,
????????Wdp
????}
????internal?static?class?ControlToImageConverter
????{
????????///?<summary>
????????///?Convert?any?control?to?a?PngBitmapEncoder
????????///?</summary>
????????///?<param?name="controlToConvert">The?control?to?convert?to?an?ImageSource</param>
????????///?<param?name="imageType">The?image?type?will?indicate?the?type?of?return?bitmap?encoder</param>
????????///?<returns>The?returned?ImageSource?of?the?controlToConvert</returns>
????????private?static?BitmapEncoder?GetImageFromControl(FrameworkElement?controlToConvert,?ImageType?imageType)
????????{
????????????var?bounds?=?controlToConvert.GetBounds(controlToConvert.Parent?as?Visual);
????????????var?renderBitmap?=?new?RenderTargetBitmap((Int32)bounds.Width,?(Int32)bounds.Height,?96d,
??????????????????????????????????????????????????????96d,?PixelFormats.Pbgra32);
????????????renderBitmap.Render(controlToConvert);
????????????BitmapEncoder?encoder?=?GetBitmapEncoderByImageType(imageType);
????????????//?puch?rendered?bitmap?into?it
????????????encoder.Frames.Add(BitmapFrame.Create(renderBitmap));
????????????return?encoder;
????????}
????????private?static?Rect?GetBounds(this?FrameworkElement?element,?Visual?from)
????????{
????????????Rect?rect?=?Rect.Empty;
????????????try
????????????{
????????????????GeneralTransform?transform?=?element.TransformToVisual(from);
????????????????rect?=?transform.TransformBounds(new?Rect(0,?0,?element.ActualWidth,?element.ActualHeight));
????????????????//?ReSharper?disable?EmptyGeneralCatchClause
????????????}
????????????catch
????????????//?ReSharper?restore?EmptyGeneralCatchClause
????????????{
????????????}
????????????return?rect;
????????}
????????///?<summary>
????????///?Get?an?encoder?by?a?specify?image?type
????????///?</summary>
????????///?<param?name="type">the?image?type</param>
????????///?<returns>return?an?eccoder</returns>
????????private?static?BitmapEncoder?GetBitmapEncoderByImageType(ImageType?type)
????????{
????????????switch?(type)
????????????{
????????????????case?ImageType.Bmp:
????????????????????return?new?BmpBitmapEncoder();
????????????????case?ImageType.Gif:
????????????????????return?new?GifBitmapEncoder();
????????????????case?ImageType.Jpeg:
????????????????????return?new?JpegBitmapEncoder();
????????????????case?ImageType.Png:
????????????????????return?new?PngBitmapEncoder();
????????????????case?ImageType.Tiff:
????????????????????return?new?TiffBitmapEncoder();
????????????????case?ImageType.Wdp:
????????????????????return?new?WmpBitmapEncoder();
????????????????default:
????????????????????return?new?PngBitmapEncoder();
????????????}
????????}
????????///?<summary>
????????///?Get?the?iamge?type?by?image?file?name
????????///?</summary>
????????///?<param?name="fileName">the?file?name?of?an?image</param>
????????///?<returns>the?iamge?type</returns>
????????private?static?ImageType?GetImageTypeByFileName(string?fileName)
????????{
????????????ImageType?returnType?=?ImageType.Png;
????????????var?extension?=?Path.GetExtension(fileName);
????????????if?(!String.IsNullOrEmpty(extension))
????????????{
????????????????switch?(extension.ToLower())
????????????????{
????????????????????case?".bmp":
????????????????????????returnType?=?ImageType.Bmp;
????????????????????????break;
????????????????????case?".gif":
????????????????????????returnType?=?ImageType.Gif;
????????????????????????break;
????????????????????case?".jpeg":
????????????????????case?".jpg":
????????????????????case?".jpe":
????????????????????case?"jfif":
????????????????????????returnType?=?ImageType.Jpeg;
????????????????????????break;
????????????????????case?".png":
????????????????????????returnType?=?ImageType.Png;
????????????????????????break;
????????????????????case?".tiff":
????????????????????case?".tif":
????????????????????????returnType?=?ImageType.Tiff;
????????????????????????break;
????????????????????case?".wdp":
????????????????????????returnType?=?ImageType.Wdp;
????????????????????????break;
????????????????????default:
????????????????????????returnType?=?ImageType.Png;
????????????????????????break;
????????????????}
????????????}
????????????return?returnType;
????????}
????????///?<summary>
????????///?Get?an?ImageSource?of?a?control
????????///?</summary>
????????///?<param?name="controlToConvert">The?control?to?convert?to?an?ImageSource</param>
????????///?<param?name="imageType">the?image?type</param>
????????///?<returns>The?returned?ImageSource?of?the?controlToConvert</returns>
????????public?static?BitmapSource?GetImageOfControl(FrameworkElement?controlToConvert,?ImageType?imageType)
????????{
????????????//?return?first?frame?of?image?
????????????var?encoder?=?GetImageFromControl(controlToConvert,?imageType);
????????????if?(encoder?!=?null?&&?encoder.Frames?!=?null?&&?encoder.Frames.Count?>?0)
????????????{
????????????????return?encoder.Frames[0];
????????????}
????????????return?new?BitmapImage();
????????}
????????///?<summary>
????????///?Get?an?ImageSource?of?a?control(Jpeg?as?default?type)
????????///?</summary>
????????///?<param?name="controlToConvert">The?control?to?convert?to?an?ImageSource</param>
????????///?<returns>The?returned?ImageSource?of?the?controlToConvert</returns>
????????public?static?BitmapSource?GetImageOfControl(FrameworkElement?controlToConvert)
????????{
????????????return?GetImageOfControl(controlToConvert,?ImageType.Jpeg);
????????}
????????///?<summary>
????????///?Save?an?image?of?a?control
????????///?</summary>
????????///?<param?name="controlToConvert">The?control?to?convert?to?an?ImageSource</param>
????????///?<param?name="fileName">The?location?to?save?the?image?to</param>
????????///?<returns>The?returned?ImageSource?of?the?controlToConvert</returns>
????????public?static?Boolean?SaveImageOfControl(FrameworkElement?controlToConvert,?String?fileName)
????????{
????????????try
????????????{
????????????????var?imageType?=?GetImageTypeByFileName(fileName);
????????????????using?(var?outStream?=?new?FileStream(fileName,?FileMode.Create))
????????????????{
????????????????????var?encoder?=?GetImageFromControl(controlToConvert,?imageType);
????????????????????encoder.Save(outStream);
????????????????}
????????????}
????????????catch?(Exception?e)
????????????{
#if?DEBUG
????????????????Console.WriteLine("Exception?caught?saving?stream:?{0}",?e.Message);
#endif
????????????????return?false;
????????????}
????????????return?true;
????????}
????}
????{
????????Bmp,
????????Gif,
????????Jpeg,
????????Png,
????????Tiff,
????????Wdp
????}
????internal?static?class?ControlToImageConverter
????{
????????///?<summary>
????????///?Convert?any?control?to?a?PngBitmapEncoder
????????///?</summary>
????????///?<param?name="controlToConvert">The?control?to?convert?to?an?ImageSource</param>
????????///?<param?name="imageType">The?image?type?will?indicate?the?type?of?return?bitmap?encoder</param>
????????///?<returns>The?returned?ImageSource?of?the?controlToConvert</returns>
????????private?static?BitmapEncoder?GetImageFromControl(FrameworkElement?controlToConvert,?ImageType?imageType)
????????{
????????????var?bounds?=?controlToConvert.GetBounds(controlToConvert.Parent?as?Visual);
????????????var?renderBitmap?=?new?RenderTargetBitmap((Int32)bounds.Width,?(Int32)bounds.Height,?96d,
??????????????????????????????????????????????????????96d,?PixelFormats.Pbgra32);
????????????renderBitmap.Render(controlToConvert);
????????????BitmapEncoder?encoder?=?GetBitmapEncoderByImageType(imageType);
????????????//?puch?rendered?bitmap?into?it
????????????encoder.Frames.Add(BitmapFrame.Create(renderBitmap));
????????????return?encoder;
????????}
????????private?static?Rect?GetBounds(this?FrameworkElement?element,?Visual?from)
????????{
????????????Rect?rect?=?Rect.Empty;
????????????try
????????????{
????????????????GeneralTransform?transform?=?element.TransformToVisual(from);
????????????????rect?=?transform.TransformBounds(new?Rect(0,?0,?element.ActualWidth,?element.ActualHeight));
????????????????//?ReSharper?disable?EmptyGeneralCatchClause
????????????}
????????????catch
????????????//?ReSharper?restore?EmptyGeneralCatchClause
????????????{
????????????}
????????????return?rect;
????????}
????????///?<summary>
????????///?Get?an?encoder?by?a?specify?image?type
????????///?</summary>
????????///?<param?name="type">the?image?type</param>
????????///?<returns>return?an?eccoder</returns>
????????private?static?BitmapEncoder?GetBitmapEncoderByImageType(ImageType?type)
????????{
????????????switch?(type)
????????????{
????????????????case?ImageType.Bmp:
????????????????????return?new?BmpBitmapEncoder();
????????????????case?ImageType.Gif:
????????????????????return?new?GifBitmapEncoder();
????????????????case?ImageType.Jpeg:
????????????????????return?new?JpegBitmapEncoder();
????????????????case?ImageType.Png:
????????????????????return?new?PngBitmapEncoder();
????????????????case?ImageType.Tiff:
????????????????????return?new?TiffBitmapEncoder();
????????????????case?ImageType.Wdp:
????????????????????return?new?WmpBitmapEncoder();
????????????????default:
????????????????????return?new?PngBitmapEncoder();
????????????}
????????}
????????///?<summary>
????????///?Get?the?iamge?type?by?image?file?name
????????///?</summary>
????????///?<param?name="fileName">the?file?name?of?an?image</param>
????????///?<returns>the?iamge?type</returns>
????????private?static?ImageType?GetImageTypeByFileName(string?fileName)
????????{
????????????ImageType?returnType?=?ImageType.Png;
????????????var?extension?=?Path.GetExtension(fileName);
????????????if?(!String.IsNullOrEmpty(extension))
????????????{
????????????????switch?(extension.ToLower())
????????????????{
????????????????????case?".bmp":
????????????????????????returnType?=?ImageType.Bmp;
????????????????????????break;
????????????????????case?".gif":
????????????????????????returnType?=?ImageType.Gif;
????????????????????????break;
????????????????????case?".jpeg":
????????????????????case?".jpg":
????????????????????case?".jpe":
????????????????????case?"jfif":
????????????????????????returnType?=?ImageType.Jpeg;
????????????????????????break;
????????????????????case?".png":
????????????????????????returnType?=?ImageType.Png;
????????????????????????break;
????????????????????case?".tiff":
????????????????????case?".tif":
????????????????????????returnType?=?ImageType.Tiff;
????????????????????????break;
????????????????????case?".wdp":
????????????????????????returnType?=?ImageType.Wdp;
????????????????????????break;
????????????????????default:
????????????????????????returnType?=?ImageType.Png;
????????????????????????break;
????????????????}
????????????}
????????????return?returnType;
????????}
????????///?<summary>
????????///?Get?an?ImageSource?of?a?control
????????///?</summary>
????????///?<param?name="controlToConvert">The?control?to?convert?to?an?ImageSource</param>
????????///?<param?name="imageType">the?image?type</param>
????????///?<returns>The?returned?ImageSource?of?the?controlToConvert</returns>
????????public?static?BitmapSource?GetImageOfControl(FrameworkElement?controlToConvert,?ImageType?imageType)
????????{
????????????//?return?first?frame?of?image?
????????????var?encoder?=?GetImageFromControl(controlToConvert,?imageType);
????????????if?(encoder?!=?null?&&?encoder.Frames?!=?null?&&?encoder.Frames.Count?>?0)
????????????{
????????????????return?encoder.Frames[0];
????????????}
????????????return?new?BitmapImage();
????????}
????????///?<summary>
????????///?Get?an?ImageSource?of?a?control(Jpeg?as?default?type)
????????///?</summary>
????????///?<param?name="controlToConvert">The?control?to?convert?to?an?ImageSource</param>
????????///?<returns>The?returned?ImageSource?of?the?controlToConvert</returns>
????????public?static?BitmapSource?GetImageOfControl(FrameworkElement?controlToConvert)
????????{
????????????return?GetImageOfControl(controlToConvert,?ImageType.Jpeg);
????????}
????????///?<summary>
????????///?Save?an?image?of?a?control
????????///?</summary>
????????///?<param?name="controlToConvert">The?control?to?convert?to?an?ImageSource</param>
????????///?<param?name="fileName">The?location?to?save?the?image?to</param>
????????///?<returns>The?returned?ImageSource?of?the?controlToConvert</returns>
????????public?static?Boolean?SaveImageOfControl(FrameworkElement?controlToConvert,?String?fileName)
????????{
????????????try
????????????{
????????????????var?imageType?=?GetImageTypeByFileName(fileName);
????????????????using?(var?outStream?=?new?FileStream(fileName,?FileMode.Create))
????????????????{
????????????????????var?encoder?=?GetImageFromControl(controlToConvert,?imageType);
????????????????????encoder.Save(outStream);
????????????????}
????????????}
????????????catch?(Exception?e)
????????????{
#if?DEBUG
????????????????Console.WriteLine("Exception?caught?saving?stream:?{0}",?e.Message);
#endif
????????????????return?false;
????????????}
????????????return?true;
????????}
????}
?
?
注意到上面的GetImageOfControl方法返回的實際是BitmapFrame, 其是BitmapSource的一種,如果你更習慣使用BitmapImage的話,免費贈送如下方法:
????????public?static?BitmapImage?ToBitmapImage(this?BitmapSource?bitmapSource)
????????{
????????????var?encoder?=?new?JpegBitmapEncoder();
????????????var?memoryStream?=?new?MemoryStream();
????????????encoder.Frames.Add(BitmapFrame.Create(bitmapSource));
????????????encoder.Save(memoryStream);
????????????var?bmp?=?new?BitmapImage();
????????????bmp.BeginInit();
????????????bmp.StreamSource?=?new?MemoryStream(memoryStream.ToArray());
????????????bmp.EndInit();
????????????memoryStream.Flush();
????????????memoryStream.Close();
????????????return?bmp;
????????}
????????{
????????????var?encoder?=?new?JpegBitmapEncoder();
????????????var?memoryStream?=?new?MemoryStream();
????????????encoder.Frames.Add(BitmapFrame.Create(bitmapSource));
????????????encoder.Save(memoryStream);
????????????var?bmp?=?new?BitmapImage();
????????????bmp.BeginInit();
????????????bmp.StreamSource?=?new?MemoryStream(memoryStream.ToArray());
????????????bmp.EndInit();
????????????memoryStream.Flush();
????????????memoryStream.Close();
????????????return?bmp;
????????}
?
?
?
?