MobiLab.ru - программирование для сотовых телефонов и КПК: Symbian C++ и OPL; J2ME, Mobile Basic, MIDlet Pascal, Windows CE, Linux. Есть форум и раздел о безопасности.
В избранное Сделать домашней Контакт
Меню
Главная
Новости
Документация
  - J2ME
  - Android
  - Symbian C++
  - Symbian OPL
  - Basic
  - Windows CE 
  - Linux
  - OpenGL ES
Безопасность
Книги
Софт
Проекты
Форум
Ссылки
Контакт

Книги


Заказать

Java 2. Библиотека профессионала. Том 1. ОсновыКей Хорстманн, Гари Корнелл
Цена:

Подпишись на рассылку



Реклама


22 декабря 2009 - Отрисовка SVG в J2ME без использования JSR 226 API.



Отрисовка SVG без использования JSR 226 API.

Довольно часто при написании проектов на Java2ME возникает необходимость в рисовании несложной векторной графики - это может быть логотип или график, а может быть и полноценный оконный интерфейс.  При этом у программиста  всего три доступных пути: использовать JSR 226 и резко ограничить количество моделей телефонов на которых приложение будет запускаться, рисовать графику вручную прописывая координаты в процедурах рисования и убив на это огромное количество времени или написать простенький векторный редактор никак не конкурирующий с большими системами. Существует и четвертый путь - написать конвертер из любого доступного векторного формата, при этом удобно использовать свободный кроссплатформенный формат - например тот же SVG. Изнутри SVG представляет подмножество XML форматов и является полностью текстовым. Формат достаточно сложный, поэтому на написание конвертера у меня ушло почти две недели. Результатом является консольная утилита InkToDraw.exe преобразовывающая исходный SVG файл в максимально простой формат и набор процедур написанных на  Java2ME для отрисовки графики на мобильном устройстве. Конвертер писался под Windows в среде Code::Block и дополнительно компилировался под Linux ASP 9.2 в среде Anjuta, соответственно работать он будет и под Windows и под Linux, такая вот кроссплатформа. Все необходимое для работы лежит в архиве.

Формат используемый на мобильном устройстве привязан к особенностям вывода в MIDP 2.0, для хранения координат используется один байт, что дает максимальный размер рисунка 256 на 256 точек, перейти на 16 бит не проблема - но при этом размер исходного блока данных увеличится в два раза, что было признано нецелесообразным.  В общем виде формат состоит из байта типа и набора координат для этого типа. Так как возможности отрисовки привязаны к Java 2 ME  спецификация формата содержит Линию, Прямоугольник, Эллипс/Дугу и Треугольник. Линия имеет два подвида: линия от точки к точке и полилиния когда результирующая ломаная описывается координатами точек. Кривые Безье апроксимируются 10 отрезками. Спецификация формата:

Вид Код Описание
100 100,3,X,Y,X1,Y1,X2,Y2,X3,Y3 (Ломаная линия, второй параметр – количество сегментов, далее идут координаты начала и координаты вершин)
101 101,X1,Y1,X2,Y2,X3,Y3,X4,Y4 (Кривая Безье, 4 пары координат полностью описывают кривую, первая и последняя пара - координаты начала и конца кривой)
102 102,3,X1,Y1,X2,Y2,X3,Y3,X4,Y4,X12,Y12,X13,Y13,X14,Y14,X22,Y22,X23,Y23,X24,Y24 (Кривая  состоящая из нескольких кривых Безье. Второй параметр - количество кривых, далее идут координаты начала и координаты вершин)
103 103,X1,Y1,W,H,A1,A2 (Контур эллипса или дуги, X1,Y1 - координаты левого верхнего угла прямоугольника в который вписан эллипс, W,H - ширина и высота эллипса/дуги, A1,A2 стартовый и конечный угол для дуги деленный пополам, чтобы уложиться в байт)
104 104,X1,Y1,W,H,A1,A2 (Залитый эллипс или сектор, X1,Y1 - координаты левого верхнего угла прямоугольника в который вписан эллипс, W,H - ширина и высота эллипса/дуги, A1,A2 стартовый и конечный угол для дуги деленный пополам, чтобы уложиться в байт)
105 105,X1,Y1,W,H,A1,A2 (Залитый эллипс или сектор, X1,Y1 - координаты левого верхнего угла прямоугольника в который вписан эллипс, W,H - ширина и высота эллипса/дуги, A1,A2 стартовый и конечный угол для дуги деленный пополам, чтобы уложиться в байт)
106 106,X1,Y1,W,H (Контур прямоугольника, X1,Y1 - координаты левого верхнего угла, W,H - ширина и высота)
107 107,X1,Y1,W,H (Залитый прямоугольник с обводкой, X1,Y1 - координаты левого верхнего угла, W,H - ширина и высота)
108 108,X1,Y1,W,H (Залитый прямоугольник, X1,Y1 - координаты левого верхнего угла, W,H - ширина и высота)
109 109,X1,Y1,W,H,RW,RH (Контур скругленного прямоугольника, X1,Y1 - координаты левого верхнего угла, W,H - ширина и высота, RW,RH - горизонтальный и вертикальный диаметр дуги скругления)
110 110,X1,Y1,W,H,RW,RH (Залитый скругленный прямоугольник с контуром, X1,Y1 - координаты левого верхнего угла, W,H - ширина и высота, RW,RH - горизонтальный и вертикальный диаметр дуги скругления)
111 111,X1,Y1,W,H,RW,RH (Залитый скругленный прямоугольник без контура, X1,Y1 - координаты левого верхнего угла, W,H - ширина и высота, RW,RH - горизонтальный и вертикальный диаметр дуги скругления)
112 112,X1,Y1,X2,Y2,X3,Y3 (Контур треугольника, X1,Y1,X2,Y2,X3,Y3 - координаты трех вершин)
113 113,X1,Y1,X2,Y2,X3,Y3 (Залитый треугольник с контуром, X1,Y1,X2,Y2,X3,Y3 - координаты трех вершин)
114 114,X1,Y1,X2,Y2,X3,Y3 (Залитый треугольник без контура, X1,Y1,X2,Y2,X3,Y3 - координаты трех вершин)
115 115,R,G,B (Цвет заливки, используется для всех залитых объектов, R,G,B - компоненты  цвета: красный, зеленый, синий)
116 116,R,G,B (Цвет рисования линий и контуров, R,G,B - компоненты  цвета: красный, зеленый, синий)
117 117,X1,Y1,X2,Y2 (Прямая, координаты задают начальную и конечную точку)
118 118 (После данного маркера все линии контура и кривые рисуются сплошной линией)
119 119 (После данного маркера все линии контура и кривые рисуются пунктирной линией)
255 255 (Маркер конца блока данных, после него рисование блока данных прекращается)

Для конвертирования под Windows используется утилита InkToDraw.exe, под Linux соответственно inktodraw. Формат командной строки у них идентичен. В общем виде коммандная строка состоит из трех аргументов - исходного файла в формате SVG, файла в который будет записан результат и опции. Из доступных опций только одна -show, вывод расширенной информации о конвертировании.

    Windows: InkToDraw.exe file.svg file.dat -options Linux: inktodraw file.svg file.dat -options

Если задан только один файл то вывод будет идти в InkDrawing.dat, а если утилита запущена без параметров будет осуществлена попытка открыть файл ScreenTest.svg и результат будет сохранен в InkDrawing.dat. К примеру, для конвертирования, мною была нарисована вот такая вот тыква.

Для того чтобы конвертировать ее в понятный обработчику формат достаточно положить файл ScreenTest.svg в одну папку с конвертером и отдать команду:

    Windows: InkToDraw.exe ScreenTest.svg Linux: inktodraw ScreenTest.svg

В результате в этой же папке появится файл InkDrawing.dat размером 453 байта, исходный файл при этом занимает  почти 18 килобайт, первые преимущества конвертера налицо ;). Теперь наша задача воспроизвести полученную картинку на мобильном устройстве. Для нетерпеливых в папке Jar есть два готовых примера: DrawTest.jar и DrawTest2.jar, друг от друга они отличаются только движком рендеринга.  Для более терпеливых читателей приготовлены проекты NetBean в папке NetBean и исходный текст без ресурсов в папке Source. Для тех кто будет собирать пакет руками достаточно создать новый проект, вставить в него исходный текст из файлов DrawTest.java или DrawTest2.java и забросить результат конвертации в папку res проекта. После сборки и запуска на экране телефона отобразится все та же тыква, после нажатия на клавишу пять апплет завершит свою работу, а любая другая клавиша отобразит ту же тыкву через другую процедуру вывода. Вариантов всего три: вывод без масштаба от левого верхнего угла, вывод с произвольным смещением и вывод со смещением и масштабом. 

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

InkDrawD Рисуем  от левого верхнего угла экрана, без масштабирования
InkDrawN Рисуем  со сдвигом, без масштаба
InkDrawS Рисуем  со сдвигом и масштабом

Параметрами для вывода является массив с данными m[], графический контекст g, смещение по x и y - dx,dy и масштабный коэффициент заданный в виде отношений двух пар целых чисел sx/mx и sy/my. К примеру для уменьшения картинки в два раза нужно задать sx=1,mx=2,sy=1,my=2 (1/2 и 1/2). Для рисования кривых Безье используется отдельная процедура drawBesier(), для преобразования байта в целое - функция i(). Процедуры восстанавливают значение текущего цвета и штриховки, так что в программе об этом беспокоиться не стоит, вывод происходит поверх уже существующего изображения. Теперь перейдем к вопросу почему в архиве приведено два практически идентичных примера. Отличаются они только способом хранения данных. В первом варианте массив данных хранится в виде байтов, но медленнее обрабатывается из за конвертации в целое каждого значения, во втором данные хранятся в виде целого (short) и занимают в два раза больше памяти, но читаются без преобразований. Варианты выбираем исходя из того что нам надо: экономить скорость вывода или память? 

При использовании данных процедур в своих проектах необходимо помнить о том что InkDrawD(), InkDrawN(), InkDrawS() независимы друг от друга, поэтому если вам нужен только вывод в фиксированном разрешении достаточно включить в проект только InkDrawD, при этом за собой она потянет процедуру рисования кривых Безье drawBesier(), а если используется хранение данных в байтовом массиве то и функцию  i(). В остальном никаких ограничений не накладывается. Если известно что рисунок будет состоять только из линий то из обработчика можно будет выкинуть все, кроме линий и цвета, что ускорит вывод и уменьшит размер кода. В общем простор для модификации достаточен. Код использует только одну возможность MIDP 2.0 - залитые треугольники, если их не использовать работать будет на любом устройстве с J2ME.

Теперь перейдем к особенностям рисования графики для конвертирования. Используем для этого Inkspace, размер нового листа указываем не больше 255 на 255 точек. Рисовать желательно с привязкой к пиксельной сетке, за границы рисунка не выходить, особенно при рисовании кривых Безье. Для рисования доступны все инструменты за исключением заливки, которую можно имитировать рисуя залитые фигуры - овал/треугольник/прямоугольник. При использовании текста не забывайте его конвертировать в кривые. Все нарисованные линии рисуются толщиной в один пиксель (толщина не учитывается). Если нарисовать замкнутую кривую с заливкой то после конвертации она будет в виде контура. Кривые содержащие больше 255 линий - отбрасываются. Недоступны градиенты и растровые эффекты, реализовать их на мобильном устройстве с нормальной скоростью весьма проблематично. Конвертер не поддерживает глобальные преобразование - поэтому не стоит ему подсовывать уменьшенную картинку из клипарта - все равно качественнее будет нарисовать или обвести готовый рисунок. 

Область применения данного конвертера достаточно широка - от текстово-графических игр до создания масштабируемых интерфейсов. Основное преимущество - возможность нарисовать картинку в произвольном разрешении. При необходимости движок вывода легко портируется на любую старую платформу и может быть использован на том же ZX-SPECTRUM или Commodore 64. Было бы желание.

Ограничения и неточности в текущей версии:
 - Залитые сектора с контуром рисуются без линий ограничивающих сектор;
 - Эллипсы и сектора нельзя поворачивать;

Что хотелось бы доработать в следующей версии (TO DO LIST ;):
 - Триангуляцию залитых кривых для вывода их треугольниками;
 - Рисование линиями разной толщины;
 - Рисование залитых кривых с помощью овалов или секторов;
 - Вывод текста векторным шрифтом;

Все необходимые упомянутые в статье файлы находятся здесь.

Автор: Shadowsshot. Почта: shadwork(a)ukr.net.


Новости
Компания velcom объявила конкурс для Android разработчиков

Sony Ericsson SDK 2.5.0.6 for the Java™ ME Platform

Конкурс для разработчиков Windows Mobile Developers 2009

Вышел Android 1.6 SDK

Motodev Studio for Android


Новые статьи
Как сделать телефонный звонок в Android

Рисование линий произвольной толщины в Java2ME

Отрисовка SVG в J2ME без использования JSR 226 API.

Создание моноширинного векторного шрифта для Java2ME.

Использование векторной графики и анимации в Java ME (JSR 226 API)

Обзор существующих Java ME SDK

Создаем игру с помощью визуальных средств NetBeans. Урок 4 – Соединение с удаленным сервером

Создание Google Android виджетов

Создаем игру с помощью визуальных средств NetBeans. Урок 3 – Задаем логику управления персонажем

Создаем игру с помощью визуальных средств NetBeans. Урок 2 – NetBeans Game Builder


[X]    Реклама




Rambler's Top100


© 2005-2009 MobiLab.ru
При использовании материалов сайта ссылка на www.mobilab.ru обязательна