2014-02-06 4 views
0

У меня есть операция на сайте, которая обрывает изображение, однако получившееся обрезанное изображение выходит значительно больше с точки зрения размера файла (оригинал - 24k, а обрезанное изображение - как 650k). Поэтому я обнаружил, что мне нужно применить некоторое сжатие к изображению, прежде чем сохранять его. Я придумал следующее:Сжатие изображения не работает

public static System.Drawing.Image CropImage(System.Drawing.Image image, Rectangle cropRectangle, ImageFormat format) 
{ 
    var croppedImage = new Bitmap(cropRectangle.Width, cropRectangle.Height); 
    using (var g = Graphics.FromImage(croppedImage)) 
    { 
     g.InterpolationMode = InterpolationMode.HighQualityBicubic; 
     g.DrawImage(
      image, 
      new Rectangle(new Point(0,0), new Size(cropRectangle.Width, cropRectangle.Height)), 
      cropRectangle, 
      GraphicsUnit.Pixel); 
     return CompressImage(croppedImage, format); 
    } 
} 

public static System.Drawing.Image CompressImage(System.Drawing.Image image, ImageFormat imageFormat) 
{ 
    var bmp = new Bitmap(image); 
    var codecInfo = EncoderFactory.GetEncoderInfo(imageFormat); 
    var encoder = System.Drawing.Imaging.Encoder.Quality; 
    var parameters = new EncoderParameters(1); 
    var parameter = new EncoderParameter(encoder, 10L); 
    parameters.Param[0] = parameter; 

    using (var ms = new MemoryStream()) 
    { 
     bmp.Save(ms, codecInfo, parameters); 
     var resultImage = System.Drawing.Image.FromStream(ms); 
     return resultImage; 
    } 
} 

Я установил качество низко, чтобы увидеть, не было никаких изменений вообще. Нет. Урожай сохраняется правильно, но сжатие - это не радость. Если я вообще обойду CompressImage(), ни размер файла, ни качество изображения не будут отличаться.

Итак, 2 вопроса. Почему ничего не происходит? Есть ли более простой способ сжать результирующее изображение на «веб-оптимизацию», подобно тому, как фотошоп сохраняет веб-изображения (я думал, что он просто лишил много информации об этом, чтобы уменьшить размер).

+1

Какой образ вы читаете в и экономии? BMP сжимается с трудом. PNG или JPG сжимаются намного лучше. Я могу легко визуализировать giong от 24k PNG до 650k BMP. –

+0

Я читаю в png/jpg. Растровое изображение - это просто промежуточный объект. – Sinaesthetic

+0

Проблема заключается не в том, что вы читаете ... это то, что вы сохраняете. Plaese проверяет правильные настройки для condecInfo и объекта paramets ... Возможно, вы сохраняете изображение с более высоким качеством, чем оригинал ... – HiperiX

ответ

2

Ваша проблема заключается в том, что вы должны «сжать» (действительно кодировать) изображение при его сохранении, а не перед тем, как сохранить его. Объект Image в вашей программе всегда несжатый.

Сохранение в MemoryStream и чтение обратно из потока будут кодировать изображение, а затем снова декодировать его обратно до того же размера (с некоторой потерей качества в процессе, если вы используете JPEG). Однако, если вы сохраните его в файле с параметрами сжатия, вы получите файл сжатого изображения.

Использование этой подпрограммы с уровнем качества JPEG 90 на исходном изображении 153 КБ дает выходное изображение 102 КБ. Если вы хотите уменьшить размер файла (с большим количеством артефактов кодирования) изменить значение параметра датчика на что-то меньше, чем 90.

public static void SaveJpegImage(System.Drawing.Image image, string fileName) 
{ 
    ImageCodecInfo codecInfo = ImageCodecInfo.GetImageEncoders() 
     .Where(r => r.CodecName.ToUpperInvariant().Contains("JPEG")) 
     .Select(r => r).FirstOrDefault(); 

    var encoder = System.Drawing.Imaging.Encoder.Quality; 
    var parameters = new EncoderParameters(1); 
    var parameter = new EncoderParameter(encoder, 90L); 
    parameters.Param[0] = parameter; 

    using (FileStream fs = new FileStream(fileName, FileMode.Create)) 
    { 
     image.Save(fs, codecInfo, parameters); 
    } 
} 
+0

Итак, в моей конкретной реализации изображение никогда не сохраняется на диске. Изображение сохраняется как двоичная информация в базе данных, а затем считывается непосредственно на веб-страницу (MVC FileResult). Как сжать изображение и сохранить байты? Если я прочитаю сжатые байты из базы данных в изображение (промежуточное), на основе того, что вы говорите, он будет повторно раздувать размер. – Sinaesthetic

+0

И это практически идентично тому, что у меня есть в настоящее время, единственное отличие в том, что я прочитал его обратно в «Изображение», прежде чем возвращать его. Я попытался исключить эту часть и вернуть массив байтов из MemoryStream, но тот же результат - файл составляет 600k, когда оригинал был 24k. – Sinaesthetic

+0

Не уверен, насколько это оптимально, но у меня есть приложение в производстве, которое сохраняет изображения в Oracle Blob. В своем примере сразу после сохранения растрового изображения в поток памяти вы получите необработанные btyes из потока: 'byte [] imageBytes = ms.ToArray(); 'и сохраните массив байтов в базе данных. Вы можете использовать разные кодировки - когда вы читаете их обратно из базы данных, это точно так же, как если бы вы делали File.Read в массив байтов - обратите внимание, что это jpg или png, а не объект Image еще. Вам нужно будет создать поток из байта [] и загрузить его, чтобы получить изображение. – Doug

-1

Я считаю, что вы не должны распоряжаться MemoryStream в то время как вы используете образ, созданный с помощью изображения. FromStream, который относится к потоку. Создание Bitmap непосредственно из потока также не работает.

Попробуйте это:

формат
private static Image CropAndCompressImage(Image image, Rectangle rectangle, ImageFormat imageFormat) 
{ 
    using(Bitmap bitmap = new Bitmap(image)) 
    { 
     using(Bitmap cropped = bitmap.Clone(rectangle, bitmap.PixelFormat)) 
     { 
      using (MemoryStream memoryStream = new MemoryStream()) 
      { 
       cropped.Save(memoryStream, imageFormat); 
       return new Bitmap(Image.FromStream(memoryStream)); 
      } 
     } 
    } 
} 
Смежные вопросы