Что касается первоначального вопроса, как создавать несжатые JPEG: никто не может, по фундаментальным причинам. Хотя я изначально предполагал, что можно написать несжатый кодировщик jpg, производящий выходные данные, которые можно декодировать любым существующим декодером, манипулируя задействованным деревом Хаффмана, мне пришлось отклонить его . Кодирование Хаффмана - это только последний шаг целого конвейера преобразований, который нельзя пропустить. Пользовательские деревья Хаффмана могут также сломать менее сложные декодеры.
Для ответа, который учитывает изменение требований, внесенное в комментарии (измените размер и сожмите любым способом, просто дайте мне нужный файлsize) можно рассуждать так:
Спецификация jpeg файла определяет маркер конца изображения. Таким образом, есть вероятность, что исправление нулей (или просто чего-нибудь) впоследствии не имеет значения. Эксперимент по исправлению некоторых изображений до определенного размера показал, что gimp, chrome, firefox и ваш JpegApp проглотили такой раздутый файл без жалоб.
Было бы довольно сложно создать сжатие, которое для любого изображения сжимается точно доВаше требование к размеру (тип: для изображения A вам необходим коэффициент сжатия 0,7143, для изображения B 0,9356633, для C 12,445 ...). Однако есть попытки предсказать коэффициенты сжатия изображения на основе необработанных данных изображения.
Поэтому я бы предложил просто изменить размер / сжать до любого размера <20480, а затем залатать его: </p>
вычислить коэффициент масштабирования на основе исходного размера jpg ижелаемый размер, включая запас прочности, чтобы учесть неопределенный характер проблемы
изменить размер изображения с этим соотношением
пропустить пропущенные байтыточно соответствовать желаемому размеру
Как указано здесь
private static void scaleAndcompress(String fileNameIn, String fileNameOut, Long desiredSize) {
try {
long size = getSize(fileNameIn);
// calculate desired ratio for conversion to stay within size limit, including a safte maring (of 10%)
// to account for the vague nature of the procedure. note, that this will also scale up if needed
double desiredRatio = (desiredSize.floatValue() / size) * (1 - SAFETY_MARGIN);
BufferedImage inImg = ImageIO.read(new File(fileNameIn));
int widthOut = round(inImg.getWidth() * desiredRatio);
int heigthOut = round(inImg.getHeight() * desiredRatio);
BufferedImage outImg = new BufferedImage(widthOut, heigthOut, BufferedImage.TYPE_INT_RGB);
outImg.getGraphics().drawImage(inImg.getScaledInstance(widthOut, heigthOut, Image.SCALE_SMOOTH), 0, 0, null);
JPEGImageWriter imageWriter = (JPEGImageWriter) ImageIO.getImageWritersByFormatName("jpg").next();
ByteArrayOutputStream outBytes = new ByteArrayOutputStream();
imageWriter.setOutput(new MemoryCacheImageOutputStream(outBytes));
imageWriter.write(null, new IIOImage(outImg, null, null), new JPEGImageWriteParam(null));
if (outBytes.size() > desiredSize) {
throw new IllegalStateException(String.format("Excess output data size %d for image %s", outBytes.size(), fileNameIn));
}
System.out.println(String.format("patching %d bytes to %s", desiredSize - outBytes.size(), fileNameOut));
patch(desiredSize, outBytes);
try (FileOutputStream outFileStream = new FileOutputStream(new File(fileNameOut))) {
outBytes.writeTo(outFileStream);
}
} catch (IOException e) {
e.printStackTrace();
}
}
private static void patch(Long desiredSize, ByteArrayOutputStream bytesOut) {
long patchSize = desiredSize - bytesOut.size();
for (long i = 0; i < patchSize; i++) {
bytesOut.write(0);
}
}
private static long getSize(String fileName) {
return (new File(fileName)).length();
}
private static int round(double f) {
return Math.toIntExact(Math.round(f));
}