大家好,
最近研究C语言图像处理这方面遇到一个难题,详情如下:
目标:将png类型图片的信息读入内存,提取所需要的数据并保存,然后转换为如jpg等其它图片格式。
1.libpng库已经装好,通过makefile调用库文件路径也正确。
2.写了一个读取函数,如下:
#include
#include
#include
#include
#include
#include
#include"png.h"
#include"pngio.h"
#include"error.h"
#include"image.h"
/*==============================================================================*
*read_png*
*==============================================================================*/
intx,y;
intwidth,height;
intchannels;
png_bytecolor_type;
png_bytebit_depth;
png_structppng_ptr;
png_infopinfo_ptr;
intnumber_of_passes;
png_bytep*row_pointers;
png_uint_32w,h;
size_tnpixels;
//png_uint_32*raster;
//png_uint_32
intread_png(char*input_filename,picture*thePicture,FILE*status_log)
{
interr=no_err;
charheader[8];//8isthemaximumsizethatcanbechecked
/*openfileandtestforitbeingapng*/
FILE*fp=fopen(input_filename,"rb");
if(fp){
//abort_("[read_png_file]File%scouldnotbeopenedforreading",file_name);
fread(header,1,8,fp);
/*checkedoutwithaproperPNGsignature*/
if(png_check_sig(header,8)){
/*initializestuff*/
png_ptr=png_create_read_struct(PNG_LIBPNG_VER_STRING,NULL,NULL,NULL);
if(png_ptr){
info_ptr=png_create_info_struct(png_ptr);
if(info_ptr){
if(setjmp(png_jmpbuf(png_ptr))){
fprintf(status_log,"Errorduringinit_io.\n");
}else{
//takesourfilestreampointer(fp)andstoresitinthepng_ptrstructforlateruse.
png_init_io(png_ptr,fp);
//letslibpngknowthatwealreadycheckedthe8signaturebytes
png_set_sig_bytes(png_ptr,8);
//informationisstoredintheinformationstruct
png_read_info(png_ptr,info_ptr);
//png_read_update_info(png_ptr,info_ptr);
width=png_get_image_width(png_ptr,info_ptr);
height=png_get_image_height(png_ptr,info_ptr);
//w=png_get_image_width(png_ptr,info_ptr);
//h=png_get_image_height(png_ptr,info_ptr);
fprintf(status_log,"png-image-details:width=%i-height=%i\n",width,height);
//npixels=width*height;
npixels=width*height;
/*Readthewholeimageintomemoryatonce.*/
/*readfile*/
if(setjmp(png_jmpbuf(png_ptr)))
fprintf(status_log,"Errorduringread_image.\n");
png_uint_32*raster=malloc(npixels*4*sizeof(png_uint_32));
//row_pointers=(png_bytep*)malloc(npixels*sizeof(png_bytep));
row_pointers=(png_bytep*)malloc(sizeof(png_bytep)*height);
for(y=0;y
row_pointers[y]=(png_byte*)malloc(png_get_rowbytes(png_ptr,info_ptr));
png_read_image(png_ptr,row_pointers);
if(raster!=NULL){
channels=png_get_channels(png_ptr,info_ptr);
fprintf(status_log,"Bild-Kanalist%d.\n",channels);
fprintf(status_log,"Bildistgeladen\n");
thePicture->pixelmap=row_pointers;
thePicture->width=width;
thePicture->height=height;
thePicture->type=png_type;
}else{
fprintf(status_log,"Memoryerror.\n");
err=mem_err;
}
fclose(fp);
}
}else{
fprintf(status_log,"png_create_info_structfailed.\n");
//err=mem_err;
}
}else{
fprintf(status_log,"png_create_read_structfailed.\n");
}
}else{
fprintf(status_log,"checkingPNGfailed.\n");
}
}else{
fprintf(status_log,"Error.Failtoopenthepng.\n");
err=file_err;
}
returnerr;
}
3.测试结果如下:
原png图片:
转换后jpg:
请问是什么原因造成这样的效果,代码有什么地方需要修改吗?
先谢谢了。
15 个解决方案
#1
是rgb赋值的时候可能出的错
一定是像素赋值算法有问题
我感觉问题应该是从这后面出现的仔细看看赋值我搞过libjpg没搞过libpng
for(y=0;ypixelmap=row_pointers;thePicture->width=width;thePicture->height=height;thePicture->type=png_type;}else{fprintf(status_log,"Memoryerror.\n");err=mem_err;}
#2
行宽计算错误。
#3
谢谢二位的回复,为我指出了一个思维方向。
@Arther_L:我也怀疑是像素赋值的问题,程序中检查了通道数是4,在另外一个C程序中有包含RGBA的结构,如下:
typedefstructpixel3{
pixelvaluer;
pixelvalueg;
pixelvalueb;
pixelvaluea;
}pixel3
逐行位置通过一个函数来计算:
get_pixel(x,y,image)(((pixel3)(image->pixelmap))[(size_t)y*(size_t)image->width+(size_t)x])
请详细说明下,非常感谢。
@zhao4zhong1:可以提示一下吗,正确的行宽计算原理是怎样的,应该怎么修改我的代码?非常感谢。
#4
原PNG文件前面的非图像数据被误以为图像数据。
#5
貌似数据读入是一行行没见你整合成一个连续块,处理[(size_t)y*(size_t)image->width+(size_t)x]下标越界,混入垃圾数据了。不处理直接按行压缩试试...
#6
感谢二位的回复,
现在我理解的是,要再对读入数据进行过滤,对吗?
@赵先生:是不是我提取png数据图像的函数用的不正确?应该用头文件函数,是吗?libpng库函数我没有完全理解,能不能请你费心帮我改下那个错误部分的代码。。真的很感谢。
@天使_su:我理解你的意思是,我malloc的问题?能不能请你详细解释一下,很感谢。
祝你们顺利。
#7
按getpixel下标取值方式,pixelmap应该是个连续块,那就一次性malloc,row_pointers各元素值定位到数据块里的某个位置,类似:
stride=png_get_rowbytes(png_ptr,info_ptr);
data=(unsigendchar*)malloc(stride*height);
for(i=0;i
row_pointers[i]=data+(height-i-1)*stride;
png_read_image(png_ptr,row_pointers);
...
thePicture->pixelmap=data;
#8
谢谢你的回复,angel_su
我程序结构如下:
1.我在另外一个头文件中(如:image.h)定义了个图片格式的结构和图片基本大小,如下:
typedefstructpixel{
pixelvaluer;
pixelvalueg;
pixelvalueb;
}pixel
typedefstructpixel3{
pixelvaluer;
pixelvalueg;
pixelvalueb;
pixelvaluea;
}pixel3
typedefstructimage{
pixel*pixelmap;
intwidth;
intheight;
}image
typedefstructpicture{
pixel*pixelmap;
intwidth;
intheight;
inttype;
}picture
//逐行读取位置函数
get_pixel(x,y,image)(((pixel)(image->pixelmap))[(size_t)y*(size_t)image->width+(size_t)x]);
get_pixel3(x,y,image)(((pixel3)(image->pixelmap))[(size_t)y*(size_t)image->width+(size_t)x]);
2.在另外的处理文件中,有个函数用来复制一个相同的图像,然后修改
3.问一个很初级的问题,因为我对png库还没有完全理解。。。
(1).这两句,我理解是为输入图片(也是输出图片)的整个大小开辟内存,对吗?
stride=png_get_rowbytes(png_ptr,info_ptr);
data=(unsigendchar*)malloc(stride*height);
(2).下面是对行指针定义,为什么计算:data+(height-i-1)*stride;?
for(i=0;i
row_pointers[i]=data+(height-i-1)*stride;
png_read_image(png_ptr,row_pointers);
(3).data和row_pointers的关系是啥?
真是麻烦你了。。谢谢。
#9
引用8楼hanow_de2的回复:
谢谢你的回复,angel_su
(2).下面是对行指针定义,为什么计算:data+(height-i-1)*stride;?
我是想直接header+data存成bmp所以把扫描线倒置,你可以改成data+i*stride...
#10
引用4楼zhao4zhong1的回复:
原PNG文件前面的非图像数据被误以为图像数据。
此结论得自于你结果图象第一行开头多了一段垃圾像素。
#11
谢谢你们回复,
但我还是。。有点一头雾水。。。
@zhao4zhong1:我想您可能是说,结果图像中黑色背景部分,就是没有填充颜色的部分。。那我应该如何修改,怎么去掉垃圾像素呢,能否具体给我个代码可以吗?谢谢。
@angel_su:不好意思,我想,可能理解你的提示了,应该用data将每一行连接起来。谢谢。
#12
比如原PNG图片前面有调色板或色彩表之类的信息被你误以为图象数据。
建议换几个尺寸相同的纯一色PNG图片试试。
#13
谢谢您的回复,赵先生
所有的图片转换后都出现这样的结果,我现在只能确定是像素赋值问题。。。但是,做了很多修改的努力,还是没成功。。。如果您能帮我看看代码,或者详细的讲一下思路,我将十分感激。
祝顺利。
#14
单纯像素操作貌似很简单,你还是上代码说明问题...
#15
libpng有自带例子代码吗?如果有,先编译链接调试其自带例子代码。