设计算法实现BMP图片等比例缩小为原来1/2

/*********************************************************************************
* @Description  : 实现图片的不失真缩小
* @Author       : ice_cui
* @Date         : 2025-04-29 15:03:13
* @Email        : Lazypanda_ice@163.com
* @LastEditTime : 2025-04-29 17:55:53
* @Version      : V1.0.0
* @Copyright    : Copyright (c) 2025 Lazypanda_ice@163.com All rights reserved.
**********************************************************************************/
#include <stdio.h>
#include <stdlib.h>

// BMP文件头结构体
typedef struct {
    unsigned char signature[2];
    unsigned int fileSize;
    unsigned short reserved1;
    unsigned short reserved2;
    unsigned int dataOffset;
} BMPFileHeader;

// BMP信息头结构体
typedef struct {
    unsigned int headerSize;
    int width;
    int height;
    unsigned short planes;
    unsigned short bitCount;
    unsigned int compression;
    unsigned int imageSize;
    int xPixelsPerMeter;
    int yPixelsPerMeter;
    unsigned int colorsUsed;
    unsigned int colorsImportant;
} BMPInfoHeader;

// 读取BMP文件头
void readBMPFileHeader(FILE *file, BMPFileHeader *fileHeader) {
    fread(fileHeader->signature, sizeof(unsigned char), 2, file);
    fread(&fileHeader->fileSize, sizeof(unsigned int), 1, file);
    fread(&fileHeader->reserved1, sizeof(unsigned short), 1, file);
    fread(&fileHeader->reserved2, sizeof(unsigned short), 1, file);
    fread(&fileHeader->dataOffset, sizeof(unsigned int), 1, file);
}

// 读取BMP信息头
void readBMPInfoHeader(FILE *file, BMPInfoHeader *infoHeader) {
    fread(&infoHeader->headerSize, sizeof(unsigned int), 1, file);
    fread(&infoHeader->width, sizeof(int), 1, file);
    fread(&infoHeader->height, sizeof(int), 1, file);
    fread(&infoHeader->planes, sizeof(unsigned short), 1, file);
    fread(&infoHeader->bitCount, sizeof(unsigned short), 1, file);
    fread(&infoHeader->compression, sizeof(unsigned int), 1, file);
    fread(&infoHeader->imageSize, sizeof(unsigned int), 1, file);
    fread(&infoHeader->xPixelsPerMeter, sizeof(int), 1, file);
    fread(&infoHeader->yPixelsPerMeter, sizeof(int), 1, file);
    fread(&infoHeader->colorsUsed, sizeof(unsigned int), 1, file);
    fread(&infoHeader->colorsImportant, sizeof(unsigned int), 1, file);
}

// 写入BMP文件头
void writeBMPFileHeader(FILE *file, BMPFileHeader *fileHeader) {
    fwrite(fileHeader->signature, sizeof(unsigned char), 2, file);
    fwrite(&fileHeader->fileSize, sizeof(unsigned int), 1, file);
    fwrite(&fileHeader->reserved1, sizeof(unsigned short), 1, file);
    fwrite(&fileHeader->reserved2, sizeof(unsigned short), 1, file);
    fwrite(&fileHeader->dataOffset, sizeof(unsigned int), 1, file);
}

// 写入BMP信息头
void writeBMPInfoHeader(FILE *file, BMPInfoHeader *infoHeader) {
    fwrite(&infoHeader->headerSize, sizeof(unsigned int), 1, file);
    fwrite(&infoHeader->width, sizeof(int), 1, file);
    fwrite(&infoHeader->height, sizeof(int), 1, file);
    fwrite(&infoHeader->planes, sizeof(unsigned short), 1, file);
    fwrite(&infoHeader->bitCount, sizeof(unsigned short), 1, file);
    fwrite(&infoHeader->compression, sizeof(unsigned int), 1, file);
    fwrite(&infoHeader->imageSize, sizeof(unsigned int), 1, file);
    fwrite(&infoHeader->xPixelsPerMeter, sizeof(int), 1, file);
    fwrite(&infoHeader->yPixelsPerMeter, sizeof(int), 1, file);
    fwrite(&infoHeader->colorsUsed, sizeof(unsigned int), 1, file);
    fwrite(&infoHeader->colorsImportant, sizeof(unsigned int), 1, file);
}

// 计算每行的字节数
int calRowSize(int width, int bitCount) {
    int rowSize = (width * bitCount + 31) / 32 * 4;
    return rowSize;
}

int main(int argc, char *argv[]) {
    if (argc != 3) {
        printf("use: %s inputaddress outputaddress\n", argv[0]);
        return 1;
    }
    //打开原BMP图片
    FILE *inputFile = fopen(argv[1], "rb");
    if (inputFile == NULL) {
        printf("open file1 is error\n");
        return 1;
    }

    BMPFileHeader fileHeader;
    BMPInfoHeader infoHeader;
    //读取原BMP的文件头和信息头
    readBMPFileHeader(inputFile, &fileHeader);
    readBMPInfoHeader(inputFile, &infoHeader);
    //将新BMP图片的宽高变为原来的1/2
    // 确保原始宽度和高度是偶数
    if (infoHeader.width % 2 != 0) {
        infoHeader.width--;
    }
    if (infoHeader.height % 2 != 0) {
        infoHeader.height--;
    }
    int originalWidth = infoHeader.width;
    int originalHeight = infoHeader.height;
    int newWidth = originalWidth / 2;
    int newHeight = originalHeight / 2;
    //计算原BMP与新BMP每行的像素点
    int originalRowSize = calRowSize(originalWidth, infoHeader.bitCount);
    int newRowSize = calRowSize(newWidth, infoHeader.bitCount);

    // 更新文件头  计算新的文件大小
    fileHeader.fileSize = fileHeader.dataOffset + newRowSize * newHeight;

    // 更新信息头  计算新的文件的宽、高以及数据区大小
    infoHeader.width = newWidth;
    infoHeader.height = newHeight;
    infoHeader.imageSize = newRowSize * newHeight;
    //打开新BMP图片
    FILE *outputFile = fopen(argv[2], "wb");
    if (outputFile == NULL) {
        printf("open file2 is error\n");
        fclose(inputFile);
        return 1;
    }

    // 写入文件头和信息头
    writeBMPFileHeader(outputFile, &fileHeader);
    writeBMPInfoHeader(outputFile, &infoHeader);

    // 跳过原文件的调色板
    fseek(inputFile, fileHeader.dataOffset, SEEK_SET);
    //为原文件数据申请内存
    unsigned char *originalImageData = (unsigned char *)malloc(originalRowSize * originalHeight);
    if (originalImageData == NULL) {
        printf("malloc is error\n");
        fclose(inputFile);
        fclose(outputFile);
        return 1;
    }

    // 读取原图像数据
    size_t readBytes = fread(originalImageData, sizeof(unsigned char), originalRowSize * originalHeight, inputFile);
    if (readBytes != (size_t)(originalRowSize * originalHeight)) {
        printf("Error reading image data\n");
        free(originalImageData);
        fclose(inputFile);
        fclose(outputFile);
        return 1;
    }
    //为新文件数据申请内存
    unsigned char *newImageData = (unsigned char *)malloc(newRowSize * newHeight);
    if (newImageData == NULL) {
        printf("malloc for newImageData is error\n");
        free(originalImageData);
        fclose(inputFile);
        fclose(outputFile);
        return 1;
    }

    // 缩小图像  原图像每两个像素点读取一个到新图像中
    for (int y = 0; y < newHeight; y++) {
        for (int x = 0; x < newWidth; x++) {
            int originalX = x * 2;
            int originalY = y * 2;
            int originalIndex = originalY * originalRowSize + originalX * (infoHeader.bitCount / 8);
            int newIndex = y * newRowSize + x * (infoHeader.bitCount / 8);

            // 检查索引是否越界
            if (originalIndex + (infoHeader.bitCount / 8) > originalRowSize * originalHeight ||
                newIndex + (infoHeader.bitCount / 8) > newRowSize * newHeight) {
                printf("Index out of bounds: originalIndex = %d, newIndex = %d\n", originalIndex, newIndex);
                free(originalImageData);
                free(newImageData);
                fclose(inputFile);
                fclose(outputFile);
                return 1;
            }
            for (int i = 0; i < infoHeader.bitCount / 8; i++) {
                newImageData[newIndex + i] = originalImageData[originalIndex + i];
            }
        }
    }

    // 写入新图像数据
    size_t writtenBytes = fwrite(newImageData, sizeof(unsigned char), newRowSize * newHeight, outputFile);
    if (writtenBytes != (size_t)(newRowSize * newHeight)) {
        printf("Error writing image data\n");
    }

    // 释放内存
    free(originalImageData);
    originalImageData = NULL;
    free(newImageData);
    newImageData = NULL;
    // 关闭文件
    fclose(inputFile);
    fclose(outputFile);

    printf("success!\n");

    return 0;
}    
posted @ 2025-04-29 18:07  ice_cui  阅读(249)  评论(0)    收藏  举报