Как сделать рендеринг java

Добавил пользователь Алексей Ф.
Обновлено: 10.09.2024

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

Немного комментариев по листингу. В программе два класса - сама отрисовка происходит в DrawingComponent - он наследуется от JPanel, а вот значения для отрисовки задаются в классе Up7 - он наследуется от JFrame. Задаем мы три параметра - два массива со значениями по осям x, y и число точек. Точки соединяются прямыми - в этом помогает метод drawPolyline.

В этом уроке мы рассмотрим несколько доступных библиотек обработки изображений и выполним простую операцию обработки изображений – загрузим изображение и нарисуем на нем фигуру.

Мы попробуем МОКРУЮ (и немного качающуюся) библиотеку, ImageJ, OpenIMAJ и двенадцать обезьян.

2. AWT

AWT-это встроенная библиотека Java, которая позволяет пользователю выполнять простые операции, связанные с отображением, такие как создание окна, определение кнопок и прослушивателей и так далее. Он также включает в себя методы, позволяющие пользователю редактировать изображения. Он не требует установки, так как поставляется с Java.

2.1. Загрузка изображения

Первое, что нужно сделать, это создать объект BufferedImage из изображения, сохраненного на нашем диске:

2.2. Редактирование изображения

Чтобы нарисовать фигуру на изображении, нам придется использовать Graphics объект, связанный с загруженным изображением. Графика объект инкапсулирует свойства, необходимые для выполнения основных операций рендеринга. Graphics2D – это класс, расширяющий Graphics . Он обеспечивает больший контроль над двумерными фигурами.

В данном конкретном случае нам нужно Graphic 2D расширить ширину фигуры, чтобы сделать ее четко видимой. Мы достигаем этого, увеличивая его свойство s troke . Затем мы задаем цвет и рисуем прямоугольник таким образом, чтобы форма была в десяти пикселях от границ изображения:

2.3. Отображение изображения

Теперь, когда мы нарисовали что-то на нашем изображении, мы хотели бы показать это. Мы можем сделать это с помощью объектов библиотеки Swing. Сначала мы создаем JLabel объект, представляющий область отображения текста или/и изображения:

Затем добавьте наш JLabel в JPanel , который мы можем рассматривать как графического интерфейса на основе Java:

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

3. ImageJ

ImageJ-это программное обеспечение на базе Java, созданное для работы с изображениями. В нем довольно много плагинов, доступных здесь . Мы будем использовать только API, так как хотим выполнять обработку самостоятельно.

Это довольно мощная библиотека, лучше, чем Swing и AWT, так как целью ее создания была обработка изображений, а не операции с графическим интерфейсом. Плагины содержат много бесплатных алгоритмов, что хорошо, когда мы хотим научиться обработке изображений и быстро увидеть результаты, а не решать математические и оптимизационные задачи, лежащие в основе алгоритмов IP.

3.1. Зависимость Maven

Чтобы начать работу с ImageJ, просто добавьте зависимость в вашего проекта pom.xml файл:

Вы найдете самую новую версию в репозитории Maven .

3.2. Загрузка изображения

Чтобы загрузить изображение, вам нужно использовать метод open Image() static, из I J класс:

3.3. Редактирование изображения

Для редактирования изображения нам придется использовать методы из Image Processor object, прикрепленные к нашему ImagePlus объекту. Думайте об этом как о Графике объекте в AWT:

3.4. Отображение изображения

Вам нужно только вызвать show() метод Image Plus object:

4. OpenIMAJ

OpenIMAJ – это набор библиотек Java, ориентированных не только на компьютерное зрение и обработку видео, но и на машинное обучение, обработку аудио, работу с Hadoop и многое другое. Все части проекта OpenIMAJ можно найти здесь в разделе “Модули.” Нам нужна только часть обработки изображений.

4.1. Зависимость Maven

Чтобы начать работу с OpenIMAJ, просто добавьте зависимость в вашего проекта pom.xml файл:

Вы найдете последнюю версию здесь .

4.1. Загрузка изображения

Чтобы загрузить изображение, используйте метод ImageUtilities.readMBF() :

MBF означает многополосное изображение с плавающей запятой (RGB в этом примере, но это не единственный способ представления цветов).

4.2. Редактирование изображения

Чтобы нарисовать прямоугольник, нам нужно определить его форму, которая представляет собой многоугольник, состоящий из 4 точек (верхний левый, нижний левый, нижний правый, верхний правый):

Как вы могли заметить, при обработке изображений ось Y меняется на противоположную. После определения формы нам нужно нарисовать ее:

Метод рисования принимает 3 аргумента: форма, толщина линии и значения канала RGB, представленные массивом Float .

4.3. Отображение изображения

Нам нужно использовать Утилиты отображения :

5. Изображение TwelveMonkeys

Библиотека TwelveMonkeys |/ImageIO предназначена для расширения Java ImageIO API, с поддержкой большего количества форматов.

В большинстве случаев код будет выглядеть так же, как и встроенный код Java, но он будет работать с дополнительными форматами изображений после добавления необходимых зависимостей.

По умолчанию Java поддерживает только эти пять форматов изображений: JPEG , PNG , BMP , WBMP , GIF .

Если мы попытаемся работать с файлом изображения в другом формате, наше приложение не сможет его прочитать и выдаст исключение NullPointerException при доступе к переменной BufferedImage .

Двенадцать обезьян добавляет поддержку следующих форматов: PNG , |/PSD , TIFF , HDR , TIFF , PCX , PICT , SGI , TGA , ICNS , ICO , CUR , Thumbs.db , SVG , WMF .

Для работы с изображениями в определенном формате нам необходимо добавить соответствующую зависимость , например imageio-jpeg или imageio-tiff .

Полный список зависимостей можно найти в документации Двенадцать обезьян .

Давайте создадим пример, который читает изображение .ico . Код будет выглядеть так же, как в разделе AWT , за исключением того, что мы откроем другое изображение:

Чтобы этот пример работал, нам нужно добавить зависимость Двенадцать обезьян , которая содержит поддержку .icon images, которая является зависимостью imageio-bmp , вместе с зависимостью imageio-core :

И это все! Встроенный ImageIO Java API автоматически загружает плагины во время выполнения. Теперь наш проект будет работать и с изображениями .ico .

6. Резюме

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

Для этих целей, возможно, было бы лучше начать изучать ImageJ или OpenIMAJ. Оба они легко включаются в проект и гораздо более мощны, чем AWT, в отношении обработки изображений.

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

Пример того как render() может быть устроена внутри:

У такого подхода могут быть проблемы с производительностью из-за необходимости постоянно выполнять поиск элементов по DOM. Чтобы избежать этого, можно превратить представление в объект и сохранить в него все нужные элементы ровно один раз, в момент инициализации.

С ростом приложения увеличивается и количество обработчиков. Каждый из них может приводить к изменению только части страницы. Как поступать в таком случае? Создавать по рендеру на каждую ситуацию или описывать все возможные изменения в одной функции рендер?

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

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

И самое интересное. Что происходит внутри этой функции? Кажется, что внутри функции рендеринга нужно определять, что произошло, и затем менять необходимую часть DOM, например, удалить какой-то элемент, которого больше нет. В реальности это очень затратный подход, его сложно программировать, так как появляется большое количество условных конструкций. Намного проще выполнять полную перерисовку в любой ситуации. Тогда код останется максимально простым.

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

Теперь наше приложение разделено на три независимых части: состояние (данные приложения), обработчики и рендеринг. Эта модель работы на тривиальных приложениях (в пару-тройку обработчиков) смотрится избыточной, но если обработчиков станет хотя бы 10, то вы увидите, что с приложением достаточно удобно работать. Виден поток данных, то есть движение данных в приложении от одних частей к другим, от обработчика до отрисовки в DOM. Всегда можно отследить, что изменилось, и как одни части приложения зависят от других. К тому же, сокращается дублирование. Например, изменение состояния может идти из разных частей приложения, но логика отрисовки при этом остаётся неизменной. В такой ситуации достаточно описать новый способ изменения уже существующего состояния, а рендеринг сделает всё остальное.

Кроме наличия разделения на три части, не менее важно то, как они друг с другом взаимодействуют:

Графический интерфейс джава довольно развит и включает классы графического вывода,методы работы с цветом, вывод контуров, фигур, изображений и текста, работу с областью отсечения, преобразование координат, и различные вспомогательные классы.

основные классы графического интерфейса

  • Graphics2D (расширение Graphics) — контекст вывода. Определяет текущее графическое состояние, а также методы графического вывода. Для обратной совместимости другие классы в определении своих методов указывают Graphics, хотя реально используют Graphics2D;
  • Color — цвет;
  • Font — шрифт;
  • Point (расширение Point2D) — точка;
  • Rectangle — четырехугольник;
  • Polygon — многоугольник;
  • BasicStroke — контур сложной духмерной фигуры;
  • AffineTransform — матрица преобразования координат;
  • BufferedImage (расширение Image) — изображение, можно использовать также для вне экранного вывода совместо с Graphics2D;
  • TexturePaint — используется для заполнения фигуры текстурой;
  • GradientPaint — используется для градиентного заполнения фигуры.

Цвет реализуется классом Color. В нем также определены статические члены стандартных цветов, как Color.white. Ниже приведен список методов Graphics2D для работы с цветом:

  • getBackground — получить цвет очищения области;
  • setBackground — установить цвет очищения области;
  • clearRect — очистить область;
  • setColor — установить текущий цвет вывода;
  • getColor — получить текущий цвет вывода;

фигуры

Поддерживаются следующие классы фигур:

  • Arc2D — дуга;
  • Area — область, составная фигура (например, четырехугольник минус эллипс);
  • CubicCurve2D — сегмент кубической кривой (сплайн);
  • Ellipse2D — эллипс;
  • QuadCurve2D — сегмент квадратичной кривой (сплайн);
  • Line2D — линия;
  • Rectangle2D — четырехугольник;
  • RoundRectangle2D — четырехугольник с закругленными углами;
  • Rectangle — четырехугольник;
  • Polygon — многоугольник;
  • BasicStroke — контур сложной духмерной фигуры.

Все эти классы реализуют интерфейс Shape:

  • contains — методы определения содержится ли указанная точка или четырехугольник внутри сложной фигуры;
  • intersects — определяет, пересекается ли сложная фигура с четырехугольником;
  • getBounds — возвращает ограничивающий сложную фигуру четырехугольник;
  • getPathIterator — возвращает итератор по сегментам сложной фигуры.

Ниже приведен список методов Graphics2D для вывода фигур. Методы с префиксом draw выводят контур фигуры, а с префиксом fill закрашенную фигуру. Кроме цвета для закраски могут использоваться изображения или цветовые градиенты, реализуемые классами TexturePaint, GradientPaint.

  • draw — сложная фигура;
  • draw3DRect — трехмерный четырехугольник;
  • drawArc — дуга;
  • drawLine — линия, также используется для вывода точки;
  • drawPolyline — вывод последовательности линий;
  • drawOval — овал;
  • drawPolygon — многоугольник;
  • drawRect — четырехугольник;
  • drawRoundRect — четырехугольник с закругленными углами.
  • fill — сложная фигура;
  • fill3DRect — трехмерный четырехугольник;
  • fillArc — дуга;
  • fillOval — овал;
  • fillPolygon — многоугольник;
  • fillRect — четырехугольник;
  • fillRoundRect — четырехугольник с закругленными углами.

текст и изображения

Методы Graphics2D для вывода символов и изображения:

  • drawBytes, drawChars — вывод символов;
  • drawString — вывод строки;
  • drawImage — вывод изображения.

преобразование координат

Методы Graphics2D для преобразование координат:

  • getTransform — получить копию текущей матрицы преобразований;
  • setTransform — установить матрицу преобразований;
  • rotate — добавление вращения к текущей матрице;
  • scale — добавление масштабирования к текущей матрице;
  • shear — добавления скоса к текущей матрице;
  • translate — добавление сдвига к текущей матрице.

область отсечения

Методы Graphics2D для работы с областью отсечения:

  • setClip — установить текущую область отсечения;
  • getClip — получить текущую область отсечения;
  • getClipBounds — получить четырехугольник окружающий область отсечения;
  • clipRect — сделать пересечение с текущией областью отсечения новой областью;
  • clip — сделать пересечение сложной фигуры с текущей областью отсечения новой областью.

интерактивность

Методы Graphics2D для интерактивности с пользователем:

  • hit — есть ли пересечение между фигурой и четырехугольником;
  • hitClip — есть ли пересечение между областью отсечения и четырехугольником;
  • дополнительно см. методы интерфейса Shape.

Пример вывода графики с помощью Swing 2D

Контекст вывода Graphics или Graphics2D забирает много системных ресурсов. Поэтому если вы их создаете явно из другого Graphics, компонента, BufferedImage и т.п. (обычно это метод getGraphics), то рекомендуется освободить ресурсы явно вызовом метода dispose.


Для вывода пользовательской графики обычно создается отдельный элемент управления, который затем размещается на главное окно. В нем перегружается метод paintComponent для Swing элементов, или методы paint и update для awt элементов.
В этих случаях ресурсы контекста вывода освобождаются автоматически.

Для сохранения родительского облика в методе можно сделать вызов super.paintComponent(g);. И далее дорисовать поверх. Для примера в нижеследующем коде замените JComponent на JButton и удалите очищение фона.

Работа с изображениями в Swing 2D

Изображения в java описываются классом BufferedImage, который объединяет в себе объект растровых данных Raster и объект цветовой модели ColorModel.

В свою очередь объект растровых данных состоит из объекта DataBuffer, содержащего
четырехугольный массив значений пикселей, и объекта SampleModel, описывающего организацию данных в массиве: число банков в DataBuffer, ширину и высоту изображения, тип значений в DataBuffer (например, TYPE_INT).

Объект ColorModel нужен для преобразования данных пикселя в значения составляющих цвета.

вывод в изображение

Для вывода в изображение всего лишь надо получить контекст вывода изображения. Например, в следующем коде создается изображение белого многоугольника на сиреневом фоне.

вывод изображения

Для вывода изображения в объекте контекста вывода Graphics2d есть несколько методов. Для краткости я опущу типы аргументов:

  • drawImage(img, x, y, observer)
  • drawImage(img, x, y, bgcolor,observer)
  • drawImage(img, x, y, width, height, bgcolor, observer)
  • drawImage(img, x, y, width, height, observer)
  • drawImage(img, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, bgcolor, observer)
  • drawImage(img, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, observer)

Первый аргумент везде само изображение.

x, y, width, height — четырехугольная область вывода.

dx1, dy1, dx2, dy2 — координаты четырехугольной области вывода.

sx1, sy1, sx2, sy2 — координаты четырехугольной части изображения, которая будет выведена.

В качестве значения аргумента observer можно указывать null. Данный аргумент нужен только при асинхронной работе с изображением.

bgcolor — цвет заднего фона для прозрачных частей изображения.

Если область вывода не соответствует выводимой части изображения, то растровые данные автоматически масштабируются.

Графические форматы файлов.

Для манипуляций с графическими файлами в Java определен класс ImageIO.
При чтении ImageIO сам определяет формат файла. Список поддерживаемых форматов зависит от реализации Java, однако гарантируется поддержка jpeg, png, gif, bmp и wbmp. Список поддерживаемых форматов можно получить вызовом ImageIO.getWriterFormatNames()

Для теста создадим компонент, который при создании будет загружать изображение с диска, тут же его запишет обратно на диск в другом формате. А само изображение будет использоваться для оформления компонента.

Подробное объяснение метода рисования с использованием класса Java Graphics

1. Проведите линию
Чтобы нарисовать отрезок линии в окне, вы можете использовать метод drawLine () класса Graphics:

drawLine( int x1, int y1, int x2, int y2)


Например, следующий код рисует отрезок линии между точкой (3,3) и точкой (50,50) и рисует точку в точке (100,100).

g.drawLine( 3 , 3 , 50 , 50 ); // Рисуем отрезок линии

g.drawLine( 100 , 100 , 100 , 100 ); // Рисуем точку.

2. Нарисуйте прямоугольник.
Есть два типа прямоугольников: нормальные и закругленные.
(1) Есть два способа нарисовать нормальный прямоугольник:
drawRect (int x, int y, int width, int height): нарисуйте прямоугольник, заключенный в каркас. Параметры x и y определяют положение левого верхнего угла, а параметры width и height - это ширина и высота прямоугольника.
fillRect (int x, int y, int width, int height): заполните прямоугольник заданным цветом, чтобы получить цветной прямоугольный блок.
Следующий код представляет собой пример рисования прямоугольника:

g.drawRect( 80 , 100 , 40 , 25 ); // Рисуем каркас

g.setColor(Color.yellow);g.fillRect( 20 , 70 , 20 , 30 ); // Рисуем цветные блоки

(2) Есть также два способа нарисовать прямоугольник с закругленными углами:
drawRoundRect (int x, int y, int width, int height, int arcWidth, int arcHeight): это прямоугольник с закругленными углами, окруженный линиями.

Параметры x и y определяют положение левого верхнего угла прямоугольника;

Параметры width и heigth - это ширина и высота прямоугольника;

arcWidth и arcHeight - это поперечный диаметр скругленной дуги и продольный диаметр скругленной дуги соответственно.
fillRoundRect (int x, int y, int width, int height, int arcWidth, int archeight): прямоугольник с закругленными углами, заполненный заданным цветом. Значение каждого параметра такое же, как и в предыдущем методе.
Следующий код представляет собой пример рисования прямоугольника:

g.drawRoundRect( 10 , 10 , 150 , 70 , 40 , 25 ); // Рисуем прямоугольник с закругленными углами

g.setColor(Color.blue); g.fillRoundRect( 80 , 100 , 100 , 100 , 60 , 40 ); // Закрашиваем прямоугольный блок с закругленными углами

g.drawRoundRect( 10 , 150 , 40 , 40 , 40 , 40 ); //Нарисовать круг

g.setColor(Color.red); g.fillRoundRect( 80 , 100 , 100 , 100 , 100 , 100 ); // Рисуем круглый блок


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

3. Нарисуйте трехмерный прямоугольник.
Есть два способа нарисовать трехмерный прямоугольник:
draw3DRect (int x, int y, int width, int height, boolean поднят): нарисуйте выделенный прямоугольник. Где x и y определяют положение верхнего левого угла прямоугольника, параметры width и height - это ширина и высота прямоугольника, а поднятый параметр указывает, является ли он выступающим или нет.
fill3DRect (int x, int y, int width, int height, boolean поднятый): заполнить выделенный прямоугольник заданным цветом.
Следующий код представляет собой пример рисования заметного прямоугольника:

g.draw3DRect( 80 , 100 , 40 , 25 , true ); // Рисуем каркас

g.setColor(Color.yellow); g.fill3DRect( 20 , 70 , 20 , 30 , true ); // Рисуем цветной блок

4. Нарисуйте овал.
Форма эллипса определяется горизонтальной и вертикальной осями эллипса. Есть два способа нарисовать эллипс:
drawOval (int x, int y, int width, int height): это эллипс, окруженный линиями для рисования. Параметры x и y определяют положение верхнего левого угла эллипса, а параметры width и height являются горизонтальной и вертикальной осями.
fillOval (int x, int y, int width, int height): эллипс, заполненный заранее определенным цветом, который представляет собой цветной блок. Вы также можете нарисовать круг, нарисовав эллипс. Когда горизонтальная ось и вертикальная ось равны, нарисованный эллипс представляет собой круг.
Следующий код представляет собой пример рисования овала:

g.drawOval( 10 , 10 , 60 , 120 ); // Рисуем эллипс

g.setColor(Color.cyan);g.fillOval( 100 , 30 , 60 , 60 ); // Закрашенный круглый блок

g.setColor(Color.magenta);g.fillOval( 15 , 140 , 100 , 50 ); // Закрашиваем эллипс

g.drawArc( 10 , 40 , 90 , 50 , 0 , 180 ); // Рисуем дугу

g.drawArc( 100 , 40 , 90 , 50 , 180 , 180 ); // Рисуем дугу

g.setColor(Color.yellow); g.fillArc( 10 , 100 , 40 , 40 , 0 ,- 270 ); // Заполняем отсутствующий трехчетвертный эллипс в правом верхнем углу

g.setColor(Color.green); g.fillArc( 60 , 110 , 110 , 60 ,- 90 ,- 270 ); // Заполняем недостающие три четверти эллипса в нижнем левом углу

6. Нарисуйте многоугольник.
Многоугольник - это замкнутый вид в плане, образованный соединением нескольких сегментов линии встык. Координаты x и y конечных точек сегментов многоугольной линии хранятся в двух массивах соответственно.Чтобы нарисовать многоугольник, нужно соединить их с сегментами прямой в порядке заданных координатных точек. Ниже приведены два наиболее часто используемых метода рисования полигонов:
drawPolygon (int xpoints [], int yPoints [], int nPoints): рисовать многоугольник.
fillPolygon (int xPoints [], int yPoints [], int nPoints): используйте цвет, установленный методом setColor (), чтобы раскрасить многоугольник. В массиве xPoints [] хранятся точки координат x, yPoints [] хранятся точки координат y, а nPoints - это количество точек координат.

Обратите внимание, что описанный выше метод не закрывает многоугольник автоматически. Чтобы нарисовать замкнутый многоугольник, последняя точка данной координатной точки должна совпадать с первой точкой. Следующий код реализует заполнение треугольника и рисование восьмиугольника.

int px1[]=< 50 , 90 , 10 , 50 >; // Первая и последняя точки совпадают для рисования многоугольника

Читайте также: