Commit 409b47ef authored by Igor Zhirkov's avatar Igor Zhirkov
Browse files

Update the assignment task text

parent 82c0522a
......@@ -14,6 +14,7 @@ BMP файл состоит из заголовка и растрового ма
Заголовок задаётся следующей структурой (обратите внимание на атрибут `packed`):
```c
// Описание для gcc и clang
#include <stdint.h>
struct bmp_header __attribute__((packed))
{
......@@ -39,33 +40,74 @@ struct bmp_header __attribute__((packed))
Каждый пиксель задаётся структурой размером 3 байта:
```c
struct pixel { uint7_t b, g, r; };
struct pixel { uint8_t b, g, r; };
```
## Padding
Если ширина изображения в пикселах кратна четырём, то строчки идут одна за другой без пропусков.
Если ширина не кратна четырём, то она дополняется мусорными байтами до ближайшего числа байтов, кратного четырём.
Эти байты называются *padding*.
Пример:
1. Изображение имеет ширину 12 пикселей = 12 * 3 байт = 36 байт. Ширина кратна четырём, каждая следующая строчка начинается сразу после предыдущей.
2. Изображение имеет ширину 5 пикселей. 5 * 3 = 15 байт, ближайшее число кратное четырём (округление вверх) это 16. После каждой строчки будет отступ в один мусорный байт перед началом следующей.
Обратите внимание: отступы в *байтах*, не в пикселях.
# Пользователям компилятора от Microsoft
Вам придётся задать структуру по-другому, без атрибута `packed`:
```c
#include <stdint.h>
#pragma pack(push, 1)
struct bmp_header
{
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;
};
#pragma pack(pop)
```
Объяснение этого прочтите находится на страницах 235&ndash;239 учебника.
# Задание
- Необходимо реализовать поворот изображения в формате BMP на 90 градусов.
- Архитектура приложения должна содержать три чётко разделённых части:
- Описание внутреннего представления картинки `struct image`, очищенное от деталей формата
- Описание внутреннего представления картинки `struct image`, очищенное от деталей формата, и функции для работы с ним: создание, деинициализация и т.д.
```c
struct image {
uint64_t width, height;
struct pixel* data;
};
```
- Функции для работы с BMP-файлами и сериализации/десериализации внутреннего представления.
```c
/* deserializer */
enum read_status {
READ_OK = 0,
READ_INVALID_SIGNATURE,
......@@ -73,71 +115,73 @@ struct bmp_header __attribute__((packed))
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 );
```
Как только мы считали изображение во внутренний формат, мы должны забыть, из какого формата оно было считано! Иначе будет сложнее добавлять новые входные форматы, отличные от BMP (почему?).
Как только мы считали изображение во внутренний формат, мы должны забыть, из какого формата оно было считано!
- Функции `from_bmp` и `to_bmp` принимают уже открытый файл, что позволяет
им работать с заранее открытыми файлами `stdin`, `stdout`, `stderr`.
Они не должны ни открывать, ни закрывать файлы.
- Вам потребуются функции, аналогичные `from_bmp` и `to_bmp`, которые будут
принимать имена файлов и заниматься корректным открытием (`fopen`) и
закрытием (`fclose`) файлов; на открытых файлах они могут запускать `from_bmp`
и `to_bmp`.
- Функции для трансформации внутреннего представления, которые работают с `struct image`.
Имеет смысл разделять открытие/закрытие файлов и работу с ними. Уже
открытие и закрытие могут сопровождаться ошибками (см. `man fopen` и
`man fclose`) и хочется отделить обработку ошибок открытия/закрытия и
обработку ошибок чтения/записи.
```c
/* создаёт копию изображения, которая повёрнута на 90 градусов */
struct image rotate( struct image const source );
```
- Для ошибок открытия/закрытия, возможно, вам захочется ввести отдельные типы перечислений.
# Пользователям компилятора от Microsoft
- Вам потребуется функция для поворота картинки в её внутреннем представлении:
Вам придётся задать структуру по-другому, без атрибута `packed`:
```c
/* создаёт копию изображения, которая повёрнута на 90 градусов */
struct image rotate( struct image const source );
```
```c
#include <stdint.h>
#pragma pack(push, 1)
struct bmp_header
{
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;
};
#pragma pack(pop)
```
Объяснение этого прочтите находится на страницах 235&ndash;239 учебника.
Эти части имеет смысл держать **в разных модулях (файлах с расширением `.c`)**. Разумеется, для каждого нужен соответствующий заголовочный файл.
- Кроме того, дополнительные функции, которые вы ввели для удобства, но
которые не относятся по смыслу ни к одному из этих модулей, можно выделить
в отдельный модуль. Часто его называют `util.c` или как-то похоже.
# Для самопроверки:
- Функции должны получать все необходимые им данные через аргументы.
- Нельзя смешивать логику вычислений и ввод-вывод.
- Нельзя использовать `typedef` для определения структур ([объяснение](https://stepik.org/lesson/408350/step/2)).
- Ваш код должен компилироваться с флагами `-std=c18 -pedantic -Wall -Werror`.
- Нельзя использовать `typedef` для определения структур ([объяснение](https://stepik.org/lesson/408350/step/2)), кроме структур из одного поля, которые являются аналогом `typedef`, но без неявных преобразований.
- Ваш код должен компилироваться с флагами `-std=c18 -pedantic -Wall -Werror` (gcc) или `-std=c18 -pedantic -Wall -Werror` (clang).
Пользователям MS Visual Studio придётся тяжко, поддержка C11/C17 пока есть только в [Visual Studio 2019 version 16.8 Preview 3](https://devblogs.microsoft.com/cppblog/c11-and-c17-standard-support-arriving-in-msvc).
Можете попробовать использовать [`cl-clang`](https://clang.llvm.org/docs/MSVCCompatibility.html).
Проверять Ваш код мы будем с помощью `gcc` и `Makefile`.
- Типы:
- Проверьте, что вы максимально возможным образом расставили `const`.
- Проверьте, что индексы используют только тип `size_t`.
- Проверьте, что вы используете только платформо-независимые типы, такие, как `int64_t` или `int_fast64_t`.
- Проверьте, что вы используете правильные спецификаторы ввода и вывода.
- Вы можете добавлять любое число вспомогательных функций для удобства, это поощряется.
- Проверьте архитектуру. Думайте о том, как бы вы хотели организовать код, чтобы легко добавлять входные форматы (не только BMP) и трансформации (не только поворот на 90 градусов).
- Проверьте архитектуру. **Решение внутри одного файла приниматься не будет**.
Думайте о том, как бы вы хотели организовать код, чтобы легко добавлять входные форматы (не только BMP) и трансформации (не только поворот на 90 градусов).
- Пожалуйста, присылайте решение в виде ссылки на репозиторий на https://gitlab.se.ifmo.ru или https://github.com .
- Не забудьте написать `Makefile`. Он должен позволять при изменении одного `.c` файла пересобрать часть проекта не пересобирая всё остальное.
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment