下面的操作是为了将项目属性设置成与我生成的Cximage文件夹里面的十四个项目属性一致
文件可关注文末公众号获取!
我将Cximage的库函数封装在一个文件夹Cximage中,如下:
这样再使用第三方库函数时就会非常方便,只需要通过路径访问相应的头文件和.lib文件即可使用相关的函数功能
可以在**Dlg.cpp文件中添加如下代码:
//包含第三方头文件
#include "cximage\include\ximage.h"
#pragma comment(lib,"cximage/lib/debug/png.lib")
#pragma comment(lib, "cximage/lib/debug/libdcr.lib")
#pragma comment(lib, "cximage/lib/debug/jpeg.lib")
#pragma comment(lib, "cximage/lib/debug/zlib.lib")
#pragma comment(lib, "cximage/lib/debug/tiff.lib")
#pragma comment(lib, "cximage/lib/debug/jasper.lib")
#pragma comment(lib, "cximage/lib/debug/cximage.lib")
#pragma comment(lib, "cximage/lib/debug/mng.lib")
#pragma comment(lib, "cximage/lib/debug/cximaged.lib")
此项目只用到了ximage.h和cximaged.lib文件
项目–属性–C/C+±-语言–将WChar_t设置为内置类型:否 (/Zc:wchar_t-)
将Cximage文件夹拷贝到项目的同级目录的Debug中
将ximaged.lib文件拷贝到与项目同级的Debug文件夹中,ximaged.lib文件可以在cximage文件夹–lib–debug中找到
在预处理器定义中添加宏:_CRT_SECURE_NO_WARNINGS
添加此宏是为了解决VS2019编译器中scanf_s与旧版的scanf不一致的问题,也可以直接在**Dlg.cpp文件第一行添加宏定义:
#define _CRT_SECURE_NO_WARNINGS
基于对话框创建新项目
public:
CStatic m_bmp;//关联第一个静态文本框的控件变量
CStatic m_bmp2;//关联第二个静态文本框的控件变量
CString m_str;
CString path;//存储路径;
int pos = 1;
CBitmap bmp[100];//用于存储导入的位图,关联它的句柄
HBITMAP bmparray[100];
int size = 0;//当前导入的位图数量
CBitmap* BmpRotate(CBitmap* cBmp);//翻转位图
// CString m_str;//编辑框文本,翻转角度
float times = 1;//缩放的倍数
float m_Angle = 0;//连续旋转的角度
int xstep = 0;//横向移动
int ystep = 0;//纵向移动
CBitmap bm;//用于缩放以及平移的临时位图
bool judge = false;
afx_msg void OnBnClickedButton10();
afx_msg void OnBnClickedButton8();
afx_msg void OnBnClickedButton9();
afx_msg void OnBnClickedButton7();
afx_msg void OnBnClickedButton6();
afx_msg void OnBnClickedButton4();
afx_msg void OnBnClickedButton5();
afx_msg void OnBnClickedButton2();
afx_msg void OnBnClickedButton3();
afx_msg void OnBnClickedButton1();
afx_msg void OnBnClickedButton11();
afx_msg void OnMouseMove(UINT nFlags, CPoint point);
afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
afx_msg void OnBnClickedButton12();
};
初始化设置
BOOL Cmybitmap4Dlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
// 将“关于...”菜单项添加到系统菜单中。
// IDM_ABOUTBOX 必须在系统命令范围内。
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000);
CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != nullptr)
{
BOOL bNameValid;
CString strAboutMenu;
bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
ASSERT(bNameValid);
if (!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}
}
// 设置此对话框的图标。 当应用程序主窗口不是对话框时,框架将自动
// 执行此操作
SetIcon(m_hIcon, TRUE); // 设置大图标
SetIcon(m_hIcon, FALSE); // 设置小图标
// TODO: 在此添加额外的初始化代码
//初始化函数中设置
m_bmp.ModifyStyle(0xf, SS_BITMAP | SS_CENTERIMAGE);//设置位图风格
m_bmp2.ModifyStyle(0xf, SS_BITMAP | SS_CENTERIMAGE);//设置位图风格
float width = 480;
float height = 800;
MoveWindow(0, 0, 3 * width + 50, height + 100);
//设置适合位图的大小
m_bmp.MoveWindow(10, 0, width, height);
m_bmp2.MoveWindow(2 * width, 0, width, height);
int pos = width * 3 / 2 - 70;
GetDlgItem(IDC_BUTTON1)->MoveWindow(pos, 15, 140, 40);
GetDlgItem(IDC_BUTTON2)->MoveWindow(pos, 65, 140, 40);
GetDlgItem(IDC_EDIT1)->MoveWindow(pos, 115, 140, 40);
GetDlgItem(IDC_BUTTON3)->MoveWindow(pos, 165, 140, 40);
GetDlgItem(IDC_BUTTON4)->MoveWindow(pos, 215, 140, 40);
GetDlgItem(IDC_BUTTON5)->MoveWindow(pos, 265, 140, 40);
GetDlgItem(IDC_BUTTON6)->MoveWindow(pos, 315, 140, 40);
GetDlgItem(IDC_BUTTON7)->MoveWindow(pos, 365, 140, 40);
GetDlgItem(IDC_BUTTON8)->MoveWindow(pos, 415, 140, 40);
GetDlgItem(IDC_BUTTON9)->MoveWindow(pos, 465, 140, 40);
GetDlgItem(IDC_BUTTON10)->MoveWindow(pos, 515, 140, 40);
GetDlgItem(IDC_BUTTON11)->MoveWindow(pos, 565, 140, 40);
GetDlgItem(IDC_BUTTON12)->MoveWindow(pos, 615, 140, 40);
GetDlgItem(IDC_BUTTON1)->SetWindowTextW(TEXT("导入"));
GetDlgItem(IDC_BUTTON2)->SetWindowTextW(TEXT("翻转"));
GetDlgItem(IDC_BUTTON3)->SetWindowTextW(TEXT("放大"));
GetDlgItem(IDC_BUTTON4)->SetWindowTextW(TEXT("缩小"));
GetDlgItem(IDC_BUTTON5)->SetWindowTextW(TEXT("左移"));
GetDlgItem(IDC_BUTTON6)->SetWindowTextW(TEXT("右移"));
GetDlgItem(IDC_BUTTON7)->SetWindowTextW(TEXT("上移"));
GetDlgItem(IDC_BUTTON8)->SetWindowTextW(TEXT("下移"));
GetDlgItem(IDC_BUTTON9)->SetWindowTextW(TEXT("下一张"));
GetDlgItem(IDC_BUTTON10)->SetWindowTextW(TEXT("上一张"));
GetDlgItem(IDC_BUTTON11)->SetWindowTextW(TEXT("上下翻转"));
GetDlgItem(IDC_BUTTON12)->SetWindowTextW(TEXT("镜像翻转"));
return TRUE; // 除非将焦点设置到控件,否则返回 TRUE
}
包括了如下几大功能:
void Cmybitmap4Dlg::OnBnClickedButton1()
{
CFileDialog dlg(TRUE, NULL, NULL, OFN_FILEMUSTEXIST, TEXT("*.bmp|*.bmp||"), this);
CRect rect;
m_bmp.GetClientRect(&rect);
if (dlg.DoModal() == IDOK)
{
CxImage image;
size++;
pos = size;
path = dlg.GetPathName();//获取文件路径
image.Load(path, CXIMAGE_FORMAT_BMP);//加载位图
image.Resample(rect.Width(), rect.Height());//重新设置位图大小
HDC hdc = ::GetDC(NULL);
HBITMAP a = image.MakeBitmap(hdc);//将位图转化为HBITMAP
//下面是存储位图以及显示当前位图的操作
bmparray[pos - 1] = a;//位图句柄存储
bmp[pos - 1].Attach(a);//储存位图信息
m_bmp.SetBitmap(a);//将位图显示至静态文本框中
::ReleaseDC(NULL, hdc);
times = 1;
m_Angle = 0;
xstep = 0;
ystep = 0;
bm.Detach();//释放之前绑定的句柄
bm.Attach(bmparray[pos - 1]);
}
else
return;
}
效果显示:
功能介绍
可以实现任意角度翻转,且可以连续翻转,亮点:图片不会失真,可以在实现其他功能的基础上继续实现此功能
Cmybitmap4Dlg::BmpRotate(CBitmap* cBmp)是我自定义的翻转函数功能,我是根据极坐标来计算出各个像素点翻转后的位置
m_Angle是编辑框中读入的角度大小,由于我自定义的函数功能有一定缺陷(超出静态文本框的位图无法显示),所以我结合了第三方库函数的反转功能image.Rotate(360 - m_Angle);
超出文本框的位置可以通过缩小位图来显示出来
代码如下:
void Cmybitmap4Dlg::OnBnClickedButton2()
{
// TODO: 在此添加控件通知处理程序代码
//翻转
BmpRotate(&bm);
}
CBitmap* Cmybitmap4Dlg::BmpRotate(CBitmap* cBmp)
{
if (times >= 1)
{
BITMAP bmp;
cBmp->GetBitmap(&bmp);//接受传过来的位图信息
BYTE* pBits = new BYTE[bmp.bmWidthBytes * bmp.bmHeight], * TempBits = new BYTE[bmp.bmWidthBytes * bmp.bmHeight];
cBmp->GetBitmapBits(bmp.bmWidthBytes * bmp.bmHeight, pBits);
int interval = bmp.bmWidthBytes / bmp.bmWidth;//单位宽度的像素
double rx0 = bmp.bmWidth * 0.5;
double ry0 = bmp.bmHeight * 0.5;
UpdateData(TRUE);
m_Angle += _ttof(m_str);
float Angle = m_Angle / 180 * 3.1415926;//化为弧度制
for (int j = 0; j < bmp.bmHeight; j++)
{
for (int i = 0; i < bmp.bmWidth; i++)
{
int tempI, tempJ;//翻转之后的横纵坐标
//tempI = 2 * rx0 - i; //行坐标关于中心点的对称点
//tempJ = 2 * ry0 - j;//列坐标关于中心点的对称点
//下面利用极坐标求得旋转位置
float R = sqrt(pow((i - rx0), 2) + pow((j - ry0), 2));//求半径
//求目的坐标在极坐标中与极轴夹角的正弦、余弦值
float cos_a = (i - rx0) / R * cos(Angle) - (j - ry0) / R * sin(Angle);
float sin_a = sin(Angle) * (i - rx0) / R + cos(Angle) * (j - ry0) / R;
tempI = R * cos_a + rx0 + xstep * 100.0;
tempJ = R * sin_a + ry0 + ystep * 100.0;
//接收翻转之后的信息
if (tempI > 0 && tempI < bmp.bmWidth)
if (tempJ > 0 && tempJ < bmp.bmHeight)
{
for (int m = 0; m < interval; m++)
TempBits[j * bmp.bmWidthBytes + i * interval + m] = pBits[tempJ * bmp.bmWidthBytes + interval * tempI + m];
//TempBits[tempJ * bmp.bmWidthBytes + interval * tempI + m] = pBits[j * bmp.bmWidthBytes + i * interval + m];
//j * bmp.bmWidthBytes定位到该行初始部分的像素位
//i * interval + m以块状的方式填充某行中的像素位
}
}
}
CBitmap* m_bitmap;
m_bitmap = new CBitmap;
m_bitmap = cBmp;
//把位图信息传到位图上
m_bitmap->SetBitmapBits(bmp.bmWidthBytes * bmp.bmHeight, TempBits);
m_bmp2.SetBitmap((HBITMAP)*m_bitmap);//通过文本框显示位图
cBmp->SetBitmapBits(bmp.bmWidthBytes * bmp.bmHeight, pBits);//每次旋转都要恢复原图片信息,防止旋转时失真
delete[] pBits;
delete[] TempBits;
return m_bitmap;
}
else
{
//不失真且可以显示完整图案的翻转函数
BITMAP BMP;
bmp[pos - 1].GetBitmap(&BMP);
CxImage image;
image.CreateFromHBITMAP(bmparray[pos - 1]);//得到位图信息
UpdateData(TRUE);
//float Angle = _ttof(m_str);//将CString转化成浮点型
m_Angle += _ttof(m_str);
image.Resample(BMP.bmWidth * times, BMP.bmHeight * times, 1);
image.Rotate(360 - m_Angle);//翻转任意角度
HDC hdc = ::GetDC(NULL);
HBITMAP a = image.MakeBitmap(hdc);//将位图转化为HBITMAP
bmparray[pos - 1] = a;
::ReleaseDC(NULL, hdc);
m_bmp2.SetBitmap(bmparray[pos - 1]);
bmparray[pos - 1] = (HBITMAP)bmp[pos - 1];
return &bmp[pos - 1];
}
}
效果如下
功能分析
亮点:可以在实现其他功能的基础上继续实现此功能
代码如下
//上下翻转
void Cmybitmap4Dlg::OnBnClickedButton11()
{
// TODO: 在此添加控件通知处理程序代码
//上下翻转
// TODO: 在此添加控件通知处理程序代码
CBitmap* newbmp;
CxImage image;
BITMAP BMP;
bmp[pos - 1].GetBitmap(&BMP);
image.CreateFromHBITMAP(bm);//得到位图信息
image.Flip();//上下翻转
image.Resample(BMP.bmWidth * times, BMP.bmHeight * times, 1);//重新设置位图大小
HDC hdc = ::GetDC(NULL);
HBITMAP a = image.MakeBitmap(hdc);//将位图转化为HBITMAP
bmparray[pos - 1] = a;
bm.Detach();
bm.Attach(bmparray[pos - 1]);
BmpRotate(&bm);
::ReleaseDC(NULL, hdc);
m_bmp2.SetBitmap(bm);
bmparray[pos - 1] = (HBITMAP)bmp[pos - 1];
}
//镜像翻转
void Cmybitmap4Dlg::OnBnClickedButton12()
{
// TODO: 在此添加控件通知处理程序代码
CBitmap* newbmp;
CxImage image;
BITMAP BMP;
bmp[pos - 1].GetBitmap(&BMP);
image.CreateFromHBITMAP(bm);//得到位图信息
image.Mirror();//镜像翻转
image.Resample(BMP.bmWidth * times, BMP.bmHeight * times, 1);//重新设置位图大小
HDC hdc = ::GetDC(NULL);
HBITMAP a = image.MakeBitmap(hdc);//将位图转化为HBITMAP
bmparray[pos - 1] = a;
bm.Detach();
bm.Attach(bmparray[pos - 1]);
BmpRotate(&bm);
::ReleaseDC(NULL, hdc);
m_bmp2.SetBitmap(bm);
bmparray[pos - 1] = (HBITMAP)bmp[pos - 1];
}
效果如下
功能分析
这里的左移和右移、上移下移都是相对原图来说的,亮点:可以在实现其他功能的基础上继续实现此功能
代码如下
//左移
void Cmybitmap4Dlg::OnBnClickedButton5()
{
// TODO: 在此添加控件通知处理程序代码
// TODO: 在此添加控件通知处理程序代码
m_Angle -= _ttof(m_str);
xstep++;
//BmpRotate(&bmp[pos - 1]);
BmpRotate(&bm);
}
//右移
void Cmybitmap4Dlg::OnBnClickedButton6()
{
// TODO: 在此添加控件通知处理程序代码
// TODO: 在此添加控件通知处理程序代码
m_Angle -= _ttof(m_str);
xstep--;
//BmpRotate(&bmp[pos - 1]);
BmpRotate(&bm);
}
//上移
void Cmybitmap4Dlg::OnBnClickedButton7()
{
// TODO: 在此添加控件通知处理程序代码
// TODO: 在此添加控件通知处理程序代码
m_Angle -= _ttof(m_str);
ystep++;
BmpRotate(&bm);
//BmpRotate(&bmp[pos - 1]);
}
//下移
void Cmybitmap4Dlg::OnBnClickedButton8()
{
// TODO: 在此添加控件通知处理程序代码
// TODO: 在此添加控件通知处理程序代码
m_Angle -= _ttof(m_str);
ystep--;
//BmpRotate(&bmp[pos - 1]);
BmpRotate(&bm);
}
翻页功能
可以对多张位图进行操作,能够实现重新显示原图的功能
代码如下
//上一张
void Cmybitmap4Dlg::OnBnClickedButton9()
{
// TODO: 在此添加控件通知处理程序代码
// TODO: 在此添加控件通知处理程序代码
pos--;
if (pos < 1)
pos = size;
m_bmp.SetBitmap(bmparray[pos - 1]);
m_Angle = 0;
xstep = 0;
ystep = 0;
bm.Detach();//释放之前绑定的句柄
bm.Attach(bmparray[pos - 1]);
}
//下一张
void Cmybitmap4Dlg::OnBnClickedButton10()
{
// TODO: 在此添加控件通知处理程序代码
// TODO: 在此添加控件通知处理程序代码
pos++;
if (pos > size)
pos = 1;
m_bmp.SetBitmap(bmparray[pos - 1]);
m_Angle = 0;
xstep = 0;
ystep = 0;
bm.Detach();//释放之前绑定的句柄
bm.Attach(bmparray[pos - 1]);
}
效果如下
放大
缩小
亮点:可以在使用其他功能的基础上继续使用此功能
例如:
旋转之后再缩放
代码如下
//放大
void Cmybitmap4Dlg::OnBnClickedButton3()
{
// TODO: 在此添加控件通知处理程序代码
// TODO: 在此添加控件通知处理程序代码
BITMAP BMP;
bmp[pos - 1].GetBitmap(&BMP);
if (times <= 1)
times *= 2;
else
times++;
//m_Angle -= _ttof(m_str);
//bmparray[pos - 1] = (HBITMAP)*BmpRotate(&bmp[pos - 1]);
CRect rect;
m_bmp.GetClientRect(&rect);
CxImage image;
image.CreateFromHBITMAP(bmparray[pos - 1]);//得到位图信息
/*image.Resample(rect.Width() * times, rect.Height() * times, 1);*/
image.Resample(BMP.bmWidth * times, BMP.bmHeight * times, 1);
HDC hdc = ::GetDC(NULL);
bmparray[pos - 1] = image.MakeBitmap(hdc);//将位图转化为HBITMAP
::ReleaseDC(NULL, hdc);
bm.Detach();//释放之前绑定的句柄
bm.Attach(bmparray[pos - 1]);
//放大之后恢复偏转角度
m_Angle -= _ttof(m_str);
bmparray[pos - 1] = (HBITMAP)*BmpRotate(&bm);
//m_bmp2.SetBitmap(bmparray[pos - 1]);
//每次缩放之后都要恢复原图片信息,防止旋转时失真
bmparray[pos - 1] = (HBITMAP)bmp[pos - 1];
xstep = 0;
ystep = 0;
}
//缩小
void Cmybitmap4Dlg::OnBnClickedButton4()
{
// TODO: 在此添加控件通知处理程序代码
// TODO: 在此添加控件通知处理程序代码
if (times <= 1)
times /= 2;
else
times--;
BITMAP BMP;
bmp[pos - 1].GetBitmap(&BMP);
//bmparray[pos - 1] = (HBITMAP)*BmpRotate(&bmp[pos - 1]);
CxImage image;
image.CreateFromHBITMAP(bmparray[pos - 1]);//得到位图信息
image.Resample(BMP.bmWidth * times, BMP.bmHeight * times, 1);
HDC hdc = ::GetDC(NULL);
bmparray[pos - 1] = image.MakeBitmap(hdc);//将位图转化为HBITMAP
::ReleaseDC(NULL, hdc);
bm.Detach();//释放之前绑定的句柄
bm.Attach(bmparray[pos - 1]);
//缩小之后恢复偏转角度
m_Angle -= _ttof(m_str);
bmparray[pos - 1] = (HBITMAP)*BmpRotate(&bm);
//m_bmp2.SetBitmap(bmparray[pos - 1]);
//每次缩放之后都要恢复原图片信息,防止旋转时失真
bmparray[pos - 1] = (HBITMAP)bmp[pos - 1];
xstep = 0;
ystep = 0;
}
效果如下
功能分析
只要点击第二个静态文本框位置区域,就可以实现对图片进行任意位置的拖动,亮点:可以在实现其他功能的基础上继续使用该功能
代码如下
void Cmybitmap4Dlg::OnMouseMove(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
CRect rect;
m_bmp2.GetClientRect(&rect);
if (judge)
{
m_bmp2.MoveWindow(point.x, point.y, rect.Width(), rect.Height());
}
CDialogEx::OnMouseMove(nFlags, point);
}
void Cmybitmap4Dlg::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
CRect rect;
m_bmp2.GetClientRect(&rect);
CDialogEx::OnLButtonDown(nFlags, point);
if (point.x > rect.right * 2&& point.y < rect.bottom && point.x < rect.right * 3 && rect.top < point.y)
judge = true;
}
void Cmybitmap4Dlg::OnLButtonUp(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
judge = false;
CDialogEx::OnLButtonUp(nFlags, point);
}
所有的功能都是在保证图片原始精度的基础上实现的;这也是我设计的一大亮点,一般的翻转函数或者缩放函数,在进行不规则角度翻转或者多次缩放之后,图片的精度都会有所损失,于是我利用已学的极坐标知识,推算出翻转前后各像素点的关系,且每次操作之后都能够保留原始精度,图片不会失真,效果较好;
所有的功能都能够嵌套使用;各大功能相互独立,互不影响,你可以在翻转任意角度的基础上继续缩放或者平移等等操作,而且精度不会因此受到影响,不会出现失真的问题
最后
关注我的微信公众号:艺千秋录
回复:位图操作
即可领取完整代码文件;