Объяснение этого прочтите находится на страницах 235–239 учебника.
# Об архитектуре
# Задание
Программа разделена на модули; каждый модуль это `.c` файл, который становится файлом с расширением `.o`.
**ВНИМАНИЕ**`view-header` это программа для просмотра заголовков BMP файлов. Это не заготовка для решения! Можете скомпилировать её с помощью `make` и проверять заголовки на битность; в решении вам нужно поддерживать только 24-битные BMP файлы.
Продуманная архитектура приложения в каждом конкретном модуле минимизирует знания о других модулях по следующим причинам:
- Когда программист работает над одним модулем (разрабатывает, модифицирует, ищет ошибки), ему проще не держать в голове знания про всю остальную программу.
- Пусть модуль A не использует определения из модуля B, но имеет к ним доступ. Разумеется, можно как угодно менять B и это не скажется на A.
Однако есть шанс, что автор программы или кто-то из будущих соавторов может использовать в модуле A определения из B — ведь к ним есть доступ.
Это установит жёсткую связь между A и B, и будет нельзя больше свободно менять B не влияя на A. Программы являются сложными системами, и мы хотим иметь минимум связей между их элементами, иначе модификация (и исправление ошибок) будут требовать постоянной модификации не одной, а многих частей программы.
В нашем случае в программе разумно выделить несколько частей.
- Необходимо реализовать поворот изображения в формате BMP на 90 градусов.
- Архитектура приложения должна содержать три чётко разделённых части:
-Описание внутреннего представления картинки `struct image`, очищенное от деталей формата, и функции для работы с ним: создание, деинициализация и т.д.
## Часть 1: Внутренний формат
Описание внутреннего представления картинки `struct image`, очищенное от деталей формата, и функции для работы с ним: создание, деинициализация и т.д.
```c
structimage{
...
...
@@ -106,67 +112,96 @@ struct bmp_header
structpixel*data;
};
```
Эта часть программы не должна знать ни про входные форматы, ни про трансформации.
## Часть 2: Входные форматы
Каждый входной формат описывается в отдельном модуле; они предоставляют функции для считывания файлов разных форматов в `struct image` и для записи на диск в тех же форматах.
Эти модули знают про модуль, описывающий `struct image`, но ничего не знают про трансформации. Поэтому можно будет добавлять новые трансформации не переписывая код для входных форматов.
Как только мы считали изображение во внутренний формат, мы должны забыть, из какого формата оно было считано! Именно поэтому в `struct image` оставлен только самый минимум деталей изображения (размеры), и никаких частей bmp-заголовка.
Функции `from_bmp` и `to_bmp` принимают уже открытый файл, что позволяет
им работать с заранее открытыми файлами `stdin`, `stdout`, `stderr`.
Функции `from_bmp` и `to_bmp` не должны ни открывать, ни закрывать файлы. Для ошибок открытия/закрытия, возможно, вам захочется ввести отдельные типы перечислений.
```
Как только мы считали изображение во внутренний формат, мы должны забыть, из
какого формата оно было считано! Именно поэтому в `struct image` оставлен
только самый минимум деталей изображения (размеры), и никаких частей
bmp-заголовка.
Как только мы считали изображение во внутренний формат, мы должны забыть, из какого формата оно было считано! Иначе будет сложнее добавлять новые входные форматы, отличные от BMP (почему?).
Вам также потребуются функции, аналогичные `from_bmp` и `to_bmp`, которые будут
принимать имена файлов и заниматься корректным открытием (`fopen`) и
закрытием (`fclose`) файлов; на открытых файлах они могут запускать `from_bmp`
и `to_bmp`.
- Функции `from_bmp` и `to_bmp` принимают уже открытый файл, что позволяет
им работать с заранее открытыми файлами `stdin`, `stdout`, `stderr`.
Они не должны ни открывать, ни закрывать файлы.
- Вам потребуются функции, аналогичные `from_bmp` и `to_bmp`, которые будут
принимать имена файлов и заниматься корректным открытием (`fopen`) и
закрытием (`fclose`) файлов; на открытых файлах они могут запускать `from_bmp`
и `to_bmp`.
Имеет смысл разделять открытие/закрытие файлов и работу с ними. Уже
открытие и закрытие могут сопровождаться ошибками (см. `man fopen` и
`man fclose`) и хочется отделить обработку ошибок открытия/закрытия и
обработку ошибок чтения/записи.
## Часть 3: Трансформации
Каждая трансформация описывается в отдельном модуле. Эти модули знают про модуль, описывающий `struct image`, но ничего не знают про входные форматы.
Поэтому можно будет добавлять новые входные форматы не переписывая код для трансформаций. Без дополнительных усилий мы получим возможность, описав входной формат, сразу же поддержать все трансформации над ним.
Вам потребуется функция для поворота картинки в её внутреннем представлении:
```c
/* создаёт копию изображения, которая повёрнута на 90 градусов */
structimagerotate(structimageconstsource);
```
**ВНИМАНИЕ**`view-header` это программа для просмотра заголовков BMP файлов. Это не заготовка для решения! Можете скомпилировать её с помощью `make` и проверять заголовки на битность; в решении вам нужно поддерживать только 24-битные BMP файлы.
Имеет смысл разделять открытие/закрытие файлов и работу с ними. Уже
открытие и закрытие могут сопровождаться ошибками (см. `man fopen` и
`man fclose`) и хочется отделить обработку ошибок открытия/закрытия и
обработку ошибок чтения/записи.
## Часть 4: всё остальное
- Для ошибок открытия/закрытия, возможно, вам захочется ввести отдельные типы перечислений.
Остальная часть программы может быть организована любым осмысленным способом. Возможно, вам захочется написать небольшую библиотеку для ввода-вывода, работы со строками и т.д.
- Вам потребуется функция для поворота картинки в её внутреннем представлении:
Приветствуется разумное создание новых модулей и введение дополнительных функций для удобства, где это необходимо.
```c
/* создаёт копию изображения, которая повёрнута на 90 градусов */
struct image rotate( struct image const source );
```
Дополнительные функции, которые вы ввели для удобства, но которые не относятся по смыслу ни к одному из этих модулей, можно выделить
в отдельный модуль. Часто его называют `util.c` или как-то похоже.
# Задание
Эти части имеет смысл держать **в разных модулях (файлах с расширением `.c`)**. Разумеется, для каждого нужен соответствующий заголовочный файл.
- Кроме того, дополнительные функции, которые вы ввели для удобства, но
которые не относятся по смыслу ни к одному из этих модулей, можно выделить
в отдельный модуль. Часто его называют `util.c` или как-то похоже.
- Необходимо реализовать поворот изображения в формате BMP на 90 градусов по часовой стрелке. Имя изображения принимайте в аргументе командной строки.
- Архитектура приложения описана в предыдущем разделе.
# Для самопроверки
- Прочитайте [правила хорошего стиля](https://gitlab.se.ifmo.ru/c-language/main/-/wikis/%D0%9F%D1%80%D0%B0%D0%B2%D0%B8%D0%BB%D0%B0-%D1%81%D1%82%D0%B8%D0%BB%D1%8F-%D0%BD%D0%B0%D0%BF%D0%B8%D1%81%D0%B0%D0%BD%D0%B8%D1%8F-%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC-%D0%BD%D0%B0-C). Ваше решение должно им соответствовать.
- Архитектура: думайте о том, как бы вы хотели организовать код, чтобы легко добавлять входные форматы (не только BMP) и трансформации (не только поворот на 90 градусов).
- Пожалуйста, присылайте решение в виде pull-request. [Инструкция](https://gitlab.se.ifmo.ru/cse/main/-/wikis/%D0%9A%D0%B0%D0%BA-%D0%BF%D0%BE%D1%81%D0%BB%D0%B0%D1%82%D1%8C-%D0%B7%D0%B0%D0%B4%D0%B0%D0%BD%D0%B8%D0%B5-%D0%BD%D0%B0-%D0%BF%D1%80%D0%BE%D0%B2%D0%B5%D1%80%D0%BA%D1%83). В крайнем случае допускается ссылка на репозиторий на https://gitlab.se.ifmo.ru или https://github.com .
- Пожалуйста, присылайте решение в виде pull-request. [Инструкция](https://gitlab.se.ifmo.ru/cse/main/-/wikis/%D0%9A%D0%B0%D0%BA-%D0%BF%D0%BE%D1%81%D0%BB%D0%B0%D1%82%D1%8C-%D0%B7%D0%B0%D0%B4%D0%B0%D0%BD%D0%B8%D0%B5-%D0%BD%D0%B0-%D0%BF%D1%80%D0%BE%D0%B2%D0%B5%D1%80%D0%BA%D1%83).
Здесь `fwrite` записывает в файл `padding * 1` байт подряд начиная с адреса `&value`.
- Такие маленькие функции, использующиеся только в одном файле, стоит помечать `static`. Тогда они не только могут быть встроены в местах вызова, но компилятор может удалить их определение из файла вообще.
- Не стоит смешивать в одном проекте `camelCase` и `snake_case`.