精华内容
下载资源
问答
  • 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

    展开全文
  • 使用Huffman压缩算法,对一幅BMP格式的图片文件进行压缩图片文件名为“Pic.bmp”,压缩后保存为“Pic.bmp.huf”文件。 程序截图: Main.cpp #include"menu.h" int main() { show(); return 0; } meun.h #...

    使用Huffman压缩算法,对一幅BMP格式的图片文件进行压缩。图片文件名为“Pic.bmp”,压缩后保存为“Pic.bmp.huf”文件。

    程序截图:
    在这里插入图片描述
    Main.cpp

    #include"menu.h"
    
    int main() {
    	show();
    	return 0;
    }
    

    meun.h

    #ifndef MENU_H
    #define MENU_H
    
    void show();
    
    #endif // !MENU_H
    
    

    menu.cpp

    #include"menu.h"
    #include<iostream>
    #include"Compress.h"
    #include"global.h"
    using namespace std;
    
    void show() {
    	cout << "========== Huffman 文件压缩 ==========" << endl;
    	cout << "请输入文件名:";
    	cin >> filename;
    	if (Compress(filename) == 1)
    		cout << "\n压缩完成!" << endl;
    	else 
    		cout << "\n压缩失败!" << endl;
    	cout << endl;
    	system("pause");
    }
    

    Huffman.h

    #ifndef HUFFMAN_H
    #define HUFFMAN_H
    
    //Huffman树节点
    typedef struct
    {
    	int weight;	//权值
    	int parent;	//父节点
    	int lchild;	//左孩子
    	int rchild;	//右孩子
    }HTNode, *HuffmanTree;
    
    typedef char **HuffmanCode;		//Huffman编码
    
    //生成Huffman树
    int CreateHuffmanTree(HuffmanTree pHT, int weight[], int n);
    
    //生成Huffman编码
    int HuffmanCoding(HuffmanCode &pHC, HuffmanTree  &pHT);
    
    void Select(HuffmanTree &HT, int i, int&s1, int&s2);
    
    int TestHufTree(HuffmanTree pHT);
    void TestHufCode(int root, HuffmanTree &pHT, HuffmanCode &pHC);
    
    #endif
    

    Huffman.cpp

    #define _CRT_SECURE_NO_WARNINGS
    #include"Huffman.h"
    #include<iostream>
    #include<malloc.h>
    
    #define OK 1
    #define ERROR 0
    
    using namespace std;
    
    //生成Huffman树
    int CreateHuffmanTree(HuffmanTree pHT, int weight[], int n) {
    	int s1, s2, i;
    	int m = 2 * n - 1;
    
    	//初始化
    	for (i = 1; i <= n; i++) {
    		pHT[i].weight = weight[i - 1];
    		pHT[i].lchild = 0;
    		pHT[i].rchild = 0;
    		pHT[i].parent = 0;
    	}
    	for (i = n + 1; i <= m; i++) {
    		pHT[i].parent = 0;
    		pHT[i].lchild = 0;
    		pHT[i].rchild = 0;
    		pHT[i].weight = 0;
    	}
    
    	for (i = n + 1; i <= m; i++)
    	{
    		//从pHT[1...i-1]中选择parent为0且weight最小的两个结点,其序号分别为s1和s2
    		Select(pHT, i - 1, s1, s2);
    		pHT[s1].parent = i;
    		pHT[s2].parent = i; //修改s1和s2结点的父指针parent
    
    		pHT[i].lchild = s1;
    		pHT[i].rchild = s2; //修改i结点的左右孩子指针
    
    		pHT[i].weight = pHT[s1].weight + pHT[s2].weight; //修改权值
    	}
    	return OK;
    }
    
    //查找Huffman树节点数组中权值最小的节点
    void Select(HuffmanTree &pHT, int i, int &s1, int &s2) {
    	int minValue = 0x7FFFFFFF;
    
    	//找到最小的一个权值
    	for (int j = 1; j <= i; j++) {
    		if (pHT[j].parent == 0 && pHT[j].weight < minValue) {
    			minValue = pHT[j].weight;
    			s1 = j;
    		}
    	}
    
    	minValue = 0x7FFFFFFF;
    	//找到倒数第二小的权值
    	for (int j = 1; j <= i; j++) {
    		if (j != s1 && pHT[j].parent == 0 && pHT[j].weight < minValue) {
    			minValue = pHT[j].weight;
    			s2 = j;
    		}
    	}
    }
    
    //生成Huffman编码 
    int HuffmanCoding(HuffmanCode &pHC, HuffmanTree &pHT)
    {
    	//无栈非递归遍历Huffman树,求Huffman编码
    	char cd[256] = { '\0' };	//记录访问路径
    	int cdlen = 0;				//记录当前路径长度
    
    	for (int i = 1; i < 512; i++) 
    		pHT[i].weight = 0;	//遍历Huffman树时用做节点的状态标志
    
    	int p = 511;			//根节点
    	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 {
    			pHT[p].weight = 0;
    			p = pHT[p].parent;
    			cdlen--;
    		}
    	}
    	return OK;
    }
    
    int TestHufTree(HuffmanTree pHT) {
    	cout << "哈夫曼树的每个节点信息为:" << endl;
    	cout << "Byte\t\tWeight\tParent\tLchild\tRchild\n";
    	for (int i = 1; i < 512; i++) {
    		//判断语句为了对齐格式
    		if (i <= 99) 
    			cout << "pHT[" << i << "]\t\t" << pHT[i].weight << "\t" << pHT[i].parent << "\t" << pHT[i].lchild << "\t" << pHT[i].rchild << endl;
    		else
    			cout << "pHT[" << i << "]\t" << pHT[i].weight << "\t" << pHT[i].parent << "\t" << pHT[i].lchild << "\t" << pHT[i].rchild << endl;
    
    	}
    	return OK;
    }
    
    void TestHufCode(int root, HuffmanTree &pHT, HuffmanCode &pHC) {
    	if (root <= 1) return;
    
    	if (pHT[root].lchild == 0 && pHT[root].rchild == 0)
    		printf("0x%02X\t%s\n", root - 1, pHC[root - 1]);
    	if (pHT[root].lchild)//访问左孩子
    		TestHufCode(pHT[root].lchild, pHT, pHC);
    	if (pHT[root].rchild)//访问右孩子
    		TestHufCode(pHT[root].rchild, pHT, pHC);
    }
    

    Compress.h

    #ifndef COMPRESS_H
    #define COMPRESS_H
    
    #include"Huffman.h" //Encode函数生明会用到HuffmanCode
    
    //文件头
    struct HEAD
    {
    	char type[4];
    	int length;
    	int weight[256];
    };
    
    //实现文件压缩
    int Compress(const char *pFilename);
    
    //读取源文件和初始化头文件的信息
    int InitHead(const char * pFilname, HEAD & sHead);
    
    //利用Huffman编码 实现压缩编码
    int Encode(const char *pFilname, const HuffmanCode pHC, char *pBuffer, const int nSize);
    
    //将二进制字符串转换成字节
    char Str2byte(const char * pBinStr);
    
    //生成压缩文件
    int WriteFile(const char * pFilename, const HEAD sHead, const char * pBuffer, const int nSize);
    
    //显示256种字节出现的次数
    void showWeight(int weight[]);
    
    #endif
    

    Compress.cpp

    #define _CRT_SECURE_NO_WARNINGS
    #include <iostream>
    #include <stdlib.h>
    #include "Compress.h"
    #include"Huffman.h"
    
    using namespace std;
    
    #define OK 1
    #define ERROR 0
    
    const int SIZE = 256;
    
    //扫描文件和初始化头文件的信息
    int InitHead(const char * pFilname, HEAD & sHead)
    {
    	strcpy(sHead.type, "HUF");		//文件类型
    	sHead.length = 0;				//源文件长度
    	for (int i = 0; i < SIZE; i++)
    		sHead.weight[i] = 0;		//权值
    
    	//以二进制流形式打开文件
    	FILE *in = fopen(pFilname, "rb");
    
    
    	//扫描文件,获得权重
    	int ch;
    	while ((ch = fgetc(in)) != EOF)
    	{
    		sHead.weight[ch]++;
    		sHead.length++;
    	}
    
    	//关闭文件
    	fclose(in);
    	in = NULL;
    	return OK;
    }
    
    //得到编码文件
    int Compress(const char * pFilename)
    {
    	//打开并扫描文件
    	cout << "正在读取文件……" << endl;
    	int weight[256] = { 0 };  
    	FILE* in = fopen(pFilename, "rb");
    	int tempch;
    	while ((tempch = getc(in)) != EOF)//获取权重
    		weight[tempch]++;
    
    	//测试,显示256种字节出现的次数
    	//showWeight(weight);
    
    	cout << "文件读取完毕!\n" << endl << endl;
    	fclose(in);
    
    	//将编码生成Huffman树
    	int n = 256;						//Huffman树共有n个叶子节点
    	int m = 2 * n - 1;					//那么就有2n+1个节点
    	HuffmanTree pHT = new HTNode[m + 1];	//定义Huffman树
    	CreateHuffmanTree(pHT, weight, n);
    
    	//测试,输出 Huffman 树每个节点的信息
    	//TestHufTree(pHT);
    
    	//生成Huffman编码
    	char** pHC = new char*[n + 1]; //编码
    	for (int i = 1; i <= n; i++)
    		pHT[i].weight = weight[i - 1];
    
    	HuffmanCoding(pHC, pHT);
    
    	//测试,显示字节的Huffman编码信息
    	//cout << "\n哈夫曼树的编码信息为:" << endl;
    	//cout << "Byte\tHuffmanCode" << endl;
    	//TestHufCode(511, pHT, pHC);
    
    	//计算编码缓冲区大小
    	int nSize = 0;
    	for (int i = 0; i < 256; i++)
    		nSize += weight[i] * strlen(pHC[i + 1]);
    	nSize = (nSize % 8) ? nSize / 8 + 1 : nSize / 8;
    
    
    	//对编码文件进行压缩
    	char *pBuffer = NULL;
    	pBuffer = new char[nSize];
    	memset(pBuffer, 0, (nSize) * sizeof(char));
    	Encode(pFilename, pHC, pBuffer, nSize);
    	if (!pBuffer) {
    		return ERROR;
    	}
    
    	HEAD sHead;
    	InitHead(pFilename, sHead);
    	cout << "目标文件大小:" << sHead.length << "字节" << endl;
    	int afterlen = WriteFile(pFilename, sHead, pBuffer, nSize);
    	cout << "压缩文件大小:" << afterlen << "字节  \n其中头文件sHead大小:" << sizeof(sHead) << "字节" << endl;
    	cout << "压缩比率:" << (double)afterlen * 100 / sHead.length << "%" << endl;
    
    	delete pHT; 
    	delete[] pHC;
    	delete pBuffer;
    
    	return OK;
    }
    
    //实现压缩编码
    int Encode(const char * pFilname, const HuffmanCode pHC, char * pBuffer, const int nSize)
    {
    	//打开文件
    	FILE *in = fopen(pFilname, "rb");
    
    	//开辟缓冲区ni
    	pBuffer = (char *)malloc(nSize * sizeof(char));
    	if (!pBuffer)
    		cout << "开辟缓冲区失败" << endl;
    
    	char cd[SIZE] = { 0 };		//工作区
    	int pos = 0;				//缓冲区指针
    	int ch;
    	//扫描文件
    	while ((ch = fgetc(in)) != EOF)
    	{
    		strcat(cd, pHC[ch + 1]);
    
    		//压缩编码
    		while (strlen(cd) >= 8)
    		{
    			pBuffer[pos++] = Str2byte(cd);
    			for (int i = 0; i < SIZE - 8; i++)
    			{
    				cd[i] = cd[i + 8];
    			}
    		}
    	}
    	if (strlen(cd) > 0)
    		pBuffer[pos++] = Str2byte(cd);
    
    	fclose(in);	
    
    	return OK;
    }
    
    //生成压缩文件
    int WriteFile(const char * pFilename, const HEAD sHead, const char * pBuffer, const int nSize)
    {
    	//生成文件名
    	char filename[256] = { 0 };
    	strcpy(filename, pFilename);
    	strcat(filename, ".huf");
    
    	//以二进制流形式打开文件
    	FILE * out = fopen(filename, "wb");
    
    	//写文件
    	fwrite(&sHead, sizeof(HEAD), 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;
    }
    
    //将字符串转换成字节
    char Str2byte(const char * pBinStr)
    {
    	char b = 0x00;
    	for (int i = 0; i < 8; i++)
    	{
    		b = b << 1;		//左移一位
    		if (pBinStr[i] == '1')
    		{
    			b = b | 0x01;
    		}
    	}
    	return b;
    }
    
    // 显示 256 种字节的出现的次数 
    void showWeight(int weight[]) {
    	cout << "原文件每个字符的权值为:" << endl;
    	cout << "Byte\t" << "Weight\t" << endl;
    	for (int i = 0; i < 256; i++) 
    		printf("0x%02X\t%d\n", i, weight[i]);
    }
    

    gobal.h

    #ifndef GLOBAL_H
    #define GLOBAL_H
    
    char  filename[256];
    
    #endif // !GLOBAL_H
    
    

    运行截图:
    在这里插入图片描述

    展开全文
  • 3、生成哈夫曼树。 4、生成哈夫曼编码。 5、压缩原文件。 6、保存压缩文件。 7、扩展功能。 实验代码参考:https://blog.csdn.net/cxh_1231/article/details/80530668 main.cpp 主函数 #include "iostream" #include...
  • 大家都知道,使用哈夫曼压缩能达到无损压缩,也就是说。保证了原图质量的同时,能够降低图片的大小。这是什么原理呢?首先我们需要了解的是...性能差),由于哈夫曼算法非常吃CPU,被迫用了其他的算法。所以Sk...
  • 开发一个控制台程序,使用Huffnan压缩算法对bmp格式图片文件进行压缩 项目结构 Huffman.h #pragma once #include<iostream> using namespace std; struct HTNode { int weight=0;//权值 int parent=0;//父...
  • 该程序能压缩文档、图片、小视频等文件,并且基于C++的算法实现,简单易懂......
  • 哈夫曼树和哈夫曼编码应用之图片压缩编码c++实现

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

    万次阅读 2016-10-25 22:54:04
    @前言总结经典的文件压缩算法原理,主要包括:哈夫曼压缩算法及其延伸,LZ77算法及其演变算法,LZ78算法及其演变算法,几何编码算法Arithmetic Coding。内容部分摘录翻译自港大‘多媒体技术’硕士课程1.进行文件压缩...
  • 图像压缩编码(哈夫曼树)

    千次阅读 2019-01-16 12:13:28
    1.首先图片压缩编码对不同文件的压缩效率是不一样的  这也是我在最后发现自己的压缩比率超高(类似于未压缩)发现的。多次确认算法无误后终于在以为大佬的博客中找到了答案。此处感谢下面这位大佬的博客。 ...
  • 学生学号 Xxx 实验课成绩 学 生 实 验 报 告 书 实验课程名称 数据结构与算法综合实验 ...数据结构与算法综合实验 实验项目名称 二叉树与赫夫曼图片压缩 报告成绩 实验者 xx 专业班级 xxx 组别 同组者 完成日期 2016 年
  • 哈夫曼编码用于常用的压缩算法,比如JPEG图片的有损压缩。也是一种不定长的前缀编码, 即任何一个编码都不是其他编码的前缀。 (http://www.cnblogs.com/wuyuankun/p/3982216.html) ...
  • 哈夫曼编码是一种高效的编码方式,在信息存储和传输过程中,用于对信息进行压缩。 计算机系统是如何存储信息的呢? 计算机不是人,它不认识中文和英文,更不认识图片和视频,它唯一“认识”的就是0(低电平)和1...
  • (笔记图片截图自课程Image and video processing: From Mars to Hollywood with a stop at the hospital的...哈弗曼编码是压缩算法中的经典,它理论上可以将数据编成平均长度最小的无前缀码(Prefix-Free Code)。 ...
  • 性能优化-图片压缩性能优化

    千次阅读 2019-04-06 20:59:33
    这里有一个历史问题,当时skia开源引擎用来处理JPEG,Android也采用了这种引擎,然而对其做了阉割处理,也就是去掉了其中的哈夫曼算法,采用了定长编码算法,然而在解码的时候依旧使用了哈夫曼...
  • Skia图像处理引擎 绘制流程见下面图1 备注:fultter 基于Skia引擎... Skia 对Java调用很友好,但会损失性能,但JPEG 存在这种功能(微信压缩哈夫曼算法进行 压缩),使用的是JPEG的压缩引擎) ...
  • 无损压缩:对内容中一些高频常出现的字符进行低字节编码,可还原,主要是一些编码算法,比如子带编码,差分编码,哈夫曼编码等。根据香农的信息理论,任何一个文件被无损压缩后的结果不可能小于其 熵 (信息论) 。...

空空如也

空空如也

1 2
收藏数 38
精华内容 15
关键字:

哈夫曼算法压缩图片