1、编译环境的安装
  1.1 解压从www.ijg.org上下载的源码,安装VS2010。
  1.2 在打开cmd定位到解压后的jpeg库目录中,并执行 NMAKE /f makefile.vc setup-v10 。(在install.txt的”HINTS FOR SPECIFIC SYSTEMS”一节中)此操作将生成(其实是重命名)vs2010的一系列工程文件。(提示nmake不是有效命令的话则修要设置环境变量的path并重启cmd)

    操作效果如下:
      ren jconfig.vc jconfig.h
      ren makejsln.v10 jpeg.sln
      ren makeasln.v10 apps.sln
      ren makejvcx.v10 jpeg.vcxproj
      ren makejfil.v10 jpeg.vcxproj.filters
      ren makecvcx.v10 cjpeg.vcxproj
      ren makecfil.v10 cjpeg.vcxproj.filters
      ren makedvcx.v10 djpeg.vcxproj
      ren makedfil.v10 djpeg.vcxproj.filters
      ren maketvcx.v10 jpegtran.vcxproj
      ren maketfil.v10 jpegtran.vcxproj.filters
      ren makervcx.v10 rdjpgcom.vcxproj
      ren makerfil.v10 rdjpgcom.vcxproj.filters
      ren makewvcx.v10 wrjpgcom.vcxproj
      ren makewfil.v10 wrjpgcom.vcxproj.filters
  1.3 运行vs2010打开jpeg.sln即可进行编译生成。
  1.4 如果自己的程序是用别的编译器版本生成的,则将jpeg的项目文件升级至对应版本,并修改项目属性中”平台工具集”使其与你的程序保持一致即可。
  1.5 编译如果出现型如 < 默认库“libcmt.lib”与其他库的使用冲突;请使用 /NODEFAULTLIB:library > 的错误提示时,说明你的程序和lib库使用的运行时库不同,最好是使用同样的运行库链接方式(/MT /MTd /MD /MDd),或者根据提示添加对应的忽略项(配置属性=>链接器=>输入=>忽略特定库, 库名加双引号,用逗号隔开)

2、解压jpeg图像

    // 以下代码省略错误处理

    struct jpeg_decompress_struct cinfo;
    // 自定义的jpeg错误处理器,要确保它的存活期贯穿整个图像处理过程
    struct my_error_mgr
    /*{
     *    struct jpeg_error_mgr pub;
     *    jmp_buf setjmp_buffer;
     *}
     */
    jerr;

    FILE * infile;		// 源文件对象
    JSAMPARRAY buffer;		// 行输出缓冲区
    int row_stride;		// 图像每行的字节数

    fopen_s(&infile, _filename, "rb");

    // 初始化jpeg解压对象并设置错误处理例程
    cinfo.err = jpeg_std_error(&jerr.pub);
    jerr.pub.error_exit = my_error_exit;    // 自定义的错误处理例程 void my_error_exit(j_common_ptr cinfo);
    
    // 设置错误处理返回点
    if (setjmp(jerr.setjmp_buffer))
    {
        fprintf(stderr, "读取失败\r\n");
        jpeg_destroy_decompress(&cinfo);
        return;
    }

    jpeg_create_decompress(&cinfo);

    // 设置输入数据来源
    jpeg_stdio_src(&cinfo, infile);

    // 使用jpeg_read_header()读取jpeg文件基本数据
    // 在调用jpeg_read_header()后直到调用jpeg_finish_decompress()之前都不应更改输入文件,
    // 如果要批量处理文件的话应该重复jpeg_read_header() 到 jpeg_finish_decompress() 之间的操作
    jpeg_read_header(&cinfo, TRUE);
    
    // 储存文件宽高等数据
    // 如果只是想获取文件的尺寸等基本信息,这个时候再调用jpeg_destroy()销毁jpeg对象或用jpeg_abort()重置jpeg对象的状态
    image_color  = cinfo.out_color_space;
    image_height = cinfo.image_height;
    image_width  = cinfo.image_width;
    image_buffer = new JSAMPLE[cinfo.image_width * cinfo.image_height * cinfo.num_components];

    //
    // 可选操作:设置其他解压参数
    //

    // 解压
    // 因为stdio是同步的所以可以忽略返回值(同上jpeg_read_hreader()也是)
    jpeg_start_decompress(&cinfo);

    // 每行的字节数
    row_stride = cinfo.output_width * cinfo.output_components;

#if 1
    buffer = (*cinfo.mem->alloc_sarray)
        ((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1);

    // 库里提供了记录图片读取状态的变量output_scanline
    while (cinfo.output_scanline < cinfo.output_height) {
        // 也可一次读取多行
        jpeg_read_scanlines(&cinfo, buffer, 1);
        // 因为读取后output_scanline已经增加了所以减1
        memcpy(image_buffer + (cinfo.output_scanline-1) * row_stride, buffer[0], row_stride);
    }
#else
    // 或者直接读取到目标缓冲区,不过这样需要一个目标缓冲区的行首地址数组来辅助
    JSAMPARRAY row_arr = new JSAMPROW[image_height];
    for (int i = 0; i < image_height; ++i)
        row_arr[i] = (JSAMPROW)(image_buffer + i * row_stride);
    while (cinfo.output_scanline < cinfo.output_height)
        (void)jpeg_read_scanlines(&cinfo, &row_arr[cinfo.output_scanline], 1);
    delete[] row_arr;
#endif

    
    // 结束解码,同理因为是stdio的操作是同步的,不用理会返回值
    jpeg_finish_decompress(&cinfo);


    // 释放资源
    jpeg_destroy_decompress(&cinfo);
    fclose(infile);

    // 最后可以检查 jerr.pub.num 的值是否非0来确认是否有数据损坏的警告产生
 

 
3、压缩jpeg图像

    // 以下代码省略错误处理

    struct jpeg_compress_struct cinfo;
    // 自定义错误处理结构,同上
    struct jpeg_error_mgr jerr;

    FILE * outfile;		// 输出文件对象
    JSAMPROW row_pointer[1];	// JSAMPLE row[s] 指针
    int row_stride;		// 图像缓冲区每行的字节数


    // 初始化jpeg压缩对象
    cinfo.err = jpeg_std_error(&jerr);
    jpeg_create_compress(&cinfo);

    // 初始化输出文件对象
    fopen_s(&outfile, filename, "wb");
    jpeg_stdio_dest(&cinfo, outfile);

    // 设置压缩参数
    // 下列四个成员的值必须设置
    cinfo.image_width = image_width;
    cinfo.image_height = image_height;
    cinfo.input_components = 3;         // 每个像素的颜色数
    cinfo.in_color_space = JCS_RGB; 	// 输入图像的颜色空间

    jpeg_set_defaults(&cinfo);          // 调用前要先设置好 cinfo.in_color_space
    
    // 设置其他非默认参数...
    jpeg_set_quality(&cinfo, _quality, TRUE);    // baseline-JPEG

    // 开始压缩
    jpeg_start_compress(&cinfo, TRUE);    // TRUE表示写入所有数据流,FALSE的情况详见文档中的
                                          // Abbreviated datastreams and multiple images 部分
                                          // 一般情况下用TRUE即可

    // 按行写入
    row_stride = image_width * 3;	// RGB

    while (cinfo.next_scanline < cinfo.image_height) {
        row_pointer[0] = &image_buffer[cinfo.next_scanline * row_stride];
        jpeg_write_scanlines(&cinfo, row_pointer, 1);
    }

    // 结束处理
    jpeg_finish_compress(&cinfo);
    fclose(outfile);

    jpeg_destroy_compress(&cinfo);