Root /ArchiveAbout
()

Точки в Паскале. SetPixel и PutPixel

Точки в Паскале. SetPixel и PutPixel

Давайте поговорим о процедурах SetPixel(x, y, c) и PutPixel(x, y, c), которые выполняют одну и ту ж работу – закрашивают пиксель с координатами (x, y) цветом c. Но зачем это надо – закрашивать точки в разные цвета? Дело в том, что любое изображение состоит из точек (пикселей), каждая из которых имеет определенный цвет и свои координаты графическом окне Pascal. Во второй части статьи (см. внизу) мы покажем, как с помощью закрашивания пикселей нарисовать прямоугольник в Паскале, отрезок линии, круг и даже эллипс. А пока немного поговорим о геометрии.

Точки в графическом окне Паскаля

Простейшим геометрическим объектом в математике является точка – нечто такое, не имеющее никакого размера, ни объема, ни площади. Правда, чтобы точку нарисовать, придется придать ей хоть какой-то размер (иначе её изобразить невозможно). Из точек построены все линии и фигуры, поверхности и тела – как на плоскости, так и в пространстве.

Чем отличается фигура от линии? Замкнутая линия на плоскости – это только граница, край, а фигура – часть плоскости, находящаяся внутри замкнутой линии. Примером линии является окружность, а соответствующая ей фигура – круг (часть плоскости).

Геометрическим телом называется множество точек в пространстве. Только не любое множество, а вся совокупность точек, отделенная от остального пространства какой-то границей, называемой поверхностью. Тело – это уже геометрическая фигура в пространстве. Примеры геометрического тела: куб, тетраэдр, шар, параллелепипед и др.

Создание изображения в Паскале реализуются с помощью растровой графики (точечной графики). Это значит, что наименьшим элементом рисунка является точка, называемая пикселем, которых представляют обычно в виде маленьких кружков или квадратиков. Если взять любое растровое изображение и сильно его увеличить, то можно увидеть отдельные области, из которых и состоит всё изображение – пиксели. Каждый пиксель имеет один цвет, и его уже нельзя разделить на меньшие части.

Другой важной характеристикой пикселя является его координаты в графическом окне, которые отсчитываются с левого верхнего угла вправо (ось OX) и вниз (ось OY). Раз так, то есть природная необходимость в подпрограммах, которые бы задавали цвет и координаты пикселя. Или, наоборот, при наличии рисунка в графическом окне было бы интересно узнать цвет пикселя с данными координатами.

Причем первые две процедуры – SetPixel и PutPixel – являются равнозначными, и вы можете использовать любую из них. Чтобы продемонстрировать действие данных процедур, давайте напишем несколько простых программ. А вот функцией GetPixel(x,y) мы займемся на следующей странице. Но сначала укажем некоторые цветовые константы – названия стандартных цветов в PascalABC.Net:

Есть многие другие цветовые константы, но нам пока этого хватит.

Точка

Итак, попробуем нарисовать точку в PascalABC.Net с координатами, например, (300, 200), окрашенную в красный цвет. Чтобы мы её увидели, напишем возле неё слово «точка». Для этого создадим простую программу, подключив к ней модуль GraphABC:

Program my_Point;
uses
  GraphABC; //подключенный модуль для работы с графикой

begin
  { Красная точка с координатой (300,200): }
  SetPixel(300, 200, clRed);
  { Надпись возле точки: }
  TextOut(301, 200, 'точка')
end.

**unit** GraphABC;: Модуль предоставляет константы, типы, процедуры, функции и классы для рисования в графическом окне **procedure** SetPixel(x,y: integer; c: Color);: Закрашивает пиксел с координатами (x,y) цветом c Цвет: clRed - красный **procedure** TextOut(x,y: integer; s: string);: Выводит строку s в прямоугольник к координатами левого верхнего угла (x,y) Запустите приложение и в открывшемся графическом окне попробуйте найти маленькую красную точку чуть выше слева слова «точка». Это и есть пиксель с координатами (300, 200). Но точки создавать не интересно. Если бы мы нарисовали совокупность точек, идущих друг за другом, например, в горизонтальном направлении, то получили бы уже линию. Давайте так и сделаем.

Строим линию и жирную линию

Как построить линию в PascalABC.Net с помощью точек? Строить линию точками, каждый раз записывая процедуру SetPixel (или PutPixel), это не правильно, поскольку для этого пришлось бы записывать SetPixel огромное количество раз. Вместо этого построение можно организовать в цикле, в котором, шаг за шагом, точки сами будут выстраиваться в прямую линию.

Нарисуем линию от точки с координатами (100, 200) до точки (400, 200). Как видим, эта прямая будет параллельна оси OX (горизонтальна в нашем понимании), поскольку начало и конец отрезка имеют одинаковую координату y = 200. Таким образом, изменять придется только координату x – от 100 до 400, а для этого мы используем цикл for (с параметром) и процедуру SetPixel. Вот какая программа у нас вышла:

Program my_Line;

uses
  GraphABC;

var
  x: integer; 

begin
  for x := 100 to 400 do
    SetPixel(x, 200, clRed)
end.

**unit** GraphABC;: Модуль предоставляет константы, типы, процедуры, функции и классы для рисования в графическом окне **type** integer;: Представляет 32-битовое целое число со знаком.Диапазон значений: -2 147 483 648 .. 2 147 483 647 **procedure** SetPixel(x,y: integer; c: Color);: Закрашивает пиксел с координатами (x,y) цветом c Цвет: clRed - красный Созданная нами линия имеет толщину 1 пиксель. А чтобы нарисовать жирную линию, нужно, естественно, построить несколько линий рядом, накладывая их как бы одну на другую столько раз, какова толщина линии. Поскольку мы будем менять не только x, но и y, то здесь не обойтись без вложенного двойного цикла. Во внешнем цикле будем изменять y, а во внутреннем – координату x. Результат наших размышлений:

Program my_Line2;

uses
  GraphABC;
 
var
  i, x, x1, x2, y, d: integer;
 
begin
  d := 3; //толщина отрезка
  x1 := 100; x2 := 400; //абсцисса начала и конца отрезка
  y := 200; //ордината отрезка 
  for i := 0 to d - 1 do //наращиваем толщину отрезка
    for x := x1 to x2 do
      PutPixel(x, y + i, clBlue)
end.

**unit** GraphABC;: Модуль предоставляет константы, типы, процедуры, функции и классы для рисования в графическом окне **type** integer;: Представляет 32-битовое целое число со знаком.Диапазон значений: -2 147 483 648 .. 2 147 483 647 **procedure** PutPixel(x,y: integer; c: Color);: Закрашивает пиксел с координатами (x,y) цветом c Цвет: clBlue - синий Линия и жирная линия в Pascal

Граница прямоугольника

Как создать прямоугольник в PascalABC.Net с помощью точек? Поскольку рисовать отрезки мы уже научились, то для создания прямоугольника придется начертить всего четыре отрезка. Для этой цели достаточно задать координаты двух противоположных вершин прямоугольника – (x1, y1) и (x2, y2), где x2 > x1, y2 > y1, – а потом нарисовать четыре стороны (линии). Вот сам код с комментариями:

Program my_Rectangle;

uses
  GraphABC;
 
var
  x, y, x1, y1, x2, y2: integer; //координаты вершин прямоугольника
 
begin
  x1 := 100; y1 := 150; //координаты левого верхнего угла
  x2 := 400; y2 := 300; //координаты правого нижнего угла
  { Нижняя и верхняя сторона: }
  for x := x1 to x2 do begin //здесь изменяется x
    PutPixel(x, y1, clRed);
    PutPixel(x, y2, clRed)
  end;
  { Левая и правая сторона: }
  for y := y1 to y2 do begin //здесь изменяется y
    PutPixel(x1, y, clRed);
    PutPixel(x2, y, clRed)
  end
end.

**unit** GraphABC;: Модуль предоставляет константы, типы, процедуры, функции и классы для рисования в графическом окне **type** integer;: Представляет 32-битовое целое число со знаком.Диапазон значений: -2 147 483 648 .. 2 147 483 647 **procedure** PutPixel(x,y: integer; c: Color);: Закрашивает пиксел с координатами (x,y) цветом c Цвет: clRed - красный **procedure** PutPixel(x,y: integer; c: Color);: Закрашивает пиксел с координатами (x,y) цветом c Цвет: clRed - красный **procedure** PutPixel(x,y: integer; c: Color);: Закрашивает пиксел с координатами (x,y) цветом c Цвет: clRed - красный **procedure** PutPixel(x,y: integer; c: Color);: Закрашивает пиксел с координатами (x,y) цветом c Цвет: clRed - красный

Закрашенный прямоугольник

А как закрасить прямоугольник в PascalABC.Net с помощью процедуры SetPixel или PutPixel? Для заливки прямоугольника каким-либо цветом используется тот же способ, что и при создании жирной линии: рисуются отрезки толщиной в 1 пиксель один за другим, пока их общая толщина не составит длину какой-то из сторон прямоугольника. Немного переформатировав код программы жирная линия, получим:

Program my_FillRectangle;

uses
  GraphABC;

var
  x, y, x1, y1, x2, y2: integer; //координаты вершин прямоугольника

begin
  x1 := 100; y1 := 150; //координаты левого верхнего угла
  x2 := 400; y2 := 300; //координаты правого нижнего угла
  for y := y1 to y2 do
    for x := x1 to x2 do 
      PutPixel(x, y, clBrown) //точки коричневого цвета
end.

**unit** GraphABC;: Модуль предоставляет константы, типы, процедуры, функции и классы для рисования в графическом окне **type** integer;: Представляет 32-битовое целое число со знаком.Диапазон значений: -2 147 483 648 .. 2 147 483 647 **procedure** PutPixel(x,y: integer; c: Color);: Закрашивает пиксел с координатами (x,y) цветом c Цвет: clBrown - коричневый Прямоугольник и закрашенный прямоугольник в Pascal

Рисуем круг

Как нарисовать круг в PascalABC.Net с помощью точек? Можно закрасить не весь прямоугольник, а какую-то его часть, например, круг, находящийся в середине квадрата с координатами противоположных вершин (x0 - r, y0 - r) и (x0 + r, y0 + r). Мы знаем, что уравнение окружности с центром в точке (x0, y0) и радиусом r выглядит так:

(x – x<sub>0</sub>)<sup>2</sup> + (y – y<sub>0</sub>)<sup>2</sup> = r<sup>2</sup>.

Но нам нужна не окружность, а круг, то есть «внутренность» окружности. Это вся совокупность точек (x, y), для которых расстояние до центра (x0, y0) не больше r:

(x – x<sub>0</sub>)<sup>2</sup> + (y – y<sub>0</sub>)<sup>2</sup> ≤ r<sup>2</sup>.

Таким образом, чтобы закрасить круг в квадрате, необходимо его точки проверять на выполнение вышеуказанного неравенства: если оно истинно, то точки (x, y) закрашиваются. Вот соответствующая программа:

program my_circle;

uses
  GraphABC;

var
  x, y, x0, y0, r: integer;
  bln: boolean; { bln = true, если точка (x,y) находится внутри
                 круга, bln = false - в противном случае }

begin
  x0 := 250; y0 := 200; //координаты центра круга
  r := 110; //радиус круга
  { Проверяем все точки прямоугольника с координатами
  противоположных вершин (x0 - r, y0 - r) и (x0 + r, y0 + r): }
  for x := x0 - r to x0 + r do
    for y := y0 - r to y0 + r do begin
      { Выражение, означающее, что точка с координатами (x, y)
      находится внутри круга радиуса r и центром (x0, y0): }
      bln := sqr(x - x0) + sqr(y - y0) <= sqr(r);
      { Если точка (x, y) попадает внутрь данного круга,
      то закрашиваем её цветом clGreen: }
      if bln then SetPixel(x, y, clGreen)
    end
end.

**unit** GraphABC;: Модуль предоставляет константы, типы, процедуры, функции и классы для рисования в графическом окне **type** integer;: Представляет 32-битовое целое число со знаком.Диапазон значений: -2 147 483 648 .. 2 147 483 647 **type** boolean;: Представляет логическое значение. **function** Sqr(x: integer): integer;: Возвращает квадрат числа x. **function** Sqr(x: integer): integer;: Возвращает квадрат числа x. **function** Sqr(x: integer): integer;: Возвращает квадрат числа x. **procedure** SetPixel(x,y: integer; c: Color);: Закрашивает пиксел с координатами (x,y) цветом c Цвет: clGreen - зеленый

Рисуем закрашенный эллипс

А как нарисовать закрашенный эллипс в PascalABC.Net с помощью точек? Для этого используем эллипс, вписанный в прямоугольник с координатами противоположных вершин (x1, y1) и (x2, y2), для которых x2 > x1, y2 > y1. Сначала укажем, что уравнение эллипса с центром в начале координат и полуосями a и b выглядит так:

(x/a)<sup>2</sup> + (y/b)<sup>2</sup> = 1.

Но поскольку нам необходимо закрасить внутреннюю часть эллипса, то уравнение превратится в неравенство заполненного эллипса:

(x/a)<sup>2</sup> + (y/b)<sup>2</sup> ≤ 1.

Стороны прямоугольника параллельны осям координат. Это означает, что координаты его центра равны полусумме координат противоположных вершин: x0 = (x1 + x2)/2, y0 = (y1 + y2)/2. А как найти a и b? Это стороны прямоугольника, разделенные на 2 (поэтому они называются полуосями): a = (x2 – x1)/2, b = (y2 – y1)/2. С учетом этого, неравенство заполненного эллипса приобретает вид:

(x – x<sub>0</sub>)<sup>2</sup>/a<sup>2</sup> + (y – y<sub>0</sub>)<sup>2</sup>/b<sup>2</sup> ≤ 1.

Program my_FillEllipse;

uses
  GraphABC;

var
  x, y, x1, y1, x2, y2, x0, y0, a, b: integer;
  bln: boolean; { bln = true, если точка (x,y) находится внутри
                 эллипса, bln = false - в противном случае }

begin
  x1 := 100; y1 := 150; { <== Координаты левого верхнего угла }
  x2 := 400; y2 := 300; { <== Координаты правого нижнего угла }
  { Координаты центра эллипса: }
  x0 := (x1 + x2) div 2;
  y0 := (y1 + y2) div 2;
  { Полуоси эллипса: }
  a := (x2 - x1) div 2;
  b := (y2 - y1) div 2;
  { Проверяем все точки прямоугольника с координатами
  противоположных вершин (x1, y1) и (x2, y2): }
  for x := x1 to x2 do
    for y := y1 to y2 do begin
      { Выражение, означающее, что точка (x, y) находится внутри
      эллипса с полуосями a и b и центром в точке (x0, y0): }
      bln := sqr((x - x0) / a) + sqr((y - y0) / b) <= 1;
      { Если точка (x, y) попадает внутрь данного эллипса,
      то закрашиваем её цветом RGB(250, 100, 200): }
      if bln then SetPixel(x, y, RGB(250, 150, 250))
    end
end.

**unit** GraphABC;: Модуль предоставляет константы, типы, процедуры, функции и классы для рисования в графическом окне **type** integer;: Представляет 32-битовое целое число со знаком.Диапазон значений: -2 147 483 648 .. 2 147 483 647 **type** boolean;: Представляет логическое значение. A **div** B - целочисленное деление А на В A **div** B - целочисленное деление А на В A **div** B - целочисленное деление А на В A **div** B - целочисленное деление А на В **function** Sqr(x: integer): integer;: Возвращает квадрат числа x. **function** Sqr(x: integer): integer;: Возвращает квадрат числа x. **procedure** SetPixel(x,y: integer; c: Color);: Закрашивает пиксел с координатами (x,y) цветом c **function** RGB(r,g,b: byte): Color;: Возвращает цвет, который содержит красную (r), зеленую (g) и синюю (b) составляющие (r,g и b - в диапазоне от 0 до 255) Круг и заполненный эллипс в Pascal

Как видно на рисунках эллипса и круга, создание изображений с помощью закрашивания пикселей имеет существенный недостаток: границы рисунков выглядят не совсем плавными, как бы ступенчатыми. Оно и понятно: ведь пиксели – не точки в геометрическом понимании, которые не имеют размера, а все-таки небольшие квадратики или кружки. Тогда почему на всех фотографиях и рисунках нет ступенек? – спросите вы. Да потому, что там используется так называемое сглаживание. Суть этого метода в основном состоит в том, чтобы ближайшие к границе точки заменять более светлыми, или точнее, наиболее близкими по цвету с фоном, из-за чего создается эффект плавного перехода.

Бывает и обратная ситуация, когда нужно не сгладить изображение, сделав границы плавными (особенно это касается геометрических фигур), а как бы размыть. Делается это так: берем несколько соседних пикселей изображения, имеющих обычно разный цвет, и заменяем на пиксели одинакового цвета, совпадающем с цветом одного из пикселей. Получается картинка с очень увеличенными пикселями.

То же касается и видео: бывает необходимость закрыть лицо персонажа такими же увеличенными пикселями, или часть области заменить одним цветом. В специализированных программах для работы с графикой типа Gimp, Photoshop или Movavi показывается замена пикселей одного цвета на пиксели другого цвета.