一个最简单的Windows BMP位图文件解析程序

站里讲解BMP格式的文章已经有了,这里主要是分享一个示例程序给需要的同学。这个示例只支持24/32位不带调色板的位图文件解析,并且实现了简单的Resize、亮度调整功能,另外加了一个比较有意思的功能就是把图片转换成RGB像素点的形式(但是输出很容易变得非常大甚至超过4G导致32bit的数值溢出)。
bmp文件有个特点,Windows规定每一行占用字节数必须是4的整数倍,多余的数据用0补足。这个在处理24bit位图时,计算数据索引时需要注意。

bitmap.h

#ifndef _BITMAP_H_
#define _BITMAP_H_

#include "types.h"

#pragma pack(1)
typedef struct tagBITMAPFILEHEADER
{
    UINT16 bfType;
    DWORD bfSize;
    UINT16 bfReserved1;
    UINT16 bfReserved2;
    DWORD bfOffBits;
} BITMAPFILEHEADER;
#pragma pack()

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

#define BMPTYPE_BM 0x4d42
#define blue(color) (BYTE)(color)
#define green(color) (BYTE)((color) >> 8)
#define red(color) (BYTE)((color) >> 16)
#define alpha(color) (BYTE)((color) >> 24)
#define makecolor(b,g,r,a) (((BYTE)(b)) | ((BYTE)(g) << 8) | ((BYTE)(r) << 16) | ((BYTE)(a) << 24) )
#endif

BMP部分:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "types.h"
#include "bitmap.h"

#pragma pack(1)
typedef struct tagBMP
{
    BITMAPFILEHEADER head;
    BITMAPINFO info;
    BYTE data[0];
} BMP;
#pragma pack()

BMP *create_bmp(DWORD w, DWORD h, WORD bitdepth)
{
    DWORD rowsize = (w * bitdepth / 8 + 3) & (~3U);
    DWORD size_image = h * rowsize;
    DWORD file_size = size_image + sizeof(BMP);

    BMP *bmp = malloc(file_size);
    if (bmp == NULL)
    {
        return NULL;
    }
    bmp->head.bfType = BMPTYPE_BM;
    bmp->head.bfSize = file_size;
    bmp->head.bfReserved1 = 0;
    bmp->head.bfReserved2 = 0;
    bmp->head.bfOffBits = sizeof(BMP);
    bmp->info.biSize = sizeof(BITMAPINFO);
    bmp->info.biWidth = w;
    bmp->info.biHeight = h;
    bmp->info.biPlanes = 1;
    bmp->info.biBitCount = bitdepth;
    bmp->info.biCompression = 0;
    bmp->info.biSizeImage = size_image;
    bmp->info.biXPelsPerMeter = 0;
    bmp->info.biYPelsPerMeter = 0;
    bmp->info.biClrUsed = 0;
    bmp->info.biClrImportant = 0;
    return bmp;
}

int save_file(const BMP *bmp, const char *path)
{
    if (bmp == NULL)
        return -1;
    FILE *fp = fopen(path, "wb+");
    if (fp == NULL)
        return -1;
    fwrite(bmp, 1, bmp->head.bfSize, fp);
    fclose(fp);
}

BMP *create_from_file(const char *path)
{
    BITMAPFILEHEADER headtemp;
    FILE *fp = fopen(path, "rb+");
    if (fp == NULL)
        goto except;
    fread(&headtemp, 1, sizeof(BITMAPFILEHEADER), fp);

    BMP *bmp = malloc(headtemp.bfSize);
    if (bmp == NULL)
    {
        goto close_file;
    }
    memcpy(&bmp->head, &headtemp, sizeof(bmp->head));
    fread(&bmp->info, 1, headtemp.bfSize - sizeof(BITMAPFILEHEADER), fp);
    return bmp;

close_file:
    fclose(fp);
except:
    return NULL;
}

void destroy_bmp(BMP **pbmp)
{
    if (pbmp != NULL)
        free(*pbmp);
    *pbmp = NULL;
}

处理函数部分

void rect(BMP *bmp, DWORD color, DWORD row, DWORD col, DWORD w, DWORD h)
{
    DWORD width = bmp->info.biWidth;
    DWORD height = bmp->info.biHeight;
    DWORD colend = MIN(col + w, width);
    DWORD rowend = MIN(row + h, height);
    const DWORD dsize = bmp->info.biBitCount / 8;
    const DWORD rowsize = (width * dsize + 3) & (~3U);
    for (DWORD i = row; i < rowend; i++)
    {
        for (DWORD j = col; j < colend; j++)
        {
            BYTE *data = bmp->data + i * rowsize + j * dsize;
            data[0] = blue(color);
            data[1] = green(color);
            data[2] = red(color);
        }
    }
}

void rect_lightness(BMP *bmp, DWORD row, DWORD col, DWORD w, DWORD h, float ratio)
{
    DWORD width = bmp->info.biWidth;
    DWORD height = bmp->info.biHeight;
    DWORD colend = MIN(col + w, width);
    DWORD rowend = MIN(row + h, height);
    const DWORD dsize = bmp->info.biBitCount / 8;
    const DWORD rowsize = (width * dsize + 3) & (~3U);
    for (DWORD i = row; i < rowend; i++)
    {
        for (DWORD j = col; j < colend; j++)
        {
            BYTE *data = bmp->data + i * rowsize + j * dsize;
            data[0] = color_truncate(((float)data[0]) * ratio);
            data[1] = color_truncate(((float)data[1]) * ratio);
            data[2] = color_truncate(((float)data[2]) * ratio);
        }
    }
}

BYTE color_truncate(int grlevel)
{
    if (grlevel < 0)
        return 0;
    if (grlevel > 255)
        return 255;
    return grlevel;
}

DWORD color_lightness(BYTE b, BYTE g, BYTE r, int delta)
{
    BYTE blue = color_truncate((int)b + delta);
    BYTE green = color_truncate((int)g + delta);
    BYTE red = color_truncate((int)r + delta);
    return makecolor(blue, green, red, 0);
}

DWORD color_lightnessf(BYTE b, BYTE g, BYTE r, float ratio)
{
    BYTE blue = color_truncate(((float)b) * ratio);
    BYTE green = color_truncate(((float)g) * ratio);
    BYTE red = color_truncate(((float)r) * ratio);
    return makecolor(blue, green, red, 0);
}

void lightness(BMP *bmp, int delta)
{
    DWORD width = bmp->info.biWidth;
    DWORD height = bmp->info.biHeight;
    const DWORD dsize = bmp->info.biBitCount / 8;
    const DWORD rowsize = (width * dsize + 3) & (~3U);
    for (DWORD i = 0; i < height; i++)
    {
        for (DWORD j = 0; j < width; j++)
        {
            BYTE *data = bmp->data + i * rowsize + j * dsize;
            data[0] = color_truncate((int)data[0] + delta);
            data[1] = color_truncate((int)data[1] + delta);
            data[2] = color_truncate((int)data[2] + delta);
        }
    }
}

void lightnessf(BMP *bmp, float ratio)
{
    DWORD width = bmp->info.biWidth;
    DWORD height = bmp->info.biHeight;
    const DWORD dsize = bmp->info.biBitCount / 8;
    const DWORD rowsize = (width * dsize + 3) & (~3U);
    for (DWORD i = 0; i < height; i++)
    {
        for (DWORD j = 0; j < width; j++)
        {
            BYTE *data = bmp->data + i * rowsize + j * dsize;
            data[0] = color_truncate((int)data[0] * ratio);
            data[1] = color_truncate((int)data[1] * ratio);
            data[2] = color_truncate((int)data[2] * ratio);
        }
    }
}

BMP *resize(const BMP *bmp, float fscale)
{
    int scale = (int)fscale;
    const DWORD dsize = bmp->info.biBitCount / 8;
    const DWORD w = bmp->info.biWidth;
    const DWORD h = bmp->info.biHeight;
    const DWORD rowsize = (w * dsize + 3) & (~3U);
    DWORD newwidth = bmp->info.biWidth * fscale;
    DWORD newheight = bmp->info.biHeight * fscale;
    DWORD newdsize = 3;
    BMP *newbmp = create_bmp(newwidth, newheight, newdsize * 8);
    DWORD newrowsize = (newwidth * newdsize + 3) & (~3U);
    if (fscale > 1.f)
    {
        for (DWORD i = 0; i < bmp->info.biHeight; i++)
        {
            for (DWORD j = 0; j < bmp->info.biWidth; j++)
            {
                const BYTE *data = bmp->data + i * rowsize + j * dsize;
                DWORD color = makecolor(data[0], data[1], data[2], 0);
                rect(newbmp, color, i * fscale, j * fscale, fscale, fscale);
            }
        }
    }
    else if (fscale < 1.f)
    {

        for (DWORD i = 0; i < newheight; i++)
        {
            for (DWORD j = 0; j < newwidth; j++)
            {
                BYTE *dstdata = newbmp->data + i * newrowsize + j * newdsize;
                const BYTE *data = bmp->data + (DWORD)(i / fscale) * rowsize + (DWORD)(j / fscale) * dsize;
                dstdata[0] = data[0];
                dstdata[1] = data[1];
                dstdata[2] = data[2];
            }
        }
    }
    return newbmp;
}

BMP *resize_screen(const BMP *bmp, WORD frame_width, WORD pixel_width)
{
    int scale = pixel_width * 3 + frame_width * 3;
    const DWORD dsize = bmp->info.biBitCount / 8;
    const DWORD w = bmp->info.biWidth;
    const DWORD h = bmp->info.biHeight;
    const DWORD rowsize = (w * dsize + 3) & (~3U);
    BMP *newbmp = create_bmp(bmp->info.biWidth * scale, bmp->info.biHeight * scale, 24);
    for (DWORD i = 0; i < bmp->info.biHeight; i++)
    {
        DWORD preblue = 0;
        for (DWORD j = 0; j < bmp->info.biWidth; j++)
        {
            const BYTE *data = bmp->data + i * rowsize + j * dsize;
            DWORD color = makecolor(data[0], data[1], data[2], 0);
            DWORD gray = data[2] * 0.3 + data[1] * 0.59 + data[0] * 0.11;
            float diffusion = 0.5;
            DWORD red = makecolor(data[0] * diffusion, data[1] * diffusion, data[2], 0);
            DWORD green = makecolor(data[0] * diffusion, data[1], data[2] * diffusion, 0);
            DWORD blue = makecolor(data[0], data[1] * diffusion, data[2] * diffusion, 0);

            // DWORD frame = color_lightnessf(data[0], data[1], data[2], 0.3);
            float lightness = 0.5;
            DWORD frameRG = color_lightnessf(0, data[1], data[2], lightness);
            DWORD frameGB = color_lightnessf(data[0], data[1], 0, lightness);
            DWORD frameBR = color_lightnessf(preblue, 0, data[2], lightness);
            preblue = blue;
            DWORD frameGray = color_lightnessf(gray, gray, gray, lightness);
            DWORD joffset = 0;
            rect(newbmp, frameBR, i * scale, j * scale, frame_width, scale);
            joffset += frame_width;
            rect(newbmp, red, i * scale, j * scale + joffset, pixel_width, scale);
            joffset += pixel_width;
            rect(newbmp, frameRG, i * scale, j * scale + joffset, frame_width, scale);
            joffset += frame_width;
            rect(newbmp, green, i * scale, j * scale + joffset, pixel_width, scale);
            joffset += pixel_width;
            rect(newbmp, frameGB, i * scale, j * scale + joffset, frame_width, scale);
            joffset += frame_width;
            rect(newbmp, blue, i * scale, j * scale + joffset, pixel_width, scale);
            joffset += pixel_width;
            rect_lightness(newbmp, i * scale, j * scale, scale, frame_width, lightness);
        }
    }
    return newbmp;
}

测试程序:

int main(int argc, char *argv[])
{
    // BMP *bmp = create_bmp(100, 100, 24);
    // save_file(bmp, "1.bmp");
    // destroy_bmp(&bmp);

    BMP *bmp = create_from_file("test.bmp");
    BMP *bmpre = resize_screen(bmp, 1, 2);
    // BMP *bmps = resize(bmpre, 0.5f);
    lightnessf(bmpre, 1.2);
    save_file(bmpre, "test1.bmp");
    destroy_bmp(&bmp);
    // destroy_bmp(&bmps);
    destroy_bmp(&bmpre);

    return 0;
}

原图
请添加图片描述
处理后(裁剪)
请添加图片描述

  • 8
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值