2009-04-29 25 views
6

मैं कुछ छवियों को उपयोगकर्ता के स्क्रीन रिज़ॉल्यूशन में बदल रहा हूं; यदि पहलू अनुपात गलत है, तो छवि काटा जाना चाहिए। मेरे कोड इस तरह दिखता है:छवि का आकार बदलना - कभी-कभी बहुत खराब गुणवत्ता?

protected void ConvertToBitmap(string filename) 
    { 
     var origImg = System.Drawing.Image.FromFile(filename); 
     var widthDivisor = (double)origImg.Width/(double)System.Windows.Forms.Screen.PrimaryScreen.Bounds.Width; 
     var heightDivisor = (double)origImg.Height/(double)System.Windows.Forms.Screen.PrimaryScreen.Bounds.Height; 
     int newWidth, newHeight; 

     if (widthDivisor < heightDivisor) 
     { 
      newWidth = (int)((double)origImg.Width/widthDivisor); 
      newHeight = (int)((double)origImg.Height/widthDivisor); 
     } 
     else 
     { 
      newWidth = (int)((double)origImg.Width/heightDivisor); 
      newHeight = (int)((double)origImg.Height/heightDivisor); 
     } 

     var newImg = origImg.GetThumbnailImage(newWidth, newHeight, null, IntPtr.Zero); 
     newImg.Save(this.GetBitmapPath(filename), System.Drawing.Imaging.ImageFormat.Bmp); 
    } 

ज्यादातर मामलों में, यह ठीक काम करता है। लेकिन कुछ छवियों के लिए, परिणाम है अत्यधिक खराब गुणवत्ता। ऐसा लगता है कि कुछ बहुत छोटे (थंबनेल आकार) में बदल दिया गया था और फिर से बढ़ाया गया .. लेकिन छवि का संकल्प सही है। मैं क्या कर सकता हूँ?

उदाहरण मूल छवि: alt text http://img523.imageshack.us/img523/1430/naturaerowoods.jpg

उदाहरण आकृति परिवर्तन छवि: alt text http://img523.imageshack.us/img523/2531/naturaerowoods.png

नोट: मैं एक WPF अनुप्रयोग है, लेकिन मैं आकार बदलने क्योंकि यह आसान है के लिए WinForms समारोह का उपयोग करें और क्योंकि मैं पहले से ही के लिए एक संदर्भ की जरूरत है एक ट्रे आइकन के लिए System.Windows.Forms।

+0

इस पूछने के लिए धन्यवाद! यह समस्या अभी भी आजकल मौजूद है ... – Andrew

उत्तर

7

बदलें पिछले दो इस के लिए अपने विधि की तर्ज की तुलना में अधिक हानिपूर्ण हैं:

var newImg = new Bitmap(newWidth, newHeight); 
Graphics g = Graphics.FromImage(newImg); 
g.DrawImage(origImg, new Rectangle(0,0,newWidth,newHeight)); 
newImg.Save(this.GetBitmapPath(filename), System.Drawing.Imaging.ImageFormat.Bmp); 
g.Dispose(); 
+2

आपको गुणवत्ता सेटिंग भी सेट करने की आवश्यकता है - वे डिफ़ॉल्ट रूप से डिफ़ॉल्ट हैं। देखें http://nathanaeljones.com/163/20-image-resizing-pitfalls/ –

+0

बीफ्री और कंप्यूटर भाषाविद दोनों के लिए चीयर्स, अब मेरे मुद्दों को हल किया ... –

+0

यदि आप इसे सर्वर पर कर रहे हैं, जैसे कि एएसपी.नेट ऐप में, [रैपर] (http://imageresizing.net) का उपयोग करना सबसे अच्छा है जो सिस्टम को ठीक करता है। memleaks ड्रॉइंग। –

7

मैं फिलहाल .NET स्रोत में नहीं देख सकता, लेकिन सबसे अधिक संभावना यह समस्या Image.GetThumbnailImage विधि में है। यहां तक ​​कि एमएसडीएन का कहना है कि "यह अच्छी तरह से काम करता है जब अनुरोधित थंबनेल छवि का आकार लगभग 120 x 120 पिक्सल होता है, लेकिन आप एक छवि से एक बड़ी थंबनेल छवि (उदाहरण के लिए, 300 x 300) का अनुरोध करते हैं जिसमें एक एम्बेडेड थंबनेल होता है, वहां कोई भी हो सकता है थंबनेल छवि में गुणवत्ता का एक उल्लेखनीय नुकसान हो "। सही आकार बदलने के लिए (यानी थंबनेलिंग नहीं), आपको Graphics.DrawImage विधि का उपयोग करना चाहिए। यदि आवश्यक हो तो बेहतर गुणवत्ता प्राप्त करने के लिए आपको Graphics.InterpolationMode के साथ भी खेलना होगा।

2

जैसा कि MSDN पर संकेत दिया गया है, GetThumbnailImage() मनमाने ढंग से छवि स्केलिंग करने के लिए डिज़ाइन नहीं किया गया है। 120x120 से अधिक कुछ भी मैन्युअल रूप से स्केल किया जाना चाहिए। बजाय इस प्रयास करें:

using(var newImg = new Bitmap(origImg, newWidth, newHeight)) 
{ 
    newImg.Save(this.GetBitmapPath(filename), System.Drawing.Imaging.ImageFormat.Bmp); 
} 

संपादित

स्पष्टीकरण का एक बिंदु के रूप में, Bitmap निर्माता के इस अधिभार Graphics.DrawImage कहता है, आप प्रक्षेप पर कोई नियंत्रण नहीं है, हालांकि।

0

उदाहरण के लिए, मूल छवि जेपीजी है और आकार बदलती छवि पीएनजी है। क्या आप उद्देश्य के प्रारूपों के बीच परिवर्तित कर रहे हैं? विभिन्न लॉसी संपीड़न योजनाओं के बीच स्विचिंग गुणवत्ता हानि का कारण बन सकता है।

+0

मैं वॉलपेपर को वॉलपेपर के रूप में उपयोग करना चाहता हूं, और उस उद्देश्य के लिए मुझे इसे बीएमपी में परिवर्तित करना है क्योंकि Win XP वॉलपेपर के लिए किसी अन्य प्रारूप को स्वीकार नहीं करता है। – eWolf

3

आप एक थंबनेल नहीं बना रहे हैं, तो एक विधि GetThumbnailImage कहा जाता है शायद एक अच्छा विचार नहीं है ...

अन्य विकल्पों के लिए उपयोग करते हुए, this CodeProject article पर एक नजर है। विशेष रूप से, यह एक नई छवि बनाता है, इसके लिए Graphics बनाता है और इंटरपोलेशन मोड को HighQualityBicubic पर सेट करता है और मूल छवि को ग्राफिक्स पर खींचता है। कम से कम कोशिश करने के लायक है।

+3

डाउनवॉटर: कृपया कारण दें ... –

+0

वे सिर्फ आपके महाकाव्य ज्ञान जॉन से अनजान हैं –

-1

यह निम्नलिखित कारकों के आधार पर व्यापक रूप से भिन्न हो रहा है:

  1. कितनी निकटता से गंतव्य संकल्प मूल संकल्प
  2. स्रोत छवि रंग गहराई
  3. छवि का एक "प्राकृतिक" पैमाने से मेल खाता है प्रकार (ओं) - कुछ अन्य लोगों
0

क्या आप इसका आकार बदलते समय छवि के आकार को बढ़ा या घटा रहे हैं? यदि आप एक छोटी छवि से एक बड़ी छवि बना रहे हैं, तो इस तरह के गिरावट की उम्मीद की जा सकती है।

+0

उनकी दो छवियां इंगित करती हैं कि मूल बड़ा है। –

0

यदि आप उन्हें बड़ा करते हैं तो चित्र निश्चित रूप से अव्यवस्थित हो जाएंगे।

0

कुछ कैमरे ने स्वयं ही डिवाइस पर पूर्वावलोकन उद्देश्यों के लिए फ़ाइल में एक आकार का थंबनेल लगाया है।

GetThumbnail विधि वास्तव में यह थंबनेल छवि प्राप्त करती है जो उच्च फ़ाइल विधि प्राप्त करने के बजाय छवि फ़ाइल के भीतर एम्बेडेड होती है।

आसान समाधान चाल है। अपने आकार बदलने या अन्य ऑपरेशन करने से पहले उस थंबनेल जानकारी को फेंकने में आसान है। की तरह तो ....

img.RotateFlip(System.Drawing.RotateFlipType.Rotate180FlipX); 
//removes thumbnails from digital camera shots 
img.RotateFlip(System.Drawing.RotateFlipType.Rotate180FlipX); 

आप बाधित अनुपात मैं System.Drawing.Image पर एक विस्तार विधि ने लिखा है कि आप काम मिल सकती है आकार बदलने के लिए प्रयास कर रहे हैं।

/// <summary> 
/// 
/// </summary> 
/// <param name="img"></param> 
/// <param name="size">Size of the constraining proportion</param> 
/// <param name="constrainOnWidth"></param> 
/// <returns></returns> 
public static System.Drawing.Image ResizeConstrainProportions(this System.Drawing.Image img, 
    int size, bool constrainOnWidth, bool dontResizeIfSmaller) 
{ 
    if (dontResizeIfSmaller && (img.Width < size)) 
     return img; 
    img.RotateFlip(System.Drawing.RotateFlipType.Rotate180FlipX); 
    img.RotateFlip(System.Drawing.RotateFlipType.Rotate180FlipX); 
    float ratio = 0; 
    ratio = (float)img.Width/(float)img.Height; 

    int height, width = 0; 
    if (constrainOnWidth) 
    { 
     height = (int)(size/ratio); 
     width = size; 
    } 
    else 
    { 
     width = (int)(size * ratio); 
     height = size; 
    } 
    return img.GetThumbnailImage(width, height, null, (new System.IntPtr(0))); 
} 
2
इस कोड के बजाय

:

newImg.Save(this.GetBitmapPath(filename), System.Drawing.Imaging.ImageFormat.Bmp); 

उपयोग इस एक:

System.Drawing.Imaging.ImageCodecInfo[] info = System.Drawing.Imaging.ImageCodecInfo.GetImageEncoders(); 
System.Drawing.Imaging.EncoderParameters param = new System.Drawing.Imaging.EncoderParameters(1); 
param.Param[0] = new System.Drawing.Imaging.EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 100L); 
newImg.Save(dest_img, info[1], param); 
संबंधित मुद्दे