代码之家  ›  专栏  ›  技术社区  ›  Pablo Fernandez

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

  •  10
  • Pablo Fernandez  · 技术社区  · 15 年前

    如何将C中的图像调整为某个硬盘大小,如2Mib?有没有比试错更好的方法(当然,即使是近似的)。

    在网上寻找解决方案时,需要搜索哪些特定的关键字?

    5 回复  |  直到 6 年前
        1
  •  0
  •   Lou Franco    8 年前

    这取决于你愿意改变什么

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

    很难猜测最终的磁盘大小,但是如果你知道一个起点,你可以得到一个很好的估计。减小尺寸可能是成比例的,减小每像素的位数也可能是成比例的。

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

        2
  •  9
  •   Guffa    15 年前

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

    info = fileSize / (width * height);
    

    我有一个图像是369636字节和1200x800像素,所以它每像素使用大约0.385字节。

    我有一个更小的版本,它是101111字节和600x400像素,所以它每像素使用大约0.4213字节。

    当你缩小一幅图像时,你会发现它通常每像素包含更多的信息,在这种情况下,大约要多9%。根据您的图像类型和压缩程度,您应该能够计算信息/像素比例增加量(C)的平均值,以便计算大致的文件大小:

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

    从中,您可以提取一个公式,用于确定要使图像达到特定文件大小所需的大小:

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

    这将使您非常接近所需的文件大小。如果您想更近一点,可以将图像调整到计算出的大小,压缩它,然后根据得到的文件大小计算每个像素的新字节值。

        3
  •  4
  •   Zach Wymer    10 年前

    我通过降低质量来达到这个目的,直到达到我想要的尺寸。

    注意:需要添加系统。图纸参考。

    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
  •  1
  •   Razvi    15 年前

    如果是24位BMP,我想你需要这样做:

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

    如果它是一个不同的BMP类型,如8位BMP,那么在头段中还会有更多的数据指定每个值的实际颜色,从0到255,因此在进行二进制搜索之前,您需要从总文件大小中减去更多的数据。

        5
  •  0
  •   Arun Prasad E S    6 年前

    转换、减少(迭代、内存中)和下载(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;
    }