9

Как изменить размер изображения на C# до определенного размера жесткого диска, например, 2MiB? Есть ли лучший способ, чем проб и ошибок (даже если это приблизительный, конечно).Как изменить размер изображения на C# до определенного размера жесткого диска?

Любые ключевые слова для поиска при поиске решения в Интернете?

+2

Какое изображение? –

ответ

0

Это зависит от того, что вы готовы изменить

  1. сделать размер изображения меньше
  2. Изменение формата изображения
  3. Если формат поддерживает сжатие с потерями, снижение качества
  4. Если вы храните мета-данные, которые вам не нужны, удалите его
  5. уменьшить количество цветов (и бит на пиксель)
  6. Изменения в палитре формат
  7. Изменения к палитре формату и уменьшить цвет

Трудно угадать, что окончательный размер диска будет, но если вы знаете, отправную точку, которую вы можете получить довольно хорошую оценку , Уменьшение размера, вероятно, будет пропорциональным, уменьшение битов на пиксель также, вероятно, будет пропорциональным.

Если вы изменили формат, сжатие или качество, это действительно просто предположение - сильно зависит от содержимого изображения.Вероятно, вы можете получить хороший диапазон, попробовав его на корпусе изображений, который соответствует тому, что вы думаете, что увидите.

7

Вы можете рассчитать примерный уровень информации для изображения, принимая оригинальный размер изображения делится на число пикселей:

info = fileSize/(width * height); 

У меня есть изображение, которое 369636 байт и 1200x800 пикселей, поэтому он использует ~ 0,385 байт на пиксель.

У меня меньшая версия, которая составляет 101111 байт и 600x400 пикселей, поэтому она использует ~ 0,4213 байт на пиксель.

Когда вы уменьшаете изображение, вы увидите, что оно обычно содержит немного больше информации на пиксель, в данном случае около 9%. В зависимости от типа изображений и сколько вы уменьшить их, вы должны быть в состоянии вычислить среднее значение для того, насколько информация/пиксель рацион увеличивается (с), так что вы можете рассчитать приблизительный размер файла:

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

Из этого можно извлечь формулу для того, как большой, вы должны сделать изображение, чтобы достичь определенного размера файла:

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

Это поможет вам довольно близко к желаемому размеру файла. Если вы хотите приблизиться, вы можете изменить размер изображения до вычисленного размера, сжать его и вычислить новое значение байта на пиксель из полученного вами размера файла.

1

Если это 24bit 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, поэтому вам нужно будет вычесть больше из общего размера файла перед двоичным поиском.

2

Я достиг этого, уменьшив качество, пока не достиг желаемого размера.

NB: Требуется добавить ссылку 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; 
} 
} 
} 
+0

спасибо, большой рабочий образец. я изменил его, чтобы снизить качество 5 единиц за раз и использовал его в моем asp.net. –

+1

Рад, что я смог помочь кому-то еще! Я заметил, что Image.FromFile (фотография) не утилизируется должным образом! Я обновил свой код, чтобы правильно распоряжаться. –

Смежные вопросы