pcx游程编码、解码超详细讲解(附带java源码)

 编码过程:(以压缩灰度图为例):

   我们利用IO流读取到图片的所有像素字节后,按从头到尾的顺序逐个检查像素,对检查过程中连续重复出现相同像素值的那些像素,用一个标志字(flagbyte,最高 2 个比特置为 1)表示重复的次数(后 6 个比特表示重复次数,0 次重复表示孤立像素,1 次重复表示有 2 个连续像素。最多 63 次重复,表示最多可以对连续 64 个像素编码),用一个色度字节(colorbyte)表示这个重复的像素值,然后将这两个字节输出到压缩文件。对与前后像素的像素值都不相同的孤立像素,若其像素值小于 192,则直接用一个色度字节表示它的像素值并将该字节输出到压缩文件中;若其像素值大于等于192,则必须用一个标志字节(后 6 比特全为 0)和一个表示其像素值的色度字节来描述它,然后将这两个字节输出到压缩文件。重复以上过程直到处理完图像数组中的所有像素。

参考下图理解编码过程:

编码过程中不需要真正的去处理字节的比特值,而是直接换算成对应的十进制进行编码。另外,我们应注意到对于连续重复的像素以及孤立但色度值大于192的像素,输出时输出的是两个字节(标志字节和色度字节,其中孤立像素标志字节为11 000 000,六个零代表无重复)。

解码过程:

  将已经编码的文件读入内存中,顺序遍历检测,若检测到的像素值小于192,则该字节就是一个孤立的且色度小于192的像素,直接输出即可;对于检测到的大于或等于192的字节,则是一个标志字节,应输出的时该字节的下一个字节,输出次数为标志字节减去192在加1(加一是因为标志字节的后六位存储的为像素的重复次数,而要我们输出的是色度个数)。

编码程序:

public class Bm {
    public static void main(String[] args) {

        OutputStream fileOut=null;
        InputStream fileIn=null;
        
        try {
            //创建输入、出流
            fileIn=new FileInputStream("待编码文件绝对路径");
            fileOut=new FileOutputStream("编码后文件输出位置的绝对路径");

            //拿到文件大小
            int num=fileIn.available();

            //定义字节数组和像素数组
            byte[] bytes=new byte[num];
            int[] pixel=new int[num];

            //将像数值读入字节数组中
            fileIn.read(bytes);

           //将字节(-128~127)转换成int(0~255),存入像素数组中
            for (int i=0;i<bytes.length;i++){
                pixel[i]=(bytes[i]&0xff);
            }

            int temp=0;
          for(int i=0;i<pixel.length;i++){

              temp=pixel[i];
              int count=count(pixel[i],i,pixel,0);
              
              // 孤立像素
              if(count==1){
                  fileOut.write(temp < 192 ? new byte[]{(byte) temp}: new byte[]{(byte) 192, (byte) temp});
                  fileOut.flush();
                  i+=count-1;
              }

              //有重复的像素
                if(count>1){
                    //当重复次数超出63时,分多次输出
                    if(count>=63){
                        int n=count/63;
                        int m=count%63;
                        while(n>0){
                            fileOut.write(new byte[]{(byte)(192+63), (byte) temp});
                            fileOut.flush();
                            n--;
                        }
                        
                        fileOut.write(new byte[]{(byte)(192+m), (byte) temp});
                        fileOut.flush();
                    }
                    //找到count个相同的数字,按照题意重复次数则为num=count-1,复原时则有num+1(即count)个重复字节
                    fileOut.write(new byte[]{(byte)(192+count-1), (byte) temp});
                    fileOut.flush();
                    //因为for循环每次下标会加1,所以此处需要减一,也可以改用while循环或将for循环改成自加0
                    i+=count-1;
                }
          }

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if (fileIn != null) {
                try {
                    fileIn.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (fileOut != null) {
                try {
                    fileOut.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

        }

    }

    /*
    计数方法
     */
    public static int count(int value,int index,int[] array,int count){

        if(index+1==array.length){
            return ++count;
        }
        if(value==array[index]){
            count++;
            index++;
            return count(value,index,array,count);
        }
       return count;
    }
}

解码程序:

public class Jm {
    public static void main(String[] args) {
        InputStream inputStream=null;
        OutputStream outputStream=null;
        try {
            inputStream=new FileInputStream("待解码文件的绝对路径");
            outputStream=new FileOutputStream("解码输出文件的路径");
            byte[] bytes=new byte[inputStream.available()];
            int []pixel=new int[inputStream.available()];
            inputStream.read(bytes);
            //将字节(-128~127)转换成int(0~255),存入像素数组中
            for (int i=0;i<bytes.length;i++){
                pixel[i]=(bytes[i]&0xff);
            }
            for(int i=0;i<pixel.length;i++){
                if(pixel[i]<192){
                    outputStream.write((byte) pixel[i]);
                    outputStream.flush();
                    continue;
                }
                //因为编码时用的是重复次数,而像素个数为重复次数加一,所以这里写出次数得加一
                int n=pixel[i]-192+1;
                while(n>0){
                    outputStream.write((byte)pixel[i+1]);
                    outputStream.flush();
                    n--;
                }
                //
                i++;
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (outputStream != null) {
                try {
                    outputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

        }

    }
}

到这里就结束了,有问题可以评论区提出哦,记得点个赞再走啊!!!

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值