Считать 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);
}
}
}
Объяснение кода листинга программы
- Функция
rotateпринимает два аргумента: указатель на структуруBmpHeaderи указатель на массивimg. - Внутри функции объявлены две переменные
iиjдля использования в циклах. - Переменная
bytesинициализируется значениемhead->bitPixel / 8, гдеhead->bitPixel— количество бит на пиксель, а/ 8— деление на 8 для получения количества байт на пиксель. - Переменная
widthинициализируется значением(bytes * head->width + bytes) & (-4), гдеhead->width— ширина изображения в пикселях, аbytes— количество байт на пиксель. Значение& (-4)используется для округления значения в меньшую сторону до ближайшего числа, кратного 4. - Переменная
iинициализируется значением 0, а переменнаяjинициализируется значением 0. - В цикле
forперебираются все строки изображения от 0 доhead->height / 2 - 1. - Внутри цикла
forперебираются все столбцы изображения от 0 доhead->width - 1. - Внутри вложенного цикла
forпроисходит обмен значений двух указателей на массивimg. Первый указатель указывает на текущую строку изображения, второй указатель указывает на строку изображения, которая будет перевернута. - Значение переменной
bytesиспользуется для определения количества байт, которые необходимо обменять. - Функция
swapиспользуется для обмена значений двух указателей на массивimg. - Значение переменной
iувеличивается на 1 после каждой итерации внешнего циклаfor. - Значение переменной
jувеличивается на 1 после каждой итерации внутреннего циклаfor. - Значение переменной
widthиспользуется для определения длины строки изображения в байтах. - Значение переменной
head->heightиспользуется для определения высоты изображения в пикселях. - Значение переменной
head->widthиспользуется для определения ширины изображения в пикселях. - Значение переменной
bytesиспользуется для определения количества байт на пиксель. - Значение переменной
iиспользуется для определения номера строки изображения. - Значение переменной
jиспользуется для определения номера столбца изображения. - Значение переменной
head->bitPixelиспользуется для определения количества бит на пиксель. - Значение переменной
imgиспользуется для указания на массив, содержащий данные изображения.