2

好的,所以我有一个大学作业,我需要使用运行长度编码和霍夫曼编码来压缩图像。我专注于运行长度编码 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 值而不是实际字节。但是我不知道如何有效地将运行长度附加到标准字节数组(我想如果我将运行长度附加到开头,然后将所有内容移到 byte[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;
}
4

2 回答 2

3

您应该能够以与使用 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();
}

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

于 2014-11-26T21:28:08.047 回答
0

您在 ByteArrayOutputStream 中使用 flush 这会给您错误的信息以使您的代码运行只需删除该行

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;
}
于 2019-05-13T09:46:06.123 回答