UPDATED: Здесь гораздо более быстрый и правильный вариант программы!
Задача: сделать негатив(инверсию) bmp изображения.
Логика решения этой задачи очень похожа на предыдущую, но теперь мы не записываем пиксели в массив, а сразу их инверсируем и записываем в файл. Для этого используем свою функцию inv_byte.
static void inv_byte(FILE *fp) { fseek(fp, ftell(fp), SEEK_SET); // фикс для windows, на linux не обязателен int byte = getc(fp); fseek(fp, -1, SEEK_CUR); putc(~byte & 0xFF, fp); }
В этой функции мы сначала считываем байт, записывая его: int byte = getc(fp);
Далее смещаем указатель на один байт влево, так как функция getc его переместила
И записываем старший разряд инверсированного байта на место старого байта.
И так для каждого пиксела.
Стоит отметить что printf(«%.2f%%\n\033[0F», progress / pixels * 100) не будет правильно работать в консоли Windows. Поэтому для Windows нужно использовать следующий код:
system("cls"); printf("%.2f%%\n", progress / pixels * 100);
Файл main.h
#ifndef MAIN_H_INCLUDED #define MAIN_H_INCLUDED typedef struct { unsigned int bfType; unsigned long bfSize; unsigned int bfReserved1; unsigned int bfReserved2; unsigned long bfOffBits; } BITMAPFILEHEADER; typedef struct { unsigned int biSize; int biWidth; int biHeight; unsigned short biPlanes; unsigned short biBitCount; unsigned int biCompression; unsigned int biSizeImage; int biXPelsPerMeter; int biYPelsPerMeter; unsigned int biClrUsed; unsigned int biClrImportant; } BITMAPINFOHEADER; static unsigned short read_u16(FILE *fp); static unsigned int read_u32(FILE *fp); static int read_s32(FILE *fp); static void inv_byte(FILE *fp); #endif // MAIN_H_INCLUDEDs
Файл main.cpp
#include <iostream> #include <stdio.h> #include <stdlib.h> #include <stdint.h> #include "main.h" int main() { FILE *pFile = fopen("file.bmp", "r+b"); // считываем заголовок файла BITMAPFILEHEADER header __attribute__((unused)); header.bfType = read_u16(pFile); header.bfSize = read_u32(pFile); header.bfReserved1 = read_u16(pFile); header.bfReserved2 = read_u16(pFile); header.bfOffBits = read_u32(pFile); // считываем заголовок изображения BITMAPINFOHEADER bmiHeader; bmiHeader.biSize = read_u32(pFile); bmiHeader.biWidth = read_s32(pFile); bmiHeader.biHeight = read_s32(pFile); bmiHeader.biPlanes = read_u16(pFile); bmiHeader.biBitCount = read_u16(pFile); bmiHeader.biCompression = read_u32(pFile); bmiHeader.biSizeImage = read_u32(pFile); bmiHeader.biXPelsPerMeter = read_s32(pFile); bmiHeader.biYPelsPerMeter = read_s32(pFile); bmiHeader.biClrUsed = read_u32(pFile); bmiHeader.biClrImportant = read_u32(pFile); float pixels = bmiHeader.biWidth * bmiHeader.biHeight; float progress = 0; for (int i = 0; i < bmiHeader.biWidth; i++) { for (int j = 0; j < bmiHeader.biHeight; j++) { inv_byte(pFile); inv_byte(pFile); inv_byte(pFile); progress++; } // выводим процент готовности printf("%.2f%%\n\033[0F", progress / pixels * 100); // пропускаем последний байт в строке getc(pFile); } fclose(pFile); return 0; } static void inv_byte(FILE *fp) { fseek(fp, ftell(fp), SEEK_SET); // фикс для windows, на linux не обязателен int byte = getc(fp); fseek(fp, -1, SEEK_CUR); putc(~byte & 0xFF, fp); } static unsigned short read_u16(FILE *fp) { unsigned char b0, b1; b0 = getc(fp); b1 = getc(fp); return ((b1 << 8) | b0); } static unsigned int read_u32(FILE *fp) { unsigned char b0, b1, b2, b3; b0 = getc(fp); b1 = getc(fp); b2 = getc(fp); b3 = getc(fp); return ((((((b3 << 8) | b2) << 8) | b1) << 8) | b0); } static int read_s32(FILE *fp) { unsigned char b0, b1, b2, b3; b0 = getc(fp); b1 = getc(fp); b2 = getc(fp); b3 = getc(fp); return ((int)(((((b3 << 8) | b2) << 8) | b1) << 8) | b0); }