9

Wie ändere ich ein Bild in C# auf eine bestimmte Festplattengröße, wie 2MiB? Gibt es einen besseren Weg als Versuch und Irrtum (auch wenn es natürlich ungefähr ist).Wie ändere ich ein Bild in C# auf eine bestimmte Festplattengröße?

Gibt es bestimmte Schlüsselwörter, nach denen Sie suchen müssen, wenn Sie versuchen, die Lösung im Internet zu finden?

+2

Welche Art von Bild? –

Antwort

0

Es hängt davon ab, was Sie bereit sind,

  1. die Größe des Bildes kleiner
  2. Ändern Sie das Format des Bildes
  3. Stellen zu ändern Wenn das Format eine verlustbehaftete Kompression unterstützt, verringern Sie die Qualität
  4. Wenn Sie Meta-Daten zu speichern, dass Sie es nicht benötigen, entfernen
  5. Reduzieren Sie die Anzahl der Farben (und Bits pro Pixel)
  6. Wechsel in ein paletted Format
  7. Wechsel in ein paletted Format und reduzieren die Farben

Es ist schwer zu erraten, was die endgültige Plattengröße sein wird, aber wenn Sie einen Ausgangspunkt kennen, können Sie eine ziemlich gute Schätzung erhalten . Das Verringern der Größe wird wahrscheinlich proportional sein, und das Reduzieren der Bits pro Pixel wird wahrscheinlich ebenfalls proportional sein.

Wenn Sie das Format, die Komprimierung oder Qualität ändern, ist es nur eine Vermutung - hängt stark vom Bildinhalt ab.Sie können wahrscheinlich eine gute Reichweite erzielen, indem Sie es auf einem Korpus von Bildern ausprobieren, die zu dem passen, was Sie zu sehen glauben.

7

Sie können eine ungefähre Informationsebene für das Bild berechnen, indem die ursprüngliche Bildgröße durch die Anzahl der Pixel unterteilt unter:

info = fileSize/(width * height); 

Ich habe ein Bild, das 369.636 Bytes und 1200x800 Pixel, so dass es verwendet ~ 0,385 Bytes pro Pixel.

Ich habe eine kleinere Version, die 101111 Bytes und 600x400 Pixel ist, so verwendet es ~ 0,4213 Bytes pro Pixel.

Wenn Sie ein Bild verkleinern, sehen Sie, dass es im Allgemeinen etwas mehr Informationen pro Pixel enthält, in diesem Fall etwa 9% mehr. Je nach Art der Bilder, und wie man sie viel schrumpfen, sollten Sie in der Lage sein, einen Durchschnitt, wie viel die Informationen/Pixel Ration erhöht (c) zu berechnen, so dass Sie eine ungefähre Dateigröße berechnen können:

newFileSize = (fileSize/(width * height)) * (newWidth * newHeight) * c 

Daraus können Sie eine Formel für extrahieren, wie groß Sie ein Bild machen müssen, um eine bestimmte Dateigröße zu erreichen:

auf die gewünschte Dateigröße
newWidth * newHeight = (newFileSize/fileSize) * (width * height)/c 

diese erhalten Sie ziemlich nah dran. Wenn Sie näher kommen möchten, können Sie das Bild auf die berechnete Größe skalieren, es komprimieren und einen neuen Byte pro Pixel Wert aus der Dateigröße berechnen, die Sie erhalten haben.

1

Wenn es ein 24-Bit-BMP Ich glaube, Sie müßten, so etwas tun:

//initial size = WxH 
long bitsperpixel = 24; //for 24 bit BMP 
double ratio; 
long size = 2 * 1 << 20;//2MB = 2 * 2^20 
size -= 0x35;//subtract the BMP header size from it 
long newH, newW, left, right, middle,BMProwsize; 
left = 1; 
right = size;//binary search for new width and height 
while (left < right) 
{ 
    middle = (left + right + 1)/2; 
    newW = middle; 
    ratio = Convert.ToDouble(newW)/Convert.ToDouble(W); 
    newH = Convert.ToInt64(ratio * Convert.ToDouble(H)); 
    BMProwsize = 4 * ((newW * bitsperpixel + 31)/32); 
    //row size must be multiple of 4 
    if (BMProwsize * newH <= size) 
     left = middle; 
    else 
     right = middle-1;     
} 

newW = left; 
ratio = Convert.ToDouble(newW)/Convert.ToDouble(W); 
newH = Convert.ToInt64(ratio * Convert.ToDouble(H)); 
//resize image to newW x newH and it should fit in <= 2 MB 

Wenn es ein anderer BMP-Typ wie 8-Bit-BMP auch im Kopfbereich ist, wird es mehr Daten werden die Angabe tatsächliche Farbe jedes Wertes von 0 bis 255, so dass Sie mehr von der gesamten Dateigröße vor der binären Suche subtrahieren müssen.

2

Ich erreichte dies durch die Reduzierung der Qualität, bis ich meine gewünschte Größe erreicht.

Hinweis: Erfordert das Hinzufügen der System.Drawing-Referenz.

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Threading.Tasks; 
using System.IO; 
using System.Drawing; 
using System.Drawing.Imaging; 
using System.Drawing.Drawing2D; 

namespace PhotoShrinker 
{ 
class Program 
{ 
/// <summary> 
/// Max photo size in bytes 
/// </summary> 
const long MAX_PHOTO_SIZE = 409600; 

static void Main(string[] args) 
{ 
    var photos = Directory.EnumerateFiles(Directory.GetCurrentDirectory(), "*.jpg"); 

    foreach (var photo in photos) 
    { 
     var photoName = Path.GetFileNameWithoutExtension(photo); 

     var fi = new FileInfo(photo); 
     Console.WriteLine("Photo: " + photo); 
     Console.WriteLine(fi.Length); 

     if (fi.Length > MAX_PHOTO_SIZE) 
     { 
      using (var image = Image.FromFile(photo)) 
      { 
        using (var stream = DownscaleImage(image)) 
        { 
         using (var file = File.Create(photoName + "-smaller.jpg")) 
         { 
          stream.CopyTo(file); 
         } 
        } 
      } 
      Console.WriteLine("File resized."); 
     } 
     Console.WriteLine("Done.") 
     Console.ReadLine(); 
    } 

} 

private static MemoryStream DownscaleImage(Image photo) 
{ 
    MemoryStream resizedPhotoStream = new MemoryStream(); 

    long resizedSize = 0; 
    var quality = 93; 
    //long lastSizeDifference = 0; 
    do 
    { 
     resizedPhotoStream.SetLength(0); 

     EncoderParameters eps = new EncoderParameters(1); 
     eps.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, (long)quality); 
     ImageCodecInfo ici = GetEncoderInfo("image/jpeg"); 

     photo.Save(resizedPhotoStream, ici, eps); 
     resizedSize = resizedPhotoStream.Length; 

     //long sizeDifference = resizedSize - MAX_PHOTO_SIZE; 
     //Console.WriteLine(resizedSize + "(" + sizeDifference + " " + (lastSizeDifference - sizeDifference) + ")"); 
     //lastSizeDifference = sizeDifference; 
     quality--; 

    } while (resizedSize > MAX_PHOTO_SIZE); 

    resizedPhotoStream.Seek(0, SeekOrigin.Begin); 

    return resizedPhotoStream; 
} 

private static ImageCodecInfo GetEncoderInfo(String mimeType) 
{ 
    int j; 
    ImageCodecInfo[] encoders; 
    encoders = ImageCodecInfo.GetImageEncoders(); 
    for (j = 0; j < encoders.Length; ++j) 
    { 
     if (encoders[j].MimeType == mimeType) 
      return encoders[j]; 
    } 
    return null; 
} 
} 
} 
+0

danke, tolle funktionierende Probe. Ich änderte es, um die Qualität 5 Einheiten auf einmal zu senken und benutzte es in meinem asp.net –

+1

Froh, dass ich jemand anderem helfen könnte! Ich habe festgestellt, dass die Image.FromFile (Foto) nicht ordnungsgemäß entsorgt wurde! Ich habe meinen Code aktualisiert, um ordnungsgemäß zu entsorgen. –

Verwandte Themen