Generovanie thumbnailov a zmena veľkosti obrázka - clipp a scale.
Ako vytvoriť Thumbnail z uploadnutého obrázku, opať veľmi bežne sa vyskytujúca téma na blogoch. Často však potrebujeme rozhodovať o tom, ako sa má obrázok, ktorý nevyhovuje predpísaným rozmerom spracovať, či a ako sa má orezať, či ho necháme zmenšiť neproporčne atd. Ponúkam kúsok kódu, ktorý zvláda všetky tieto bežné situácie a ak niekto chce používateľovi ešte umožniť rozhodnúť o umietnení clipovacieho okna, poľahky si to do metódky dorobíte.
Módy zmeny veľkosti obrázka:
- Clipp - Obrázok zostáva proporčne nezmenený, môže prísť ku jeho zmenšeniu. V prípade, že v jednom rozmere prekračuje vymedzenú cieľovú veľkosť, je orezaný buď z dola, alebo z prava. To je priestor pre ďalšie parametre pre orezenie.(presná pozícia,prípadne aspoň možnosť voľby orezania vertikálne a horizontálne z prava, z ľava, na stred resp. z hora, z dola, na stred
- ScaleToFit - Obrázok zmení veľkosť presne podľa cieľových rozmerov, môže prísť ku deformovaniu proporcií obrázka
- ScaleIntoBounds - Obrázok zostáva proporčne nezmenený, cieľové rozmery slúžia ako vonkanjšie hranice, do ktorých sa snaží obrázok vtesnať
public enum ScaleType
{
Clipp,
ScaleToFit,
ScaleIntoBounds
}
public class ImageHelper
{
public static Bitmap GetThumbNail(Bitmap oImg, Size oTmbSize, ScaleType eScaleType)
{
int iSourceWidth = oImg.Width;
int iSourceHeight = oImg.Height;
if (eScaleType == ScaleType.Clipp || eScaleType == ScaleType.ScaleIntoBounds)
{
SizeF oTmbSizeF = (SizeF)oTmbSize;
SizeF oOrigSizeF = (SizeF)oImg.Size;
float fWidthRatio = oOrigSizeF.Width / oTmbSizeF.Width;
float fHeightRatio = oOrigSizeF.Height / oTmbSizeF.Height;
if (eScaleType == ScaleType.Clipp)
{
if (fWidthRatio < fHeightRatio)
iSourceHeight = (int)Math.Round((double)(oTmbSizeF.Height * fWidthRatio));
else
iSourceWidth = (int)Math.Round((double)(oTmbSizeF.Width * fHeightRatio));
}
else
{
if (fWidthRatio > fHeightRatio)
oTmbSize.Height = (int)Math.Round((double)(oOrigSizeF.Height / fWidthRatio));
else
oTmbSize.Width = (int)Math.Round((double)(oOrigSizeF.Width / fHeightRatio));
}
}
Bitmap oThumbNail = new Bitmap(oTmbSize.Width, oTmbSize.Height, PixelFormat.Format24bppRgb);
using (Graphics oGraphics = Graphics.FromImage(oThumbNail))
{
oGraphics.CompositingQuality = CompositingQuality.HighQuality;
oGraphics.SmoothingMode = SmoothingMode.HighQuality;
oGraphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
Rectangle oDestRectangle = new Rectangle(0, 0, oTmbSize.Width, oTmbSize.Height);
Rectangle oSrcRectangle = new Rectangle(0, 0, iSourceWidth, iSourceHeight);
oGraphics.DrawImage(oImg, oDestRectangle, oSrcRectangle, GraphicsUnit.Pixel);
}
return oThumbNail;
}
public static void SaveCompressedJpg(Image oImg, string sFileName, short shCompressLevel)
{
using (EncoderParameters oCodecParams = new EncoderParameters(1))
{
using (EncoderParameter oParam = new EncoderParameter(Encoder.Quality, (long)shCompressLevel))
{
oCodecParams.Param[0] = oParam;
ImageCodecInfo oCodecInfo = FindEncoder(ImageFormat.Jpeg);
oImg.Save(sFileName, oCodecInfo, oCodecParams);
}
}
}
private static ImageCodecInfo FindEncoder(ImageFormat eImgFormat)
{
ImageCodecInfo[] arrCodecInfo = ImageCodecInfo.GetImageEncoders();
ImageCodecInfo[] arrCodecInfo2 = arrCodecInfo;
for (int i = 0; i < arrCodecInfo2.Length; i++)
{
ImageCodecInfo oCodecInfo = arrCodecInfo2
;
if (oCodecInfo.FormatID.Equals(eImgFormat.Guid))
return oCodecInfo;
}
return null;
}
}
Ako to použiť? Po úspešnom uložení napr. článku alebo update, môžeme spracovať obrázok. Nemusíme to vnárať do tranzakcie, ak je obrázok nepovinný, len upozorniť používateľa, že obrázok sa nepodarilo spracovať.
try
{
if (!Directory.Exists(destPath))
Directory.CreateDirectory(destPath);
if (FUPict.HasFile)
{
using (Bitmap oImage = (Bitmap)Bitmap.FromStream(FUPict.FileContent))
{
FUPict.FileContent.Position = 0;
//cieľovú veľkosť môžeme urobiť configurovateľnú, napr. cez custom configuračnú sekciu vo webconfigu, potom ale odporúčam odkladať aj pôvodný obrázok
//ak si to vzhľadom na zdroje servera môžeme dovoliť kôly resizeu pri zmene veľkosti, ale na to treba napísať navyše nejaký jednodcuhý patcher
using (Bitmap oThumbImg = ImageHelper.GetThumbNail(
oImage,
new Size(100, 100),
ScaleType.Clipp))
{
//podobne ako veľkosť môžeme urobiť configurovateľný aj cieľový formát obrázka
ImageFormat oImgFormat = ImageFormat.Jpeg;
//odporúčam vytvárať subfoldre za predpokladu, že bude existovať rádovo väčši počet obrázkov ako 1000 napr. podľa dátumu
string sFullPath = Server.MapPath(destPath + "\\test.jpg");
if (oImgFormat == ImageFormat.Jpeg)
//kvalitu odporúčam opať urobiť konfigurovateľnú
ImageHelper.SaveCompressedJpg(oThumbImg, sFullPath, 60);
else
oThumbImg.Save(sFullPath, oImgFormat);
}
}
}
}
catch (Exception oEx)
{
//Display warning
CtrlStatus.AddMsg(Resources.ErrorMessages.SavingImageFailure);
//Log Error
}