bmp图片合并算法

用到的数据结构如下:
  1. //一个方框
  2. struct RectItem
  3. {
  4.     unsigned int x;           //方框在合并后的图片的x坐标
  5.     unsigned int y;           //方框在合并后的图片的y坐标
  6.     unsigned int width;       //方框的宽
  7.     unsigned int height;      //方框的高
  8. };
  9. //一张图片
  10. struct ImageItem
  11. {
  12.     unsigned int id;          //图片item的ID
  13.     unsigned int x;           //图片item在合并后的图片的x坐标
  14.     unsigned int y;           //图片item在合并后的图片的y坐标
  15.     char filename[256];       //图片名字
  16.     BITMAP bmp;               //BITMAP结构,只用于到高宽
  17.     HBITMAP hbmp;             //图片handle,借用windows API合并图片
  18. };
  19. //图片列表
  20. class ImageList
  21. {
  22. public:
  23.     void Insert(CString strPath);
  24.     ImageList();
  25.     ~ImageList();
  26.     int GetMaxHeight();
  27.     int GetMaxWidth();
  28.     BOOL merge(CString outfile);     //生成合并后的图片
  29.     void InitFromStringArray(CString *pStr, int count);
  30.     void LoadFromIni(CString strPath);
  31.     void SaveToIni(CString strPath);
  32.     int GetImageCount();
  33.     ImageItem images[128];             //待合并的图片数组
  34. private:
  35.     void MyBitBlt(int index);          //计算出images[index]在合并后图片的坐标
  36.     void DeleteRectItem(int index);
  37.     void InsertRectItem( RectItem * item );
  38.     void clean();
  39.     RectItem rects[256];                 //合并时产生的空隙(方框)数组
  40.     int merge_image_width;               //合并后图片的宽,实际上是等于要合并的图片中宽最大的图片的宽
  41.     int merge_image_height;              //合并后图片的高
  42.     int m_imageCount;                    //待合并的图片数
  43.     int m_rectCount;                     //空隙(方框)方框数
  44. };
  45. extern ImageList GlobalImageList;
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. int ImageList::GetImageCount()
  15. {
  16.     return m_imageCount;
  17. }
  18. void ImageList::Insert(CString strPath)
  19. {
  20.     ImageItem item;
  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.         CString str;
  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.     
  39.     //对images进行排序
  40.     for (int i = 0; i < m_imageCount; i++)
  41.     {
  42.         if (item.bmp.bmWidth > images[i].bmp.bmWidth )
  43.             break;
  44.         if (item.bmp.bmWidth == images[i].bmp.bmWidth && item.bmp.bmHeight > images[i].bmp.bmHeight )
  45.             break;
  46.     }
  47.     for (int j = m_imageCount; j > i; j--)
  48.     {
  49.         memcpy(&images[j], &images[j-1], sizeof(ImageItem) );
  50.     }
  51.     memcpy(&images[i], &item, sizeof(ImageItem) );
  52.     m_imageCount++;
  53.     //设置ID
  54.     for (i = 0; i < m_imageCount; i++)
  55.     {
  56.         images[i].id = i + 1;
  57.     }
  58. }
  59. BOOL ImageList::merge(CString outfile)
  60. {
  61.     merge_image_width = GetMaxWidth();
  62.     for (int i = 0; i < m_imageCount; i++)
  63.     {
  64.         MyBitBlt(i);
  65.     }
  66.     
  67.     unsigned int width = merge_image_width;
  68.     unsigned int height = merge_image_height;
  69.     
  70.     HDC   imgDC = CreateCompatibleDC( NULL );
  71.     
  72.     VOID   *   pbits32;
  73.     HBITMAP   holdBmp,hbm32;
  74.     BITMAPFILEHEADER   hdr;
  75.     BITMAPINFOHEADER   bmi;
  76.     unsigned   char*   buffer;  
  77.     HANDLE   hFile;
  78.     int   LineDataBytes=width*4;  
  79.     int   Zero=(4-((width*3)%4))%4;  
  80.     int   TotalDataBytes=(width*3+Zero)*height;
  81.     
  82.     BOOL   result=FALSE;  
  83.     
  84.     if(width<=0   ||   height<=0)  
  85.         return   FALSE;  
  86.     
  87.     hdr.bfType =   ((WORD)   ('M'   <<   8)   |   'B');   //"BM"
  88.     hdr.bfReserved1   =   0;  
  89.     hdr.bfReserved2   =   0;  
  90.     hdr.bfOffBits =   (DWORD)   (sizeof(hdr)+sizeof(bmi));  
  91.     hdr.bfSize =   (width*3+Zero)*height   +   hdr.bfOffBits;
  92.     
  93.     bmi.biSize=sizeof(BITMAPINFOHEADER);  
  94.     bmi.biWidth=width;  
  95.     bmi.biHeight=height;  
  96.     bmi.biPlanes=1;  
  97.     bmi.biBitCount=24;  
  98.     bmi.biCompression=BI_RGB;  
  99.     bmi.biSizeImage=0;  
  100.     bmi.biXPelsPerMeter=0;  
  101.     bmi.biYPelsPerMeter=0;  
  102.     bmi.biClrUsed=0;  
  103.     bmi.biClrImportant=0;  
  104.     hFile=CreateFile(outfile,GENERIC_WRITE,FILE_SHARE_WRITE,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
  105.     if(INVALID_HANDLE_VALUE!=hFile)
  106.     {
  107.         DWORD   bw;
  108.         
  109.         WriteFile(hFile,(LPSTR)&hdr,   sizeof(hdr),&bw,NULL);
  110.         WriteFile(hFile,(LPSTR)&bmi,   sizeof(bmi),&bw,NULL);
  111.         
  112.         
  113.         bmi.biBitCount=32;  
  114.         
  115.         if (hbm32 = CreateDIBSection(imgDC, (BITMAPINFO*)&bmi, DIB_RGB_COLORS, &pbits32, NULL, 0) )  
  116.         {  
  117.             BYTE   *p32   =   (BYTE *)pbits32;  
  118.             LONG   *p;
  119.             unsigned int   i,j,h=0;
  120.             
  121.             buffer=(unsigned   char*)malloc(TotalDataBytes);
  122.             holdBmp = (HBITMAP)SelectObject(imgDC, hbm32);  
  123.             
  124.             //TODO:将这些数据都变成局部变量
  125.             for (i = 0; i < m_imageCount; i++)
  126.             {
  127.                 HDC hdc = CreateCompatibleDC( NULL );
  128.                 HBITMAP hOldBmp = (HBITMAP)SelectObject(hdc, images[i].hbmp);
  129.                 BitBlt(imgDC,   images[i].x,   images[i].y,   images[i].bmp.bmWidth,   images[i].bmp.bmHeight,   hdc,   0,   0,   SRCCOPY); 
  130.                 //DeleteObject(SelectObject(hdc, hOldBmp));
  131.                 DeleteDC(hdc);
  132.             }
  133.             
  134.             for   (i   =   0;i<height;   i++)
  135.             {  
  136.                 for   (j   =   0;j<width;   j++)
  137.                 {  
  138.                     p   =   (LONG   *)p32   +   j;  
  139.                     buffer[h]   =   GetRValue(*p);  
  140.                     buffer[h+1]   =   GetGValue(*p);  
  141.                     buffer[h+2]   =   GetBValue(*p);  
  142.                     h+=3;  
  143.                 }
  144.                 if(Zero)h+=Zero;  
  145.                 p32 += LineDataBytes;  
  146.             }
  147.             WriteFile(hFile,(LPSTR)buffer,   TotalDataBytes,&bw,NULL);
  148.             DeleteObject(SelectObject(imgDC,   holdBmp));
  149.             free(buffer);
  150.             result=TRUE;
  151.         }
  152.         CloseHandle(hFile);  
  153.     }
  154.     
  155.     DeleteDC(imgDC);
  156.     return   result;
  157. }
  158. void ImageList::clean()
  159. {
  160.     for (int i = 0; i < m_imageCount; i++ ) 
  161.     {
  162.         DeleteObject(images[i].hbmp);
  163.         images[i].hbmp = NULL;
  164.     }
  165.     memset( images, 0, sizeof(images) );
  166.     memset( rects, 0, sizeof(rects) );
  167.     m_imageCount = 0;
  168.     m_rectCount = 0;
  169.     merge_image_width = 0;
  170.     merge_image_height = 0;
  171. }
  172. int ImageList::GetMaxHeight()
  173. {
  174.     int height = 0;
  175.     for (int i = 0; i < m_imageCount; i++)
  176.     {
  177.         if (height < images[i].bmp.bmHeight)
  178.         {
  179.             height = images[i].bmp.bmHeight;
  180.         }
  181.     }
  182.     return height;
  183. }
  184. int ImageList::GetMaxWidth()
  185. {
  186.     int width = 0;
  187.     for (int i = 0; i < m_imageCount; i++)
  188.     {
  189.         if (width < images[i].bmp.bmWidth)
  190.         {
  191.             width = images[i].bmp.bmWidth;
  192.         }
  193.     }
  194.     return width;
  195. }
  196. void ImageList::SaveToIni(CString strPath)
  197. {
  198.     CString sessionName = "Bitmap";
  199.     char key[64];
  200.     char value[1024];
  201.     memset(value, 0, sizeof(value));
  202.     sprintf(value, "%i", m_imageCount);
  203.     WritePrivateProfileString(sessionName, "count", value, strPath);
  204.     for ( int i = 0; i < m_imageCount; i++)
  205.     {
  206.         memset(key, 0, sizeof(key));
  207.         sprintf(key, "bmp%d", i);
  208.         
  209.         memset(value, 0, sizeof(value));
  210.         WritePrivateProfileString(sessionName, key, images[i].filename, strPath);   
  211.     }
  212. }
  213. void ImageList::LoadFromIni(CString strPath)
  214. {
  215.     CString sessionName = "Bitmap";
  216.     char key[64];
  217.     char value[1024];
  218.     CString filePath[100];
  219.     int fileCount = 0;
  220.     //读取bmp文件的个数
  221.     memset(value, 0, sizeof(value));
  222.     GetPrivateProfileString( sessionName, "count""", value, sizeof(value), strPath );
  223.     sscanf(value, "%i", &fileCount);
  224.     
  225.     //将每个路径依次存到数据里
  226.     for ( int i = 0; i < fileCount ; i++)
  227.     {
  228.         memset(key, 0, sizeof(key));
  229.         sprintf(key, "bmp%d", i);
  230.         
  231.         memset(value, 0, sizeof(value));
  232.         GetPrivateProfileString( sessionName, key, "", value, sizeof(value), strPath );
  233.         filePath[i].Format(value);
  234.     }
  235.     
  236.     //根据CString数组初始化image list
  237.     InitFromStringArray(filePath, fileCount);
  238. }
  239. void ImageList::InitFromStringArray(CString *pStr, int count)
  240. {
  241.     clean();
  242.     for ( int i = 0; i < count; i++, pStr++ )   
  243.     {
  244.         Insert(*pStr);
  245.     }
  246. }
  247. void ImageList::MyBitBlt(int image_index)
  248. {
  249.     int i;
  250. searchproper:
  251.     for ( i = 0; i < m_rectCount; i++ )
  252.     {
  253.         //rect和image一样大小,设置image的坐标,并将删除rects中的一项
  254.         if ( images[image_index].bmp.bmWidth == rects[i].width &&
  255.              images[image_index].bmp.bmHeight == rects[i].height )
  256.         {
  257.             images[image_index].x = rects[i].x;
  258.             images[image_index].y = rects[i].y;
  259.             DeleteRectItem(i);
  260.             return;
  261.         }
  262.         //rect和image的宽一样大小,高rect更大
  263.         if ( images[image_index].bmp.bmWidth == rects[i].width &&
  264.              images[image_index].bmp.bmHeight < rects[i].height )
  265.         {
  266.             images[image_index].x = rects[i].x;
  267.             images[image_index].y = rects[i].y;
  268.             //TODO: check right
  269.             RectItem temp;
  270.             temp.height = rects[i].height - images[image_index].bmp.bmHeight;
  271.             temp.width = rects[i].width;
  272.             temp.x = rects[i].x;
  273.             temp.y = rects[i].y + images[image_index].bmp.bmHeight;
  274.             DeleteRectItem(i);
  275.             InsertRectItem(&temp);
  276.             return;
  277.         }
  278.         //rect和image的高一样大小,宽rect更大
  279.         if ( images[image_index].bmp.bmWidth < rects[i].width &&
  280.             images[image_index].bmp.bmHeight == rects[i].height )
  281.         {
  282.             images[image_index].x = rects[i].x;
  283.             images[image_index].y = rects[i].y;
  284.             RectItem temp;
  285.             temp.height = rects[i].height;
  286.             temp.width = rects[i].width - images[image_index].bmp.bmWidth;
  287.             temp.x = rects[i].x + images[image_index].bmp.bmWidth;
  288.             temp.y = rects[i].y;
  289.             DeleteRectItem(i);
  290.             InsertRectItem(&temp);
  291.             return;
  292.         }
  293.         //rect比image高和宽都大
  294.         if ( images[image_index].bmp.bmWidth < rects[i].width &&
  295.             images[image_index].bmp.bmHeight < rects[i].height )
  296.         {
  297.             images[image_index].x = rects[i].x;
  298.             images[image_index].y = rects[i].y;
  299.             RectItem temp1;
  300.             temp1.height = images[image_index].bmp.bmHeight;
  301.             temp1.width = rects[i].width - images[image_index].bmp.bmWidth;
  302.             temp1.x = rects[i].x + images[image_index].bmp.bmWidth;
  303.             temp1.y = rects[i].y;
  304.             RectItem temp2;
  305.             temp2.height = rects[i].height - images[image_index].bmp.bmHeight;
  306.             temp2.width = rects[i].width;
  307.             temp2.x = rects[i].x;
  308.             temp2.y = rects[i].y + images[image_index].bmp.bmHeight;
  309.             DeleteRectItem(i);
  310.             InsertRectItem(&temp1);
  311.             InsertRectItem(&temp2);
  312.             return;
  313.         }
  314.     }
  315.     
  316.     //找不到合适的rect,就新建一项,并将其插入合适的地方
  317.     RectItem new_item;
  318.     new_item.height = images[image_index].bmp.bmHeight;
  319.     new_item.width = merge_image_width;
  320.     new_item.x = 0;
  321.     new_item.y = merge_image_height;
  322.     
  323.     merge_image_height += new_item.height;
  324.     
  325.     InsertRectItem( &new_item );
  326.     goto searchproper;
  327. }
  328. void ImageList::DeleteRectItem(int index)
  329. {
  330.     for ( int i = index; i < m_rectCount; i++ )
  331.     {
  332.         memcpy( &rects[i], &rects[i+1], sizeof(RectItem) );
  333.     }
  334.     m_rectCount--;
  335. }
  336. void ImageList::InsertRectItem( RectItem * item )
  337. {
  338.     int i, j;
  339.     //找到该插入的位置,将其存到i
  340.     for ( i = 0; i < m_rectCount; i++ )
  341.     {
  342.         if ( item->width < rects[i].width )
  343.         {
  344.             break;
  345.         }
  346.         if ( item->width == rects[i].width &&
  347.              item->height < rects[i].height )
  348.         {
  349.             break;
  350.         }
  351.     }
  352.     
  353.     //插入
  354.     for ( j = m_rectCount - 1; j >= i ; j-- )
  355.     {
  356.         memcpy( &rects[j+1], &rects[j], sizeof(RectItem) );
  357.     }
  358.     memcpy( &rects[i], item, sizeof(RectItem) );
  359.     m_rectCount++;
  360. }
测试代码如下:
  1.     CFileDialog fileDlg(TRUE,
  2.                         NULL,
  3.                         NULL,
  4.                         OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT | OFN_ALLOWMULTISELECT,
  5.                         "bmp文件(*.bmp)|*.bmp||",
  6.                         NULL);   
  7.     fileDlg.m_ofn.lpstrFile =   new   TCHAR[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: init bmp ini data
  12.     CString filePath[100];
  13.     //获取图片路径
  14.     POSITION pos = fileDlg.GetStartPosition();
  15.     int fileCount;  
  16.     for (fileCount = 0; pos!=0; fileCount++)
  17.     {
  18.         CString file = 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"); 
以下是合并图片的测试效果:


合并的每一张小图片是从一张合照里剪切下来的,每张小图片的大小是不一样的,而且是未知的。从效果可以看得出,该算法尽可能地将图片挤在一起,但也还有待改进之处。
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值