Быстрый негатив bmp изображения в C++

Написал куда более быстрый вариант инверсии bmp изображения на C++, чем предыдущий. В этом варианте мы читаем изображение, записывая всю информацию о нём в массив, и создаём новое изображение с такими-же данными заголовков, но с инверсированными данными цветов. Всё работает значительно быстрее и код стал более простым.

Файл 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;
 
typedef struct
{
    int   rgbBlue;
    int   rgbGreen;
    int   rgbRed;
    int   rgbReserved;
} RGBQUAD;
 
 
static unsigned short read_u16(FILE *fp);
static unsigned int   read_u32(FILE *fp);
static int            read_s32(FILE *fp);
 
static void write_u16(unsigned short input, FILE *fp);
static void write_u32(unsigned int input, FILE *fp);
static void write_s32(int input, FILE *fp);
#endif // MAIN_H_INCLUDEDs

Файл main.cpp

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include "main.h"
 
int main()
{
    printf("Starting...\n");
    FILE *pFile = fopen("input.bmp", "rb");
 
    // считываем заголовок файла
    BITMAPFILEHEADER header;
 
    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);
 
 
    // инициализация массива пикселей
    RGBQUAD *pixels = new RGBQUAD[bmiHeader.biHeight * bmiHeader.biWidth];
 
    // читаем байты цветов
    for (int i = 0; i < bmiHeader.biHeight * bmiHeader.biWidth; i++) {
        pixels[i].rgbBlue = getc(pFile);
        pixels[i].rgbGreen = getc(pFile);
        pixels[i].rgbRed = getc(pFile);
    }
    fclose(pFile);
 
 
    FILE *oFile = fopen("output.bmp", "wb");
 
    // записываем заголовок файла
    write_u16(header.bfType, oFile);
    write_u32(header.bfSize, oFile);
    write_u16(header.bfReserved1, oFile);
    write_u16(header.bfReserved2, oFile);
    write_u32(header.bfOffBits, oFile);
 
    // записываем заголовок изображения
    write_u32(bmiHeader.biSize, oFile);
    write_s32(bmiHeader.biWidth, oFile);
    write_s32(bmiHeader.biHeight, oFile);
    write_u16(bmiHeader.biPlanes, oFile);
    write_u16(bmiHeader.biBitCount, oFile);
    write_u32(bmiHeader.biCompression, oFile);
    write_u32(bmiHeader.biSizeImage, oFile);
    write_s32(bmiHeader.biXPelsPerMeter, oFile);
    write_s32(bmiHeader.biYPelsPerMeter, oFile);
    write_u32(bmiHeader.biClrUsed, oFile);
    write_u32(bmiHeader.biClrImportant, oFile);
 
    // записываем байты цветов
    for (int i = 0; i < bmiHeader.biHeight * bmiHeader.biWidth; i++) {
        putc(~pixels[i].rgbBlue & 0xFF, oFile);
        putc(~pixels[i].rgbGreen & 0xFF, oFile);
        putc(~pixels[i].rgbRed & 0xFF, oFile);
    }
 
    fclose(oFile);
    printf("Complete\n");
    return 0;
}
 
 
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);
}
 
static void write_u16(unsigned short input, FILE *fp)
{
    putc(input, fp);
    putc(input >> 8, fp);
}
 
static void write_u32(unsigned int input, FILE *fp)
{
    putc(input, fp);
    putc(input >> 8, fp);
    putc(input >> 16, fp);
    putc(input >> 24, fp);
}
 
static void write_s32(int input, FILE *fp)
{
    putc(input, fp);
    putc(input >> 8, fp);
    putc(input >> 16, fp);
    putc(input >> 24, fp);
}
  • Pingback: Негатив bmp изображения на C++ | ziggi - blog()

  • raimur

    Все вроде хорошо но пиксели не в последовательности…Как быть и так и сяк крутил..
    #define _CRT_SECURE_NO_DEPRECATE

    #include
    #include
    #include
    #include
    #include

    using namespace std;

    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;

    typedef struct
    {
    int rgbBlue;
    int rgbGreen;
    int rgbRed;
    int rgbReserved;
    } RGBQUAD;

    static unsigned short read_u16(FILE *fp);
    static unsigned int read_u32(FILE *fp);
    static int read_s32(FILE *fp);

    static void write_u16(unsigned short input, FILE *fp);
    static void write_u32(unsigned int input, FILE *fp);
    static void write_s32(int input, FILE *fp);

    int main()
    {
    FILE * pFile = fopen("warrior1.bmp", "rb");
    FILE *oFile = fopen("rewarrior.bmp", "wb");

    // считываем заголовок файла
    BITMAPFILEHEADER header;

    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);

    RGBQUAD **rgb = new RGBQUAD*[bmiHeader.biWidth];
    for (int i = 0; i < bmiHeader.biWidth; i++) {
    rgb[i] = new RGBQUAD[bmiHeader.biHeight];
    }

    for (int i = 0; i < bmiHeader.biWidth; i++) {
    for (int j = 0; j < bmiHeader.biHeight; j++) {
    rgb[i][j].rgbReserved = 0;
    rgb[i][j].rgbBlue = getc(pFile);
    rgb[i][j].rgbGreen = getc(pFile);
    rgb[i][j].rgbRed = getc(pFile);
    }
    }

    //Запись в файл

    // записываем заголовок файла
    write_u16(header.bfType, oFile);
    write_u32(header.bfSize, oFile);
    write_u16(header.bfReserved1, oFile);
    write_u16(header.bfReserved2, oFile);
    write_u32(header.bfOffBits, oFile);

    // записываем заголовок изображения
    write_u32(bmiHeader.biSize, oFile);
    write_s32(bmiHeader.biWidth, oFile);
    write_s32(bmiHeader.biHeight, oFile);
    write_u16(bmiHeader.biPlanes, oFile);
    write_u16(bmiHeader.biBitCount, oFile);
    write_u32(bmiHeader.biCompression, oFile);
    write_u32(bmiHeader.biSizeImage, oFile);
    write_s32(bmiHeader.biXPelsPerMeter, oFile);
    write_s32(bmiHeader.biYPelsPerMeter, oFile);
    write_u32(bmiHeader.biClrUsed, oFile);
    write_u32(bmiHeader.biClrImportant, oFile);

    // записываем байты цветов
    /* for (int i = 0; i < bmiHeader.biHeight * bmiHeader.biWidth; i++) {
    putc(pixels[i].rgbBlue , oFile);
    putc(pixels[i].rgbGreen , oFile);
    putc(pixels[i].rgbRed , oFile);
    putc(pixels[i].rgbReserved, oFile);
    }*/
    for (int i = 0; i < bmiHeader.biWidth; i++) {
    for (int j = 0; j < bmiHeader.biHeight; j++) {
    putc(rgb[i][j].rgbBlue, oFile);
    putc(rgb[i][j].rgbGreen, oFile);
    putc(rgb[i][j].rgbRed, oFile);
    putc(rgb[i][j].rgbReserved, oFile);
    }
    }

    // выводим результат
    for (int i = 0; i < bmiHeader.biWidth-1; i++) {
    for (int j = 0; j < bmiHeader.biHeight-1; j++) {
    printf("%d %d %d %d\n", rgb[i][j].rgbRed, rgb[i][j].rgbGreen, rgb[i][j].rgbBlue, rgb[i][j].rgbReserved);
    }
    printf("\n");
    }

    fclose(pFile);
    fclose(oFile);
    _getch();
    return 0;
    }

    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, fp);
    }

    static void write_u32(unsigned int input, FILE *fp)
    {
    putc(input, fp);
    putc(input >> 8, fp);
    putc(input >> 16, fp);
    putc(input >> 24, fp);
    }

    static void write_s32(int input, FILE *fp)
    {
    putc(input, fp);
    putc(input >> 8, fp);
    putc(input >> 16, fp);
    putc(input >> 24, fp);
    }

  • raimur

    Эта программа просто открывает фаил и записывает его в другой
    Но заходит один а выходит горстка пикселей..Как быть? Помогите пожалуйста!

    • У BMP много стандартов, в этом примере это не учтено.

  • raimur

    Разобрался..Переписал. Если кому интересно

    #include 
    #include 
    #include 
    #include 
     
    using namespace std;
     
    int main()
    {
    	unsigned char r = 0, g = 0, b = 0, x = 0; //пиксели
    	std::ifstream is("warrior1.bmp", std::ios::binary); //Открытие входа
    	ofstream os("rewarrior.bmp", ios::binary); //Файл выхода
     
    	//---------------Заголовок-----------------------------------------
    	unsigned char signature[2];//Строка BM (в Windows).
    	is.read(reinterpret_cast(signature), sizeof(signature)); 
    	unsigned int fileSize;//Размер файла в байтах.
    	is.read(reinterpret_cast(&fileSize), sizeof(fileSize));
    	unsigned int reserved;//Зарезервированное поле. Нужно инициализировать нулём.
    	is.read(reinterpret_cast(&reserved), sizeof(reserved));
    	unsigned int offset;//Адрес с которого начинается собственно изображение. Или по другому - смещение к началу изображения.
    	is.read(reinterpret_cast(&offset), sizeof(offset));
    	//---------------Поля заголовка Windows V3:
    	unsigned int headerSize;//Размер заголовка.Всегда задаётся 40 байт.
    	is.read(reinterpret_cast(&headerSize), sizeof(headerSize));
    	unsigned int dimensions[2];//Ширина и высота изображения в пикселях.
    	is.read(reinterpret_cast(dimensions), sizeof(dimensions));
    	unsigned short colorPlanes;// Данное поле всегда содержит единицу.
    	is.read(reinterpret_cast(&colorPlanes), sizeof(colorPlanes));
    	unsigned short bpp;//Глубина цвета - количество битов в пикселе.
    	is.read(reinterpret_cast(&bpp), sizeof(bpp));
    	unsigned int compression;//Метод сжатия.
    	is.read(reinterpret_cast(&compression), sizeof(compression));
    	unsigned int imgSize;//Размер изображения. Здесь указывается размер непосредственно изображения - без учёта размера заголовков.
    	is.read(reinterpret_cast(&imgSize), sizeof(imgSize));
    	unsigned int resolution[2];//Горизонтальное и вертикальное разрешение в пикселях на метр (количество пикселей в одном метре).4 байта.
    	is.read(reinterpret_cast(resolution), sizeof(resolution));
    	unsigned int pltColors;//Количество цветов в палитре.
    	is.read(reinterpret_cast(&pltColors), sizeof(pltColors));
    	unsigned int impColors;//Количество важных цветов в палитре.*/
    	is.read(reinterpret_cast(&impColors), sizeof(impColors));
     
    	//--------------чтение пикселей--------------------------------------
    	char* Pixels = new char[dimensions[1] * dimensions[2] * bpp * 4 / 32];
    	for (unsigned int i = dimensions[1]; i > 0; --i)
    	{
    		for (unsigned int j = 0; j < dimensions[0]; ++j)
    		{
    			is.read(reinterpret_cast(&b), sizeof(b));
    			is.read(reinterpret_cast(&g), sizeof(g));
    			is.read(reinterpret_cast(&r), sizeof(r));
    			is.read(reinterpret_cast(&x), sizeof(x));
    			Pixels[(dimensions[0] * i + j) * 4] = b;
    			Pixels[(dimensions[0] * i + j) * 4 + 1] = g;
    			Pixels[(dimensions[0] * i + j) * 4 + 2] = r;
    			Pixels[(dimensions[0] * i + j) * 4 + 3] = 0;
    		}
    	}
     
    	is.close();
     
     
    	//Запись в файл
    	os.write(reinterpret_cast(signature), sizeof(signature));
    	os.write(reinterpret_cast(&fileSize), sizeof(fileSize));
    	os.write(reinterpret_cast(&reserved), sizeof(reserved));
    	os.write(reinterpret_cast(&offset), sizeof(offset));
     
    	os.write(reinterpret_cast(&headerSize), sizeof(headerSize));
    	os.write(reinterpret_cast(dimensions), sizeof(dimensions));
    	os.write(reinterpret_cast(&colorPlanes), sizeof(colorPlanes));
    	os.write(reinterpret_cast(&bpp), sizeof(bpp));
    	os.write(reinterpret_cast(&compression), sizeof(compression));
    	os.write(reinterpret_cast(&imgSize), sizeof(imgSize));
    	os.write(reinterpret_cast(resolution), sizeof(resolution));
    	os.write(reinterpret_cast(&pltColors), sizeof(pltColors));
    	os.write(reinterpret_cast(&impColors), sizeof(impColors));
     
    	for (unsigned int i = dimensions[1]; i > 0; --i)
    	{
    		for (unsigned int j = 0; j < dimensions[0]; ++j)
    		{
    			b = Pixels[(dimensions[0] * i + j) * 4];
    			g = Pixels[(dimensions[0] * i + j) * 4 + 1];
    			r = Pixels[(dimensions[0] * i + j) * 4 + 2];
    			x = 0;
    			os.write(reinterpret_cast(&b), sizeof(b));
    			os.write(reinterpret_cast(&g), sizeof(g));
    			os.write(reinterpret_cast(&r), sizeof(r));
    			os.write(reinterpret_cast(&x), sizeof(x));
    		}
    	}
     
    	os.close();
    	cout << "Done";
    	_getch();
    	return 0;
    }
Перейти к верхней панели