精华内容
下载资源
问答
  • libjpeg哈夫曼算法压缩图片

    千次阅读 2017-04-24 22:49:09
    Android原生的压缩方法,不在乎两种:通过设置simpleSize根据图片尺寸压缩图片;通过Bitmap.compress方法通过压缩图片质量,去压缩。但是我们当我们对图片质量和图片文件大小同时存在要求时,我们发现无论怎么去设置...

    之前的博客提到过关于图片压缩的方法: Android 图片压缩,Bitmap优化


    Android原生的压缩方法,不在乎两种:通过设置simpleSize根据图片尺寸压缩图片;通过Bitmap.compress方法通过压缩图片质量,去压缩。但是我们当我们对图片质量和图片文件大小同时存在要求时,我们发现无论怎么去设置参数,我们所做的效果总是不能尽如人意,而且同样大小的图片,效果却总是比iOS的效果差很多。

    其实归根到底的是iOS和Android的压缩算法存在一些差异。

    Android所用的是skia的压缩算法,它在google的很多地方,比如chrome、Android等都有使用,而Bitmap的压缩算法就是通过这个实现。而Skia是libjpeg进行了封装,google在实现skia时对其中一个地方进行了修改:通过哈夫曼算法来进行图片压缩,但是采用这个算法的时候,机器可能会出现性能问题,于是并没有调动这个方法。

    [plain]  view plain  copy
      在CODE上查看代码片 派生到我的代码片
    1. boolean optimize_coding   
    2. TRUE causes the compressor to compute optimal Huffman coding tables   
    3. for the image. This requires an extra pass over the data and   
    4. therefore costs a good deal of space and time. The default is   
    5. FALSE, which tells the compressor to use the supplied or default   
    6. Huffman tables. In most cases optimal tables save only a few percent   
    7. of file size compared to the default tables. Note that when this is   
    8. TRUE, you need not supply Huffman tables at all, and any you do   
    9. supply will be overwritten.  
    但是,这个问题在十年前或许存在,但是现在的机器已经完全可以解决性能问题,而google却忘记了更正当年的代码。


    接下来,我们就自己去编译生成libjpeg的动态库,然后调用。

    github中android libjpeg的源文件地址:https://github.com/libjpeg-turbo/libjpeg-turbo

    这个我们需要自己去编译,但是已经有人帮我们编译好了,压缩算法也已经实现,因此,我们去下载然后编译即可:https://github.com/bither/bither-android-lib


    首先将上面下载好的已经编译好的libjpeg放到jni目录下,将下图内容都放到jni目录中:


    安装好ndk以后,直接输入ndk-build即可。

    接下来就会编译生成arm下的动态库,使用的时候必须在项目中新建一个包net.bither.util,然后加入下面这个类方法,也就是使用了libjpeg开启哈夫曼算法的压缩算法:

    [java]  view plain  copy
      在CODE上查看代码片 派生到我的代码片
    1. /* 
    2.  * Copyright 2014 http://Bither.net 
    3.  * 
    4.  * Licensed under the Apache License, Version 2.0 (the "License"); 
    5.  * you may not use this file except in compliance with the License. 
    6.  * You may obtain a copy of the License at 
    7.  * 
    8.  *    http://www.apache.org/licenses/LICENSE-2.0 
    9.  * 
    10.  * Unless required by applicable law or agreed to in writing, software 
    11.  * distributed under the License is distributed on an "AS IS" BASIS, 
    12.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
    13.  * See the License for the specific language governing permissions and 
    14.  * limitations under the License. 
    15.  */  
    16.   
    17. package net.bither.util;  
    18.   
    19. import android.graphics.Bitmap;  
    20. import android.graphics.Bitmap.Config;  
    21. import android.graphics.Canvas;  
    22. import android.graphics.Rect;  
    23. import android.util.Log;  
    24.   
    25. public class NativeUtil {  
    26.     private static int DEFAULT_QUALITY = 95;  
    27.   
    28.     public static void compressBitmap(Bitmap bit, String fileName,  
    29.             boolean optimize) {  
    30.         compressBitmap(bit, DEFAULT_QUALITY, fileName, optimize);  
    31.   
    32.     }  
    33.   
    34.     public static void compressBitmap(Bitmap bit, int quality, String fileName,  
    35.             boolean optimize) {  
    36.         Log.d("native""compress of native");  
    37.   
    38.         // if (bit.getConfig() != Config.ARGB_8888) {  
    39.         Bitmap result = null;  
    40.   
    41.         result = Bitmap.createBitmap(bit.getWidth() / 3, bit.getHeight() / 3,  
    42.                 Config.ARGB_8888);// 缩小3倍  
    43.         Canvas canvas = new Canvas(result);  
    44.         Rect rect = new Rect(00, bit.getWidth(), bit.getHeight());// original  
    45.         rect = new Rect(00, bit.getWidth() / 3, bit.getHeight() / 3);// 缩小3倍  
    46.         canvas.drawBitmap(bit, null, rect, null);  
    47.         saveBitmap(result, quality, fileName, optimize);  
    48.         result.recycle();  
    49.         // } else {  
    50.         // saveBitmap(bit, quality, fileName, optimize);  
    51.         // }  
    52.   
    53.     }  
    54.   
    55.     private static void saveBitmap(Bitmap bit, int quality, String fileName,  
    56.             boolean optimize) {  
    57.   
    58.         compressBitmap(bit, bit.getWidth(), bit.getHeight(), quality,  
    59.                 fileName.getBytes(), optimize);  
    60.   
    61.     }  
    62.   
    63.     private static native String compressBitmap(Bitmap bit, int w, int h,  
    64.             int quality, byte[] fileNameBytes, boolean optimize);  
    65.   
    66.     static {  
    67.         System.loadLibrary("jpegbither");  
    68.         System.loadLibrary("bitherjni");  
    69.   
    70.     }  
    71.   
    72. }  

    注意包名和方法名都是不能变的,因为在编译的时候已经被确定。

    如果我们想要去修改方法名放入自己的项目中怎么办。那我们就需要去修改一下bitherlibjni.c这个文件。

    例如我想把这个方法放在com.example.test中的ImageUtils中,

    我们只需要把c文件中的

    jstring Java_net_bither_util_NativeUtil_compressBitmap(JNIEnv* env,
          jobject thiz, jobject bitmapcolor, int w, int h, int quality,
          jbyteArray fileNameStr, jboolean optimize) {
    修改为

    jstring Java_com_example_test_ImageUtils_compressBitmap(JNIEnv* env,
          jobject thiz, jobject bitmapcolor, int w, int h, int quality,
          jbyteArray fileNameStr, jboolean optimize) {
    这个对会ndk开发的同学应该都知道,接下来我们重新运行ndk-build就可以重新替换so文件然后调用我们自己的libjpeg了。

    但是,目前libjpeg是很多年前的了。github上这个库只支持arm架构的cpu,如果我们想用这个库的话,只能通过在加载so文件的时候对其进行trycatch处理,来防止x86等其他cpu架构的机器加载so文件报错。


    压缩效果对比:

    原图:



    bitmap压缩:




    libjpeg压缩:




    github下载地址:https://github.com/xiaoqiAndroid/LibJpegCompress/tree/master

    展开全文
  • 该代码实现哈夫曼基本算法,并对输入的图片进行压缩,最终输出译码后的图片,代码真实可用,想理解学习哈夫曼压缩的同学可以看看。
  • libjpeg-turbo | Main / libjpeg-turbo libjpeg编译文档 ...Mac环境编译 libjpeg压缩库 cmake version 3.5.2 针对的arm-v7完整的编译脚本 #!/bin/bash # Set these variables to suit your needs NDK_PATH=/...

    libjpeg-turbo | Main / libjpeg-turbo

    libjpeg编译文档
    libjpeg-turbo/BUILDING· GitHub
    Mac环境编译 libjpeg压缩库
    cmake version 3.5.2
    针对的arm-v7完整的编译脚本

    #!/bin/bash
    
    # Set these variables to suit your needs
    NDK_PATH=/Users/dsh/Downloads/android/NDK/android-ndk-r17c
    TOOLCHAIN=gcc
    ANDROID_VERSION=21
    
    # cd {build_directory}
    cmake -G"Unix Makefiles" \
      -DANDROID_ABI=armeabi-v7a \
      -DANDROID_ARM_MODE=arm \
      -DANDROID_PLATFORM=android-${ANDROID_VERSION} \
      -DANDROID_TOOLCHAIN=${TOOLCHAIN} \
      -DCMAKE_ASM_FLAGS="--target=arm-linux-androideabi${ANDROID_VERSION}" \
      -DCMAKE_TOOLCHAIN_FILE=${NDK_PATH}/build/cmake/android.toolchain.cmake \
    # [additional CMake flags] {source_directory}
    make
    

    编译完成以后 需要在libjpeg-turbo-2.0.4 文件夹下找到以下文件
    1、 需要用到的头文件
    turbojpeg.h
    jpeglib.h
    jmorecfg.h
    jerror.h
    jconfig.h

    2、编译完成的静态库
    libturbojpeg.a

    编写代码

        const char *path = env->GetStringUTFChars(path_, 0);
    
    
        //从bitmap获取argb数据
        AndroidBitmapInfo info;//info=new 对象();
        //获取里面的信息
        AndroidBitmap_getInfo(env, bitmap, &info);
        //得到图片中的像素信息
        uint8_t *pixels;//uint8_t char    java   byte     *pixels可以当byte[]
        AndroidBitmap_lockPixels(env, bitmap, (void **) &pixels);
        //jpeg argb中去掉他的a ===>rgb
        int w = info.width;
        int h = info.height;
        int color;
        //开一块内存用来存入rgb信息
        uint8_t *data = (uint8_t *) malloc(w * h * 3);//data中可以存放图片的所有内容
        uint8_t *temp = data;
        uint8_t r, g, b;
        //循环取图片的每一个像素
        for (int i = 0; i < h; i++) {
            for (int j = 0; j < w; j++) {
                color = *(int *) pixels;//0-3字节  color4 个字节  一个点
                //取出rgb
                r = (color >> 16) & 0xFF;//    #rrggbb  16  0000rr   8  00rrgg
                g = (color >> 8) & 0xFF;
                b = color & 0xFF;
                //存放,以前的主流格式jpeg    bgr
                *data = b;
                *(data + 1) = g;
                *(data + 2) = r;
                data += 3;
                //指针跳过4个字节
                pixels += 4;
            }
        }
        //把得到的新的图片的信息存入一个新文件 中
        write_JPEG_file(temp,w,h,q,path);
    
        AndroidBitmap_unlockPixels(env, bitmap);
        free(data);
    
        env->ReleaseStringUTFChars(path_, path);
    

    理解哈夫曼算法
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EMNQFZTX-1580611679589)(:storage/83fcef4e-9744-4603-8b77-b6af6186e1c1/b5c83a8f.png)]

    编写libjepg 压缩代码

    void write_JPEG_file(uint8_t *data, int width, int height, jint quality, const char *path) {
        // 1、 创建jpeg压缩对象
        jpeg_compress_struct jpegStruct;
        jpeg_error_mgr errorMgr;
        jpegStruct.err = jpeg_std_error(&errorMgr);
        jpeg_create_compress(&jpegStruct);
        // 2、 指定存储文件
        FILE * file = fopen(path,"wb");
        jpeg_stdio_dest(&jpegStruct,file);
        // 3、 设置压缩参数
        jpegStruct.image_width = width;
        jpegStruct.image_height = height;
        jpegStruct.input_components = 3;
        jpegStruct.in_color_space = JCS_RGB;
        jpeg_set_defaults(&jpegStruct);
        jpegStruct.optimize_coding = true;
        jpeg_set_quality(&jpegStruct,quality,1);
        // 4、 开始压缩
        jpeg_start_compress(&jpegStruct,1);
        // 5、循环写入每一行数据
        int row_stride = width * 3;
        JSAMPROW row[1];
        while (jpegStruct.next_scanline < jpegStruct.image_height){
            uint8_t * pixels = data + jpegStruct.next_scanline;
            row[0] = pixels;
            jpeg_write_scanlines(&jpegStruct,row,1);
        }
        // 6、压缩完成
        jpeg_finish_compress(&jpegStruct);
    
        // 7、释放jpeg对象
        fclose(file);
        jpeg_destroy_compress(&jpegStruct);
    }
    
    展开全文
  • Huffman算法也是一种无损压缩算法,但与LZW压缩算法不同,Huffman需要得到每种字符出现概率的先验知识。通过计算字符序列中每种字符出现的频率,为每种字符进行唯一的编码设计,使得频率高的字符占的位数短,而频率...

    原文地址:https://blog.51cto.com/13598859/2070274

     

    Huffman算法也是一种无损压缩算法,但与LZW压缩算法不同,Huffman需要得到每种字符出现概率的先验知识。通过计算字符序列中每种字符出现的频率,为每种字符进行唯一的编码设计,使得频率高的字符占的位数短,而频率低的字符长,来达到压缩的目的。通常可以节省20%~90%的空间,很大程度上依赖数据的特性!Huffman编码是变长编码,即每种字符对应的编码长度不唯一。

    前缀码:任何一个字符的编码都不是同一字符集中另一种字符编码的前缀。Huffman编码为最优前缀码,即压缩后数据量最小。

    项目链接:https://github.com/ewgcat/CompressImageByHuffman

    使用libjpeg进行图片压缩(哈夫曼算法,无损压缩)

    使用方法:

    方法一、依赖compress

    方法二、拷贝example 的lib包下文件到你的项目,具体使用参考例子

    推荐方法 下载compress,根据具体需求,重新打包

    注意

    1、只支持armeabi;

    2、压缩过程是耗时操作,必须在子线程中调用

    3、图片压缩有最大极限,如果要指定压缩到多少KB,请结合其他压缩方式使用。

    使用效果

    将3.58M的图片无损压缩到100KB

    展开全文
  • 通过“图片压缩编码”的编程实践,学习树、遍历二叉树、哈夫曼树、哈夫曼编码和他们的编程应用。 (1)掌握树的存储结构 (2)掌握二叉树的三种遍历方法 (3)掌握并理解Huffman树、Huffman编码等知识和应用 (4)掌握文件的...
  • 用MATLAB做的基于霍夫曼编码的图像压缩,里面有个文件时专门的霍夫曼编码函数,自己写的。 用MATLAB做的基于霍夫曼编码的图像压缩,里面有个文件时专门的霍夫曼编码函数,自己写的。
  • 哈夫曼图片压缩及解压

    千次阅读 2019-09-28 02:35:33
    哈夫曼图片压缩及解压 文件 功能 Huffman 哈夫曼编码 compress 解压 //Compress.h #ifndef COMPRESS_H #define COMPRESS_H typedef unsigned char * buffer; int Compress(const char *pFilename); ...

    哈夫曼图片压缩及解压

    文件功能
    Huffman哈夫曼编码
    compress解压
    //Compress.h
    #ifndef COMPRESS_H
    #define COMPRESS_H
    typedef unsigned char * buffer;
    int Compress(const char *pFilename);
    unsigned char Str2byte(const char *pBinStr);
    int Encode(const char*pFilename, const HuffmanCode pHC,buffer &pBuffer, const int nSize);
    
    struct HEAD
    {
        char type[4];//文件类型
        int length;//原文件长度
        int weight[256];//权值数值
    };
    int WriteFile(const char*pFilename, const HEAD sHead, unsigned char * pBuffer, const int nSize);
    int InitHead(const char *pFilename, HEAD &sHead);
    int UnCompress(const char*pFilename);
    #endif
    //Huffman.h
    #ifndef HUFFMAN_H
    #define HUFFMAN_H
    #define OK 1
    #define SIZE 256
    struct HTNode {
        int weight;//权值
        int parent;//父节点
        int lchild;//左孩子
        int rchild;//右孩子
    };
    typedef HTNode *HuffmanTree;//动态分配数组存储Huffman树
    typedef char **HuffmanCode;//动态分配哈夫曼编码表
    
    
    //void PreorderTraverse(int root, HuffmanTree pHT);
    int HuffmanCoding(HuffmanCode &pHC, HuffmanTree &pHT);
    int Select(HuffmanTree pHT, int nSize);
    void TestHufTree(HuffmanTree pHT);
    void TestHufCode(int root, HuffmanTree pHT, HuffmanCode pHC);
    void TestHufTreeN(int root, HuffmanTree pHT);
    
    int HfmTree(HuffmanTree &pHT, int *w, int n);
    
    #endif
    //huffman.cpp
    #include<iostream>
    #include<cstring>
    #include"huffman.h"
    #pragma warning( disable : 4996)
    using namespace std;
    /*
    void PreorderTraverse(int root, HuffmanTree pHT)
    {
        cout << pHT[root].weight << " ";//访问节点
        if (pHT[root].lchild)//左孩子
        {
            PreorderTraverse(pHT[root].lchild, pHT);
        }
        if (pHT[root].rchild)//右孩子
        {
            PreorderTraverse(pHT[root].rchild, pHT);
        }
    }
    */
    int HuffmanCoding(HuffmanCode &pHC, HuffmanTree &pHT)
    {
        pHC = (HuffmanCode)malloc((SIZE + 1) * sizeof(char*));
        //无栈非递归遍历 
        char cd[SIZE] = { '\0' };//记录访问路径
        int cdlen = 0;//记录当前路径长度
        for (int i = 1; i < 512; i++)
        {
            pHT[i].weight = 0;//遍历 Huffman树时用作节点的状态标志
        }
    
        int p = 2*SIZE-1;//根节点
        while (p != 0)
        {
            if (pHT[p].weight == 0)//向左
            {
                pHT[p].weight = 1;
                if (pHT[p].lchild != 0)
                {
                    p = pHT[p].lchild;
                    cd[cdlen++] = '0';
                }
                else if (pHT[p].rchild == 0)//登记叶子节点的字符编码
                {
                    pHC[p] = (char*)malloc((cdlen+1) * sizeof(char));
                    cd[cdlen] = '\0';
                    strcpy(pHC[p], cd);//复制编码
                }
            }
            else if (pHT[p].weight == 1)//向右
            {
                pHT[p].weight = 2;
                if (pHT[p].rchild != 0)//右孩子为叶子节点
                {
                    p = pHT[p].rchild;
                    cd[cdlen++] = '1';
                }
            }
            else
            {
                //退回父节点,编码长度减1
                pHT[p].weight = 0;
                p = pHT[p].parent;
                --cdlen;
            }
    //      printf("*");
        }
        return OK;
    }
    
    int Select(HuffmanTree pHT, int nSize)
    {
        int minValue = 0x7FFFFFFF;//最小值
        int min = 0;
        //找到最小权值的元素序号
        for (int i = 1; i <= nSize; i++)
        {
            if (pHT[i].parent == 0 && pHT[i].weight < minValue)
            {
                minValue = pHT[i].weight;
                min = i;
            }
        }
        return min;
    }
    
    void TestHufTree(HuffmanTree pHT)
    {
        for (int i = 1; i < 2*SIZE; i++)
        {
            printf("pHT[%d]\t%d\t%d\t%d\t%d\n", i, pHT[i].weight, pHT[i].parent,pHT[i].lchild,pHT[i].rchild);
        }
    }
    
    int HfmTree(HuffmanTree &pHT, int *w, int n)
    {
        int m = 2 * n - 1;
        pHT = (HuffmanTree)malloc((m + 1) * sizeof(HTNode));
        if (!pHT)
        {
            cerr << "内存分配失败! " << endl;
            return -1;
        }
        //初始化树
        HuffmanTree p = pHT + 1;//0号单元不使用
        for (int i = 0; i < m; i++)
        {
            p->weight = (i < n) ? w[i] : 0;
            p->parent = 0;
            p->lchild = 0;
            p->rchild = 0;
            p++;
        }
        for (int i = n + 1; i <= m; i++)
        {
            //第一个最小元素
            int s1 = Select(pHT, i - 1);//找出前i-1个中最小元素
            pHT[s1].parent = i;
    
            //第二个最小元素
            int s2 = Select(pHT, i - 1);
            pHT[s2].parent = i;
    
            pHT[i].weight = pHT[s1].weight + pHT[s2].weight;
            pHT[i].lchild = s1;
            pHT[i].rchild = s2;
        }
        return 0;
    }
    
    void TestHufCode(int root, HuffmanTree pHT, HuffmanCode pHC)
    {
        if (pHT[root].lchild == 0 && pHT[root].rchild == 0)
        {
            printf("0x%02X %s\n", root - 1, pHC[root]);
        }
        if (pHT[root].lchild)//访问左孩子
        {
            TestHufCode(pHT[root].lchild, pHT, pHC);
        }
        if (pHT[root].rchild)
        {
            TestHufCode(pHT[root].rchild, pHT, pHC);
        }
    }
    
    void TestHufTreeN(int root, HuffmanTree pHT)
    {
        cout << pHT[root].weight << "\t"<<pHT[root].lchild<<"\t"<<pHT[root].rchild<<"\t"<<pHT[root].parent<<"\n";
        if (pHT[root].lchild != 0)
        {
            TestHufTreeN(pHT[root].lchild, pHT);
        }
        if (pHT[root].rchild != 0)
        {
            TestHufTreeN(pHT[root].rchild, pHT);
        }
    }
    //Compress.cpp
    #include"huffman.h"
    #include"Compress.h"
    #include<iostream>
    #pragma warning( disable : 4996)
    using namespace std;
    //Compress
    //InitHead
    //Encode
    //Str2byte
    //WriteFile
    unsigned char Str2byte(const char *pBinStr)
    {
        unsigned char b = 0x00;
        for (int i = 0; i < 8; i++)
        {
            b = b << 1;
            if (pBinStr[i] == '1')
            {
                b = b | 0x01;
            }
        }
        return b;
    }
    
    int Compress(const char *pFilename)
    {
        int weight[256] = { 0 };
        //以二进制打开文件
        FILE* in = fopen(pFilename, "rb");
        if (in == NULL)
        {
            cout << "Failed to open the file!" << endl;
            exit(0);
        }
        cout << "成功打开文件 " << pFilename << endl;
        int ch;
        while ((ch = getc(in)) != EOF)
        {
            weight[ch]++;
        }
        fclose(in);
        //cout << "Byte Weight" << endl;
        //for (int i = 0; i < SIZE; i++)
        //{
        //  printf("0x%02X %d\n", i, weight[i]);
        //}
    
        HuffmanTree hfmt;
        HfmTree(hfmt, weight, SIZE);
        cout << "成功生成哈夫曼树" << endl;
    //  TestHufTree(hfmt);
        //  TestHufTreeN(511, hfmt);
        HuffmanCode hfmc=(HuffmanCode)malloc((SIZE+1)*sizeof(char*));
    //  for (int i = 1; i <= SIZE; i++)
    //      hfmt[i].weight = weight[i - 1]
        //根据哈夫曼树进行编码
        HuffmanCoding(hfmc, hfmt);
        cout << "成功完成哈夫曼编码" << endl;
    //  cout << "先序遍历哈夫曼树输出编码信息:" << endl;
    //  TestHufCode(2 * SIZE - 1, hfmt, hfmc);//测试哈夫曼编码
    //  cout << "压缩后的文件编码:" << endl;
    
        //计算编码缓冲区大小
        int nSize = 0;
        for (int i = 0; i < 256; i++)
        {
            nSize += weight[i] * strlen(hfmc[i+1]);
        }
        nSize = (nSize % 8) ? nSize / 8 + 1 : nSize / 8;
    
    //  cout <<"nSize = "<<nSize << endl << endl;
    
        //对原文件进行压缩编码
        unsigned char* pBuffer = NULL;
        pBuffer = (unsigned char *)malloc(nSize*sizeof(unsigned char));
        memset(pBuffer, 0, (nSize) * sizeof(unsigned char));
    //  cout << "begin: " << strlen(pBuffer) << endl;
        cout << "----";
    //  int n;
    //  cout << "input n:";
    //  cin >> n;
        //将编码写入缓冲区
        Encode(pFilename, hfmc, pBuffer, nSize);
    //  cout << "after: " << strlen(pBuffer) << endl;
    //  cout << "len of puf  = " << strlen(pBuffer) << endl;
    //  cout << "!pBuffer = " << !pBuffer << endl;
        if (!pBuffer)
        {
            cout << "!pBuffer = " << !pBuffer << endl;
            return -1;
        }
        cout << "\n压缩完毕" << endl;
        //for (int i = 1; i < nSize; i++)
        //{
        //  printf("%X\n", pBuffer[i]);
        //}
    
        HEAD sHead;
        InitHead(pFilename, sHead);
        cout <<"原文件"<< pFilename<<"大小为:" << sHead.length << "Byte" << endl;
        int len_after = WriteFile(pFilename, sHead, pBuffer, nSize);
        cout << "大小为:" << len_after << "Byte \n头文件sHead大小为:" << sizeof(sHead)<<"Byte"<<endl;
        cout << "压缩比率:" << (double)len_after * 100 / sHead.length << "%" << endl;
        free(hfmt);
        free(hfmc);
        free(pBuffer);
        return OK;
    }
    
    
    int Encode(const char*pFilename, const HuffmanCode pHC,buffer &pBuffer, const int nSize)
    {
        //开辟缓冲区
    //  cout << "+++++";
        FILE* in = fopen(pFilename, "rb");
        if (in == NULL)
        {
            cout << "Failed to open the file!" << endl;
            exit(0);
        }
        pBuffer = (unsigned char*)malloc(nSize * sizeof(unsigned char));
        if (!pBuffer)
        {
            cerr << "开辟缓冲区失败" << endl;
            return -1;
        }
        cout << "loading";
        int sign = 0;//用于控制小数点输出
        char cd[SIZE] = { 0 };//工作区
        int pos = 0;//缓冲区指针
        int ch;
        //扫描文件,根据huffmman编码表对其进行压缩,压缩结果暂存到缓冲区中
        while ((ch = getc(in)) != EOF)
        {
            if (sign % 1000 == 1)
                printf(".");
            sign++;
            strcat(cd, pHC[ch+1]);//从HC复制编码串到cd
    
    
            //打印压缩后的文件编码
    //      printf("%s", pHC[ch + 1]);
    
    
            //压缩编码
            while (strlen(cd) >= 8)
            {
                //截取字符串左边的8个字符,编码成字节
                pBuffer[pos++] = Str2byte(cd);
                //字符串整体左移8个字节
                for (int i = 0; i < SIZE - 8; i++)
                {
                    cd[i] = cd[i + 8];
                }
            }
        }
        if (strlen(cd) > 0)
        {
            pBuffer[pos++] = Str2byte(cd);
        }
        fclose(in);
    //  printf("%", pBuffer);
        return OK;
    }
    
    int InitHead(const char *pFilename, HEAD &sHead)
    {
        //初始化文件头
        strcpy(sHead.type, "HUF");//文件类型
        sHead.length = 0;//原文件长度
        for (int i = 0; i < SIZE; i++)
        {
            sHead.weight[i] = 0;
        }
        FILE *in = fopen(pFilename, "rb");
        int ch;
        while ((ch = fgetc(in)) != EOF)
        {
            sHead.weight[ch]++;
            sHead.length++;
        }
        fclose(in);
        in = NULL;
        return OK;
    }
    
    int WriteFile(const char*pFilename, const HEAD sHead, unsigned char * pBuffer, const int nSize)
    {
        //生成文件名
        char filename[256] = { 0 };
        strcpy(filename, pFilename);
        strcat(filename, ".huf");
        //以二进制流形式打开文件
        FILE *out = fopen(filename, "wb");
        //写文件头
        fwrite(&sHead, sizeof(sHead), 1, out);
        //写压缩后的编码
        fwrite(pBuffer, sizeof(char), nSize, out);
        //关闭文件,释放文件指针
        fclose(out);
        out = NULL;
        cout << "生成压缩文件:" << filename << endl;
        int len = sizeof(HEAD) + strlen(pFilename) + 1 + nSize;
        return len;
    }
    //解压函数
    int UnCompress(const char*pFilename)
    {
        char outputfile[255];
        FILE *ifp, *ofp;
        ifp = fopen(pFilename, "rb");//打开.huf文件
        if (!ifp)
        {
            cerr << "Failed to open this file!" << endl;
            return -1;
        }
        cout << "输入解压后的文件名,(原文件名为" << pFilename << "): " << endl;
        cin >> outputfile;
    //  strcpy(outputfile, "d:\\aaa.png");
        ofp = fopen(outputfile, "wb");
        if (!ofp)
        {
            cerr << "Failed to open this file!" << endl;
            return -1;
        }
        HEAD sHead;
        //读文件头
        fread(&sHead, sizeof(HEAD), 1, ifp);
        HuffmanTree hfmt = NULL;
        HfmTree(hfmt, sHead.weight, 256);
        HuffmanCode hfmc = NULL;
        HuffmanCoding(hfmc, hfmt);
        int max = 0;
        for (int k = 1; k <= 256; k++) {
            if (strlen(hfmc[k]) > max) {
                max = strlen(hfmc[k]);
            }//找出最长的编码
        }
        //
        int nSize = 0;
        for (int i = 0; i < 256; i++)
        {
            nSize += sHead.weight[i] * strlen(hfmc[i + 1]);
        }
        nSize = (nSize % 8) ? nSize / 8 + 1 : nSize / 8;
        cout << "nsize =  " << nSize << endl;
    //  unsigned char *pBuffer = NULL;
        unsigned char* pBuffer = NULL;
        pBuffer = (unsigned char *)malloc(nSize * sizeof(unsigned char));
        memset(pBuffer, 0, (nSize) * sizeof(unsigned char));
    //  pBuffer = (unsigned char*)malloc(nSize*sizeof(unsigned char));
        fread(pBuffer, sizeof(unsigned char), nSize, ifp);
        //for (int i = 0; i < nSize; i++)
        //{
        //  printf("%x\n", pBuffer[i]);
        //}
        char ch[SIZE] = { 0 };
        unsigned char c;
        for (int i = 0; i < nSize; i++)
        {
    //      printf("%x\n", pBuffer[i]);
            char s[SIZE] = { 0 };
            char buf[SIZE] = { 0 };
            _itoa(pBuffer[i], buf, 2);
    
            for (int k = 8; k > strlen(buf); k--)
            {
                strcat(s, "0");
            }
            strcat(s, buf);
            strcat(ch, s);
    //      cout << "ch = " << ch << endl;
            int m = 2 * SIZE - 1;
            while (strlen(ch) >= max)
            {
    //          cout << "**";
                int j = 0;
                while (ch[j] != '\0')
                {
    //              cout << "....";
                    int t = m;
                    while (hfmt[t].lchild != 0 && hfmt[t].rchild != 0)
                    {
                        if (ch[j] == '0')
                        {
                            t = hfmt[t].lchild;
                        }
                        else
                        {
                            t = hfmt[t].rchild;
                        }
                        j++;
                    }
                    c = (unsigned char)(t - 1);
    //              cout << (t - 1) << endl;
                    fwrite(&c, 1, 1, ofp);
    
                    for (int b = 0; b < SIZE - j; b++)
                    {
                        ch[b] = ch[b + j];
                    }
                    break;
                }
    //          cout << "::::";
            }
        }
        cout << "解压成功" << endl;
        fclose(ifp);
        fclose(ofp);
    
        return OK;
    }
    
    //main.cpp
    #include"huffman.h"
    #include"Compress.h"
    #include<iostream>
    #include<cstdlib>
    using namespace std;
    #pragma warning( disable : 4996)
    
    int main()
    {
        cout << "= = = = = = = =Huffman 文件压缩= = = = = = = =" << endl;
        cout << "**1.压缩文件" << endl;
        cout << "**2.解压文件" << endl;
        cout << "= = = = = = = = = =  = = = = = = = = = = = = =" << endl;
        int choose = 0;
        cout << "----选择功能:";
        cin >> choose;
        while (choose == 1 || choose == 2)
        {
            if (choose == 1)
            {
                cout << "请输入文件名:";
                char filename[256];
                cin >> filename;
                Compress(filename);
            }
            else if (choose == 2)
            {
                cout << "输入你要解压的文件名(.huf后缀): ";
                char newfilename[SIZE] = { 0 };
                cin >> newfilename;
                //  strcpy(newfilename, "d:\\t.png.huf");
                UnCompress(newfilename);
            }
            else
                break;
            cout << "----选择功能:";
            cin >> choose;
        }
    
    
    //  system("pause");
        return 0;
    }
    

    转载于:https://www.cnblogs.com/sgawscd/p/10846284.html

    展开全文
  • C语言实现的huffman压缩压缩算法
  • 设计并实现一个使用哈夫曼算法对文件进行压缩的工具软件。 通过命令行参数指定操作模式(压缩/解压)、源文件名、目标文件名。 压缩操作将源文件按字节读入并统计字节频率,生成字节的哈夫曼编码,将编码树和用...
  • package edu.princeton.cs.algs4; /** * The Huffman class provides static methods for compressing * and expanding a binary input using Huffman codes over the 8-bit extended * ASCII alphabet. ...
  • 大家都知道,使用哈夫曼压缩能达到无损压缩,也就是说。保证了原图质量的同时,能够降低图片的大小。这是什么原理呢?首先我们需要了解的是...性能差),由于哈夫曼算法非常吃CPU,被迫用了其他的算法。所以Sk...
  • 草稿版代码 内容超详细 可压缩任何文件类型 亲测可用 100%还原
  • 哈夫曼编码实现图像压缩,是自己整理的讲稿,希望对大家有用
  • 写入压缩文件,后缀.huf,先写入文件头(包括文件类型,权值列表,文件长度,以便于从压缩文件中再次生成哈夫曼编码来解压,也可以用其他的方式,比如直接将哈夫曼编码以先序遍历的方式写入压缩文件的开始,代码中有...
  • 使用Huffman压缩算法,对一幅BMP格式的图片文件进行压缩图片文件名为“Pic.bmp”,压缩后保存为“Pic.bmp.huf”文件。 程序截图: Main.cpp #include"menu.h" int main() { show(); return 0; } meun.h #...
  • 比较详细的注释,故在此不多解释,注意.docx文件效率比较差,因为其本身已经压缩,txt则可以见到明显的压缩效果 #!/usr/bin/env python3 # -*- coding: utf-8 -*- import sys sys.setrecursionlimit(1000000) ...
  • **原因:**当时由于CPU和内存在手机上都非常吃紧 性能差,由于哈夫曼算法非常吃CPU,被迫用了其他的算法。 需求:,随着安卓设备硬件水平的提升,可以在性能的安卓设备上使用一些比较耗费性能的算法,使得...
  • 该程序能压缩文档、图片、小视频等文件,并且基于C++的算法实现,简单易懂......
  • 哈夫曼编码压缩图像

    千次阅读 2020-06-15 10:09:47
    loc:第一次排序时是i,因为哈夫曼编码先将概率从大到小排序;当不是第一次时,就是上一次排序的位置 find(S(j,:)==loc):S保存的是每次排序前的位置,所以这一命令可以找到排序后,即当前该概率值ai的位置 find(S...
  • 哈夫曼图片压缩

    2018-06-27 10:30:27
    数据结构应用统计文件中256种不同字节重复的次数,以每种字节重复的次数作为权值,构造一棵有256个...使用Huffman压缩算法,对一副BMP格式的图片文件进行压缩图片名为“Pic.bmp”,压缩后保存为”Pic.bmp.huf”文件。
  • VS2010以上通过,实现压缩功能,很方便
  • 3、生成哈夫曼树。 4、生成哈夫曼编码。 5、压缩原文件。 6、保存压缩文件。 7、扩展功能。 实验代码参考:https://blog.csdn.net/cxh_1231/article/details/80530668 main.cpp 主函数 #include "iostream" #include...
  • 离散数学老师布置了一份大作业,作业题目就是用自己喜欢的编程语言来实现课上所学的哈夫曼编码算法(Huffman Coding)。哈夫曼编码是一种采用变长编码表来表示数据的编码方式。其详细介绍详见下方引自维基百科的引文...
  • python哈夫曼压缩与解压算法 压缩 #encoding: utf-8 from bitarray import bitarray import random import json class Node(object): """docstring for Node""" left=None right=None times=0 char = '' ...
  • 哈夫曼压缩与解压缩(c语言版)

    千次阅读 多人点赞 2019-09-29 19:18:13
    学过数据结构的同学,应该都听过哈夫曼树,和哈夫曼压缩算法,今天小编向大家讲解哈夫曼压缩压缩的过程以及代码也算是记录一下自己所学所做的东西。 哈夫曼压缩,其实效率不是很高,一般情况下压缩率1...
  • 哈夫曼树和哈夫曼编码应用之图片压缩编码c++实现

    千次阅读 多人点赞 2018-12-07 22:38:04
    因此今天我就分享给大家c语言数据结构有关哈夫曼压缩图片的项目实现。   一:下面先介绍有关的知识: 1.背景 压缩软件是用特定算法压缩数据的工具,压缩后的文件称为压缩包,可以对其进行解压。那么为什么要...
  • java实现哈夫曼压缩与解压缩

    千次阅读 2019-09-30 10:30:03
    哈夫曼压缩与解压缩(java版) 一哈夫曼树以及文件压缩原理: 1.哈夫曼树 : 2.如何利用haffman编码实现文件压缩: 二主要技术点: 三实现过程: 四运行展示: 哈夫曼压缩与解压缩(java版) 一哈夫曼树以及...
  • 构造这种树的算法最早是由哈夫曼(Huffman)1952年提出,这种树在信息检索中很有用。 结点之间的路径长度:从一个结点到另一个结点之间的分支数目。 树的路径长度:从树的根到树中每一个结点的路径长度之和。 ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,543
精华内容 617
关键字:

哈夫曼算法压缩图片