自己寫遠端控制軟體之影象壓縮

LiuYinChina發表於2013-01-31
由於要壓縮成 JPG 檔案,我用的是 Intel ilj 庫,別說你沒聽過哦,可壓縮 YUYV和 Bmp,以下是我的 JpegEncoder,
使用簡單,介面清晰,誰用誰知道。至於在客戶端顯示 JPG,我就交給 OleLoadPicture 了,因為 ilj 在解壓的時候,有時會記憶體洩露,但是 OleLoadPicture 在使用時會有個問題就是如果 JPG 檔案本身有問題,會造成 OleLoadPicture 死鎖,我查了一下,據說是 Microsoft 的 BUG,這麼長時間了也不知道 Fix 沒有。不過 OleLoadPicture 死鎖在這個程式是不太可能出現的,我說的是我在公司的情況,細節我就不說了。

#ifndef JPEGEncoder_H
#define JPEGEncoder_H

//////////////////////////////////////////////////////////////////////////

#include <Windows.h>

//////////////////////////////////////////////////////////////////////////

#include "ijl.h"

//////////////////////////////////////////////////////////////////////////

#pragma comment(lib, "ijl15l.lib")

//////////////////////////////////////////////////////////////////////////

template <DWORD dwUnique>
class JPEGEncoderT
{
public:
	JPEGEncoderT()
	{
		ijlInit(&m_jpeg);
	}
	~JPEGEncoderT()
	{
		ijlFree(&m_jpeg);
	}

	//////////////////////////////////////////////////////////////////////////

	IJLERR Encode(DWORD dwWidth, DWORD dwHeight, LPVOID lpRGBSrc, DWORD dwSrcLength, LPVOID lpJPEGDst, DWORD dwDstLength, LPDWORD lpJPEGSize, DWORD dwBitCount)
	{
		DWORD dwByteCount = dwBitCount / 8;
		if (lpRGBSrc == NULL || lpJPEGDst == NULL || dwSrcLength == 0 || dwDstLength == 0 || lpJPEGSize == NULL) {
			return IJL_MEMORY_ERROR;
		}
		if (dwDstLength < (dwWidth * dwHeight)) {
			return IJL_BUFFER_TOO_SMALL;
		}

		IJLERR ijlError		= IJL_RESERVED;
		m_jpeg.upsampling_reqd	= FALSE;
		m_jpeg.cconversion_reqd	= FALSE;
		m_jpeg.DIBBytes		= (LPBYTE) lpRGBSrc;
		m_jpeg.JPGBytes		= (LPBYTE) lpJPEGDst;

		m_jpeg.DIBWidth		= dwWidth;
		m_jpeg.DIBHeight	= -dwHeight;
		m_jpeg.JPGWidth		= dwWidth;
		m_jpeg.JPGHeight	= dwHeight;
		m_jpeg.DIBSubsampling= IJL_NONE;
		m_jpeg.JPGFile		= NULL;
		m_jpeg.JPGSizeBytes	= dwDstLength;
		m_jpeg.jquality		= 100;

		//////////////////////////////////////////////////////////////////////////

		m_jpeg.DIBChannels    = dwByteCount;
		m_jpeg.JPGChannels    = dwByteCount;
		m_jpeg.DIBPadBytes    = IJL_DIB_PAD_BYTES(m_jpeg.DIBWidth, dwByteCount);
		switch (dwBitCount) {
			case 24:
				m_jpeg.DIBColor       = IJL_BGR;
				m_jpeg.JPGColor       = IJL_YCBCR;
				m_jpeg.JPGSubsampling = IJL_411;
				break;
			case 32:
				m_jpeg.DIBColor       = IJL_RGBA_FPX;
				m_jpeg.JPGColor       = IJL_YCBCRA_FPX;
				m_jpeg.JPGSubsampling = IJL_4114;
				break;
			default:
				return IJL_UNSUPPORTED_BYTES_PER_PIXEL;
				break;
		}

		//////////////////////////////////////////////////////////////////////////

		ijlError = ijlWrite(&m_jpeg, IJL_JBUFF_WRITEWHOLEIMAGE);
		if (ijlError == IJL_OK) {
			*lpJPEGSize = m_jpeg.JPGSizeBytes;
		}
		return ijlError;
	}

	//////////////////////////////////////////////////////////////////////////

	IJLERR Encode(DWORD dwWidth, DWORD dwHeight, LPVOID lpYUYVSrc, DWORD dwSrcLength, LPVOID lpJPEGDst, DWORD dwDstLength, LPDWORD lpJPEGSize)
	{
		if (lpYUYVSrc == NULL || lpJPEGDst == NULL || dwSrcLength == 0 || dwDstLength == 0 || lpJPEGSize == NULL) {
			return IJL_MEMORY_ERROR;
		}
		if (dwDstLength < (dwWidth * dwHeight >> 1)) {
			return IJL_BUFFER_TOO_SMALL;
		}

		IJLERR ijlError = IJL_RESERVED;
		m_jpeg.DIBBytes		= (LPBYTE) lpYUYVSrc;
		m_jpeg.JPGBytes		= (LPBYTE) lpJPEGDst;

		m_jpeg.DIBWidth		= dwWidth;
		m_jpeg.DIBHeight	= dwHeight;
		m_jpeg.JPGWidth		= m_jpeg.DIBWidth;
		m_jpeg.JPGHeight	= m_jpeg.DIBHeight;
		m_jpeg.JPGFile		= NULL;
		m_jpeg.JPGSizeBytes	= dwDstLength;
		m_jpeg.jquality		= 100;

		//////////////////////////////////////////////////////////////////////////

		m_jpeg.DIBChannels	= 3;
		m_jpeg.JPGChannels	= m_jpeg.DIBChannels;

		m_jpeg.DIBColor		= IJL_YCBCR;
		m_jpeg.JPGColor		= IJL_YCBCR;
		m_jpeg.DIBSubsampling= IJL_422;
		m_jpeg.JPGSubsampling= IJL_422;

		//////////////////////////////////////////////////////////////////////////

		ijlError = ijlWrite(&m_jpeg, IJL_JBUFF_WRITEWHOLEIMAGE);
		if (ijlError == IJL_OK) {
			*lpJPEGSize = m_jpeg.JPGSizeBytes;
		}
		return ijlError;
	}

private:
	JPEG_CORE_PROPERTIES m_jpeg;
};

//////////////////////////////////////////////////////////////////////////

typedef JPEGEncoderT<0> CJPEGEncoder;

//////////////////////////////////////////////////////////////////////////

#endif

把顯示的程式碼也貼上來,(只要來一般格式的影象,直接用 CopyImage 就可以顯示了,方便,哈哈!)
OwnerPolicy,這可是我研究了<產生式程式設計>後突發的靈感,簡單實用,便於元件化一些類。
DialogScreen 裡包含了客戶端滑鼠和鍵盤的捕捉(不捕捉怎麼發給伺服器,讓伺服器執行啊)。程式碼簡單,你懂的。
BEGIN_TEMPLATE_MESSAGE_MAP 在 VS2005 下才有,VC6 及 VS2003 不支援。

#ifndef DialogScreen_H
#define DialogScreen_H

//////////////////////////////////////////////////////////////////////////

#include <AfxWin.h>

#include "Resource.h"

#include "OwnerPolicy.h"

//////////////////////////////////////////////////////////////////////////

#include <OCIDL.h>
#include <OleCtl.h>

//////////////////////////////////////////////////////////////////////////

template <typename OwnerT>
class DialogScreenT	:	public CDialog, 
						public OwnerPolicy<OwnerT>
{
	enum
	{
		HOT_KEY_ID = 0x1000, 
	};

public:
	void FullScreen()
	{
		DialogScreenT<OwnerT>::FullScreen(GetSafeHwnd());
	}
	void CopyImage(LPVOID lpBuffer, DWORD dwLength)
	{
		if ((lpBuffer == NULL) || (dwLength == 0)) {
			return;
		}

		HGLOBAL hPicture = ::GlobalReAlloc(m_hPicture, dwLength, GMEM_MOVEABLE);
		if (hPicture == NULL) {
			return;
		}
		m_hPicture = hPicture;

		LPVOID pData = ::GlobalLock(m_hPicture);
		if (pData == NULL) {
			return;
		}

		CopyMemory(pData, lpBuffer, dwLength);
		GlobalUnlock(m_hPicture);

		ShowPicture(m_hPicture, GetSafeHwnd());
	}

public:
	DialogScreenT(CWnd *pParent = NULL)
		:	CDialog(DialogScreenT::IDD, pParent)
	{
		//{{AFX_DATA_INIT(DialogScreenT)
		//}}AFX_DATA_INIT

		m_hPicture = ::GlobalAlloc(GMEM_MOVEABLE, 32);
	}
	~DialogScreenT()
	{
		if (m_hPicture != NULL) {
			GlobalFree(m_hPicture);
			m_hPicture = NULL;
		}
	}

	//{{AFX_DATA(CMainDialog)
	enum { IDD = IDD_DLG_SCREEN };
	//}}AFX_DATA

	//{{AFX_VIRTUAL(DialogScreenT)
protected:
	virtual void DoDataExchange(CDataExchange *pDX)
	{
		CDialog::DoDataExchange(pDX);
		//{{AFX_DATA_MAP(DialogScreenT)
		//}}AFX_DATA_MAP
	}
	//}}AFX_VIRTUAL

protected:
	//{{AFX_MSG(DialogScreenT)
	virtual BOOL OnInitDialog()
	{
		CDialog::OnInitDialog();

		//////////////////////////////////////////////////////////////////////////
		RegisterHotKey(GetSafeHwnd(), HOT_KEY_ID, MOD_SHIFT|MOD_CONTROL, 'C');
		return TRUE;
	}

	LRESULT OnHotKey(WPARAM wParam, LPARAM lParam)
	{
		if (wParam == HOT_KEY_ID) {
			DestroyWindow();
		}
		return 0;
	}
	afx_msg void OnPaint()
	{
		CPaintDC dc(this);

		ShowPicture(m_hPicture, GetSafeHwnd());
	}
	afx_msg void OnDestroy()
	{
		UnregisterHotKey(GetSafeHwnd(), HOT_KEY_ID);

		CDialog::OnDestroy();
	}
	afx_msg void OnLButtonDown(UINT nFlags, CPoint ptMouse)
	{
		owner()->OnMouseEvent(this, MOUSEEVENTF_LEFTDOWN, ptMouse.x, ptMouse.y);
	}
	afx_msg void OnLButtonUp(UINT nFlags, CPoint ptMouse)
	{
		owner()->OnMouseEvent(this, MOUSEEVENTF_LEFTUP, ptMouse.x, ptMouse.y);
	}
	afx_msg void OnLButtonDblClk(UINT nFlags, CPoint ptMouse)
	{
		owner()->OnMouseEvent(this, MOUSEEVENTF_LEFTDOWN|MOUSEEVENTF_LEFTUP, ptMouse.x, ptMouse.y);
		owner()->OnMouseEvent(this, MOUSEEVENTF_LEFTDOWN|MOUSEEVENTF_LEFTUP, ptMouse.x, ptMouse.y);
	}
	afx_msg void OnRButtonDown(UINT nFlags, CPoint ptMouse)
	{
		owner()->OnMouseEvent(this, MOUSEEVENTF_RIGHTDOWN, ptMouse.x, ptMouse.y);
	}
	afx_msg void OnRButtonUp(UINT nFlags, CPoint ptMouse)
	{
		owner()->OnMouseEvent(this, MOUSEEVENTF_RIGHTUP, ptMouse.x, ptMouse.y);
	}
	afx_msg void OnRButtonDblClk(UINT nFlags, CPoint ptMouse)
	{
		owner()->OnMouseEvent(this, MOUSEEVENTF_RIGHTDOWN|MOUSEEVENTF_RIGHTUP, ptMouse.x, ptMouse.y);
		owner()->OnMouseEvent(this, MOUSEEVENTF_RIGHTDOWN|MOUSEEVENTF_RIGHTUP, ptMouse.x, ptMouse.y);
	}

	//////////////////////////////////////////////////////////////////////////

	afx_msg void OnSysKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
	{
		owner()->OnKeybdEvent(this, nChar, 0);

		CDialog::OnSysKeyDown(nChar, nRepCnt, nFlags);
	}
	afx_msg void OnSysKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags)
	{
		owner()->OnKeybdEvent(this, nChar, KEYEVENTF_KEYUP);

		CDialog::OnSysKeyUp(nChar, nRepCnt, nFlags);
	}

	afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
	{
		owner()->OnKeybdEvent(this, nChar, 0);

		CDialog::OnKeyDown(nChar, nRepCnt, nFlags);
	}
	afx_msg void OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags)
	{
		owner()->OnKeybdEvent(this, nChar, KEYEVENTF_KEYUP);

		CDialog::OnKeyUp(nChar, nRepCnt, nFlags);
	}
	//}}AFX_MSG
	DECLARE_MESSAGE_MAP()

	//////////////////////////////////////////////////////////////////////////

protected:
	virtual void OnOK()
	{
		owner()->OnKeybdEvent(this, VK_RETURN, 0);
		owner()->OnKeybdEvent(this, VK_RETURN, KEYEVENTF_KEYUP);
	}

	virtual void OnCancel()
	{
		owner()->OnKeybdEvent(this, VK_ESCAPE, 0);
		owner()->OnKeybdEvent(this, VK_ESCAPE, KEYEVENTF_KEYUP);
	}

private:
	static void FullScreen(HWND hWnd)
	{
		INT nFrameWidth		= GetSystemMetrics(SM_CXFRAME);
		INT nFrameHeight	= GetSystemMetrics(SM_CYFRAME);
		INT nCaptionHeight	= GetSystemMetrics(SM_CYCAPTION);
		INT nScreenWidth	= GetSystemMetrics(SM_CXSCREEN);
		INT nScreenHeight	= GetSystemMetrics(SM_CYSCREEN);

		CRect rect;
		::GetClientRect(hWnd, &rect);

		rect.left	= rect.left - nFrameWidth;
		rect.top	= rect.top - nFrameHeight - nCaptionHeight;
		rect.bottom	= rect.top + nScreenHeight + 2 * nFrameHeight + nCaptionHeight;
		rect.right	= rect.left + nScreenWidth + 2 * nFrameWidth;

		::SetWindowPos(hWnd, HWND_TOPMOST, rect.left, rect.top, rect.Width(), rect.Height(), SWP_SHOWWINDOW);
	}
	static HRESULT ShowPicture(HGLOBAL hGlobal, HWND hWnd)
	{
		HDC hDC = NULL;
		OLE_XSIZE_HIMETRIC xWidth = 0;
		OLE_YSIZE_HIMETRIC xHeight = 0;

		CComQIPtr<IStream> pStream;
		CComQIPtr<IPicture>	pPicture;

		CRect rect;
		HRESULT hResult = E_FAIL;
		if (!::IsWindow(hWnd)) {
			goto Exit;
		}
		::GetClientRect(hWnd, &rect);

		hDC = ::GetDC(hWnd);
		if (hDC == NULL) {
			goto Exit;
		}
		if (FAILED(CreateStreamOnHGlobal(hGlobal, FALSE, &pStream)) || pStream == NULL) {
			goto Exit;
		}
		if (FAILED(OleLoadPicture(pStream, 0, TRUE, IID_IPicture, (LPVOID *) &pPicture)) || pPicture == NULL) {
			goto Exit;
		}

		if (FAILED(pPicture->get_Width(&xWidth))) {
			goto Exit;
		}
		if (FAILED(pPicture->get_Height(&xHeight))) {
			goto Exit;
		}
		if (FAILED(pPicture->Render(hDC, 0, 0, rect.Width(), rect.Height(), 0, xHeight, xWidth, -xHeight, NULL))) {
			goto Exit;
		}

		hResult = S_OK;
	Exit:
		if (hDC != NULL) {
			::ReleaseDC(hWnd, hDC);
			hDC = NULL;
		}
		return hResult;
	}

private:
	HGLOBAL m_hPicture;
};

//////////////////////////////////////////////////////////////////////////

BEGIN_TEMPLATE_MESSAGE_MAP(DialogScreenT, OwnerT, CDialog)
	//{{AFX_MSG_MAP(DialogScreenT)
	ON_WM_PAINT()
	ON_WM_DESTROY()
	ON_WM_LBUTTONDOWN()
	ON_WM_LBUTTONUP()
	ON_WM_LBUTTONDBLCLK()
	ON_WM_RBUTTONDOWN()
	ON_WM_RBUTTONUP()
	ON_WM_RBUTTONDBLCLK()
	ON_WM_KEYDOWN()
	ON_WM_KEYUP()
	ON_WM_SYSKEYDOWN()
	ON_WM_SYSKEYUP()
	ON_MESSAGE(WM_HOTKEY, OnHotKey)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

//////////////////////////////////////////////////////////////////////////

#endif


相關文章