Question

Comment redimensionner une image d'une image en C # à une certaine taille du disque dur, comme 2MiB? Y at-il une meilleure façon de tâtonnement (même si elle est approximative, bien sûr).

Les mots clés particuliers pour rechercher en essayant de trouver la solution sur le web?

Était-ce utile?

La solution

Cela dépend de ce que vous êtes prêt à changer

  1. Assurez-vous de la taille de l'image plus petite
  2. Changer le format de l'image
  3. Si le format supporte une compression avec perte, diminuer la qualité
  4. Si vous stockez des méta-données que vous n'avez pas besoin, retirez
  5. Réduire le nombre de couleurs (et les bits par pixel)
  6. Modifier un format palettisée
  7. Modifier un format palettisée et réduire les couleurs

Il est difficile de deviner ce que la taille du disque final sera, mais si vous connaissez un point de départ, vous pouvez obtenir une assez bonne estimation. La réduction de la taille sera probablement proportionnelle, ce qui réduit les bits par pixel sera également probablement proportionnelle.

Si vous changez le format, la compression ou la qualité, il est vraiment juste une supposition - dépend fortement du contenu de l'image. Vous pourriez probablement obtenir une bonne gamme en essayant sur un corpus d'images qui correspond à ce que vous pensez que vous allez voir.

Autres conseils

Vous pouvez calculer un niveau d'information approximative pour l'image en prenant la taille de l'image originale divisée par le nombre de pixels:

info = fileSize / (width * height);

I ai une image qui est 369636 octets et 1200x800 pixels, de sorte qu'il utilise ~ 0,385 octets par pixel.

J'ai une version plus petite qui est 101111 octets et 600x400 pixels, il utilise ~ 0.4213 octets par pixel.

Lorsque vous réduisez une image, vous verrez qu'il contient généralement un peu plus d'informations par pixel, dans ce cas, environ 9% de plus. En fonction de votre type d'images et combien vous les psy, vous devriez être en mesure de calculer une moyenne pour combien l'augmentation des rations d'information / pixel (c), de sorte que vous pouvez calculer une taille approximative du fichier:

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

De cela, vous pouvez extraire une formule pour la taille que vous devez faire une image pour atteindre une taille de fichier spécifique:

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

Cela vous être assez proche de la taille du fichier souhaité. Si vous voulez vous rapprocher, vous pouvez redimensionner l'image à la taille calculée, compresser et calculer un nouveau octets par valeur de pixel de la taille du fichier que vous avez obtenu.

J'ai réalisé en réduisant la qualité jusqu'à ce que j'atteint ma taille désirée.

NB: vous oblige à ajouter la référence System.Drawing

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

Si elle est un 24bit BMP je pense que vous devez faire quelque chose comme ceci:

//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

S'il est un autre type BMP comme 8 bits BMP également dans la section d'en-tête, il y aura plus de données spécifiant la couleur réelle de chaque valeur de 0 à 255 et vous aurez besoin de soustraire plus de la taille totale du fichier avant le binaire recherche.

Convertir, Réduire (itératifs, en mémoire) & Télécharger (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;
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top