Хорошо, поэтому у меня есть университетское задание, где мне нужно сжать изображение, используя кодировку Run-Length и кодировку huffman. Я сосредоточен на кодировании Run-Length atm, так как не думаю, что у меня будет время для реализации huffman.
То, что я сейчас делаю, - это передать буферное изображение, затем делать
public byte[] byteArray(BufferedImage image){
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] imageInByte = null;
try{
ImageIO.write(image, "BMP", baos);
baos.flush();
imageInByte = baos.toByteArray();
baos.close();
}catch(IOException e){
System.out.println(e.getMessage());
}
return imageInByte;
}
для получения байта изображения. Я тогда беру это и делаю фактическое сжатие, чтобы сделать это atm. Я использую stringBuffer, который, я уверен, ошибается, но я не могу придумать другой способ сделать это. поэтому код для этого
public String getRunLength(){
StringBuffer dest = new StringBuffer();
for(int i =0; i < imageByteArray.length; i++){
int runlength = 1;
while(i+1 < imageByteArray.length && imageByteArray[i] == imageByteArray[i+1]){
runlength++;
i++;
}
dest.append(runlength);
dest.append(imageByteArray[i]);
}
return dest.toString();
}
Я почти уверен, что не должен преобразовываться в строку, так как, когда я вернусь к байтам, я получаю значения ascii, а не фактические байты. Но я не могу понять, как я мог бы эффективно добавлять длину выполнения в стандартный байт-массив (я думаю, что смог бы это сделать, добавив длину начала в начало, а затем переместил все после байта [i + runLength] вниз runLength в массиве.. но это было бы крайне неэффективно и подвержено ошибкам... возможно)
Затем мне нужно сохранить его как образ, который, очевидно, не работает в настоящий момент, но код, который я сейчас получил,
try{
File newImage = new File("Saved.png");
ImageIO.write(rleImage, "BMP", newImage);
}catch(Exception e){
System.out.println("something fucked up");
}
Спасибо за любую помощь, которую вы могли бы предоставить :)
Просто заметил, что я пропустил ту часть, где я установил rleImage, который сделан как
public BufferedImage stringToImage(String runLengthEncode){
ByteArrayInputStream bais = new ByteArrayInputStream(runLengthEncode.getBytes());
try{
imageRLE = ImageIO.read(new ByteArrayInputStream(runLengthEncode.getBytes()));
}catch(IOException e){
}
//decode(runLengthEncode);
if(imageRLE == null)
System.out.println("imageRLE is null");
return imageRLE;
}
Вы должны иметь возможность использовать ByteArrayOutputStream точно так же, как вы используете StringBuffer:
public byte[] getRunLength(){
ByteArrayOutputStream dest = new ByteArrayOutputStream();
for(int i =0; i < imageByteArray.length; i++){
int runlength = 1;
while(i+1 < imageByteArray.length && imageByteArray[i] == imageByteArray[i+1]){
runlength++;
i++;
}
dest.write((byte)runlength);
dest.write((byte)imageByteArray[i]);
}
return dest.toByteArray();
}
Это позволяет избежать конвертации в char и обратно.
Кстати, алгоритм неэффективен и, вероятно, ошибочен. Вы перебираете каждого персонажа, а затем для каждого персонажа вы ожидаете пробел символов. Вам не нужно это делать. Вы уже проходите через все персонажи, поэтому все, что вам нужно сделать, это помнить, что такое последний персонаж, и ac соответственно.
public byte[] getRunLength(){
ByteArrayOutputStream dest = new ByteArrayOutputStream();
byte lastByte = imageByteArray[0];
int matchCount = 1;
for(int i=1; i < imageByteArray.length; i++){
byte thisByte = imageByteArray[i];
if (lastByte == thisByte) {
matchCount++;
}
else {
dest.write((byte)matchCount);
dest.write((byte)lastByte);
matchCount=1;
lastByte = thisByte;
}
}
dest.write((byte)matchCount);
dest.write((byte)lastByte);
return dest.toByteArray();
}
Вы увидите, что это касается каждого байтового значения только один раз.
вы используете flush в ByteArrayOutputStream, это даст вам неверную информацию, чтобы ваш код работал, просто удалите строку
public byte[] byteArray(BufferedImage image){
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] imageInByte = null;
try{
ImageIO.write(image, "BMP", baos);
imageInByte = baos.toByteArray();
baos.close();
}catch(IOException e){
System.out.println(e.getMessage());
}
return imageInByte;
}