• Главная
  • Карта сайта
Не найдено

Динамічна графіка в Java сервлетах

  1. огляд
  2. Читання і запис зображень, вимоги до JDK
  3. формати зображень
  4. архітектура сервлету
  5. Створення зображень в Java 1.1
  6. Створення зображень в Java 1.2
  7. продуктивність
  8. висновок

огляд


    Як створити графічний лічильник відвідувань? Діаграму, яка зображує завантаженість каналу до провайдера або кількість листів в черзі? Одним словом, як сформувати зображення динамічно за запитом користувача? У своїй статті Ken McCrary пропонує варіанти вирішення цього завдання. (2500 слів)

Графіки і діаграми дозволяють полегшити сприйняття аналітичної інформації. Уявіть, наприклад, таблицю вимірювань параметрів завантаженості каналу, що проводяться кожні п'ять хвилин. Важко повірити, що у вас вистачить терпіння переглядати її хоча б раз на тиждень. Тоді як, відповідна діаграма видається цілком легкотравної і вичерпної. У багатьох випадках зображення повинні створюватися в реальному часі за запитом користувача. Потреба в цьому може бути обумовлена ​​природою відображуваних даних, в разі, коли дані надходять безперервно або змінюються з часом, або ж можливістю значно зменшити використовується дисковий простір. Звичайно ж, не завжди доречно (технічно здійсненно) конструювати зображення динамічно, але, там, де це дійсно необхідно, використання вдалих технологічних рішень може привести до значного виграшу в продуктивності і якості сервісу.

Читання і запис зображень, вимоги до JDK


Для того щоб сервлет - додаток, що виконується на сервері, яке обробляє запити користувачів, - міг динамічно створювати зображення, перш за все, необхідний механізм читання і запису графічних файлів. Точніше, сервлет повинен вміти відправити отриману картинку у відповідь на запит користувача. Основні бібліотеки (Core API) для Java не надають коштів, використовуючи які можна було б зберегти отримане в пам'яті зображення в одному з графічних форматів. Є бібліотеки Sun для Java 1.1 і ліцензовані Sun бібліотеки для Java 1.2. Оскільки, вони розташовані в пакеті com.sun вони не відносяться ні до основних бібліотеках, ні до стандартних розширень (standard extension), тому використовують їх застосування не можна вважати переносяться (portable). Іншими словами, вони можуть і не працювати на віртуальній машині, випущеної іншою компанією. Варто зазначити, що затверджений запит Java Specification Request JSR-000015 на стандартне розширення Java 2 містить опис механізму для читання і запису графічних файлів; коли він буде реалізований, можна буде писати переносяться програми, які здійснюють введення / виведення зображень.

Для цієї статті я підготував приклади, що працюють на платформах Java 1.1 і Java 1.2.

формати зображень


Формат GIF - найпоширеніший формат графічних файлів в Інтернет. Він широко підтримується броузерами, в тому числі і найпершими. На жаль, написання програм, що генерують зображення в цьому форматі, потенційно утруднено патентом на алгоритм стиснення даних. Програм, наведені в цій статті, створюють зображення у форматі JPEG і PNG. Формат JPEG обраний, перш за все, з тих міркувань, що реалізація Sun Java 1.2 дозволяє формувати зображення цього типу без застосування додаткових бібліотек. (В прикладі додатка для JDK 1.1 можна отримати файл не тільки в форматі PNG, але і в багатьох інших, в тому числі - JPEG і GIF - прим. Перекладача)

Одне з відмінностей між форматами JPEG і GIF полягає в тому, що алгоритм стиснення даних, який використовується в GIF, на відміну від алгоритму, який використовується в JPEG, не спотворює зображення. Зазвичай, артефакти в JPEG картинках не сильно помітні. (Слід зазначити, що формат JPEG краще справляється з поданням фотографій, ніж тексту, діаграм або зображень, що містять тонкі лінії і чіткі межі колірних переходів - прим. Перекладача) Другий приклад застосовує формат PNG з алгоритмом стиснення без втрати даних і, до того ж, вільний від правових труднощів.

архітектура сервлету


Розіб'ємо нашу програму на дві частини. Перша частина - сервлет - відповідає за обробку HTTP запиту і повертає клієнту потрібне зображення, якщо це можливо. Друга частина, клас, який формує картинку. Для простоти реалізації, як параметр при зверненні до сервлету наймення використовуваного класу. Відповідний Java клас повинен реалізовувати певний інтерфейс для спілкування з сервлетом. Наведемо опис цього інтерфейсу:

public interface ImageProducer {/ ** * MIME тип створюваного зображення. * * @Return MIME тип зображення. * / Public String getMIMEType (); / ** * Створює зображення і записує його в зазначений потік. * * @Param stream Куди писати картинку. * / Public void createImage (OutputStream stream) throws IOException; }

Інтерфейс ImageProducer містить метод для визначення типу зображення і метод для формування зображення. Отримана картинка відправляється клієнтові.

Наступний код демонструє, як сервлет працює з класами, що реалізують інтерфейс ImageProducer:

ImageProducer imageProducer = (ImageProducer) Class.forName (request.getQueryString ()). NewInstance (); response.setContentType (imageProducer.getMIMEType ()); imageProducer.createImage (response.getOutputStream ());

Сервлет створює (завантажується) клас з ім'ям, зазначеним в параметрах запиту - частини URL справа після "?". Отриманий клас приводиться до типу ImageProducer. Потім, звертаючись до відповідних методів, сервлет отримує тип і формує зображення. У разі якщо немає помилок, картинка пересилається клієнту.

Наведений код може викликати кілька винятків, найбільш поширені з них: ClassNotFoundException і ClassCastException. Перше викликано тим, що клас, ім'я якого передано в якості параметра запиту, не доступний завантажувачу (ClassLoader), друге ж тим, що вказаний клас не реалізує інтерфейс ImageProducer. У разі помилки клієнт, звичайно ж, не отримує картинку, і броузер виводить зображення, що показує, що сервер не відповів на запит. Програма тестувалася з використанням Java Server Web Development Kit (JSWDK 1.0.1), але ви повинні отримати аналогічні результати на більшості інших Веб серверах, які підтримують Java.

Створення зображень в Java 1.1


Для свого першого прикладу я підготував код, який буде працювати на платформі Java 1.1. Хоча віртуальні машини JVM 1.2 досить поширені, не всі можуть розміщувати програми на цій платформі. На жаль, провайдери не сильно поспішають оновлювати віртуальні машини на своїх серверах. Як наслідок, доводиться розробляти сервлети, що працюють на платформі Java 1.1. Це не сильно ускладнять завдання; тим не менш, є деякі складності, пов'язані з формуванням зображень, які ми обговоримо нижче.

Будемо будувати кругову діаграму (pie chart), яку ми, для повноти картини, розфарбуємо і підпишемо. На діаграмі будуть зображені напої, що вживаються розробниками програмного забезпечення. Подивимося, як можна це зробити.

Для операцій вводу / виводу зображень в Java 1.1 Sun пропонує бібліотеку Jimi. Sun придбав її у невеликій компанії. Перед тим, як почати поширювати цю бібліотеку, компанія Sun перенесла класи в пакет com.sun, а в іншому нічого не змінила.

Наступні кроки необхідно виконати для формування PNG зображення з використанням Jimi.

  1. Створити вікно програми (Frame для отримання зображення.
  2. Використовую AWT зображення, створити реалізацію класу Graphics.
  3. Намалювати картинку за допомогою об'єкта Graphics.
  4. Створити об'єкт JimiWriter на основі потоку даних, що передаються клієнту.
  5. Перетворити зображення в відповідний формат і відправити його клієнту.

Для формування і модифікації зображень на платформі Java 1.1 необхідно використовувати активну AWT компоненту. Як правило, сервлет не повинен створювати AWT компоненти, які зазвичай використовуються в додатках з графічним інтерфейсом користувача. В цьому випадку, вам потрібен графічний (AWT) об'єкт для того, що б отримати об'єкт класу Graphics, за допомогою якого можна малювати нові картинки. Доведеться змиритися з маленьким віконцем на консолі Веб сервера. Якщо вам відомі способи створення зображення в Java 1.1 без використання AWT компонент, будь ласка, повідомте мені. Один з можливих варіантів, завантажити з диска сервера заздалегідь підготовлений шаблон, наприклад методом java.awt.Toolkit.createImage (). Після того, як ви створили AWT зображення, ви можете отримати реалізацію класу Graphics і використовувати її для малювання. Маючи в своєму розпорядженні об'єкт Graphics, ви можете закрити непотрібне вікно на консолі сервера. Я залишу цей експеримент зацікавленим читачам.

Нагадаю, що для зв'язку з класом, який малює кругову діаграму, сервлет використовує інтерфейс ImageProducer. Тому наш клас JIMIProducer повинен реалізовувати цей інтерфейс. Перш за все, створимо AWT вікно, AWT зображення і, нарешті, об'єкт Graphics:

Frame f = new Frame (); f.setVisible (true; image = f.createImage (ImageWidth, ImageHeight); graphics = image.getGraphics (); f.setVisible (false);

Ключовий метод класу JIMIProducer - drawSlice. Отримуючи на вході мітку і величину сегмента в градусах, цей метод малює сегмент діаграми, розфарбовує його і підписує. Далі, я розповім детальніше, як це відбувається.

Заповнюватимемо "нутрощі" діаграми за годинниковою стрілкою, починаючи з положення «три години", тобто першу лінію проведемо з центру до окружності обмежує діаграму в положенні годинникової стрілки о третій годині дня (чи ночі, як вам більше подобається). Відступимо за годинниковою стрілкою необхідну кількість градусів і намалюємо другу лінію, що обмежує сегмент діаграми. І так далі. Наведений нижче код отримує на вході величину сегмента в градусах і малює кордон цього сегмента. Він викликається послідовно для всіх сегментів, при цьому передбачається, що в сумі кутові величини складуть 360 градусів.

// ************************************************ * // Перетворимо кут в радіани // 1 градус = pi / 180 радіан // ******************************** ***************** double theta = degrees * (3.14 / 180); currentTheta + = theta; // ************************************************ * // Переводимо в декартові координати // x = r cos @ // y = r sin @ // *************************** ********************** double x = Radius * Math.cos (currentTheta); double y = Radius * Math.sin (currentTheta); Point mark2 = newPoint (center); mark2.translate ((int) x, (int) y); graphics.drawLine (center.x, center.y, mark2.x, mark2.y);

Потім, потрібно розфарбувати сегменти діаграми. Для цього можна скористатися дуже корисним методом fillArc ():

graphics.setColor (colors [colorIndex ++]); graphics.fillArc (Inset, Inset, PieWidth, PieHeight, -1 * lastAngle, -1 * degrees);

Останнє завдання методу drawSlice () намалювати мітки сегментів. Розташування написи розраховується, грунтуючись на метриці використовуваного шрифту. Остаточний варіант діаграми можна подивитися на малюнку.


Мал. 1. - Остаточний варіант кругової діаграми. (Не всі браузери показують файли формату PNG, тому тут ми поставили GIF файл.)

Створення зображень в Java 1.2


Практично всі цікавляться зараз курсами акцій на біржі. Намалюємо (всім на радість) на нашій діаграмі курс акцій компанії Sun за одну з тижнів березня.

Для створення зображень в форматі JPEG використовується клас com.sun.image.codec.jpeg.JPEGImageEncoder. Повторюся, що приналежність до пакету com.sun означає, що цей клас не є частиною основного API і до нього можна адресувати відповідні попередження.

Клас JPEGImageEncoder "розуміє", як перекодувати зображення java.awt.image.BufferedImage, так що його і будемо використовувати. Для створення класу BufferedImage потрібно вказати необхідні розміри зображення. Після створення, клас BufferedImage надає клас ava.awt.Graphics2D, який можна використовувати для малювання на відповідній класу BufferedImage зображенні. Все просто? Отже, основні кроки, необхідні для формування зображення в форматі JPEG:

  1. Створюємо клас JPEGImageEncoder, надаючи йому потік OutputStream даних переданих клієнтові.
  2. Створюємо клас BufferedImage необхідних розмірів.
  3. Використовуємо реалізацію класу Graphics2D, що надається класом BufferedImage, для малювання діаграми.
  4. За допомогою отриманого раніше класу JPEGImageEncoder перекодіруя намальоване зображення в формат JPEG і пишемо його в потік, що відправляється клієнтові.

Обговоримо деякі деталі малювання з використанням Graphics2D.

Для створення графіка курсу акцій потрібно, власне, намалювати кілька ліній. Пакет Java 2D, java.awt.geom, містить всі необхідні для цього класи. Абстрактний клас Line2D визначає відрізок прямої. Він має дві реалізації, що відрізняються типом використовуваних координат. Клас Line2D.Double застосовує примітивний тип double, а клас Line2D.Float - речові числа з плаваючою крапкою. Висока точність абсолютно зайва для нашого графіка, але я не буду економити і створю відрізки прямої класом Line2D.Double.

Наведемо, як приклад, ділянку програми, який малює горизонтальну вісь графіка:

horAxis = new Line2D.Double (HorzInset, ImageHeight - VertInset, ImageWidth - HorzInset, ImageHeight - VertInset); graphics.draw (horAxis);

Горизонтальна вісь будується з невеликим відступом від межі екрану, надаючи місце для розмітки. Після створення ви малюєте линю, звертаючись до методу draw () об'єкта Graphics2D. Нагадаю, що ви отримали його від реалізації класу BufferedImage. Клас Graphics2D містить методи для малювання графічних примітивів, для наших цілей цілком достатньо. На малюнку 2 наведено остаточний варіант графіка.


Мал. 2. - Остаточний варіант графіка курсу акцій.

продуктивність


Погана продуктивність - одне з основних звинувачень супротивників Java. Я не поділяю цієї позиції. Я переконаний в тому, що від можна домогтися гарної продуктивності для програми, написаної на Java, динамічно створює зображення. Як розробник програмного забезпечення, я можу дати вам пораду: якщо вас не влаштовує продуктивність, купуйте більш досконалі комп'ютери.

висновок


У цій статті я показав, як можна створювати в програмах на мові Java прості зображення, і скористався цією технікою для написання сервлету, формує картинку за запитом користувача. Ця технологія має величезну кількість додатків, обмежене, хіба що, рамками уяви. Два питання варто мати на увазі, розробляючи програми на основі викладених ідей: продуктивність алгоритму, що створює зображення, і обмеження пропускної здатності каналу зв'язку сервера. Для вирішення останньої проблеми, очевидно, потрібно максимально зменшити розмір картинки, в першому випадку застосовувати стандартні методи оптимізації додатків.

про автора

KenMcCrary, сертифікований Sun Java developer, живе в Нью-Йорку, Research Triangle Park. Він працював над великою кількістю Java проектів. Ви можете відвідати його сайт http://www.KenMcCrary.com

ресурси

Діаграму, яка зображує завантаженість каналу до провайдера або кількість листів в черзі?
Одним словом, як сформувати зображення динамічно за запитом користувача?
Все просто?
Провайдеры:
  • 08.09.2015

    Batyevka.NET предоставляет услуги доступа к сети Интернет на территории Соломенского района г. Киева.Наша миссия —... 
    Читать полностью

  • 08.09.2015
    IPNET

    Компания IPNET — это крупнейший оператор и технологический лидер на рынке телекоммуникаций Киева. Мы предоставляем... 
    Читать полностью

  • 08.09.2015
    Boryspil.Net

    Интернет-провайдер «Boryspil.net» начал свою работу в 2008 году и на данный момент является одним из крупнейших поставщиков... 
    Читать полностью

  • 08.09.2015
    4OKNET

    Наша компания работает в сфере телекоммуникационных услуг, а именно — предоставлении доступа в сеть интернет.Уже... 
    Читать полностью

  • 08.09.2015
    Телегруп

    ДП «Телегруп-Украина» – IT-компания с 15-летним опытом работы на рынке телекоммуникационных услуг, а также официальный... 
    Читать полностью

  • 08.09.2015
    Софтлинк

    Высокая скоростьМы являемся участником Украинского центра обмена трафиком (UA — IX) с включением 10 Гбит / сек... 
    Читать полностью