bmp图像的90度旋转

从网上搜到的,原链接没有说明原始出处, 感谢原作者和转载者
代码中的注释是根据自己的理解改写的

delphi 图像旋转 - 酷联云视 - 博客园 (cnblogs.com) 

一开始是用canvas.pixel处理, 实在是太慢, 又搜到了这个scanline方式的, 实测逆时针90度旋转好用, 就又改了一个顺时针90度旋转的, 原文是针对正常的24位的bmp图, 这个已经修改为用于8位bmp图形文件
(对delphi一知半解, 最后是试出来的, 前后花了近两天时间;中间还被迫使用三次逆时针90度来代替顺时针90度, 实在是汗... 好在最后还是能用了)

procedure rotate2(bmpfilename: PChar); stdcall;    //逆时针旋转
var
  sourcebmp: Graphics.TBitmap;
  nIdx, nOfs, x, y, i, nMultiplier: integer;
  nMemWidth, nMemHeight, nMemSize, nScanLineSize: LongInt;
  aScnLnBuffer: PChar;
  aScanLine: PByteArray;
begin

  sourcebmp := Graphics.TBitmap.Create();
  sourcebmp.LoadFromFile(bmpfilename);

  nMultiplier := 1;
  nMemWidth := sourcebmp.Height;
  nMemHeight := sourcebmp.Width;
  //实际需要内存大小
  nMemSize := nMemWidth * nMemHeight * nMultiplier;
  //开辟内存
  GetMem(aScnLnBuffer, nMemSize);
  try
    //Scanline的长度
    nScanLineSize := sourcebmp.Width * nMultiplier;
    //为ScanLine分配内存
    GetMem(aScanLine, nScanLineSize);
    try

      //从sourcebmp, 通过byte数组 向缓冲区导入数据
      for y := 0 to sourcebmp.Height - 1 do
      begin
        //1.把source中的行, 逐行复制到byte数组中
        Move(sourcebmp.ScanLine[y]^, aScanLine^, nScanLineSize);
        for x := 0 to sourcebmp.Width - 1 do
        begin//2.宽和高交换,逆时针旋转
          nIdx := ((sourcebmp.Width - 1) - x) * nMultiplier;
          nOfs := (x * nMemWidth * nMultiplier) + (y * nMultiplier);
          for i := 0 to nMultiplier - 1 do
            Byte(aScnLnBuffer[nOfs + i]) := aScanLine[nIdx + i];
        end;
      end;

      sourcebmp.Height := nMemHeight;
      sourcebmp.Width := nMemWidth;
      for y := 0 to nMemHeight - 1 do
      begin
        //缓冲区的数据写回sourcebmp
        nOfs := y * nMemWidth * nMultiplier;
        Move((@(aScnLnBuffer[nOfs]))^, sourcebmp.ScanLine[y]^, nMemWidth * nMultiplier);
      end;
      sourcebmp.SaveToFile(bmpfilename);
    finally
      //释放内存aScanLine
      FreeMem(aScanLine, nScanLineSize);
    end;
  finally
    //释放内存aScnLnBuffer
    FreeMem(aScnLnBuffer, nMemSize);
  end;
  sourcebmp.Free;
end;

procedure rotate(bmpfilename: PChar); stdcall;    //顺时针旋转
var
  sourcebmp: Graphics.TBitmap;
  nIdx, nOfs, x, y, i, nMultiplier: integer;
  nMemWidth, nMemHeight, nMemSize, nScanLineSize: LongInt;
  aScnLnBuffer: PChar;
  aScanLine: PByteArray;
begin

  sourcebmp := Graphics.TBitmap.Create();
  sourcebmp.LoadFromFile(bmpfilename);

  nMultiplier := 1;
  nMemWidth := sourcebmp.Height;
  nMemHeight := sourcebmp.Width;
  //实际需要内存大小
  nMemSize := nMemWidth * nMemHeight * nMultiplier;
  //开辟内存
  GetMem(aScnLnBuffer, nMemSize);
  try
    //Scanline的长度
    nScanLineSize := sourcebmp.Width * nMultiplier;
    //为ScanLine分配内存
    GetMem(aScanLine, nScanLineSize);

    try
    
      //从sourcebmp, 通过byte数组 向缓冲区导入数据
      for y := 0 to sourcebmp.Height - 1 do
      begin
        //1.把source中的行, 逐行复制到byte数组中
        Move(sourcebmp.ScanLine[y]^, aScanLine^, nScanLineSize);
        for x := 0 to sourcebmp.Width - 1 do
        begin   //2.宽和高交换,顺时针旋转
          nIdx := x * nMultiplier;
          nOfs := (x * nMemWidth * nMultiplier) + ((sourcebmp.Height - 1 - y) * nMultiplier);
          for i := 0 to nMultiplier - 1 do
            Byte(aScnLnBuffer[nOfs + i]) := aScanLine[nIdx + i];
        end;
      end;

      //缓冲区的数据写回sourcebmp
      sourcebmp.Height := nMemHeight;
      sourcebmp.Width := nMemWidth;
      for y := 0 to nMemHeight - 1 do
      begin
        //通过byte数组的方式, 逐行写回sourcebmp
        nOfs := y * nMemWidth * nMultiplier;
        Move((@(aScnLnBuffer[nOfs]))^, sourcebmp.ScanLine[y]^, nMemWidth * nMultiplier);
      end;
      sourcebmp.SaveToFile(bmpfilename);
    finally
      //释放内存aScanLine
      FreeMem(aScanLine, nScanLineSize);
    end;

  finally
    //释放内存aScnLnBuffer
    FreeMem(aScnLnBuffer, nMemSize);
  end;
  
  sourcebmp.Free;

end;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
bmp图像旋转90可以通过以下步骤来实现: 1. 读取bmp图像的头文件,获取图像的宽、高、像素位数等信息; 2. 创建一个新的bmp图像文件,将宽和高交换,像素位数保持不变; 3. 逐行读取原始bmp图像中的像素数据,并将其逆时针旋转90后写入新的bmp图像中; 4. 保存新的bmp图像文件。 以下是一个简单的C++代码示例,可以实现bmp图像逆时针旋转90: ```c++ #include <iostream> #include <fstream> #include <vector> using namespace std; #pragma pack(push, 1) // 定义bmp文件头结构体 struct BMPFileHeader { char type[2]; uint32_t size; uint16_t reserved1; uint16_t reserved2; uint32_t offbits; }; // 定义bmp信息头结构体 struct BMPInfoHeader { uint32_t size; int32_t width; int32_t height; uint16_t planes; uint16_t bit_count; uint32_t compression; uint32_t size_image; int32_t x_pels_per_meter; int32_t y_pels_per_meter; uint32_t clr_used; uint32_t clr_important; }; // 定义RGB颜色结构体 struct RGBColor { uint8_t b; uint8_t g; uint8_t r; }; #pragma pack(pop) // 将bmp图像逆时针旋转90 void rotateImage(const char* input_filename, const char* output_filename) { // 打开原始bmp图像文件 ifstream input_file(input_filename, ios::binary); if (!input_file) { cerr << "Failed to open input file!" << endl; return; } // 读取bmp文件头信息 BMPFileHeader file_header; input_file.read(reinterpret_cast<char*>(&file_header), sizeof(BMPFileHeader)); // 读取bmp信息头信息 BMPInfoHeader info_header; input_file.read(reinterpret_cast<char*>(&info_header), sizeof(BMPInfoHeader)); // 获取原始bmp图像的宽和高 int32_t width = info_header.width; int32_t height = info_header.height; // 创建新的bmp图像文件 ofstream output_file(output_filename, ios::binary); if (!output_file) { cerr << "Failed to create output file!" << endl; return; } // 将宽和高互换,像素位数不变 info_header.width = height; info_header.height = width; // 写入新的bmp文件头信息 output_file.write(reinterpret_cast<const char*>(&file_header), sizeof(BMPFileHeader)); output_file.write(reinterpret_cast<const char*>(&info_header), sizeof(BMPInfoHeader)); // 计算每行像素数据的字节数 int row_size = (width * 3 + 3) & (~3); // 分配缓冲区用于存储一行像素数据 vector<RGBColor> row_data(row_size / 3); // 逐行读取原始bmp图像中的像素数据,并将其逆时针旋转90后写入新的bmp图像中 for (int y = 0; y < height; ++y) { // 读取一行像素数据 input_file.read(reinterpret_cast<char*>(row_data.data()), row_size); // 逐列将像素数据写入新的bmp图像中 for (int x = 0; x < width; ++x) { RGBColor color = row_data[x]; output_file.write(reinterpret_cast<const char*>(&color), sizeof(RGBColor)); } } // 关闭文件 input_file.close(); output_file.close(); } int main() { rotateImage("input.bmp", "output.bmp"); return 0; } ``` 需要注意的是,该示例代码只适用于24位真彩色的bmp图像。如果bmp图像的像素位数不同,需要对代码进行相应的修改。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值