Как получить миниатюру хорошего качества
Я пытаюсь создать миниатюру высокого качества этого изображения, с Java и Scalr 3.2
![full scale image]()
Это соответствующий исходный код, где THUMB_WIDTH = 77
и THUMB_HEIGHT = 57
BufferedImage srcImg = ImageIO.read(new File(sourceFile));
BufferedImage dstImg = Scalr.resize(srcImg, Scalr.Method.QUALITY,
THUMB_WIDTH, THUMB_HEIGHT);
ImageIO.write(dstImg, format, new File(destFile));
Если я использую format = "png"
, вот результат:
![png thumbnail]()
Если я использую format = "jpg"
, вот результат:
![jpg thumbnail]()
С imagemagick ident Я узнал, что JPEG сохранен с качеством 75, что совершенно недостаточно для создания красивой миниатюры, PNG не выглядит хорошо для меня.
Вот результат идентификации исходного файла и двух миниатюр:
$ identify 42486_1.jpg 42486_s1.jpg 42486_s1.png
42486_1.jpg JPEG 580x435 580x435+0+0 8-bit DirectClass 50.6KB 0.000u 0:00.000
42486_s1.jpg[1] JPEG 77x58 77x58+0+0 8-bit DirectClass 2.22KB 0.000u 0:00.000
42486_s1.png[2] PNG 77x58 77x58+0+0 8-bit DirectClass 12.2KB 0.000u 0:00.000
Вопросы
- Как улучшить качество созданного эскиза?
- Как сохранить JPEG с более высоким качеством? Я хотел бы попробовать с более высоким качеством и сравнить результаты. Я не нашел ничего в JavaDoc для ImageIO.write.
- Почему я скажу Scalr, что мои максимальные размеры 77x57 и выводят изображение 77x58? Я думаю, что это сохранить пропорцию, но это моя максимальная ширина и максимальная высота. Ширина или высота могут быть меньше, но не более.
ОБНОВЛЕНИЕ. С помощью веб-поиска я нашел статью о том, как настроить качество сжатия изображений JPEG. Я написал свой собственный метод, чтобы сохранить настройку BufferedImage качества:
/**
* Write a JPEG file setting the compression quality.
*
* @param image
* a BufferedImage to be saved
* @param destFile
* destination file (absolute or relative path)
* @param quality
* a float between 0 and 1, where 1 means uncompressed.
* @throws IOException
* in case of problems writing the file
*/
private void writeJpeg(BufferedImage image, String destFile, float quality)
throws IOException {
ImageWriter writer = null;
FileImageOutputStream output = null;
try {
writer = ImageIO.getImageWritersByFormatName("jpeg").next();
ImageWriteParam param = writer.getDefaultWriteParam();
param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
param.setCompressionQuality(quality);
output = new FileImageOutputStream(new File(destFile));
writer.setOutput(output);
IIOImage iioImage = new IIOImage(image, null, null);
writer.write(null, iioImage, param);
} catch (IOException ex) {
throw ex;
} finally {
if (writer != null) writer.dispose();
if (output != null) output.close();
}
}
Вот результаты. PNG:
![png thumbnail]()
Качество JPEG 75:
![jpg thumbnail]()
Качество JPEG 90 (гравитационные потоки сохраняются как качество JPEG 90):
![jpg thumbnail quality 90]()
и размер файла:
thumb90.jpg JPEG 77x58 77x58+0+0 8-bit DirectClass 6.89KB 0.000u 0:00.000
ОБНОВЛЕНИЕ 2: тест для сравнения Scalr с java-image-scaling.
private void scaleAndSaveImageWithScalr(String sourceFile, String destFile, int width, int height)
throws IOException {
BufferedImage sourceImage = ImageIO.read(new File(sourceFile));
BufferedImage destImage = Scalr.resize(sourceImage, Scalr.Method.QUALITY, width, height);
writeJpeg(destImage, destFile, JPEG_QUALITY);
}
private void scaleAndSaveImageWithJImage(String sourceFile, String destFile, int width, int height)
throws IOException {
BufferedImage sourceImage = ImageIO.read(new File(sourceFile));
ResampleOp resampleOp = new ResampleOp(width, height);
resampleOp.setFilter(ResampleFilters.getLanczos3Filter());
resampleOp.setUnsharpenMask(AdvancedResizeOp.UnsharpenMask.Normal);
BufferedImage destImage = resampleOp.filter(sourceImage, null);
writeJpeg(destImage, destFile, JPEG_QUALITY);
}
Качество JPEG 90, созданное с помощью Scalr:
![jpg thumb from scalr]()
Качество JPEG 90, сгенерированное с помощью масштабирования java-изображения:
![jpg thumb from java-image-scaling]()
Я больше не получал никаких отзывов, поэтому мой личный вывод заключается в том, что масштабирование java-image обеспечивает превосходное качество, и поэтому я выбираю библиотеку.
Ответы
Ответ 1
Это не полный ответ на ваш вопрос, но:
Что касается качества JPEG:
Качество сжатия можно установить с помощью ImageWriteParam
в качестве описанного здесь. Они предлагают использовать значение int
0 | 1, но я считаю, что вы должны фактически определять значение с плавающей точкой между 0.0 и 1.0.
Что касается проблем с размером масштабирования:
На странице Scalr:
ПРИМЕЧАНИЕ. Если указаны ширина и высота, которые нарушают изображения (например, попытка изменить размер изображения 800 × 600 на 150 × 150 квадрат) библиотека сначала рассмотрит ориентацию изображения (пейзаж/квадрат или портрет), а затем выберите основное измерение (пейзаж или квадрат используют ширину, портрет использует высоту), чтобы пересчитать правильный вторичный размер; игнорирование того, что было передано пользователемчто нарушало пропорции.
В вашем случае основным размером будет ширина 77, и поэтому ваш предел высоты 57 будет проигнорирован.
Ответ 2
@Stivlo, я сожалею, что не ответил на это, я никогда не получал уведомления от SO о вопросе.
java-image-scaling имеет несколько хороших фильтров, чтобы помочь с тонкой настройкой, если вам это нужно. Тем не менее, в v4.2 imgscalr я добавил новый ULTRA_QUALITY, который может приблизиться к тому, что вы хотите.
Я надеюсь, что это поможет, но поймите, что это ответ на почти год после факта, к сожалению. Извините.
Ответ 3
Я запускал те же тесты, и java-image-scaling окончательно добился лучших результатов для миниатюр меньше 250 пикселей. Он также поддерживает резкую фильтрацию, что делает результаты лучше.
Я сохраняю обе библиотеки, поскольку синтаксис Scalr часто бывает проще, только с одной строкой.
Ответ 4
Обратите внимание, что если ваши изображения имеют альфа-канал, обе библиотеки являются проблематичными. Я говорю только об уменьшающихся изображениях, я не тестировал их увеличение.
java-image-scaling может создать уродливую границу вокруг прозрачных ребер в зависимости от изображения, и это выглядит очень плохо. Я не нашел способа избежать этого.
Scalr только проблематично с использованием (ультра) качественных режимов. Его можно легко использовать таким образом, который работает отлично, хотя: бикубическая интерполяция оставляет артефакты в прозрачных изображениях, поэтому вы можете избежать этого. Поскольку он по умолчанию для (ультра) качественных изображений и scaleImageIncrementally() защищен, вам придется подклассифицировать его для этого, хотя, если вы хотите, чтобы качество (фракция выше 2 выглядела очень размытой с билинейной фильтрацией).
Ответ 5
Если вы хотите получить качественный результат, используйте библиотеку [RapidDecoder] [1]. Это просто:
import rapid.decoder.BitmapDecoder;
...
Bitmap bitmap = BitmapDecoder.from(getResources(), R.drawable.image) .scale(ширина, высота) .useBuiltInDecoder(правда) .decode();
Не забудьте использовать встроенный декодер, если вы хотите уменьшить масштаб менее 50% и результат HQ.