Обеспечение того, чтобы экспортированный JPEG был меньше максимального размера файла - PullRequest
10 голосов
/ 12 мая 2011

В настоящее время у меня есть приложение, которое делает снимок экрана рабочего стола докладчика, а затем передает его по специальному протоколу зрителям. Чтобы изображения передавались достаточно быстро, чтобы получить частоту кадров 2–3 изображения в секунду, я должен убедиться, что размер изображения всегда меньше ~ 300 КБ.

Я использую C # для приложения докладчика, которое кодирует снимок экрана в JPEG с помощью процесса, описанного ниже. Меня беспокоит то, что качество изображения может сильно различаться при использовании статического сжатия. Если у меня есть приложение, которое захватывает мой экран, вывод изображений составит ~ 200 КБ, когда у меня полноэкранный режим Visual Studio, но если я сверну экран и у меня появится фон рабочего стола, это будет ~ 400 КБ.

Я мог бы поместить процесс кодирования в цикл и непрерывно уменьшать размер изображения, пока размер байтового массива не станет меньше 300 КБ, но это кажется утомительной операцией. Есть ли другой метод, который я мог бы использовать?

Спасибо заранее.

// get the screenshot
System.Drawing.Rectangle totalSize = System.Drawing.Rectangle.Empty;
//foreach (Screen s in Screen.AllScreens)
totalSize = System.Drawing.Rectangle.Union(totalSize, Screen.PrimaryScreen.Bounds);
Bitmap screenShotBitmap = new Bitmap(totalSize.Width, totalSize.Height, System.Drawing.Imaging.PixelFormat.Format32bppRgb);
screenShotBitmap.SetResolution(96, 96);
Graphics screenShotGraphics = Graphics.FromImage(screenShotBitmap);
screenShotGraphics.CopyFromScreen(totalSize.X, totalSize.Y,
                    0, 0, totalSize.Size, CopyPixelOperation.SourceCopy);
screenShotGraphics.Dispose();

// image codec information
ImageCodecInfo imageCodecInfo = GetEncoderInfo("image/jpeg");

// encoder settings
System.Drawing.Imaging.Encoder encoderQuality;
System.Drawing.Imaging.Encoder encoderColor;
encoderQuality = System.Drawing.Imaging.Encoder.Quality;
encoderColor = System.Drawing.Imaging.Encoder.ColorDepth;

// compression & quality for JPEG output
Int64 quality = 40L;

// storage for exported JPEG
byte[] screenShotByteArray;

// encoder parameters
EncoderParameter encoderQualityParameter = new EncoderParameter(encoderQuality, quality);
//EncoderParameter encoderColorParameter = new EncoderParameter(encoderColor, 8L);

// encoder parameters table
EncoderParameters encoderParameters = new EncoderParameters(1);
encoderParameters.Param[0] = encoderQualityParameter;
//encoderParameters.Param[1] = encoderColorParameter;

// get the code into a memory stream
MemoryStream screenShotMemoryStream = new MemoryStream();
screenShotBitmap.Save(screenShotMemoryStream, imageCodecInfo, encoderParameters);

// convert to a byte array
screenShotByteArray = screenShotMemoryStream.GetBuffer();

// close the memory stream
screenShotMemoryStream.Close();

1 Ответ

5 голосов
/ 12 мая 2011

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

РЕДАКТИРОВАТЬ:Немного объяснив бинарный поиск.Возьмите гипотетический случай изображения, которое сжимается до quality*10000 байтов, поэтому оптимальным параметром качества будет 30. Теперь наивным подходом будет попытка установить фиксированный параметр качества (например, 80, который даст 800 000 байтов), а затем уменьшить его наопределенное количество до 300000 байт.Если вы хотите снизить качество изображения на 5 на каждом шаге, попробуйте 12 настроек качества этим методом, пока не найдете нужную настройку. бинарный поиск даст результат быстрее, например:

Quality    Size    Next step
80         800000  Too big, so quality := quality/2
40         400000  Too big, so quality := quality/2
20         200000  Too small, so quality := (40+20)/2
30         300000  Reached desired size

Это дает результат только после 4 попыток (или 3 в зависимости от того, что 200000 байт слишком мало или для вас просто отлично)).Поскольку размер не имеет линейного отношения к качеству, этот пример немного нереалистичен, но бинарный поиск все же должен давать вам лучшие результаты, чем наивный подход.

Вы также можете использовать некоторые типичные изображения для «обучения»,Закодируйте их, используя различные настройки качества (например, 100,90, ..., 20,10) и посмотрите, насколько они велики по сравнению с их исходным размером.Это может дать хорошую первую оценку в большинстве случаев, хотя вам все равно придется корректировать при обнаружении изображений с гораздо более или менее подробной информацией в них.

В качестве альтернативы, посмотрите на кодировщики JPEG2000, у которых есть возможность установитьразмер файла вместо качества.

РЕДАКТИРОВАТЬ: Я не знаю библиотек кодирования JPEG2000 для C #, кажется, только плавающие вокруг декодеры, так что это может быть сложнее, чем я думал вначале.Вы можете попробовать CSJ2K , но описание не похоже на то, что оно готово к использованию.

...