丢弃Image类的GetThumbnailImage方法

2006年11月17日 6:06 下午  |  分类:Develop

GetThumbnailImage的确是构造一个缩略图最简单的方法但同样存在一些不足:
1、如当源图尺寸过大时,生成的缩略图质量会很低,而且同源图的尺寸是一种正比的关系
2、当源图是一个Gif图片且含有透明色时,生成的缩略图会将透明色填充成黑色。

今天在工作中就遇到这样的问题,基于上面二个原因,于是决定放弃GetThumbnailImage方法了。
最终采用Graphics类的DrawImage方法至于质量问题,适当的设定一下,可以达到很好的效果。

/// </summary>
/// <param name="SourceFile">文件在服务器上的物理地址</param>
/// <param name="strSavePathFile">保存在服务器上的路径</param>
/// <param name="ThumbWidth">宽度</param>
/// <param name="ThumbHeight">高度</param>
/// <param name="BgColor">背景</param>
public static void myGetThumbnailImage(string SourceFile, string strSavePathFile, int ThumbWidth, int ThumbHeight, string BgColor)
{
System.Drawing.Image oImg = System.Drawing.Image.FromFile(SourceFile);
//小图
int intwidth, intheight;
if (oImg.Width > oImg.Height)
{
if (oImg.Width > ThumbWidth)
{
intwidth = ThumbWidth;
intheight = (oImg.Height * ThumbWidth) / oImg.Width;
}
else
{
intwidth = oImg.Width;
intheight = oImg.Height;
}
}
else
{
if (oImg.Height > ThumbHeight)
{
intwidth = (oImg.Width * ThumbHeight) / oImg.Height; intheight = ThumbHeight;
}
else
{
intwidth = oImg.Width; intheight = oImg.Height;
}
}
//构造一个指定宽高的Bitmap
Bitmap bitmay = new Bitmap(intwidth, intheight);
Graphics g = Graphics.FromImage(bitmay);
Color myColor;
if (BgColor == null) myColor = Color.FromName("white");
else
myColor = Color.FromName(BgColor);
//用指定的颜色填充Bitmap
g.Clear(myColor);
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
//开始画图
g.DrawImage(oImg, new Rectangle(0, 0, intwidth, intheight), new Rectangle(0, 0, oImg.Width, oImg.Height), GraphicsUnit.Pixel);
bitmay.Save(strSavePathFile, System.Drawing.Imaging.ImageFormat.Jpeg);
g.Dispose();
bitmay.Dispose();
oImg.Dispose();
//删除源图
try
{
File.Delete(SourceFile);
}
catch { }
}

GDI+中对图片的裁剪已解决

2006年11月7日 5:42 下午  |  分类:Develop

没想到Bitmap中的Clone方法可以解决这一切

void CutImage(HttpPostedFile post,string ppuid,out string imagename)
{
System.Drawing.Image SourceImg = System.Drawing.Image.FromStream(post.InputStream);
if (SourceImg.Height > ConfigHelper.UserFaceMaxHeight)
{
this._lbl_upload_msg.Text = "最大高度不得大于 " + ConfigHelper.UserFaceMaxHeight;
return;
}
if (SourceImg.Width > ConfigHelper.UserFaceMaxWidth)
{
this._lbl_upload_msg.Text = "最大宽度不得大于 " + ConfigHelper.UserFaceMaxWidth;
return;
}
ImageFormat format = getImageformat(System.IO.Path.GetExtension(post.FileName));
string filename = ppuid+"."+format.ToString();
imagename = filename;

if (!UserFaceDir.EndsWith("\\"))
UserFaceDir = UserFaceDir+"\\";
filename = UserFaceDir + filename;
int SourceImgWidth = SourceImg.Width;
int SourceImgHeight = SourceImg.Height;
if ((SourceImgWidth != ConfigHelper.UserFaceWidth) && (SourceImgHeight != ConfigHelper.UserFaceHeight))
{
//如果宽高比例为1:1,则直接构成缩略图
if (((Double)SourceImgWidth / SourceImgHeight) == 1)
{
System.Drawing.Image thumbimg = SourceImg.GetThumbnailImage(ConfigHelper.UserFaceWidth, ConfigHelper.UserFaceHeight, null, IntPtr.Zero);
thumbimg.Save(filename, format);
thumbimg.Dispose();
SourceImg.Dispose();
return;
}
Bitmap bit = new Bitmap(SourceImg);
Rectangle rec = new Rectangle(); //构造一个Rectangle类,一个矩形
rec.Width = ConfigHelper.UserFaceWidth;
rec.Height = ConfigHelper.UserFaceHeight;
if (SourceImgWidth > rec.Width)
rec.X = (SourceImgWidth - rec.Width) / 2;
else
{
rec.X = 0;
rec.Width = SourceImg.Width;
}
if (SourceImgHeight > rec.Height)
rec.Y = (SourceImgHeight - rec.Height) / 2;
else
{
rec.Y = 0;
rec.Height = SourceImg.Height;
}

try
{
//这里就是把从上传过程中构造的bitmap克隆一份,并按定义好的矩形裁剪
bit.Clone(rec, PixelFormat.DontCare).Save(filename, format);
}
catch (Exception ex)
{
this._lbl_upload_msg.Text = ex.Message;
return;
}
finally
{
bit.Dispose();
SourceImg.Dispose();
}
}
}

写得很粗糙,暂时不支持多帧的gif图片,也没做生成图片时质量方面的考虑,明天解决这一切。

对Graphics.DrawImageUnscaledAndClipped的疑虑

2006年11月7日 2:01 下午  |  分类:Develop

一直没有深入了解研究c#中的GDI+,仅仅只是在应用中构造缩略图或加一下水印
在今天的项目中,遇到以下的需求
用户在上传图片后,统一调整为64*64;宽高大于64的,从图片中间截取,先不论这种设计合不合理,现在问题出现在对原始图片的裁剪上。

.Net中提供了Image类与Graphics类,这二个类可以达到目的。

System.Drawing.Image SourceImg = System.Drawing.Image.FromStream(this.FileUpload1.PostedFile.InputStream);
int SourceImgWidth = SourceImg.Width; //图片的原始Width
int SourceImgHeight = SourceImg.Height; //图片的原始Height
if ((SourceImgWidth != 64) && (SourceImgHeight != 64))
{
//System.Drawing.Imaging.ImageFormat f = g.RawFormat;
Bitmap b = new Bitmap(64, 64);
Graphics gh = Graphics.FromImage(b);
gh.DrawImageUnscaledAndClipped(SourceImg, new Rectangle(0, 0, SourceImgWidth, SourceImgHeight));
gh.SmoothingMode = SmoothingMode.AntiAlias;
b.Save(@"C:\yy1.jpg");
gh.Dispose();
b.Dispose();
SourceImg.Dispose();
}

查SDK中对于DrawImageUnscaledAndClipped方法的解释:
在不进行缩放的情况下绘制指定的图像,并在需要时剪辑该图像以适合指定的矩形。

我的理解是:
gh.DrawImageUnscaledAndClipped(SourceImg, new Rectangle(0, 0, 64, 64));
在源图上剪辑一指定矩形的区域,在Rectangel结构中已经定义了x坐标为0,y坐标为0,
执行上面的代码,生成的图片为

将Retangle中的x坐标稍做修改,为了说明问题,将空白部分用黑色填充了
gh.DrawImageUnscaledAndClipped(SourceImg, new Rectangle(10, 0, 64, 64));
生成的图片

看来Rectangle中的x坐标并不是决定在源图中要裁剪的x坐标值
那到底如何在对一张源图进行裁剪呢?