整理自:
http://hi.baidu.com/lewutian/item/e8eed42664ee61122a0f1c89
http://blog.csdn.net/mcgrady_tracy/article/details/7439066
1.下载编译库
下载库:
http://www.ijg.org/ 网址下面的windows版本的。本文下载的是jpegsr9a.zip。
编译库:
libjpeg,以vs2008为例, 首先要把jconfig.vc复制为jconfig.h。
打开VS2008的command line prompt命令行提示符,切换到解压的libjpeg目录下,输入"nmake -f makefile.vc"
完成后取出libjpeg.lib就行了
2.项目中引入库
将编译出来的lib目录和lib名称配置到VC的linker中,头文件引入就可以了。
3.实例代码(Jpeglib读取图像函数说明见代码注释)
JEPGFile.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "jpeglib.h"
#define PUT_2B(array,offset,value) \
(array[offset] = (char) ((value) & 0xFF), \
array[offset+1] = (char) (((value) >> 8) & 0xFF))
#define PUT_4B(array,offset,value) \
(array[offset] = (char) ((value) & 0xFF), \
array[offset+1] = (char) (((value) >> 8) & 0xFF), \
array[offset+2] = (char) (((value) >> 16) & 0xFF), \
array[offset+3] = (char) (((value) >> 24) & 0xFF))
void write_bmp_header(j_decompress_ptr cinfo, FILE *output_file)
{
//cinfo已经转换为小端模式了
char bmpfileheader[14];
char bmpinfoheader[40];
long headersize, bfSize;
int bits_per_pixel, cmap_entries;
int step;
/* Compute colormap size and total file size */
if (cinfo->out_color_space == JCS_RGB) {
if (cinfo->quantize_colors) {
/* Colormapped RGB */
bits_per_pixel = 8;
cmap_entries = 256;
} else {
/* Unquantized, full color RGB */
bits_per_pixel = 24;
cmap_entries = 0;
}
} else {
/* Grayscale output. We need to fake a 256-entry colormap. */
bits_per_pixel = 8;
cmap_entries = 256;
}
step = cinfo->output_width * cinfo->output_components;
while ((step & 3) != 0) step++;
/* File size */
headersize = 14 + 40 + cmap_entries * 4; /* Header and colormap */
bfSize = headersize + (long) step * (long) cinfo->output_height;
/* Set unused fields of header to 0 */
memset(bmpfileheader, 0, sizeof(bmpfileheader));
memset(bmpinfoheader, 0 ,sizeof(bmpinfoheader));
/* Fill the file header */
bmpfileheader[0] = 0x42;/* first 2 bytes are ASCII 'B', 'M' */
bmpfileheader[1] = 0x4D;
PUT_4B(bmpfileheader, 2, bfSize); /* bfSize */
/* we leave bfReserved1 & bfReserved2 = 0 */
PUT_4B(bmpfileheader, 10, headersize); /* bfOffBits */
/* Fill the info header (Microsoft calls this a BITMAPINFOHEADER) */
PUT_2B(bmpinfoheader, 0, 40); /* biSize */
PUT_4B(bmpinfoheader, 4, cinfo->output_width); /* biWidth */
PUT_4B(bmpinfoheader, 8, cinfo->output_height); /* biHeight */
PUT_2B(bmpinfoheader, 12, 1); /* biPlanes - must be 1 */
PUT_2B(bmpinfoheader, 14, bits_per_pixel); /* biBitCount */
/* we leave biCompression = 0, for none */
/* we leave biSizeImage = 0; this is correct for uncompressed data */
if (cinfo->density_unit == 2) { /* if have density in dots/cm, then */
PUT_4B(bmpinfoheader, 24, (INT32) (cinfo->X_density*100)); /* XPels/M */
PUT_4B(bmpinfoheader, 28, (INT32) (cinfo->Y_density*100)); /* XPels/M */
}
PUT_2B(bmpinfoheader, 32, cmap_entries); /* biClrUsed */
/* we leave biClrImportant = 0 */
if (fwrite(bmpfileheader, 1, 14, output_file) != (size_t) 14) {
printf("write bmpfileheader error\n");
}
if (fwrite(bmpinfoheader, 1, 40, output_file) != (size_t) 40) {
printf("write bmpinfoheader error\n");
}
if (cmap_entries > 0) {
}
}
void write_pixel_data(j_decompress_ptr cinfo, unsigned char *output_buffer, FILE *output_file)
{
int rows, cols;
int row_width;
int step;
unsigned char *tmp = NULL;
unsigned char *pdata;
row_width = cinfo->output_width * cinfo->output_components;
step = row_width;
while ((step & 3) != 0) step++;
pdata = (unsigned char *)malloc(step);
memset(pdata, 0, step);
// JPEG左上角的开始一行行写的数据,转换为BMP的从左下角开始一行行写的数据
// 也就是JPEG最末的行放置到BMP最开始行,JPEG最开始行放置到BMP最末行就对了。
tmp = output_buffer + row_width * (cinfo->output_height - 1);
for (rows = 0; rows < cinfo->output_height; rows++) {
for (cols = 0; cols < row_width; cols += 3) {
// 大端模式转换为小端模式
pdata[cols + 2] = tmp[cols + 0];
pdata[cols + 1] = tmp[cols + 1];
pdata[cols + 0] = tmp[cols + 2];
}
tmp -= row_width;
fwrite(pdata, 1, step, output_file);
}
free(pdata);
}
/*读JPEG文件相当于解压文件*/
int read_jpeg_file(const char *input_filename, const char *output_filename)
{
struct jpeg_decompress_struct cinfo;
struct jpeg_error_mgr jerr;
FILE *input_file;
FILE *output_file;
JSAMPARRAY buffer;
int row_width;
unsigned char *output_buffer;
unsigned char *tmp = NULL;
cinfo.err = jpeg_std_error(&jerr);
if ((input_file = fopen(input_filename, "rb")) == NULL) {
fprintf(stderr, "can't open %s\n", input_filename);
return -1;
}
if ((output_file = fopen(output_filename, "wb")) == NULL) {
fprintf(stderr, "can't open %s\n", output_filename);
return -1;
}
// Initialization of JPEG compression objects
jpeg_create_decompress(&cinfo);
/* Specify data source for decompression */
jpeg_stdio_src(&cinfo, input_file);
/* 1.设置读取jpg文件头部,Read file header, set default decompression parameters */
(void) jpeg_read_header(&cinfo, TRUE);
/* 2.开始解码数据 Start decompressor */
(void) jpeg_start_decompress(&cinfo);
row_width = cinfo.output_width * cinfo.output_components;
/* 3.跳过读取的头文件字节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_width, 1);
write_bmp_header(&cinfo, output_file);
output_buffer = (unsigned char *)malloc(row_width * cinfo.output_height);
memset(output_buffer, 0, row_width * cinfo.output_height);
tmp = output_buffer;
/* 4.Process data由左上角从上到下行行扫描 */
while (cinfo.output_scanline < cinfo.output_height) {
(void) jpeg_read_scanlines(&cinfo, buffer, 1);
memcpy(tmp, *buffer, row_width);
tmp += row_width;
}
// 写入数据,注意大小端转换和图像数据坐标表示差异在内存中的顺序
write_pixel_data(&cinfo, output_buffer, output_file);
free(output_buffer);
(void) jpeg_finish_decompress(&cinfo);
jpeg_destroy_decompress(&cinfo);
/* Close files, if we opened them */
fclose(input_file);
fclose(output_file);
return 0;
}
int write_jpeg_file(char * filename, int quality)
{
struct jpeg_compress_struct cinfo;
unsigned char * image_buffer;
int i = 0;
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.
*/
/*1.第一步创建jpeg compress 对象*/
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(filename, "wb")) == NULL) {
fprintf(stderr, "can't open %s\n", filename);
exit(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:
*/
/*2.设置 压缩参数 libjpeg中的宽度和高度是两个全局的
我这默认设置成640 480。根据demo中的说明color_space必须
得设置*/
cinfo.image_width = 640; /* image width and height, in pixels */
cinfo.image_height = 480;
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:
*/
/*设置quality为2*/
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.
*/
/*3. 开始压缩*/
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 = 640 * 3; /* JSAMPLEs per row in image_buffer */
image_buffer = (unsigned char*)malloc(640*480*3);
if (NULL == image_buffer)
{
return -1;
}
for(i=0; i< 640*480; i++)
{
// 4.构造的数据,数据是RGB形式Pixel
image_buffer[i*3] = 255/*i*255*/;
image_buffer[i*3+1] = 255/*128-(i*255)&0x7f*/;
image_buffer[i*3+2] = 0/*255-(i*255)&0xff*/;
}
while (cinfo.next_scanline < 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.
*/
// 5.将数据扫描输入,image_buffer数据是RGB形式Pixel
row_pointer[0] = & image_buffer[cinfo.next_scanline * row_stride];
(void) jpeg_write_scanlines(&cinfo, row_pointer, 1);
}
/* Step 6: Finish compression */
// 6.完成压缩
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);
/* And we're done! */
}
int main(int argc, char *argv[])
{
read_jpeg_file("f:\\data\\animal.jpg", "f:\\data\\animal.bmp");
write_jpeg_file("f:\\data\\createJpg.jpg", 2);
return 0;
}