基于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中添加函数声明
//@{
/** @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);
透明实现函数
{
// 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 "source" 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 "source" 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 "source" 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 "source" 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文件,外层对话框
#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的实现:
//
#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中包含需要的数据结构
#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实现
//
#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文件包含消息列表
#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