不正确的位图复制/输出

2023-11-29

因此,我在尝试读取任何 24bpp 位图图像并在同一文件夹中重新创建它时,无法准确弄清楚到底出了什么问题。它适用于一张图像,但不适用于我测试过的其他两张图像。从位图中读取时,我使用标头本身中找到的信息。可以说我有三个问题。 1)我是否正确读取位图? 2)我是否正确计算/使用/写入填充? 3)我输出正确吗? 第三,通过该图像及其输出确认否。

另外,为图像分配 2d 数组的原因是这样我可以稍后尝试将位图旋转 90 度。

不幸的是我无法发布图像,拍摄的图像来自这里,rgb_24bpp.bmphttp://pyglet.googlecode.com/svn/trunk/tests/image/

这是用于读取图像并计算填充的代码。

ifstream myBitmap("rgb_24bpp.bmp", ios::binary | ios::beg);

// Get the total file size in bytes, testing file access
begin = myBitmap.tellg();
myBitmap.seekg(0, ios::end);
end = myBitmap.tellg();

// Actually reading image file
myBitmap.seekg( 0, ios::beg);
myBitmap.read((char*)FileHeader, sizeof(BITMAPFILEHEADER));
myBitmap.read((char*)InfoHeader, sizeof(BITMAPINFOHEADER));
test = myBitmap.tellg();

RGBQUAD ** Image = new RGBQUAD*[InfoHeader->biWidth];
for (int i = 0; i < InfoHeader->biWidth; ++i) {
    Image[i] = new RGBQUAD[InfoHeader->biHeight];
}
int pitch = InfoHeader->biWidth * 3;

if (pitch % 4 != 0)
{
    pitch += 4 - (pitch % 4);
}

int padding = pitch - (InfoHeader->biWidth * 3);
cout << "padding: " << padding << endl;

myBitmap.seekg(FileHeader->bfOffBits, ios::beg);
for (int i = InfoHeader->biHeight; i > 0; --i) {
    for (int j = 0; j < InfoHeader->biWidth; ++j) {
        myBitmap.read((char*)&Image[j][i], sizeof(RGBQUAD));
    }
    if (padding != 0) myBitmap.read(PadBuffer, padding);
}
myBitmap.close();

begin/end/test 都是streampos 并打印在控制台上用于调试。 这是用于输出/重新创建图像的代码。

ofstream BitmapOut("Output.bmp");
BitmapOut.write((char*)FileHeader, sizeof(BITMAPFILEHEADER));
BitmapOut.write((char*)InfoHeader, sizeof(BITMAPINFOHEADER));
for (int i = InfoHeader->biHeight; i > 0; --i) {
    for (int j = 0; j < InfoHeader->biWidth; ++j) {
        BitmapOut.write((char*)&Image[j][i], sizeof(RGBQUAD));
    }
    if (padding != 0) BitmapOut.write("\0\0\0\0\0\0\0", padding);
}

BitmapOut.close();

我已经确认这两个标头确实正确,并且可以在 3 个不同的测试中正确地从中提取数据。 利用这个人的代码(抱歉,这个项目是非商业性的,仅供自学)。在 C++ 中读取 .bmp 文件

除了注释掉 RGBQUAD 中的保留并有效地制作 RGBTRI 之外。


你可以这样做。另外,如果你不想创建一个临时数组来复制像素,你可以轻松地读取、查找、读取、查找等。或者你可以一次读取所有内容。有很多方法可以读取位图并提高效率/降低效率。这取决于你想怎么做。另一种有效的方法是保存 BitmapInfoHeader 和 BitmapFileHeader。然后,当您决定将位图写入磁盘时,只需先写入标头,然后写入像素即可。更快更容易......在这个例子中我没有这样做。我将把这个问题留给你来解决。

这是我为回答您的问题而编写的示例代码。我更喜欢使用一维数组。

#include <fstream>
#include <cstring>
#include <windows.h>

typedef struct
{
    unsigned int width, height;
    unsigned char* pixels;
} Bitmap;

void InitBitmap(Bitmap* bmp)
{
    if (bmp)
    {
        bmp->width = 0;
        bmp->height = 0;
        bmp->pixels = NULL;
    }
}

void FreeBitmap(Bitmap* bmp)
{
    if (bmp && bmp->pixels)
    {
        bmp->width = 0;
        bmp->height = 0;
        delete[] bmp->pixels;
        bmp->pixels = NULL;
    }
}

bool ReadBitmap(const char* FilePath, Bitmap* bmp)
{
    std::fstream hFile(FilePath, std::ios::in | std::ios::binary);

    if (!bmp || !hFile.is_open())
        return false;

    BITMAPINFO Info;
    BITMAPFILEHEADER Header;
    memset(&Info, 0, sizeof(Info));
    memset(&Header, 0, sizeof(Header));

    hFile.read((char*)&Header, sizeof(Header));
    hFile.read((char*)&Info.bmiHeader, sizeof(Info.bmiHeader));

    bmp->width = Info.bmiHeader.biWidth;
    bmp->height = Info.bmiHeader.biHeight < 0 ? -Info.bmiHeader.biHeight : Info.bmiHeader.biHeight;
    size_t size = Info.bmiHeader.biSizeImage;

    bmp->pixels = new unsigned char[size];
    hFile.seekg(Header.bfOffBits, std::ios::beg);
    hFile.read((char*)bmp->pixels, size);
    hFile.close();

    return true;
}

bool WriteBitmap(const char* FilePath, Bitmap* bmp)
{
    std::fstream hFile(FilePath, std::ios::out | std::ios::binary);

    if (!bmp || !hFile)
        return false;

    BITMAPINFO Info;
    BITMAPFILEHEADER Header;
    memset(&Info, 0, sizeof(Info));
    memset(&Header, 0, sizeof(Header));

    Info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    Info.bmiHeader.biWidth = bmp->width;
    Info.bmiHeader.biHeight = bmp->height;
    Info.bmiHeader.biPlanes = 1;
    Info.bmiHeader.biBitCount = 24;
    Info.bmiHeader.biCompression = BI_RGB;
    Info.bmiHeader.biSizeImage = 0;
    Header.bfType = 0x4D42;
    Header.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
    size_t size = (((24 * bmp->width + 31) & ~31) / 8) * bmp->height;

    hFile.write((char*)&Header, sizeof(Header));
    hFile.write((char*)&Info.bmiHeader, sizeof(Info.bmiHeader));
    hFile.write((char*)bmp->pixels, size);
    hFile.close();
    return true;
}

int main()
{
    Bitmap bmp;
    InitBitmap(&bmp);

    ReadBitmap("C:/Users/Brandon/Desktop/foo.bmp", &bmp);
    WriteBitmap("C:/Users/Brandon/Desktop/foo2.bmp", &bmp);

    FreeBitmap(&bmp);
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

不正确的位图复制/输出 的相关文章

随机推荐

  • 您能解释一下 STA 和 MTA 吗?

    您能用自己的话解释一下STA和MTA吗 另外 什么是公寓线程 它们仅与 COM 相关吗 如果是这样 为什么 COM 线程模型称为 单元 模型 其中初始化的 COM 对象的执行上下文与单个线程 单线程单元 或多个线程 多线程单元 相关联 在此
  • 如何在 Fortran 中计算大整数?

    我需要生成一些大整数 请参见下面的示例 Input Result 40 165580141 80 37889062373143906 120 8670007398507948658051921 160 1983924214061919432
  • Spark 作业执行时间随着非常宽的数据集和列数呈指数增长[重复]

    这个问题已经存在了 我在 Spark 中创建了一个固定宽度的文件导入解析器 并对各种数据集执行了一些执行测试 它在最多 1000 列的情况下工作正常 但是 随着列数和固定宽度长度的增加 Spark 作业性能迅速下降 在20k列和固定宽度长度
  • 使用 JavaScript 访问变量对象的属性

    我有一个 js 对象 如下所示 var object divisions ocd division country us name United States 我想访问嵌套对象下列出的属性 ocd division country us 又
  • SSRS 中 PDF/打印报告的目录

    这是我所知道的 我知道文档图和书签可以在屏幕上使用 但不能在 pdf 中使用 SSRS 不具备将带页码的打印目录生成 pdf 的开箱即用功能 我知道可以通过将文档结构图导出到Word来生成TOC 这种方法不适用于我的情况 全局变量可以存储页
  • Margin 的左边距:自动元素 = 填充 100% 宽度溢出项目的左侧

    让我用下面的 HTML 来演示这个问题 section style text align center section
  • AngularJS 中 $broadcast()、$emit() 和 $on() 的用法

    我明白那个 Broadcast Emit And On 用于在一个控制器中引发事件并在另一个控制器中进行处理 如果可能的话 有人可以给我一些关于上述三个用法的实时示例吗 因为我是新手angular JS 我已浏览以下链接并了解基本用法 ht
  • 优化INSERT/UPDATE/DELETE操作

    我想知道是否可以以某种方式优化以下脚本 它确实向磁盘写入了大量数据 因为它删除了可能是最新的行并重新插入它们 我正在考虑应用诸如 在重复键更新时插入 之类的内容 并发现了单行更新的一些可能性 但我不知道如何在以下上下文中应用它INSERT
  • Firebase 数据库复制

    我需要来自 2 个 iOS 应用程序 具有不同捆绑名称 中的一个 Firebase 项目数据库的数据 所以 问题是 是否可以在 2 个不同的 Firebase 项目数据库之间配置复制 或者是否可以将 1 个 Firebase 项目 1 个数
  • TIBCO EMS 服务器是否管理重新连接?或者客户呢?

    TIBCO EMS NET 参考指南说 第 134 页 要启用重新连接行为和容错功能 serverURL 参数必须是两个或多个 URL 的逗号分隔列表 在只有一台服务器的情况下 您可以提供该服务器 URL 的两个副本以启用客户端重新连接 例
  • Python 向下舍入到自定义步骤

    我们有一个部分工作的代码和 2 个具有不同类型的自定义步骤的示例 示例 2 Int 有效 而示例 1 则无效 因为它是向上舍入而不是向下舍入 import math def step size to precision ss return
  • 涉及 char 数组的 C 语句的含义

    我正在为一个项目开发一种算法 并且遇到了一些我认为可能有用的代码 然而 当我尝试阅读代码时 我在理解代码中的语句时遇到了一些困难 这是代码 int firstWord MAX WORD SIZE 0 c 0 while word1 c 0
  • 使用 Vanilla Javascript 检测滚动以帮助更改导航 CSS [重复]

    这个问题在这里已经有答案了 我试图检测页面上的滚动是否超过高度为 80 像素的固定顶部导航的 100 像素 计划是 一旦用户的滚动超过上述 100 像素 导航栏将更改背景颜色 我看过很多关于这个主题的教程 但我看到的所有教程都是使用 Jqu
  • 在元素上使用重复的类名?

    我发现有很多框架会在元素上添加新类名之前检查重复的类名 我认为这会降低性能 当元素有重复的类名时会出现问题吗 当使用重复的类名时 它还会应用 CSS 类 而不会发生冲突 div class aa bb cc aa div 可以简单地添加一个
  • 创建计算器(JS)

    我有一条线calc 2 add 3 add 5 res 并需要写一个解决方案 以便我有10因此 我试过这个 class Calc constructor num this num num add a this num a return th
  • 带有自定义滚动条的自动完成 jquery UI 插件

    有人尝试为 jquery UI 自动完成小部件制作自定义滚动条吗 我正在尝试将 jScrollPane jquery 组件与自动完成小部件结合使用 但到目前为止没有取得任何成功 如果有人知道一些带有自定义滚动条的 jquery 自动完成组件
  • 将循环放入 C 宏中

    我正在寻找一种将以下函数结构转换为宏的方法 我知道 这是一个愚蠢且毫无意义的例子 但它说明了这一点 因为我无法给出我的实际源代码 int foo int x int y do x y while x gt y return x y note
  • 使用新数据重新渲染漏斗高图

    我在 MVC3 应用程序中使用 highcharts 并且在数据修改后尝试刷新 但图表不刷新 我绘制的图表如下 function initializeChart chart1 new Highcharts Chart chart rende
  • 使用 Apache FTPClient 检索文件时如何保留修改日期?

    我在用org apache commons net ftp FTPClient用于从 ftp 服务器检索文件 当文件保存在我的计算机上时 保留文件上最后修改的时间戳至关重要 有人对如何解决这个问题有建议吗 这就是我解决它的方法 public
  • 不正确的位图复制/输出

    因此 我在尝试读取任何 24bpp 位图图像并在同一文件夹中重新创建它时 无法准确弄清楚到底出了什么问题 它适用于一张图像 但不适用于我测试过的其他两张图像 从位图中读取时 我使用标头本身中找到的信息 可以说我有三个问题 1 我是否正确读取