Максимально возможное сжатие изображения с помощью setCompressionQuality

Прежде чем я начну, нет, это не возможный дублирующий вопрос для теоретического предела сжатия . Мне просто нужно найти способ сжать изображение на несколько сотен байт больше, чем оно есть, используя JAVA.

Я пытался сжать изображение размером 5 КБ. Максимальное сжатие уменьшает его до 980 байт, что довольно эффективно, но мне нужно, чтобы он был сжат хотя бы до 500 байт.

Вот мой фрагмент кода:

  File compressedImageFile = new File("D:\\compress.jpg");
  OutputStream os =new FileOutputStream(compressedImageFile);

  Iterator<ImageWriter>writers = 
  ImageIO.getImageWritersByFormatName("jpg");
  ImageWriter writer = (ImageWriter) writers.next();

  ImageOutputStream ios = ImageIO.createImageOutputStream(os);
  writer.setOutput(ios);

  ImageWriteParam param = writer.getDefaultWriteParam();
  param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
  param.setCompressionQuality(0.01f);
  writer.write(null, new IIOImage(image, null, null), param);
  os.close();
  ios.close();
  writer.dispose();

Здесь compressedImageFile — это буферизованное изображение, которое я получил из входного файла изображения. И, в строке param.setCompressionQuality(0.01f), сколько бы я ни ставил значение ниже 0.01f, это не имеет значения. Является ли 0.01f нижним пределом сжатия?

Если да, то есть ли способ сжать его дальше?


person deathstroke    schedule 14.06.2014    source источник
comment
возможный дубликат Любой теоретический предел сжатия?   -  person torquestomp    schedule 14.06.2014
comment
Нисколько. Я не собираюсь сжимать его до чрезвычайно малых значений. И это не теоретически. Мне нужно знать, есть ли способ сжать изображение на несколько сотен байтов дальше в JAVA, используя указанный метод или любой другой метод.   -  person deathstroke    schedule 14.06.2014


Ответы (2)


Значение, которое передается методу setCompressionQuality, является значением float, которое должно находиться в диапазоне от 0,0f до 1,0f. Однако сжатие не является чем-то «непрерывным» или «линейным» в этом смысле. Вы не можете себе представить, что файл со 100 байтами будет иметь 100 байт для качества 1,0, 50 байт для качества 0,5 и 0 байт для качества 0,0. Точно так же нельзя ожидать разницы в сжатии для качества 0,000001 и 0,000002.

Значение, которое передается этому методу, используется для внутренних вычислений, в частности, для настройки таблицы квантования JPEG. Вы можете ознакомиться с классами из javax.imageio.plugins.jpeg, но... ожидайте, что вы не поймете их без глубоких базовых знаний. В любом случае значение от 0,0 до 1,0 должно быть дискретизировано в любой форме. Грубо говоря: оно может быть преобразовано в значение int от 0 до 255, поэтому может не быть разницы в сжатии для 0,01 и 0,00, поскольку оба значения будут преобразованы в одно и то же значение int, а именно 0.

Это может объяснить, почему нет разницы в сжатии для «небольших» различий в значениях. Причина, по которой файл изображения вряд ли может быть сжат до сколь угодно малого размера, заключается в том, что существует предел сжатия, подразумеваемый используемым алгоритмом. Конечно, вы можете создать собственное сжатие наподобие JPEG, где максимальное сжатие превращает изображение в большой прямоугольник с одним цветом, который теоретически (!) может храниться как один байт (или, может быть, 3 байта). Но это просто не предназначено для сжатия JPEG.

В https://stackoverflow.com/a/22016608/3182664 я разместил небольшое служебное приложение, которое позволяет вам настроить желаемое размер изображения и желаемое сжатие. Например, вы можете выбрать размер файла 10 КБ, и программа рассчитает уровень сжатия, необходимый для достижения этого размера файла. Однако это не позволит вам добиться более высокого уровня сжатия, чем при ручной установке качества 0,0.


РЕДАКТИРОВАТЬ: Что касается комментариев и других ответов, относящихся к теории информации: здесь это не совсем применимо. Произвольное большое и сложное изображение теоретически может быть сжато до размера всего 3 байта, при условии, что вся информация об исходном изображении будет потеряна. JPEG является сжатием с потерями, и некоторая информация теряется для всех настроек качества, кроме самого высокого. Так что это не связано с теорией информации, а просто с вопросом о том, какую потерю информации человек готов принять и что поддерживается стандартом JPEG. (Например, каждый файл JPEG может содержать некоторую информацию, такую ​​как таблица квантования, которая всегда может занимать несколько байтов независимо от фактического содержимого изображения).

person Marco13    schedule 14.06.2014
comment
Я видел служебное приложение, которое вы разместили. Хотя это не помогает мне, это может быть полезно для меня в будущем. Спасибо. И спасибо за объяснение. - person deathstroke; 14.06.2014

Не имея самого изображения, никто не сможет ответить на ваш вопрос в данном конкретном случае. Суть теории сжатия заключается в том, что неважно, хотите ли вы «чрезвычайно малые» значения — любой желаемый размер сжатия может быть невозможен.

Для любого заданного алгоритма существуют изображения размером 5 КБ, которые вы даже не можете сжать до размера ниже 4,99 КБ. Для вашего изображения Колмогровская сложность в Java вполне может составлять 980 байт, и в этом случае в мире нет Java-кода, который мог бы сократить его до 500. Перейдите по ссылкам в дубликате, чтобы понять, почему то, о чем вы просите, потенциально невозможно. (Опять же, не имея под рукой фактических байтов изображения, никто не может точно сказать, существует ли алгоритм, позволяющий сократить его до 500 байт).

person torquestomp    schedule 14.06.2014
comment
Спасибо. Теперь я понимаю. - person deathstroke; 14.06.2014