主页 > 原创 > 基于FreeImage拼接/合成图片程序实现

基于FreeImage拼接/合成图片程序实现

实现后的效果如下(参见文后视频):
(1)点击添加照片按钮可以同时添加多张照片,也可以多次选择多张照片添加;
(2)鼠标左键不选中任何照片可以拖动画布;
(3)鼠标滚轮可以放大缩小画布,照片比例与实际图像像素保持不变;
(4)选中单独照片拖曳可以移动照片的位置并将照片置顶;
(5)移动单一照片时其他照片位置不变且此照片半透明;
(6)由于画布所占像素可能太大,保持时如果出错会弹出提示信息,保存过程中弹出等待对话框,完成后自动关闭。

1.设计思想
(1)主程序为一个基于CDialogEx的CDlgJointPhoto对话框,包含新增照片、确定、取消按钮,主体区域为实际操作的CDlgJointPhotoView是一个非模态的对话框。
(2)在CDlgJointPhotoView中获取鼠标左键、滚轮时间的监听来拖动、缩放视图。
(3)将所有的照片封装在vector列表中,并遍历绘制。
(4)为了避免屏幕闪烁的问题需要使用双缓冲技术。
(5)为了实现拖动照片透明绘图,需要在FreeImage的c++封装FreeImagePlus中增加drawAlpha函数,实现透明绘图。
(6)为了处理错误信息,需要弹出提示对话框。由于合成处理时间过长需要在新的线程里保存文件并提示正在处理。
(7)由于图片可能很大,保存到bmp虽然很快但会非常占用硬盘空间(动辄500mb),保存到jpg可以大幅度减少图片空间(很大时也只有10mb左右)

2.代码实现
FreeImage对mfc的透明绘图实现,需要在fipWinImage中添加drawAlpha函数,如下所示:
头文件FreeImagePlus.h类fipWinImage中添加函数声明

 /**@name Painting operations */
 //@{  

  /** @brief Set alpha to -1 to use the bitmap's own alpha channel, or set to 0..255 to apply an override across all pixels
  @param hDC Handle to the device context
 @param rcDest Destination rectangle
 @param alpha  Transparent alpha
 @see FreeImage_Composite
  */

  void drawAlpha(HDC hDC, RECT& rcDest, int alpha);

透明实现函数

void fipWinImage::drawAlpha(HDC hDC, RECT& rcDest, int alpha)
{
 // Convert to a standard bitmap if needed
 if(_bHasChanged) {
    if(_bDeleteMe) {
      FreeImage_Unload(_display_dib);
     _display_dib = NULL;
      _bDeleteMe = FALSE;
   }
   FREE_IMAGE_TYPE image_type = getImageType();
    if(image_type == FIT_BITMAP) {
      BOOL bHasBackground = FreeImage_HasBackgroundColor(_dib);
     BOOL bIsTransparent = FreeImage_IsTransparent(_dib);

      UINT nBPP = FreeImage_GetBPP(_dib);
     if ( nBPP == 32 )
     {
       // Create the transparent / alpha blended image
       _display_dib = FreeImage_Copy(_dib, 0,0,FreeImage_GetWidth(_dib),
         FreeImage_GetHeight(_dib));

       // as required by AlphaBlend
        FreeImage_PreMultiplyWithAlpha(_display_dib);

       // Remember to delete _display_dib
        _bDeleteMe = TRUE;
      }
     else
      {
       _display_dib = _dib;
      }
   } else {
      // Convert to a standard dib for display

      if(image_type == FIT_COMPLEX) {
       // Convert to type FIT_DOUBLE
       FIBITMAP *dib_double = FreeImage_GetComplexChannel(_dib, FICC_MAG);
       // Convert to a standard bitmap (linear scaling)
        _display_dib = FreeImage_ConvertToStandardType(dib_double, TRUE);
       // Free image of type FIT_DOUBLE
        FreeImage_Unload(dib_double);
     } else if((image_type == FIT_RGBF) || (image_type == FIT_RGB16)) {
        // Apply a tone mapping algorithm and convert to 24-bit
        _display_dib = FreeImage_ToneMapping(_dib, _tmo, _tmo_param_1, _tmo_param_2);
     } else {
        // Other cases: convert to a standard bitmap (linear scaling)
       _display_dib = FreeImage_ConvertToStandardType(_dib, TRUE);
     }
     // Remember to delete _display_dib

      UINT nBPP = FreeImage_GetBPP(_dib);
     if ( nBPP == 32 )
     {
       // as required by AlphaBlend
        FreeImage_PreMultiplyWithAlpha(_display_dib);
     }

     _bDeleteMe = TRUE;
    }

   _bHasChanged = FALSE;
 }

 int nImageWidth = FreeImage_GetWidth(_display_dib);
 int nImageHeight = FreeImage_GetHeight(_display_dib);

 int nDestWidth = rcDest.right - rcDest.left;
  int nDestHeight = rcDest.bottom - rcDest.top;

 UINT nBPP = FreeImage_GetBPP(_display_dib);

 BLENDFUNCTION blend = {AC_SRC_OVER,0,(alpha>=0&&alpha<=255)?alpha:255,(nBPP==32)?AC_SRC_ALPHA:0};

 // The destinatino hDC is at least 32 bits, we can blend directly to it.
  if ( ::GetDeviceCaps(hDC, BITSPIXEL) >= 32 )
  {
   // create a &quot;source&quot; DC and bitmap (as required by AlphaBlend()
   HDC hdcSrc = CreateCompatibleDC(NULL);

    HBITMAP bm = CreateCompatibleBitmap(hDC, nImageWidth, nImageHeight);
    HBITMAP oldbm = (HBITMAP)SelectObject(hdcSrc, bm);

    // copy the FIBITMAP bits into the &quot;source&quot; DC

#ifdef _WIN32_WCE
   SetStretchBltMode(hdcSrc, COLORONCOLOR);    
    StretchDIBits(hdcSrc, 0, 0, nImageWidth, nImageHeight,
     0, 0, nImageWidth, nImageHeight,
      FreeImage_GetBits(_display_dib),
      FreeImage_GetInfo(_display_dib), DIB_RGB_COLORS, SRCCOPY);
#else
   SetDIBits(  hdcSrc,                         // handle to DC
     bm,                             // handle to bitmap
     0,                              // starting scan line
     nImageHeight,                   // number of scan lines
     FreeImage_GetBits(_display_dib),// array of bitmap bits
     FreeImage_GetInfo(_display_dib),// bitmap data
      DIB_RGB_COLORS                  // type of color indexes to use
     );
#endif

    // blend the compatible DC on to the target DC.
   AlphaBlend(hDC, rcDest.left, rcDest.top, nDestWidth , nDestHeight,
     hdcSrc, 0,0, nImageWidth, nImageHeight, blend);

   // Free bitmaps and surfaces
    SelectObject(hdcSrc, oldbm);
    DeleteObject(bm);
   DeleteDC(hdcSrc);
 }
 // Otherwise we must create a 32 bit working surface
  else
  {
   // create a 32 bit dib section to hold the original screen area
#define LONGWORDALIGNEDBYTES(bits) ((((bits) + 31) / 32) * 4)
#define ALIGN_DWORD(bytes) (((((bytes)*8) + 31) / 32) * 4)

    BITMAPINFO bmi;
   memset(&bmi, 0, sizeof(BITMAPINFO));
    bmi.bmiHeader.biSize        = sizeof(BITMAPINFOHEADER);
   bmi.bmiHeader.biWidth       = nDestWidth;
   bmi.bmiHeader.biHeight      = nDestHeight;
    bmi.bmiHeader.biPlanes      = 1;
    bmi.bmiHeader.biBitCount    = 32;    // force to 32 bit color
   bmi.bmiHeader.biCompression = BI_RGB;
   bmi.bmiHeader.biSizeImage   = ALIGN_DWORD(nDestWidth) * nDestHeight;

    // a working surface to hold the captured background from the target
    HDC hWorkDC = ::CreateCompatibleDC(NULL);
   if ( ! hWorkDC )
      return;

   // Create DIB to use as a work place for our transforms
   LPVOID pBitmapBits = NULL;
    HBITMAP hDIB = ::CreateDIBSection(hWorkDC, &bmi, DIB_RGB_COLORS, &pBitmapBits, NULL, (DWORD)0);
   if ( hDIB == NULL)
    {
     ReleaseDC(NULL, hWorkDC);
     return;
   }
   HBITMAP hOrgBMP = (HBITMAP) SelectObject(hWorkDC, hDIB);

    // copy from the target surface into the work surface
   ::StretchBlt(hWorkDC, 0,0,nDestWidth,nDestHeight,
      hDC,rcDest.left,rcDest.top,nDestWidth,nDestHeight,SRCCOPY);

   // AlphaBlend between FIBITMAP and the working surface
    {
     // create a &quot;source&quot; DC and bitmap (as required by AlphaBlend()
     HDC hdcSrc = CreateCompatibleDC(NULL);
      HBITMAP bm = CreateCompatibleBitmap(hWorkDC, nImageWidth, nImageHeight);
      HBITMAP oldbm = (HBITMAP)SelectObject(hdcSrc, bm);

      // copy the FIBITMAP bits into the &quot;source&quot; DC
#ifdef _WIN32_WCE
     SetStretchBltMode(hdcSrc, COLORONCOLOR);    
      StretchDIBits(hdcSrc, 0, 0, nImageWidth, nImageHeight,
       0, 0, nImageWidth, nImageHeight,
        FreeImage_GetBits(_display_dib),
        FreeImage_GetInfo(_display_dib), DIB_RGB_COLORS, SRCCOPY);
#else
     SetDIBits(  hdcSrc,                          // handle to DC
        bm,                              // handle to bitmap
        0,                               // starting scan line
        nImageHeight,                    // number of scan lines
        FreeImage_GetBits(_display_dib), // array of bitmap bits
        FreeImage_GetInfo(_display_dib), // bitmap data
       DIB_RGB_COLORS                   // type of color indexes to use
        );
#endif

      AlphaBlend(hWorkDC, 0, 0, nDestWidth, nDestHeight,
        hdcSrc, 0,0, nImageWidth, nImageHeight, blend);

     // Free bitmaps and surfaces
      SelectObject(hdcSrc, oldbm);
      DeleteObject(bm);
     DeleteDC(hdcSrc);
   }

   // Transform the working/blended image from 32 bits to the target surface's format
   ::StretchBlt(hDC, rcDest.left, rcDest.top,nDestWidth,nDestHeight,
     hWorkDC,0,0,nDestWidth,nDestHeight,SRCCOPY);

    // cleanup
    SelectObject(hWorkDC, hOrgBMP);
   DeleteDC(hWorkDC);
    DeleteObject(hDIB);
 }
}

CDlgJointPhoto.h文件,外层对话框

#pragma once
#include "afxwin.h"
#include "Common.h"
#include "DlgJointPhotoView.h"


// CDlgJointPhoto dialog
class CDlgJointPhoto : public CSkinManager
{
 DECLARE_DYNAMIC(CDlgJointPhoto)

public:
  CDlgJointPhoto(CWnd* pParent = NULL);   // standard constructor
 CDlgJointPhoto(CString timestamp, CWnd* pParent = NULL);
  virtual ~CDlgJointPhoto();

// Dialog Data
  enum { IDD = IDD_DLG_JOINT_PHOTO };

protected:
 HICON m_hIcon;
  virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support

  DECLARE_MESSAGE_MAP()

 virtual BOOL OnInitDialog();

protected:
  CSkinStatic m_stTitle;
  CSkinButton m_btnOK;
  CSkinButton m_btnCancel;
  CSkinButton m_btnAdd;
 vector<CString> m_pathList;
 CDlgJointPhotoView m_JointPhotoView;
  CString m_filePath;

private:
 void AddPhotos();

public:
  afx_msg void OnBnClickedBttonAddPhoto();
  afx_msg void OnBnClickedOk();
 afx_msg void OnBnClickedCancel();
};

CDlgJointPhoto的实现:

// DlgJointPhoto.cpp : implementation file
//

#include "stdafx.h"
#include "Coalmine.h"
#include "DlgJointPhoto.h"
#include "afxdialogex.h"


// CDlgJointPhoto dialog

IMPLEMENT_DYNAMIC(CDlgJointPhoto, CDialogEx)

CDlgJointPhoto::CDlgJointPhoto(CWnd* pParent /*=NULL*/)
  : CSkinManager(CDlgJointPhoto::IDD, pParent, _T("/images/pipeline/Frame.png"), en_Wnd_Normal)
{
  m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

CDlgJointPhoto::CDlgJointPhoto( CString filePath, CWnd* pParent /*= NULL*/ ) : CSkinManager(CDlgJointPhoto::IDD, pParent, _T("/images/pipeline/Frame.png"), en_Wnd_Normal)
{
 m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
 m_filePath = filePath;
}

CDlgJointPhoto::~CDlgJointPhoto()
{
}

void CDlgJointPhoto::DoDataExchange(CDataExchange* pDX)
{
  CSkinManager::DoDataExchange(pDX);
  DDX_Control(pDX, IDC_STATIC_JOINT_TITLE, m_stTitle);
  DDX_Control(pDX, IDOK, m_btnOK);
  DDX_Control(pDX, IDCANCEL, m_btnCancel);
  DDX_Control(pDX, IDD_BUTTON_ADD_PHOTO, m_btnAdd);
}


BEGIN_MESSAGE_MAP(CDlgJointPhoto, CSkinManager)
 ON_BN_CLICKED(IDD_BUTTON_ADD_PHOTO, &CDlgJointPhoto::OnBnClickedBttonAddPhoto)
  ON_BN_CLICKED(IDOK, &CDlgJointPhoto::OnBnClickedOk)
 ON_BN_CLICKED(IDCANCEL, &CDlgJointPhoto::OnBnClickedCancel)
END_MESSAGE_MAP()

BOOL CDlgJointPhoto::OnInitDialog()
{
  CSkinManager::OnInitDialog();
 SetIcon(m_hIcon, TRUE);     // 设置大图标
  SetIcon(m_hIcon, FALSE);    // 设置小图标
  RenderEngine->AddFont(_T("华文新魏"), 20);
  setButton(m_btnOK);
 setButton(m_btnCancel);
 setButton(m_btnAdd);
  setFont(m_stTitle);
 m_JointPhotoView.Create(IDD_DLG_JOINT_PHOTO_VIEW, this);
  CRect rcView;
 GetWindowRect(&rcView);
 m_JointPhotoView.MoveWindow(rcView.left,rcView.top+140,rcView.Width()-100,rcView.Height()-200);
 return TRUE;
}


// CDlgJointPhoto message handlers


void CDlgJointPhoto::OnBnClickedBttonAddPhoto()
{
 AddPhotos();
  m_JointPhotoView.SetImageList(m_pathList);
  m_JointPhotoView.SetFocus();
}

void CDlgJointPhoto::AddPhotos()
{
  CString fileExtensions = L"图像文件|*.jpg;*.bmp;*.png||";                                      
  CFileDialog fileDlg(TRUE,
   NULL,
   NULL,
   OFN_ALLOWMULTISELECT | OFN_ENABLESIZING | OFN_HIDEREADONLY,
   fileExtensions);
  const int MIN_FILE_NUMBER = 10;
 fileDlg.m_ofn.lpstrFile = new TCHAR[_MAX_PATH * MIN_FILE_NUMBER];        
 memset(fileDlg.m_ofn.lpstrFile, 0, _MAX_PATH * MIN_FILE_NUMBER);
  fileDlg.m_ofn.nMaxFile = _MAX_PATH * MIN_FILE_NUMBER;
 m_pathList.clear();
 if (IDOK == fileDlg.DoModal())
  {
   POSITION pos = fileDlg.GetStartPosition();
    while (NULL != pos)
   {
     m_pathList.push_back(fileDlg.GetNextPathName(pos));
   }
 }
 delete[] fileDlg.m_ofn.lpstrFile;
}

void CDlgJointPhoto::OnBnClickedOk()
{
 JOINT_PHOTO_MSG result;
 m_JointPhotoView.SaveImage(m_filePath, result);

 if (result!=JOINT_MSG_SAVED)
  {
   CString szTmp;
    switch (result)
   {
   case JOINT_MSG_LOAD_BG_FAILED:
      szTmp = L"加载背景失败!";
     break;
    case JOINT_MSG_PASTE_FAILED:
      szTmp = L"粘贴照片失败!";
     break;
    case JOINT_MSG_SAVE_FAILED:
     szTmp = L"保存照片失败!";
     break;
    case JOINT_MSG_SCALE_FAILED:
      szTmp = L"缩放照片失败!";
     break;
    case JOINT_MSG_CROP_FAILED:
     szTmp = L"裁剪照片失败!";
     break;
    case JOINT_MSG_CONVERT_FAILED:
      szTmp = L"转换照片失败!";
     break;
    case JOINT_MSG_NONE:
    default:
      szTmp = L"未知错误";
      break;
    }
   CDlgMessage(L"拼接照片出错", szTmp).DoModal();
  }
 else
 {
   OnOK();
 }
}

void CDlgJointPhoto::OnBnClickedCancel()
{
 OnCancel();
}

CDlgJointPhotoView.h中包含需要的数据结构

#pragma once
#include "Common.h"
#include "FreeImagePlus.h"
#include "DlgMessage.h"

#define TOP_OFFSET 20
#define LEFT_OFFSET 10
#define INIT_IMAGE_HEIGHT 200
#define MOVE_TRANSPARENT_ALPHA 128
#define INIT_SCALE 0.05

typedef struct tagFipImage{
 fipWinImage fip;
  CRect rect;
 bool selected;
  CString path;
} FipImage;

typedef struct tagSaveMessage{
  CString path;
 CDlgMessage* dlg;
 vector<FipImage>* fipList;
  JOINT_PHOTO_MSG result;
} SaveMessage;

// CDlgJointPhotoView dialog

class CDlgJointPhotoView : public CSkinManager
{
  DECLARE_DYNAMIC(CDlgJointPhotoView)

public:
  CDlgJointPhotoView(CWnd* pParent = NULL);   // standard constructor
 virtual ~CDlgJointPhotoView();

// Dialog Data
  enum { IDD = IDD_DLG_JOINT_PHOTO_VIEW };

protected:
  vector<FipImage> m_fipList;

private:
 bool isLeftDown;
  double m_scale;
 double m_imageHeight;
 CPoint m_basePoint;
 int m_selectedIndex;

  CDC* m_pDC;
  CRect m_rect;
  CDC m_memDC;
 CBitmap* m_pOrgBMP;
  CBitmap m_memBitmap;

public:
 void SetImageList(vector<CString>& pathList);
 void SaveImage(CString path, JOINT_PHOTO_MSG &result);

protected:
  bool hasSelected();
 void prepareDraw();
 void releaseDraw();
 static UINT threadSaveImage(LPVOID lpParameter);

protected:
  virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support

  DECLARE_MESSAGE_MAP()
public:
  afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
  afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
  afx_msg BOOL OnMouseWheel(UINT nFlags, short zDelta, CPoint pt);
  afx_msg void OnMouseMove(UINT nFlags, CPoint point);
  afx_msg BOOL OnEraseBkgnd(CDC* pDC);
};

DlgJointPhotoView.cpp实现

// DlgJointPhotoView.cpp : implementation file
//

#include "stdafx.h"
#include "Coalmine.h"
#include "DlgJointPhotoView.h"
#include "afxdialogex.h"


// CDlgJointPhotoView dialog

IMPLEMENT_DYNAMIC(CDlgJointPhotoView, CDialogEx)

CDlgJointPhotoView::CDlgJointPhotoView(CWnd* pParent /*=NULL*/)
  : CSkinManager(CDlgJointPhotoView::IDD, pParent)
{
 isLeftDown = false;
 m_scale = INIT_SCALE;
 m_imageHeight = INIT_IMAGE_HEIGHT;
  m_basePoint = CPoint(-1,-1);
  m_selectedIndex = -1;
}

CDlgJointPhotoView::~CDlgJointPhotoView()
{
}

void CDlgJointPhotoView::DoDataExchange(CDataExchange* pDX)
{
 CSkinManager::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CDlgJointPhotoView, CSkinManager)
  ON_WM_LBUTTONDOWN()
 ON_WM_LBUTTONUP()
 ON_WM_MOUSEWHEEL()
  ON_WM_MOUSEMOVE()
 ON_WM_ERASEBKGND()
END_MESSAGE_MAP()

void CDlgJointPhotoView::SetImageList( vector<CString>& pathList )
{
  if (pathList.size()==0)
 {
   return;
 }
 
  prepareDraw();

  for (size_t i=0;i<m_fipList.size();i++)
 {
   if (m_selectedIndex!=i)
   {
     m_fipList[i].fip.draw(m_memDC.GetSafeHdc(), m_fipList[i].rect);
   }
 }

 if (m_selectedIndex!=-1)
  {
   m_fipList[m_selectedIndex].fip.draw(m_memDC.GetSafeHdc(), m_fipList[m_selectedIndex].rect);
 }

 FipImage image;
 image.selected = false;
 fipWinImage fip;
  CRect _rect;
  double deltaX = LEFT_OFFSET;

  if (m_fipList.size()>0)
 {
   m_scale = m_fipList[0].rect.Height()/(m_fipList[0].fip.getHeight()*1.0);
  }

 for (size_t i=0;i<pathList.size();i++)
  {
   fip.loadU(pathList[i]);

   int h = fip.getHeight();
    int w = fip.getWidth();
   m_imageHeight = h*m_scale;

    _rect.top = TOP_OFFSET;
   _rect.left = (LONG)deltaX;
    _rect.bottom = (LONG)(m_imageHeight+TOP_OFFSET);
    _rect.right = (LONG)(deltaX+m_imageHeight/(h*1.0)*w);
   deltaX = _rect.right+LEFT_OFFSET;

   fip.draw(m_memDC.GetSafeHdc(), _rect);
    image.rect = _rect;
   image.fip = fip;
    image.path = pathList[i];
   m_fipList.push_back(image);
 }
 releaseDraw();
}

void CDlgJointPhotoView::OnLButtonDown(UINT nFlags, CPoint point)
{
 isLeftDown = true;
  m_basePoint = point;

  bool select_flag = false;

 vector<FipImage>::reverse_iterator it = m_fipList.rbegin();
 while (it!=m_fipList.rend())
  {
   if(it->rect.PtInRect(point))
    {
     FipImage fip;
     it->selected = true;
      m_selectedIndex = m_fipList.size()-1;
     fip = *it;
      select_flag = true;
     m_fipList.erase((++it).base());
     m_fipList.push_back(fip);
     break;
    }
   it++;
 }

 if (!select_flag)
 {
   m_selectedIndex = -1;
   for (size_t i=0;i<m_fipList.size();i++)
   {
     m_fipList[i].selected = false;
    }
 }
 else
  {
   for (size_t i=0;i<m_fipList.size();i++)
   {
     if ((int)i<m_selectedIndex)
     {
       m_fipList[i].selected = false;
      }
   }
 }

 CSkinManager::OnLButtonDown(nFlags, point);
}

void CDlgJointPhotoView::OnLButtonUp(UINT nFlags, CPoint point)
{
  isLeftDown = false;
 m_basePoint = CPoint(-1,-1);

  prepareDraw();

  for (size_t i=0;i<m_fipList.size();i++)
 {
   if (m_selectedIndex!=i)
   {
     m_fipList[i].fip.draw(m_memDC.GetSafeHdc(), m_fipList[i].rect);
   }
 }

 if (m_selectedIndex!=-1)
  {
   m_fipList[m_selectedIndex].fip.draw(m_memDC.GetSafeHdc(), m_fipList[m_selectedIndex].rect);
 }

 releaseDraw();

  CSkinManager::OnLButtonUp(nFlags, point);
}

BOOL CDlgJointPhotoView::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt)
{
  CPoint point = pt;
  ScreenToClient(&point);

 prepareDraw();

  double scale;

 if (zDelta<0)
 {
   if (m_fipList.size()>0 && m_fipList[0].rect.Width()>20)
   {
     scale=0.8;
    }
   else
    {
     scale=1.0;
    }
 }
 else
  {
   scale=1.25;
 }

 for (size_t i=0;i<m_fipList.size();i++)
 {
   int left,right,top,bottom;

    left = (int)(point.x+scale*(m_fipList[i].rect.left-point.x));
   right = (int)(point.x+scale*(m_fipList[i].rect.right-point.x));
   top = (int)(point.y+scale*(m_fipList[i].rect.top-point.y));
   bottom = (int)(point.y+scale*(m_fipList[i].rect.bottom-point.y));

   m_fipList[i].rect.SetRect(left,top,right,bottom);
   m_fipList[i].fip.draw(m_memDC.GetSafeHdc(), m_fipList[i].rect);
 }

 releaseDraw();

  return CSkinManager::OnMouseWheel(nFlags, zDelta, pt);
}

void CDlgJointPhotoView::OnMouseMove(UINT nFlags, CPoint point)
{
 if (m_fipList.size()==0)
  {
   return;
 }
 if (MK_LBUTTON == nFlags && isLeftDown)
 {
   prepareDraw();

    LONG delta_x = point.x-m_basePoint.x;
   LONG delta_y = point.y-m_basePoint.y;

   if (m_selectedIndex==-1)
    {
     for (size_t i=0;i<m_fipList.size();i++)
     {
       m_fipList[i].rect.OffsetRect(delta_x, delta_y);
       m_fipList[i].fip.draw(m_memDC.GetSafeHdc(), m_fipList[i].rect);
     }
   }
   else
    {
     for (size_t i=0;i<m_fipList.size();i++)
     {
       if (m_selectedIndex!=i)
       {
         m_fipList[i].fip.draw(m_memDC.GetSafeHdc(), m_fipList[i].rect);
       }
     }
     m_fipList[m_selectedIndex].rect.OffsetRect(delta_x, delta_y);
     m_fipList[m_selectedIndex].fip.drawAlpha(m_memDC.GetSafeHdc(), m_fipList[m_selectedIndex].rect, MOVE_TRANSPARENT_ALPHA);
    }
   releaseDraw();
    m_basePoint = point;
  }
 CSkinManager::OnMouseMove(nFlags, point);
}

BOOL CDlgJointPhotoView::OnEraseBkgnd(CDC* pDC)
{
  return TRUE;
}

void CDlgJointPhotoView::SaveImage( CString path, JOINT_PHOTO_MSG &result)
{
  CDlgMessage dlg(L"系统消息", L"正在合成照片,请稍等", MB_DISABLE);

  SaveMessage msg;
  msg.path = path;
  msg.dlg = &dlg;
 msg.fipList = &m_fipList;

 CWinThread* thread = AfxBeginThread( threadSaveImage, &msg, THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED );
  ASSERT_VALID( thread );
 thread->ResumeThread();

 dlg.DoModal();
  result = msg.result;
}

bool CDlgJointPhotoView::hasSelected()
{
  for (size_t i=0;i<m_fipList.size();i++)
 {
   if (m_fipList[i].selected)
    {
     return true;
    }
 }
 return false;
}

void CDlgJointPhotoView::prepareDraw()
{
 m_pDC=GetDC();
  GetClientRect(&m_rect);

 m_memDC.CreateCompatibleDC(m_pDC);
  m_memBitmap.CreateCompatibleBitmap(m_pDC,m_rect.Width(),m_rect.Height());
 m_pOrgBMP = m_memDC.SelectObject(&m_memBitmap);
 CBrush brush(RGB(255,255,255));
 m_memDC.FillRect(m_rect, &brush);

 //可以尝试在对内存DC绘图之前将显示DC图像做为背景复制到内存DC中.
  //memDC.BitBlt(0,0,rect.Width(),rect.Height(),pDC,0,0,SRCCOPY);
}

void CDlgJointPhotoView::releaseDraw()
{
 m_pDC->BitBlt(0,0,m_rect.Width(),m_rect.Height(),&m_memDC,0,0,SRCCOPY);
 m_memDC.SelectObject(m_pOrgBMP);
  m_memDC.DeleteDC();
 m_memBitmap.DeleteObject();
 ReleaseDC(m_pDC);
}

UINT CDlgJointPhotoView::threadSaveImage( LPVOID lpParameter )
{
 SaveMessage* msg = (SaveMessage*)lpParameter;
 vector<FipImage>* fipList = msg->fipList;
 msg->result = JOINT_MSG_NONE;

 double scale = 1.0;
   CString bg_path = getExePath();
   bg_path.Append(L"images\\combine_bg.png");

  fipWinImage fip;
  if (!fip.loadU(bg_path))
  {
   msg->result = JOINT_MSG_LOAD_BG_FAILED;
   goto end;
 }

 int _top, _left, _right, _bottom;

 if (fipList->size()>0)
  {
   scale = (*fipList)[0].fip.getHeight()/((*fipList)[0].rect.Height()*1.0);
    _top = (*fipList)[0].rect.top;
    _left = (*fipList)[0].rect.left;
    _right = (*fipList)[0].rect.right;
    _bottom = (*fipList)[0].rect.bottom;
  }

 for (size_t i=0;i<(*fipList).size();i++)
  {
   _top=_top>(*fipList)[i].rect.top?(*fipList)[i].rect.top:_top;
   _left=_left>(*fipList)[i].rect.left?(*fipList)[i].rect.left:_left;
    _right=_right<(*fipList)[i].rect.right?(*fipList)[i].rect.right:_right;
   _bottom=_bottom<(*fipList)[i].rect.bottom?(*fipList)[i].rect.bottom:_bottom;
  }

 int new_width = (int)ceil((_right-_left)*scale)+100;
  int new_height = (int)ceil((_bottom-_top)*scale)+100;

 if (!fip.rescale(new_width, new_height, FILTER_BOX))
  {
   msg->result = JOINT_MSG_SCALE_FAILED;
   goto end;
 }
 //result = fip.setSize(fip.getImageType(), 20000, 7000, fip.getBitsPerPixel(), 255, 255, 255);
  //result = fip.convertTo24Bits();
 //result = fip.setSize(FIT_BITMAP, new_width, new_height, 8, 255, 255, 255);
  //result = fip.convertTo24Bits();
 _right = 0;
 _bottom = 0;
  for (size_t i=0;i<(*fipList).size();i++)
  {
   int left = (int)floor(scale*((*fipList)[i].rect.left-_left));
   int top = (int)floor(scale*((*fipList)[i].rect.top-_top));
    int right = left+(*fipList)[i].fip.getWidth();
    int bottom = top+(*fipList)[i].fip.getHeight();
   if (!fip.pasteSubImage((*fipList)[i].fip, left, top))
   {
     msg->result = JOINT_MSG_PASTE_FAILED;
   }
   _right = _right<right?right:_right;
   _bottom = _bottom<bottom?bottom:_bottom;
  }
 if (!fip.crop(0, 0, _right, _bottom))
 {
   msg->result = JOINT_MSG_CROP_FAILED;
    goto end;
 }
 if (!fip.convertTo24Bits())
 {
   msg->result = JOINT_MSG_CONVERT_FAILED;
   goto end;
 }

 if (fip.saveU(msg->path, 0))
  {
   if (msg->result==JOINT_MSG_NONE)
    {
     msg->result = JOINT_MSG_SAVED;
    }
 }
 else
  {
   msg->result = JOINT_MSG_SAVE_FAILED;
  }
 end:
  msg->dlg->PostMessage( MESSAGE_MSG_BOX, NULL, MESSAGE_JOINT_SAVED);
 return 0;
}

Common.h文件包含消息列表

#pragma once

#include "DlgMessage.h"
#include <string.h>

#define MESSAGE(X,Y) CDlgMessage(L#X,L#Y).DoModal();
#define DB CSqliteHelper::getInstance()

#define USE_SLOPE_DISTANCE //使用斜距
#define USE_NEAR_CATALOG_POINT //使用临近编录点
#define USE_LAST_MEASURE_POINT //使用最后一个测量点
//#define USE_SELECT_IMAGES //筛选照片

enum APP_MESSAGE{
 MESSAGE_MSG_BOX = (WM_APP+0x2000),
  MESSAGE_JOINT_SAVED = 0x0001
};

enum JOINT_PHOTO_MSG{
 JOINT_MSG_NONE,
 JOINT_MSG_SCALE_FAILED,
 JOINT_MSG_LOAD_BG_FAILED,
 JOINT_MSG_PASTE_FAILED,
 JOINT_MSG_CROP_FAILED,
  JOINT_MSG_CONVERT_FAILED,
 JOINT_MSG_SAVE_FAILED,
  JOINT_MSG_SAVED,
};

void copy_str(char *des, CString src, size_t size=127);
CSqliteHelper* sqlite();
void setButton(CSkinButton &button, size_t width=120, size_t height=36);
void setFont(ISkinControl &text, COLORREF rgb=RGB(0,0,0));
void enableWindow(CWnd &wnd, BOOL enable=TRUE);
CString getFileName(CString fullPath);
double getDistance(CPoint p1, CPoint p2);
CString getExePath();

[KGVID width=”640″ height=”476″]http://www.xdty.org/wp-content/uploads/2014/05/Video_2014-05-08_114722.mp4[/KGVID]

Tags: freeimage freeimage透明 MFC 拼接照片 照片合成

评论:1

  1. yuanc 回复
    2016 年 3 月 18 日 于 下午 4:59

    很好图像处理例程!

发表评论

邮箱地址不会被公开。 必填项已用*标注