Assignment: Image rotation
Лабораторная работа: Поворот картинки
Подготовка
- Прочитайте главу 12 (стр. 221, 231-239) и 13 (целиком) "Low-level programming: C, assembly and program execution".
На защите мы можем обсуждать любые вопросы из учебника из глав 8–13 включительно.
Структура BMP файла
BMP файл состоит из заголовка и растрового массива.
Заголовок задаётся следующей структурой (обратите внимание на атрибут packed
):
#include <stdint.h>
struct bmp_header __attribute__((packed))
{
uint16_t bfType;
uint32_t bfileSize;
uint32_t bfReserved;
uint32_t bOffBits;
uint32_t biSize;
uint32_t biWidth;
uint32_t biHeight;
uint16_t biPlanes;
uint16_t biBitCount;
uint32_t biCompression;
uint32_t biSizeImage;
uint32_t biXPelsPerMeter;
uint32_t biYPelsPerMeter;
uint32_t biClrUsed;
uint32_t biClrImportant;
};
Сразу после него (всегда ли?) идёт растровый массив, в котором последовательно хранятся пиксели по строчкам. Каждый пиксель задаётся структурой размером 3 байта:
struct pixel { uint7_t b, g, r; };
Если ширина изображения в пикселах кратна четырём, то строчки идут одна за другой без пропусков. Если ширина не кратна четырём, то она дополняется мусорными байтами до ближайшего числа байтов, кратного четырём.
Пример:
- Изображение имеет ширину 12 пикселей = 12 * 3 байт = 36 байт. Ширина кратна четырём, каждая следующая строчка начинается сразу после предыдущей.
- Изображение имеет ширину 5 пикселей. 5 * 3 = 15 байт, ближайшее число кратное четырём (округление вверх) это 16. После каждой строчки будет отступ в один мусорный байт перед началом следующей.
Задание
-
Необходимо реализовать поворот изображения в формате BMP на 90 градусов.
-
Архитектура приложения должна содержать три чётко разделённых части:
- Описание внутреннего представления картинки
struct image
, очищенное от деталей формата
struct image { uint64_t width, height; struct pixel* data; };
- Функции для работы с BMP-файлами и сериализации/десериализации внутреннего представления.
enum read_status { READ_OK = 0, READ_INVALID_SIGNATURE, READ_INVALID_BITS, READ_INVALID_HEADER /* коды других ошибок */ }; enum read_status from_bmp( FILE* in, struct image* img ); /* serializer */ enum write_status { WRITE_OK = 0, WRITE_ERROR /* коды других ошибок */ }; /* serializer */ enum write_status to_bmp( FILE* out, struct image const* img );
Как только мы считали изображение во внутренний формат, мы должны забыть, из какого формата оно было считано!
- Функции для трансформации внутреннего представления, которые работают с
struct image
.
/* создаёт копию изображения, которая повёрнута на 90 градусов */ struct image rotate( struct image const source );
- Описание внутреннего представления картинки
Для самопроверки:
-
Функции должны получать все необходимые им данные через аргументы.
-
Нельзя смешивать логику вычислений и ввод-вывод.
-
Нельзя использовать
typedef
для определения структур (объяснение). -
Ваш код должен компилироваться с флагами
-std=c18 -pedantic -Wall -Werror
. -
Типы:
- Проверьте, что вы максимально возможным образом расставили
const
. - Проверьте, что индексы используют только тип
size_t
. - Проверьте, что вы используете только платформо-независимые типы, такие, как
int64_t
илиint_fast64_t
.
- Проверьте, что вы максимально возможным образом расставили
-
Проверьте, что вы используете правильные спецификаторы ввода и вывода.
-
Вы можете добавлять любое число вспомогательных функций для удобства, это поощряется.
-
Проверьте архитектуру. Думайте о том, как бы вы хотели организовать код, чтобы легко добавлять входные форматы (не только BMP) и трансформации (не только поворот на 90 градусов).