C#中基于GDI+(Graphics)图像处理系列之前言

      • 前言
      • 图像处理工具类的全部源码
      • 完整示例程序源码下载
      • 示例程序截图

前言

图像处理是开发工程师们学习某种语言入门时就会遇到的问题,笔者刚开始接触C#使用GDI+进行图像处理,觉得太简单了,就没有深入研究,随着工作经验的积累,踏遍若干坑以后突然觉得还是有必要将这块的知识好好总结一下,毕竟还是有一些比较冷门的知识在实际应用中给我们的程序带来更多的灵活性,比如将图片保存成jpeg时进一步控制图片的质量、怎样获取任意角度旋转后的图像、怎样获取透明图像等等。

本文后面将直接放出图像处理工具类的全部源码和示例程序源码,供有一定开发能力的同学直接获取并使用。

需要深入了解代码的同学可以根据以下章节详细了解功能点的实现,会详细说明获取高质量缩略图的要领、图像旋转的实现步骤等重要内容。

  1. C#中基于GDI+(Graphics)图像处理系列之高质量缩略图
  2. C#中基于GDI+(Graphics)图像处理系列之图片压缩优化(敬请期待)
  3. C#中基于GDI+(Graphics)图像处理系列之任意角度旋转图像
  4. C#中基于GDI+(Graphics)图像处理系列之文字或者图片水印(透明、任意角度旋转)(敬请期待)

图像处理工具类的全部源码

/************************************************************
 * Copyright (C) Corporation. All rights reserved.
 *
 * Author      :  lihaitao
 * Email        : [email protected]com
 * Create Date  :  2016-8-15
 * Description  : 图片处理工具,包括固定宽高、限制宽高、限制长边、文字水印(透明)、图片水印(透明、任意角度旋转)
 *
 *
 * Revision History:
 *      Date         Author               Description
 *      2016-8-15   lihaitao               create
 *
*************************************************************/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.IO;
using System.Runtime.InteropServices;

namespace SDLight.Util
{
    public partial class ImageTool
    {
        #region 变量
        //优化良好的图片每个像素平均占用文件大小,经验值,可根据需要修改
        private static readonly double sizePerPx = 0.18;
        #endregion
        #region 生成高质量缩略图、优化图片
        /// <summary>
        /// 生成高质量缩略图(固定宽高),不一定保持原宽高比
        /// </summary>
        /// <param name="destPath">目标保存路径</param>
        /// <param name="srcPath">源文件路径</param>
        /// <param name="width">生成缩略图的宽度,设置为0,则与源图比处理</param>
        /// <param name="height">生成缩略图的高度,设置为0,则与源图等比例处理</param>
        /// <param name="quality">1~100整数,无效值则取默认值95</param>
        /// <param name="mimeType">如 image/jpeg</param>
        public bool GetThumbnailImage(string destPath, string srcPath, int destWidth, int destHeight, int quality, out string error, string mimeType = "image/jpeg")
        {
            bool retVal = false;
            error = string.Empty;
            //宽高不能小于0
            if (destWidth < 0 || destHeight < 0)
            {
                error = "目标宽高不能小于0";
                return retVal;
            }
            //宽高不能同时为0
            if (destWidth == 0 && destHeight == 0)
            {
                error = "目标宽高不能同时为0";
                return retVal;
            }
            Image srcImage = null;
            Image destImage = null;
            Graphics graphics = null;
            try
            {
                //获取源图像
                srcImage = Image.FromFile(srcPath, false);
                //计算高宽比例
                float d = (float)srcImage.Height / srcImage.Width;
                //如果输入的宽为0,则按高度等比缩放
                if (destWidth == 0)
                {
                    destWidth = Convert.ToInt32(destHeight / d);
                }
                //如果输入的高为0,则按宽度等比缩放
                if (destHeight == 0)
                {
                    destHeight = Convert.ToInt32(destWidth * d);
                }
                //定义画布
                destImage = new Bitmap(destWidth, destHeight);
                //获取高清Graphics
                graphics = GetGraphics(destImage);
                //将源图像画到画布上,注意最后一个参数GraphicsUnit.Pixel
                graphics.DrawImage(srcImage, new Rectangle(0, 0, destWidth, destHeight), new Rectangle(0, 0, srcImage.Width, srcImage.Height), GraphicsUnit.Pixel);
                //如果是覆盖则先释放源资源
                if (destPath == srcPath)
                {
                    srcImage.Dispose();
                }
                //保存到文件,同时进一步控制质量
                SaveImage2File(destPath, destImage, quality, mimeType);
                retVal = true;
            }
            catch (Exception ex)
            {
                error = ex.Message;
            }
            finally
            {
                if (srcImage != null)
                    srcImage.Dispose();
                if (destImage != null)
                    destImage.Dispose();
                if (graphics != null)
                    graphics.Dispose();
            }
            return retVal;
        }
        /// <summary>
        /// 对图片进行压缩优化(限制宽高),始终保持原宽高比
        /// </summary>
        /// <param name="destPath">目标保存路径</param>
        /// <param name="srcPath">源文件路径</param>
        /// <param name="max_Width">压缩后的图片宽度不大于这值,如果为0,表示不限制宽度</param>
        /// <param name="max_Height">压缩后的图片高度不大于这值,如果为0,表示不限制高度</param>
        /// <param name="quality">1~100整数,无效值则取默认值95</param>
        /// <param name="mimeType">如 image/jpeg</param>
        public bool GetCompressImage(string destPath, string srcPath, int maxWidth, int maxHeight, int quality, out string error,string mimeType = "image/jpeg")
        {
            bool retVal = false;
            error = string.Empty;
            //宽高不能小于0
            if (maxWidth < 0 || maxHeight < 0)
            {
                error = "目标宽高不能小于0";
                return retVal;
            }
            Image srcImage = null;
            Image destImage = null;
            Graphics graphics = null;
            try
            {
                //获取源图像
                srcImage = Image.FromFile(srcPath, false);
                FileInfo fileInfo = new FileInfo(srcPath);
                //目标宽度
                var destWidth = srcImage.Width;
                //目标高度
                var destHeight = srcImage.Height;
                //如果输入的最大宽为0,则不限制宽度
                //如果不为0,且原图宽度大于该值,则附值为最大宽度
                if (maxWidth != 0 && destWidth > maxWidth)
                {
                    destWidth = maxWidth;
                }
                //如果输入的最大宽为0,则不限制宽度
                //如果不为0,且原图高度大于该值,则附值为最大高度
                if (maxHeight != 0 && destHeight > maxHeight)
                {
                    destHeight = maxHeight;
                }
                float srcD = (float)srcImage.Height / srcImage.Width;
                float destD = (float)destHeight / destWidth;
                //目的高宽比 大于 原高宽比 即目的高偏大,因此按照原比例计算目的高度
                if (destD > srcD)
                {
                    destHeight = Convert.ToInt32(destWidth * srcD);
                }
                else if (destD < srcD) //目的高宽比 小于 原高宽比 即目的宽偏大,因此按照原比例计算目的宽度
                {
                    destWidth = Convert.ToInt32(destHeight / srcD);
                }
                //如果维持原宽高,则判断是否需要优化
                if (destWidth == srcImage.Width && destHeight == srcImage.Height &&
                    fileInfo.Length < destWidth * destHeight * sizePerPx)
                {
                    error = "图片不需要压缩优化";
                    return retVal;
                }
                //定义画布
                destImage = new Bitmap(destWidth, destHeight);
                //获取高清Graphics
                graphics = GetGraphics(destImage);
                //将源图像画到画布上,注意最后一个参数GraphicsUnit.Pixel
                graphics.DrawImage(srcImage, new Rectangle(0, 0, destWidth, destHeight), new Rectangle(0, 0, srcImage.Width, srcImage.Height), GraphicsUnit.Pixel);
                //如果是覆盖则先释放源资源
                if (destPath == srcPath)
                {
                    srcImage.Dispose();
                }
                //保存到文件,同时进一步控制质量
                SaveImage2File(destPath, destImage, quality, mimeType);
                retVal = true;

            }
            catch (Exception ex)
            {
                error = ex.Message;
            }
            finally
            {
                if (srcImage != null)
                    srcImage.Dispose();
                if (destImage != null)
                    destImage.Dispose();
                if (graphics != null)
                    graphics.Dispose();
            }
            return retVal;
        }
        /// <summary>
        /// 对图片进行压缩优化,始终保持原宽高比,限制长边长度,常用场景:相片
        /// </summary>
        /// <param name="destPath">目标保存路径</param>
        /// <param name="srcPath">源文件路径</param>
        /// <param name="max_Length">压缩后的图片边(宽或者高)长变不大于这值,为0表示不限制</param>
        /// <param name="quality">1~100整数,无效值,则取默认值95</param>
        /// <param name="mimeType">如 image/jpeg</param>
        public bool GetCompressImage(string destPath, string srcPath, int maxLength, int quality, out string error, string mimeType = "image/jpeg")
        {
            bool retVal = false;
            error = string.Empty;
            //最大边长不能小于0
            if (maxLength < 0)
            {
                error = "最大边长不能小于0";
                return retVal;
            }
            Image srcImage = null;
            Image destImage = null;
            Graphics graphics = null;
            try
            {
                //获取源图像
                srcImage = Image.FromFile(srcPath, false);
                FileInfo fileInfo = new FileInfo(srcPath);
                //目标宽度
                var destWidth = srcImage.Width;
                //目标高度
                var destHeight = srcImage.Height;
                //如果限制
                if (maxLength > 0)
                {
                    //原高宽比
                    float srcD = (float)srcImage.Height / srcImage.Width;
                    //如果宽>高,且大于 限制
                    if (destWidth > destHeight && destWidth > maxLength)
                    {
                        destWidth = maxLength;
                        destHeight = Convert.ToInt32(destWidth * srcD);
                    }
                    else
                    {
                        if (destHeight > maxLength)
                        {
                            destHeight = maxLength;
                            destWidth = Convert.ToInt32(destHeight / srcD);
                        }
                    }
                }
                //如果维持原宽高,则判断是否需要优化
                if (destWidth == srcImage.Width && destHeight == srcImage.Height &&
                    fileInfo.Length < destWidth * destHeight * sizePerPx)
                {
                    error = "图片不需要压缩优化";
                    return retVal;
                }
                //定义画布
                destImage = new Bitmap(destWidth, destHeight);
                //获取高清Graphics
                graphics = GetGraphics(destImage);
                //将源图像画到画布上,注意最后一个参数GraphicsUnit.Pixel
                graphics.DrawImage(srcImage, new Rectangle(0, 0, destWidth, destHeight), new Rectangle(0, 0, srcImage.Width, srcImage.Height), GraphicsUnit.Pixel);
                //如果是覆盖则先释放源资源
                if (destPath == srcPath)
                {
                    srcImage.Dispose();
                }
                //保存到文件,同时进一步控制质量
                SaveImage2File(destPath, destImage, quality, mimeType);
                retVal = true;
            }
            catch (Exception ex)
            {
                error = ex.Message;
            }
            finally
            {
                if (srcImage != null)
                    srcImage.Dispose();
                if (destImage != null)
                    destImage.Dispose();
                if (graphics != null)
                    graphics.Dispose();
            }
            return retVal;
        }
        #endregion
        #region 从图片中挖取一块区域
        /// <summary>
        /// 从源图片中挖取一块区域保存为新图片
        /// </summary>
        /// <param name="destPath">保存路径</param>
        /// <param name="srcPath">源路径,两个路径可以相同,相同则会覆盖源图片</param>
        /// <param name="x">挖取区域左上角x值</param>
        /// <param name="y">挖取区域左上角y值</param>
        /// <param name="width">挖取区域的宽度</param>
        /// <param name="height">挖取区域的高度</param>
        /// <param name="quality">1~100整数,无效值,则取默认值95</param>
        /// <param name="error"></param>
        /// <param name="mimeType"></param>
        /// <returns></returns>
        public bool GetDigImage(string destPath, string srcPath, int x, int y, int width, int height, int quality, out string error, string mimeType = "image/jpeg")
        {
            bool retVal = false;
            error = string.Empty;
            Image srcImage = null;
            Image destImage = null;
            Graphics graphics = null;
            try
            {
                //获取源图像
                srcImage = Image.FromFile(srcPath, false);
                //定义画布
                destImage = new Bitmap(width, height);
                //获取高清Graphics
                graphics = GetGraphics(destImage);
                //将源图像的某区域画到新画布上,注意最后一个参数GraphicsUnit.Pixel
                graphics.DrawImage(srcImage, new Rectangle(0, 0, width, height), new Rectangle(x, y, width, height), GraphicsUnit.Pixel);
                //如果是覆盖则先释放源资源
                if (destPath == srcPath)
                {
                    srcImage.Dispose();
                }
                //保存到文件,同时进一步控制质量
                SaveImage2File(destPath, destImage, quality, mimeType);
                retVal = true;
            }
            catch (Exception ex)
            {
                error = ex.Message;
            }
            finally
            {
                if (srcImage != null)
                    srcImage.Dispose();
                if (destImage != null)
                    destImage.Dispose();
                if (graphics != null)
                    graphics.Dispose();
            }
            return retVal;
        }
        #endregion
        #region 在图片加入文字水印或者图片水印,并控制水印透明度,图片水印还可以控制旋转角度
        /// <summary>
        /// 给图片加入文字水印,且设置水印透明度
        /// </summary>
        /// <param name="destPath">保存地址</param>
        /// <param name="srcPath">源文件地址,如果想覆盖源图片,两个地址参数一定要一样</param>
        /// <param name="text">文字</param>
        /// <param name="font">字体,为空则使用默认,注意,在创建字体时 GraphicsUnit.Pixel </param>
        /// <param name="brush">刷子,为空则使用默认</param>
        /// <param name="pos">设置水印位置,1左上,2中上,3右上
        ///                                 4左中,5中,  6右中
        ///                                 7左下,8中下,9右下</param>
        /// <param name="padding">跟css里的padding一个意思</param>
        /// <param name="quality">1~100整数,无效值,则取默认值95</param>
        /// <param name="opcity">不透明度  100 为完全不透明,0为完全透明</param>
        /// <param name="error"></param>
        /// <param name="mimeType"></param>
        /// <returns></returns>
        public bool DrawWaterText(string destPath, string srcPath, string text, Font font, Brush brush, int pos, int padding, int quality, int opcity, out string error, string mimeType = "image/jpeg")
        {
            bool retVal = false;
            error = string.Empty;
            Image srcImage = null;
            Image destImage = null;
            Graphics graphics = null;
            if (font == null)
            {
                font = new Font("微软雅黑", 20, FontStyle.Bold, GraphicsUnit.Pixel);//统一尺寸
            }
            if (brush == null)
            {
                brush = new SolidBrush(Color.White);
            }
            try
            {
                //获取源图像
                srcImage = Image.FromFile(srcPath, false);
                //定义画布,大小与源图像一样
                destImage = new Bitmap(srcImage);
                //获取高清Graphics
                graphics = GetGraphics(destImage);
                //将源图像画到画布上,注意最后一个参数GraphicsUnit.Pixel
                graphics.DrawImage(srcImage, new Rectangle(0, 0, destImage.Width, destImage.Height), new Rectangle(0, 0, srcImage.Width, srcImage.Height), GraphicsUnit.Pixel);
                //如果水印字不为空,且不透明度大于0,则画水印
                if (!string.IsNullOrEmpty(text) && opcity > 0)
                {
                    //获取可以用来绘制水印图片的有效区域
                    Rectangle validRect = new Rectangle(padding, padding, srcImage.Width - padding * 2, srcImage.Height - padding * 2);
                    //获取绘画水印文字的格式,即文字对齐方式
                    StringFormat format = GetStringFormat(pos);
                    //如果不透明度==100,那么直接将字画到当前画布上.
                    if (opcity == 100)
                    {
                        graphics.DrawString(text, font, brush, validRect, format);
                    }
                    else
                    {
                        //如果不透明度在0到100之间,就要实现透明效果,文字没法透明,图片才能透明
                        //则先将字画到一块临时画布,临时画布与destImage一样大,先将字写到这块画布上,再将临时画布画到主画布上,同时设置透明参数
                        Bitmap transImg = null;
                        Graphics gForTransImg = null;
                        try
                        {
                            //定义临时画布
                            transImg = new Bitmap(destImage);
                            //获取高清Graphics
                            gForTransImg = GetGraphics(transImg);
                            //绘制文字
                            gForTransImg.DrawString(text, font, brush, validRect, format);
                            //**获取带有透明度的ImageAttributes
                            ImageAttributes imageAtt = GetAlphaImgAttr(opcity);
                            //将这块临时画布画在主画布上
                            graphics.DrawImage(transImg, new Rectangle(0, 0, destImage.Width, destImage.Height), 0, 0, transImg.Width, transImg.Height, GraphicsUnit.Pixel, imageAtt);
                        }
                        catch (Exception ex)
                        {
                            error = ex.Message;
                            return retVal;
                        }
                        finally
                        {
                            if (transImg != null)
                                transImg.Dispose();
                            if (gForTransImg != null)
                                gForTransImg.Dispose();
                        }
                    }
                }
                //如果两个地址相同即覆盖,则提前Dispose源资源
                if (destPath.ToLower() == srcPath.ToLower())
                {
                    srcImage.Dispose();
                }
                //保存到文件,同时进一步控制质量
                SaveImage2File(destPath, destImage, quality, mimeType);
                retVal = true;
            }
            catch (Exception ex)
            {
                error = ex.Message;
            }
            finally
            {
                if (srcImage != null)
                    srcImage.Dispose();
                if (destImage != null)
                    destImage.Dispose();
                if (graphics != null)
                    graphics.Dispose();
            }
            return retVal;
        }
        /// <summary>
        /// 给图片加入图片水印,且设置水印透明度,旋转角度
        /// </summary>
        /// <param name="destPath">保存地址</param>
        /// <param name="srcPath">源文件地址,如果想覆盖源图片,两个地址参数一定要一样</param>
        /// <param name="waterPath">水印图片地址</param>
        /// <param name="pos">设置水印位置,1左上,2中上,3右上
        ///                                 4左中,5中,  6右中
        ///                                 7左下,8中下,9右下</param>
        /// <param name="padding">跟css里的padding一个意思</param>
        /// <param name="quality">1~100整数,无效值,则取默认值95</param>
        /// <param name="opcity">不透明度  100 为完全不透明,0为完全透明</param>
        /// <param name="angle">顺时针旋转角度</param>
        /// <param name="error"></param>
        /// <param name="mimeType"></param>
        /// <returns></returns>
        public bool DrawWaterImage(string destPath, string srcPath, string waterPath, int pos, int padding, int quality, int opcity, int angle, out string error, string mimeType = "image/jpeg")
        {
            bool retVal = false;
            error = string.Empty;
            Image srcImage = null;
            Image waterImage = null;
            Image destImage = null;
            Graphics graphics = null;
            try
            {
                //获取原图
                srcImage = Image.FromFile(srcPath, false);
                //获取水印图片
                waterImage = Image.FromFile(waterPath, false);
                var waterRect = new Rectangle(0, 0, waterImage.Width, waterImage.Height);
                //定义画布
                destImage = new Bitmap(srcImage);
                //获取高清Graphics
                graphics = GetGraphics(destImage);
                //将源图画到画布上
                graphics.DrawImage(srcImage, new Rectangle(0, 0, destImage.Width, destImage.Height), new Rectangle(0, 0, srcImage.Width, srcImage.Height), GraphicsUnit.Pixel);
                //不透明度大于0,则画水印
                if (opcity > 0)
                {
                    //获取可以用来绘制水印图片的有效区域
                    Rectangle validRect = new Rectangle(padding, padding, srcImage.Width - padding * 2, srcImage.Height - padding * 2);
                    //如果要进行旋转
                    if (angle != 0)
                    {
                        Image rotateImage = null;
                        try
                        {
                            //获取水印图像旋转后的图像
                            rotateImage = GetRotateImage(waterImage, angle);
                            if (rotateImage != null)
                            {
                                //旋转后图像的矩形区域
                                var rotateRect = new Rectangle(0, 0, rotateImage.Width, rotateImage.Height);
                                //计算水印图片的绘制位置
                                var destRect = GetRectangleByPostion(validRect, rotateRect, pos);
                                //如果不透明度>=100,那么直接将水印画到当前画布上.
                                if (opcity == 100)
                                {
                                    graphics.DrawImage(rotateImage, destRect, rotateRect, GraphicsUnit.Pixel);
                                }
                                else
                                {
                                    //如果不透明度在0到100之间,设置透明参数
                                    ImageAttributes imageAtt = GetAlphaImgAttr(opcity);
                                    //将旋转后的图片画到画布上
                                    graphics.DrawImage(rotateImage, destRect, 0, 0, rotateRect.Width, rotateRect.Height, GraphicsUnit.Pixel, imageAtt);
                                }
                            }
                        }
                        catch (Exception ex)
                        {
                            error = ex.Message;
                            return retVal;

                        }
                        finally
                        {
                            if (rotateImage != null)
                                rotateImage.Dispose();
                        }
                    }
                    else
                    {
                        //计算水印图片的绘制位置
                        var destRect = GetRectangleByPostion(validRect, waterRect, pos);
                        //如果不透明度=100,那么直接将水印画到当前画布上.
                        if (opcity == 100)
                        {
                            graphics.DrawImage(waterImage, destRect, waterRect, GraphicsUnit.Pixel);
                        }
                        else
                        {
                            //如果不透明度在0到100之间,设置透明参数
                            ImageAttributes imageAtt = GetAlphaImgAttr(opcity);
                            //将水印图片画到画布上
                            graphics.DrawImage(waterImage, destRect, 0, 0, waterRect.Width, waterRect.Height, GraphicsUnit.Pixel, imageAtt);

                        }
                    }

                }
                //如果两个地址相同即覆盖,则提前Dispose源资源
                if (destPath.ToLower() == srcPath.ToLower())
                {
                    srcImage.Dispose();
                }
                SaveImage2File(destPath, destImage, quality, mimeType);
                retVal = true;
            }
            catch (Exception ex)
            {
                error = ex.Message;
            }
            finally
            {
                if (srcImage != null)
                    srcImage.Dispose();
                if (destImage != null)
                    destImage.Dispose();
                if (graphics != null)
                    graphics.Dispose();
                if (waterImage != null)
                    waterImage.Dispose();
            }
            return retVal;
        }
        #endregion
        #region 共用方法
        /// <summary>
        /// 将Image实例保存到文件,注意此方法不执行 img.Dispose()
        /// 图片保存时本可以直接使用destImage.Save(path, ImageFormat.Jpeg),但是这种方法无法进行进一步控制图片质量
        /// </summary>
        /// <param name="path"></param>
        /// <param name="img"></param>
        /// <param name="quality">1~100整数,无效值,则取默认值95</param>
        /// <param name="mimeType"></param>
        public void SaveImage2File(string path, Image destImage, int quality, string mimeType = "image/jpeg")
        {
            if (quality <= 0 || quality > 100) quality = 95;
            //创建保存的文件夹
            FileInfo fileInfo = new FileInfo(path);
            if (!Directory.Exists(fileInfo.DirectoryName))
            {
                Directory.CreateDirectory(fileInfo.DirectoryName);
            }
            //设置保存参数,保存参数里进一步控制质量
            EncoderParameters encoderParams = new EncoderParameters();
            long[] qua = new long[] { quality };
            EncoderParameter encoderParam = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, quality);
            encoderParams.Param[0] = encoderParam;
            //获取指定mimeType的mimeType的ImageCodecInfo
            var codecInfo = ImageCodecInfo.GetImageEncoders().FirstOrDefault(ici => ici.MimeType == mimeType);
            destImage.Save(path, codecInfo, encoderParams);
        }
        /// <summary>
        /// 获取高清的Graphics
        /// </summary>
        /// <param name="img"></param>
        /// <returns></returns>
        public Graphics GetGraphics(Image img)
        {
            var g = Graphics.FromImage(img);
            //设置质量
            g.SmoothingMode = SmoothingMode.HighQuality;
            g.CompositingQuality = CompositingQuality.HighQuality;
            //InterpolationMode不能使用High或者HighQualityBicubic,如果是灰色或者部分浅色的图像是会在边缘处出一白色透明的线
            //用HighQualityBilinear却会使图片比其他两种模式模糊(需要肉眼仔细对比才可以看出)
            g.InterpolationMode = InterpolationMode.Default;
            g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias;
            return g;
        }
        /// <summary>
        /// 获取文字水印位置
        /// </summary>
        /// <param name="pos">
        ///         1左上,2中上,3右上
        ///         4左中,5中,  6右中
        ///         7左下,8中下,9右下
        /// </param>
        /// <returns></returns>
        public StringFormat GetStringFormat(int pos)
        {
            StringFormat format = new StringFormat();
            switch (pos)
            {
                case 1: format.Alignment = StringAlignment.Near; format.LineAlignment = StringAlignment.Near; break;
                case 2: format.Alignment = StringAlignment.Center; format.LineAlignment = StringAlignment.Near; break;
                case 3: format.Alignment = StringAlignment.Far; format.LineAlignment = StringAlignment.Near; break;
                case 4: format.Alignment = StringAlignment.Near; format.LineAlignment = StringAlignment.Center; break;
                case 6: format.Alignment = StringAlignment.Far; format.LineAlignment = StringAlignment.Center; break;
                case 7: format.Alignment = StringAlignment.Near; format.LineAlignment = StringAlignment.Far; break;
                case 8: format.Alignment = StringAlignment.Center; format.LineAlignment = StringAlignment.Far; break;
                case 9: format.Alignment = StringAlignment.Far; format.LineAlignment = StringAlignment.Far; break;
                default: format.Alignment = StringAlignment.Center; format.LineAlignment = StringAlignment.Center; break;
            }
            return format;
        }
        /// <summary>
        /// 获取图片水印位置,及small在big里的位置
        /// 如果small的高度大于big的高度,返回big的高度
        /// 如果small的宽度大于big的宽度,返回big的宽度
        /// </summary>
        /// <param name="pos">
        ///         1左上,2中上,3右上
        ///         4左中,5中,  6右中
        ///         7左下,8中下,9右下
        /// </param>
        /// <returns></returns>
        public Rectangle GetRectangleByPostion(Rectangle big, Rectangle small, int pos)
        {
            if (big.Width < small.Width)
            {
                small.Width = big.Width;
            }
            if (big.Height < small.Height)
            {
                small.Height = big.Height;
            }
            Rectangle retVal = small;
            switch (pos)
            {
                case 1: retVal.X = 0; retVal.Y = 0; break;
                case 2: retVal.X = (big.Width - small.Width) / 2; retVal.Y = 0; break;
                case 3: retVal.X = big.Width - small.Width; retVal.Y = 0; break;
                case 4: retVal.X = 0; retVal.Y = (big.Height - small.Height) / 2; break;
                case 6: retVal.X = big.Width - small.Width; retVal.Y = (big.Height - small.Height) / 2; break;
                case 7: retVal.X = 0; retVal.Y = big.Height - small.Height; break;
                case 8: retVal.X = (big.Width - small.Width) / 2; retVal.Y = big.Height - small.Height; break;
                case 9: retVal.X = big.Width - small.Width; retVal.Y = big.Height - small.Height; break;
                default: retVal.X = (big.Width - small.Width) / 2; retVal.Y = (big.Height - small.Height) / 2; break;
            }
            retVal.X += big.X;
            retVal.Y += big.Y;
            return retVal;
        }
        /// <summary>
        /// 获取一个带有透明度的ImageAttributes
        /// </summary>
        /// <param name="opcity"></param>
        /// <returns></returns>
        public ImageAttributes GetAlphaImgAttr(int opcity)
        {
            if (opcity < 0 || opcity > 100)
            {
                throw new ArgumentOutOfRangeException("opcity 值为 0~100");
            }
            //颜色矩阵
            float[][] matrixItems =
            {
                new float[]{1,0,0,0,0},
                new float[]{0,1,0,0,0},
                new float[]{0,0,1,0,0},
                new float[]{0,0,0,(float)opcity / 100,0},
                new float[]{0,0,0,0,1}
            };
            ColorMatrix colorMatrix = new ColorMatrix(matrixItems);
            ImageAttributes imageAtt = new ImageAttributes();
            imageAtt.SetColorMatrix(colorMatrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap);
            return imageAtt;
        }
        /// <summary>
        /// 计算矩形绕中心任意角度旋转后所占区域矩形宽高
        /// </summary>
        /// <param name="width">原矩形的宽</param>
        /// <param name="height">原矩形高</param>
        /// <param name="angle">顺时针旋转角度</param>
        /// <returns></returns>
        public Rectangle GetRotateRectangle(int width, int height, float angle)
        {
            double radian = angle * Math.PI / 180; ;
            double cos = Math.Cos(radian);
            double sin = Math.Sin(radian);
            //只需要考虑到第四象限和第三象限的情况取大值(中间用绝对值就可以包括第一和第二象限)
            int newWidth = (int)(Math.Max(Math.Abs(width * cos - height * sin), Math.Abs(width * cos + height * sin)));
            int newHeight = (int)(Math.Max(Math.Abs(width * sin - height * cos), Math.Abs(width * sin + height * cos)));
            return new Rectangle(0, 0, newWidth, newHeight);
        }
        /// <summary>
        /// 获取原图像绕中心任意角度旋转后的图像
        /// </summary>
        /// <param name="rawImg"></param>
        /// <param name="angle"></param>
        /// <returns></returns>
        public Image GetRotateImage(Image srcImage, int angle)
        {
            angle = angle % 360;
            //原图的宽和高
            int srcWidth = srcImage.Width;
            int srcHeight = srcImage.Height;
            //图像旋转之后所占区域宽和高
            Rectangle rotateRec = GetRotateRectangle(srcWidth, srcHeight, angle);
            int rotateWidth = rotateRec.Width;
            int rotateHeight = rotateRec.Height;
            //目标位图
            Bitmap destImage = null;
            Graphics graphics = null;
            try
            {
                //定义画布,宽高为图像旋转后的宽高
                destImage = new Bitmap(rotateWidth, rotateHeight);
                //graphics根据destImage创建,因此其原点此时在destImage左上角
                graphics = Graphics.FromImage(destImage);
                //要让graphics围绕某矩形中心点旋转N度,分三步
                //第一步,将graphics坐标原点移到矩形中心点,假设其中点坐标(x,y)
                //第二步,graphics旋转相应的角度(沿当前原点)
                //第三步,移回(-x,-y)
                //获取画布中心点
                Point centerPoint = new Point(rotateWidth / 2, rotateHeight / 2);
                //将graphics坐标原点移到中心点
                graphics.TranslateTransform(centerPoint.X, centerPoint.Y);
                //graphics旋转相应的角度(绕当前原点)
                graphics.RotateTransform(angle);
                //恢复graphics在水平和垂直方向的平移(沿当前原点)
                graphics.TranslateTransform(-centerPoint.X, -centerPoint.Y);
                //此时已经完成了graphics的旋转

                //计算:如果要将源图像画到画布上且中心与画布中心重合,需要的偏移量
                Point Offset = new Point((rotateWidth - srcWidth) / 2, (rotateHeight - srcHeight) / 2);
                //将源图片画到rect里(rotateRec的中心)
                graphics.DrawImage(srcImage, new Rectangle(Offset.X, Offset.Y, srcWidth, srcHeight));
                //重至绘图的所有变换
                graphics.ResetTransform();
                graphics.Save();
            }
            catch (Exception ex)
            {
                throw ex;
            }
            finally
            {
                if (graphics != null)
                    graphics.Dispose();
            }
            return destImage;
        }
        #endregion
    }
}

完整示例程序源码下载

http://download.csdn.net/detail/lhtzbj12/9730116

示例程序截图

时间: 2024-10-22 05:27:41

C#中基于GDI+(Graphics)图像处理系列之前言的相关文章

android图像处理系列之五--给图片添加边框(中)

前面一篇讲到给图片加边框的方式,只能给图片加一些有规则的边框,如果想加一些比较精美的效果,就有点麻烦了.下面就给出解决这个问题的思路. 思路是:一些比较精美的花边图片我们是很难用代码控制,就目前本人水平是达不到,不排除牛人,再说了PS那些效果都是程序员做出来,肯定有实现的方法,这可能就要涉及很复杂的图形学.扯远了,接来说怎么用那些精美的花边做为图片的边框.简单的方式是用两张图片叠加.最简单的一种是本文介绍的,用透明的PNG格式图片.因为Android是支持PNG图片处理的,而且PNG图片有透明度

C# (GDI+相关) 图像处理(各种旋转、改变大小、柔化、锐化、雾化、底片、浮雕、黑白、滤镜效果)

原文:C# (GDI+相关) 图像处理(各种旋转.改变大小.柔化.锐化.雾化.底片.浮雕.黑白.滤镜效果) C#图像处理   (各种旋转.改变大小.柔化.锐化.雾化.底片.浮雕.黑白.滤镜效果)     一.各种旋转.改变大小   注意:先要添加画图相关的using引用.   //向右旋转图像90°代码如下: private void Form1_Paint(object sender, System.Windows.Forms.PaintEventArgs e) {   Graphics g

MFC中的GDI绘图&lt;转&gt;

一.关于GDI的基本概念 什么是GDI? Windows绘图的实质就是利用Windows提供的图形设备接口GDI(Graphics Device Interface)将图形绘制在显示器上. 在Windows操作系统中,动态链接库C:\WINDOWS\system32\gdi32.dll(GDI Client DLL)中定义了GDI函数,实现与设备无关的包括屏幕上输出像素.在打印机上输出硬拷贝以及绘制Windows用户界面功能.在Visual C++6.0中的头文件C:\Program Files

HLS图像处理系列——在ZEDBoard搭建DDR图像处理通路

ZYNQ芯片内包含一个丰富特性的基于双核ARM Cortex-A9的处理子系统(Processing System,PS)和Xilinx 28nm可编程逻辑(Programmable Logic,PL).PS除了核心外还包括片上存储器.外部存储器接口以及大量外设连接接口. 利用ARM,我们可以做嵌入式操作系统相关的任务,如图形界面.用户输入.网络.DDR3控制等,由于ARM本身具有丰富的外设接口,而且支持多级流水线,处理这些事务游刃有余,但对于计算量较大的应用却捉襟见肘,因为ARM本身还是典型的

GDI+学习笔记(九)带插件的排序算法演示器(MFC中的GDI+实例)

带插件的排序算法演示器 本节将通过一个实例来说明GDI+在MFC中的应用.这个算法演示器其实是本人算法系列的一个开端,由于csdn没有树状的目录结构,咱也只好使用链表了不是?好了,废话不多说,开始今天的文章. (一)功能说明 我们初步制定功能如下: (1). 能够通过柱状图,自动展示排序算法的交换比较过程 (2). 能够使用插件的形式进行开发.即,当新完成一个算法后,只需要完成一个插件文件(我们这里使用动态库dll),由主程序加载插件,即可进行执行,而不再需要重新编译主程序. (3). 保证主程

[我给Unity官方视频教程做中文字幕]beginner Graphics – Lessons系列之纹理Textures

[我给Unity官方视频教程做中文字幕]beginner Graphics – Lessons系列之纹理Textures 本篇分享一下第6个已完工的视频,即<beginner Graphics – Lessons系列之纹理Textures>.听译.时间轴.压制者均为本人.请勿将视频用于非法目的. 有需要高清视频的同学麻烦点个赞并留下你的Email~ 有视频有真相 视频中的重点 纹理是一个图片文件 Unity有多种使用纹理的方式最常见的方式是把纹理赋给网格的基础纹理属性使网格具有纹理的表面 纹理

MFC中的GDI绘图(1)

一.关于GDI的基本概念 什么是GDI         Windows绘图的实质就是利用Windows提供的图形设备接口GDI(Graphics Device Interface)将图形绘制在显示器上. 在Windows操作系统中,动态链接库C:\WINDOWS\system32\gdi32.dll(GDI Client DLL)中定义了GDI函数,实现与设备无关的包括屏幕上输出像素.在打印机上输出硬拷贝以及绘制Windows用户界面功能.在Visual C++6.0中的头文件C:\Progra

vs2008中使用gdi+的设置

vs2008中使用gdi+ 1.新建一个mfc工程 2.在stdafx.h文件中加入以下几行语句:#include <gdiplus.h>                //#pragma comment(lib, "gdiplus.lib") //在工程属性中添加亦可using namespace Gdiplus;            //使用GDI+的命名空间, 若不用的话每次使用Gdiplus时均加上命名空间亦可 3.修改App类在App类(以下例子中为CTestA

Delphi中使用GDI+进行绘图(1)

Delphi的VCL类库中,默认使用的是GDI绘图接口,该接口封装了Win32 GDI接口,能够满足基本的绘图功能,但如果要实现更高级的绘图功能,往往比较困难,GDI+是微软在GDI之后的一个图形接口,功能比GDI丰富很多,在VCL中使用GDI+,能够实现很多高级绘图功能. 目前有多种Delphi对GDI+的封装实现,以下介绍最简单的两种: 1.使用Delphi内置的GDI+接口 首先,创建一个VCL Form应用,窗口文件如下: Pascal Code 12345678910111213141