libjpeg压缩图片,产生的缩略图颜色有失真

xuhui_7810 2016-11-14 09:09:48
各位大神:
我用libjpeg压缩图片,产生的缩略图颜色有失真,原图和缩略图如下:


我的代码如下:

struct my_error_mgr {
struct jpeg_error_mgr pub; /* "public" fields */

jmp_buf setjmp_buffer; /* for return to caller */
};

typedef struct my_error_mgr * my_error_ptr;



//读取Jpeg图片的数据并返回,如果出错,返回NULL
unsigned char* App::ReadJpeg(char* path, int& width, int& height)
{
FILE *file = fopen( path, "rb" );
if ( file == NULL ) {
return NULL;
}

struct jpeg_decompress_struct info; //for our jpeg info

// struct jpeg_error_mgr err; //the error handler
// info.err = jpeg_std_error(&err);

struct my_error_mgr my_err;

info.err = jpeg_std_error(&my_err.pub);
my_err.pub.error_exit = my_error_exit;

/* Establish the setjmp return context for my_error_exit to use. */
if (setjmp(my_err.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.
*/
printf("Error occured\n");
jpeg_destroy_decompress(&info);
fclose(file);
return NULL;
}

jpeg_create_decompress( &info ); //fills info structure
jpeg_stdio_src( &info, file ); //void

int ret_Read_Head = jpeg_read_header( &info, 1 ); //int

if(ret_Read_Head != JPEG_HEADER_OK){
printf("jpeg_read_header failed\n");
fclose(file);
jpeg_destroy_decompress(&info);
return NULL;
}

bool bStart = jpeg_start_decompress( &info );
if(!bStart){
printf("jpeg_start_decompress failed\n");
fclose(file);
jpeg_destroy_decompress(&info);
return NULL;
}
int w = width = info.output_width;
int h = height = info.output_height;
int numChannels = info.num_components; // 3 = RGB, 4 = RGBA
printf("ReadJpeg out_color_space =%d\n", info.out_color_space);
unsigned long dataSize = w * h * numChannels;

// read RGB(A) scanlines one at a time into jdata[]
unsigned char *data = (unsigned char *)malloc( dataSize );
if(!data) return NULL;

unsigned char* rowptr;
while ( info.output_scanline < (unsigned)h )
{
rowptr = data + info.output_scanline * w * numChannels;
jpeg_read_scanlines( &info, &rowptr, 1 );
}

jpeg_finish_decompress( &info );

fclose( file );

return data;
}

/*参数为:
*返回图片的宽度(w_Dest),
*返回图片的高度(h_Dest),
*返回图片的位深(bit_depth),
*源图片的RGB数据(src),
*源图片的宽度(w_Src),
*源图片的高度(h_Src)
*/
unsigned char* App::do_Stretch_Linear(int w_Dest,int h_Dest,int bit_depth,unsigned char *src,int w_Src,int h_Src)
{
int sw = w_Src-1, sh = h_Src-1, dw = w_Dest-1, dh = h_Dest-1;
int B, N, x, y;
int nPixelSize = bit_depth/8;
unsigned char *pLinePrev,*pLineNext;
unsigned char *pDest = new unsigned char[w_Dest*h_Dest*bit_depth/8];
unsigned char *tmp;
unsigned char *pA,*pB,*pC,*pD;

for(int i=0;i<=dh;++i)
{
tmp =pDest + i*w_Dest*nPixelSize;
y = i*sh/dh;
N = dh - i*sh%dh;
pLinePrev = src + (y++)*w_Src*nPixelSize;
//pLinePrev =(unsigned char *)aSrc->m_bitBuf+((y++)*aSrc->m_width*nPixelSize);
pLineNext = (N==dh) ? pLinePrev : src+y*w_Src*nPixelSize;
//pLineNext = ( N == dh ) ? pLinePrev : (unsigned char *)aSrc->m_bitBuf+(y*aSrc->m_width*nPixelSize);
for(int j=0;j<=dw;++j)
{
x = j*sw/dw*nPixelSize;
B = dw-j*sw%dw;
pA = pLinePrev+x;
pB = pA+nPixelSize;
pC = pLineNext + x;
pD = pC + nPixelSize;
if(B == dw)
{
pB=pA;
pD=pC;
}

for(int k=0;k<nPixelSize;++k)
{
pA++;
pB++;
pC++;
pD++;
*(tmp++) = ( unsigned char )( int )(
( B * N * ( (*pA) - (*pB) - (*pC) + (*pD) ) + dw * N * (*pB)
+ dh * B * (*pC) + ( dw * dh - dh * B - dw * N ) * (*pD)
+ dw * dh / 2 ) / ( dw * dh ) );
}
}
}
return pDest;
}

bool App::write_JPEG_file (char * filename, unsigned char* image_buffer, int quality,int image_height, int image_width)
{

if(filename == NULL || image_buffer == NULL) return false;

struct jpeg_compress_struct cinfo;
struct jpeg_error_mgr jerr;
FILE * outfile; /* target file */
JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */
int row_stride; /* physical row width in image buffer */
cinfo.err = jpeg_std_error(&jerr);
/* Now we can initialize the JPEG compression object. */
jpeg_create_compress(&cinfo);

if ((outfile = fopen(filename, "wb")) == NULL) {
fprintf(stderr, "can't open %s\n", filename);
return false;
}
jpeg_stdio_dest(&cinfo, outfile);

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_EXT_BGR; /* colorspace of input image */

jpeg_set_defaults(&cinfo);



cinfo.comp_info[0].v_samp_factor = 1;
cinfo.comp_info[0].h_samp_factor = 1;
jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values */);

jpeg_start_compress(&cinfo, TRUE);

row_stride = image_width * 3; /* JSAMPLEs per row in image_buffer */

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

jpeg_finish_compress(&cinfo);
fclose(outfile);

jpeg_destroy_compress(&cinfo);

return true;
}

//生成图片的缩略图(图片的一个缩小版本)
bool App::generate_image_thumbnail(char* inputFile, char* outputFile)
{
if(inputFile == NULL || outputFile == NULL) return false;

//读取jpeg图片像素数组
int w=0,h=0;
unsigned char* buff = ReadJpeg(inputFile,w,h);
if(buff == NULL) {
printf("ReadJpeg Failed\n");
return false;
}
printf("generate_image_thumbnail src w=%d, h=%d\n", w, h);
//缩放图片,缩放后的大小为(tb_w,tb_h)
int tb_w = 384, tb_h = 208;
unsigned char * img_buf = do_Stretch_Linear(tb_w,tb_h,24,buff,w,h);
free(buff);

//将缩放后的像素数组保存到jpeg文件
bool bRetWrite = write_JPEG_file(outputFile,img_buf,90, tb_h, tb_w);
delete[] img_buf;

if(bRetWrite){
return true;
}else{
printf("GenerateImageThumbnail: write failed\n");
return true;
}
}

/*
* Here's the routine that will replace the standard error_exit method:
*/

void
App::my_error_exit (j_common_ptr cinfo)
{
/* cinfo->err really points to a my_error_mgr struct, so coerce pointer */
my_error_ptr myerr = (my_error_ptr) cinfo->err;

/* Always display the message. */
/* We could postpone this until after returning, if we chose. */
(*cinfo->err->output_message) (cinfo);

/* Return control to the setjmp point */
longjmp(myerr->setjmp_buffer, 1);
}

void main(void)
{
generate_image_thumbnail("/src.jpg", "/dest.jpg");
}



之前我将cinfo.in_color_space 设为 JCS_RGB,一样有颜色失真,之前是红色和蓝色反了,所以改成了cinfo.in_color_space = JCS_EXT_BGR;,但这样改之后,颜色变成了这个样子。请问现在该怎么处理呢? (我这边不方便编译libjpeg,改不了它的源码)
...全文
553 5 打赏 收藏 转发到动态 举报
写回复
用AI写文章
5 条回复
切换为时间正序
请发表友善的回复…
发表回复
xuhui_7810 2016-11-18
  • 打赏
  • 举报
回复
请大神们指点一二
xuhui_7810 2016-11-16
  • 打赏
  • 举报
回复
请大神们再帮忙分析一二,
cocoabird 2016-11-15
  • 打赏
  • 举报
回复
JPEG 算法本身,将通常屏幕上表示颜色的 RGB(红绿蓝)数值,转换为 YUV 数值(亮度,蓝色分量,红色分量)。正常情况下这个算法是轻微有损的。 可以试试原生的libjpeg-turbo
xuhui_7810 2016-11-15
  • 打赏
  • 举报
回复
各位大神,不要让这贴子沉了啊
xuhui_7810 2016-11-15
  • 打赏
  • 举报
回复
JPEG 算法本身,将通常屏幕上表示颜色的 RGB(红绿蓝)数值,转换为 YUV 数值(亮度,蓝色分量,红色分量)。正常情况下这个算法是轻微有损的。 可以试试原生的libjpeg-turbo 你好,请问libjpeg有没有其他方法有所改善呢?我这压缩出来的缩略图,看起来不像是轻微有损,颜色失真比较严重。如果是轻微有损,作为缩略图还勉强可以接受

23,125

社区成员

发帖
与我相关
我的任务
社区描述
Linux/Unix社区 应用程序开发区
社区管理员
  • 应用程序开发区社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧