Считать bmp побайтно и пересохранить - C (СИ)

Узнай цену своей работы

Формулировка задачи:

необходимо открыть bmp файл, считать заголовок(читаю оба в одну структуру) считать растровый массив( с этим походу и есть беда) произвести манипуляции с массивом(это пока опустим) и сохранить результат в новый bmp (пока что просто перезаписать этот файл с другим именем) пробую так насколько я понял, беда с чтением растрового массива. как его правильно читать?
#include <stdio.h>
 
int openBMP(char* path);
int saveBMP(char* path);
#pragma pack(push, 2)
struct BmpHeader {
    unsigned char b1, b2; // Символы BM (2 байта)
    unsigned long size; // Размер файла (4 байта)
    unsigned short notUse1; // (2 байта)
    unsigned short notUse2; // (2 байта)
    unsigned long massPos; // Местанахождение данных растрового массива (4 байта)
 
    unsigned long headerLength; // Длинна этого заголовка (4 байта)
    unsigned long width; // Ширина изображения (4 байта)
    unsigned long height; // Высота изображения (4 байта)
    unsigned short colorPlaneNumber; // Число цветовых плоскостей (2 байта)
    unsigned short bitPixel; // Бит/пиксель (2 байта)
    unsigned long compressMethod; // Метод сжатия (4 байта)
    unsigned long massLength; // Длинна массива с мусоро (4 байта)
    unsigned long massWidth; // Ширина массива с мусором (4 байта)
    unsigned long massHeight; // Высота массива с мусором (4 байта)
    unsigned long colorNumber; // Число цветов изображения (4 байта)
    unsigned long generalColorNumber; // Число основных цветов (4 байта)
 
} bmpHeader;
#pragma pack(pop)
 
unsigned char** img;
int main(void)
{
 
    if (readBMP("D:\\1.bmp") == 0) {
        printf("bad path");
        return 0;
    }
 
    if (saveBMP("D:\\_1.bmp") == 0) {
        printf("bad path");
        return 0;
    }
    return 0;
}
 
int readBMP(char* path) {
    FILE* file;
    int i, j;
    file = fopen(path,"rb");
    if(file == NULL) return 0;
    fread(&bmpHeader, sizeof(bmpHeader), 1, file);
    if (bmpHeader.b1 != 'B' || bmpHeader.b2 != 'M' || bmpHeader.bitPixel != 24) {
        printf("corrupted file");
        return 0;
    }
    img = (unsigned char**)calloc(bmpHeader.width, sizeof(*img));
    for(i = 0; i < bmpHeader.width; ++i)
        img[i] = (unsigned char*)calloc(bmpHeader.height, sizeof(*img[i]));
    for (i = 0; i < bmpHeader.width; i++) {
        for (j = 0; j < bmpHeader.height; j++) {
            fread(&img[i][j], sizeof(img[i][j]), 1, file);
        }
    }
 
    fclose(file);
    return 1;
}
 
int saveBMP(char* path) {
    FILE* file;
    int i, j;
    file = fopen(path,"wb");
    if(file == NULL) return 0;
    fwrite(&bmpHeader, sizeof(bmpHeader), 1, file);
    for (i = 0; i < bmpHeader.width; i++) {
        for (j = 0; j < bmpHeader.height; j++) {
            fwrite(&img[i][j], sizeof(img[i][j]), 1, file);
        }
    }
    fclose(file);
    return 1;
}

Решение задачи: «Считать bmp побайтно и пересохранить»

textual
Листинг программы
void rotate(const struct BmpHeader* head, unsigned char* img) {
    int i, j;
    int bytes = head->bitPixel / 8;
    int width = (bytes * head->width + bytes) & (-4);
 
    for (i = 0; i < head->height / 2; ++i) {
        for (j = 0; j < head->width; ++j) {
            swap(img + (width * i) + j * bytes,
                 img + (width * (head->height - i - 1)) + j * bytes,
                 bytes);
        }
    }
}

Объяснение кода листинга программы

  1. Функция rotate принимает два аргумента: указатель на структуру BmpHeader и указатель на массив img.
  2. Внутри функции объявлены две переменные i и j для использования в циклах.
  3. Переменная bytes инициализируется значением head->bitPixel / 8, где head->bitPixel — количество бит на пиксель, а / 8 — деление на 8 для получения количества байт на пиксель.
  4. Переменная width инициализируется значением (bytes * head->width + bytes) & (-4), где head->width — ширина изображения в пикселях, а bytes — количество байт на пиксель. Значение & (-4) используется для округления значения в меньшую сторону до ближайшего числа, кратного 4.
  5. Переменная i инициализируется значением 0, а переменная j инициализируется значением 0.
  6. В цикле for перебираются все строки изображения от 0 до head->height / 2 - 1.
  7. Внутри цикла for перебираются все столбцы изображения от 0 до head->width - 1.
  8. Внутри вложенного цикла for происходит обмен значений двух указателей на массив img. Первый указатель указывает на текущую строку изображения, второй указатель указывает на строку изображения, которая будет перевернута.
  9. Значение переменной bytes используется для определения количества байт, которые необходимо обменять.
  10. Функция swap используется для обмена значений двух указателей на массив img.
  11. Значение переменной i увеличивается на 1 после каждой итерации внешнего цикла for.
  12. Значение переменной j увеличивается на 1 после каждой итерации внутреннего цикла for.
  13. Значение переменной width используется для определения длины строки изображения в байтах.
  14. Значение переменной head->height используется для определения высоты изображения в пикселях.
  15. Значение переменной head->width используется для определения ширины изображения в пикселях.
  16. Значение переменной bytes используется для определения количества байт на пиксель.
  17. Значение переменной i используется для определения номера строки изображения.
  18. Значение переменной j используется для определения номера столбца изображения.
  19. Значение переменной head->bitPixel используется для определения количества бит на пиксель.
  20. Значение переменной img используется для указания на массив, содержащий данные изображения.

ИИ поможет Вам:


  • решить любую задачу по программированию
  • объяснить код
  • расставить комментарии в коде
  • и т.д
Попробуйте бесплатно

Оцени полезность:

10   голосов , оценка 4.2 из 5
Похожие ответы