在c中复制bmp

2023-12-07

背景:
我想将 bmp(未压缩的 24 RGB)图像从一个文件名复制到另一个文件名。我正在使用来自 TDM-GCC 的 mingw 编译器(版本 4.9.2,32 位,SJLJ),它带有代码块。

Problem:
程序适用于黑白图像和简单的彩色图像,但不适用于复杂的彩色图像。请查看所附图片。我没有足够的声誉来发布其他图像,因此我尝试发布 2 个最相关的图像。该程序无法复制 lenna 图像。这种行为的原因是什么?

Code:

 #include <stdio.h>
 #include <stdlib.h>
 #include <stdint.h>
 #pragma pack(1)

/*  The following is to access the DIB information
https://msdn.microsoft.com/en-us/library/cc230309.aspx
https://msdn.microsoft.com/en-us/library/dd183374(v=vs.85).aspx
https://msdn.microsoft.com/en-us/library/dd183376(v=vs.85).aspx */

typedef uint8_t  BYTE;
typedef uint32_t DWORD;
typedef int32_t  LONG;
typedef uint16_t WORD;

typedef struct
{
    WORD bfType;
    DWORD bfSize;
    WORD bfReserved1;
    WORD bfReserved2;
    DWORD bfOffBits;
}BITMAPFILEHEADER;

typedef struct
{
    DWORD biSize;
    LONG biWidth;
    LONG biHeight;
    WORD biPlanes;
    WORD biBitCount;
    DWORD biCompression;
    DWORD biSizeImage;
    LONG biXPelsPerMeter;
    LONG biYPelsPerMeter;
    DWORD biClrUsed;
    DWORD biClrImportant;
}BITMAPINFOHEADER;


typedef struct
{
    BYTE rgbtBlue;
    BYTE rgbtGreen;
    BYTE rgbtRed;
}RGBTRIPLE;

int main(void)
{
    char *infile = "testin.bmp";
    char *outfile = "testout.bmp";

    FILE *inptr = fopen(infile, "r");
    if (inptr == NULL)
    {
        fprintf(stderr, "Could not open %s.\n", infile);
        return 2;
    }

    FILE *outptr = fopen(outfile, "w");
    if (outptr == NULL)
    {
        fclose(inptr);
        fprintf(stderr, "Could not create %s.\n", outfile);
        return 3;
    }

    BITMAPFILEHEADER bf;
    fread(&bf, sizeof(BITMAPFILEHEADER), 1, inptr);

    BITMAPINFOHEADER bi;
    fread(&bi, sizeof(BITMAPINFOHEADER), 1, inptr);

    fwrite(&bf, sizeof(BITMAPFILEHEADER), 1, outptr);

    fwrite(&bi, sizeof(BITMAPINFOHEADER), 1, outptr);

    int padding = (4 - (bi.biWidth * sizeof(RGBTRIPLE)) % 4) % 4;

    int i, j, k, biHeight;

    for(i = 0, biHeight = abs(bi.biHeight); i < biHeight; i++)
    {
        for(j = 0; j < bi.biWidth; j++)
        {
        RGBTRIPLE triple;

        fread(&triple, sizeof(RGBTRIPLE), 1, inptr);

        fwrite(&triple, sizeof(RGBTRIPLE), 1, outptr);
        }
    }

    fseek(inptr, padding, SEEK_CUR);

    for(k = 0; k < padding; k++)
    {
        fputc(0x00, outptr);
    }

fclose(inptr);

fclose(outptr);

return 0;

}

输入图像:

input image

输出图像:

output image


我对所提供的数据进行了一些修改,我很确定发生了什么:

FILE *inptr = fopen(infile, "r");

and

FILE *outptr = fopen(outfile, "w");

以文本模式打开文件。

这是我从 Microsoft 的 C API 中了解到的一种特殊行为,似乎这也适用于 mingw TDM-GCC(我很难相信这一点,直到转储的数据让我相信我的怀疑是正确的)。

微软的C API中的文件I/O区分文本模式和二进制模式:

  • fopen(infile, "rt") and fopen(outfile, "wt")以文本模式打开文件。
  • fopen(infile, "rb") and fopen(outfile, "wb")以二进制模式打开文件。
  • fopen(infile, "r") and fopen(outfile, "w")默认为文本模式。

在文本模式下,文件读取会替换所有 Microsoft 行结束符 ("\r\n") 通过 Unix 行尾 ("\n")以及写作相反("\n"变成"\r\n").

如果内容是纯文本,这是合理的,但它可能会破坏二进制内容的输出,其中一个字节0x0d每当一个字节被插入0x0a(具有任何含义)发生在数据流中。

为了证明这一点,

  1. 我下载了您的示例文件(不幸的是以 PNG 格式上传)
  2. 将文件(回)转换为 24 位 BMP(使用 GIMP)
  3. 为每个进行了十六进制转储:

    $ hexdump -C IkW6FbN.bmp >IkW6FbN.bmp.txt
    
    $ hexdump -C jnxpTwE.bmp >jnxpTwE.bmp.txt
    
  4. 终于加载了IkW6FbN.bmp.txt and jnxpTwE.bmp.txt into WinMerge进行比较。

Snapshot of WinMerge showing where wrong contents start in output file

如快照所示,输入和输出文件的前 14037 (0x36d5) 字节具有相同的内容。然后,输入文件“意外”包含三个字节0a 0a 0a输出文件的位置0d 0a 0d 0a 0d 0a。因此,各个原始像素(以及所有后续像素)都会被损坏。

(正如您可能已经猜到的那样,0a是换行符的十六进制值'\n', 0d回车符之一'\r'.)

顺便提一句。输出文件可能比输入文件长一点(由于插入了 CR 字节)。 BMP 查看器可能会忽略这一点,因为 BMP 标头准确说明了原始图像需要多少字节(并且会忽略额外的字节)。

正如您可能已经认识到的那样,您应该更改fopen()打电话给

FILE *inptr = fopen(infile, "rb");

and

FILE *outptr = fopen(outfile, "wb");

解决您的问题。

顺便提一句。 *x 操作系统(例如 Linux)上的 C API 没有文本和二进制模式的区别。相反,b被简单地忽略(这有助于编写可移植代码)。

进一步阅读:cppreference.com 上的 fopen、fopen_s

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

在c中复制bmp 的相关文章

  • BASIC 中的 C 语言中的 PeekInt、PokeInt、Peek、Poke 等效项

    我想知道该命令的等效项是什么Peek and Poke 基本和其他变体 用 C 语言 类似PeekInt PokeInt 整数 涉及内存条的东西 我知道在 C 语言中有很多方法可以做到这一点 我正在尝试将基本程序移植到 C 语言 这只是使用
  • 在模板类中声明模板友元类时出现编译器错误

    我一直在尝试实现我自己的链表类以用于教学目的 我在迭代器声明中指定了 List 类作为友元 但它似乎无法编译 这些是我使用过的 3 个类的接口 Node h define null Node
  • free 和 malloc 在 C 中如何工作?

    我试图弄清楚如果我尝试 从中间 释放指针会发生什么 例如 看下面的代码 char ptr char malloc 10 sizeof char for char i 0 i lt 10 i ptr i i 10 ptr ptr ptr pt
  • 如何在 C++ 中标记字符串?

    Java有一个方便的分割方法 String str The quick brown fox String results str split 在 C 中是否有一种简单的方法可以做到这一点 The 增强分词器 http www boost o
  • 如何使从 C# 调用的 C(P/invoke)代码“线程安全”

    我有一些简单的 C 代码 它使用单个全局变量 显然这不是线程安全的 所以当我使用 P invoke 从 C 中的多个线程调用它时 事情就搞砸了 如何为每个线程单独导入此函数 或使其线程安全 我尝试声明变量 declspec thread 但
  • C++ 多行字符串原始文字[重复]

    这个问题在这里已经有答案了 我们可以像这样定义一个多行字符串 const char text1 part 1 part 2 part 3 part 4 const char text2 part 1 part 2 part 3 part 4
  • 需要帮助优化算法 - 两百万以下所有素数的总和

    我正在尝试做一个欧拉计划 http projecteuler net问题 我正在寻找 2 000 000 以下所有素数的总和 这就是我所拥有的 int main int argc char argv unsigned long int su
  • 访问外部窗口句柄

    我当前正在处理的程序有问题 这是由于 vista Windows 7 中增强的安全性引起的 特别是 UIPI 它阻止完整性级别较低的窗口与较高完整性级别的窗口 对话 就我而言 我想告诉具有高完整性级别的窗口进入我们的应用程序 它在 XP 或
  • 方程“a + bx = c + dy”的积分解

    在等式中a bx c dy 所有变量都是整数 a b c and d是已知的 我如何找到整体解决方案x and y 如果我的想法是正确的 将会有无限多个解 由最小公倍数分隔b and d 但我只需要一个解决方案 我可以计算其余的 这是一个例
  • C# xml序列化必填字段

    我需要将一些字段标记为需要写入 XML 文件 但没有成功 我有一个包含约 30 个属性的配置类 这就是为什么我不能像这样封装所有属性 public string SomeProp get return someProp set if som
  • 有没有办法让 doxygen 自动处理未记录的 C 代码?

    通常它会忽略未记录的 C 文件 但我想测试 Callgraph 功能 例如 您知道在不更改 C 文件的情况下解决此问题的方法吗 设置变量EXTRACT ALL YES在你的 Doxyfile 中
  • 相当于Linux中的导入库

    在 Windows C 中 当您想要链接 DLL 时 您必须提供导入库 但是在 GNU 构建系统中 当您想要链接 so 文件 相当于 dll 时 您就不需要链接 为什么是这样 是否有等效的 Windows 导入库 注意 我不会谈论在 Win
  • C++ 继承的内存布局

    如果我有两个类 一个类继承另一个类 并且子类仅包含函数 那么这两个类的内存布局是否相同 e g class Base int a b c class Derived public Base only functions 我读过编译器无法对数
  • 为什么C++代码执行速度比java慢?

    我最近用 Java 编写了一个计算密集型算法 然后将其翻译为 C 令我惊讶的是 C 的执行速度要慢得多 我现在已经编写了一个更短的 Java 测试程序和一个相应的 C 程序 见下文 我的原始代码具有大量数组访问功能 测试代码也是如此 C 的
  • C# 中最小化字符串长度

    我想减少字符串的长度 喜欢 这串 string foo Lorem ipsum dolor sit amet consectetur adipiscing elit Aenean in vehicula nulla Phasellus li
  • 为什么 std::uint32_t 与 uint32_t 不同?

    我对 C 有点陌生 我有一个编码作业 很多文件已经完成 但我注意到 VS2012 似乎有以下语句的问题 typedef std uint32 t identifier 不过 似乎将其更改为 typedef uint32 t identifi
  • 尝试将 SQLite DB 从数据复制到 SD 卡

    我正在使用以下代码 该代码发布在 Stack Overflow 上的某个位置 并根据我的目的进行了修改 try File sd Environment getExternalStorageDirectory File data Enviro
  • MySQL Connector C/C API - 使用特殊字符进行查询

    我是一个 C 程序 我有一个接受域名参数的函数 void db domains query char name 使用 mysql query 我测试数据库中是否存在域名 如果不是这种情况 我插入新域名 char query 400 spri
  • 指针和内存范围

    我已经用 C 语言编程有一段时间了 但对 C 语言还是很陌生 有时我对 C 处理内存的方式感到困惑 考虑以下有效的 C 代码片段 const char string void where is this pointer variable l
  • 类型或命名空间“MyNamespace”不存在等

    我有通常的类型或命名空间名称不存在错误 除了我引用了程序集 using 语句没有显示为不正确 并且我引用的类是公共的 事实上 我在不同的解决方案中引用并使用相同的程序集来执行相同的操作 并且效果很好 顺便说一句 这是VS2010 有人有什么

随机推荐

  • 如何使用 Firebase 将多个通知折叠为单个通知?

    我在 Firebase Cloud Functions 中有一个函数 用于向我的应用程序中的特定用户发送通知 并且具有notificationContent下面的代码 const notificationContent notificati
  • java.lang.NoClassDefFoundError: org/apache/poi/ss/usermodel/Row

    我制作了一个小型应用程序 它从 excel xls 文件 中读取数据并将内容显示到 JTable 中 Eclipse 中一切正常 但是当我创建 jar 文件并尝试运行它时 出现以下问题 java lang NoClassDefFoundEr
  • 隐藏文本,但如果在没有 JavaScript 的情况下复制和粘贴,则显示它

    我正在尝试为一个短篇小说网站进行设计 我听说的一个故事如果有人复制并粘贴文本 效果会更好 多余的行就会出现 有没有办法只用 HTML 和 CSS 来实现这一点 我尝试过使用display none 但这似乎并没有复制隐藏的文本 我不想为此使
  • jQuery 获取元素的渲染高度?

    如何获取元素的渲染高度 假设你有一个 div 里面有一些内容的元素 里面的内容将会拉伸 div 当您没有明确设置高度时 如何获得 渲染 高度 显然 我尝试过 var h document getElementById someDiv sty
  • 每个数据库的 Cloud Firestore 移动并发连接限制和每个数据库每秒的最大写入次数

    Firebase Cloud Firestore 已正式结束测试版 每个数据库的移动设备的新最大并发连接限制和每个数据库每秒的最大写入次数是多少 发布文章https cloud google com blog products databa
  • 更改 Facebook SDK 请求对话框标题和通知标题

    这个问题是关于android的 我已经花了一周的时间尝试显示我自己的消息作为邀请 请求对话框和通知的标题 对于facebook SDK 3 0 但我不知道如何 并且facebook SDK文档是一段 我必须从头开始阅读所有文档才能了解一点信
  • 用户卸载并重新安装时设备 UUID 不唯一

    我有一个系统 每个用户只允许为两个设备安装应用程序 当用户在同一设备上卸载并重新安装时 就会出现此问题 因此 当应用程序检查 Web 服务时 它将生成新的 UUID 应用程序将发送 UUID 和登录 ID 以检查具有该登录 ID 的用户是否
  • 为什么会出现这种行为?__proto__ vs 原型?

    function Obj1 name this proto Name name getName function alert this Name function Obj2 name this prototype Name name get
  • 如何在 jGit 中使用过滤器?

    我该如何使用RevFilter在 jGit 中吗 我找到了有关完成特定任务的问题的答案 获取两个日期之间所做的提交 答案是使用特定的子类RevFilter 但是 我不知道如何使用RevFilters 特别是 我想知道我需要做什么才能得到我链
  • SQL 查询查找与一组类别匹配的产品

    我有 3 个表 产品 类别和 pro cat link 一款产品可以通过表 pro cat link 链接到一个或多个类别 我的查询必须回答以下问题 查找与一组类别匹配的所有产品 例如 查找所有 黄色和水果和甜 的产品 在 SO 研究这个问
  • 如何禁用 gridview 中命令字段控件中的控件

    如何在网格视图中查找命令字段控件 在不在行数据绑定中的方法中 到目前为止 我已经使用了这个编码 但我找不到控件
  • Angularjs 将值从一个页面传递到另一个页面

    在下面的代码中 我尝试在单击时更改到另一个页面并希望传递对象i我该怎么做 在下面的代码中 我将其视为未定义 如何解决这个问题
  • SSAO 文物分为三部分

    我真的很难解决 SSAO 着色器的问题 并且迫切需要一些帮助 基本上 着色器似乎对某些对象有效 但在其他对象上看起来很糟糕 从下面您可以看到球体看起来是正确的 但立方体似乎在法线上进行了不应该的遮挡 这是一个屏幕截图 我的着色器基于本教程
  • Azure 网站上的 SignalR CryptographicException

    我在 Azure 网站中部署的 SignalR 中遇到了此异常 在调试环境下运行良好 它是 SignalR 1 0 1 我使用 NET MVC 和 WebApi The data protection operation was unsuc
  • 如何使用 Azure Function V2 管理签名证书

    我正在使用消费计划上的 Azure Functions 应用程序 Func 应用程序需要加载特定的签名证书 在本地计算机中 我将证书设置为个人证书 一切正常 在azure上发布后 我收到此错误 LocalMachine 中有 0 个主题名称
  • 如何找到数组中可能的最小键组合

    我有一个始终有 6 个键的数组 var ary 5 10 28 50 56 280 我有一个变量定义为limit我想核对一下 我想从上面的数组中找到尽可能低的组合或键的总和limit 我们称之为result 我试图在一些限制范围内工作 1
  • java中简单的流读/写问题

    我正在尝试通过 URLConnection 上传文件 但我需要将其作为二进制文件读取 写入 而不进行任何编码更改 所以我尝试阅读byte 数组从一个FileInputStream 但现在我有一个问题 这PrintWriter我用于输出到服务
  • Oracle 休眠 ORA-01461 CLOB

    大家好 我的问题是我无法在 clob 字段中写入大日期 currentli 我可以写长度不超过4000的字符串 你能解释一下为什么我不能将 clob 写入 clob 字段吗 我在用着 Oracle 数据库 11g 企业版版本 11 2 0
  • Zend_Session:在任何输出发送到浏览器之前必须启动会话

    我以前遇到过这个问题 但我不记得如何解决它 我创建了一个简单的控制器 不能再简单了 我只是想向浏览器回显一些内容 我收到以下消息 Fatal error Uncaught exception Zend Session Exception w
  • 在c中复制bmp

    背景 我想将 bmp 未压缩的 24 RGB 图像从一个文件名复制到另一个文件名 我正在使用来自 TDM GCC 的 mingw 编译器 版本 4 9 2 32 位 SJLJ 它带有代码块 Problem 程序适用于黑白图像和简单的彩色图像