Java中的运行长度编码图像压缩

时间:2014-11-26 20:48:40

标签: java image-processing image-compression run-length-encoding

好的,所以我有一个大学任务,我需要使用行程编码和霍夫曼编码来压缩图像。我专注于运行长度编码atm,因为我不认为我有时间实现霍夫曼。

我目前正在做的是传入缓冲图像,然后执行

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;
}

获取图像的字节。 然后我接受并进行实际的压缩,为此我要使用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 ]在数组中向下运行长度数量..但这将是非常低效并且容易出错...可能)

然后我需要将其保存为图像,这显然目前尚未正常工作,但我目前获得的代码是

 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;
}

2 个答案:

答案 0 :(得分:2)

您应该能够以与使用StringBuffer完全相同的方式使用ByteArrayOutputStream:

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并返回。

顺便说一句,该算法效率低下,可能是错误的。迭代每个字符,然后为每个字符迭代字符范围。你不需要这样做。你已经遍历了所有角色,所以你需要做的就是记住最后一个角色是什么,并相应地进行交流。

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();
}

您将看到这只触及每个字节值一次。

答案 1 :(得分:0)

您在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;
}