mp3裁减器:乱弹运用Direct技术进行图像裁减的实现



绪言:
   这是篇很肤浅文章严格意义上来讲不能算是篇技术型文章只能说是自己在学习direct编程时点心得体会,不过里面还是包含了不少win32编程和direct编程基础知识拿到这里来献丑也是为了希望为正在从事direct编程朋友尽点绵力这篇文章主要是讲了我利用direct编程实现个图像裁减过程其效果图如下:

裁减前:


裁减后:


图中画白线地方就是裁减后区域^_^
如果朋友们在里面发现了bug请告诉我如果朋友们有什么更好意见和指教也请告诉我^_^


回:初窥门径

   windows编程是有定流程其实也就是最开始我们必须创建个主而这个主就应该是个大消息循环这个主大致流程如下图:


   首先我们必须做个最基本事情就是创建个窗体并注册再基于这个窗体上我们才能干更多就好比先有张画布然后我们可以在画布中绘图

//************************************************************
//:WinMain( )
//功能:Windows入口创建主窗口处理消息循环
//************************************************************
PASCAL WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, nCmdShow)
{
MSG msg; //消息结构

InitWindow(hInstance,nCmdShow); //化窗体

while(1) //消息循环
{
(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
(msg.messageWM_QUIT) //退出消息循环
;
TranslateMessage(&msg); //得到消息处理回调
DispatchMessage(&msg);
}
}
msg.wParam;
}

在讲本消息循环的前我想先谈下Dos和Windows驱动机制区别:

   DOS主要使用顺序过程驱动设计思路方法顺序过程驱动个明显开始明显过程及个明显结束因此能直接控制事件或过程顺序虽然在顺序过程驱动中也有很多处理异常思路方法但这样异常处理也仍然是顺序过程驱动结构

   而Windows驱动方式是事件驱动就是不由事件顺序来控制而是由事件发生来控制所有事件是无序所为在你编写你并不知道用户先按哪个按纽也不知道先触发哪个消息任务就是对正在开发应用要发出或要接收消息进行排序和管理事件驱动设计是密切围绕消息产生和处理而展开条消息是有关发生事件消息


WinMain( )原型如下:

PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, nCmdShow)

个参数hInstance是标识该应用句柄不过句柄又是什么呢?其实就是个指向该所占据内存区域指针它唯地代表了该应用Windows使用它管理内存中各种对象
第 2个参数是hPrevInstance应用个例子句柄别管它对于Win32位而言般是NULL.
第 3个参数是lpCmdLine是指向应用命令行参数指针比如说我们运行\"test hello\"则此参数指向串为\"hello\"
最后个参数是nCmdShow个用来指定窗口显示方式整数它告诉应用如何化窗口如最大化最小化等状态有关窗口显示方式其他种类将在下图介绍说明


然后我们要化窗体并且注册它然后我们才能使用它
//************************************************************
//:InitWindow( )
//功能:创建窗口
//************************************************************
BOOL InitWindow( HINSTANCE hInstance, nCmdShow )
{
WNDCLASS wc;
wc.style = NULL; //窗口类风格
wc.lpfnWndProc = (WNDPROC)WinProc; //指向窗口过程指针
wc.cbClsExtra = 0; //窗口类附加数据
wc.cbWndExtra = 0; //窗口类附加数据
wc.hInstance = hInstance; //拥有窗口类例子句柄
wc.hIcon = NULL; //最小窗口图标
wc.hCursor = NULL; //窗口内使用光标
wc.hbrBackground = NULL; //用来着色窗口背景刷子
wc.lpszMenuName = NULL; //指向菜单资源名指针
wc.lpszClassName = \"menpao_RPG_DEMO\";// 指向窗口类名指针
RegisterClass(&wc); //注册窗口
hwnd = CreateWindow(\"menpao_RPG_DEMO\",\"menpao_RPG_DEMO\",WS_POPUP|WS_MAXIMIZE,0,0,GetMetrics( SM_CXSCREEN ) ,GetMetrics( SM_CYSCREEN ), NULL,NULL,hInstance,NULL);


( !hwnd ) FALSE;
ShowWindow(hwnd,nCmdShow); //显示窗口
UpdateWindow(hwnd); //刷新窗口
TRUE;
}
(1)第个参数:成员style控制窗口样式某些重要特性在WINDOWS.H中定义了些前缀为CS常量中可组合使用这些常量.其他还有以下些特性:


(2)第 2个参数:lpfnWndProc给它消息处理名称即可必要时应该进行强制类型转换将其转换成WNDPROC型
(3)第 3, 4个参数:cbWndExtra域指定用本窗口类建立所有窗口结构分配额外字节数当有两个以上窗口属于同窗口类时如果想将区别数据和每个窗口分别相对应则使用该域很有用这般来讲你只要把它们设为0就行了,不必过多考虑
(4)第 5个参数:hInstance成员给它值是窗口所对应应用句柄表明该窗口和此应用s是相关联
(5)第 6个参数:成员hIcon被设置成应用所使用图标句柄图标是将应用最小化时出现在任务栏里图标用以表示仍驻留在内存中Windows提供了些默认图标我们也可定义自己图标VC里面专有个制作图标工具
(6)第 7个参数: hCursor域定义该窗口产生光标形状LoadCursor可返回固有光标句柄或者应用定义光标句柄IDC_ARROW表示箭头光标.
(7)第 8个参数:hbrBackground成员用来定义窗口背景色这里设为NULL
(8)第 9个参数:lpszMenuName用来指定菜单名中没有定义菜单所以为NULL
(9)第十个参数:lpszClassName指定了本窗口类名命名为“menpao_RPG_DEMO”
当对WNDCLASS结构域赋值后就可注册窗口类了在创建窗口的前是必须要注册窗口类注册窗口类用API是RegisterClass,注册失败就会出现个对话框如所示RegisterClass返回0值,也只能返回0值注册不成功已经不能再进行下去了

注册完了以后就是创建该窗体般我们APICreatWindows完成
以上面注册这个窗体为例
hwnd = CreateWindow(
\"menpao_RPG_DEMO\", //创建这个窗体类名称
\"menpao_RPG_DEMO\", //窗口标题
WS_POPUP|WS_MAXIMIZE, //窗口风格全部风格见后表
0, //窗口位置x坐标
0, //窗口位置y坐标
GetMetrics(SM_CXSCREEN ), //窗口高度这里是全屏
GetMetrics( SM_CYSCREEN ),//窗口高度这里是全屏
NULL, //父窗口句柄
NULL, //菜单句柄
hInstance, //应用句柄
NULL); //最后个参数是附加数据般都是0
参数1:登记窗口类名这个类名刚才咱们在注册窗口时已经定义过了
参数2:用来表明窗口标题可以和第个参数
参数3: 用来表明窗口风格如有无最大化最小化按纽啊什么 具体其他风格见下图所示


   在DirectX编程中我们般使用是WS_POPUP | WS_MAXIMIZE用这个标志创建窗口没有标题栏和系统菜单且窗口为最大化可以充分满足DirectX编程需要

参数4,5: 用来表明运行后窗口在屏幕中坐标值
参数6,7: 用来表明窗口化时(即初运行时)窗口大小即长度和宽度
参数8: 在创建窗口时可以指定其父窗口这里没有父窗口则参数值为0
参数9: 用以指明窗口菜单菜单以后会讲这里暂时为0
最后个参数是附加数据般都是0
如果窗口创建成功CreateWindow( )返回新窗口句柄否则返回NULL
不要以为创建和注册完了以后就大功告成这样话你是在屏幕上什么也看不见我们必须要另外个API才能看见窗体就是ShowWindow,他原型是:
ShowWindow (hwnd, iCmdShow)
其第个参数是窗口句柄告诉ShowWindow显示哪个窗口而第 2个参数则告诉它如何显示这个窗口还有很多其他样式


   WinMain完ShowWindow后还需要UpdateWindow最终把窗口显示了出来UpdateWindow将产生个WM_PAINT消息这个消息将使窗口重画即使窗口得到更新.

然后就是最重要消息循环和回调这就是windows编程灵魂了
reader:“其实上面介绍是最最基本win32编程基础啊“地球人都知道啊!”作者真是笨蛋以为我们都是白痴啊不要在这里班门弄斧
writer:“◎#!¥%※…………”
该死寝室要停电了
预听后事如何且待下回分解


第 2回:循序渐进

   大 4了象学长们说得那样很忙可是在忙了几天莫名其妙事后又不知道这几天是如何样浑浑噩噩过来!好像这段经历是瞬间就从地球上消失了吴宇森记忆裂痕

   书归正传!可以毫不夸张windows编程核心中核心就是回调只要看过李维大师vcl构架和侯捷老师深入浅出 MFC人都应该明白windows就是个大消息循环,当遇到外部有其他命令时就会暂停这个大循环而进行外部给命令事件而外部命令这个就是回调(winproc)他是通过句柄(hwnd)来确定这个命令触发窗体同样我们先写回调原型在这个区别消息将被switch语句分配到区别处理中去Windows消息处理原型是这样定义:



LRESULT CALLBACK WindowProc(
HWND hwnd, //接收消息窗口句柄
UINT uMsg, //主消息值
WPARAM wParam, //副消息值1
vLPARAM lParam //副消息值2
);

消息处理必须按照上面这个样式来定义当然名称可以随便取
就以我们这个裁减为例子我们回调是这样写:

LRESULT CALLBACK WinProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
{
switch( message )
{
WM_SETCURSOR:
SetCursor(NULL);
0;
WM_KEYDOWN:
switch( wParam )
{
VK_ESCAPE: //按下键盘ESC键触发事件
MessageBox(hWnd,\"quit!\",\"Keyboard\",MB_OK);
PostQuitMessage( 0 );
;
VK_SPACE: //按下键盘空格键触发事件

drawp.x1=x;
drawp.y1=y;
drawp.x2=x3;
drawp.y2=y3;
enable=1;
0;
}
0;
WM_LBUTTONDOWN: //按下鼠标左键触发事件
x=()LOWORD(lParam);
y=()HIWORD(lParam);
;
WM_LBUTTONUP: //放开鼠标右键触发事件
x3=()LOWORD(lParam);
y3=()HIWORD(lParam);
drawp.Rectanglep(x,y,x3,y3);
;
WM_MOUSEMOVE: //鼠标移动触发事件
enable=2;
;
WM_DESTROY:
PostQuitMessage( 0 );
0;
}

DefWindowProc(hWnd, message, wParam, lParam);
}

看起来就这么简单可是这里面确包含了很多智慧结晶!致敬!!


第 3回:博大精深

   上面就是windows编程基础东西了没那么复杂如果还有什么不清楚强烈建议看我上面推荐那两本书(好像在给李维老师和候捷老师书作宣传J)不过这才远远不够呢微软还给了我们很多API这些他们都把他封装好了我们拿来用就可以了direct编程也包含了大量这样如果要编写游戏或完成其他图形处理东东direct编程知识是必不可少先说说基础东东

   首先我们必须加入两个direct库文件这是微软给我们就好像当初老师告诉我们在编写c语言时候如果要做运算就必须在开始加上#inculde<math.h>是道理如果你用是.net编程环境可以按以下步筹加入这两个头文件:首先在\"Solution Explorer\"窗口中找到工程名然后在上面按右键并选择\"Properties\"在出现窗口中选择\"Linker\" --- \"Input\" --- \"Additional Dependencies\"最后填上要加入LIB文件名(ddraw.lib和dxguid.lib)即可然后在头文件里申明得库(# <ddraw.h>).

   开始时候我们要进行就是建立direct对象设置显示模式建立指针建立缓存Cache设置DirectDraw控制级建立页面设置页面填充页面设置透明色……还是先说过例子吧就那我们这个裁减举例好

LPDIRECTDRAW7 lpDD; // DirectDraw对象指针
LPDIRECTDRAWSURFACE7 lpDDSPrimary; // DirectDraw主页面指针
LPDIRECTDRAWSURFACE7 lpDDSBuffer; // DirectDraw后台缓存Cache指针
LPDIRECTDRAWSURFACE7 lpDDSMap; // DirectDraw放背景图指针
LPDIRECTDRAWSURFACE7 lpDDSMouse; // DirectDraw放鼠标指针

void init
{
DDSURFACEDESC2 ddsd; // DirectDraw页面描述
DirectDrawCreateEx (NULL, (void **)&lpDD,IID_IDirectDraw7, NULL); //创建DirectDraw对象
lpDD->SetCooperativeLevel(hwnd,DDSCL_EXCLUSIVE|DDSCL_FULLSCREEN);//设置DirectDraw控制级
lpDD->SetDisplayMode( 640, 480, 32, 0, DDSDM_STANDARDVGAMODE ); //设置显示模式
mem(&ddsd, 0, (DDSURFACEDESC2));//开始创建主页面先清空页面描述
ddsd.dwSize = ( ddsd );//填充页面描述
ddsd.dwFlags = DDSD_CAPS|DDSD_BACKBUFFERCOUNT; //有后台缓存Cache
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE|DDSCAPS_FLIP|DDSCAPS_COMPLEX;
ddsd.dwBackBufferCount = 1; //个后台缓存Cache
lpDD->CreateSurface( &ddsd, &lpDDSPrimary, NULL ); //创建主页面

ddsd.ddsCaps.dwCaps = DDSCAPS_BACKBUFFER; //这是后台缓存Cache
lpDDSPrimary->GetAttachedSurface( &ddsd.ddsCaps, &lpDDSBuffer ); //创建后台缓存Cache

ddsd.dwSize = ( ddsd );
ddsd.dwFlags = DDSD_CAPS|DDSD_WIDTH|DDSD_HEIGHT;
ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN; //这是离屏页面
ddsd.dwHeight = 480; //高


ddsd.dwWidth = 640; //宽
lpDD->CreateSurface( &ddsd, &lpDDSMap, NULL ); //创建放背景图页面
ddsd.dwHeight=26;
ddsd.dwWidth=32;
lpDD->CreateSurface( &ddsd, &lpDDSMouse, NULL);//创建放鼠标页面
ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN; //全屏显示

//清空各个页面
DDBLTFX ddBltFx;
ddBltFx.dwSize=(DDBLTFX);
ddBltFx.dwFillColor=0;
lpDDSPrimary ->Blt(NULL,NULL,NULL,DDBLT_WAIT|DDBLT_COLORFILL,&ddBltFx);
lpDDSBuffer->Blt(NULL,NULL,NULL,DDBLT_WAIT|DDBLT_COLORFILL,&ddBltFx);
lpDDSMap->Blt(NULL,NULL,NULL,DDBLT_WAIT|DDBLT_COLORFILL,&ddBltFx);
lpDDSMouse->Blt(NULL,NULL,NULL,DDBLT_WAIT|DDBLT_COLORFILL,&ddBltFx);

//贴图和设置透明色
DDReLoadBitmap(lpDDSMap,\"inn.BMP\");
DDReLoadBitmap(lpDDSMouse,\"mouse.BMP\");
MakeRect(0,0,640,480);
lpDDSPrimary->BltFast(0,0,lpDDSMap,&r,NoKey);
DDSetColorKey(lpDDSMap,RGB(0,255,0));
DDSetColorKey(lpDDSMouse,RGB(0,255,0));
}

老规矩还是对每个都来个具体介绍说明吧:

创建direct对象原型是
HRESULT WINAPI DirectDrawCreateEx(
GUID FAR *lpGUID,
LPVOID *lplpDD,
REFIID iid,
IUnknown FAR *pUnkOuter
);

个参数是lpGUID:指向DirectDraw接口全局唯标志符(Global Unique IDenty)指针在这里我们给它NULL表示我们将使用当前DirectDraw接口
第 2个参数是lplpDD:这个参数是用来接受DirectDraw对象地址在这里我们给它用强制类型转换为void**类型&lpdd(传递指针指针这样这个才能改变指针指向)
第 3个参数是iid:这里给它IID_IDirectDraw7吧表示我们要创建IDirectDraw7对象如果是d8,d9后面写成89即可
第 4个参数是pUnkOuter:有COM 集中特征考虑到将来兼容性目前必须是NULL
所有DirectDraw返回值都是HRESULT类型它是个32位
从上面化我们可以知道在对象创建完成了以后是设置d7对象控制级原型是:
HRESULT SetCooperativeLevel (HWND hWnd, DWORD dwFlags )
个参数是窗口句柄我们给它hWnd
第 2个参数是控制级标志参数见下表:


ok然后就是设置显示模式原型是:
HRESULT SetDisplayMode(
DWORD dwWidth,
DWORD dwHeight,
DWORD dwBPP,
DWORD dwRefreshRate,
DWORD dwFlags
);

dwWidth and dwHeight用来设置显示模式宽度和高度
dwBPP用来设置显示模式颜色位数
dwRefreshRate设置屏幕刷新率0为使用默认值
dwFlags现在唯有效值是DDSDM_STANDARDVGAMODE

创建页面先清空申请空间(类似于c中析构)

mem(&ddsd, 0, (DDSURFACEDESC2));//开始创建主页面先清空页面描述
ddsd.dwSize = ( ddsd );//填充页面描述
ddsd.dwFlags = DDSD_CAPS|DDSD_BACKBUFFERCOUNT; //有后台缓存Cache
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE|DDSCAPS_FLIP|DDSCAPS_COMPLEX;
ddsd.dwBackBufferCount = 1; //个后台缓存Cache
lpDD->CreateSurface( &ddsd, &lpDDSPrimary, NULL ); //创建主页面

创建主页面原型是:

HRESULT CreateSurface(
LPDDSURFACEDESC2 lpDDSurfaceDesc,
LPDIRECTDRAWSURFACE FAR *lplpDDSurface,
IUnknown FAR *pUnkOuter
);

个参数是被填充了页面信息DDSURFACEDESC2结构地址此处为&ddsd;
第 2个参数是接收主页面指针地址此处为&lpDDSPrimary;
第 3个参数现在必须为NULL为该所保留

后面创建放背景和鼠标页面也是个道理
后面就是贴图把要显示图片先贴出来个指针指定其位置后面要使用时候直接操作指针即可不过在这的前还是要清空页面最后贴好图后要设置图片透明色这样图片我们才可见

//清空各个页面
DDBLTFX ddBltFx;
ddBltFx.dwSize=(DDBLTFX);
ddBltFx.dwFillColor=0;
lpDDSPrimary ->Blt(NULL,NULL,NULL,DDBLT_WAIT|DDBLT_COLORFILL,&ddBltFx);
lpDDSBuffer->Blt(NULL,NULL,NULL,DDBLT_WAIT|DDBLT_COLORFILL,&ddBltFx);
lpDDSMap->Blt(NULL,NULL,NULL,DDBLT_WAIT|DDBLT_COLORFILL,&ddBltFx);
lpDDSMouse->Blt(NULL,NULL,NULL,DDBLT_WAIT|DDBLT_COLORFILL,&ddBltFx);

//贴图和设置透明色
DDReLoadBitmap(lpDDSMap,\"inn.BMP\");
DDReLoadBitmap(lpDDSMouse,\"mouse.BMP\");
MakeRect(0,0,640,480);
lpDDSPrimary->BltFast(0,0,lpDDSMap,&r,NoKey);
DDSetColorKey(lpDDSMap,RGB(0,255,0));
DDSetColorKey(lpDDSMouse,RGB(0,255,0));



写到这里也该休息下了
reader:“这人如何这样不负责任总是写没头没尾!#$%*^*”
weter:“先卖个关子篇章中我们会进入到具体功能实现上到底是如何样完成图片裁减工作?他原理是如何样?”
预听后事如何且待下回分解


第 4回:

   今天是最后话了而且废话了这么久都没有切入主题偶对不住大家啦今天我们就正儿 8经进入这次我们这个冗长故事核心部分了,同时也是最后个部分

   书归正传在direct编程里面有两个比较重要也是使用频率相当高两个在进入主题前我们必须先介绍这两个我们这个里面也是用了他们

个很有用是BltFast原型是
HRESULT BltFast(
DWORD dwX,
DWORD dwY,
LPDIRECTDRAWSURFACE lpDDSrcSurface,
LPRECT lpSrcRect,
DWORD dwTrans
);

下面将逐介绍这几个参数:
(1)dwX和dwY:图像将被传送到目标页面何处
(2)lpDDSrcSurface:图像传送操作源页面目标页面就是此思路方法页面
(3)lpSrcRect:个 RECT (Rectangle即矩形)结构地址指明源页面上将被传送区域如果该参数是NULL整个源页面将被使用RECT结构在DirectDraw中非常常用最好在中定义个RECT类型全局变量如rect再象这样写:void MakeRect (有关这个就是我说第 2个非常有用我们在后面在专门对他进行介绍和介绍说明)
(4)dwTrans:指定传送类型有如下几种:
DDBLTFAST_NOCOLORKEY
指定进行次普通复制不带透明成分
DDBLTFAST_SRCCOLORKEY
指定进行次带透明色图像传送使用源页面透明色
DDBLTFAST_WAIT
如果图像传送器正忙不断重试直到图像传送器准备好并传送好时才返回般都使用这个参数由于第 4个参数比较长而且有时候是两个搭配起来用所以大多数时候都是定义两个全局变量后面使用起来就比较方便
DWORD SrcKey = DDBLTFAST_SRCCOLORKEY | DDBLTFAST_WAIT
DWORD NoKey = DDBLTFAST_NOCOLORKEY | DDBLTFAST_WAIT
第 2个很有用就是我们前面提到void MakeRect ,这般是个自定义我们可以这样定义他:

void MakeRect ( left, top, right, bottom)
{
rect.bottom = bottom;
rect.left = left;
rect.right = right;
rect.top = top;
}

主要是确定了这个r结构 4个边际
所以要裁减副图片到个页面中就很简单了是不是^_^举个例子:我们要贴第哪个背景到SPrimary这个主页面里就可以这样
MakeRect(0,0,640,480);
lpDDSBuffer->BltFast(0,0,lpDDSPrimary,&r,NoKey);


核心部分

   哪个背景大小是640*480所以我们右边际是640下边际是480最后在利用BltFast贴出来就是了而且没有透明这样我们就可以贴图了

   可是如何样裁减呢?其实也就没什么难度了你想在MakeRect这个里面我们改变要贴图大小不就可以贴同幅图里任意位置图部分了吗,这就是裁减了塞然后我们设成变量用鼠标自定义贴大小就必须和windows消息循环机制联合起来使用了塞我们在mousedown时候得到他个坐标在mouseup时候得到他个坐标将两个坐标的间图片贴出来就可以了塞其实这个裁减主要核心技术就在这里了实现思想也就是这么回事简单吧:)其他都是些旁支末节东西了不过我们还是要介绍完

   ok,到这里我们就可以单独写个类出来完成我们图片裁减和贴图功能了我们写个类叫draw.cpp,这里我们还把他头文件draw.h写出来

draw.h:
# !d (draw_h)
# draw_h

draw
{
public:
x1;
y1;
x2;
y2;
void Rectanglep( x1, y1, width, height);//做成个鼠标在屏幕移动矩形
void blt( x1, y1, x2, y2);//完成我们图片裁减功能
};

#end

draw.cpp:
# \".h\"

void draw::blt( x1, y1, x2, y2)
{
x1=drawp.x1;
y2=drawp.y1;
x2=drawp.x2;
y2=drawp.y2;
MakeRect(x1,y1,x2,y2);
lpDDSBuffer->BltFast(0,0,lpDDSMap,&r,SrcKey);
}

void draw::Rectanglep( x1, y1, x2, y2)
{
HDC hdc;
lpDDSPrimary->GetDC(&hdc);//主页面得到句柄
HPEN Red_Pen=CreatePen(PS_SOLID,0,RGB(0,255,0));//填充画笔颜色
SelectObject(hdc,Red_Pen);//设置画笔类型
Line(x1,y1,x1,y2,hdc);//画线
Line(x1,y1,x2,y1,hdc);
Line(x2,y1,x2,y2,hdc);
Line(x1,y2,x2,y2,hdc);
lpDDSPrimary->ReleaseDC(hdc);//用完后释放句柄
}



这里就是对这两自定义具体化了
就是我们前面介绍实现图形裁减部分而且定义了 4个变量作为鼠标取点坐标
第 2个就是鼠标在屏幕上运动画出轨迹是由 4条线组成个矩形这里用到了API作图也就是微软给我们(微软什么都给我们封装好了用起来还真是方便呀)

然后就是公共使用个类这里面自定义可以全部被自由使用
我们定义为

publicfuction.cpp

//direct前面介绍过可以参看前面章节
void init
{
DDSURFACEDESC2 ddsd;
DirectDrawCreateEx (NULL, (void **)&lpDD,IID_IDirectDraw7, NULL);
lpDD->SetCooperativeLevel(hwnd,DDSCL_EXCLUSIVE|DDSCL_FULLSCREEN);
lpDD->SetDisplayMode( 640, 480, 32, 0, DDSDM_STANDARDVGAMODE );
mem(&ddsd, 0, (DDSURFACEDESC2));
ddsd.dwSize = ( ddsd );
ddsd.dwFlags = DDSD_CAPS|DDSD_BACKBUFFERCOUNT;
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE|DDSCAPS_FLIP|DDSCAPS_COMPLEX;
ddsd.dwBackBufferCount = 1;
lpDD->CreateSurface( &ddsd, &lpDDSPrimary, NULL );

ddsd.ddsCaps.dwCaps = DDSCAPS_BACKBUFFER;
lpDDSPrimary->GetAttachedSurface( &ddsd.ddsCaps, &lpDDSBuffer );

ddsd.dwSize = ( ddsd );
ddsd.dwFlags = DDSD_CAPS|DDSD_WIDTH|DDSD_HEIGHT;
ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
ddsd.dwHeight = 480;
ddsd.dwWidth = 640;
lpDD->CreateSurface( &ddsd, &lpDDSMap, NULL );
ddsd.dwHeight=26;
ddsd.dwWidth=32;
lpDD->CreateSurface( &ddsd, &lpDDSMouse, NULL);
ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;

DDBLTFX ddBltFx;
ddBltFx.dwSize=(DDBLTFX);
ddBltFx.dwFillColor=0;
lpDDSPrimary ->Blt(NULL,NULL,NULL,DDBLT_WAIT|DDBLT_COLORFILL,&ddBltFx);
lpDDSBuffer->Blt(NULL,NULL,NULL,DDBLT_WAIT|DDBLT_COLORFILL,&ddBltFx);
lpDDSMap->Blt(NULL,NULL,NULL,DDBLT_WAIT|DDBLT_COLORFILL,&ddBltFx);
lpDDSMouse->Blt(NULL,NULL,NULL,DDBLT_WAIT|DDBLT_COLORFILL,&ddBltFx);
DDReLoadBitmap(lpDDSMap,\"inn.BMP\");
DDReLoadBitmap(lpDDSMouse,\"mouse.BMP\");
MakeRect(0,0,640,480);
lpDDSPrimary->BltFast(0,0,lpDDSMap,&r,NoKey);
DDSetColorKey(lpDDSMap,RGB(0,255,0));
DDSetColorKey(lpDDSMouse,RGB(0,255,0));
}

//取矩形举例前面也介绍过
void MakeRect( left, top, right, bottom)
{
r.bottom=bottom;
r.left=left;
r.right=right;
r.top=top;
}

//画直线
void Line( x1, y1, x2, y2,HDC dc)
{
MoveToEx (dc, x1, y1, 0);//得到画直线起始坐标
LineTo (dc, x2, y2);//得到画直线终点坐标
}

//在屏幕上输出文字
void pr(char text[255], x, y)
{
HDC hdc;
lpDDSBuffer->GetDC(&hdc);//后台页面得到句柄
SetBkMode(hdc, TRANSPARENT);//设置显示模式
SetTextColor(hdc, RGB(0,255,255));//输出文字颜色
TextOut(hdc, x, y , text, strlen(text));//输出文字
lpDDSBuffer->ReleaseDC(hdc);//释放句柄
}

//前台和后台页面不断交换这样才能交替显示两个页面
void Flip
{
HRESULT ddrval;
ddrval=lpDDSPrimary->Flip(NULL,DDFLIP_WAIT);
(ddrvalDDERR_SURFACELOST)
Restore;
}

//指针释放指针用完以后得释放
HRESULT Restore(void)
{
HRESULT ddrval;
ddrval = lpDDSPrimary->Restore;
ddrval = lpDDSBuffer->Restore;
ddrval = lpDDSMouse->Restore;
ddrval = lpDDSMap->Restore;
init;
ddrval;
}

在公共类里面还有个最关键得就是refresh
void refresh
{
//将背景图贴到buffer页面了这样刷新时候直都在显示幅图


MakeRect(0,0,640,480);
lpDDSBuffer->BltFast(0,0,lpDDSMap,&r,NoKey);
//鼠标移动同样写在刷新里面是为了不会有鼠标移动过痕迹留下
POINT curpos;
GetCursorPos(&curpos);
for ( i=0;i<2;i)
{
CursorX[i]=CursorX[i+1];
CursorY[i]=CursorY[i+1];
CursorX[2]=curpos.x;
CursorY[2]=curpos.y;
lpDDSBuffer->BltFast(CursorX[1],CursorY[1],lpDDSMouse,NULL,SrcKey);
}

//ok,了裁减思路方法个标志在这个标志为1时候才
(enable1)
drawp.blt(drawp.x1,drawp.y1,drawp.x2,drawp.y2);

//了鼠标移动画矩形思路方法也有个标志当标志为2时候才
(enable2)
drawp.Rectanglep(x,y,curpos.x,curpos.y);

//为串赋值以便这些
char *text=\"LEFT MOUSEDOWN:点击鼠标左键可以确定裁剪个顶点坐标\";
char *text1=\"LEFT MOUSEMOVE:拖动鼠标可以选取裁剪区域\";
char *text2=\"LEFT MOUSEUP:放掉鼠标左键可以取定另外个顶点坐标\";
char *text3=\"SPACE:按空格键可以贴出裁剪区域\";
char *text4=\"世间本无事庸人自扰自!\";

//显示字自定义在屏幕上显示文字放在刷新页面里是可以直都显示
pr(text,10,10);
pr(text1,10,30);
pr(text2,10,50);
pr(text3,10,70);
pr(text4,400,450);

//翻页主页和buffer页交替显示
Flip;
}

就这样这就是全部功能实现和原理了再回到消息循环机制里面看看

.h:
# !d(Course_Design)

# Course_Design

# <windows.h>
# <math.h>
# <ddraw.h>
# \"ddutil.h\"
# \"draw.h\"

extern HDC hdc;
extern RECT r;
extern HWND hwnd;
extern DWORD SrcKey;
extern DWORD NoKey;
extern POINT curpos;
extern enable;
extern x;
extern y;
extern x3;
extern y3;

extern LPDIRECTDRAW7 lpDD;
extern LPDIRECTDRAWSURFACE7 lpDDSPrimary;
extern LPDIRECTDRAWSURFACE7 lpDDSBuffer;
extern LPDIRECTDRAWSURFACE7 lpDDSMap;
extern LPDIRECTDRAWSURFACE7 lpDDSMouse;
extern draw drawp;

void init;
void MakeRect( left, top, right, bottom);
void refresh;
void Flip;
void pr(char text[255], x, y);
void Line( x1, y1, x2, y2,HDC dc);
HRESULT Restore(void);

#end

.cpp

# \".h\"

.cpp
BOOL InitWindow( HINSTANCE hInstance, nCmdShow );
LRESULT CALLBACK WinProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam );

HWND hwnd;
RECT r;
HDC hdc;
POINT curpos;
enable;
x;
y;
x3;
y3;

LPDIRECTDRAW7 lpDD;
LPDIRECTDRAWSURFACE7 lpDDSPrimary;
LPDIRECTDRAWSURFACE7 lpDDSBuffer;
LPDIRECTDRAWSURFACE7 lpDDSMap;
LPDIRECTDRAWSURFACE7 lpDDSMouse;

DWORD SrcKey = DDBLTFAST_SRCCOLORKEY | DDBLTFAST_WAIT;
DWORD NoKey = DDBLTFAST_NOCOLORKEY | DDBLTFAST_WAIT;
draw drawp;

PASCAL WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, nCmdShow)
{
MSG msg;

InitWindow(hInstance,nCmdShow);

init;//
while(1)
{
(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
(msg.messageWM_QUIT)
;
TranslateMessage(&msg);
DispatchMessage(&msg);
}

{
refresh;//消息循环完成刷新功能具体功能在前面介绍这个时说过了
}
}
msg.wParam;
}

BOOL InitWindow( HINSTANCE hInstance, nCmdShow )
{
WNDCLASS wc;
wc.style = NULL;
wc.lpfnWndProc = (WNDPROC)WinProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;


wc.hIcon = NULL;
wc.hCursor = NULL;
wc.hbrBackground = NULL;
wc.lpszMenuName = NULL;
wc.lpszClassName = \"Course Design\";
RegisterClass(&wc);
hwnd = CreateWindow(\"Course Design\",\"My Course Design\",WS_POPUP|WS_MAXIMIZE,0,0,GetMetrics( SM_CXSCREEN ),GetMetrics( SM_CYSCREEN ), NULL,NULL,hInstance,NULL);
( !hwnd ) FALSE;
ShowWindow(hwnd,nCmdShow);
UpdateWindow(hwnd);
TRUE;
}

LRESULT CALLBACK WinProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
{
switch( message )
{
WM_SETCURSOR:
SetCursor(NULL);
0;
WM_KEYDOWN:
switch( wParam )
{
VK_ESCAPE://按ESC键退出
MessageBox(hWnd,\"quit!\",\"Keyboard\",MB_OK);
PostQuitMessage( 0 );
;
VK_SPACE://按空格键得到两个坐标并将标志设为1
drawp.x1=x;
drawp.y1=y;
drawp.x2=x3;
drawp.y2=y3;
enable=1;
0;
}
0;
WM_LBUTTONDOWN://按下鼠标左键得到个点坐标
x=()LOWORD(lParam);
y=()HIWORD(lParam);
;
WM_LBUTTONUP://放开鼠标左键得到个点坐标并画出这个矩形
x3=()LOWORD(lParam);
y3=()HIWORD(lParam);
drawp.Rectanglep(x,y,x3,y3);
;
WM_MOUSEMOVE://鼠标移动时设置标志为2
enable=2;
;
WM_DESTROY:
PostQuitMessage( 0 );
0;
}
DefWindowProc(hWnd, message, wParam, lParam);
}

这样全部代码我就放出来我想只要比照着注释看就能明白个大概了

   整理总结的洋洋洒洒写了这么多东西自己都感觉很凌乱句口头禅:“清不到方向”所以有必要整理总结总体来说我们做了个图片裁减然后这是个很简单主要用到了Windows消息循环和Direct编程这两个方面知识而要实现核心就是裁减也就只用到了Direct编程贴图(BltFast)也就是贴图大小和范围变化区别就实现了裁减了(-->裁减-->direct-->BltFast),这就是核心完成任务了其他无非是使用起来方便或者其他希望我把自己要说说清楚了希望大家能看懂我说是什么也就不枉费我莫名其妙说了大串了哈

   说实话这是我第次写这么多字技术性文章没有什么经验自己都觉得写比较凌乱而且似乎没有重点我只能做到尽量做到把关键原理和知识说清楚把源代码尽量多做上注释让大家看明白如果有什么看不懂和希望问就给我留言到邮箱有时间话,我会尽量给大家回复清楚其实Dierct编程是很有意思个部分这里面包含了很多东西甚至还可以做游戏不过我也只是知半解还有很多东西至今没有琢磨透同时也非常希望在这方面编程有自己心得体会和体会朋友多和我交流共同进步啦

   总算大功告成辛苦啊!!直以为写东西是件多么简单到今天自己亲自尝试了后才知道原本世界上根本没有什么简单东西哈这样来更加佩服侯捷老师和李维老师智慧了写出来东西丝丝入扣不但能够简单明了说清楚事物本质,而且语言幽默看了以后真是过目不忘哈还应该多多学习哈

#incldue<参考资料>
{
李维大师vcl构架;
侯捷老师深入浅出 MFC;
彭博朋友电脑游戏自己编;
microsoftSDK7开发指南;
SDK路报SDK讲座;
}

Tags:  mp3裁减 图片裁减 裁减呀 mp3裁减器

延伸阅读

最新评论

发表评论