Resizing a Photographic image with GDI+ for .NET
来源:互联网 发布:黄浦区知明学校 编辑:程序博客网 时间:2024/06/05 04:15
http://www.codeproject.com/KB/GDI-plus/imageresize.aspx
This article describes the various techniques used to resize a photographic image with GDI+ and C#+ for .NET.
Introduction
One of the common tasks often performed to photographic images is resizing. In general, scaling an image by a certain percentage is quite simple. On the other hand this might not produce an image that best meets your needs. Often it is more appropriate to Crop and/or Pad that image to achieve a standard height or width. Using some simple techniques, there is an easy way to accomplish these tasks programmatically using C# and GDI+.
In the first step we will load two photographs. The first photograph has a landscape orientation while the other is portrait. This will allow for a better demonstration of how one can resize a photograph of varying sizes and proportions.
string WorkingDirectory = @"C:\Tutorials\ImageResize";Image imgPhotoVert = Image.FromFile(WorkingDirectory + @"\imageresize_vert.jpg");Image imgPhotoHoriz = Image.FromFile(WorkingDirectory + @"\imageresize_horiz.jpg");Image imgPhoto = null;
Example # 1 - Scale by percent
In this example we will demonstrate a simple method of scaling a photograph by a specified percentage. Both the width and height will be scaled uniformly.
imgPhoto = ScaleByPercent(imgPhotoVert, 50);imgPhoto.Save(WorkingDirectory + @"\images\imageresize_1.jpg", ImageFormat.Jpeg);imgPhoto.Dispose();....static Image ScaleByPercent(Image imgPhoto, int Percent){ float nPercent = ((float)Percent/100); int sourceWidth = imgPhoto.Width; int sourceHeight = imgPhoto.Height; int sourceX = 0; int sourceY = 0; int destX = 0; int destY = 0; int destWidth = (int)(sourceWidth * nPercent); int destHeight = (int)(sourceHeight * nPercent); Bitmap bmPhoto = new Bitmap(destWidth, destHeight, PixelFormat.Format24bppRgb); bmPhoto.SetResolution(imgPhoto.HorizontalResolution, imgPhoto.VerticalResolution); Graphics grPhoto = Graphics.FromImage(bmPhoto); grPhoto.InterpolationMode = InterpolationMode.HighQualityBicubic; grPhoto.DrawImage(imgPhoto, new Rectangle(destX,destY,destWidth,destHeight), new Rectangle(sourceX,sourceY,sourceWidth,sourceHeight), GraphicsUnit.Pixel); grPhoto.Dispose(); return bmPhoto;}
Scaled to 50% of original size
In the above example we define a series of variables that are used in the process of scaling the image.sourceWidth
, sourceHeight
, sourceX
, sourceY
are used to build up a source rectangle structure. This structure specifies the portion of the source image object to draw. In our example we want the entire image, so our source rectangle will have the following values: new Rectangle(0,0,370,450)
.
destWidth
, destHeight
, destX
, destY
are used to build a destination rectangle structure. This structure specifies the location and size of the drawn image. The image is scaled to fit this rectangle. ThedestWidth
and destHeight
are calculated by multiplying thesourceWidth
and sourceHeight
by the percentage we want it scaled by. The result is aBitmap
with the new width and height and a destination rectangle with the following values:new Rectangle(0,0,185,225)
.
Example #2 - Scale to a fixed size
A very common task used when creating images for a web site is to resize those images to have a fixed width and height. Often when displaying a list of data, it is beneficial to have any columns that contain images occupy identical dimensions. Since images will have varying orientations it will be necessary to fit either the width or height, then pad the opposite dimension with filler.
imgPhoto = FixedSize(imgPhotoVert, 300, 300);imgPhoto.Save(WorkingDirectory + @"\images\imageresize_3.jpg", ImageFormat.Jpeg);imgPhoto.Dispose();....static Image FixedSize(Image imgPhoto, int Width, int Height){ int sourceWidth = imgPhoto.Width; int sourceHeight = imgPhoto.Height; int sourceX = 0; int sourceY = 0; int destX = 0; int destY = 0; float nPercent = 0; float nPercentW = 0; float nPercentH = 0; nPercentW = ((float)Width/(float)sourceWidth); nPercentH = ((float)Height/(float)sourceHeight); if(nPercentH < nPercentW) { nPercent = nPercentH; destX = System.Convert.ToInt16((Width - (sourceWidth * nPercent))/2); } else { nPercent = nPercentW; destY = System.Convert.ToInt16((Height - (sourceHeight * nPercent))/2); } int destWidth = (int)(sourceWidth * nPercent); int destHeight = (int)(sourceHeight * nPercent); Bitmap bmPhoto = new Bitmap(Width, Height, PixelFormat.Format24bppRgb); bmPhoto.SetResolution(imgPhoto.HorizontalResolution, imgPhoto.VerticalResolution); Graphics grPhoto = Graphics.FromImage(bmPhoto); grPhoto.Clear(Color.Red); grPhoto.InterpolationMode = InterpolationMode.HighQualityBicubic; grPhoto.DrawImage(imgPhoto, new Rectangle(destX,destY,destWidth,destHeight), new Rectangle(sourceX,sourceY,sourceWidth,sourceHeight), GraphicsUnit.Pixel); grPhoto.Dispose(); return bmPhoto;}
In the above example it is our desire to create an image with a width of 300 and a height of 300. The first step in accomplishing this is to determine the smallest possible percent that we can shrink this image, while making sure to fill the maximum height and width.
nPercentW = ((float)Width/(float)sourceWidth);nPercentH = ((float)Height/(float)sourceHeight);if(nPercentH < nPercentW){ nPercent = nPercentH; destX = (int)((Width - (sourceWidth * nPercent))/2);}else{ nPercent = nPercentW; destY = (int)((Height - (sourceHeight * nPercent))/2);}
To do this we will calculate both a height percentage and a width percentage and check which is smaller.nPercentW
=.8108 while nPercentH
=.6666. Choosing the smaller percentage guarantees that none of the image will be cropped. Since height is the smaller reduction, this will be our maximum percent to scale the original image.
When this percent is applied to the width, we end up with a width equal to 247. Our desireddestWidth
was 300, so we will need to pad each side of the image with 27 additional pixels. This padding is accomplished by setting thedestX
=27. This will shift the newly scaled image to the right 27 pixels.
Using the desired nPercent
and destX
, we can build up the appropriate destinationRectangle
and draw the new image.
Example #3 - Scale with cropping
The last resizing technique we will discuss is the process of cropping an image. This technique follows a similar methodology as the previous fixed size example with a few exceptions.
imgPhoto = Crop(imgPhotoVert, 300, 300, AnchorPosition.Bottom);imgPhoto.Save(WorkingDirectory + @"\images\imageresize_4.jpg", ImageFormat.Jpeg);imgPhoto.Dispose();....static Image Crop(Image imgPhoto, int Width, int Height, AnchorPosition Anchor){ int sourceWidth = imgPhoto.Width; int sourceHeight = imgPhoto.Height; int sourceX = 0; int sourceY = 0; int destX = 0; int destY = 0; float nPercent = 0; float nPercentW = 0; float nPercentH = 0; nPercentW = ((float)Width/(float)sourceWidth); nPercentH = ((float)Height/(float)sourceHeight); if(nPercentH < nPercentW) { nPercent = nPercentW; switch(Anchor) { case AnchorPosition.Top: destY = 0; break; case AnchorPosition.Bottom: destY = (int) (Height - (sourceHeight * nPercent)); break; default: destY = (int) ((Height - (sourceHeight * nPercent))/2); break; } } else { nPercent = nPercentH; switch(Anchor) { case AnchorPosition.Left: destX = 0; break; case AnchorPosition.Right: destX = (int) (Width - (sourceWidth * nPercent)); break; default: destX = (int) ((Width - (sourceWidth * nPercent))/2); break; } } int destWidth = (int)(sourceWidth * nPercent); int destHeight = (int)(sourceHeight * nPercent); Bitmap bmPhoto = new Bitmap(Width, Height, PixelFormat.Format24bppRgb); bmPhoto.SetResolution(imgPhoto.HorizontalResolution, imgPhoto.VerticalResolution); Graphics grPhoto = Graphics.FromImage(bmPhoto); grPhoto.InterpolationMode = InterpolationMode.HighQualityBicubic; grPhoto.DrawImage(imgPhoto, new Rectangle(destX,destY,destWidth,destHeight), new Rectangle(sourceX,sourceY,sourceWidth,sourceHeight), GraphicsUnit.Pixel); grPhoto.Dispose(); return bmPhoto;}
When cropping an image you have 5 choices as to how one decides, what part of the image to crop. We refer to this as how one anchors the image. Top, bottom, and center are appropriate when cropping an image's height where as left, right and center are appropriate for width. (There are more, but for the purpose of this example we will focus in these 5.)
Similar to example #2, the first thing we need to do is determine a height percentage and a width percentage that gets us to the desired dimensions. Since our desired dimensions are 300x300, we end up with the same percentages as in the previous example. Once again we will compare the two, but this time we will choose the larger of the two percentages. (nPercentW
= .8108)
if(nPercentH < nPercentW){ nPercent = nPercentW; switch(Anchor) { case AnchorPosition.Top: destY = 0; break; case AnchorPosition.Bottom: destY = (int)(Height - (sourceHeight * nPercent)); break; default: destY = (int)((Height - (sourceHeight * nPercent))/2); break; }}
Image anchored top
Image anchored center
Image anchored bottom
By using 3 different destY
values, we can achieve the 3 different ways to crop the image. If our source image would have had a landscape orientation, then left, right and center would have been appropriate anddestX
would have been used to achieve a crop of the image's width.
One last thing...
In all of the examples, we called both the SetResolution
andInterpolationMode
prior to drawImage
.SetResolution
does just as the name implies. In these examples, we carry over the original image's resolution by setting this property equal toimgPhoto.HorizontalResolution
, imgPhoto.VerticalResolution
.
bmPhoto.SetResolution(imgPhoto.HorizontalResolution, imgPhoto.VerticalResolution);Graphics grPhoto = Graphics.FromImage(bmPhoto);grPhoto.InterpolationMode = InterpolationMode.HighQualityBicubic;
Interpolation refers to how data is interpolated between endpoints. In its simplest form, to interpolate is to estimate a missing value by taking an average of known values at neighboring points. Below is the graphical representation of three different approaches to interpolation.
In general the bicubic interpolation is used when more accuracy is desired than the bilinear interpolation.
Bicubic interpolation
Bilinear interpolation
Nearest-neighbor interpolation
That's it! Compile the project, run it, and see what happens! The code is fairly straightforward. If it all makes sense, then these resizing techniques can be used to scale virtually any image.
License
This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.
A list of licenses authors might use can be found here
About the Author
Joel NeubeckUnited States
Member
In his free time, he enjoys spending time with his wife and children.
http://www.codeproject.com/KB/GDI-plus/imageresize.aspx
- Resizing a Photographic image with GDI+ for .NET
- Image Processing for Dummies with C# and GDI+ Part 4 - Bilinear Filters and Resizing
- Creating a Watermarked Photograph with GDI+ for .NET
- Creating a Watermarked Photograph with GDI+ for .NET
- Resizing a Form to Fit an Image
- Photographic Image Synthesis with Cascaded Refinement Networks(由语义分割图生成逼真街景图)
- Dynamically creating a pie chart with ASP.NET and GDI+
- Image Processing for Dummies with C# and GDI+ Part 6 - The HSL color space
- Image Processing for Dummies with C# and GDI+ Part 5 - Displacement filters, including swirl
- Image Processing for Dummies with C# and GDI+ Part 3 - Edge Detection Filters
- Image Processing for Dummies with C# and GDI+ Part 2 - Convolution Filters
- Image Processing for Dummies with C# and GDI+ Part 1 - Per Pixel Filters
- IOS Dev Intro - Image Resizing
- Loading a true type font with GDI+
- Image Resizing Techniques_ iOS图像分辨率
- U-net for image segmentation
- System.Drawing.Image.Save, A generic error occurred in GDI+.
- Screen Capturing a Form in .NET - Using GDI and GDI+
- 美文-今天我学会控制情绪
- LINUX学习笔记13——进程间通信2信号
- cuda与openGL之间的interoperation操作
- java从菜鸟到架构师的必看书籍
- Pidgin和Miranda连接Openfire
- Resizing a Photographic image with GDI+ for .NET
- vi recording
- myeclipse优化方案 myeclipse 10 优化
- LINUX学习笔记14——进程间通信3共享内存
- AndroidManifest.xml中的内容详解
- ubuntu 11.10输入法图标消失
- LINUX学习笔记15——进程间通信4消息队列
- 这是一位女孩在异国结婚时,他父亲从大陆寄来的信,
- HEX WORKSHOP 文件比较批处理