Как уменьшить размер изображения в C# and.NET 3.5?

у меня есть снимок экрана, который я беру в своем мобильном приложении. Снимок экрана занимает около 32 КБ, при сохранении в PNG на диске.

Я отправляю их на центральный сервер SQL, и 32 КБ слишком велико для того количества раз, когда мне нужно будет хранить этот снимок экрана (приблизительно 2500 раз в день).

есть ли какой-либо обман, который я могу сделать, чтобы заставить его сэкономить меньше?

вот код, который я использую сейчас, чтобы взять его из Bitmap в байт (для отправки на сервер для хранение):

MemoryStream stream = new MemoryStream();
 _signatureImage.Save(stream, ImageFormat.Png);
 return stream.ToArray();

_signatureImage это Bitmap и это скриншот, о котором идет речь.

вот пример снимка экрана, который я сохраняю:

Screen Shot Image

вещи, которые приходят на ум (но я не знаю, как это сделать):

  1. уменьшите фактическую высоту и ширину изображения (но, надеюсь, таким образом, чтобы не исказить его).
  2. измените его на черно-белое изображение (не уверен, что я увижу реальную экономию места от этого)
  3. сжать его больше (мне это не нравится, потому что тогда он не читается из базы данных).

обратите внимание, все это должно быть сделано программно и не может занять много времени, поэтому сложные манипуляции с изображениями отсутствуют.

Спасибо за любую помощь.

7 ответов


    private static Image ResizeImage(int newSize, Image originalImage)
    {
        if (originalImage.Width <= newSize)
            newSize = originalImage.Width;

        var newHeight = originalImage.Height * newSize / originalImage.Width;

        if (newHeight > newSize)
        {
            // Resize with height instead
            newSize = originalImage.Width * newSize / originalImage.Height;
            newHeight = newSize;
        }

        return originalImage.GetThumbnailImage(newSize, newHeight, null, IntPtr.Zero);
    }

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

EDIT:

вы можете создать новый растровый объект и изменить размер исходного изображения в этот растровый объект.

Bitmap b = new Bitmap(newWidth, newHeight);
Graphics g = Graphics.FromImage((Image)b);
g.InterpolationMode = InterpolationMode.HighQualityBicubic;

g.DrawImage(imgToResize, 0, 0, newWidth, newHeight);
g.Dispose();

return (Image)b;

У меня нет компактной рамки, но кажется, что это должно работать для вас.


Если глубина цвета не является проблемой, вы можете изменить его на черно-белый или 16 цветовой режим. Должна быть значительная экономия по сравнению с требованиями хранения 24-bpp (или 32-bpp с alpha) png. Другая вещь, о которой нужно думать, - это сохранить ее как a .gif файл в 256 цветовом режиме.

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


изменить цветовую палитру на более низкую глубину цвета. Взгляните на этот вопрос (хорошо выглядишь на answert), который показывает преобразование в 1bpp. Вы можете перейти на 8bpp вместо 1bpp и иметь значительную экономию размера. Механизм преобразования будет таким же, как показано на рисунке.

редактировать

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

Изменить 2

Если просто изменение размера изображения является разумным решением (вы, очевидно, потеряете данные при этом), то вы можете использовать пространство имен изображений в SDF для создания миниатюры как Алекс объясняет.


Если монохромное изображение приемлемо, вы можете попробовать TIFF G4 (сжатие без потерь). TIFF G4 известен тем, что очень эффективен в размере файла для хранения черно-белого изображения. К сожалению, у меня нет никакой информации о том, как он сравнивается с PNG, но стоит изучить его.

здесь это информация и пример того, как это сделать в C#


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

EDIT: я лжец. Просто попробовал это в краске, и это около 40k по сравнению с оригинальным 20k. Я мог бы поклясться, что у них была огромная экономия пространства, когда я использовал их раньше...

EDIT EDIT: хорошо, по-видимому, у них есть огромные сбережения. Просто для этих изображений PNG имеет еще большую экономию. Просто попробовал 16-цветное растровое изображение, и это взорвалось это до 150k.

EDIT EDIT EDIT: но монохромное растровое изображение сжимается до 9k байт, в то время как PNG остается на 20k даже на молнии.


Итак, похоже, что если вы хотите пройти маршрут сжатия, вы можете сначала преобразовать в монохромное растровое изображение, а затем сжать для изображений около половины размера PNG.

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


запуск фейерверков с фотографией, которая не будет такой же, но должна дать идею

66% quality JPG with no smoothing is 17.5k
PNG8 with 256 colours is 58K (down to 42 using websnap palette)
PNG8 with black and white palette is 14k

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


fwiw хранение образа физически внутри SQL server не является оптимальным решением. Если вы используете Sql Server 2008, Вы должны посмотреть на поддержку потока файлов, которая позволит вам хранить физические образы на диске и получать к ним доступ, как если бы они были внутренними для SQL Server. Это, скорее всего, облегчит вашу потребность беспокоиться о размере файла.