Негатив bmp изображения на C++

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);
}
Перейти к верхней панели