由于要压缩成 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