Множество притяжений корней метода Ньютона

Существующие файлы:

Какого файла не хватает — догадаетесь сами: это несложно, ежели «pozor» достаточно хорошо впитан.

Краткое содержание части лекции про запись PNG-файла

Оглавленьице:

Вместо введения

Давайте смотреть на main.c. Идею того, что картинка — это прямоугольник с целыми координатами точек (пикселов; pixel — picture element) и к каждой точке приписано дополнительное свойство — цвет, вам нужно как-то дополнительно объяснить или это понятно? Если нужно — пишите письма: автор будет жечь напалмом (не так, конечно: албанско-бобруйские коннотации Б-го противны?).

Цвет кодируется тройкой интенсивностей базовых (в модели RGB: red, green, blue) цветов; амплитуда каждой компоненты преставляет из себя целое число от нуля до 255, умещаясь, таким образом, в один байт. А цвет точки, тогда, умещается в 3 байта, которые состоят из 24 битов; такой цвет, поэтому называется 3x8=24-битным (иногда).

Герменевтика горизонтального

Поскольку картинка — это прямоугольник с цветными точками, то его можно представлять ещё и как совокупность строчек (rows); их количество равно высоте картинки, а каждая строчка уже состоит из горизонтально расположенных пикселов. Их в каждой строке столько, какова ширина картинки. Поэтому строчка является массивом пикселов, каждый пиксел — тройка байтов (red, green, blue), следовательно, графически оно (массив этот) выглядит так:

| R1 | G1 | B1 | R2 | G2 | B2 | ... | Rn | Gn | Bn |
каждая ячейка — байт. Индексы — номер байта. Что такое «R», «G» и «B? Это, наверное, что-то с космосом связано.

И вот, в main(), мы как раз сначала распределяем память под массив указателей на строки, а дальше — под каждую из строк. До этого, конечно, инициализируя ширину и высоту. Для компактного хранения всех данных, относящихся к картинке, мы используем структуру pngdata, которую вводим сами же, в newton.h,

struct pngdata {
    int width, height;
    png_bytep *rows;
};
png_bytep — это тип данных, который нам предоставляет libpng, сами мы его, поэтому, не определяем: он приходит из png.h.

Землемерное

Чтобы в такой «геометрической» конструкции дойти до отдельного пиксела с координатами (x, y), надо сделать так:
png_byte *bp = pp->rows[x] + 3 * y;
и bp будет указывать на байт Ry. Поэтому bp[0] — это Ry, bp[1] — Gy, bp[2] — By и, скажем, simple_image() устроено так, как оно и устроено («Ото /не путать с ОТО/ ты объяснил, так объяснил, графоманец; тушите свет!»):
void
simple_image(struct pngdata *pp) {
    unsigned int x, y;

    for (x = 0; x < pp->height; x++)
        for (y = 0; y < pp->width; y++) {
            png_byte *bp = pp->rows[x] + 3 * y;
            bp[0] = (x * y) % 256;
            bp[1] = y % 256;
            bp[2] = sin(x * x + y * y) * 256;
        }
}
На этом с заполнением данных картинки — всё, объяснение закончено.

Das ist fantastisch! А теперь — десерт.

Переходим к записи нарисованного в файл. За это отвечает отдельная функция — png_write(), в которую я (Он?) выделил всё, что необходимо для записи:

  1. открытие выходного файла (с помощью fopen());
  2. создание базовой структуры png_struct с помощью png_create_write_struct(): она содержит совершенно общие настройки, касающиеся конфигурации алгоритмов записи PNG-файла;
  3. создание структуры png_info, несущей информацию именно о нашем файле и его обработке: функциям его записи/чтения, обработки ошибок и т. п.;
  4. разделение на две структуры делается потому, что их (структур) задачи почти ортогональны: мы можем использовать одну и ту же png_struct для разных png_info, поэтому тратить память на, скажем, содержание данных png_struct внутри (разных) png_info — не всегда разумно;
  5. потом, с помощью png_init_io(), мы связываем распределённый png_info с полученным нами (с помощью fopen()) 'FILE *': функция записи по-умолчанию как раз работает с потоками из stdio.h, которые и описываются 'FILE *'; (Керниган и Ритчи из меня, конечно, такой — тесносплетённые в единого; интересно — целого?)
  6. у многих файлов (не только формата PNG, но и других) есть заголовок, описывающий метаданные (данные о данных ;?) и сами данные; так вот, png_set_IHDR() прямо и заполняет эти самые метаданные; ей как раз мы и передаём размеры картинки, характеристики цветности (PNG_COLOR_TYPE_RGB), чередования элементов картинки (PNG_INTERLACE_NONE, см. прогрессивное) и кое-чего остального (поищите «png_set_IHDR» в TFM /локальная копия/ и непременно обрящите оное; вы считаете, что верно — «об-ре-тё-те»? Так точно! Однако, насяльника, whatever);
  7. дальше мы записываем заголовок — png_write_info() и данные — png_write_image(); далее — завершаем процесс записи — png_write_end().
Обратите внимание: семь (прописью: Se7en) пунктов. К чему бы Это?

Соответственно, после каждого движения в png_write() мы проверям, получилось ли оно, и используем goto (к _bailout) для обработки ошибок, которая совершенно стандартна (если мы правильно инициализируем сначала переменные, конечно). Это — один из случаев, когда goto не против структурности (локальная копия), а за неё. Как мне кажется, конечно.

That's all, folks!