README.md 9.07 KB
Newer Older
Igor Zhirkov's avatar
Igor Zhirkov committed
1
# Assignment: Image rotation
Igor Zhirkov's avatar
Igor Zhirkov committed
2
---
Igor Zhirkov's avatar
Igor Zhirkov committed
3
Лабораторная работа: Поворот картинки
Igor Zhirkov's avatar
Igor Zhirkov committed
4

Igor Zhirkov's avatar
Igor Zhirkov committed
5 6
# Подготовка

Igor Zhirkov's avatar
Igor Zhirkov committed
7
- Прочитайте главу 12 (стр. 221, 231–239) и 13 (целиком) "Low-level programming: C, assembly and program execution". 
Igor Zhirkov's avatar
Igor Zhirkov committed
8 9 10 11 12 13 14 15 16

На защите мы можем обсуждать любые вопросы из учебника из глав 8–13 включительно.

# Структура BMP файла

BMP файл состоит из заголовка и растрового массива.
Заголовок задаётся следующей структурой (обратите внимание на атрибут `packed`):

```c
17
// Описание для gcc и clang
Igor Zhirkov's avatar
Igor Zhirkov committed
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
#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 байта:

```c
43
   struct pixel { uint8_t b, g, r; };
Igor Zhirkov's avatar
Igor Zhirkov committed
44 45
```

46 47
## Padding

Igor Zhirkov's avatar
Igor Zhirkov committed
48 49
Если ширина изображения в пикселах кратна четырём, то строчки идут одна за другой без пропусков.
Если ширина не кратна четырём, то она дополняется мусорными байтами до ближайшего числа байтов, кратного четырём.
50
Эти байты называются *padding*.
Igor Zhirkov's avatar
Igor Zhirkov committed
51 52 53 54 55 56

Пример:

1. Изображение имеет ширину 12 пикселей = 12 * 3 байт = 36 байт. Ширина кратна четырём, каждая следующая строчка начинается сразу после предыдущей.
2. Изображение имеет ширину 5 пикселей. 5 * 3 = 15 байт, ближайшее число кратное четырём (округление вверх) это 16. После каждой строчки будет отступ в один мусорный байт перед началом следующей.

57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
Обратите внимание: отступы в *байтах*, не в пикселях.



# Пользователям компилятора от 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 учебника. 

Igor Zhirkov's avatar
Igor Zhirkov committed
92 93 94

# Задание

Igor Zhirkov's avatar
Igor Zhirkov committed
95 96 97
**ВНИМАНИЕ** `view-header` это программа для просмотра заголовков BMP файлов. Это не заготовка для решения! Можете скомпилировать её с помощью `make` и проверять заголовки на битность; в решении вам нужно поддерживать только 24-битные BMP файлы.


Igor Zhirkov's avatar
Igor Zhirkov committed
98 99 100

- Необходимо реализовать поворот изображения в формате BMP на 90 градусов.
- Архитектура приложения должна содержать три чётко разделённых части:
101 102
   - Описание внутреннего представления картинки `struct image`, очищенное от деталей формата, и функции для работы с ним: создание, деинициализация и т.д.

Igor Zhirkov's avatar
Igor Zhirkov committed
103 104 105 106 107 108
   ```c
   struct image {
     uint64_t width, height;
     struct pixel* data;
   };
   ```
109
   
Igor Zhirkov's avatar
Igor Zhirkov committed
110 111 112
   - Функции для работы с BMP-файлами и сериализации/десериализации внутреннего представления.

    ```c
113
    /*  deserializer   */
Igor Zhirkov's avatar
Igor Zhirkov committed
114 115 116 117 118 119 120
    enum read_status  {
        READ_OK = 0,
        READ_INVALID_SIGNATURE,
        READ_INVALID_BITS,
        READ_INVALID_HEADER
        /* коды других ошибок  */
        };
121
        
Igor Zhirkov's avatar
Igor Zhirkov committed
122
    enum read_status from_bmp( FILE* in, struct image* img );
123
    
Igor Zhirkov's avatar
Igor Zhirkov committed
124 125 126 127 128 129
    /*  serializer   */
    enum  write_status  {
        WRITE_OK = 0,
        WRITE_ERROR
        /* коды других ошибок  */
    };
130
    
Igor Zhirkov's avatar
Igor Zhirkov committed
131 132 133
    enum write_status to_bmp( FILE* out, struct image const* img );
    
    ```
134 135
   
   Как только мы считали изображение во внутренний формат, мы должны забыть, из какого формата оно было считано! Иначе будет сложнее добавлять новые входные форматы, отличные от BMP (почему?).
Igor Zhirkov's avatar
Igor Zhirkov committed
136

137 138 139 140 141 142 143 144
    - Функции `from_bmp` и `to_bmp` принимают уже открытый файл, что позволяет
      им работать с заранее открытыми файлами `stdin`, `stdout`, `stderr`.
      Они не должны ни открывать, ни закрывать файлы.
    
    - Вам потребуются функции, аналогичные `from_bmp` и `to_bmp`, которые будут
      принимать имена файлов и заниматься корректным открытием (`fopen`) и
      закрытием (`fclose`) файлов; на открытых файлах они могут запускать `from_bmp`
      и `to_bmp`.
Igor Zhirkov's avatar
Igor Zhirkov committed
145

146 147 148 149
      Имеет смысл разделять открытие/закрытие файлов и работу с ними. Уже
      открытие и закрытие могут сопровождаться ошибками (см. `man fopen` и 
      `man fclose`) и хочется отделить обработку ошибок открытия/закрытия и
      обработку ошибок чтения/записи.
Igor Zhirkov's avatar
Igor Zhirkov committed
150

151
    - Для ошибок открытия/закрытия, возможно, вам захочется ввести отдельные типы перечислений.
Igor Zhirkov's avatar
Igor Zhirkov committed
152

153
    - Вам потребуется функция для поворота картинки в её внутреннем представлении:
Igor Zhirkov's avatar
Igor Zhirkov committed
154

155 156 157 158
      ```c
      /* создаёт копию изображения, которая повёрнута на 90 градусов */
      struct image rotate( struct image const source );
      ```
Igor Zhirkov's avatar
Igor Zhirkov committed
159

160
  Эти части имеет смысл держать **в разных модулях (файлах с расширением `.c`)**. Разумеется, для каждого нужен соответствующий заголовочный файл.
Igor Zhirkov's avatar
Igor Zhirkov committed
161

162 163 164
  - Кроме того, дополнительные функции, которые вы ввели для удобства, но
    которые не относятся по смыслу ни к одному из этих модулей, можно выделить
    в отдельный модуль. Часто его называют `util.c` или как-то похоже.
Igor Zhirkov's avatar
Igor Zhirkov committed
165 166


Igor Zhirkov's avatar
Igor Zhirkov committed
167
# Для самопроверки
168

Igor Zhirkov's avatar
Fixes  
Igor Zhirkov committed
169
- Прочитайте [правила хорошего стиля](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). Ваше решение должно им соответствовать.
Igor Zhirkov's avatar
Igor Zhirkov committed
170
- Архитектура: думайте о том, как бы вы хотели организовать код, чтобы легко добавлять входные форматы (не только BMP) и трансформации (не только поворот на 90 градусов).
Igor Zhirkov's avatar
Igor Zhirkov committed
171
- Пожалуйста, присылайте решение в виде 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 .
Igor Zhirkov's avatar
Igor Zhirkov committed
172