您能看出这个生成缩略图的方法有什么问题吗?
昨天又使用了某個(gè)多年以前寫的,或者說是“收集”而來的方法。這個(gè)方法的作用是根據(jù)一幅圖片(一般是幅大圖)生成它的縮略圖。這個(gè)方法用了許多年了,一直沒有去懷疑過它的正確性,但是昨天忽然發(fā)現(xiàn)它一直以來都存在一個(gè)問題,雖然可能不是那么明顯,而且也不會(huì)造成太大問題(否則早就發(fā)現(xiàn)了)——但是,這的確是個(gè)不妥的地方。這個(gè)問題在我看來也有一定借鑒意義,因此我打算把它展示出來。那么,您能否看出它究竟是錯(cuò)在什么地方了呢?
生成縮略圖的規(guī)則很簡單,概括地說有三點(diǎn):
這個(gè)規(guī)則其實(shí)就是最傳統(tǒng)的縮略圖生成方式,使用如Windows照片瀏覽器等軟件打開圖片后,一般來說默認(rèn)都會(huì)如此調(diào)整圖片尺寸。而我們?nèi)绻枰獙懸欢未a來實(shí)現(xiàn)這一點(diǎn)也并不困難,以下便是我用了許多年的方法:
/// <summary> /// Creates a thumbnail from an existing image. Sets the biggest dimension of the /// thumbnail to either desiredWidth or Height and scales the other dimension down /// to preserve the aspect ratio /// </summary> /// <param name="imageStream">stream to create thumbnail for</param> /// <param name="desiredWidth">maximum desired width of thumbnail</param> /// <param name="desiredHeight">maximum desired height of thumbnail</param> /// <returns>Bitmap thumbnail</returns> public Bitmap CreateThumbnail(Bitmap originalBmp, int desiredWidth, int desiredHeight) {// If the image is smaller than a thumbnail just return itif (originalBmp.Width <= desiredWidth && originalBmp.Height <= desiredHeight){return originalBmp;}int newWidth, newHeight;// scale down the smaller dimensionif ((decimal)desiredWidth / originalBmp.Width < (decimal)desiredHeight / originalBmp.Height){decimal desiredRatio = (decimal)desiredWidth / originalBmp.Width;newWidth = desiredWidth;newHeight = (int)(originalBmp.Height * desiredRatio);}else{decimal desiredRatio = (decimal)desiredHeight / originalBmp.Height;newHeight = desiredHeight;newWidth = (int)(originalBmp.Width * desiredRatio);}// This code creates cleaner (though bigger) thumbnails and properly// and handles GIF files better by generating a white background for// transparent images (as opposed to black)// This is preferred to calling Bitmap.GetThumbnailImage()Bitmap bmpOut = new Bitmap(newWidth, newHeight);using (Graphics graphics = Graphics.FromImage(bmpOut)){graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;graphics.FillRectangle(Brushes.White, 0, 0, newWidth, newHeight);graphics.DrawImage(originalBmp, 0, 0, newWidth, newHeight);}return bmpOut; }它的具體來源我已經(jīng)記不得了,不過從英文注釋上來看這應(yīng)該是個(gè)老外寫的代碼,那么我們現(xiàn)在就來解釋一番。首先,這個(gè)方法會(huì)先判斷源圖片的大小是否已經(jīng)可以放入目標(biāo)區(qū)域(desiredWidth * desiredHeight)中了,如果是,則直接返回源圖片。如果不滿足第一個(gè)判斷,則說明寬和高之中至少有一個(gè)超出了目標(biāo)尺寸,而我們要對(duì)源圖片進(jìn)行等比例縮放。
那么縮放的“比例”又是多少呢?自然是“寬”或“高”中縮放“程度大”的那個(gè)。因?yàn)槿绻凑湛s放程度小的那條邊的比例來改變圖片尺寸,那么另一條邊勢必會(huì)超出范圍。因此,我們接下來便是比較desiredWidth與originalBmp.Width之比,以及desiredHeight與originalBmp.Height之比孰大孰小。哪個(gè)小,則意味著我們要把它作為縮放依據(jù),因?yàn)樗鼘?duì)圖片尺寸的限制要比另一條邊來的嚴(yán)格。于是乎,再第二個(gè)條件判斷的任意一個(gè)分支中,我們都可以計(jì)算出縮放的比例(desiredRatio),然后把作為“依據(jù)”的那條邊設(shè)為desiredWidth/Height,將另一條邊根據(jù)縮放比例進(jìn)行調(diào)整。在計(jì)算和比較過程中我們都使用了decimal數(shù)據(jù)類型,因?yàn)樗?NET中精度最高的浮點(diǎn)數(shù)類型,我們以此減少計(jì)算過程中所帶來的誤差。
至于得到了newWidth和newHeight之后,我們便只要根據(jù)這個(gè)尺寸生成目標(biāo)圖片即可,它便是源圖片的縮略圖,符合我們之前提出的三個(gè)要求。
聽起來很簡單,看上去也沒有什么問題,不是嗎?不過,其實(shí)這個(gè)實(shí)現(xiàn)中有一個(gè)不那么明顯的問題,您發(fā)現(xiàn)了嗎?(答案)
總結(jié)
以上是生活随笔為你收集整理的您能看出这个生成缩略图的方法有什么问题吗?的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 我犯了一个错误,您能指出吗?(结论)
- 下一篇: 关于浮点数计算时的精度问题