libjpeg-turbo是对libjpeg的扩展,支持SIMD指令,如X86架构的MMX、SSE、SSE2、3DNOW,ARM架构的NEON,在对jpeg进行编码和解码的过程中能提高速度。
MMX:多媒体扩展的缩写,第六代CPU芯片重要特点,57条指令。
SSE2:SIMD流技术扩展2,144个新增指令,被MMX优化过的程序很容易被SSE2进行更深层次的优化。
NEON:可加速多媒体和信号处理算法,它是ARM系列处理器的128位SIMD架构扩展。
在速度上,libjpeg-turbo一般是libjpeg的2-4倍。它既能调用libjpegAPI,又可调用TurboJPEG API。可以使用libjpeg-turbo替代libjpeg。
编译libjpeg-turbo:
1、从https://sourceforge.net/projects/libjpeg-turbo/通过TortoiseSVN下载libjpeg-turbo最新源代码,将其保存到D:\soft\libjpeg-turbo文件夹下;
2、从http://www.cmake.org/下载最新版的CMake,并安装;
3、在D:\soft\libjpeg-turbo文件夹下手动创建一个vs2010文件夹;
4、打开CMake,其中where isthe source code选项,选择D:/soft/libjpeg-turbo/libjpeg-turbo;where to build thebinaries选项,选择D:/soft/libjpeg-turbo/vs2010;
5、点击Configure,在弹出的对话框中选择VisualStudio 10,其它默认,点击Finish;
6、如果有红色框显示,继续点击Configure(将CMAKE_INSTALL_PREFIX中的value改为D:\libjpeg-turbo);
7、点击Generate,此时会在vs2010文件夹中看到libjpeg-turbo.sln文件;
8、从https://sourceforge.net/projects/nasm/下载最新版的nasm;
9、将nasm安装到D:\ProgramFiles\NASM文件夹下,并将其中的nasm.exe和ndisasm.exe两个文件拷贝到C:\ProgramFiles\Microsoft Visual Studio 10.0\VC\bin下(如果是64位,则拷贝到C:\ProgramFiles (x86)\Microsoft Visual Studio 10.0\VC\bin),将其D:\ProgramFiles\NASM添加到系统环境变量中;
10、打开libjpeg-turbo.sln,分别在Debug和Release下,选择Solution Explorer里的Solution libjpeg-turbo,点击右键,运行”Rebuild Solution”,然后选中INSTALL, build;
11、全部完成后会在D:\libjpeg-turbo文件夹下生成bin、doc、lib、include四个文件夹,编译成功(说明:默认的Debgu和Release下生成的所有文件夹都相同,注意区分);
12、打开vs2010,新建一个控制台应用程序,为vs2010配置libjpeg-turbo环境:选择View--> Properties Manager-->分别选中Debug和Release上的Microsoft.Cpp.Win32.user,点击右键-->Properties:VC++ Directories,Include Directories:D:\libjpeg-turbo\include;Library Directories:D:\libjpeg-turbo\lib;
13、选中工程-->Properties-->Configuration Properties-->Linker-->Input-->AdditionalDependencies:Debug和Release,添加相应的.lib库;
14、将D:\libjpeg-turbo\bin加入到windows系统环境变量Path中,重启。
新建一个控制台工程:
1、将jconfig.h文件拷贝到该工程目录下;
2、stdafx.h:
#pragma once
#include "targetver.h"
#include
#include "D:/Soft/libjpegturbo/libjpegturbo/jpeglib.h"
3、stdafx.cpp:
#include "stdafx.h"
// TODO: reference any additional headers you need in STDAFX.H
// and not in this file
#ifdef _DEBUG
#pragma comment(lib, "D:/Soft/libjpegturbo/vs2010/Debug/jpeg-static.lib")
#else
#pragma comment(lib, "D:/Soft/libjpegturbo/vs2010/Release/jpeg-static.lib")
#endif
4、main.cpp:
#include "stdafx.h"
#include
#include
#include
#include
#include
using namespace std;
int read_JPEG_file(string strImageName)
{
/* This struct contains the JPEG decompression parameters and pointers to
* working space (which is allocated as needed by the JPEG library).
*/
struct jpeg_decompress_struct cinfo;
/* We use our private extension JPEG error handler.
* Note that this struct must live as long as the main JPEG parameter
* struct, to avoid dangling-pointer problems.
*/
struct jpeg_error_mgr jerr;
/* More stuff */
FILE * infile;/* source file */
JSAMPARRAY buffer;/* Output row buffer */
int row_stride;/* physical row width in output buffer */
/* In this example we want to open the input file before doing anything else,
* so that the setjmp() error recovery below can assume the file is open.
* VERY IMPORTANT: use "b" option to fopen() if you are on a machine that
* requires it in order to read binary files.
*/
if ((infile = fopen(strImageName.c_str(), "rb")) == NULL) {
fprintf(stderr, "can't open %s\n", strImageName);
return -1;
}
/* Step 1: allocate and initialize JPEG decompression object */
/* We set up the normal JPEG error routines, then override error_exit. */
cinfo.err = jpeg_std_error(&jerr);
/* Establish the setjmp return context for my_error_exit to use. */
//if (setjmp(jerr.setjmp_buffer)) {
/* If we get here, the JPEG code has signaled an error.
* We need to clean up the JPEG object, close the input file, and return.
*/
//jpeg_destroy_decompress(&cinfo);
//fclose(infile);
//return -1;
//}
/* Now we can initialize the JPEG decompression object. */
jpeg_create_decompress(&cinfo);
/* Step 2: specify data source (eg, a file) */
jpeg_stdio_src(&cinfo, infile);
/* Step 3: read file parameters with jpeg_read_header() */
jpeg_read_header(&cinfo, TRUE);
/* We can ignore the return value from jpeg_read_header since
* (a) suspension is not possible with the stdio data source, and
* (b) we passed TRUE to reject a tables-only JPEG file as an error.
* See libjpeg.txt for more info.
*/
printf("image_width = %d\n", cinfo.image_width);
printf("image_height = %d\n", cinfo.image_height);
printf("num_components = %d\n", cinfo.num_components);
/* Step 4: set parameters for decompression */
/* In this example, we don't need to change any of the defaults set by
* jpeg_read_header(), so we do nothing here.
*/
printf("enter scale M/N:\n");
//scanf("%d/%d", &cinfo.scale_num, &cinfo.scale_denom);
cinfo.scale_num = 2;
cinfo.scale_denom = 4;
printf("scale to : %d/%d\n", cinfo.scale_num, cinfo.scale_denom);
/* Step 5: Start decompressor */
jpeg_start_decompress(&cinfo);
/* We can ignore the return value since suspension is not possible
* with the stdio data source.
*/
//输出的图象的信息
printf("output_width = %d\n", cinfo.output_width);
printf("output_height = %d\n", cinfo.output_height);
printf("output_components = %d\n", cinfo.output_components);
/* We may need to do some setup of our own at this point before reading
* the data. After jpeg_start_decompress() we have the correct scaled
* output image dimensions available, as well as the output colormap
* if we asked for color quantization.
* In this example, we need to make an output work buffer of the right size.
*/
/* JSAMPLEs per row in output buffer */
row_stride = cinfo.output_width * cinfo.output_components;
/* Make a one-row-high sample array that will go away when done with image */
buffer = (*cinfo.mem->alloc_sarray)((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1);
/* Step 6: while (scan lines remain to be read) */
/* jpeg_read_scanlines(...); */
/* Here we use the library's state variable cinfo.output_scanline as the
* loop counter, so that we don't have to keep track ourselves.
*/
while (cinfo.output_scanline < cinfo.output_height) {
/* jpeg_read_scanlines expects an array of pointers to scanlines.
* Here the array is only one element long, but you could ask for
* more than one scanline at a time if that's more convenient.
*/
jpeg_read_scanlines(&cinfo, buffer, 1);
/* Assume put_scanline_someplace wants a pointer and sample count. */
//put_scanline_someplace(buffer[0], row_stride);
}
/* Step 7: Finish decompression */
jpeg_finish_decompress(&cinfo);
/* We can ignore the return value since suspension is not possible
* with the stdio data source.
*/
/* Step 8: Release JPEG decompression object */
/* This is an important step since it will release a good deal of memory. */
jpeg_destroy_decompress(&cinfo);
/* After finish_decompress, we can close the input file.
* Here we postpone it until after no more JPEG errors are possible,
* so as to simplify the setjmp error logic above. (Actually, I don't
* think that jpeg_destroy can do an error exit, but why assume anything...)
*/
fclose(infile);
/* At this point you may want to check to see whether any corrupt-data
* warnings occurred (test whether jerr.pub.num_warnings is nonzero).
*/
return 0;
}
int write_JPEG_file(string strImageName, int quality)
{
unsigned char* image_buffer; /* Points to large array of R,G,B-order data */
int image_height = 200; /* Number of rows in image */
int image_width = 400; /* Number of columns in image */
/* This struct contains the JPEG compression parameters and pointers to
* working space (which is allocated as needed by the JPEG library).
* It is possible to have several such structures, representing multiple
* compression/decompression processes, in existence at once. We refer
* to any one struct (and its associated working data) as a "JPEG object".
*/
struct jpeg_compress_struct cinfo;
/* This struct represents a JPEG error handler. It is declared separately
* because applications often want to supply a specialized error handler
* (see the second half of this file for an example). But here we just
* take the easy way out and use the standard error handler, which will
* print a message on stderr and call exit() if compression fails.
* Note that this struct must live as long as the main JPEG parameter
* struct, to avoid dangling-pointer problems.
*/
struct jpeg_error_mgr jerr;
/* More stuff */
FILE * outfile; /* target file */
JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */
int row_stride; /* physical row width in image buffer */
/* Step 1: allocate and initialize JPEG compression object */
/* We have to set up the error handler first, in case the initialization
* step fails. (Unlikely, but it could happen if you are out of memory.)
* This routine fills in the contents of struct jerr, and returns jerr's
* address which we place into the link field in cinfo.
*/
cinfo.err = jpeg_std_error(&jerr);
/* Now we can initialize the JPEG compression object. */
jpeg_create_compress(&cinfo);
/* Step 2: specify data destination (eg, a file) */
/* Note: steps 2 and 3 can be done in either order. */
/* Here we use the library-supplied code to send compressed data to a
* stdio stream. You can also write your own code to do something else.
* VERY IMPORTANT: use "b" option to fopen() if you are on a machine that
* requires it in order to write binary files.
*/
if ((outfile = fopen(strImageName.c_str(), "wb")) == NULL) {
fprintf(stderr, "can't open %s\n", strImageName);
//exit(1);
return -1;
}
jpeg_stdio_dest(&cinfo, outfile);
/* Step 3: set parameters for compression */
/* First we supply a description of the input image.
* Four fields of the cinfo struct must be filled in:
*/
cinfo.image_width = image_width; /* image width and height, in pixels */
cinfo.image_height = image_height;
cinfo.input_components = 3; /* # of color components per pixel */
cinfo.in_color_space = JCS_RGB; /* colorspace of input image */
/* Now use the library's routine to set default compression parameters.
* (You must set at least cinfo.in_color_space before calling this,
* since the defaults depend on the source color space.)
*/
jpeg_set_defaults(&cinfo);
/* Now you can set any non-default parameters you wish to.
* Here we just illustrate the use of quality (quantization table) scaling:
*/
jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values */);
/* Step 4: Start compressor */
/* TRUE ensures that we will write a complete interchange-JPEG file.
* Pass TRUE unless you are very sure of what you're doing.
*/
jpeg_start_compress(&cinfo, TRUE);
/* Step 5: while (scan lines remain to be written) */
/* jpeg_write_scanlines(...); */
/* Here we use the library's state variable cinfo.next_scanline as the
* loop counter, so that we don't have to keep track ourselves.
* To keep things simple, we pass one scanline per call; you can pass
* more if you wish, though.
*/
row_stride = image_width * 3; /* JSAMPLEs per row in image_buffer */
image_buffer = new unsigned char[row_stride * cinfo.image_height];
memset(image_buffer, 0xff, row_stride * cinfo.image_height);
int line = 0;
//while (cinfo.next_scanline < cinfo.image_height) {
while (line < cinfo.image_height) {
/* jpeg_write_scanlines expects an array of pointers to scanlines.
* Here the array is only one element long, but you could pass
* more than one scanline at a time if that's more convenient.
*/
//row_pointer[0] = &image_buffer[cinfo.next_scanline * row_stride];
row_pointer[0] = &image_buffer[line * row_stride];
jpeg_write_scanlines(&cinfo, row_pointer, 1);
line ++;
}
delete image_buffer;
/* Step 6: Finish compression */
jpeg_finish_compress(&cinfo);
/* After finish_compress, we can close the output file. */
fclose(outfile);
/* Step 7: release JPEG compression object */
/* This is an important step since it will release a good deal of memory. */
jpeg_destroy_compress(&cinfo);
return 0;
}
struct Image
{
int bpp;
int width;
int height;
unsigned char* data;
};
struct jerror_mgr
{
jpeg_error_mgr base;
jmp_buf jmp;
};
METHODDEF(void) jerror_exit(j_common_ptr jinfo)
{
jerror_mgr* err = (jerror_mgr*)jinfo->err;
longjmp(err->jmp, 1);
}
METHODDEF(void) joutput_message(j_common_ptr)
{
}
bool Image_LoadJpeg(Image* image, unsigned char* img_data, unsigned int img_size)
{
jpeg_decompress_struct jinfo;
jerror_mgr jerr;
jinfo.err = jpeg_std_error(&jerr.base);
jerr.base.error_exit = jerror_exit;
jerr.base.output_message = joutput_message;
jpeg_create_decompress(&jinfo);
image->data = NULL;
if (setjmp(jerr.jmp)) goto bail;
jpeg_mem_src(&jinfo, img_data, img_size);
if (jpeg_read_header(&jinfo, TRUE) != JPEG_HEADER_OK) goto bail;
jinfo.dct_method = JDCT_FLOAT; // change this to JDCT_ISLOW on Android/iOS
if (!jpeg_start_decompress(&jinfo)) goto bail;
if (jinfo.num_components != 1 && jinfo.num_components != 3) goto bail;
image->data = new (std::nothrow) unsigned char [jinfo.output_width * jinfo.output_height * jinfo.output_components];
if (!image->data) goto bail;
{
JSAMPROW ptr = image->data;
while (jinfo.output_scanline < jinfo.output_height)
{
if (jpeg_read_scanlines(&jinfo, &ptr, 1) != 1) goto bail;
ptr += jinfo.output_width * jinfo.output_components;
}
}
if (!jpeg_finish_decompress(&jinfo)) goto bail;
image->bpp = jinfo.output_components;
image->width = jinfo.output_width;
image->height = jinfo.output_height;
jpeg_destroy_decompress(&jinfo);
return true;
bail:
jpeg_destroy_decompress(&jinfo);
if (image->data) delete [] image->data;
return false;
}
struct ImageData {
unsigned char *pixels;
long width;
long height;
};
int TestImage(string strSrcImageName, string strDstImageName)
{
//read
struct jpeg_decompress_struct cinfo_decompress;
FILE* infile;
int row_stride;
struct jpeg_error_mgr jerr;
if ((infile = fopen(strSrcImageName.c_str(), "rb")) == NULL) {
fprintf(stderr, "can't open %s\n", strSrcImageName);
return -1;
}
cinfo_decompress.err = jpeg_std_error(&jerr);
jpeg_create_decompress(&cinfo_decompress);
jpeg_stdio_src(&cinfo_decompress, infile);
int ret = jpeg_read_header(&cinfo_decompress, TRUE);
if (ret != JPEG_HEADER_OK) return -1;
jpeg_start_decompress(&cinfo_decompress);
row_stride = cinfo_decompress.output_width * cinfo_decompress.output_components;
int buffer_height = 1;
JSAMPARRAY buffer = (JSAMPARRAY)malloc(sizeof(JSAMPROW) * buffer_height);
buffer[0] = (JSAMPROW)malloc(sizeof(JSAMPLE) * row_stride);
//JSAMPARRAY buffer = (*cinfo_decompress.mem->alloc_sarray)((j_common_ptr)&cinfo_decompress, JPOOL_IMAGE, row_stride, 1);
ImageData *imageData;
imageData = new ImageData;
imageData->width = cinfo_decompress.output_width;
imageData->height = cinfo_decompress.output_height;
imageData->pixels = new unsigned char [cinfo_decompress.output_width * cinfo_decompress.output_height * cinfo_decompress.output_components];
long counter = 0;
while (cinfo_decompress.output_scanline < cinfo_decompress.output_height) {
jpeg_read_scanlines(&cinfo_decompress, buffer, 1);
memcpy(imageData->pixels + counter, buffer[0], row_stride);
counter += row_stride;
}
jpeg_finish_decompress(&cinfo_decompress);
jpeg_destroy_decompress(&cinfo_decompress);
fclose(infile);
//write
unsigned char* image_buffer;
int image_height = cinfo_decompress.output_height;
int image_width = cinfo_decompress.output_width;
FILE * outfile;
JSAMPROW row_pointer[1];
int row_stride_dst;
struct jpeg_compress_struct cinfo_compress;
cinfo_compress.err = jpeg_std_error(&jerr);
jpeg_create_compress(&cinfo_compress);
if ((outfile = fopen(strDstImageName.c_str(), "wb")) == NULL) {
fprintf(stderr, "can't open %s\n", strDstImageName);
//exit(1);
return -1;
}
jpeg_stdio_dest(&cinfo_compress, outfile);
cinfo_compress.image_width = image_width;
cinfo_compress.image_height = image_height;
cinfo_compress.input_components = 3;
cinfo_compress.in_color_space = JCS_YCbCr;
int quality = 70;
jpeg_set_defaults(&cinfo_compress);
jpeg_set_quality(&cinfo_compress, quality, TRUE);
jpeg_start_compress(&cinfo_compress, TRUE);
row_stride_dst = image_width * 3;
image_buffer = new unsigned char[row_stride_dst * cinfo_compress.image_height];
memcpy(image_buffer, imageData->pixels, row_stride_dst * cinfo_compress.image_height);
while (cinfo_compress.next_scanline < cinfo_compress.image_height) {
row_pointer[0] = &image_buffer[cinfo_compress.next_scanline * row_stride_dst];
jpeg_write_scanlines(&cinfo_compress, row_pointer, 1);
}
jpeg_finish_compress(&cinfo_compress);
fclose(outfile);
jpeg_destroy_compress(&cinfo_compress);
if (imageData) {
delete imageData;
imageData = NULL;
}
if (image_buffer)
delete [] image_buffer;
return 0;
}
int main(int argc, char* argv[])
{
string strImageName = "1.jpg";
int flag1 = read_JPEG_file(strImageName);
if (flag1 == 0) cout<<"read ok!"<
参考文献:
1、 http://libjpeg-turbo.virtualgl.org/
2、 http://www.linuxsir.org/bbs/thread374093.html
3、 http://blog.sina.com.cn/s/blog_a5b979d30101af56.html
4、 http://blog.csdn.net/jwzhangjie/article/details/8807409
5、 http://blog.csdn.net/hongwazi_2010/article/details/9153087
GitHub:https://github.com//fengbingchun/OCR_Test