Введение
Небольшой печатной мастерской нужна открытка из цветной сетки. Сначала вы запустите готовый образец размером четыре на четыре, сделаете его краску теплее, а затем завершите программу C, превращающую прямоугольный символьный рисунок в настоящий файл изображения.
Нужно знать переменные, условия, циклы, массивы и функции C, а также основы навигации в терминале. Двумерные индексы и вывод изображения объясняются здесь. Подготовленная среда в браузере содержит терминал Workspace и Postcard Preview. Картинка — файл P3 PPM: читаемые числа, а не PNG. Время чтения и практики оценено автором, а не измерено при работе начинающих.
Выведите небольшой образец и измените его цвет
На этом шаге вы увидите, как готовый пример C превращается в изображение, а затем измените одну краску.
Откройте вкладку Workspace. Терминал находится в /home/labex/project/postcards; явно указанный cd также поможет вернуться после смены каталога. pwd показывает текущий каталог, а ls перечисляет его файлы.
cd /home/labex/project/postcards
pwd
ls
Подготовлены sample.c, незавершённый card.c и предоставленный art.h. Меняйте только sample.c и card.c, оставляя art.h без изменений. cat показывает файл, не редактируя его:
cat sample.c
Пример использует сетку из четырёх строк и четырёх столбцов. В grid[row][col] первый индекс выбирает строку сверху вниз, второй — столбец слева направо. Оба начинаются с нуля. Каждый элемент равен 0 или 1 и выбирает тройку RGB из color. RGB обозначает красный, зелёный и синий; каждая компонента — целое число от 0 до 255. Второй индекс в color[c][0] выбирает красный, [1] — зелёный, [2] — синий.
printf записывает текст в стандартный вывод, обычно в этот терминал. \n начинает новую строку. Файл P3 начинается с P3, ширины и высоты, а затем максимального значения компоненты 255. После этого идут тройки RGB, читаемые слева направо в каждой строке и от верхней строки к нижней. Числа разделяет пробельное пространство, поэтому одна тройка на строку допустима. P3 также поддерживает комментарии #.
Скомпилируйте пример. gcc — компилятор C; -std=c11 выбирает C11, -Wall -Wextra включает полезные предупреждения, а -o sample задаёт исполняемому файлу имя sample.
gcc -std=c11 -Wall -Wextra sample.c -o sample
./sample запускает исполняемый файл в текущем каталоге. > перенаправляет стандартный вывод в файл вместо терминала. Оболочка открывает или заменяет этот файл до запуска программы. Используйте новое имя, указанное ниже:
./sample > sample.ppm
Переключитесь на вкладку Postcard Preview. Нажмите Refresh files, выберите sample.ppm в Postcard file, затем нажмите Open postcard. Состояние показывает 4 × 4 pixels · sample.ppm. Вы увидите тёмную несимметричную фигуру на кремовом фоне. Просмотрщик отображает только что созданный файл и не дорисовывает отсутствующие пиксели.
Вернитесь в Workspace. Измените тёмную краску {30, 76, 64} на тёплый цвет {170, 70, 45}. Команда редактирования sed использует s/old/new/ для замены именно этого текста, а -i сохраняет изменение в sample.c. Одинарные кавычки передают выражение замены в sed одним неизменённым аргументом.
sed -i 's/{30, 76, 64}/{170, 70, 45}/' sample.c
После изменения исходника скомпилируйте его заново: старый исполняемый файл сам не обновится.
gcc -std=c11 -Wall -Wextra sample.c -o sample
./sample > sample.ppm
Перейдите в Postcard Preview, оставьте выбранным sample.ppm и снова нажмите Open postcard. Измениться должен только цвет переднего плана; размеры и кремовые пиксели остаются прежними.
Если терминал сообщает, что файл не найден, вернитесь в рабочий каталог уже изученными cd и ls. Если просмотрщик сообщает об отсутствии файла, вернитесь в Workspace и убедитесь, что компиляция прошла успешно, прежде чем выполнять ./sample > sample.ppm. Ошибка компилятора означает, что новый исполняемый файл не создан: исправьте указанную строку исходника и повторите компиляцию.
Сопоставьте прямоугольный рисунок с пикселями RGB
На этом шаге вы завершите генератор открытки и откроете его реальный результат.
Начните в Workspace, в /home/labex/project/postcards. Прочитайте предоставленный рисунок и незавершённый генератор:
cd /home/labex/project/postcards
cat art.h
cat card.c
#include "art.h" делает подготовленные определения доступными при компиляции card.c. #define WIDTH 5 и #define HEIGHT 3 дают имена размерам. pattern содержит три строки по пять цифровых символов. Каждая строка символов резервирует WIDTH + 1 позиций, поскольку C хранит после видимых символов завершающий символ со значением ноль; циклы используют только пять видимых позиций.
Первая строка, "10000", начинается с цвета палитры 1 и продолжается четырьмя пикселями цвета 0. Символ '2' — не целое число 2. Вычитание символа '0' преобразует один из предоставленных цифровых символов в индекс палитры: '2' - '0' равно 2. Рисунок содержит только цифры от 0 до 3, соответствующие четырём строкам палитры. Не меняйте рисунок, размеры и цвета. Используйте в циклах WIDTH и HEIGHT, чтобы после перекомпиляции программа работала и с предоставленными прямоугольными рисунками от 1 до 16 столбцов и строк с теми же индексами палитры 0–3.
Незавершённый генератор записывает заголовок, но не пиксели. Один заголовок ещё не изображение. Дополните его внешним циклом по y (строкам) и внутренним по x (столбцам). pattern[y][x] выбирает символ, а palette[c][0..2] — его значения RGB. Маркеры %d в printf выводят целочисленные аргументы в указанном порядке.
Используйте следующий полный исходник. cat > card.c заменяет этот файл. <<'EOF' начинает here-document: оболочка буквально копирует следующие строки до строки, содержащей только EOF. Кавычки у разделителя не дают оболочке выполнять подстановки в исходнике C. Скопируйте весь блок, включая последний EOF.
cat > card.c <<'EOF'
#include <stdio.h>
#include "art.h"
int main(void) {
printf("P3\n%d %d\n255\n", WIDTH, HEIGHT);
for (int y = 0; y < HEIGHT; y++) {
for (int x = 0; x < WIDTH; x++) {
int c = pattern[y][x] - '0';
printf("%d %d %d\n", palette[c][0], palette[c][1], palette[c][2]);
}
}
return 0;
}
EOF
Скомпилируйте программу и создайте новый выходной файл:
gcc -std=c11 -Wall -Wextra card.c -o card
./card > original.ppm
Предоставленный инструмент проверки только декодирует файл; он не создаёт и не исправляет открытку. Запустите его, передав имя файла аргументом:
python3 /home/labex/.local/share/pixel-postcards/inspect.py original.ppm
Ожидаемый вывод:
5 x 3 pixels; 15 RGB triples; max value 255
Чем полезны эти числа? Квадрат мог бы скрыть перестановку размеров. Этот рисунок из пяти столбцов и трёх строк должен быть шире своей высоты, с тёмной полосой слева. WIDTH управляет внутренним циклом, HEIGHT — внешним; их перестановка может вызвать выход за границы строки или пропуск пикселей.
Переключитесь в Postcard Preview. Нажмите Refresh files, выберите original.ppm, затем Open postcard. Проверьте состояние 5 × 3 и сравните строки с art.h. Нажмите Download PPM, чтобы сохранить настоящий файл изображения. Браузер может скачать PPM вместо прямого отображения; смотрите изображение в этом просмотрщике. Вернитесь в Workspace для проверки лабораторной.
На снимке выбран original.ppm, показаны его сохранённые размеры 5 × 3 и ссылка Download PPM под изображением. Сравните тёмную полосу слева и все три строки.
![]()
Сохраните в рабочем каталоге card.c, исполняемый файл card, art.h и original.ppm.
Если просмотрщик сообщает о неправильном числе пикселей, файл существует, но неполон: проверьте границы обоих циклов, сохраните card.c, перекомпилируйте и заново создайте original.ppm. Экранное увеличение не меняет сохранённые размеры. В следующей лабораторной вы создадите действительно увеличенные файлы изображений.
Резюме
Вы скомпилировали и перекрасили небольшой пример, а затем сопоставили прямоугольный массив символов с тройками RGB. Программа C создала настоящий файл P3, который вы декодировали, просмотрели и скачали. Вы потренировались указывать сначала строку в индексах и перенаправлять стандартный вывод.


