用到的数据结构如下:
cpp文件如下:
测试代码如下:
以下是合并图片的测试效果:
合并的每一张小图片是从一张合照里剪切下来的,每张小图片的大小是不一样的,而且是未知的。从效果可以看得出,该算法尽可能地将图片挤在一起,但也还有待改进之处。
- //一个方框
- structRectItem
- {
- unsignedintx;//方框在合并后的图片的x坐标
- unsignedinty;//方框在合并后的图片的y坐标
- unsignedintwidth;//方框的宽
- unsignedintheight;//方框的高
- };
- //一张图片
- structImageItem
- {
- unsignedintid;//图片item的ID
- unsignedintx;//图片item在合并后的图片的x坐标
- unsignedinty;//图片item在合并后的图片的y坐标
- charfilename[256];//图片名字
- BITMAPbmp;//BITMAP结构,只用于到高宽
- HBITMAPhbmp;//图片handle,借用windowsAPI合并图片
- };
- //图片列表
- classImageList
- {
- public:
- voidInsert(CStringstrPath);
- ImageList();
- ~ImageList();
- intGetMaxHeight();
- intGetMaxWidth();
- BOOLmerge(CStringoutfile);//生成合并后的图片
- voidInitFromStringArray(CString*pStr,intcount);
- voidLoadFromIni(CStringstrPath);
- voidSaveToIni(CStringstrPath);
- intGetImageCount();
- ImageItemimages[128];//待合并的图片数组
- private:
- voidMyBitBlt(intindex);//计算出images[index]在合并后图片的坐标
- voidDeleteRectItem(intindex);
- voidInsertRectItem(RectItem*item);
- voidclean();
- RectItemrects[256];//合并时产生的空隙(方框)数组
- intmerge_image_width;//合并后图片的宽,实际上是等于要合并的图片中宽最大的图片的宽
- intmerge_image_height;//合并后图片的高
- intm_imageCount;//待合并的图片数
- intm_rectCount;//空隙(方框)方框数
- };
- externImageListGlobalImageList;
- ImageList::ImageList()
- {
- memset(images,0,sizeof(images));
- memset(rects,0,sizeof(rects));
- m_imageCount=0;
- m_rectCount=0;
- merge_image_width=0;
- merge_image_height=0;
- }
- ImageList::~ImageList()
- {
- clean();
- }
- intImageList::GetImageCount()
- {
- returnm_imageCount;
- }
- voidImageList::Insert(CStringstrPath)
- {
- ImageItemitem;
- item.hbmp=(HBITMAP)LoadImage(AfxGetInstanceHandle(),
- (LPCTSTR)strPath,
- IMAGE_BITMAP,
- 0,
- 0,
- LR_LOADFROMFILE);
- if(item.hbmp==NULL)
- {
- CStringstr;
- str.Format("无法打开指定的图片:%s",strPath);
- AfxMessageBox(str);
- }else
- {
- GetObject(item.hbmp,sizeof(BITMAP),&item.bmp);
- }
- //memset(images[m_imageCount].filename,0,sizeof(images[m_imageCount].filename);
- strcpy(item.filename,strPath.GetBuffer(strPath.GetLength()));
- //对images进行排序
- for(inti=0;i<m_imageCount;i++)
- {
- if(item.bmp.bmWidth>images[i].bmp.bmWidth)
- break;
- if(item.bmp.bmWidth==images[i].bmp.bmWidth&&item.bmp.bmHeight>images[i].bmp.bmHeight)
- break;
- }
- for(intj=m_imageCount;j>i;j--)
- {
- memcpy(&images[j],&images[j-1],sizeof(ImageItem));
- }
- memcpy(&images[i],&item,sizeof(ImageItem));
- m_imageCount++;
- //设置ID
- for(i=0;i<m_imageCount;i++)
- {
- images[i].id=i+1;
- }
- }
- BOOLImageList::merge(CStringoutfile)
- {
- merge_image_width=GetMaxWidth();
- for(inti=0;i<m_imageCount;i++)
- {
- MyBitBlt(i);
- }
- unsignedintwidth=merge_image_width;
- unsignedintheight=merge_image_height;
- HDCimgDC=CreateCompatibleDC(NULL);
- VOID*pbits32;
- HBITMAPholdBmp,hbm32;
- BITMAPFILEHEADERhdr;
- BITMAPINFOHEADERbmi;
- unsignedchar*buffer;
- HANDLEhFile;
- intLineDataBytes=width*4;
- intZero=(4-((width*3)%4))%4;
- intTotalDataBytes=(width*3+Zero)*height;
- BOOLresult=FALSE;
- if(width<=0||height<=0)
- returnFALSE;
- hdr.bfType=((WORD)('M'<<8)|'B');//"BM"
- hdr.bfReserved1=0;
- hdr.bfReserved2=0;
- hdr.bfOffBits=(DWORD)(sizeof(hdr)+sizeof(bmi));
- hdr.bfSize=(width*3+Zero)*height+hdr.bfOffBits;
- bmi.biSize=sizeof(BITMAPINFOHEADER);
- bmi.biWidth=width;
- bmi.biHeight=height;
- bmi.biPlanes=1;
- bmi.biBitCount=24;
- bmi.biCompression=BI_RGB;
- bmi.biSizeImage=0;
- bmi.biXPelsPerMeter=0;
- bmi.biYPelsPerMeter=0;
- bmi.biClrUsed=0;
- bmi.biClrImportant=0;
- hFile=CreateFile(outfile,GENERIC_WRITE,FILE_SHARE_WRITE,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
- if(INVALID_HANDLE_VALUE!=hFile)
- {
- DWORDbw;
- WriteFile(hFile,(LPSTR)&hdr,sizeof(hdr),&bw,NULL);
- WriteFile(hFile,(LPSTR)&bmi,sizeof(bmi),&bw,NULL);
- bmi.biBitCount=32;
- if(hbm32=CreateDIBSection(imgDC,(BITMAPINFO*)&bmi,DIB_RGB_COLORS,&pbits32,NULL,0))
- {
- BYTE*p32=(BYTE*)pbits32;
- LONG*p;
- unsignedinti,j,h=0;
- buffer=(unsignedchar*)malloc(TotalDataBytes);
- holdBmp=(HBITMAP)SelectObject(imgDC,hbm32);
- //TODO:将这些数据都变成局部变量
- for(i=0;i<m_imageCount;i++)
- {
- HDChdc=CreateCompatibleDC(NULL);
- HBITMAPhOldBmp=(HBITMAP)SelectObject(hdc,images[i].hbmp);
- BitBlt(imgDC,images[i].x,images[i].y,images[i].bmp.bmWidth,images[i].bmp.bmHeight,hdc,0,0,SRCCOPY);
- //DeleteObject(SelectObject(hdc,hOldBmp));
- DeleteDC(hdc);
- }
- for(i=0;i<height;i++)
- {
- for(j=0;j<width;j++)
- {
- p=(LONG*)p32+j;
- buffer[h]=GetRValue(*p);
- buffer[h+1]=GetGValue(*p);
- buffer[h+2]=GetBValue(*p);
- h+=3;
- }
- if(Zero)h+=Zero;
- p32+=LineDataBytes;
- }
- WriteFile(hFile,(LPSTR)buffer,TotalDataBytes,&bw,NULL);
- DeleteObject(SelectObject(imgDC,holdBmp));
- free(buffer);
- result=TRUE;
- }
- CloseHandle(hFile);
- }
- DeleteDC(imgDC);
- returnresult;
- }
- voidImageList::clean()
- {
- for(inti=0;i<m_imageCount;i++)
- {
- DeleteObject(images[i].hbmp);
- images[i].hbmp=NULL;
- }
- memset(images,0,sizeof(images));
- memset(rects,0,sizeof(rects));
- m_imageCount=0;
- m_rectCount=0;
- merge_image_width=0;
- merge_image_height=0;
- }
- intImageList::GetMaxHeight()
- {
- intheight=0;
- for(inti=0;i<m_imageCount;i++)
- {
- if(height<images[i].bmp.bmHeight)
- {
- height=images[i].bmp.bmHeight;
- }
- }
- returnheight;
- }
- intImageList::GetMaxWidth()
- {
- intwidth=0;
- for(inti=0;i<m_imageCount;i++)
- {
- if(width<images[i].bmp.bmWidth)
- {
- width=images[i].bmp.bmWidth;
- }
- }
- returnwidth;
- }
- voidImageList::SaveToIni(CStringstrPath)
- {
- CStringsessionName="Bitmap";
- charkey[64];
- charvalue[1024];
- memset(value,0,sizeof(value));
- sprintf(value,"%i",m_imageCount);
- WritePrivateProfileString(sessionName,"count",value,strPath);
- for(inti=0;i<m_imageCount;i++)
- {
- memset(key,0,sizeof(key));
- sprintf(key,"bmp%d",i);
- memset(value,0,sizeof(value));
- WritePrivateProfileString(sessionName,key,images[i].filename,strPath);
- }
- }
- voidImageList::LoadFromIni(CStringstrPath)
- {
- CStringsessionName="Bitmap";
- charkey[64];
- charvalue[1024];
- CStringfilePath[100];
- intfileCount=0;
- //读取bmp文件的个数
- memset(value,0,sizeof(value));
- GetPrivateProfileString(sessionName,"count","",value,sizeof(value),strPath);
- sscanf(value,"%i",&fileCount);
- //将每个路径依次存到数据里
- for(inti=0;i<fileCount;i++)
- {
- memset(key,0,sizeof(key));
- sprintf(key,"bmp%d",i);
- memset(value,0,sizeof(value));
- GetPrivateProfileString(sessionName,key,"",value,sizeof(value),strPath);
- filePath[i].Format(value);
- }
- //根据CString数组初始化imagelist
- InitFromStringArray(filePath,fileCount);
- }
- voidImageList::InitFromStringArray(CString*pStr,intcount)
- {
- clean();
- for(inti=0;i<count;i++,pStr++)
- {
- Insert(*pStr);
- }
- }
- voidImageList::MyBitBlt(intimage_index)
- {
- inti;
- searchproper:
- for(i=0;i<m_rectCount;i++)
- {
- //rect和image一样大小,设置image的坐标,并将删除rects中的一项
- if(images[image_index].bmp.bmWidth==rects[i].width&&
- images[image_index].bmp.bmHeight==rects[i].height)
- {
- images[image_index].x=rects[i].x;
- images[image_index].y=rects[i].y;
- DeleteRectItem(i);
- return;
- }
- //rect和image的宽一样大小,高rect更大
- if(images[image_index].bmp.bmWidth==rects[i].width&&
- images[image_index].bmp.bmHeight<rects[i].height)
- {
- images[image_index].x=rects[i].x;
- images[image_index].y=rects[i].y;
- //TODO:checkright
- RectItemtemp;
- temp.height=rects[i].height-images[image_index].bmp.bmHeight;
- temp.width=rects[i].width;
- temp.x=rects[i].x;
- temp.y=rects[i].y+images[image_index].bmp.bmHeight;
- DeleteRectItem(i);
- InsertRectItem(&temp);
- return;
- }
- //rect和image的高一样大小,宽rect更大
- if(images[image_index].bmp.bmWidth<rects[i].width&&
- images[image_index].bmp.bmHeight==rects[i].height)
- {
- images[image_index].x=rects[i].x;
- images[image_index].y=rects[i].y;
- RectItemtemp;
- temp.height=rects[i].height;
- temp.width=rects[i].width-images[image_index].bmp.bmWidth;
- temp.x=rects[i].x+images[image_index].bmp.bmWidth;
- temp.y=rects[i].y;
- DeleteRectItem(i);
- InsertRectItem(&temp);
- return;
- }
- //rect比image高和宽都大
- if(images[image_index].bmp.bmWidth<rects[i].width&&
- images[image_index].bmp.bmHeight<rects[i].height)
- {
- images[image_index].x=rects[i].x;
- images[image_index].y=rects[i].y;
- RectItemtemp1;
- temp1.height=images[image_index].bmp.bmHeight;
- temp1.width=rects[i].width-images[image_index].bmp.bmWidth;
- temp1.x=rects[i].x+images[image_index].bmp.bmWidth;
- temp1.y=rects[i].y;
- RectItemtemp2;
- temp2.height=rects[i].height-images[image_index].bmp.bmHeight;
- temp2.width=rects[i].width;
- temp2.x=rects[i].x;
- temp2.y=rects[i].y+images[image_index].bmp.bmHeight;
- DeleteRectItem(i);
- InsertRectItem(&temp1);
- InsertRectItem(&temp2);
- return;
- }
- }
- //找不到合适的rect,就新建一项,并将其插入合适的地方
- RectItemnew_item;
- new_item.height=images[image_index].bmp.bmHeight;
- new_item.width=merge_image_width;
- new_item.x=0;
- new_item.y=merge_image_height;
- merge_image_height+=new_item.height;
- InsertRectItem(&new_item);
- gotosearchproper;
- }
- voidImageList::DeleteRectItem(intindex)
- {
- for(inti=index;i<m_rectCount;i++)
- {
- memcpy(&rects[i],&rects[i+1],sizeof(RectItem));
- }
- m_rectCount--;
- }
- voidImageList::InsertRectItem(RectItem*item)
- {
- inti,j;
- //找到该插入的位置,将其存到i
- for(i=0;i<m_rectCount;i++)
- {
- if(item->width<rects[i].width)
- {
- break;
- }
- if(item->width==rects[i].width&&
- item->height<rects[i].height)
- {
- break;
- }
- }
- //插入
- for(j=m_rectCount-1;j>=i;j--)
- {
- memcpy(&rects[j+1],&rects[j],sizeof(RectItem));
- }
- memcpy(&rects[i],item,sizeof(RectItem));
- m_rectCount++;
- }
- CFileDialogfileDlg(TRUE,
- NULL,
- NULL,
- OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT|OFN_ALLOWMULTISELECT,
- "bmp文件(*.bmp)|*.bmp||",
- NULL);
- fileDlg.m_ofn.lpstrFile=newTCHAR[MAX_PATH*100];//最多允许100个文件
- fileDlg.m_ofn.nMaxFile=100*MAX_PATH;
- ZeroMemory(fileDlg.m_ofn.lpstrFile,sizeof(TCHAR)*fileDlg.m_ofn.nMaxFile);
- if(fileDlg.DoModal()!=IDOK)return;
- //TODO:initbmpinidata
- CStringfilePath[100];
- //获取图片路径
- POSITIONpos=fileDlg.GetStartPosition();
- intfileCount;
- for(fileCount=0;pos!=0;fileCount++)
- {
- CStringfile=fileDlg.GetNextPathName(pos);
- if(file.Find(".bmp")==-1)
- {
- AfxMessageBox("非bmp文件,程序退出。");
- exit(1);
- }
- filePath[fileCount]=file;
- }
- GlobalImageList.InitFromStringArray(filePath,fileCount);
- GlobalImageList.merge("merge.bmp");
合并的每一张小图片是从一张合照里剪切下来的,每张小图片的大小是不一样的,而且是未知的。从效果可以看得出,该算法尽可能地将图片挤在一起,但也还有待改进之处。