node 16位 转24位_同时将24位和32位BMP图像顺时针旋转90度

上一次我们将24位的皮卡丘旋转了90度,但是后来改需求了。。。要求把32位的.bmp文件也能够旋转90度。上次就懵逼的我继续懵逼,只好继续转向CSDN求助。

1d94b55028db531090d62c9f6c0090b4.png

浏览了各种求助帖(还找到了数年前的信科大一学长),终于发现了32位和24位的区别:32位图的每一个像素信息占4个字节,除了RGB三个颜色值以外,还有一个字节存储的是透明度。在读取和写入32位图的时候,每一个像素就要多读(写)一个字节。这就导致了24位和32位的DATA结构体不一样。如果定义两个DATA结构体,之后每次涉及到它的时候都要判断一下图的位数,好像很麻烦的亚子。为了解决这个问题,我们就不得不放弃上一次所用的DATA结构体了 。

//Farewell my DATA~
struct DATA
{
    BYTE blue;
    BYTE green;
    BYTE red;
};

我们转而直接按字节(BYTE)读取,不再将一个像素的信息装在结构体中,而是将其分开读取。需要在原来的代码上做一些改变,先把所有DATA类型的指针改为BYTE类型,分配存储空间的时候把空间大小也调整一下。

//32位就分配size*4,24位就分配size*3
BYTE *imgdata=new BYTE[size * srcInfo.biBitCount / 8];

然后我们把原来代码中的所有数字3改成biBitCount/8:

fread(imgdata + i * w * srcInfo.biBitCount / 8, srcInfo.biBitCount / 8, w, p);

这里因为imgdata的类型已经是unsigned char*了,只占1个字节,所以不用再进行指针类型转换(char*)了。

原先在旋转操作中赋值的时候只用赋值一次,就能将DATA结构体赋值给新的target指针。但现在没有DATA结构体了,我们就需要对每个像素的字节依次赋值:

for (int i=0; i<newH; i++){
        for (int j=0; j<newW; j++){
            *(target + (i * newW + j)*newInfo.biBitCount / 8) = *(src + (j * w + newH - i - 1)*newInfo.biBitCount / 8);
            *(target + (i * newW + j)*newInfo.biBitCount / 8 + 1) = *(src + (j * w + newH - i - 1)*newInfo.biBitCount / 8 + 1);
            *(target + (i * newW + j)*newInfo.biBitCount / 8 + 2) = *(src + (j * w + newH - i - 1)*newInfo.biBitCount / 8 + 2);
            if (newInfo.biBitCount == 32) {
                *(target + (i * newW + j) * newInfo.biBitCount / 8 + 3) =
                        *(src + (j * w + newH - i - 1) * newInfo.biBitCount / 8 + 3);
            }
        }
    }

这样主体就完成了,但是如果只修改这些的话,会发现最终生成的32位图无法打开。原因在于32位图和24位图的信息头有一点点差异:多了一些不知道是啥的内容。我们就把这些东西放在一个新的结构体Plus里吧。在读取和写入的时候判断一下图像位数,如果是32位就把这个Plus也读/写一下。

struct Plus{
    DWORD        bV5RedMask;
    DWORD        bV5GreenMask;
    DWORD        bV5BlueMask;
    DWORD        bV5AlphaMask;
    DWORD        bV5CSType;
    CIEXYZTRIPLE bV5Endpoints;
    DWORD        bV5GammaRed;
    DWORD        bV5GammaGreen;
    DWORD        bV5GammaBlue;
    DWORD        bV5Intent;
    DWORD        bV5ProfileData;
    DWORD        bV5ProfileSize;
    DWORD        bV5Reserved;
};

Plus的内容来自CSDN,其中那个醒目的CIEXYZTRIPLE是啥...我也不知道 。所以只好开始了漫长的搜索之路,最终找到了他的定义:

c45985dc94bcc0d26f55e266cf378f6b.png
CIEXYZTRIPLE的定义

图中FXPT2DOT30表示它们是带有2位元整数部分和30位元小数部分的定点值,这说的是啥我也不懂,只需要知道FXPT2DOT30其实就和int差不多就好了:

typedef int FXPT2DOT30;

现在就把所有东西全部定义好了,试着转一下这个年代久远的32位图:

ce7171cd979bc6b7d65c49dcf4411c41.png
原图

0d8c5e030fc8a74bd51c3ba7c88446e3.png
顺时针旋转90度

最后附上完整的代码:

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;

typedef unsigned char BYTE;
typedef unsigned short WORD;
typedef unsigned int DWORD;
typedef int FXPT2DOT30;

typedef struct tagCIEXYZ
{
    FXPT2DOT30 ciexyzX ;
    FXPT2DOT30 ciexyzY ;
    FXPT2DOT30 ciexyzZ ;
}
CIEXYZ, * LPCIEXYZ ;

typedef struct tagCIEXYZTRIPLE {
    CIEXYZ ciexyzRed ;
    CIEXYZ ciexyzGreen ;
    CIEXYZ ciexyzBlue ;
}CIEXYZTRIPLE;

//位图文件头定义;
struct  Header{
    DWORD bfSize;//文件大小
    WORD bfReserved1;//保留字
    WORD bfReserved2;//保留字
    DWORD bfOffBits;//从文件头到实际位图数据的偏移字节数
};

//位图信息头定义
struct Info{
    DWORD biSize;//信息头大小
    DWORD biWidth;//图像宽度
    DWORD biHeight;//图像高度
    WORD biPlanes;//位平面数,必须为1
    WORD biBitCount;//每像素位数
    DWORD  biCompression; //压缩类型
    DWORD  biSizeImage; //压缩图像大小字节数
    DWORD  biXPelsPerMeter; //水平分辨率
    DWORD  biYPelsPerMeter; //垂直分辨率
    DWORD  biClrUsed; //位图实际用到的色彩数
    DWORD  biClrImportant; //本位图中重要的色彩数
};

struct Plus{
    DWORD        bV5RedMask;
    DWORD        bV5GreenMask;
    DWORD        bV5BlueMask;
    DWORD        bV5AlphaMask;
    DWORD        bV5CSType;
    CIEXYZTRIPLE bV5Endpoints;
    DWORD        bV5GammaRed;
    DWORD        bV5GammaGreen;
    DWORD        bV5GammaBlue;
    DWORD        bV5Intent;
    DWORD        bV5ProfileData;
    DWORD        bV5ProfileSize;
    DWORD        bV5Reserved;
};

WORD bfType;//文件类型
Header srcHead;//原文件文件头
Info srcInfo;//原文件信息头
Plus srcPlus;
int h,w,size;//原图像的高度、宽度和尺寸

int getDiff(Info & info)
{
    int DataSizePerline = (info.biWidth * info.biBitCount+31) / 8;
    DataSizePerline -= DataSizePerline % 4;
    return DataSizePerline - info.biWidth * info.biBitCount / 8;
}

void rotation(const BYTE* src){
    int newH = w;
    int newW = h;//图片旋转90度之后宽度、高度互换
    int newSize = newH * newW;

    FILE *p;
    p=fopen("dest.bmp","wb");
    Header newHead = srcHead;
    Info newInfo = srcInfo;
    Plus newPlus = srcPlus;


    //修改旋转后图片的尺寸、宽度和高度
    newHead.bfSize = (DWORD)(newHead.bfSize);
    newInfo.biHeight = (DWORD)newH;
    newInfo.biWidth = (DWORD)newW;
    int newdiff = getDiff(newInfo);
    newInfo.biSizeImage = (DWORD)((newInfo.biWidth * newInfo.biBitCount / 8 + newdiff) * newInfo.biHeight);

    //将种类、文件头、信息头写入新bmp文件
    fwrite(&bfType,1, sizeof(WORD),p);
    fwrite(&newHead,1, sizeof(Header),p);
    fwrite(&newInfo,1, sizeof(Info),p);
    if (newInfo.biBitCount == 32){
        fwrite(&newPlus, 1, sizeof(Plus), p);
    }

    BYTE* target = new BYTE[newSize * newInfo.biBitCount / 8];
    for (int i=0; i<newH; i++){
        for (int j=0; j<newW; j++){
            *(target + (i * newW + j)*newInfo.biBitCount / 8) = *(src + (j * w + newH - i - 1)*newInfo.biBitCount / 8);
            *(target + (i * newW + j)*newInfo.biBitCount / 8 + 1) = *(src + (j * w + newH - i - 1)*newInfo.biBitCount / 8 + 1);
            *(target + (i * newW + j)*newInfo.biBitCount / 8 + 2) = *(src + (j * w + newH - i - 1)*newInfo.biBitCount / 8 + 2);
            if (newInfo.biBitCount == 32) {
                *(target + (i * newW + j) * newInfo.biBitCount / 8 + 3) =
                        *(src + (j * w + newH - i - 1) * newInfo.biBitCount / 8 + 3);
            }
        }
    }

    for (int i=0; i<newH; i++){
        fwrite(target + i * newW * (newInfo.biBitCount / 8), newInfo.biBitCount / 8, newW, p);
        fseek(p, newdiff, SEEK_CUR);
    }

    fclose(p);
    delete []target;
}

int main(){
    FILE* p;
    p = fopen("src.bmp", "rb");
    if (p != NULL){
        //先读取文件类型
        fread(&bfType, 1, sizeof(WORD), p);
        //读取bmp文件的文件头和信息头
        fread(&srcHead,1, sizeof(Header), p);
        fread(&srcInfo,1, sizeof(Info), p);
        if (srcInfo.biBitCount == 32){
            fread(&srcPlus, 1, sizeof(Plus), p);
        }
        h=srcInfo.biHeight;
        w=srcInfo.biWidth;
        size = w * h;

        BYTE *imgdata=new BYTE[size * srcInfo.biBitCount / 8];
        int diff = getDiff(srcInfo);

        //读取原图片像素信息
        for (int i=0;i<h;i++){
            fread(imgdata + i * w * srcInfo.biBitCount / 8, srcInfo.biBitCount / 8, w, p);
            fseek(p, diff, SEEK_CUR);
        }
        fclose(p);
        rotation(imgdata);
        delete []imgdata;
    }
    else{
        cout<<"无法打开文件"<<endl;
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
void CExample10View::OnSave555BiBitfields() { // TODO: Add your command handler code here if(lpBmpDataBuf==NULL) { MessageBox("当前没有打开的位图"); return; } BYTE r,g,b; LPBYTE lpDest,lpSrc; int i,j; int nheapSize; CFileDialog filesavebox(FALSE,"bmp","BI_BITFIELDS.bmp",OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT,"files(*.bmp)|*.bmp|",NULL); CFile file; CString strPathname; if(m_bmi.biBitCount!=24) { MessageBox("当前打开的位图不是24位位图"); return; } memcpy(&m_newbmf,&m_bmf,sizeof(BITMAPFILEHEADER)); memcpy(&m_newbmi,&m_bmi,sizeof(BITMAPINFOHEADER)); m_newbmi.biBitCount=16; m_newbmi.biCompression=BI_BITFIELDS;//即3 m_newbmi.biSizeImage=WIDTHBYTES(m_newbmi.biWidth,m_newbmi.biBitCount)*m_newbmi.biHeight; m_newbmf.bfSize=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+sizeof(DWORD)*3 +WIDTHBYTES(m_newbmi.biWidth,m_newbmi.biBitCount)*m_newbmi.biHeight; m_newbmf.bfOffBits=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+sizeof(DWORD)*3; nheapSize=sizeof(BITMAPINFOHEADER)+sizeof(DWORD)*3 +WIDTHBYTES(m_newbmi.biWidth,m_newbmi.biBitCount)*m_newbmi.biHeight; if(lpnewBmpDataBuf!=NULL) { delete []lpnewBmpDataBuf; lpnewBmpDataBuf=NULL; } lpnewBmpDataBuf=new BYTE[nheapSize]; memcpy(lpnewBmpDataBuf,&m_newbmi,sizeof(BITMAPINFOHEADER)); DWORD* lp=(DWORD*)(lpnewBmpDataBuf+sizeof(BITMAPINFOHEADER)); *lp++=0x00007c00; *lp++=0x000003e0; *lp =0x0000001f; for(i=0;i<m_newbmi.biHeight;i++) { for(j=0;j<m_newbmi.biWidth;j++) { lpSrc=lpBmpDataBuf+sizeof(BITMAPINFOHEADER) +WIDTHBYTES(m_bmi.biWidth,m_bmi.biBitCount)*(m_bmi.biHeight-1-i) +j*3; lpDest=lpnewBmpDataBuf+sizeof(BITMAPINFOHEADER)+sizeof(DWORD)*3 +WIDTHBYTES(m_newbmi.biWidth,m_newbmi.biBitCount)*(m_newbmi.biHeight-1-i) +j*2; b=*lpSrc++; b&=0xf8; g=*lpSrc++; g&=0xf8; r=*lpSrc++; r&=0xf8; WORD* lp=(WORD*)lpDest; *lp=0; *lp=r<<7; *lp+=(g<>3); } } if(filesavebox.DoModal()!=IDOK) return; strPath

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值