2010-03-24 10 views
5

Próbuję napisać metodę zmniejszania rozmiaru dowolnego obrazu za każdym razem o 50%, ale znalazłem problem. Czasami mam większy rozmiar pliku, podczas gdy obraz jest tak naprawdę połową tego, co było. Zajmuję się DPI i PixelFormat. Czego jeszcze brakuje?Czasami skalowanie w dół mapy bitowej generuje większy plik. Czemu?

Dziękuję za poświęcony czas.

public Bitmap ResizeBitmap(Bitmap origBitmap, int nWidth, int nHeight) 
{ 
    Bitmap newBitmap = new Bitmap(nWidth, nHeight, origBitmap.PixelFormat); 

    newBitmap.SetResolution(
     origBitmap.HorizontalResolution, 
     origBitmap.VerticalResolution); 

    using (Graphics g = Graphics.FromImage((Image)newBitmap)) 
    { 
     g.InterpolationMode = InterpolationMode.HighQualityBicubic; 

     g.DrawImage(origBitmap, 0, 0, nWidth, nHeight); 
    } 

    return newBitmap; 
} 

http://imgur.com/lY9BN.png

http://imgur.com/KSka0.png

Edit: Oto brakujący kod:

int width = (int)(bitmap.Width * 0.5f); 
int height = (int)(bitmap.Height * 0.5f); 
Bitmap resizedBitmap = ResizeBitmap(bitmap, width, height); 
resizedBitmap.Save(newFilename); 

Edit 2: oparciu o komentarze, to jest rozwiązanie I "ve Znaleziono:

private void saveAsJPEG(string savingPath, Bitmap bitmap, long quality) 
{ 
    EncoderParameter parameter = new EncoderParameter(Encoder.Compression, quality); 
    ImageCodecInfo encoder = getEncoder(ImageFormat.Jpeg); 
    if (encoder != null) 
    { 
     EncoderParameters encoderParams = new EncoderParameters(1); 
     encoderParams.Param[0] = parameter; 
     bitmap.Save(savingPath, encoder, encoderParams); 
    } 
} 

private ImageCodecInfo getEncoder(ImageFormat format) 
{ 

    ImageCodecInfo[] codecs = ImageCodecInfo.GetImageDecoders(); 
    foreach (ImageCodecInfo codec in codecs) 
     if (codec.FormatID == format.Guid) 
      return codec; 

    return null; 
} 
+0

Kompresja? Skompresowane bity/piksele są różne. – graphicdivine

+0

Opublikuj kod eksportu JPEG w języku C#. Zgaduję, że jest to problem z kompresją. – futureelite7

+0

Och, właśnie dodałem brakujący kod –

Odpowiedz

6

Prawdopodobnie zachowujesz obraz JPEG z niskim współczynnikiem kompresji (wysoka jakość).

+0

Zgaduję również. – mafu

+0

Cóż, nie wybieram żadnego współczynnika kompresji. Czy istnieje sposób, w jaki mogę użyć tego samego współczynnika kompresji, co w oryginalnym obrazie? Dzięki. –

+2

@ Matías - z tego, co pamiętam, współczynnik kompresji nie jest zapisany w nagłówku, więc informacje zostaną utracone po zapisaniu pliku. – ChrisF

1

Powiedziałbym, że zapisujesz go jako JPEG o wysokiej jakości (mniej więcej przestrzeni sprężania ==)

2

Problem nie leży w kodzie pisał, ale gdzie można zapisać w formacie JPEG. Jakiego współczynnika kompresji używasz?

1

Wygląda na to, że twoje bitmapy są zapisywane jako jpeg i wiedząc, że C# lubi robić dla ciebie rzeczy, prawdopodobnie jest to oszczędność przy domyślnym poziomie kompresji, który jest dość niski. Oryginalny jpeg musi mieć przyzwoity poziom kompresji. Nawet jeśli był to ten sam poziom kompresji, sposób w jaki działa format jpeg może oznaczać, że znalazłeś fuksa, który dawkuje podbicie w niższej rozdzielczości.

Mapa bitowa ma jednak dokładny rozmiar, jeśli ma dziesięć pikseli szerokości i dziesięć wysokości, to jest 100 pikseli, na przykład 16-bitowy (2-bajtowy) kolor, który ma 200 bajtów plus trochę nagłówka.

obniż rozdzielczość do 5 na 5, masz 50 bajtów plus bit nagłówka, powinna być taka sama ilość nagłówka.

4

Ponowna kompresja obrazu JPEG to coś, czego należy unikać. Ale prawdziwym problemem jest tutaj InterpolationMode, a wysokiej jakości generuje wiele subtelnie zacienionych pikseli, co utrudnia kompresję obrazu. Korzystanie z InterpolationMode.NearestNeighbor powinno tego unikać, ale kosztem uzyskania obrazu o niższej jakości.

+0

Próbowałem tego, a rozmiar pliku jest wciąż większy niż oryginalny obraz. –

+0

@ Matías: co się dzieje, gdy zaczynasz od PNG, aby uniknąć hałasu spowodowanego 1. kompresją? –

+0

Co masz na myśli? Moje obrazy źródłowe to zawsze JPEG, przepraszam, że wcześniej o tym nie wspomniałem. –

1

Wypróbuj ten kod, aby zapisać posiadany plik JPEG. Pozwoli to na ustawienie jakości kompresji. Eksperymentuj i zobacz, czy to pomaga w problemach z rozmiarem:

private void saveJpeg(string path, Bitmap img, long quality) 
{ 
    EncoderParameter parameter = new EncoderParameter(Encoder.Quality, quality); 
    ImageCodecInfo encoder = this.getEncoderInfo("image/jpeg"); 
    if (encoder != null) 
    { 
     EncoderParameters encoderParams = new EncoderParameters(1); 
     encoderParams.Param[0] = parameter; 
     img.Save(path, encoder, encoderParams); 
    } 
} 

private ImageCodecInfo getEncoderInfo(string mimeType) 
{ 
    ImageCodecInfo[] imageEncoders = ImageCodecInfo.GetImageEncoders(); 
    for (int i = 0; i < imageEncoders.Length; i++) 
    { 
     if (imageEncoders[i].MimeType == mimeType) 
     { 
      return imageEncoders[i]; 
     } 
    } 
    return null; 
} 
+0

co to jest getEncoderInfo? –

+0

Przepraszam, zupełnie zapomniałem o tej metodzie. Teraz powinno być kompletne (chociaż domyślam się, że jest już za późno :)) – Jefim

+0

Dziękuję, działa świetnie! –

1

Wygląda na to, że oryginał jest wyjściem z aparatu cyfrowego. Sądzę, że producenci aparatów wykorzystują własne superoptymalizowane algorytmy kompresji, podczas gdy wspólna biblioteka może mieć mniej efektywną implementację. (I oczywiście prawdopodobnie nie używasz tego samego poziomu kompresji co kamera.)

Dodatkowo kamera wykorzystuje surowe dane (prawdopodobnie najpierw wykonuje "magiczne" wstępne przetwarzanie) z czujników jako dane wejściowe. Podczas ponownego kompresowania wejście zawiera kompresję i przeskalowanie artefaktów, co może spowodować, że kompresja będzie mniej skuteczna.

Właściwie myślę, że jeśli kompresji obrazu kilka razy z samym jpg algorytmem na samym poziomie, może rosnąć w rozmiarze ponieważ artefakty z poprzednich uciśnięć dodaje „szczegóły”, które jest trudniejsze do kompresji (i staje się coraz brzydsze).

(The algorytm kompresji kamera może również być optymalizowany dla faktu, że wejście jest zawsze zdjęcie, podczas gdy ogólny cel algorytm może zrobić trochę mniej skuteczne rzeczy do dość dobrze zarówno pracować na zdjęcia i linii sztuki mieszany obrazy zawierające zdjęcia i wygenerowane elementy graficzne.)

+0

Format JPEG nie działa dobrze na grafikę liniową, o ile nie podniesie się poziomu jakości do maksimum. Masz rację, że producenci aparatów potrafią zoptymalizować swoje algorytmy JPEG. Kiedy Sigma pojawiła się z czujnikiem Foveon, odkryli, że algorytm, którego używali, tracił trochę szczegółów, które dostarczał ich nowy czujnik w porównaniu z konkurencją, i musieli to zaadaptować. –

+0

Oczywiście nie jest to dobre dla grafiki liniowej (użyj do tego png itp.). Tak naprawdę myślałem o mieszanych obrazach z wieloma różnymi typami grafiki. (Zaktualizowałem swoją odpowiedź) –