Слои и изображения в Визуал Бейсик 6

         Программа для рисования, в которой есть не только рисование, но и стереометрия, векторная графика и анимация сделана в среде Визуал Бейсик 6. Люди, незнакомые с программированием, но знакомые с Фотошопом, ожидают встретить в графическом редакторе привычные им по Фотошопу слои, такие же удобные и эффективные.
  И хотя Визуал Бейсик в полной мере работать со слоями неспособен – например, он не может учитывать их прозрачность, которую при необходимости приходится эмулировать, но кое-какие в этом плане возможности у него есть.

     КАК ФОРМИРУЕТСЯ ИЗОБРАЖЕНИЕ

  Изображение, на котором можно рисовать, является одним из элементов с которыми может работать Бейсик. Этот элемент называется PictureBox.

  PictureBox состоит из двух слоёв – слой Picture и слой Image, этот слой мы и видим на экране монитора, он лежит поверх слоя Picture и совершенно заслоняет его, то есть, является непрозрачным.

  Что касается размера слоёв, то слой Image имеет размер, определяемый свойствами Width и Height (ширина и высота), причём в этот размер входит ещё и толщина бордюра – по два пикселя на каждую сторону.
  Слой Picture имеет тот же размер, если свойство AutoSize=True, а если это свойство равно False, то тогда слой Picture может отличаться по размеру от слоя Image - он может быть больше Image или может быть равен ему. А вот быть меньше он, по видимому, не может – как только мы увеличим размер Image, так сразу же и слой Picture увеличит свой размер, а пустые незаполненные места будут заполнены цветом фона – тем цветом, который установлен как свойство Picture.BackColor для этого элемента. Такой же цвет приобретут и незаполненные области слоя Image.

  На иллюстрации показаны два элемента PictureBox и их слоями. Для обоих элементов свойство AutoSize установлено в положение False, Width и Height для элемента 2 выставлены маленькими, поэтому поле Image2 такое маленькое.
  Вы видите на этом поле большую красную точку. Она пропадёт, если выполнить действие Picture2.Cls (очистка слоя), а если выполнить перенос изображения Picture2.Picture = Picture2.Image, то эта точка появится на   поле Picture2 в том зелёном уголке, который на нём очерчен. О переносах мы поговорим ниже.   

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

  Обычно, видимым и больших размеров делается только один PictureBox, а другие или невидимы, или выглядывают на панели инструментов, показывая маленький прямоугольник верхнего левого угла, так, как это показано на иллюстрации. В этом маленьком прямоугольничке можно нарисовать красный кружок – метку, знак того, что на поле что-то записано, или что это поле используется как-то особо. Можно этот уголочек использовать и в качестве кнопки – кликнешь по нему, и с поля_2 что-нибудь считается особым образом.

     ИЗОБРАЖЕНИЯ НА СЛОЯХ И ИХ ПЕРЕНОС

  Изображение на слое Picture может быть совсем не тем, что на слое Image. Слой Image это слой незакреплённой графики – то, что мы на нём нарисуем, мы можем закрепить, используя оператор Picture1.Picture = Picture1.Image, или стереть, воспользовавшись действием Picture1.Cls – хотя это действие никакое не стирание, оно попросту переносит изображение со слоя Picture на слой Image, делая эти изображения одинаковыми.

  Изображение можно перенести с одного элемента PictureBox на другой. Для этого существуют два метода - Picture1.Picture = Picture2.Picture (обозначим его кратко P=>PI) и Picture1.Picture = Picture2.Image (I=>PI).
  Оба метода меняют и Picture и Image того PictureBox на который изображение переносится, одновременно меняются и размеры PictureBox, подстраиваясь под вновь полученное изображение.

  На внешнем виде картинки, то есть, на её границах, это изменение размера никак не скажется – дело в том, что я установил в положение False свойство AutoSize всех элементов PictureBox, а границы рисунка перемещаю особыми кнопками с нарисованными на них стрелками, вы можете видеть эти кнопки на иллюстрации. Поэтому, если мне надо будет посмотреть на то большое, что я загрузил извне, или перенёс с другого рисунка, то я всегда могу воспользоваться этими кнопочками, расширить поле Image, и провести загрузку или перенос картинки ещё раз.

  В моей программе перенос, показанный на иллюстрации синим, никогда не делается, зато используется перенос Image в обратном направлении - Picture2.Picture = Picture1.Image, для него есть специальная кнопочка с надписью 1=>2 на ней. И это удобно – нарисовал что-нибудь новое и тут же перенёс нарисованное на поле_2, минуя операцию закрепления.
  В программе есть ещё и поле_6, аналогичное полю_2, его слой Picture тоже используется для оперативного хранения изображений. Есть и невидимые поля, уже не помню, сколько их, кажется три, и их слои также используются при работе.

      ПЕРЕНОС МЕТОДОМ PaintPicture

  Действие Picture1.PaintPicture Picture2, X1,Y1,W1,H1,X2,Y2,W1,H1 перенесёт фрагмент изображения с поля Picture2 на поле Image1. Координаты X1,Y1 и размеры на поле Image1 могут быть любыми, а координаты переносимых точек на поле Picture2 не должны выходить за рамки этого поля. Поэтому, во избежание ошибки, при переносе методом PaintPicture это условие проверяется.
  А как его проверить? Ведь размеры Width и Height это размеры поля Image, а не поля Picture. Приходится запоминать размеры поля Picture2 в момент его заполнения. Если оно заполняется методом Picture2.Picture = Picture1.Image, то я запоминаю значения Width и Height поля Image1 так –

    K2w = Picture1.Width: K2h = Picture1.Height 

а после Picture2.Picture = Picture1. Picture запоминаю это –

    K2w = K1w: K2h = K1h   

как вы понимаете, значения K1w и K1h я определял заранее, и точно таким же способом.

     ВОЗМОЖНОСТИ РИСОВАНИЯ

  При рисовании на поле Image никаких ограничений на координаты нет. Если нарисованное попадёт за границы поля, то его мы попросту не увидим, и перенести куда-либо не сможем.
  Чтение цвета пикселя методом C = Picture1.Point(X, Y) за границами поля даст цвет равный -1, и это будет признаком того, что мы пытаемся читать цвет вне поля, и, следовательно, полученное значение С использовать нельзя. Чаще всего такое чтение попросту пропускается.

      НЕВИДИМЫЕ СЛОИ

  Элементы PictureBox в зависимости от свойства Visible могут быть как видимыми, так и невидимыми. На невидимых полях можно рисовать точно так же, как и на видимых, с них можно считывать цвет пикселя, и с них можно переносить изображение методом PaintPicture.
  Таким образом, связь между слоями можно осуществлять или по-пиксельно, или переносом прямоугольного массива точек. Интересно сопоставить скорости того и другого процесса между собой – скорость чтения цвета пикселя на моём ноутбуке составляет 127 тысяч пикселей в секунду, скорость записи пикселя заданного цвета равна 169 тысяч пикселей в секунду, отсюда получим, что скорость переноса одного пикселя равна 1/(1/127+1/169)=72.5 тысяч пикселей в секунду.
  Скорость переноса методом PaintPicture составляет 286 переноса в секунду. Деля одно на другое и извлекая квадратный корень, получим 16, а это значит, что квадрат размером 16х16 пикселей будет перенесён одним и другим способом за одно и то же время – 1/286=3.5 мсек.
  Это не значит, что по-пиксельный перенос неэффективен для большего количества пикселей. При скорости движения стилуса 20 пикселей в секунду (это небольшая скорость, характерная для вырисовывания деталей) и при возникновении цикла переноса через каждые два пикселя (именно такая ситуация характерна для работы с планшетом) время, отведённое на цикл, составит 0.1 секунду.
  За это время можно обслужить перенос 7250 пикселей. Это квадрат со сторонами 85х85 пикселей или круг диаметра 108 пикселей – то есть, не очень большой, но заметный на рисунке фрагмент. Именно с такими фрагментами и можно работать, используя метод по-пиксельного переноса. И именно с такими фрагментами удобно работать в плане полупрозрачности, поворота изображения на произвольный угол, или использования динамических опций рисования.
  Что касается переноса пикселей массивом, то этот метод не позволяет делать таких вещей но он может использоваться как подспорье, как дополнительное средство для быстрого копирования. В частности такого, как копирование кругами - http://proza.ru/2019/10/20/1299

  Итак, я рассказал вам (а заодно и лучше разобрался сам) об устройстве полей, предназначенных для рисования, они похожи на подобные слои в Фотошопе, но имеют свою специфику.  Опыт показывает, что при должной организации, возможности для рисования в программе, созданной в среде Визуал Бейсик, оказываются ничуть не хуже.

_________
1.08.2023


Рецензии