10
votes

Comment redimensionner une image en C # à une certaine taille de disque dur?

Comment redimensionner une image une image en C # à une certaine taille de disque dur, comme 2MIB? Existe-t-il un meilleur moyen que l'essai et l'erreur (même s'il est approximatif, bien sûr).

Des mots-clés particuliers à rechercher lors de la recherche de la solution sur le Web?


0 commentaires

5 Réponses :


10
votes

Vous pouvez calculer un niveau d'information approximatif pour l'image en prenant la taille d'image d'origine divisée par le nombre de pixels: xxx pré>

J'ai une image de 369636 octets et 1200x800 pixels, donc il utilise ~ 0,385 octets par pixel. P>

J'ai une version plus petite qui correspond à 101111 octets et 600x400 pixels, il utilise donc ~ 0,4213 octets par pixel. P>

Lorsque vous réduisez une image Je verra que cela contiendra généralement un peu plus d'informations par pixel, dans ce cas environ 9% de plus. Selon votre type d'images et combien vous les rétrécissez, vous devriez être en mesure de calculer une moyenne pour la quantité de ration de l'information / pixel (C), de sorte que vous puissiez calculer une taille de fichier approximative: P>

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


0 commentaires

1
votes

Si c'est un BMP de 24 bits, je pense que vous auriez besoin de faire quelque chose comme ceci: xxx

S'il s'agit d'un type BMP différent, tel que 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 Vous devrez donc soustraire davantage de la taille totale du fichier avant la recherche binaire.


0 commentaires

0
votes

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

  1. Faites la taille de l'image plus petite
  2. changer le format de l'image
  3. Si le format prend en charge une compression avec perte, diminuez la qualité
  4. Si vous stockez des méta-données dont vous n'avez pas besoin, retirez-le
  5. Réduisez le nombre de couleurs (et de bits par pixel)
  6. passer à un format Paleté
  7. passe à un format palesté et réduisez les couleurs

    Il est difficile de deviner quelle sera la taille du disque final, mais si vous connaissez un point de départ, vous pouvez obtenir une très bonne estimation. La réduction de la taille sera probablement proportionnelle, réduisant ainsi les bits par pixel sera probablement proportionnel.

    Si vous changez du format, de la compression ou de la qualité, il s'agit vraiment d'une hypothèse - dépend fortement du contenu de l'image. Vous pouvez probablement avoir une bonne cuisinière en l'essayant sur un corpus d'images qui correspondent à ce que vous pensez voir.


0 commentaires

6
votes

J'ai obtenu ceci en réduisant la qualité jusqu'à ce que j'ai atteint la taille souhaitée.

NB: vous nécessite d'ajouter la référence System.Drawing. P>

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


4 commentaires

Merci, excellent échantillon de travail. Je l'ai changé pour réduire la qualité 5 unités à la fois et l'a utilisé dans mon asp.net


Heureux de pouvoir aider quelqu'un d'autre! J'ai remarqué que l'image.fromfile (photo) n'était pas éliminée correctement! J'ai mis à jour mon code pour disposer correctement.


Le changement de qualité n'affecte pas la taille de mon état et la boucle va une boucle colposée infinie


Je ne transformerais pas la console.writeline () et voyez quelles valeurs vous obtenez. Peut-être que la qualité de l'image est déjà très faible ou que vous essayez de le redimensionner pour être trop petite, plus petite qu'un changement de différence de qualité peut être effectué?



1
votes

Convertir, réduire (itératif, en mémoire) et 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;
}


0 commentaires