//----------------------------------------------------------------------------- // FILENAME: ImageProcessor.cs // // DESCRIPTION: // 图片处理工具类,进行图片缩放和水印的处理 // // AUTHOR: BlueStone // // CREATEDATE: 2008-3-28 // // //----------------------------------------------------------------------------- using System; using System.Collections.Generic; using System.Text; using System.Drawing; using System.Drawing.Imaging; using System.IO; namespace Megajoy.Common.Tools { // 水印的水平对齐方式 public enum WatermarkHAlignEnum { WHA_LEFT = 0, WHA_CENTER = 1, WHA_RIGHT = 2 }; // 水印的垂直对齐方式 public enum WatermarkVAlignEnum { WVA_TOP = 0, WVA_CENTER = 1, WVA_BOTTOM = 2 }; // 图像处理的状态 public enum ImageProcessStatusEnum { IPS_PROCESSING = 0, IPS_FINISHED = 1, IPS_FAILED = 2, IPS_WARNING = 3 }; public delegate void ImageProcessCallback(ImageProcessStatusEnum iStatus, string sMsg); // 图像处理的参数结构体 public class ImageProcessParam { public ImageProcessParam() { m_lpszInputImageFile = m_lpszOutputImageFile = m_lpszWatermarkFile = m_lpszWatermarkBlendFile = ""; m_iWatermarkHAlign = WatermarkHAlignEnum.WHA_LEFT; m_iWatermarkVAlign = WatermarkVAlignEnum.WVA_TOP; m_nHorizontalMargin = m_nVerticalMargin = m_nDestWidth = m_nDestHeight = 0; m_bStretchOrCrop = false; m_fnImageProcessCallback = null; m_bOverride = false; m_nCompressQuality = 100; } public string m_lpszInputImageFile; // 输入的图片文件路径 public string m_lpszOutputImageFile; // 输出的图片文件路径 // 水印文件 public string m_lpszWatermarkFile; // 水印文件文件名 public string m_lpszWatermarkBlendFile; // 水印文件Alpha通道掩图 // 水印排列方式 public WatermarkHAlignEnum m_iWatermarkHAlign; // 水平对齐方式 public WatermarkVAlignEnum m_iWatermarkVAlign; // 垂直对齐方式 public int m_nHorizontalMargin; // 水平位置空出的像素数 public int m_nVerticalMargin; // 垂直位置空出的像素数 public int m_nDestWidth; // 输出文件的图像宽度 public int m_nDestHeight; // 输出文件的图像高度 public bool m_bStretchOrCrop; // 在原始图像比例和目标图像比例不一致的时候采用伸展还是切割方式处理图像 public ImageProcessCallback m_fnImageProcessCallback; public bool m_bOverride; // 是否允许覆盖已经存在的文件 public int m_nCompressQuality; // 如果输出是JPEG,则可以指定压缩的质量 }; public class ImageProcessor { public static bool ImageProcess( ImageProcessParam param) { if( !CheckParam( param ) ) { return false; } Bitmap imgSrc = null; try { imgSrc = new Bitmap( param.m_lpszInputImageFile ); } catch( Exception error ) { StatusCallback( param, ImageProcessStatusEnum.IPS_FAILED, String.Format("Failed to load InputImagefile {0}.", param.m_lpszInputImageFile) ); return false; } ImageCodecInfo codecInfo = GetImageCodecInfo( param.m_lpszOutputImageFile ); bool bMultiFrame = false; if( bMultiFrame ) { } else { // 进行单帧图片的处理 Bitmap pOutputFrame = null; bool bRet = DoImageResizeProcess( param, imgSrc, out pOutputFrame ); imgSrc.Dispose(); if( bRet == false ) { return false; } if( param.m_lpszWatermarkFile.Length > 0 ) { Bitmap pOutputWatermarkedFrame; bRet = DoImageWaterMarkProcess( param, pOutputFrame, out pOutputWatermarkedFrame ); pOutputFrame.Dispose(); if( bRet == false ) { return false; } pOutputFrame = pOutputWatermarkedFrame; } if( pOutputFrame != null ) { EncoderParameters pEncoderParameters = null; // An EncoderParameters object has an array of // EncoderParameter objects. In this case, there is only // one EncoderParameter object in the array. long[] parameterValue = new long[1]; parameterValue[0] = 0; EncoderParameter saveParam = new EncoderParameter( System.Drawing.Imaging.Encoder.SaveFlag, parameterValue ); parameterValue[0] = (long)param.m_nCompressQuality; EncoderParameter qualityParam = new EncoderParameter( System.Drawing.Imaging.Encoder.Quality, parameterValue ); if( IsSupportSetCompressQuality( param.m_lpszOutputImageFile ) ) { pEncoderParameters = new EncoderParameters(2); pEncoderParameters.Param[0] = saveParam; pEncoderParameters.Param[1] = qualityParam; } else { pEncoderParameters = new EncoderParameters(1); pEncoderParameters.Param[0] = saveParam; } try { pOutputFrame.Save(param.m_lpszOutputImageFile, codecInfo, pEncoderParameters); } catch (Exception error) { StatusCallback(param, ImageProcessStatusEnum.IPS_FAILED, String.Format("Failed to save to OutImageFile {0}", param.m_lpszOutputImageFile)); return false; } finally { pOutputFrame.Dispose(); } return true; } } return false; } static ImageCodecInfo GetImageCodecInfo(string sOutputFileName) { FileInfo fi = new FileInfo( sOutputFileName ); string sExtName = "*" + fi.Extension; ImageCodecInfo[] codecs = ImageCodecInfo.GetImageEncoders( ); foreach( ImageCodecInfo codec in codecs ) { string sFileTypes = codec.FilenameExtension; string[] sFileTypeList = sFileTypes.Split( ';' ); foreach( string sFileType in sFileTypeList ) { if( string.Compare( sFileType, sExtName, true ) == 0 ) { return codec; } } } return null; } //----------------------------------------------------------------------------- // FUNCTION: IsSupportSetCompressQuality // // DESCRIPTION: // 根据指定的文件的扩展名判断该文件类型是否支持设置压缩质量设置 // PARAM: // [lpszFileName] - 指定的文件名 // // RETURN: // TRUE: 支持多帧 // FALSE: 不支持多帧 //----------------------------------------------------------------------------- static bool IsSupportSetCompressQuality( string lpszFileName ) { int nDotPos = lpszFileName.LastIndexOf('.'); if( nDotPos < 0 ) { return false; } string sExtName = lpszFileName.Substring( nDotPos + 1 ); if( string.Compare( sExtName, "jpg", true ) == 0 ) { return true; } else if( string.Compare( sExtName, "jpeg", true ) == 0 ) { return true; } else { return false; } } static void StatusCallback(ImageProcessParam param, ImageProcessStatusEnum status, string sMsg) { if (param.m_fnImageProcessCallback != null) { param.m_fnImageProcessCallback(status, sMsg); } } static bool CheckParam(ImageProcessParam param) { if (param.m_lpszInputImageFile.Length == 0) { StatusCallback( param, ImageProcessStatusEnum.IPS_FAILED, "InputImageFile cannot be empty" ); return false; } if (!File.Exists(param.m_lpszInputImageFile)) { StatusCallback( param, ImageProcessStatusEnum.IPS_FAILED, string.Format( "Specified InputImageFile {0} cannot be found", param.m_lpszInputImageFile ) ); return false; } if (param.m_lpszOutputImageFile.Length == 0 ) { StatusCallback( param, ImageProcessStatusEnum.IPS_FAILED, "OutputImageFile cannot be empty" ); return false; } if ( File.Exists( param.m_lpszOutputImageFile) && !param.m_bOverride) { StatusCallback( param, ImageProcessStatusEnum.IPS_FAILED, string.Format( "Specified OutputImageFile {0} has existed.", param.m_lpszOutputImageFile ) ); return false; } return true; } //----------------------------------------------------------------------------- // FUNCTION: DoImageResizeProcess // // DESCRIPTION: // 进行一帧图片的变换尺寸的操作 // // PARAMS: // [param] - 图片处理上下文参数 // [pInputFrame] - 输入的图片对象指针 // [ppOutputFrame] - 输出的图片对象指针的指针 // RETURN: // TRUE: SUCCESS // FALSE: FAILED //----------------------------------------------------------------------------- static bool DoImageResizeProcess( ImageProcessParam param, System.Drawing.Bitmap pInputFrame, out System.Drawing.Bitmap ppOutputFrame) { // 进行图片的尺寸片换的操作 ppOutputFrame = null; if( param.m_nDestWidth == 0 && param.m_nDestHeight == 0 ) { // 两个都是0,表示不对尺寸进行变换 try { ppOutputFrame = pInputFrame.Clone( new Rectangle(0, 0, pInputFrame.Width, pInputFrame.Height ), pInputFrame.PixelFormat ); return true; } catch( Exception error ) { StatusCallback( param, ImageProcessStatusEnum.IPS_FAILED, "Failed to clone image." ); return false; } } else { int nSrcWidth, nSrcHeight; int nDestWidth, nDestHeight; nSrcWidth = pInputFrame.Width; nSrcHeight = pInputFrame.Height; nDestWidth = param.m_nDestWidth; nDestHeight= param.m_nDestHeight; if( nDestWidth == 0 ) { nDestWidth = nSrcWidth * nDestHeight / nSrcHeight; } if( nDestHeight == 0 ) { nDestHeight = nSrcHeight * nDestWidth / nSrcWidth; } if( param.m_bStretchOrCrop == true && Math.Abs( ((float)nSrcWidth / (float)nDestWidth) - ((float)nSrcHeight / (float)nDestHeight) ) > 0.01f ) { // 创建输出图片对象,并将graphic对象基于输出图片进行创建 Bitmap pOutputFrame = new Bitmap( nDestWidth, nDestHeight, pInputFrame.PixelFormat ); Graphics graph = Graphics.FromImage( pOutputFrame ); // 如果长宽的缩放比例超过1%需要考虑进行Crop Rectangle rectCrop = new Rectangle(); Rectangle rectDest = new Rectangle(); if( ((float)nSrcWidth / (float)nDestWidth) > ((float)nSrcHeight / (float)nDestHeight) ) { float fShrinkRate = (float)nDestHeight / (float)nSrcHeight; rectCrop.X = (int)(nSrcWidth - nDestWidth / fShrinkRate)/2; rectCrop.Width = (int)(nSrcWidth + nDestWidth / fShrinkRate)/2; rectCrop.Y = 0; rectCrop.Height = nSrcHeight; } else { float fShrinkRate = (float)nDestWidth / (float)nSrcWidth; rectCrop.Y = (int)(nSrcHeight - nDestHeight / fShrinkRate)/2; rectCrop.Height = (int)(nDestHeight / fShrinkRate); rectCrop.X = 0; rectCrop.Width = nSrcWidth; } rectDest.X = 0; rectDest.Y = 0; rectDest.Width = nDestWidth; rectDest.Height = nDestHeight; try { graph.DrawImage(pInputFrame, rectDest, rectCrop.X, rectCrop.Y, rectCrop.Width, rectCrop.Height, GraphicsUnit.Pixel); } catch (Exception error) { StatusCallback(param, ImageProcessStatusEnum.IPS_FAILED, "Failed to call drawimage."); return false; } finally { graph.Dispose(); } ppOutputFrame = pOutputFrame; } else { // 直接进行缩放 Bitmap pOutputFrame = new Bitmap( nDestWidth, nDestHeight, pInputFrame.PixelFormat ); Graphics graph = Graphics.FromImage( pOutputFrame ); try { graph.DrawImage(pInputFrame, 0, 0, nDestWidth, nDestHeight); } catch (Exception error) { StatusCallback(param, ImageProcessStatusEnum.IPS_FAILED, "Failed to call drawimage."); return false; } finally { graph.Dispose(); } ppOutputFrame = pOutputFrame; } return true; } } static byte RGB2GRAY(Color clr) { uint nGray = ((((uint)clr.B) * 117 + ((uint)clr.G) * 601 + ((uint)clr.R) * 306) >> 10); return (byte)nGray; } //----------------------------------------------------------------------------- // FUNCTION: DoImageWaterMarkProcess // // DESCRIPTION: // 进行一帧图片的打水印操作 // // PARAMS: // [param] - 图片处理上下文参数 // [pInputFrame] - 输入的图片对象指针 // [ppOutputFrame] - 输出的图片对象指针的指针 // RETURN: // TRUE: SUCCESS // FALSE: FAILED //----------------------------------------------------------------------------- static bool DoImageWaterMarkProcess( ImageProcessParam param, System.Drawing.Bitmap pInputFrame, out System.Drawing.Bitmap ppOutputFrame ) { ppOutputFrame = null; if( param.m_lpszWatermarkFile.Length > 0 ) { // 打图片水印 Bitmap imgWatermark = null; try { imgWatermark = new Bitmap( param.m_lpszWatermarkFile, false ); } catch( Exception error ) { StatusCallback( param, ImageProcessStatusEnum.IPS_FAILED, String.Format( "Failed to load WatermarkFile {0}.", param.m_lpszWatermarkFile ) ); return false; } int nWatermarkWidth = imgWatermark.Width; int nWatermarkHeight = imgWatermark.Height; if( param.m_lpszWatermarkBlendFile.Length > 0 ) { Bitmap imgWatermarkBlend = null; try { imgWatermarkBlend = new Bitmap(param.m_lpszWatermarkBlendFile, false); } catch( Exception error ) { StatusCallback( param, ImageProcessStatusEnum.IPS_FAILED, String.Format( "Failed to load WatermarkBlendFile {0}.", param.m_lpszWatermarkBlendFile ) ); return false; } if( imgWatermark.Width != imgWatermarkBlend.Width || imgWatermark.Height != imgWatermarkBlend.Height ) { StatusCallback( param, ImageProcessStatusEnum.IPS_FAILED, "The dimension of Watermark and WatermarkBlend is not equal." ); return false; } Bitmap imgBlendedWaterMark = new Bitmap(nWatermarkWidth, nWatermarkHeight, PixelFormat.Format32bppArgb); for( int nI = 0; nI < nWatermarkWidth; nI++ ) { for( int nJ = 0; nJ < nWatermarkHeight; nJ++ ) { Color clr; clr = imgWatermarkBlend.GetPixel( nI, nJ ); int nGray = (int)RGB2GRAY( clr ); clr = imgWatermark.GetPixel( nI, nJ ); Color newClr = Color.FromArgb( (int)((clr.ToArgb() & 0x00FFFFFF) | (nGray << 24)) ); imgBlendedWaterMark.SetPixel(nI, nJ, newClr); } } imgWatermark.Dispose( ); imgWatermarkBlend.Dispose(); imgWatermark = imgBlendedWaterMark; } // 生成新的打上水印的图像 int nWidth = pInputFrame.Width; int nHeight = pInputFrame.Height; Bitmap pOutputFrame = new Bitmap( nWidth, nHeight, pInputFrame.PixelFormat ); Graphics graph = Graphics.FromImage( pOutputFrame ); try { graph.DrawImage( pInputFrame, 0, 0, pInputFrame.Width, pInputFrame.Height ); } catch( Exception error ) { graph.Dispose(); StatusCallback( param, ImageProcessStatusEnum.IPS_FAILED, "Failed to call drawimage." ); return false; } Rectangle rectDest = new Rectangle(); // 计算打水印的位置 if( nWatermarkWidth + param.m_nHorizontalMargin * 2 > nWidth ) { rectDest.X = param.m_nHorizontalMargin; rectDest.Width = (nWidth - param.m_nHorizontalMargin * 2); } else { if( param.m_iWatermarkHAlign == WatermarkHAlignEnum.WHA_LEFT ) { rectDest.X = param.m_nHorizontalMargin; rectDest.Width = nWatermarkWidth; } else if( param.m_iWatermarkHAlign == WatermarkHAlignEnum.WHA_CENTER ) { rectDest.X = (nWidth - nWatermarkWidth)/2; rectDest.Width = nWatermarkWidth; } else { rectDest.X = (nWidth - param.m_nHorizontalMargin - nWatermarkWidth); rectDest.Width = nWatermarkWidth; } } if( nWatermarkHeight + param.m_nVerticalMargin * 2 > nHeight ) { rectDest.Y = param.m_nVerticalMargin; rectDest.Height = (nHeight - param.m_nVerticalMargin * 2); } else { if( param.m_iWatermarkVAlign == WatermarkVAlignEnum.WVA_TOP ) { rectDest.Y = param.m_nVerticalMargin; rectDest.Height= nWatermarkHeight; } else if( param.m_iWatermarkVAlign == WatermarkVAlignEnum.WVA_CENTER ) { rectDest.Y = (nHeight - nWatermarkHeight)/2; rectDest.Height= nWatermarkHeight; } else { rectDest.Y = (nHeight - param.m_nVerticalMargin - nWatermarkHeight); rectDest.Height= nWatermarkHeight; } } try { graph.DrawImage(imgWatermark, rectDest.X, rectDest.Y, rectDest.Width, rectDest.Height); } catch (Exception error) { StatusCallback(param, ImageProcessStatusEnum.IPS_FAILED, "Failed to call drawimage."); return false; } finally { imgWatermark.Dispose(); graph.Dispose(); } ppOutputFrame = pOutputFrame; return true; } else { // 打文字水印 } return false; } } }