Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Курсовая работа.docx
Скачиваний:
36
Добавлен:
01.09.2021
Размер:
1.57 Mб
Скачать

Тестирование

На рисунке 1 представлено исходное изображение, разрешение 483 604, глубина цвета 32 бит, размер 1,11 Мб.

Рисунок 1 – Исходное изображение

  1. Масштабирование

На рисунке 2 представлено изображение, получившееся в результате выполнения программы. Разрешение 1000 500, размер 1,28 Мб.

Рисунок 2 – Изображение после масштабирование

  1. Уменьшение глубины цвета

На рисунке 3 представлено изображение после уменьшения глубины цвета до 4 бит, разрешение 483 604, размер 144 кб.

Рисунок 3 – Изображение после уменьшения глубины изображения до 4 бит

На рисунке 4 представлено изображение после уменьшения глубины цвета до 8 бит, разрешение 483 604, размер 286 кб.

Рисунок 4 – Изображение после уменьшения глубины изображения до 8 бит

Код реализации

Image* im1 = new Image((char*)"Безымянный.bmp"); // Создание объекта изображения из файла

Image* im2 = new Image(0, 24, 900, 500);// Создание изображения с заданными параметрами

Image im3, im4;// Создание пустого изображения

(*im2) /= *im1; // Приведение img к масштабу img2

im3 = *im1 / 8; // делаем битность 8

im4 = *im1 / 4; // делаем битность 4

im3.writeimage((char*)"img_8.bmp");

im4.writeimage((char*)"img_4.bmp");

im2->writeimage((char*)"img_res.bmp");

Вывод

В ходе выполнения работы был изучен теоретический материал для работы с bmp файлами. Также была написана программа, позволяющая изменять размер исходного изображения и глубину цвета до 4 и 8 бит. Для хранения изображения используется одномерный массив.

Листинг программы

#define _CRT_SECURE_NO_WARNINGS

#include <locale>

#include <stdio.h>

using namespace std;

#pragma pack(push,1)

struct BITMAPFILEHEADER

{

unsigned short Type;

unsigned long Size; // Размер файла в байтах, BitCount*Height*Width+ OffsetBits

unsigned short Reserved1; // Зарезервирован; должен быть нуль

unsigned short Reserved2; // Зарезервирован; должен быть нуль

unsigned long OffsetBits; // Смещение данных от начала файла в байтах

};

#pragma pack(pop)

#pragma pack(push,1)

struct BITMAPINFOHEADER

{

unsigned long Size; // Число байтов необходимое для структуры = 40

unsigned long Width; // Ширина точечного рисунка в пикселях

unsigned long Height; // Высота точечного рисунка в пикселях

unsigned short Planes; // Число плоскостей целевого устройства = 1

unsigned short BitCount; // Глубина цвета, число бит на точку = 0,1,4,8,16,24,32

unsigned long Compression; // Тип сжатия = 0 для несжатого изображения

unsigned long SizeImage; // Размер изображения в байтах BitCount*Height*Width

unsigned long XPelsPerMeter; // Разрешающая способность по горизонтали

unsigned long YPelsPerMeter; // Разрешающая способность по вертикали

unsigned long ColorUsed; // Число индексов используемых цветов. Если все цвета = 0

unsigned long ColorImportant; // Число необходимых цветов = 0

};

#pragma pack(pop)

#pragma pack(push,1)

struct RGBTRIPLE

{

unsigned char Blue;

unsigned char Green;

unsigned char Red;

};

#pragma pack(pop)

#pragma pack(push,1)

struct RGBQUAD

{

unsigned char Blue;

unsigned char Green;

unsigned char Red;

unsigned char Reserved;

};

#pragma pack(pop)

class Image {

BITMAPINFOHEADER BMInfoHeader; // Информационный заголовок изображения

RGBTRIPLE* Rgbtriple; // Массив с описанием пикселей типа RGBTRIPLE

RGBQUAD* Palette; // Палитра изображения(присутствует только, если глубина цвета равна 1, 4 или 8)

void setEmptyImageParams(); // Выставление внутренних параметров, соответствующих

// пустому изображению

int loadImageFF(FILE* f); // загружает изображение из переданного файла

void saveImageTF(FILE* f); // сохраняет изображение в файл

void SETHEADER(int Width, int Height, int BitCount); // устанавливает параметры заголовка изображения (BMInfoHeader)

// выделяет память под изображение

// если требуется форматом, создает и заполняет палитру

void INITIMAGE(const Image& Inp); // делает копию изображения (заполняет заголовок и копирует данные)

void copyDataIMAGE(const Image& Inp); // копирует данные при совпадении заголовков изображений

void copyAndConvertDataFromImage(const Image& Inp); // копирует и преобразует данные переданного изображения в текущий формат

bool COUNTBIT(unsigned short BitCount) // проверяет допустимость битности изображения

{

return BitCount == 24 || BitCount == 8 || BitCount == 4;

}

int addCOUNTBIT(int Width, unsigned short BitCount) // считает сколько нужно дописывать в файл байт после записи строки изображения,

// чтобы получить размет строки кратным 4

{

int remainder = getImageRowSize(Width, BitCount) % 4; // вычисляем остаток от деления длины строки на 4

return remainder ? 4 - remainder : 0; // возвращаем дополнение до 4

}

int getImageRowSize(int Width, unsigned short BitCount) // возвращает сколько байт требуется для записи строки изображения в файл

{

// Width * BitCount дает необходимое число бит для хранения строки изображения

// ((Width * BitCount + 7) / 8) вычисляет количество байт и округляет в большую сторону

return (Width * BitCount + 7) / 8;

}

int getTotalImageSize(int Width, int Height, unsigned short BitCount) // возвращает полный размер данных при записи в файл

{

// вычисляем сколько байт требуется для записи строки изображения в файл, добавляем нужное количество байт для кратности 4 и умножаем на количество строк

return (getImageRowSize(BMInfoHeader.Width, BMInfoHeader.BitCount) + addCOUNTBIT(Width, BitCount)) * Height;

}

unsigned char getGrayscaleColor(unsigned char Red, unsigned char Green, unsigned char Blue) // вычисляет градацию серого для переданного цвета

{

int result = Red * 0.299 + Green * 0.597 + Blue * 0.114; // формула из методички

if (result > 255) // проверяем выход за границы байта

{

result = 255;

}

return (unsigned char)result;

}

unsigned char getGrayscaleColor(RGBTRIPLE color) // вычисляет градацию серого для переданного цвета

{

return getGrayscaleColor(color.Red, color.Green, color.Blue);

}

unsigned char getGrayscaleColor(RGBQUAD color) // вычисляет градацию серого для переданного цвета

{

return getGrayscaleColor(color.Red, color.Green, color.Blue);

}

unsigned char getNearestPaletteColorIndex(unsigned char grayscaleColor) // бинарным поиском ищет ближайший цвет в палитре (так как она упорядочена по возрастанию оттенков серого)

{

int minIndex = 0; // установка минимального индекса для поиска

int maxIndex = BMInfoHeader.ColorUsed - 1; // установка максимального индекса для поиска

while (maxIndex >= minIndex) // продолжаем искать пока минимальный индекс не перейдет за максимальный

// (в этом случае значение grayscaleColor находится между Palette[minIndex - 1] и Palette[minIndex], так как сначала всегда

// проверяем можно ли изменить minIndex)

{

int middleIndex = (minIndex + maxIndex) / 2; // вычисление среднего индекса между крайними

if (Palette[middleIndex].Red == grayscaleColor) // проверяем не нашли ли искомое значение (так как палитка состоит из оттенков серого

// Palette[middleIndex].Red == Palette[middleIndex].Green == Palette[middleIndex].Blue)

{

return middleIndex; // возвращаем индекс палитры в случае успеха

}

else if (Palette[middleIndex].Red < grayscaleColor) // если текущее значение палитры оказалось меньше требуемого,

// сдвигаем левый край поиска

{

minIndex = middleIndex + 1;

}

else

maxIndex = middleIndex - 1; // если текущее значение палитры оказалось больше требуемого,

// сдвигаем правый край поиска

}

if (minIndex == BMInfoHeader.ColorUsed) // если minIndex стало равным общему количеству элементов, то значит переданное значение

// больше максимального значения в палитре

{

return BMInfoHeader.ColorUsed - 1; // поэтому возвращаем индекс наибольшего значения палитры

}

if (minIndex == 0) // если minIndex не изменился, то все время сдвигался правый конец области поиска

// значит значение grayscaleColor меньше минимального в палитре

{

return 0; // поэтому возвращаем индекс минимального значения палитры

}

int prevDelta = grayscaleColor - Palette[minIndex - 1].Red; // в оставшемся случае, как было указано ранее,

// значение grayscaleColor находится между Palette[minIndex - 1] и Palette[minIndex]

// потому считаем от какого значения оно отстоит меньше

int nextDelta = Palette[minIndex].Red - grayscaleColor;

return prevDelta < nextDelta ? minIndex - 1 : minIndex; // и возвращаем этот индекс

}

public:

Image(char Mode, unsigned short BCount, int Width, int Height); // Конструктор создания изображения

Image(char* fileName); // Конструктор объекта изображения из файла

Image(); // Конструктор без параметров, создает пустой контейнер под изображение

Image(const Image& i); // Конструктор копии

~Image(); // Деструктор

int loadimage(char* fileName); // метод загрузки изображения аналогичный конструктору, возвращает 0 в случае ошибки

void writeimage(char* fileName); // метод записи изображения в файл

Image& operator = (const Image& Inp); // Перегрузка оператора =

Image operator / (short Depth); // Перегрузка оператора /

Image& operator /= (const Image& Inp); // Перегрузка оператора /=

};

// Реализация конструктора без параметров

Image::Image()

{

setEmptyImageParams(); // Заполняем параметры пустого изображения

}

Image::Image(char* fileName)

{

setEmptyImageParams(); // Заполняем параметры пустого изображения

loadimage(fileName); // выполняем загрузку из файла с переданным именем

}

// Реализация деструктора

Image::~Image()

{

if (Rgbtriple) // Если есть указатель на данные, то нужно очистить выделенную под изображение память

{

/* for (int i = 0; i < BMInfoHeader.Height; i++) // Проходим по всем строкам изображения

{

delete[] Rgbtriple[i]; // и удаляем выделенную под строку память

}*/

delete[] Rgbtriple; // Удаляем память, содержащую массив указателей на строки

Rgbtriple = NULL; // Инициализируем указатель на данные невалидным значением

// (не обязательно, так как пороисходит в деструкторе)

}

if (Palette) // Удаление палитры, если она была создана

{

delete[] Palette;

Palette = NULL;

}

}

void Image::SETHEADER(int Width, int Height, int BitCount)

{

// Заполняем необходимые поля информации об изображении

BMInfoHeader.Width = Width; // Ширина точечного рисунка в пикселях

BMInfoHeader.Height = Height; // Высота точечного рисунка в пикселях

BMInfoHeader.Planes = 1; // Число плоскостей целевого устройства = 1

BMInfoHeader.BitCount = BitCount; // Глубина цвета, число бит на точку

BMInfoHeader.SizeImage = getTotalImageSize(Width, Height, BitCount); // Размер изображения в байтах

if (BMInfoHeader.BitCount <= 8)

{

BMInfoHeader.ColorUsed = 1 << BMInfoHeader.BitCount; // = 2 в степени BMInfoHeader.BitCount

Palette = new RGBQUAD[BMInfoHeader.ColorUsed]; // Выделение памяти под палитру цветов

for (int i = 0; i < BMInfoHeader.ColorUsed; i++) // заполняем значения палитры градациями серого от 0 до 255

{

unsigned char color = (255 * i / (BMInfoHeader.ColorUsed - 1));

Palette[i].Red = color;

Palette[i].Green = color;

Palette[i].Blue = color;

Palette[i].Reserved = 0;

}

}

// Выделение памяти для двумерного массива размером Height*Width типа RGBTRIPLE

// Выделяем память под указатели на строки

if (BMInfoHeader.SizeImage > 0)

{

Rgbtriple = new RGBTRIPLE[BMInfoHeader.Height * BMInfoHeader.Width];

/*Rgbtriple = new RGBTRIPLE * [BMInfoHeader.Height];

for (int i = 0; i < BMInfoHeader.Height; i++)

{

// Выделяем память под каждую строку изображения

Rgbtriple[i] = new RGBTRIPLE[BMInfoHeader.Width];

}*/

}

else

{

Rgbtriple = NULL;

}

}

// Реализация конструктора создания изображения

Image::Image(char Mode, unsigned short BCount, int Width, int Height)

{

// Выставление начальных параметров, соответствующих пустому изображению

setEmptyImageParams();

// Проверяем какую желаемую битность нам передали в конструктор

// Поддерживается хранение данных только в RGBTRIPLE

if (COUNTBIT(BCount))

{

SETHEADER(Width, Height, BCount); // заполняем заголовок изображения и выделяем памят

if (Palette)

{

Mode = Palette[getNearestPaletteColorIndex(Mode)].Red; // получаем ближайший к переданному цвет в палитре, если она используется

}

// Заполнение данных изображения переданным значением

for (int i = 0; i < (int)BMInfoHeader.Height; i++){

for (int j = 0; j < (int)BMInfoHeader.Width; j++)

{

Rgbtriple[i * BMInfoHeader.Width + j].Red = Mode;

Rgbtriple[i * BMInfoHeader.Width + j].Green = Mode;

Rgbtriple[i * BMInfoHeader.Width + j].Blue = Mode;

}

}

}

// Задали неподдерживаемый параметр битности

}

// Выставление параметров, соответствующих пустому изображению

void Image::setEmptyImageParams()

{

Rgbtriple = NULL;

Palette = NULL;

BMInfoHeader.Size = 40;

BMInfoHeader.Width = 0;

BMInfoHeader.Height = 0;

BMInfoHeader.Planes = 0;

BMInfoHeader.BitCount = 0;

BMInfoHeader.Compression = 0;

BMInfoHeader.SizeImage = 0;

BMInfoHeader.XPelsPerMeter = 0;

BMInfoHeader.YPelsPerMeter = 0;

BMInfoHeader.ColorUsed = 0;

BMInfoHeader.ColorImportant = 0;

}

int Image::loadImageFF(FILE* f)

{

BITMAPFILEHEADER BMFileHeader;

// считываем заголовок изображения

fread(&BMFileHeader, sizeof(BITMAPFILEHEADER), 1, f);

// загружаем заголовок изображения

BITMAPINFOHEADER FileBMInfoHeader;

fread(&FileBMInfoHeader, sizeof(BITMAPINFOHEADER), 1, f);

// заполняем заголовок и выделяем память для картинки, описанной в файле

SETHEADER(FileBMInfoHeader.Width, FileBMInfoHeader.Height, FileBMInfoHeader.BitCount);

RGBQUAD* filePalette = NULL;

// Создаем и загружаем файловую палитру, если она присутствует

if (BMInfoHeader.BitCount <= 8)

{

filePalette = new RGBQUAD[BMInfoHeader.ColorUsed];

fread(filePalette, sizeof(RGBQUAD), BMInfoHeader.ColorUsed, f);

}

// переходим к началу данных изображения

fseek(f, BMFileHeader.OffsetBits, SEEK_SET);

// вычисляем смещение между строками

const int additionalRowOffset = addCOUNTBIT(FileBMInfoHeader.Width, FileBMInfoHeader.BitCount);

if (FileBMInfoHeader.BitCount == 24)

{

for (int i = BMInfoHeader.Height - 1; i >= 0; i--)

{

// считываем сразу всю строку изображенмя, так как она совпадает с внутренним форматом хранения в памяти

fread(Rgbtriple + i * FileBMInfoHeader.Width, sizeof(RGBTRIPLE), FileBMInfoHeader.Width, f);//

//fread(Rgbtriple[i], sizeof(RGBTRIPLE), FileBMInfoHeader.Width, f);

// пропускаем смещение между строками

if (additionalRowOffset)

{

fseek(f, additionalRowOffset, SEEK_CUR);

}

}

}

else if (FileBMInfoHeader.BitCount == 32)

{

// считываем каждый пиксель отдельно

for (int i = BMInfoHeader.Height - 1; i >= 0; i--)

{

for (int j = 0; j < BMInfoHeader.Width; j++)

{

RGBQUAD fileQuad;

fread(&fileQuad, sizeof(RGBQUAD), 1, f);

Rgbtriple[i * BMInfoHeader.Width + j].Red = fileQuad.Red;

Rgbtriple[i * BMInfoHeader.Width + j].Green = fileQuad.Green;

Rgbtriple[i * BMInfoHeader.Width + j].Blue = fileQuad.Blue;

}

}

}

else // загрузка изображений с палитрой

{

const unsigned char topBitsOffset = 8 - BMInfoHeader.BitCount; // показывает на сколько нужно переметить биты из старшей части байта, чтобы получить цвет

unsigned char colorMask = (1 << BMInfoHeader.BitCount) - 1; // выставляем младшие BMInfoHeader.BitCount бит в 1 для получения маски цвета

colorMask <<= 8 - BMInfoHeader.BitCount; // перемещаем эти единицы в старшие биты байта, так как данные располагаются от старших битов к младшим

for (int i = BMInfoHeader.Height - 1; i >= 0; i--)

{

int leftBits = 0; // указывает сколько непрочитанных бит осталось в байте

unsigned char paletteByte = 0; // текущий считанный байт в изображении

for (int j = 0; j < BMInfoHeader.Width; j++)

{

if (!leftBits) // если в текущем байте рассмотрели все биты, то считываем следующий

{

fread(&paletteByte, 1, 1, f);

leftBits = 8;

}

int paletteIndex = (paletteByte & colorMask) >> topBitsOffset; // получаем текущий индекс в палитре файла применением маски и сдвигом

// полученного значения

leftBits -= BMInfoHeader.BitCount; // обновляем количество необработанных бит

paletteByte <<= BMInfoHeader.BitCount; // перемещаем их в старшую часть байта

unsigned char sourceGrayscale = getGrayscaleColor(filePalette[paletteIndex]); // вычисляем оттенок серого для цвета пикселя из файла

unsigned char grayscale = Palette[getNearestPaletteColorIndex(sourceGrayscale)].Red; // получаем ближайший к нему цвет из палиты

// заполняем данные изображения

Rgbtriple[i * BMInfoHeader.Width + j].Red = grayscale;

Rgbtriple[i * BMInfoHeader.Width + j].Green = grayscale;

Rgbtriple[i * BMInfoHeader.Width + j].Blue = grayscale;

}

// пропускаем смещение между строками изображения в файле

if (additionalRowOffset)

{

fseek(f, additionalRowOffset, SEEK_CUR);

}

}

}

// удаляем файловую палитру, если она была создана

if (filePalette)

{

delete[] filePalette;

}

return 1;

}

// Реализация метода загрузки изображения

int Image::loadimage(char* fileName)

{

FILE* f;

// открываем требуемый файл

f = fopen(fileName, "rb"); // необходимо открывать бинарный файл

// производим загрузку данных

int resultCode = loadImageFF(f);

// закрываем файл

fclose(f);

return resultCode;

}

void Image::saveImageTF(FILE* f) // сохраняет данные в переданный файл

{

// получаем смещение между строками изображения в файле

const int additionalRowOffset = addCOUNTBIT(BMInfoHeader.Width, BMInfoHeader.BitCount);

// Заполняем заголовок файла BMP

BITMAPFILEHEADER BMFileHeader;

BMFileHeader.Type = 0x4D42; // сигнатура

BMFileHeader.OffsetBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER); // смещение до данных изображения

// полный размер файла = сумма размера всех заголовков, палитры и данных файла

BMFileHeader.Size = BMFileHeader.OffsetBits + getTotalImageSize(BMInfoHeader.Width, BMInfoHeader.Height, BMInfoHeader.BitCount);

BMFileHeader.Reserved1 = 0; // не используется

BMFileHeader.Reserved2 = 0; // не используется

if (Palette) // добавляем данные о палитре

{

const int paletteSize = sizeof(RGBQUAD) * BMInfoHeader.ColorUsed; // вычисляем размер палитры

BMFileHeader.Size += paletteSize; // добавляем его к общему размеру файла

BMFileHeader.OffsetBits += paletteSize; // и к смещению до данных изображения

}

// записываем заголовок файла

fwrite(&BMFileHeader, sizeof(BITMAPFILEHEADER), 1, f);

// записываем заголовок изображения

fwrite(&BMInfoHeader, sizeof(BITMAPINFOHEADER), 1, f);

if (BMInfoHeader.BitCount == 24)

{

for (int i = BMInfoHeader.Height - 1; i >= 0; i--)

{

// для формата 24 бит просто копируем в файл строку изображения, так как он совпадает с внутренним форматом хранения

fwrite(Rgbtriple + i * BMInfoHeader.Width, sizeof(RGBTRIPLE), BMInfoHeader.Width, f);

// записываем нужное количество 0 для смещения между строками изображения

if (additionalRowOffset)

{

const int Zero = 0;

fwrite(&Zero, 1, additionalRowOffset, f);

}

}

}

else // изображение с палитрой

{

// вычисляем смещение необходимое для перемещения индекса цвета первого пикселя в старшие биты

const int startPaletteDataOffset = 8 - BMInfoHeader.BitCount;

// сохранение изображений с палитрой

for (int i = BMInfoHeader.Height - 1; i >= 0; i--)

{

int currentPaletteDataOffset = startPaletteDataOffset; // выставляем на сколько нужно сместить следующее значение при записи в байт

int leftBits = 8; // храним сколько бит еще можно использовать в байте

int paletteByte = 0; // хранит текущее значение для записи в файл

for (int j = 0; j < BMInfoHeader.Width; j++)

{

unsigned char paletteColorIndex = getNearestPaletteColorIndex(Rgbtriple[i * BMInfoHeader.Width + j].Red); // получаем индекс палитры для текущего цвета

paletteByte |= paletteColorIndex << currentPaletteDataOffset; // смещаем его на нужное количество бит и записываем в результат

currentPaletteDataOffset -= BMInfoHeader.BitCount; // уменьшаем требуемый сдвиг для следующего индека

leftBits -= BMInfoHeader.BitCount; // уменьшаем количество оставшихся бит

if (!leftBits)

{

// если кончились свободные биты, то записываем собранный байт в файл

fwrite(&paletteByte, 1, 1, f);

// и выставляем параметры на начальные

currentPaletteDataOffset = startPaletteDataOffset;

leftBits = 8;

paletteByte = 0;

}

}

// если после завершения обработки строки остались незаписанные биты (байт полностью не заполнился), то записываем их в файл

if (leftBits != 8)

{

fwrite(&paletteByte, 1, 1, f);

}

// записываем нужное количество 0 для смещения между строками изображения

if (additionalRowOffset)

{

const int Zero = 0;

fwrite(&Zero, 1, additionalRowOffset, f);

}

}

}

}

void Image::INITIMAGE(const Image& Inp) // делает копию изображения (заполняет заголовок и копирует данные)

{

setEmptyImageParams(); // Заполняем параметры пустого изображения

SETHEADER(Inp.BMInfoHeader.Width, Inp.BMInfoHeader.Height, Inp.BMInfoHeader.BitCount); // заполняем заголовок и выделяем нужную память

copyDataIMAGE(Inp); // копируем данные изображения

}

void Image::copyDataIMAGE(const Image& Inp)

{

// Проверяем совпадение разрешения и битности, после чего скопируем данные

if (BMInfoHeader.Width == Inp.BMInfoHeader.Width

&& BMInfoHeader.Height == Inp.BMInfoHeader.Height

&& BMInfoHeader.BitCount == Inp.BMInfoHeader.BitCount)

{

//Копирование строк изображения

//const int rowSize = BMInfoHeader.Width * sizeof(RGBTRIPLE);

memcpy(Rgbtriple, Inp.Rgbtriple, BMInfoHeader.Height * BMInfoHeader.Width * sizeof(RGBTRIPLE));

/* for (int i = 0; i < BMInfoHeader.Height; ++i)

{

memcpy(Rgbtriple[i], Inp.Rgbtriple[i], rowSize);

}*/

// Замечание: палитру не копируем, так как она создается автоматически при инициализации заголовка изображения

// и одинакова для выбранной битности

}

}

Image::Image(const Image& im)

{

INITIMAGE(im); // делаем копию изображения

}

void Image::writeimage(char* fileName) // выполняет запись в файл

{

FILE* f;

f = fopen(fileName, "w+b"); // необходимо открывать бинарный файл

saveImageTF(f); // сохраняет данные в файл

fclose(f);

}

Image& Image::operator = (const Image& Inp) // Перегрузка оператора =

{

if (Rgbtriple) // если изображение уже создано

{

copyDataIMAGE(Inp); // то пробуем только скопировать данные (при совпадении форматов)

}

else

{

INITIMAGE(Inp); // иначе создаем копию

}

return *this;

}

void Image::copyAndConvertDataFromImage(const Image& Inp) // функция преобразования данных переданного изображения в текущий формат

{

const bool isSourceWithPalette = Inp.Palette != NULL; // используется ли в исходном изображении палитра

for (int i = 0; i < BMInfoHeader.Height; i++)

{

for (int j = 0; j < BMInfoHeader.Width; j++)

{

unsigned char grayscale = isSourceWithPalette ? Inp.Rgbtriple[i * BMInfoHeader.Width + j].Red // для исходного изображения с палитрой берем оттенок серого сразу из данных картинки

: getGrayscaleColor(Inp.Rgbtriple[i * BMInfoHeader.Width + j]); // иначе вычисляем его

grayscale = Palette[getNearestPaletteColorIndex(grayscale)].Red; // получаем значение серого в палитре итогового изображения

// записываем оттенок серого в пиксель итогового изображения

Rgbtriple[i * BMInfoHeader.Width + j].Red = grayscale;

Rgbtriple[i * BMInfoHeader.Width + j].Green = grayscale;

Rgbtriple[i * BMInfoHeader.Width + j].Blue = grayscale;

}

}

}

Image Image::operator / (short Depth) // Перегрузка оператора

{

Image result(0, Depth, BMInfoHeader.Width, BMInfoHeader.Height); // создаем пустое изображение

result.copyAndConvertDataFromImage(*this); // выполняем преобразование текущего изображения в итоговое

return result;

}

Image& Image::operator /= (const Image& Inp) // Перегрузка оператора /=, выполняет запись переданного изображения в текущее с изменением размера

{

float xRatio = (float)Inp.BMInfoHeader.Width / BMInfoHeader.Width; // вычисление соотношения ширины изображений

float yRatio = (float)Inp.BMInfoHeader.Height / BMInfoHeader.Height; // вычисление соотношения высоты изображений

for (int i = 0; i < BMInfoHeader.Height; i++)

{

for (int j = 0; j < BMInfoHeader.Width; j++)

{

int sourceX = (int)(j * xRatio); // вычисление x координаты в исходном изображении

int sourceY = (int)(i * yRatio); // вычисление y координаты в исходном изображении

Rgbtriple[i * BMInfoHeader.Width + j] = Inp.Rgbtriple[sourceY * Inp.BMInfoHeader.Width + sourceX]; // запись значения цвета из исходного изображения в текущее

}

}

return *this;

}

int main(void)

{

setlocale(LC_ALL, "Russian");

Image* im1 = new Image((char*)"Image.bmp"); // Создание объекта изображения из файла

Image* im2 = new Image(0, 24, 900, 500);// Создание изображения с заданными параметрами

Image im3, im4;// Создание пустого изображения

(*im2) /= *im1; // Приведение img к масштабу img2

im3 = *im1 / 8; // делаем битность 8

im4 = *im1 / 4; // делаем битность 4

im3.writeimage((char*)"img_8.bmp");

im4.writeimage((char*)"img_4.bmp");

im2->writeimage((char*)"img_res.bmp");

return 0;

}

Соседние файлы в предмете Технология программирования