最近想做一个图片缩放的软件,能批量处理一批图片,并且能够在图片添加水印文字和水印logo。从网上参考的核心代码如下:
1.合并两个图片
/// <summary>
/// 合并两张图片,支持不透明度和透明色
/// </summary>
/// <param name="b0">图片一</param>
/// <param name="b1">图片二</param>
/// <param name="X">起始坐标X</param>
/// <param name="Y">起始坐标Y</param>
/// <param name="b1_alpha">图片二的不透明度</param>
/// <param name="TransColor">被作为透明色处理的颜色</param>
/// <param name="delta">透明色的容差,类似Ps中的魔棒的容差。</param>
/// <returns>合并后的图片</returns>
public static Bitmap KiMerge(Bitmap b0, Bitmap b1, int X, int Y, int b1_alpha,Color TransColor,int delta)
{
if (b0.Equals(null) || b1.Equals(null))
{
return null;
}
int w0 = b0.Width;
int h0 = b0.Height;
int w1 = b1.Width;
int h1 = b1.Height;
int w, h;
if (X + w1 > w0)
{
w = w0 - X;
}
else
{
w = w1;
}
if (Y + h1 > h0)
{
h = h0 - Y;
}
else
{
h = h1;
}
BitmapData srcData = b0.LockBits(new Rectangle(X, Y, w, h), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
BitmapData dstData = b1.LockBits(new Rectangle(0, 0, w, h), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
unsafe
{
byte* pIn = (byte*)srcData.Scan0.ToPointer();
byte* pLogo = (byte*)dstData.Scan0.ToPointer();
for (int y = 0; y < h; y++)
{
for (int x = 0; x < w; x++)
{
// 判断透明色
Color c = Color.FromArgb(pLogo[2], pLogo[1], pLogo[0]);
if (!ColorIsSimilar(c, TransColor, delta))
{
float bili = (float)b1_alpha / (float)255; // 不是透明色,加权平均
float inbili = 1.0f - bili;
int r, g, b;
b = (int)(pIn[0] * inbili + pLogo[0] * bili);
g = (int)(pIn[1] * inbili + pLogo[1] * bili);
r = (int)(pIn[2] * inbili + pLogo[2] * bili);
pIn[0] = (byte)b;
pIn[1] = (byte)g;
pIn[2] = (byte)r;
}
pIn += 3;
pLogo += 3;
}
pIn += srcData.Stride - w * 3;
pLogo += dstData.Stride - w * 3;
}
b0.UnlockBits(srcData);
b1.UnlockBits(dstData);
}
return b0;
}
2.图片缩放(1)
//************************************************************//
//下面给出三个简单的方法,后面两个方法是扩展,估计有时用得着
//************************************************************//
/// <summary>
/// 缩小图片
/// </summary>
/// <param name="strOldPic">源图文件名(包括路径)</param>
/// <param name="strNewPic">缩小后保存为文件名(包括路径)</param>
/// <param name="intWidth">缩小至宽度</param>
/// <param name="intHeight">缩小至高度</param>
public void SmallPic(string strOldPic, string strNewPic, int intWidth, int intHeight)
{
System.Drawing.Bitmap objPic,objNewPic;
try
{
objPic = new System.Drawing.Bitmap(strOldPic);
objNewPic=new System.Drawing.Bitmap(objPic,intWidth,intHeight);
objNewPic.Save(strNewPic);
}
catch(Exception exp){throw exp;}
finally
{
objPic=null;
objNewPic=null;
}
}
/// <summary>
/// 按比例缩小图片,自动计算高度
/// </summary>
/// <param name="strOldPic">源图文件名(包括路径)</param>
/// <param name="strNewPic">缩小后保存为文件名(包括路径)</param>
/// <param name="intWidth">缩小至宽度</param>
public void SmallPic(string strOldPic, string strNewPic, int intWidth)
{
System.Drawing.Bitmap objPic,objNewPic;
try
{
objPic = new System.Drawing.Bitmap(strOldPic);
int intHeight=(intWidth / objPic.Width) * objPic.Height;
objNewPic=new System.Drawing.Bitmap(objPic,intWidth,intHeight);
objNewPic.Save(strNewPic);
}
catch(Exception exp){throw exp;}
finally
{
objPic=null;
objNewPic=null;
}
}
/// <summary>
/// 按比例缩小图片,自动计算宽度
/// </summary>
/// <param name="strOldPic">源图文件名(包括路径)</param>
/// <param name="strNewPic">缩小后保存为文件名(包括路径)</param>
/// <param name="intHeight">缩小至高度</param>
public void SmallPic(string strOldPic, string strNewPic, int intHeight)
{
System.Drawing.Bitmap objPic,objNewPic;
try
{
objPic = new System.Drawing.Bitmap(strOldPic);
int intWidth=(intHeight / objPic.Height) * objPic.Width;
objNewPic=new System.Drawing.Bitmap(objPic,intWidth,intHeight);
objNewPic.Save(strNewPic);
}
catch(Exception exp){throw exp;}
finally
{
objPic=null;
objNewPic=null;
}
}
//************************************************************//
图片缩放(2)效果最好的。
图片无损缩放
* 一个图片缩放的类
*
********************************************************************/
using System;
using System.IO;
using System.Drawing;
using System.Drawing.Imaging;
using System.Drawing.Drawing2D;
namespace ZHT.Utility.Share
{
public class Thumbnail
{
public Thumbnail()
{
}
/// <SUMMARY>
/// 图片缩放
/// </SUMMARY>
/// <PARAM name="sourceFile">图片源路径</PARAM>
/// <PARAM name="destFile">缩放后图片输出路径</PARAM>
/// <PARAM name="destHeight">缩放后图片高度</PARAM>
/// <PARAM name="destWidth">缩放后图片宽度</PARAM>
/// <RETURNS></RETURNS>
public static bool GetThumbnail(string sourceFile, string destFile, int destHeight, int destWidth)
{
System.Drawing.Image imgSource = System.Drawing.Image.FromFile(sourceFile);
System.Drawing.Imaging.ImageFormat thisFormat = imgSource.RawFormat;
int sW = 0, sH = 0;
// 按比例缩放
int sWidth = imgSource.Width;
int sHeight = imgSource.Height;
if(sHeight>destHeight || sWidth>destWidth)
{
if((sWidth*destHeight)>(sHeight*destWidth))
{
sW = destWidth;
sH = (destWidth*sHeight)/sWidth;
}
else
{
sH = destHeight;
sW = (sWidth*destHeight)/sHeight;
}
}
else
{
sW = sWidth;
sH = sHeight;
}
Bitmap outBmp = new Bitmap(destWidth, destHeight);
Graphics g = Graphics.FromImage(outBmp);
g.Clear(Color.WhiteSmoke);
// 设置画布的描绘质量
g.CompositingQuality = CompositingQuality.HighQuality;
g.SmoothingMode = SmoothingMode.HighQuality;
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.DrawImage(imgSource, new Rectangle((destWidth-sW)/2,(destHeight-sH)/2, sW, sH),0,0, imgSource.Width, imgSource.Height, GraphicsUnit.Pixel);
g.Dispose();
// 以下代码为保存图片时,设置压缩质量
EncoderParameters encoderParams = new EncoderParameters();
long[] quality = new long[1];
quality[0] = 100;
EncoderParameter encoderParam = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, quality);
encoderParams.Param[0] = encoderParam;
try
{
//获得包含有关内置图像编码解码器的信息的ImageCodecInfo 对象。
ImageCodecInfo[] arrayICI = ImageCodecInfo.GetImageEncoders();
ImageCodecInfo jpegICI = null;
for (int x = 0; x < arrayICI.Length; x++)
{
if (arrayICI[x].FormatDescription.Equals("JPEG"))
{
jpegICI = arrayICI[x];//设置JPEG编码
break;
}
}
if (jpegICI != null)
{
outBmp.Save(destFile, jpegICI, encoderParams);
}
else
{
outBmp.Save(destFile, thisFormat);
}
return true;
}
catch
{
return false;
}
finally
{
imgSource.Dispose();
outBmp.Dispose();
}
}
}
}
3.图片的裁剪
C#图片处理之:图片缩放和剪裁 作者:ki1381
其实在GDI+中,缩放和剪裁可以看作同一个操作,无非就是原始区域的选择不同罢了。空口无凭,先看具体算法可能更好理解。
/// <summary>
/// Resize图片
/// </summary>
/// <param name="bmp">原始Bitmap</param>
/// <param name="newW">新的宽度</param>
/// <param name="newH">新的高度</param>
/// <param name="Mode">保留着,暂时未用</param>
/// <returns>处理以后的图片</returns>
public static Bitmap KiResizeImage(Bitmap bmp, int newW, int newH, int Mode)
{
try
{
Bitmap b = new Bitmap(newW, newH);
Graphics g = Graphics.FromImage(b);
// 插值算法的质量
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.DrawImage(bmp, new Rectangle(0, 0, newW, newH), new Rectangle(0, 0, bmp.Width, bmp.Height), GraphicsUnit.Pixel);
g.Dispose();
return b;
}
catch
{
return null;
}
}
// ===============================
/// <summary>
/// 剪裁 -- 用GDI+
/// </summary>
/// <param name="b">原始Bitmap</param>
/// <param name="StartX">开始坐标X</param>
/// <param name="StartY">开始坐标Y</param>
/// <param name="iWidth">宽度</param>
/// <param name="iHeight">高度</param>
/// <returns>剪裁后的Bitmap</returns>
public static Bitmap KiCut(Bitmap b, int StartX, int StartY, int iWidth, int iHeight)
{
if (b == null)
{
return null;
}
int w = b.Width;
int h = b.Height;
if (StartX >= w || StartY >= h)
{
return null;
}
if (StartX + iWidth > w)
{
iWidth = w - StartX;
}
if (StartY + iHeight > h)
{
iHeight = h - StartY;
}
try
{
Bitmap bmpOut = new Bitmap(iWidth, iHeight, PixelFormat.Format24bppRgb);
Graphics g = Graphics.FromImage(bmpOut);
g.DrawImage(b, new Rectangle(0, 0, iWidth, iHeight), new Rectangle(StartX, StartY, iWidth, iHeight), GraphicsUnit.Pixel);
g.Dispose();
return bmpOut;
}
catch
{
return null;
}
}
注意到区别了吗?提示,g.DrawImage中第二个new Rectangle。
目标其实都是new Rectangle(0, 0, iWidth, iHeight),缩放算法把整个原始图都往目标区域里塞new Rectangle(0, 0, bmp.Width, bmp.Height),而剪裁只是把原始区域上等宽等高的那个区域new Rectangle(StartX, StartY, iWidth, iHeight)1:1的塞到目标区域里。很容易吧。
4.浮雕图片
private void button1_Click(object sender, EventArgs e)
{
//以浮雕效果显示图像
try
{
int Height = this.pictureBox1.Image.Height;
int Width = this.pictureBox1.Image.Width;
Bitmap newBitmap = new Bitmap(Width, Height);
Bitmap oldBitmap = (Bitmap)this.pictureBox1.Image;
Color pixel1, pixel2;
for (int x = 0; x < Width - 1; x++)
{
for (int y = 0; y < Height - 1; y++)
{
int r = 0, g = 0, b = 0;
pixel1 = oldBitmap.GetPixel(x, y);
pixel2 = oldBitmap.GetPixel(x + 1, y + 1);
r = Math.Abs(pixel1.R - pixel2.R + 128);
g = Math.Abs(pixel1.G - pixel2.G + 128);
b = Math.Abs(pixel1.B - pixel2.B + 128);
if (r > 255)
r = 255;
if (r < 0)
r = 0;
if (g > 255)
g = 255;
if (g < 0)
g = 0;
if (b > 255)
b = 255;
if (b < 0)
b = 0;
newBitmap.SetPixel(x, y, Color.FromArgb(r, g, b));
}
}
this.pictureBox1.Image = newBitmap;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "信息提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
}
1.合并两个图片
/// <summary>
/// 合并两张图片,支持不透明度和透明色
/// </summary>
/// <param name="b0">图片一</param>
/// <param name="b1">图片二</param>
/// <param name="X">起始坐标X</param>
/// <param name="Y">起始坐标Y</param>
/// <param name="b1_alpha">图片二的不透明度</param>
/// <param name="TransColor">被作为透明色处理的颜色</param>
/// <param name="delta">透明色的容差,类似Ps中的魔棒的容差。</param>
/// <returns>合并后的图片</returns>
public static Bitmap KiMerge(Bitmap b0, Bitmap b1, int X, int Y, int b1_alpha,Color TransColor,int delta)
{
if (b0.Equals(null) || b1.Equals(null))
{
return null;
}
int w0 = b0.Width;
int h0 = b0.Height;
int w1 = b1.Width;
int h1 = b1.Height;
int w, h;
if (X + w1 > w0)
{
w = w0 - X;
}
else
{
w = w1;
}
if (Y + h1 > h0)
{
h = h0 - Y;
}
else
{
h = h1;
}
BitmapData srcData = b0.LockBits(new Rectangle(X, Y, w, h), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
BitmapData dstData = b1.LockBits(new Rectangle(0, 0, w, h), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
unsafe
{
byte* pIn = (byte*)srcData.Scan0.ToPointer();
byte* pLogo = (byte*)dstData.Scan0.ToPointer();
for (int y = 0; y < h; y++)
{
for (int x = 0; x < w; x++)
{
// 判断透明色
Color c = Color.FromArgb(pLogo[2], pLogo[1], pLogo[0]);
if (!ColorIsSimilar(c, TransColor, delta))
{
float bili = (float)b1_alpha / (float)255; // 不是透明色,加权平均
float inbili = 1.0f - bili;
int r, g, b;
b = (int)(pIn[0] * inbili + pLogo[0] * bili);
g = (int)(pIn[1] * inbili + pLogo[1] * bili);
r = (int)(pIn[2] * inbili + pLogo[2] * bili);
pIn[0] = (byte)b;
pIn[1] = (byte)g;
pIn[2] = (byte)r;
}
pIn += 3;
pLogo += 3;
}
pIn += srcData.Stride - w * 3;
pLogo += dstData.Stride - w * 3;
}
b0.UnlockBits(srcData);
b1.UnlockBits(dstData);
}
return b0;
}
2.图片缩放(1)
//************************************************************//
//下面给出三个简单的方法,后面两个方法是扩展,估计有时用得着
//************************************************************//
/// <summary>
/// 缩小图片
/// </summary>
/// <param name="strOldPic">源图文件名(包括路径)</param>
/// <param name="strNewPic">缩小后保存为文件名(包括路径)</param>
/// <param name="intWidth">缩小至宽度</param>
/// <param name="intHeight">缩小至高度</param>
public void SmallPic(string strOldPic, string strNewPic, int intWidth, int intHeight)
{
System.Drawing.Bitmap objPic,objNewPic;
try
{
objPic = new System.Drawing.Bitmap(strOldPic);
objNewPic=new System.Drawing.Bitmap(objPic,intWidth,intHeight);
objNewPic.Save(strNewPic);
}
catch(Exception exp){throw exp;}
finally
{
objPic=null;
objNewPic=null;
}
}
/// <summary>
/// 按比例缩小图片,自动计算高度
/// </summary>
/// <param name="strOldPic">源图文件名(包括路径)</param>
/// <param name="strNewPic">缩小后保存为文件名(包括路径)</param>
/// <param name="intWidth">缩小至宽度</param>
public void SmallPic(string strOldPic, string strNewPic, int intWidth)
{
System.Drawing.Bitmap objPic,objNewPic;
try
{
objPic = new System.Drawing.Bitmap(strOldPic);
int intHeight=(intWidth / objPic.Width) * objPic.Height;
objNewPic=new System.Drawing.Bitmap(objPic,intWidth,intHeight);
objNewPic.Save(strNewPic);
}
catch(Exception exp){throw exp;}
finally
{
objPic=null;
objNewPic=null;
}
}
/// <summary>
/// 按比例缩小图片,自动计算宽度
/// </summary>
/// <param name="strOldPic">源图文件名(包括路径)</param>
/// <param name="strNewPic">缩小后保存为文件名(包括路径)</param>
/// <param name="intHeight">缩小至高度</param>
public void SmallPic(string strOldPic, string strNewPic, int intHeight)
{
System.Drawing.Bitmap objPic,objNewPic;
try
{
objPic = new System.Drawing.Bitmap(strOldPic);
int intWidth=(intHeight / objPic.Height) * objPic.Width;
objNewPic=new System.Drawing.Bitmap(objPic,intWidth,intHeight);
objNewPic.Save(strNewPic);
}
catch(Exception exp){throw exp;}
finally
{
objPic=null;
objNewPic=null;
}
}
//************************************************************//
图片缩放(2)效果最好的。
图片无损缩放
* 一个图片缩放的类
*
********************************************************************/
using System;
using System.IO;
using System.Drawing;
using System.Drawing.Imaging;
using System.Drawing.Drawing2D;
namespace ZHT.Utility.Share
{
public class Thumbnail
{
public Thumbnail()
{
}
/// <SUMMARY>
/// 图片缩放
/// </SUMMARY>
/// <PARAM name="sourceFile">图片源路径</PARAM>
/// <PARAM name="destFile">缩放后图片输出路径</PARAM>
/// <PARAM name="destHeight">缩放后图片高度</PARAM>
/// <PARAM name="destWidth">缩放后图片宽度</PARAM>
/// <RETURNS></RETURNS>
public static bool GetThumbnail(string sourceFile, string destFile, int destHeight, int destWidth)
{
System.Drawing.Image imgSource = System.Drawing.Image.FromFile(sourceFile);
System.Drawing.Imaging.ImageFormat thisFormat = imgSource.RawFormat;
int sW = 0, sH = 0;
// 按比例缩放
int sWidth = imgSource.Width;
int sHeight = imgSource.Height;
if(sHeight>destHeight || sWidth>destWidth)
{
if((sWidth*destHeight)>(sHeight*destWidth))
{
sW = destWidth;
sH = (destWidth*sHeight)/sWidth;
}
else
{
sH = destHeight;
sW = (sWidth*destHeight)/sHeight;
}
}
else
{
sW = sWidth;
sH = sHeight;
}
Bitmap outBmp = new Bitmap(destWidth, destHeight);
Graphics g = Graphics.FromImage(outBmp);
g.Clear(Color.WhiteSmoke);
// 设置画布的描绘质量
g.CompositingQuality = CompositingQuality.HighQuality;
g.SmoothingMode = SmoothingMode.HighQuality;
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.DrawImage(imgSource, new Rectangle((destWidth-sW)/2,(destHeight-sH)/2, sW, sH),0,0, imgSource.Width, imgSource.Height, GraphicsUnit.Pixel);
g.Dispose();
// 以下代码为保存图片时,设置压缩质量
EncoderParameters encoderParams = new EncoderParameters();
long[] quality = new long[1];
quality[0] = 100;
EncoderParameter encoderParam = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, quality);
encoderParams.Param[0] = encoderParam;
try
{
//获得包含有关内置图像编码解码器的信息的ImageCodecInfo 对象。
ImageCodecInfo[] arrayICI = ImageCodecInfo.GetImageEncoders();
ImageCodecInfo jpegICI = null;
for (int x = 0; x < arrayICI.Length; x++)
{
if (arrayICI[x].FormatDescription.Equals("JPEG"))
{
jpegICI = arrayICI[x];//设置JPEG编码
break;
}
}
if (jpegICI != null)
{
outBmp.Save(destFile, jpegICI, encoderParams);
}
else
{
outBmp.Save(destFile, thisFormat);
}
return true;
}
catch
{
return false;
}
finally
{
imgSource.Dispose();
outBmp.Dispose();
}
}
}
}
3.图片的裁剪
C#图片处理之:图片缩放和剪裁 作者:ki1381
其实在GDI+中,缩放和剪裁可以看作同一个操作,无非就是原始区域的选择不同罢了。空口无凭,先看具体算法可能更好理解。
/// <summary>
/// Resize图片
/// </summary>
/// <param name="bmp">原始Bitmap</param>
/// <param name="newW">新的宽度</param>
/// <param name="newH">新的高度</param>
/// <param name="Mode">保留着,暂时未用</param>
/// <returns>处理以后的图片</returns>
public static Bitmap KiResizeImage(Bitmap bmp, int newW, int newH, int Mode)
{
try
{
Bitmap b = new Bitmap(newW, newH);
Graphics g = Graphics.FromImage(b);
// 插值算法的质量
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.DrawImage(bmp, new Rectangle(0, 0, newW, newH), new Rectangle(0, 0, bmp.Width, bmp.Height), GraphicsUnit.Pixel);
g.Dispose();
return b;
}
catch
{
return null;
}
}
// ===============================
/// <summary>
/// 剪裁 -- 用GDI+
/// </summary>
/// <param name="b">原始Bitmap</param>
/// <param name="StartX">开始坐标X</param>
/// <param name="StartY">开始坐标Y</param>
/// <param name="iWidth">宽度</param>
/// <param name="iHeight">高度</param>
/// <returns>剪裁后的Bitmap</returns>
public static Bitmap KiCut(Bitmap b, int StartX, int StartY, int iWidth, int iHeight)
{
if (b == null)
{
return null;
}
int w = b.Width;
int h = b.Height;
if (StartX >= w || StartY >= h)
{
return null;
}
if (StartX + iWidth > w)
{
iWidth = w - StartX;
}
if (StartY + iHeight > h)
{
iHeight = h - StartY;
}
try
{
Bitmap bmpOut = new Bitmap(iWidth, iHeight, PixelFormat.Format24bppRgb);
Graphics g = Graphics.FromImage(bmpOut);
g.DrawImage(b, new Rectangle(0, 0, iWidth, iHeight), new Rectangle(StartX, StartY, iWidth, iHeight), GraphicsUnit.Pixel);
g.Dispose();
return bmpOut;
}
catch
{
return null;
}
}
注意到区别了吗?提示,g.DrawImage中第二个new Rectangle。
目标其实都是new Rectangle(0, 0, iWidth, iHeight),缩放算法把整个原始图都往目标区域里塞new Rectangle(0, 0, bmp.Width, bmp.Height),而剪裁只是把原始区域上等宽等高的那个区域new Rectangle(StartX, StartY, iWidth, iHeight)1:1的塞到目标区域里。很容易吧。
4.浮雕图片
private void button1_Click(object sender, EventArgs e)
{
//以浮雕效果显示图像
try
{
int Height = this.pictureBox1.Image.Height;
int Width = this.pictureBox1.Image.Width;
Bitmap newBitmap = new Bitmap(Width, Height);
Bitmap oldBitmap = (Bitmap)this.pictureBox1.Image;
Color pixel1, pixel2;
for (int x = 0; x < Width - 1; x++)
{
for (int y = 0; y < Height - 1; y++)
{
int r = 0, g = 0, b = 0;
pixel1 = oldBitmap.GetPixel(x, y);
pixel2 = oldBitmap.GetPixel(x + 1, y + 1);
r = Math.Abs(pixel1.R - pixel2.R + 128);
g = Math.Abs(pixel1.G - pixel2.G + 128);
b = Math.Abs(pixel1.B - pixel2.B + 128);
if (r > 255)
r = 255;
if (r < 0)
r = 0;
if (g > 255)
g = 255;
if (g < 0)
g = 0;
if (b > 255)
b = 255;
if (b < 0)
b = 0;
newBitmap.SetPixel(x, y, Color.FromArgb(r, g, b));
}
}
this.pictureBox1.Image = newBitmap;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "信息提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
}