#define GetImageSize(width,height,nCount) ((width*nCount+31)/32)*4*height
#define OPENBMP(n) "d:\\bmp\\"#n".bmp"
#define SAVEBMP(n) "d:\\bmp\\"#n"R.bmp"
typedef struct tagRotateINfo
{
INT nWidth;
INT nHeight;
VOID *pScan0; // pointer to first scanline
INT nBpp; // bits per pixel
INT nSrcStride; // distance between scanlines of Src
INT nDstStride; // distance between scanlines of dst
VOID *pDst; // pointer to destination
}ROTATEINFO, *LPROTATEINFO;
BOOL CRotateImageDoc::Rotateclockwise90()
{
// read image file
CFile file;
if (!file.Open(OPENBMP(1), CFile::modeRead) )
{
return FALSE;
}
// get file header
BITMAPFILEHEADER FileHeader ={0};
file.Read(&FileHeader, sizeof(BITMAPFILEHEADER));
if (FileHeader.bfType != ((WORD) ('M' << 8) | 'B'))
{
return FALSE;
}
// get bitmap info
DWORD dwBmpInfo = FileHeader.bfOffBits - sizeof(BITMAPFILEHEADER);
DWORD dwRgb = dwBmpInfo - sizeof(BITMAPINFOHEADER);
//apply memory
LPBITMAPINFO pBmpInfo = (LPBITMAPINFO)new BYTE[dwBmpInfo];
if (pBmpInfo == NULL)
{
file.Close();
return FALSE;
}
memset(pBmpInfo, 0, sizeof(BYTE)*dwBmpInfo);
file.Read(pBmpInfo, dwBmpInfo);
if (pBmpInfo->bmiHeader.biBitCount >= 8 && pBmpInfo->bmiHeader.biCompression!=0)
{
file.Close();
return FALSE;
}
// Get image data line by line
DWORD dwWidth = pBmpInfo->bmiHeader.biWidth;
DWORD dwHeight = pBmpInfo->bmiHeader.biHeight;
WORD wBitCount = pBmpInfo->bmiHeader.biBitCount;
DWORD dwSrcSize = GetImageSize(dwWidth, dwHeight, wBitCount);
DWORD dwDstSize = GetImageSize(dwHeight, dwWidth, wBitCount);
LPBYTE pSrcData = new BYTE[dwSrcSize];
LPBYTE pDstData = new BYTE[dwDstSize];
ASSERT(NULL != pSrcData && NULL != pDstData);
ZeroMemory(pSrcData, sizeof(BYTE)*dwSrcSize);
ZeroMemory(pDstData, sizeof(BYTE)*dwDstSize);
DWORD dwColorTable = dwRgb/sizeof(RGBQUAD);
RGBQUAD *pRgbQuad = new RGBQUAD[dwColorTable];
ASSERT(NULL != pRgbQuad);
ZeroMemory(pRgbQuad, dwRgb);
// read
LPBYTE lpTemp = pSrcData;
INT nSrcStride = ((dwWidth*wBitCount+31)/32)*4;
INT nDstStride = ((dwHeight*wBitCount+31)/32)*4;
for (DWORD i = 0; i < dwHeight; ++i)
{
file.Read(lpTemp, nSrcStride);
lpTemp += nSrcStride;
}
file.Seek(sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER), CFile::begin);
file.Read(pRgbQuad, dwRgb);
file.Close();
// set rotate infomation
ROTATEINFO RoInfo = {0};
RoInfo.nWidth = pBmpInfo->bmiHeader.biWidth;
RoInfo.nHeight = pBmpInfo->bmiHeader.biHeight;
RoInfo.pScan0 = pSrcData;
RoInfo.pDst = pDstData;
RoInfo.nBpp = pBmpInfo->bmiHeader.biBitCount;
RoInfo.nSrcStride = nSrcStride;
RoInfo.nDstStride = nDstStride;
RotateImage(RoInfo);
// store file
CFile fileW;
fileW.Open(SAVEBMP(1), CFile::modeCreate|CFile::modeReadWrite);
// write head info
fileW.Write(&FileHeader, sizeof(BITMAPFILEHEADER));
// write bitmap info
pBmpInfo->bmiHeader.biWidth = RoInfo.nHeight;
pBmpInfo->bmiHeader.biHeight = RoInfo.nWidth;
fileW.Write(pBmpInfo, dwBmpInfo);
// write file data line by line
lpTemp = (LPBYTE)RoInfo.pDst;
for (i = 0; i < dwWidth; ++i)
{
fileW.Write(lpTemp, nDstStride);
lpTemp += nDstStride;
}
fileW.Close();
return TRUE;
}
BOOL CRotateImageDoc::RotateImage(ROTATEINFO RoInfo)
{
//////////////////////////////////////////////////////////////////////////
/* I just support above 8 bits image,
the bits of 1,2,4, I will convert to 24 bits at first, then do them as normal*/
//////////////////////////////////////////////////////////////////////////
// get src prototype with color bits
// if bpp is 8 bits, the step is one byte; if bpp is 16 bits, the step is two bytes, as soon on.
INT nStep = RoInfo.nBpp / 8;
INT nSrcStride = RoInfo.nSrcStride;
INT nDstStride = RoInfo.nDstStride;
INT nDiff = nSrcStride - RoInfo.nWidth*nStep;
// check the src and dst are validate both.
ASSERT(NULL != RoInfo.pScan0 && NULL != RoInfo.pDst);
LPBYTE pSrcLine = (LPBYTE)RoInfo.pScan0, pDstLine = (LPBYTE)RoInfo.pDst; //pointer to working line of Src & Dst buffer
LPBYTE pSrcPixel = NULL, pDstPixel = NULL; //pointer to working pixel of Src & Dst buffer
for (INT i = 0; i < RoInfo.nHeight; ++i)
{
pSrcPixel = pSrcLine + (nSrcStride - nStep - nDiff);
pDstPixel = pDstLine;
for (INT j = 0; j < RoInfo.nWidth; ++j)
{
memcpy(pDstPixel, pSrcPixel, nStep);
pDstPixel += nDstStride;
pSrcPixel -= nStep;
}
//get next line
pSrcLine += nSrcStride;
pDstLine += nStep;
}
return TRUE;
}
It taken me about three hours, too long!
Hope I can do it better next time.