how to create a new bitmap with rotated image?

cocacola 2000-11-22 05:02:00
...全文
157 2 打赏 收藏 转发到动态 举报
写回复
用AI写文章
2 条回复
切换为时间正序
请发表友善的回复…
发表回复
cocacola 2000-11-23
  • 打赏
  • 举报
回复
#define BMPWIDTH(w) ((w*3+3)/4*4);
STDMETHODIMP CFunctions::GetRotatedBitmap(long hbmp, long rad, LPDISPATCH *ppobj)
{
*ppobj = NULL;
if (hbmp == NULL)
return S_OK;
BITMAP bm;
::GetObject((HGDIOBJ)hbmp,sizeof(bm),&bm);
HDC sdc = ::CreateCompatibleDC(NULL);
BITMAPINFO bminfo;
ZeroMemory(&bminfo,sizeof(bminfo));
BITMAPINFOHEADER& bmhdr = bminfo.bmiHeader;
bmhdr.biSize = sizeof(BITMAPINFOHEADER);
bmhdr.biWidth = bm.bmWidth;
bmhdr.biHeight = bm.bmHeight;
bmhdr.biPlanes = 1;
bmhdr.biBitCount = 24;
bmhdr.biCompression = DIB_RGB_COLORS;
int wb = BMPWIDTH(bm.bmWidth);
BYTE* src = new BYTE[wb * bm.bmHeight + 0x10000];
int r = ::GetDIBits(sdc,(HBITMAP)hbmp,0,bm.bmHeight,src,&bminfo,DIB_RGB_COLORS);
HGDIOBJ o1 = ::SelectObject(sdc,(HGDIOBJ)hbmp);
if (rad == 90 || rad == 270)
{
bmhdr.biWidth = bm.bmHeight;
bmhdr.biHeight = bm.bmWidth;
}
HBITMAP hbmp1 = ::CreateCompatibleBitmap(sdc,bmhdr.biWidth,bmhdr.biHeight);
::SelectObject(sdc,o1);
int wb1 = BMPWIDTH(bmhdr.biWidth);
BYTE* dst = new BYTE[wb1 * bmhdr.biHeight + 0x10000];
for(int x = 0;x < bm.bmWidth;x++)
{
for (int y=0;y<bm.bmHeight;y++)
{
int x1,y1;
switch(rad)
{
case 90:
x1 = y;
y1 = (bm.bmWidth-x);
break;
case 180:
x1 = (bm.bmWidth-x);
y1 = (bm.bmHeight-y);
break;
case 270:
x1 = (bm.bmHeight-y);
y1 = x;
break;
default:
x1 = x;
y1 = y;
break;
}
CopyMemory(dst + wb1 * y1 + x1 * 3,src + wb * y + x * 3,3);
}
}
r = ::SetDIBits(sdc,hbmp1,0,bmhdr.biHeight,dst,&bminfo,DIB_RGB_COLORS);
::DeleteDC(sdc);
delete [] src;
delete [] dst;
PICTDESC pic;
pic.cbSizeofstruct = sizeof(pic);
pic.picType = PICTYPE_BITMAP;
pic.bmp.hbitmap = hbmp1;
pic.bmp.hpal = NULL;
HRESULT hr = ::OleCreatePictureIndirect(&pic,IID_IDispatch,TRUE,(LPVOID*)ppobj);
return hr;
}
stranger 2000-11-22
  • 打赏
  • 举报
回复
// GetRotatedBitmap - Create a new bitmap with rotated image
// Returns - Returns new bitmap with rotated image
// hBitmap - Bitmap to rotate
// radians - Angle of rotation in radians
// clrBack - Color of pixels in the resulting bitmap that do
// not get covered by source pixels
// Note - If the bitmap uses colors not in the system palette
// then the result is unexpected. You can fix this by
// adding an argument for the logical palette.
HBITMAP GetRotatedBitmap( HBITMAP hBitmap, float radians, COLORREF clrBack )
{
// Create a memory DC compatible with the display
CDC sourceDC, destDC;
sourceDC.CreateCompatibleDC( NULL );
destDC.CreateCompatibleDC( NULL );

// Get logical coordinates
BITMAP bm;
::GetObject( hBitmap, sizeof( bm ), &bm );

float cosine = (float)cos(radians);
float sine = (float)sin(radians);

// Compute dimensions of the resulting bitmap
// First get the coordinates of the 3 corners other than origin
int x1 = (int)(-bm.bmHeight * sine);
int y1 = (int)(bm.bmHeight * cosine);
int x2 = (int)(bm.bmWidth * cosine - bm.bmHeight * sine);
int y2 = (int)(bm.bmHeight * cosine + bm.bmWidth * sine);
int x3 = (int)(bm.bmWidth * cosine);
int y3 = (int)(bm.bmWidth * sine);

int minx = min(0,min(x1, min(x2,x3)));
int miny = min(0,min(y1, min(y2,y3)));
int maxx = max(x1, max(x2,x3));
int maxy = max(y1, max(y2,y3));

int w = maxx - minx;
int h = maxy - miny;


// Create a bitmap to hold the result
HBITMAP hbmResult = ::CreateCompatibleBitmap(CClientDC(NULL), w, h);

HBITMAP hbmOldSource = (HBITMAP)::SelectObject( sourceDC.m_hDC, hBitmap );
HBITMAP hbmOldDest = (HBITMAP)::SelectObject( destDC.m_hDC, hbmResult );

// Draw the background color before we change mapping mode
HBRUSH hbrBack = CreateSolidBrush( clrBack );
HBRUSH hbrOld = (HBRUSH)::SelectObject( destDC.m_hDC, hbrBack );
destDC.PatBlt( 0, 0, w, h, PATCOPY );
::DeleteObject( ::SelectObject( destDC.m_hDC, hbrOld ) );

// Set mapping mode so that +ve y axis is upwords
sourceDC.SetMapMode(MM_ISOTROPIC);
sourceDC.SetWindowExt(1,1);
sourceDC.SetViewportExt(1,-1);
sourceDC.SetViewportOrg(0, bm.bmHeight-1);

destDC.SetMapMode(MM_ISOTROPIC);
destDC.SetWindowExt(1,1);
destDC.SetViewportExt(1,-1);
destDC.SetWindowOrg(minx, maxy);

// Now do the actual rotating - a pixel at a time
// Computing the destination point for each source point
// will leave a few pixels that do not get covered
// So we use a reverse transform - e.i. compute the source point
// for each destination point

for( int y = miny; y < maxy; y++ )
{
for( int x = minx; x < maxx; x++ )
{
int sourcex = (int)(x*cosine + y*sine);
int sourcey = (int)(y*cosine - x*sine);
if( sourcex >= 0 && sourcex < bm.bmWidth && sourcey >= 0
&& sourcey < bm.bmHeight )
destDC.SetPixel(x,y,sourceDC.GetPixel(sourcex,sourcey));
}
}

// Restore DCs
::SelectObject( sourceDC.m_hDC, hbmOldSource );
::SelectObject( destDC.m_hDC, hbmOldDest );

return hbmResult;
}

// GetRotatedBitmap - Create a new bitmap with rotated image
// Returns - Returns new bitmap with rotated image
// hDIB - Device-independent bitmap to rotate
// radians - Angle of rotation in radians
// clrBack - Color of pixels in the resulting bitmap that do
// not get covered by source pixels
HANDLE GetRotatedBitmap( HANDLE hDIB, float radians, COLORREF clrBack )
{
// Get source bitmap info
BITMAPINFO &bmInfo = *(LPBITMAPINFO)hDIB ;
int bpp = bmInfo.bmiHeader.biBitCount; // Bits per pixel

int nColors = bmInfo.bmiHeader.biClrUsed ? bmInfo.bmiHeader.biClrUsed :
1 << bpp;
int nWidth = bmInfo.bmiHeader.biWidth;
int nHeight = bmInfo.bmiHeader.biHeight;
int nRowBytes = ((((nWidth * bpp) + 31) & ~31) / 8);

// Make sure height is positive and biCompression is BI_RGB or BI_BITFIELDS
DWORD &compression = bmInfo.bmiHeader.biCompression;
if( nHeight < 0 || (compression!=BI_RGB && compression!=BI_BITFIELDS))
return NULL;

LPVOID lpDIBBits;
if( bmInfo.bmiHeader.biBitCount > 8 )
lpDIBBits = (LPVOID)((LPDWORD)(bmInfo.bmiColors +
bmInfo.bmiHeader.biClrUsed) +
((compression == BI_BITFIELDS) ? 3 : 0));
else
lpDIBBits = (LPVOID)(bmInfo.bmiColors + nColors);


// Compute the cosine and sine only once
float cosine = (float)cos(radians);
float sine = (float)sin(radians);

// Compute dimensions of the resulting bitmap
// First get the coordinates of the 3 corners other than origin
int x1 = (int)(-nHeight * sine);
int y1 = (int)(nHeight * cosine);
int x2 = (int)(nWidth * cosine - nHeight * sine);
int y2 = (int)(nHeight * cosine + nWidth * sine);
int x3 = (int)(nWidth * cosine);
int y3 = (int)(nWidth * sine);

int minx = min(0,min(x1, min(x2,x3)));
int miny = min(0,min(y1, min(y2,y3)));
int maxx = max(x1, max(x2,x3));
int maxy = max(y1, max(y2,y3));

int w = maxx - minx;
int h = maxy - miny;


// Create a DIB to hold the result
int nResultRowBytes = ((((w * bpp) + 31) & ~31) / 8);
long len = nResultRowBytes * h;
int nHeaderSize = ((LPBYTE)lpDIBBits-(LPBYTE)hDIB) ;
HANDLE hDIBResult = GlobalAlloc(GMEM_FIXED,len+nHeaderSize);
// Initialize the header information
memcpy( (void*)hDIBResult, (void*)hDIB, nHeaderSize);
BITMAPINFO &bmInfoResult = *(LPBITMAPINFO)hDIBResult ;
bmInfoResult.bmiHeader.biWidth = w;
bmInfoResult.bmiHeader.biHeight = h;
bmInfoResult.bmiHeader.biSizeImage = len;

LPVOID lpDIBBitsResult = (LPVOID)((LPBYTE)hDIBResult + nHeaderSize);

// Get the back color value (index)
ZeroMemory( lpDIBBitsResult, len );
DWORD dwBackColor;
switch(bpp)
{
case 1: //Monochrome
if( clrBack == RGB(255,255,255) )
memset( lpDIBBitsResult, 0xff, len );
break;
case 4:
case 8: //Search the color table
int i;
for(i = 0; i < nColors; i++ )
{
if( bmInfo.bmiColors[i].rgbBlue == GetBValue(clrBack)
&& bmInfo.bmiColors[i].rgbGreen == GetGValue(clrBack)
&& bmInfo.bmiColors[i].rgbRed == GetRValue(clrBack) )
{
if(bpp==4) i = i | i<<4;
memset( lpDIBBitsResult, i, len );
break;
}
}
// If not match found the color remains black
break;
case 16:
// Windows95 supports 5 bits each for all colors or 5 bits for red & blue
// and 6 bits for green - Check the color mask for RGB555 or RGB565
if( *((DWORD*)bmInfo.bmiColors) == 0x7c00 )
{
// Bitmap is RGB555
dwBackColor = ((GetRValue(clrBack)>>3) << 10) +
((GetRValue(clrBack)>>3) << 5) +
(GetBValue(clrBack)>>3) ;
}
else
{
// Bitmap is RGB565
dwBackColor = ((GetRValue(clrBack)>>3) << 11) +
((GetRValue(clrBack)>>2) << 5) +
(GetBValue(clrBack)>>3) ;
}
break;
case 24:
case 32:
dwBackColor = (((DWORD)GetRValue(clrBack)) << 16) |
(((DWORD)GetGValue(clrBack)) << 8) |
(((DWORD)GetBValue(clrBack)));
break;
}


// Now do the actual rotating - a pixel at a time
// Computing the destination point for each source point
// will leave a few pixels that do not get covered
// So we use a reverse transform - e.i. compute the source point
// for each destination point

for( int y = 0; y < h; y++ )
{
for( int x = 0; x < w; x++ )
{
int sourcex = (int)((x+minx)*cosine + (y+miny)*sine);
int sourcey = (int)((y+miny)*cosine - (x+minx)*sine);
if( sourcex >= 0 && sourcex < nWidth && sourcey >= 0
&& sourcey < nHeight )
{
// Set the destination pixel
switch(bpp)
{
BYTE mask;
case 1: //Monochrome
mask = *((LPBYTE)lpDIBBits + nRowBytes*sourcey +
sourcex/8) & (0x80 >> sourcex%8);
//Adjust mask for destination bitmap
mask = mask ? (0x80 >> x%8) : 0;
*((LPBYTE)lpDIBBitsResult + nResultRowBytes*(y) +
(x/8)) &= ~(0x80 >> x%8);
*((LPBYTE)lpDIBBitsResult + nResultRowBytes*(y) +
(x/8)) |= mask;
break;
case 4:
mask = *((LPBYTE)lpDIBBits + nRowBytes*sourcey +
sourcex/2) & ((sourcex&1) ? 0x0f : 0xf0);
//Adjust mask for destination bitmap
if( (sourcex&1) != (x&1) )
mask = (mask&0xf0) ? (mask>>4) : (mask<<4);
*((LPBYTE)lpDIBBitsResult + nResultRowBytes*(y) +
(x/2)) &= ~((x&1) ? 0x0f : 0xf0);
*((LPBYTE)lpDIBBitsResult + nResultRowBytes*(y) +
(x/2)) |= mask;
break;
case 8:
BYTE pixel ;
pixel = *((LPBYTE)lpDIBBits + nRowBytes*sourcey +
sourcex);
*((LPBYTE)lpDIBBitsResult + nResultRowBytes*(y) +
(x)) = pixel;
break;
case 16:
DWORD dwPixel;
dwPixel = *((LPWORD)((LPBYTE)lpDIBBits +
nRowBytes*sourcey + sourcex*2));
*((LPWORD)((LPBYTE)lpDIBBitsResult +
nResultRowBytes*y + x*2)) = (WORD)dwPixel;
break;
case 24:
dwPixel = *((LPDWORD)((LPBYTE)lpDIBBits +
nRowBytes*sourcey + sourcex*3)) & 0xffffff;
*((LPDWORD)((LPBYTE)lpDIBBitsResult +
nResultRowBytes*y + x*3)) |= dwPixel;
break;
case 32:
dwPixel = *((LPDWORD)((LPBYTE)lpDIBBits +
nRowBytes*sourcey + sourcex*4));
*((LPDWORD)((LPBYTE)lpDIBBitsResult +
nResultRowBytes*y + x*4)) = dwPixel;
}
}
else
{
// Draw the background color. The background color
// has already been drawn for 8 bits per pixel and less
switch(bpp)
{
case 16:
*((LPWORD)((LPBYTE)lpDIBBitsResult +
nResultRowBytes*y + x*2)) =
(WORD)dwBackColor;
break;
case 24:
*((LPDWORD)((LPBYTE)lpDIBBitsResult +
nResultRowBytes*y + x*3)) |= dwBackColor;
break;
case 32:
*((LPDWORD)((LPBYTE)lpDIBBitsResult +
nResultRowBytes*y + x*4)) = dwBackColor;
break;
}
}
}
}

return hDIBResult;
}
源码链接: https://pan.quark.cn/s/0f7c75cb3aad ### MIPI Video Mode 与 Command Mode 的差异 #### 一、引言 MIPI (Mobile Industry Processor Interface) 是一种用于连接移动设备中处理器及其外围设备的标准化接口。MIPI 接口支持多种协议,其中包含 DSI (Display Serial Interface) 和 DCS (Display Control Interface) 等协议。在 MIPI 接口的应用中,主要涉及两种工作模式:Video Mode(视频模式)和 Command Mode(命令模式)。本文旨在系统性地阐述这两种模式的工作机制、特性以及实际应用环境。 #### 二、LCD RAM 概念说明 在进一步探讨 MIPI 的两种模式之前,有必要对文中提及的“LCD RAM”概念进行明确。实际上,“LCD RAM”并非一个通用术语,而是本文作者用来描述 LCD 控制器中用于存储显示数据的内存区域。LCD(Liquid Crystal Display,液晶显示屏)通常配备一个控制 IC(Integrated Circuit,集成电路),该控制 IC 可能内置 RAM 以缓存显示数据。 #### 三、MIPI Video Mode(视频模式) **定义:** - 视频模式是一种类似于传统 RGB 接口的工作模式,它要求主机持续不断地向显示器传输刷新数据。 - 在这种模式下,数据和控制信号以报文的形式通过 MIPI 总线进行传输。 - 显示器本身无需配备帧缓冲器,因为主机会周期性地刷新屏幕。 **特点:** 1. **实时性高:** 主机需要不...
源码下载地址: https://pan.quark.cn/s/a4b39357ea24 在电磁模拟技术中,CST(Computer Simulation Technology)是一种被广泛采纳的软件工具,它主要用于电磁场、微波、天线以及射频系统的设计工作。本资料将详细分析CST软件中离散端口的具体配置方法,这些方法对于提升仿真结果的精确度和专业水准具有决定性作用。离散端口在CST软件中扮演着模拟信号输入或输出的重要角色,它们构成了仿真模型不可或缺的部分。在配置离散端口时,一个核心的原则是保证端口的方向与网格线保持一致,这是因为这样做能够有效降低计算过程中产生的误差,并确保仿真数据的有效性。如果未能遵循这一指导原则,可能会引发未知的计算问题,进而导致仿真结果失去可靠性。 在CST软件中配置离散端口,通常需要借助“Pick Points”这一功能。通过选择“Pick Edge Center”选项,端口将被设定在模型边缘的中心位置上。然而,这种做法并不总是能够确保端口与网格线保持平行。在某些特定情形下,模型的几何构造可能不允许直接选取一个与网格线平行的边作为端口的安装位置。 为了克服这一挑战,可以采用多种不同的策略。如果模型本身已经包含一条与馈电口平行的边,那么可以直接利用这条边来建立端口,此时CST软件会自动调整端口使其与网格线对齐。另一种可选的方法是,当模型不具备现成的平行边时,用户可以手动构建一个几何结构,比如一个立方体,并使其边缘与馈电口平行。通过这种方式,新建立的几何结构的边缘就可以作为端口的位置,从而确保端口与网格线的平行关系。 在实施上述操作时,必须关注端口尺寸的合理性和物理意义的一致性。端口的尺寸应当依据实际天线馈电部分的尺寸进行适当调整,过大的端口或...
代码下载链接: https://pan.quark.cn/s/a4b39357ea24 【使用TensorFlow进行图像识别】 图像识别作为计算机视觉领域的关键任务之一,其核心在于通过算法解析和理解图像所包含的信息。在此资源中,我们将集中探讨如何借助功能强大的深度学习框架TensorFlow来执行手写数字识别。手写数字识别构成了众多实际应用的基础,例如自动支票处理、光学字符识别(OCR)等场景。 TensorFlow是由Google创建的一个开源库,它主要用于数值运算和机器学习,尤其在深度学习方面表现卓越。其核心优势在于可以构建并训练复杂的神经网络架构,并且在多种硬件环境中实现高效执行,涵盖CPU和GPU平台。 在此实践项目中,我们将运用TensorFlow来构建一个卷积神经网络(CNN)模型,这种架构是处理图像数据的理想选择。CNNs通过模仿人脑视觉皮层的运作机制,能够自主地提取图像中的关键特征,进而达成识别目标。在手写数字识别的特定情境下,这些特征可能涉及笔画的几何形态、走向以及相互间的连接模式。 对于CNN的基础结构,我们需要具备相应的认知,其通常由卷积层、池化层、全连接层以及激活函数等部分组成。卷积层借助滤波器(亦称卷积核)对图像进行扫描,以捕捉局部特征;池化层则用于降低数据维度,同时保留核心信息;全连接层将特征向量映射至各类别的概率分布;而激活函数如ReLU则通过引入非线性元素,使模型能够学习更为复杂的模式。 在此案例中,建议采用MNIST数据集,这是一个广泛用于手写数字识别的标准测试集。该数据集包含60,000个训练样本和10,000个测试样本,每个样本均为28x28像素的灰度图像,代表0到9这十个数字中的某一个。为了训练模型,必须首先加载数据,并...

16,550

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC相关问题讨论
社区管理员
  • 基础类社区
  • Creator Browser
  • encoderlee
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

        VC/MFC社区版块或许是CSDN最“古老”的版块了,记忆之中,与CSDN的年龄几乎差不多。随着时间的推移,MFC技术渐渐的偏离了开发主流,若干年之后的今天,当我们面对着微软的这个经典之笔,内心充满着敬意,那些曾经的记忆,可以说代表着二十年前曾经的辉煌……
        向经典致敬,或许是老一代程序员内心里面难以释怀的感受。互联网大行其道的今天,我们期待着MFC技术能够恢复其曾经的辉煌,或许这个期待会永远成为一种“梦想”,或许一切皆有可能……
        我们希望这个版块可以很好的适配Web时代,期待更好的互联网技术能够使得MFC技术框架得以重现活力,……

试试用AI创作助手写篇文章吧