首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >用C创建简单的位图(没有外部库)

用C创建简单的位图(没有外部库)
EN

Stack Overflow用户
提问于 2018-04-29 19:30:56
回答 1查看 9.6K关注 0票数 1

出于学习目的,我想使用C编程语言创建一个2x2的位图图像,而不使用外部库(比如SDL)。

我读到我需要为位图文件创建一个头文件,但无法理解如何在代码中实现它,以及为什么bmp头文件有这些参数。我找不到任何关于如何使用C来做这件事的清晰的教程。

你能通过一个简单的有文档记录的例子为我提供一些如何实现这一点的指导吗?我使用的是Linux。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-04-29 23:16:30

为什么bmp报头会有这些参数

位图中的像素数据本质上是一维的字节数组。如果没有显示宽度、高度、位数和其他有关位图的信息的标题信息,就不可能解释这些数据。

有不同类型的位图,包括不同的调色板格式和非调色板16、24或32位,以及这些组中的一些组中的不同类型。

标头还包括由于历史原因而存在的其他信息。这对学习C语言没有什么价值,你只能接受它。

头信息在两个结构中,BITMAPFILEHEADERBITMAPINFO,这有点复杂,因为这两个结构都是被打包的。

像素数据取决于位图格式。没有前面提到的单一位图格式。下面的例子显示了一个24位的位图。

其他奇怪之处在于,每行的宽度应该始终是4字节的倍数。这称为填充。另外,位图行从底部开始,而不是从顶部开始。在其他resources中对此进行了解释

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>

int main(void)
{
    //width, height, and bitcount are the key factors:
    int32_t width = 2;
    int32_t height = 2;
    uint16_t bitcount = 24;//<- 24-bit bitmap

    //take padding in to account
    int width_in_bytes = ((width * bitcount + 31) / 32) * 4;

    //total image size in bytes, not including header
    uint32_t imagesize = width_in_bytes * height;

    //this value is always 40, it's the sizeof(BITMAPINFOHEADER)
    const uint32_t biSize = 40;

    //bitmap bits start after headerfile, 
    //this is sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER)
    const uint32_t bfOffBits = 54; 

    //total file size:
    uint32_t filesize = 54 + imagesize;

    //number of planes is usually 1
    const uint16_t biPlanes = 1;

    //create header:
    //copy to buffer instead of BITMAPFILEHEADER and BITMAPINFOHEADER
    //to avoid problems with structure packing
    unsigned char header[54] = { 0 };
    memcpy(header, "BM", 2);
    memcpy(header + 2 , &filesize, 4);
    memcpy(header + 10, &bfOffBits, 4);
    memcpy(header + 14, &biSize, 4);
    memcpy(header + 18, &width, 4);
    memcpy(header + 22, &height, 4);
    memcpy(header + 26, &biPlanes, 2);
    memcpy(header + 28, &bitcount, 2);
    memcpy(header + 34, &imagesize, 4);

    //prepare pixel data:
    unsigned char* buf = malloc(imagesize);
    for(int row = height - 1; row >= 0; row--)
    {
        for(int col = 0; col < width; col++)
        {
            buf[row * width_in_bytes + col * 3 + 0] = 255;//blue
            buf[row * width_in_bytes + col * 3 + 1] = 0;//green
            buf[row * width_in_bytes + col * 3 + 2] = 0;//red
        }
    }

    FILE *fout = fopen("test.bmp", "wb");
    fwrite(header, 1, 54, fout);
    fwrite((char*)buf, 1, imagesize, fout);
    fclose(fout);
    free(buf);

    return 0;
}

您可以使用结构重写此代码。在这段代码中,结构被打包成依赖于编译器的#pragma pack(push, 1)。如果#pragma指令有效,则使用此版本。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>

#pragma pack(push, 1)
struct my_BITMAPFILEHEADER {
    uint16_t bfType;
    uint32_t bfSize;
    uint16_t bfReserved1;
    uint16_t bfReserved2;
    uint32_t bfOffBits;
};

struct my_BITMAPINFOHEADER {
    uint32_t biSize;
    int32_t  biWidth;
    int32_t  biHeight;
    uint16_t biPlanes;
    uint16_t biBitCount;
    uint32_t biCompression;
    uint32_t biSizeImage;
    int32_t  biXPelsPerMeter;
    int32_t  biYPelsPerMeter;
    uint32_t biClrUsed;
    uint32_t biClrImportant;
};
#pragma pack(pop)

int main(void)
{
    if(sizeof(struct my_BITMAPFILEHEADER) != 14 &&
        sizeof(struct my_BITMAPINFOHEADER) != 40)
    {
        printf("bitmap structures not packed properly\n");
        return 0;
    }

    //only width and height can be changed in this code:
    int width = 2;
    int height = 2;

    int bitcount = 24;//<- 24-bit bitmap
    int width_in_bytes = ((width * bitcount + 31) / 32) * 4;    //for padding
    uint32_t imagesize = width_in_bytes * height;   //total image size

    struct my_BITMAPFILEHEADER filehdr = { 0 };
    struct my_BITMAPINFOHEADER infohdr = { 0 };

    memcpy(&filehdr, "BM", 2);//bitmap signature
    filehdr.bfSize = 54 + imagesize;//total file size
    filehdr.bfOffBits = 54; //sizeof(filehdr) + sizeof(infohdr)

    infohdr.biSize = 40; //sizeof(infohdr)
    infohdr.biPlanes = 1; //number of planes is usually 1
    infohdr.biWidth = width;
    infohdr.biHeight = height;
    infohdr.biBitCount = bitcount;
    infohdr.biSizeImage = imagesize;

    //prepare pixel data:
    unsigned char* buf = malloc(imagesize);
    for(int row = height - 1; row >= 0; row--)
    {
        for(int col = 0; col < width; col++)
        {
            buf[row * width_in_bytes + col * 3 + 0] = 255;//blue
            buf[row * width_in_bytes + col * 3 + 1] = 0;//red
            buf[row * width_in_bytes + col * 3 + 2] = 0;//green
        }
    }

    FILE *fout = fopen("test.bmp", "wb");
    fwrite(&filehdr, sizeof(filehdr), 1, fout);
    fwrite(&infohdr, sizeof(infohdr), 1, fout);
    fwrite((char*)buf, 1, imagesize, fout);
    fclose(fout);
    free(buf);

    return 0;
}

第一个版本使用unsigned char header[54]来实现相同的功能。查看每个数据的大小及其在内存中的相对位置。该结构为14字节长。bfType从0开始,长度为2字节长(16位)。bfSize从位置2开始,长度为4字节长...

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
struct my_BITMAPFILEHEADER {
    uint16_t bfType; //starts at 0, 2 bytes long
    uint32_t bfSize; //starts at 2, 4 bytes long
    uint16_t bfReserved1; //starts at 6, 2 bytes long
    uint16_t bfReserved2; //starts at 8, 2 bytes long
    uint32_t bfOffBits; //starts at 10, 4 bytes long
};

然后你就有了下一个40字节长的结构:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
struct my_BITMAPINFOHEADER {
    uint32_t biSize;//starts at 14
    int32_t  biWidth;//starts at 18
    int32_t  biHeight;//starts at 22
    uint16_t biPlanes;//starts at 26
    uint16_t biBitCount;//starts at 28
    uint32_t biCompression;//starts at 30
    uint32_t biSizeImage;//starts at 34
    int32_t  biXPelsPerMeter;
    int32_t  biYPelsPerMeter;
    uint32_t biClrUsed;
    uint32_t biClrImportant;
};

biSize从0开始。但之前的结构是14个字节。因此,biSzie14开始。这应该会揭开前一个版本中用于将整数复制到header中的数字的奥秘

票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/50090500

复制
相关文章
Python | 从 PDF 中提取文本内容
本来打算推一篇如何使用 Python 从 PDF 中提取文本内容的文章,但是因为审核原因,公众号上发不出来。尝试排查了一个小时,还是没有搞定,索性就放弃挣扎了。我在这里放出来文章的第一部分,如果有兴趣,可以前往我的 Github 或者码云上查看全文。
PyStaData
2020/07/21
3.1K0
python:如何从 URL 中快速提取域名?
有时候,我们要从一段很长的 URL 里面提取出域名。例如从https://www.kingname.info/2020/10/02/copy-from-ssh/,我需要获取的是kingname.info。
王图思睿
2021/06/16
9.2K0
如何从文本中构建用户画像
一文告诉你什么是用户画像 介绍了到底什么是用户画像,了解了用户画像的本质是为了让机器去看之后,这里谈一谈如何从文本中构建用户画像。
abs_zero
2018/04/11
4.8K0
如何从文本中构建用户画像
如何从网站提取数据?
在当今时代,根据数据情况来制定业务决策是许多公司的头等大事。为了推动这些决策,公司全天候跟踪,监视和记录相关数据。幸运的是,很多网站的服务器上存储了大量公共数据,可以帮助企业在竞争激烈的市场中保持领先地位。
用户7850017
2021/01/29
3.1K0
分享回顾丨如何利用NLP技术从海量文本中提取观点?
ABOUT CLASS 关于课程 本文为3月29日晚,达观数据联合创始人、文本审核组总负责人张健在将门技术社群,分享“文本观点挖掘技术及其应用”课题的内容回顾。主要内容包括结合实践经验,盘点观点挖掘的应用场景及价值、目前业界主流的观点挖掘技术以及该技术目前面临的挑战。 NO.1 什么是文本观点挖掘? 在简单介绍观点挖掘的基本概念之后,张健首先对“观点”的五个组成要素进行了强调: 观点评价对象(客体); 观点评价对象的属性。例如,我评价谁哪里哪里好,又哪里哪里不好,“哪里”就是属性; 观点所蕴含的情感极性。包
达观数据
2018/06/04
5.3K0
如何从内存提取LastPass中的账号密码
简介 首先必须要说,这并不是LastPass的exp或者漏洞,这仅仅是通过取证方法提取仍旧保留在内存中数据的方法。之前我阅读《内存取证的艺术》(The Art of Memory Forensics)时,其中有一章节就有讨论从浏览器提取密码的方法。当你使用标准的用户名/密码方式登录一个网页,通常会发送一个包含了你的用户名及密码的post请求,这些都是以明文方式发送(这里不过多讨论SSL,在SSL内部也是明文发送的)。 本文描述如何找到这些post请求并提取信息,当然如果你捕获到浏览器登录,这些方法就很实用。
FB客服
2018/02/09
5.7K0
如何从内存提取LastPass中的账号密码
PHP 提取富文本中的全部图片(提取文章中的全部图片)
未经允许不得转载:肥猫博客 » PHP 提取富文本中的全部图片(提取文章中的全部图片)
超级小可爱
2023/02/20
2.2K0
如何用Python批量提取PDF文本内容?
本文为你展示,如何用Python把许多PDF文件的文本内容批量提取出来,并且整理存储到数据框中,以便于后续的数据分析。
王树义
2018/08/22
5.7K3
如何用Python批量提取PDF文本内容?
Python批量提取PDF文件中的文本
首先需要执行命令pip install pdfminer3k来安装处理PDF文件的扩展库。 import os import sys import time pdfs = (pdfs for pdfs in os.listdir('.') if pdfs.endswith('.pdf')) for pdf1 in pdfs: pdf = pdf1.replace(' ', '_').replace('-', '_').replace('&', '_') os.rename(pdf1, pdf
Python小屋屋主
2018/04/16
6K0
ChemDataExtractor:从PDF、HTM、文本等中提取化学数据
ChemDataExtractor是一种从科学文档中自动提取化学信息的工具。给它一篇期刊文章,它将从文本中提取化学名称、属性和光谱,以便将它们导入数据库或电子表格。
DrugAI
2021/01/28
2.8K0
关于从文本中提取数字,这些公式各显神通
很多时候,要达到目的并不会只有一种方法,正是这样,才会体现出创新性和创造力,也才更有趣。
fanjy
2022/11/16
1.3K0
关于从文本中提取数字,这些公式各显神通
ChemDataExtractor:从PDF、HTM、文本等中提取化学数据
ChemDataExtractor是一种从科学文档中自动提取化学信息的工具。给它一篇期刊文章,它将从文本中提取化学名称、属性和光谱,以便将它们导入数据库或电子表格。
DrugAI
2021/01/28
1.7K0
如何从 Debian 系统中的 DEB 包中提取文件?
DEB 包是 Debian 系统中常见的软件包格式,用于安装和管理软件。有时候,您可能需要从 DEB 包中提取特定的文件,以便查看其内容、修改或进行其他操作。本文将详细介绍如何从 Debian 系统中的 DEB 包中提取文件,并提供相应的示例。
网络技术联盟站
2023/06/08
3.6K0
如何从 Debian 系统中的 DEB 包中提取文件?
如何从网络发送文本
如果您想从您的网络平台发送文本,那么您可以在下面看到我们的流程。 最新的邮件数据库从您的网络平台为您提供任何类型的文本发送服务。 如果您想从您的 wordpress 或 php 或 html 网站发送文本,那么您应该从该网站了解它。
最新邮件数据库
2022/05/25
8520
excel数据提取技巧:从混合文本中提取数字的万能公式
在上一篇文章中,小花讲解了通过观察混合文本特征,设置特定公式,完成数据提取的三种情景。于是,有些小花瓣悄悄跟小花说:小花老师,我笨,看不出数据特征,我又懒,不想分情景设置不同公式,有没有那种霸王级万能公式,啥混合文本咱都可以硬上弓?
用户8639654
2021/07/26
6.2K0
文本提取仨兄弟
周二 · 函数  关键词:left、right、mid 1语法 =Left(text,[num_chars]) =Right(text,[num_chars]) =Mid(text,start_num,num_chars) 在单元格输入=LEFT(、=RIGHT(或=MID(,就会提示上述语法 Left、Right是指从字符串text中,提取最前/最后几位字符 Mid是从第start_num位数起,提取num_chars长度的字符 仨函数返回的均为文本类型,哪怕是从数值中提取 2基本用法 大陆18位身份证身
企鹅号小编
2018/01/10
7760
文本提取仨兄弟
R语言提取PDF文件中的文本内容
综上步骤,我们便可以随便获取任意章节的任意内容。那么接下来就是对这些文字的应用,各位集思广益吧。
一粒沙
2019/07/31
9.8K1
如何在Power Query中提取数据?——文本篇
平时我们经常用到需要根据一定的需求在数据中把符合需求的数据提取出来,那我们看下在Power Query中是如何进行操作的。
逍遥之
2020/03/23
5.2K0
使用 Python 和 TFIDF 从文本中提取关键词
关键词提取是从简明概括长文本内容的文档中,自动提取一组代表性短语。关键词是一个简短的短语(通常是一到三个单词),高度概括了文档的关键思想并反映一个文档的内容,清晰反映讨论的主题并提供其内容的摘要。
数据STUDIO
2022/05/24
4.5K0
使用 Python 和 TFIDF 从文本中提取关键词
点击加载更多

相似问题

帕尔康的ORM遗产?

14

帕尔康持久性

13

帕尔康伏特按位操作?

11

帕尔康尼Mac和xampp

13

我如何计算列的帕尔康伏特?

24
添加站长 进交流群

领取专属 10元无门槛券

AI混元助手 在线答疑

扫码加入开发者社群
关注 腾讯云开发者公众号

洞察 腾讯核心技术

剖析业界实践案例

扫码关注腾讯云开发者公众号
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文