Frage

Wie man ein Bild ein Bild in C # zu einer bestimmten Festplattengröße, wie 2MiB, um die Größe? Gibt es einen besseren Weg, als Versuch und Irrtum (auch wenn es annähernd, natürlich).

Jede bestimmte Keywords zu suchen, wenn sie versuchen, die Lösung im Internet zu finden?

War es hilfreich?

Lösung

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

  1. Stellen Sie die Größe des Bildes klein
  2. Ändern Sie das Format des Bildes
  3. Wenn das Format eine verlustbehaftete Kompression unterstützt, verringern Sie die Qualität
  4. Wenn Sie Meta-Daten zu speichern, die Sie nicht benötigen, entfernen Sie es
  5. Reduzieren Sie die Anzahl der Farben (und Bits pro Pixel)
  6. Wechsel zu einem paletted Format
  7. Wechsel zu einem 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 zu bekommen. Reduktion der Größe wird wahrscheinlich proportional sein, werden die Bits pro Pixel reduziert proportional wahrscheinlich auch sein.

Wenn Sie das Format, Kompression oder Qualität ändern, es ist wirklich nur eine Vermutung - hängt stark von dem Bildinhalt. Man könnte wahrscheinlich ein gutes Angebot erhalten, indem es auf einem Korpus von Bildern versucht, die übereinstimmt, was denken Sie, werden Sie sehen werden.

Andere Tipps

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 101.111 Bytes und 600x400 Pixel, so dass es verwendet ~ 0,4213 Bytes pro Pixel.

Wenn Sie ein Bild schrumpfen, werden Sie sehen, dass es in der Regel etwas mehr Informationen pro Pixel enthalten wird, mehr in diesem Fall etwa 9%. Je nach Art der Bilder und wie viel Sie schrumpfen sie, 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

Von diesem können Sie eine Formel für extrahieren, wie groß Sie haben ein Bild zu machen, eine bestimmte Dateigröße zu erreichen:

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

Diese erhalten Sie auf die gewünschte Dateigröße ziemlich nahe. Wenn Sie näher kommen wollen, können Sie das Bild auf die berechnete Größe der Größe, komprimieren und berechnen, dass Sie eine neue Bytes pro Pixelwert aus der Dateigröße bekommen.

ich erreichen dies durch die Qualität zu reduzieren, bis ich meine gewünschte Größe erreicht hat.

NB: Erfordern Sie den System.Drawing Verweis hinzuzufügen

.
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;
}
}
}

Wenn es eine 24-Bit-BMP Ich glaube, Sie müssten, 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 sich um einen anderer BMP-Typ wie 8-Bit-BMP auch im Kopfbereich wird es mehr Daten, die tatsächliche Farbe jeden Wert von 0 bis 255 spezifizieren, so müssen Sie mehr von der Gesamtgröße der Datei vor dem binären subtrahieren Suche.

Konvertieren, Reduce (Iterative, In Memory) und Download (MVC)

public ActionResult ReduceFileSize(string ImageURL, long MAX_PHOTO_SIZE) //KB
{
    var photo = Server.MapPath("~/" + ImageURL); //Files/somefiles/2018/DOC_82401583cb534b95a10252d29a1eb4ee_1.jpg

    var photoName = Path.GetFileNameWithoutExtension(photo);

    var fi = new FileInfo(photo);

    //const long MAX_PHOTO_SIZE = 100; //KB //109600;

    var MAX_PHOTO_SIZE_BYTES = (MAX_PHOTO_SIZE * 1000);

    if (fi.Length > MAX_PHOTO_SIZE_BYTES)
    {
        using (var image = Image.FromFile(photo))
        {
            using (var mstream = DownscaleImage(image, MAX_PHOTO_SIZE_BYTES))
            {

                //Convert the memorystream to an array of bytes.
                byte[] byteArray = mstream.ToArray();
                //Clean up the memory stream
                mstream.Flush();
                mstream.Close();
                // Clear all content output from the buffer stream
                Response.Clear();
                // Add a HTTP header to the output stream that specifies the default filename
                // for the browser's download dialog
                Response.AddHeader("Content-Disposition", "attachment; filename=" + fi.Name);
                // Add a HTTP header to the output stream that contains the 
                // content length(File Size). This lets the browser know how much data is being transfered
                Response.AddHeader("Content-Length", byteArray.Length.ToString());
                // Set the HTTP MIME type of the output stream
                Response.ContentType = "application/octet-stream";
                // Write the data out to the client.
                Response.BinaryWrite(byteArray);

            }
        }
    }
    else
    {
        return null;
    }

    return null;
}



private static MemoryStream DownscaleImage(Image photo, long MAX_PHOTO_SIZE_BYTES)
{
    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_BYTES);

    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;
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top