如何将C#中的图像大小调整为某个硬盘大小?

pup*_*eno 10 c# image-manipulation image image-processing image-resizing

如何将图像中的图像大小调整为C#到某个硬盘大小,如2MiB?有没有比试验和错误更好的方法(当然,即使它是近似的).

尝试在网络上找到解决方案时要搜索的任何特定关键字?

Guf*_*ffa 9

您可以通过将原始图像大小除以像素数来计算图像的近似信息级别:

info = fileSize / (width * height);
Run Code Online (Sandbox Code Playgroud)

我有一个369636字节和1200x800像素的图像,所以它每像素使用~0.385字节.

我有一个101111字节和600x400像素的较小版本,因此它每像素使用~0.4213字节.

缩小图像时,您会发现每个像素通常会包含更多的信息,在这种情况下大约多9%.根据您的图像类型以及缩小它们的数量,您应该能够计算信息/像素比例增加的平均值(c),以便您可以计算出近似的文件大小:

newFileSize = (fileSize / (width * height)) * (newWidth * newHeight) * c
Run Code Online (Sandbox Code Playgroud)

通过此,您可以提取一个公式,以确定图像达到特定文件大小所需的大小:

newWidth * newHeight = (newFileSize / fileSize) * (width * height) / c
Run Code Online (Sandbox Code Playgroud)

这将使您非常接近所需的文件大小.如果您想要靠近,可以将图像调整为计算大小,压缩它并根据您获得的文件大小计算每像素值的新字节数.


Zac*_*mer 5

我通过降低质量直到达到期望的尺寸来实现这一目标。

注意:要求您添加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;
}
}
}
Run Code Online (Sandbox Code Playgroud)


Lou*_*nco 0

这取决于你愿意改变什么

  1. 使图像尺寸变小
  2. 更改图像的格式
  3. 如果格式支持有损压缩,请降低质量
  4. 如果您存储不需要的元数据,请将其删除
  5. 减少颜色数量(以及每像素位数)
  6. 更改为调色板格式
  7. 更改为调色板格式并减少颜色

很难猜测最终的磁盘大小是多少,但如果您知道起点,则可以获得相当好的估计。减小尺寸可能成比例,减少每像素位数也可能成比例。

如果您更改格式、压缩或质量,这实际上只是一种猜测——很大程度上取决于图像内容。您可以通过在与您认为会看到的内容相匹配的图像语料库上进行尝试来获得良好的范围。