libpng使用例子

来源:互联网 发布:淘宝翻新机质量怎么样 编辑:程序博客网 时间:2024/05/17 01:30

本例使用libpng,将一系列单个的序列帧png文件合并成一个大的png, 去除无用的空白,计算每个系列的最小有效范围。

请看源码吧,libpng用法有不明白的,可以参考一下,有抄到的到方请保留版权

 

 

//@author aerror //2011/12/02#include "stdafx.h"#include <Windows.h>#include <stdio.h>#include <time.h>#include <sys/types.h>#include <sys/stat.h>#include <errno.h>#include <tchar.h>#include <vector>#include <string>#include <list>extern "C"{#include "png.h"}#define EnsureVectorSize(v,ds)  {if(v.size()<(unsigned int)ds){ v.resize(ds);}}typedef struct _RECTANGLE{int top;int left;int bottom;int right;}TRECTANGLE;class PNG_SRC_FILE{public:std::string filename;png_bytep   bmp;unsigned int rawWidth  ;unsigned int rawHeight  ;PNG_SRC_FILE(const char * src){filename =src;bmp = NULL;}virtual ~PNG_SRC_FILE(){if(bmp!=NULL){delete []bmp;}}};typedef std::list<  PNG_SRC_FILE *> TPNG_SRC_FILE_LIST;typedef std::list<   PNG_SRC_FILE *>::iterator TPNG_SRC_FILE_LIST_ITER;bool filename_sort(PNG_SRC_FILE * x1,PNG_SRC_FILE * x2){return x1->filename < x2->filename;}typedef struct _tanimation_info{const char *actionName;const char *actionDir;unsigned rowHeight;unsigned frameWidth;unsigned frameHeight;unsigned totalFrame;unsigned fps;TPNG_SRC_FILE_LIST  * filelist;unsigned int minTop     ;unsigned int maxBottom  ;unsigned int minLeft    ;unsigned int maxRight   ;}TANIMATION_INFO;std::vector<BYTE>s_srcDibBitsBuffer;std::vector<BYTE>s_dstDibBitsBuffer;std::vector<BYTE>s_dstPngRowsBuffer;std::vector<BYTE>s_dstPngTempBuffer;int outputToPngFileNormal(const char *szFileName,unsigned int numDibBtis,const unsigned char *pDibBytes,unsigned int _width, unsigned int _height){FILE *fp;png_structp png_ptr;png_infop info_ptr;/* open the file */fp = fopen(szFileName, "wb");if (fp == NULL)  return (ERROR);png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,NULL, NULL, NULL);if (png_ptr == NULL){  fclose(fp);  return (ERROR);}/* Allocate/initialize the image information data.  REQUIRED */info_ptr = png_create_info_struct(png_ptr);if (info_ptr == NULL){  fclose(fp);  png_destroy_write_struct(&png_ptr,  png_infopp_NULL);  return (ERROR);}/* Set error handling.  REQUIRED if you aren't supplying your own* error handling functions in the png_create_write_struct() call.*/if (setjmp(png_jmpbuf(png_ptr))){  /* If we get here, we had a problem reading the file */  fclose(fp);  png_destroy_write_struct(&png_ptr, &info_ptr);  return (ERROR);}png_init_io(png_ptr, fp);/* Set the image information here.  Width and height are up to 2^31,* bit_depth is one of 1, 2, 4, 8, or 16, but valid values also depend on* the color_type selected. color_type is one of PNG_COLOR_TYPE_GRAY,* PNG_COLOR_TYPE_GRAY_ALPHA, PNG_COLOR_TYPE_PALETTE, PNG_COLOR_TYPE_RGB,* or PNG_COLOR_TYPE_RGB_ALPHA.  interlace is either PNG_INTERLACE_NONE or* PNG_INTERLACE_ADAM7, and the compression_type and filter_type MUST* currently be PNG_COMPRESSION_TYPE_BASE and PNG_FILTER_TYPE_BASE. REQUIRED*/int src_bytes_per_pixel= numDibBtis/_width/_height;png_uint_32 k, height, width;height = _height;width = _width;png_set_IHDR(png_ptr, info_ptr, width, height, 8,    PNG_COLOR_TYPE_RGB_ALPHA,  PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);png_text text_ptr[2]={0,0};char szDetail[255]="pvr";/*sprintf(szDetail,"type=%d method=%d size=%dx%d lefttop=%d,%d frame=%dx%d\n",pInfo->type,pInfo->method,(int)(pInfo->width),(int)(pInfo->height), (int)(pInfo->left),(int)(pInfo->top),(int)(pInfo->frmWidth),(int)(pInfo->frmHeith) );*/text_ptr[0].key = "Author";text_ptr[0].text = "dany21cn@21cn.com";text_ptr[0].compression = PNG_TEXT_COMPRESSION_NONE;text_ptr[1].key = "Description";text_ptr[1].text = szDetail;text_ptr[1].compression = PNG_TEXT_COMPRESSION_NONE;png_set_text(png_ptr, info_ptr, text_ptr, 2);/* Write the file header information.  REQUIRED */png_write_info(png_ptr, info_ptr);if (height > PNG_UINT_32_MAX/png_sizeof(png_bytep)) png_error (png_ptr, "Image is too tall to process in memory");png_bytep image =  NULL;png_bytep imagerow =  NULL;EnsureVectorSize(s_dstPngRowsBuffer,width*4);imagerow =&s_dstPngRowsBuffer[0];for(int y=0;y<_height;y++){for(int x=0;x<_width;x++){int dx = x;//+pInfo->left;int dy = y;//+pInfo->top;if(dx>width || dy>height){printf("invalid offset operation\n");return ERROR;}const unsigned char* psrc = pDibBytes + y*_width*src_bytes_per_pixel+ x*src_bytes_per_pixel;png_bytep pdst = NULL;pdst = imagerow  +dx*4;if(src_bytes_per_pixel==4){/*pdst[0] = psrc[2];pdst[1] = psrc[1];pdst[2] = psrc[0];pdst[3] = psrc[3];*/pdst[0] = psrc[0];pdst[1] = psrc[1];pdst[2] = psrc[2];pdst[3] = psrc[3];}}png_write_row(png_ptr,imagerow);}/* You can write optional chunks like tEXt, zTXt, and tIME at the end* as well.  Shouldn't be necessary in 1.1.0 and up as all the public* chunks are supported and you can use png_set_unknown_chunks() to* register unknown chunks into the info structure to be written out.*//* It is REQUIRED to call this to finish writing the rest of the file */png_write_end(png_ptr, info_ptr);/* clean up after the write, and free any memory allocated */png_destroy_write_struct(&png_ptr, &info_ptr);fclose(fp);return 0;}TRECTANGLE cutTransparent(png_bytep bmp, unsigned int width, unsigned int height ){TRECTANGLE  t={0,0,height,width};//row by row from top//for(int y=0;y<height;y++){bool thisLineEmpty = true;for(int x=0;x<width;x++){unsigned char* psrc = bmp + y*width*4+ x*4;unsigned  int v =  *(unsigned int* )psrc;if(v &0xFF000000){thisLineEmpty = false;break;}}if(thisLineEmpty){t.top ++ ;}else{break;}}for(int y=height-1;y>=0;y--){bool thisLineEmpty = true;for(int x=0;x<width;x++){unsigned char* psrc = bmp + y*width*4+ x*4;unsigned  int v =  *(unsigned int* )psrc;if(v &0xFF000000){thisLineEmpty = false;break;}}if(thisLineEmpty){t.bottom --;}else{break;}}for(int x=0;x<width;x++){bool thisLineEmpty = true;for(int y=0;y<height;y++){unsigned char* psrc = bmp + y*width*4+ x*4;unsigned  int v =  *(unsigned int* )psrc;if(v &0xFF000000){thisLineEmpty = false;break;}}if(thisLineEmpty){t.left ++ ;}else{break;}}for(int x=width-1;x>=0;x--){bool thisLineEmpty = true;for(int y=0;y<height;y++){unsigned char* psrc = bmp + y*width*4+ x*4;unsigned  int v =  *(unsigned int* )psrc;if(v &0xFF000000){thisLineEmpty = false;break;}}if(thisLineEmpty){t.right --;}else{break;}}return t;}/**stand=standbyattack=Normal attacksquat=Morale attackattacked=under attackdefense=????*/void concat(const char *packsDir, const char *outputDir){WIN32_FIND_DATAA FindFileData;HANDLE hFind = INVALID_HANDLE_VALUE;char DirSpec[MAX_PATH];  // directory specificationchar DirBase[MAX_PATH];  // directory specificationchar filename_dest[MAX_PATH];char npc_name[MAX_PATH];DWORD dwError;TANIMATION_INFO aniInfo[4]={{ "stand","standby",0,0,0,0,0,0,0,0,0,0},{ "attack","Normal attack",0,0,0,0,0,0,0,0,0,0},{ "squat","Morale attack",0,0,0,0,0,0,0,0,0,0},{ "attacked","under attack",0,0,0,0,0,0,0,0,0,0}};strcpy(DirSpec,packsDir);int rlen = strlen(DirSpec);if(DirSpec[rlen -1]=='\\'){DirSpec[rlen-1]='\0';}strcpy(DirBase,DirSpec);char *last = strrchr(DirBase,'\\');strcpy(npc_name,last+1);char szCurPath[MAX_PATH];GetCurrentDirectoryA(MAX_PATH,szCurPath);unsigned int currentRowHeight = 0;unsigned int output_width=0;unsigned int output_height=0;for(int n=0;n<4;n++){strcpy(DirSpec,DirBase);strcat(DirSpec,"\\序列\\");strcat(DirSpec,aniInfo[n].actionDir);SetCurrentDirectoryA(DirSpec);strcat(DirSpec,"\\*.png");aniInfo[n].filelist = new TPNG_SRC_FILE_LIST();TPNG_SRC_FILE_LIST &filelist = *aniInfo[n].filelist;hFind = FindFirstFileA(DirSpec, &FindFileData);if (hFind != INVALID_HANDLE_VALUE) {while (FindNextFileA(hFind, &FindFileData) != 0) {filelist.push_back(new PNG_SRC_FILE(FindFileData.cFileName));}dwError = GetLastError();FindClose(hFind);}if(filelist.empty()){continue;}filelist.sort(filename_sort);//剪切//unsigned int minTop    =0 ;unsigned int maxBottom =0 ;unsigned int minLeft   =0 ;unsigned int maxRight  =0 ;for(TPNG_SRC_FILE_LIST_ITER  iter = filelist.begin(); iter !=filelist.end(); iter++){png_structp png_ptr=NULL;png_infop info_ptr=NULL;png_infop end_info_ptr=NULL;/* open the file */FILE *fp = fopen((*iter)->filename.c_str(), "rb");if (fp == NULL)return ;png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,NULL, NULL, NULL);info_ptr = png_create_info_struct(png_ptr);end_info_ptr = png_create_info_struct(png_ptr);png_init_io(png_ptr, fp);png_read_info(png_ptr,info_ptr);png_bytep dibbytes = new png_byte[info_ptr->width * info_ptr->height * 4];(*iter)->bmp = dibbytes ;(*iter)->rawWidth = info_ptr->width;(*iter)->rawHeight = info_ptr->height;for(int y=0;y<info_ptr->height;y++){png_bytep pdest = dibbytes + y*info_ptr->width*4;png_read_row(png_ptr,pdest,NULL);}TRECTANGLE cut = cutTransparent(dibbytes,info_ptr->width,info_ptr->height);if(minTop==0 || minTop> cut.top){minTop = cut.top;}if(minLeft==0 || minLeft> cut.left){minLeft = cut.left;}if(maxRight < cut.right){maxRight = cut.right;}if(maxBottom < cut.bottom){maxBottom  = cut.bottom;}png_destroy_read_struct(&png_ptr,&info_ptr,&end_info_ptr);fclose(fp);}aniInfo[n].fps = 10;aniInfo[n].frameWidth = maxRight - minLeft;aniInfo[n].frameHeight  = maxBottom-minTop;aniInfo[n].totalFrame= filelist.size();aniInfo[n].rowHeight = currentRowHeight;aniInfo[n].minTop     =minTop     ;aniInfo[n].maxBottom  =maxBottom  ;aniInfo[n].minLeft    =minLeft    ;aniInfo[n].maxRight   =maxRight   ;currentRowHeight += aniInfo[n].frameHeight;if(output_width  < aniInfo[n].frameWidth * aniInfo[n].totalFrame){output_width   = aniInfo[n].frameWidth * aniInfo[n].totalFrame;}output_height = currentRowHeight;}EnsureVectorSize(s_srcDibBitsBuffer, output_height * output_width * 4);png_bytep  bigmap = &s_srcDibBitsBuffer[0];currentRowHeight = 0;std::string xml;const char *headline_fmt =  "<SWFLoader isBattle=\"true\" name=\"%s\" url=\"assets/soldiers/%s.swf\" load=\"false\">\n";const char *actionline_fmt =  "  <action name=\"%s\" rowHeight=\"%d\" frameWidth=\"%d\" frameHeight=\"%d\" fps=\"120\" totalFrame=\"%d\" attackFrame=\"0\" attackedFrame=\"0\" isRight=\"true\" offsetX=\"115\" offsetY=\"-268\"/>\n";const char *endline_fmt =  "</SWFLoader>\n";sprintf(DirSpec,headline_fmt,npc_name,npc_name);xml = DirSpec;for(int n=0;n<4;n++){TPNG_SRC_FILE_LIST &filelist = *aniInfo[n].filelist;if(filelist.empty()){continue;}sprintf(DirSpec,actionline_fmt,aniInfo[n].actionName,aniInfo[n].rowHeight,aniInfo[n].frameWidth,aniInfo[n].frameHeight,aniInfo[n].totalFrame);xml +=DirSpec;int curCol= 0;for(TPNG_SRC_FILE_LIST_ITER   iter = filelist.begin(); iter !=filelist.end(); iter++){int yy = 0;for(int y=aniInfo[n].minTop;y<aniInfo[n].maxBottom;y++){int xx = 0;for(int x=aniInfo[n].minLeft;x<aniInfo[n].maxRight;x++){unsigned int* psrc = (unsigned int*)((*iter)->bmp + y*(*iter)->rawWidth *4+ x*4);int dx =  curCol * aniInfo[n].frameWidth  +  xx;int dy =  currentRowHeight +yy;unsigned int* dest = (unsigned int*)(bigmap + dy * output_width * 4 + dx*4);xx++;*dest = *psrc;}yy ++;}curCol ++;PNG_SRC_FILE * f = *iter;delete f;}delete aniInfo[n].filelist;currentRowHeight += aniInfo[n].frameHeight;}xml += endline_fmt;SetCurrentDirectoryA(szCurPath);strcpy(filename_dest,outputDir);if(outputDir[strlen(outputDir)-1]!='\\')strcat(filename_dest,"\\");strcat(filename_dest,npc_name);strcat(filename_dest,".png");outputToPngFileNormal(filename_dest,4*output_width * output_height, &s_srcDibBitsBuffer[0],output_width,output_height);strcpy(filename_dest,outputDir);if(outputDir[strlen(outputDir)-1]!='\\')strcat(filename_dest,"\\");strcat(filename_dest,"AnimationConfig.xml");FILE *xmlFile = fopen(filename_dest,"a");if(xmlFile==NULL){return ;}fwrite(xml.c_str(),1,xml.length(),xmlFile);fclose(xmlFile);}void print_uasge(){printf("USEAGE:\n""   pngconcat  x:\\path\\to\\yournpcdirectory x:\\path\\to\\output \n""EXAMPLE:\n""   pngconcat  D:\\hero_xxxxxx D:\\temp \n");}int checkDir(const char * szdir){ struct _stat buf;   int result;   char timebuf[26];   const char* filename = szdir;   errno_t err;   // Get data associated with "crt_stat.c":    result = _stat( filename, &buf );   // Check if statistics are valid:    if( result != 0 )   {      perror( "Problem getting information" );      switch (errno)      {         case ENOENT:           printf("File %s not found.\n", filename);           break;         case EINVAL:           printf("Invalid parameter to _stat.\n");           break;         default:           /* Should never be reached. */           printf("Unexpected error in _stat.\n");      }  return -1;   }   else   {   if( (buf.st_mode & _S_IFDIR)==0)   {     printf("input %s is not a directory.\n", filename); return -1;   }   }   return 0;}int _tmain(int argc, _TCHAR* argv[]){if(argc != 3 || checkDir(argv[1])  || checkDir(argv[2]) ){print_uasge();return -1;}concat(argv[1],argv[2]);return 0;}


 

原创粉丝点击