bmp图片合并算法

用到的数据结构如下:
  1. //一个方框
  2. structRectItem
  3. {
  4. unsignedintx;//方框在合并后的图片的x坐标
  5. unsignedinty;//方框在合并后的图片的y坐标
  6. unsignedintwidth;//方框的宽
  7. unsignedintheight;//方框的高
  8. };
  9. //一张图片
  10. structImageItem
  11. {
  12. unsignedintid;//图片item的ID
  13. unsignedintx;//图片item在合并后的图片的x坐标
  14. unsignedinty;//图片item在合并后的图片的y坐标
  15. charfilename[256];//图片名字
  16. BITMAPbmp;//BITMAP结构,只用于到高宽
  17. HBITMAPhbmp;//图片handle,借用windowsAPI合并图片
  18. };
  19. //图片列表
  20. classImageList
  21. {
  22. public:
  23. voidInsert(CStringstrPath);
  24. ImageList();
  25. ~ImageList();
  26. intGetMaxHeight();
  27. intGetMaxWidth();
  28. BOOLmerge(CStringoutfile);//生成合并后的图片
  29. voidInitFromStringArray(CString*pStr,intcount);
  30. voidLoadFromIni(CStringstrPath);
  31. voidSaveToIni(CStringstrPath);
  32. intGetImageCount();
  33. ImageItemimages[128];//待合并的图片数组
  34. private:
  35. voidMyBitBlt(intindex);//计算出images[index]在合并后图片的坐标
  36. voidDeleteRectItem(intindex);
  37. voidInsertRectItem(RectItem*item);
  38. voidclean();
  39. RectItemrects[256];//合并时产生的空隙(方框)数组
  40. intmerge_image_width;//合并后图片的宽,实际上是等于要合并的图片中宽最大的图片的宽
  41. intmerge_image_height;//合并后图片的高
  42. intm_imageCount;//待合并的图片数
  43. intm_rectCount;//空隙(方框)方框数
  44. };
  45. externImageListGlobalImageList;
cpp文件如下:
  1. ImageList::ImageList()
  2. {
  3. memset(images,0,sizeof(images));
  4. memset(rects,0,sizeof(rects));
  5. m_imageCount=0;
  6. m_rectCount=0;
  7. merge_image_width=0;
  8. merge_image_height=0;
  9. }
  10. ImageList::~ImageList()
  11. {
  12. clean();
  13. }
  14. intImageList::GetImageCount()
  15. {
  16. returnm_imageCount;
  17. }
  18. voidImageList::Insert(CStringstrPath)
  19. {
  20. ImageItemitem;
  21. item.hbmp=(HBITMAP)LoadImage(AfxGetInstanceHandle(),
  22. (LPCTSTR)strPath,
  23. IMAGE_BITMAP,
  24. 0,
  25. 0,
  26. LR_LOADFROMFILE);
  27. if(item.hbmp==NULL)
  28. {
  29. CStringstr;
  30. str.Format("无法打开指定的图片:%s",strPath);
  31. AfxMessageBox(str);
  32. }else
  33. {
  34. GetObject(item.hbmp,sizeof(BITMAP),&item.bmp);
  35. }
  36. //memset(images[m_imageCount].filename,0,sizeof(images[m_imageCount].filename);
  37. strcpy(item.filename,strPath.GetBuffer(strPath.GetLength()));
  38. //对images进行排序
  39. for(inti=0;i<m_imageCount;i++)
  40. {
  41. if(item.bmp.bmWidth>images[i].bmp.bmWidth)
  42. break;
  43. if(item.bmp.bmWidth==images[i].bmp.bmWidth&&item.bmp.bmHeight>images[i].bmp.bmHeight)
  44. break;
  45. }
  46. for(intj=m_imageCount;j>i;j--)
  47. {
  48. memcpy(&images[j],&images[j-1],sizeof(ImageItem));
  49. }
  50. memcpy(&images[i],&item,sizeof(ImageItem));
  51. m_imageCount++;
  52. //设置ID
  53. for(i=0;i<m_imageCount;i++)
  54. {
  55. images[i].id=i+1;
  56. }
  57. }
  58. BOOLImageList::merge(CStringoutfile)
  59. {
  60. merge_image_width=GetMaxWidth();
  61. for(inti=0;i<m_imageCount;i++)
  62. {
  63. MyBitBlt(i);
  64. }
  65. unsignedintwidth=merge_image_width;
  66. unsignedintheight=merge_image_height;
  67. HDCimgDC=CreateCompatibleDC(NULL);
  68. VOID*pbits32;
  69. HBITMAPholdBmp,hbm32;
  70. BITMAPFILEHEADERhdr;
  71. BITMAPINFOHEADERbmi;
  72. unsignedchar*buffer;
  73. HANDLEhFile;
  74. intLineDataBytes=width*4;
  75. intZero=(4-((width*3)%4))%4;
  76. intTotalDataBytes=(width*3+Zero)*height;
  77. BOOLresult=FALSE;
  78. if(width<=0||height<=0)
  79. returnFALSE;
  80. hdr.bfType=((WORD)('M'<<8)|'B');//"BM"
  81. hdr.bfReserved1=0;
  82. hdr.bfReserved2=0;
  83. hdr.bfOffBits=(DWORD)(sizeof(hdr)+sizeof(bmi));
  84. hdr.bfSize=(width*3+Zero)*height+hdr.bfOffBits;
  85. bmi.biSize=sizeof(BITMAPINFOHEADER);
  86. bmi.biWidth=width;
  87. bmi.biHeight=height;
  88. bmi.biPlanes=1;
  89. bmi.biBitCount=24;
  90. bmi.biCompression=BI_RGB;
  91. bmi.biSizeImage=0;
  92. bmi.biXPelsPerMeter=0;
  93. bmi.biYPelsPerMeter=0;
  94. bmi.biClrUsed=0;
  95. bmi.biClrImportant=0;
  96. hFile=CreateFile(outfile,GENERIC_WRITE,FILE_SHARE_WRITE,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
  97. if(INVALID_HANDLE_VALUE!=hFile)
  98. {
  99. DWORDbw;
  100. WriteFile(hFile,(LPSTR)&hdr,sizeof(hdr),&bw,NULL);
  101. WriteFile(hFile,(LPSTR)&bmi,sizeof(bmi),&bw,NULL);
  102. bmi.biBitCount=32;
  103. if(hbm32=CreateDIBSection(imgDC,(BITMAPINFO*)&bmi,DIB_RGB_COLORS,&pbits32,NULL,0))
  104. {
  105. BYTE*p32=(BYTE*)pbits32;
  106. LONG*p;
  107. unsignedinti,j,h=0;
  108. buffer=(unsignedchar*)malloc(TotalDataBytes);
  109. holdBmp=(HBITMAP)SelectObject(imgDC,hbm32);
  110. //TODO:将这些数据都变成局部变量
  111. for(i=0;i<m_imageCount;i++)
  112. {
  113. HDChdc=CreateCompatibleDC(NULL);
  114. HBITMAPhOldBmp=(HBITMAP)SelectObject(hdc,images[i].hbmp);
  115. BitBlt(imgDC,images[i].x,images[i].y,images[i].bmp.bmWidth,images[i].bmp.bmHeight,hdc,0,0,SRCCOPY);
  116. //DeleteObject(SelectObject(hdc,hOldBmp));
  117. DeleteDC(hdc);
  118. }
  119. for(i=0;i<height;i++)
  120. {
  121. for(j=0;j<width;j++)
  122. {
  123. p=(LONG*)p32+j;
  124. buffer[h]=GetRValue(*p);
  125. buffer[h+1]=GetGValue(*p);
  126. buffer[h+2]=GetBValue(*p);
  127. h+=3;
  128. }
  129. if(Zero)h+=Zero;
  130. p32+=LineDataBytes;
  131. }
  132. WriteFile(hFile,(LPSTR)buffer,TotalDataBytes,&bw,NULL);
  133. DeleteObject(SelectObject(imgDC,holdBmp));
  134. free(buffer);
  135. result=TRUE;
  136. }
  137. CloseHandle(hFile);
  138. }
  139. DeleteDC(imgDC);
  140. returnresult;
  141. }
  142. voidImageList::clean()
  143. {
  144. for(inti=0;i<m_imageCount;i++)
  145. {
  146. DeleteObject(images[i].hbmp);
  147. images[i].hbmp=NULL;
  148. }
  149. memset(images,0,sizeof(images));
  150. memset(rects,0,sizeof(rects));
  151. m_imageCount=0;
  152. m_rectCount=0;
  153. merge_image_width=0;
  154. merge_image_height=0;
  155. }
  156. intImageList::GetMaxHeight()
  157. {
  158. intheight=0;
  159. for(inti=0;i<m_imageCount;i++)
  160. {
  161. if(height<images[i].bmp.bmHeight)
  162. {
  163. height=images[i].bmp.bmHeight;
  164. }
  165. }
  166. returnheight;
  167. }
  168. intImageList::GetMaxWidth()
  169. {
  170. intwidth=0;
  171. for(inti=0;i<m_imageCount;i++)
  172. {
  173. if(width<images[i].bmp.bmWidth)
  174. {
  175. width=images[i].bmp.bmWidth;
  176. }
  177. }
  178. returnwidth;
  179. }
  180. voidImageList::SaveToIni(CStringstrPath)
  181. {
  182. CStringsessionName="Bitmap";
  183. charkey[64];
  184. charvalue[1024];
  185. memset(value,0,sizeof(value));
  186. sprintf(value,"%i",m_imageCount);
  187. WritePrivateProfileString(sessionName,"count",value,strPath);
  188. for(inti=0;i<m_imageCount;i++)
  189. {
  190. memset(key,0,sizeof(key));
  191. sprintf(key,"bmp%d",i);
  192. memset(value,0,sizeof(value));
  193. WritePrivateProfileString(sessionName,key,images[i].filename,strPath);
  194. }
  195. }
  196. voidImageList::LoadFromIni(CStringstrPath)
  197. {
  198. CStringsessionName="Bitmap";
  199. charkey[64];
  200. charvalue[1024];
  201. CStringfilePath[100];
  202. intfileCount=0;
  203. //读取bmp文件的个数
  204. memset(value,0,sizeof(value));
  205. GetPrivateProfileString(sessionName,"count","",value,sizeof(value),strPath);
  206. sscanf(value,"%i",&fileCount);
  207. //将每个路径依次存到数据里
  208. for(inti=0;i<fileCount;i++)
  209. {
  210. memset(key,0,sizeof(key));
  211. sprintf(key,"bmp%d",i);
  212. memset(value,0,sizeof(value));
  213. GetPrivateProfileString(sessionName,key,"",value,sizeof(value),strPath);
  214. filePath[i].Format(value);
  215. }
  216. //根据CString数组初始化imagelist
  217. InitFromStringArray(filePath,fileCount);
  218. }
  219. voidImageList::InitFromStringArray(CString*pStr,intcount)
  220. {
  221. clean();
  222. for(inti=0;i<count;i++,pStr++)
  223. {
  224. Insert(*pStr);
  225. }
  226. }
  227. voidImageList::MyBitBlt(intimage_index)
  228. {
  229. inti;
  230. searchproper:
  231. for(i=0;i<m_rectCount;i++)
  232. {
  233. //rect和image一样大小,设置image的坐标,并将删除rects中的一项
  234. if(images[image_index].bmp.bmWidth==rects[i].width&&
  235. images[image_index].bmp.bmHeight==rects[i].height)
  236. {
  237. images[image_index].x=rects[i].x;
  238. images[image_index].y=rects[i].y;
  239. DeleteRectItem(i);
  240. return;
  241. }
  242. //rect和image的宽一样大小,高rect更大
  243. if(images[image_index].bmp.bmWidth==rects[i].width&&
  244. images[image_index].bmp.bmHeight<rects[i].height)
  245. {
  246. images[image_index].x=rects[i].x;
  247. images[image_index].y=rects[i].y;
  248. //TODO:checkright
  249. RectItemtemp;
  250. temp.height=rects[i].height-images[image_index].bmp.bmHeight;
  251. temp.width=rects[i].width;
  252. temp.x=rects[i].x;
  253. temp.y=rects[i].y+images[image_index].bmp.bmHeight;
  254. DeleteRectItem(i);
  255. InsertRectItem(&temp);
  256. return;
  257. }
  258. //rect和image的高一样大小,宽rect更大
  259. if(images[image_index].bmp.bmWidth<rects[i].width&&
  260. images[image_index].bmp.bmHeight==rects[i].height)
  261. {
  262. images[image_index].x=rects[i].x;
  263. images[image_index].y=rects[i].y;
  264. RectItemtemp;
  265. temp.height=rects[i].height;
  266. temp.width=rects[i].width-images[image_index].bmp.bmWidth;
  267. temp.x=rects[i].x+images[image_index].bmp.bmWidth;
  268. temp.y=rects[i].y;
  269. DeleteRectItem(i);
  270. InsertRectItem(&temp);
  271. return;
  272. }
  273. //rect比image高和宽都大
  274. if(images[image_index].bmp.bmWidth<rects[i].width&&
  275. images[image_index].bmp.bmHeight<rects[i].height)
  276. {
  277. images[image_index].x=rects[i].x;
  278. images[image_index].y=rects[i].y;
  279. RectItemtemp1;
  280. temp1.height=images[image_index].bmp.bmHeight;
  281. temp1.width=rects[i].width-images[image_index].bmp.bmWidth;
  282. temp1.x=rects[i].x+images[image_index].bmp.bmWidth;
  283. temp1.y=rects[i].y;
  284. RectItemtemp2;
  285. temp2.height=rects[i].height-images[image_index].bmp.bmHeight;
  286. temp2.width=rects[i].width;
  287. temp2.x=rects[i].x;
  288. temp2.y=rects[i].y+images[image_index].bmp.bmHeight;
  289. DeleteRectItem(i);
  290. InsertRectItem(&temp1);
  291. InsertRectItem(&temp2);
  292. return;
  293. }
  294. }
  295. //找不到合适的rect,就新建一项,并将其插入合适的地方
  296. RectItemnew_item;
  297. new_item.height=images[image_index].bmp.bmHeight;
  298. new_item.width=merge_image_width;
  299. new_item.x=0;
  300. new_item.y=merge_image_height;
  301. merge_image_height+=new_item.height;
  302. InsertRectItem(&new_item);
  303. gotosearchproper;
  304. }
  305. voidImageList::DeleteRectItem(intindex)
  306. {
  307. for(inti=index;i<m_rectCount;i++)
  308. {
  309. memcpy(&rects[i],&rects[i+1],sizeof(RectItem));
  310. }
  311. m_rectCount--;
  312. }
  313. voidImageList::InsertRectItem(RectItem*item)
  314. {
  315. inti,j;
  316. //找到该插入的位置,将其存到i
  317. for(i=0;i<m_rectCount;i++)
  318. {
  319. if(item->width<rects[i].width)
  320. {
  321. break;
  322. }
  323. if(item->width==rects[i].width&&
  324. item->height<rects[i].height)
  325. {
  326. break;
  327. }
  328. }
  329. //插入
  330. for(j=m_rectCount-1;j>=i;j--)
  331. {
  332. memcpy(&rects[j+1],&rects[j],sizeof(RectItem));
  333. }
  334. memcpy(&rects[i],item,sizeof(RectItem));
  335. m_rectCount++;
  336. }
测试代码如下:
  1. CFileDialogfileDlg(TRUE,
  2. NULL,
  3. NULL,
  4. OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT|OFN_ALLOWMULTISELECT,
  5. "bmp文件(*.bmp)|*.bmp||",
  6. NULL);
  7. fileDlg.m_ofn.lpstrFile=newTCHAR[MAX_PATH*100];//最多允许100个文件
  8. fileDlg.m_ofn.nMaxFile=100*MAX_PATH;
  9. ZeroMemory(fileDlg.m_ofn.lpstrFile,sizeof(TCHAR)*fileDlg.m_ofn.nMaxFile);
  10. if(fileDlg.DoModal()!=IDOK)return;
  11. //TODO:initbmpinidata
  12. CStringfilePath[100];
  13. //获取图片路径
  14. POSITIONpos=fileDlg.GetStartPosition();
  15. intfileCount;
  16. for(fileCount=0;pos!=0;fileCount++)
  17. {
  18. CStringfile=fileDlg.GetNextPathName(pos);
  19. if(file.Find(".bmp")==-1)
  20. {
  21. AfxMessageBox("非bmp文件,程序退出。");
  22. exit(1);
  23. }
  24. filePath[fileCount]=file;
  25. }
  26. GlobalImageList.InitFromStringArray(filePath,fileCount);
  27. GlobalImageList.merge("merge.bmp");
以下是合并图片的测试效果:


合并的每一张小图片是从一张合照里剪切下来的,每张小图片的大小是不一样的,而且是未知的。从效果可以看得出,该算法尽可能地将图片挤在一起,但也还有待改进之处。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值