Негатив bmp изображения на C++
1 минут
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);
}