PaintCAD Mobile - журнал разработки

jaguar50
Новичок
Сообщения: 25
Зарегистрирован: Вс ноя 22, 2009 6:50 pm

Re: PaintCAD Mobile - журнал разработки

Сообщение jaguar50 » Вт окт 21, 2025 1:32 am

СпойлерПоказать
blackstrip писал(а): Пт окт 17, 2025 6:06 pm Проблема оперативной памяти
blackstrip писал(а): Ср окт 08, 2025 10:10 pmДля сименса прописаны клавиши как для самых последних моделей Benq-Siemens, предпросмотр по физической "Взять трубку", тип линий по "Громкость-", фото по "Громкость+", а физическая "Положить трубку" не используется, т.к. она закрывает паинткад. На более старый сименс x65/75 потребуется дополнительная настройка вручную. Но там, на сименсах, и так сейчас от слишком толстых классов паинткада при запуске сразу исключение OutOfMemorу и вылет. Эту проблему надо будет попробовать решить позже
Паинткад давно уже не идет на слабых телефонах с MIDP2. Запускаем вот эту последнюю версию с настройкой клавиш и т.п. на Siemens C65 эмуляторе и видим OutOfMemory:

Изображение

Т.е. ява распаковала JAR-архив, взяла главный класс PaintCAD, запустила его, там в самом начале создаются экземпляры класса стартового окна Loading и главного класса MainForm. Потом передается отображение в Loading. И где-то там не хватило памяти и всё, конец)

Когда-то давно такая ошибка стала вылетать - и тогда класс MainForm был поделен на два класса: MainForm и MainForm2. Часть процедур и переменных были перекинуты в MainForm2. И тогда все заработало и OutOfMemory перестал вылетать. Но потом программа росла-росла и вот уже лет пять-десять на старых сименсах она не запускается опять.

Попробуем разобраться из-за чего так происходит. Варианты:
1) если классы и ресурсы (картинки) помещаются в оперативную память и занимают там место, то этого места не хватило и привет. Можно было бы сделать для слабых телефонов версию с мелкой графикой, не занимающей много места
2) предел по размеру класса, как только класс вырастает до некоторого предельного для телефона размера (например, 64 килобайта) - ява больше не хочет грузить его и при загрузке такого большого класса выдает OutOfMemory (тогда понятно почему разделение класса MainForm на два класса помогло - было, например 80 кбайт, а стало 40 и 40, оба класса стали загружаться и запускаться без проблем). Тогда надо снова делить MainForm и делать MainForm3 =)
3) что-нибудь неведомое, что знают только те, кто знает как работает ява (это не я, ха-ха), как она грузит классы и запускает их, на что тратится Java-heap и т.д. Тут бы помог вывод с разблюдовкой по классам - какой класс сколько хочет занять, какой сколько занимает, какой спотыкается на выделении памяти и заваливает всю программу, и в какой момент все это происходит

У эмулятора, кстати, есть output window - выдает всякие сообщения. И он после ошибки OutOfMemory выдает вот что:

Изображение

Провалена инициализация класса paintcad.ah. Интересное имя paintcad.ah - из-за обфускатора, который шифрует и переименовывает все классы чтоб никто не декомпилировал ява-проги. Выключим его, увидим реальные имена:

Изображение

Не удается инициализировать класс MainForm. Уберем все создания экземпляров классов и переход на MainForm - эмулятор бесконечно показывает анимацию "Please wait...", видимо чтоб программа загрузила все что надо и наконец-то перешла на первый Displayable-класс:

Изображение

Попробуем передадим отображение на новый класс сохранения 24-битного BMP:

Код: Выделить всё

display = Display.getDisplay(this);
display.setCurrent(new SBMP24());
О, чудо - он показывается:

Изображение

Т.е. загрузить, распаковать куда-то и запустить 600-килобайтовый JAR полностью - у Siemens C65 сил хватает. И начать отображать один из классов-displayabl-ов - тоже хватает. Хорошо. Делать low-версию с урезанным количеством ресурсов не придется.

Попробуем создать только экземпляр Loading, а перейти на SBMP24:

Код: Выделить всё

displayabl = new Loading();
display = Display.getDisplay(this);
display.setCurrent(new SBMP24());
И тоже видим OutOfMemory. Причем в Output window эмулятора - ничего не выводится. Будем отрезать от Loading-а кусочки пока он не станет таким худым что запустится =)

Вырезав все из Loading (включая все обращения к статическим переменным MainForm) - зазапускался паинткад с отображением SBMP24 окошка. Хорошо.

Теперь передадим отображение прямо на Loading, как это обычно и происходит в необрезанном паинткаде:

Код: Выделить всё

displayabl = new Loading();
display = Display.getDisplay(this);
display.setCurrent(displayabl);
В процедуре отрисовки пропишем просто зарисовку экрана черным:

Код: Выделить всё

g.setColor(0,0,0);
g.fillRect(0,0,getWidth(),getHeight());
И оно рисуется:

Изображение

Но стоит добавить в этот хорошо рисующий черным Loading обращение хоть к одной статической переменной класса MainForm - и снова OutOfMemory. Видимо, в этот момент класс MainForm подгружается - при первом обращении к его переменным.

Уберем обращение к большому классу MainForm. И проверим, действительно ли, класс не может загрузиться если он большого размера, или это неправда.

Сейчас Loading почти 4 килобайта:

Изображение

А MainForm аж 119 килобайт:

Изображение

Напихаем в Loading от души кода в какую-нибудь фиктивную процедуру так чтобы он разросся до подобного размера. Добавим статичную процедуру:

Код: Выделить всё

  static void Fictive() {
    JoySetup.KEY_FOTO = (int)System.currentTimeMillis();
  }
Размер увеличился до 3,99 килобайта:

Изображение

Повторим строчку приравнивания 10 раз вместо одного:

Код: Выделить всё

  static void Fictive() {

    JoySetup.KEY_FOTO = (int)System.currentTimeMillis();
    JoySetup.KEY_FOTO = (int)System.currentTimeMillis();
    JoySetup.KEY_FOTO = (int)System.currentTimeMillis();
    JoySetup.KEY_FOTO = (int)System.currentTimeMillis();
    JoySetup.KEY_FOTO = (int)System.currentTimeMillis();
    JoySetup.KEY_FOTO = (int)System.currentTimeMillis();
    JoySetup.KEY_FOTO = (int)System.currentTimeMillis();
    JoySetup.KEY_FOTO = (int)System.currentTimeMillis();
    JoySetup.KEY_FOTO = (int)System.currentTimeMillis();
    JoySetup.KEY_FOTO = (int)System.currentTimeMillis();
    
  }
Стало 4,09 килобайта:

Изображение

Loading увеличился на 100 байт. А нам надо нарастить 115 килобайт. Хорошо, вставляем в процедуру 100 таких строчек вместо 10, смотрим линейно ли растет размер (мало ли какая оптимизация явы включится). Видим 5,05 килобайта:

Изображение

Вырос на 1 килобайт примерно. Как раз в 10 раз больше чем 100 байт. Окей, теперь добавим 100 раз по 100 строчек +) Должен быть класс 100 с лишним килобайт.

Теперь Jbuilder помер, пишет что байт-код превышает 65536 байт (64 килобайта):

Изображение

Может ему не нравится одна большая процедура. Хорошо, сделаем 10 маленьких.

10 маленьких preverifier-у понравились. Класс Loading теперь 111 килобайт:

Изображение

Пробуем запустить его и отрисовать черный экран. И он рисуется:

Изображение

Может быть порог размера класса выше 111 килобайт. Добавим фиктивных процедур и дотянем размер Loading-класса до 118 килобайт и даже выше:

Изображение

122 килобайта и... снова все рисуется. Значит нет никакого "предельного" размера class-файла (по крайней мере при текущем размере проблемного класса MainForm в 118 килобайт) и это не поддельное OutOfMemory, а настоящее. Память явы переполняется при подгрузке и инициализации MainForm.

Добавим в отрисовку помимо черного экрана еще и доступное количество памяти и общее количество памяти в байтах:
g.setColor(0,0,0);
g.fillRect(0,0,getWidth(),getHeight());
g.setColor(0,200,0);
g.drawString(String.valueOf(Runtime.getRuntime().freeMemory()),5,5,Graphics.LEFT|Graphics.TOP);
g.drawString(String.valueOf(Runtime.getRuntime().totalMemory()),5,25,Graphics.LEFT|Graphics.TOP);
При чистом Loading-модуле без запросов к MainForm и другим классам:

Изображение

В этих же условиях, но после обфускации:

Изображение

Этот же JAR, собранный в APK и запущенный под андроидом 2.3.3 на эмуляторе - запустим дважды, цифры могут отличаться, т.к. в яве постоянно garbage collector чистит всякие ненужные вещи в памяти, но примерно количество свободной памяти должно быть одинаково в обоих запусках:

Изображение

Изображение

А теперь дернем одну из переменных толстого класса MainForm и посмотрим сколько теперь свободной памяти - тоже дважды посмотрим для точности:

Изображение

Изображение

Всего на 12 килобайт стало меньше. И это сваливает сименс в OutOfMemory... (проверил на всякий случай на этой же версии JAR - да, все еще сваливает +) Очень странно.

Может быть еще есть какой-то лимит. По количеству переменных, связей между классами, статичных переменных, расшаренных на весь мидлет.

Допустим, андроид неправильно все делает и при подключении большого класса MainForm толком не выделяет память (неизвестно как сделана ява андроида). Проверим тогда и на обычных J2ME-телефонах.

Nokia N90:

Просто Loading, без связи с большим MainForm - нокия говорит, что у нее всего 1 мегабайт памяти, и свободной всего около 70-100 килобайт (иногда даже 4 килобайта показывает), как будто она все классы паинткада сразу загрузила несмотря на то, есть ли с ними связи или нет:

Изображение

Изображение

Изображение

Изображение

Изображение

Изображение

Теперь Loading, дергающий переменную MainForm - у нокии открылось второе дыхание и теперь всего памяти не 1 миллион байт, а 2,5 миллиона, чудеса. И свободной опять около 100 килобайт. Как будто после связи с MainForm (и связью самого класса MainForm со всеми остальными связанными классами) вместо занимаемых 900 килобайт теперь нужно 2300 килобайт - если действительно это так, то здесь сименс и помирает на OutOfMemory со своими доступными 1500 килобайтами, 2300 в него не влезают:

Изображение

Изображение

Изображение

Изображение

Изображение

Изображение

Изображение

Надоело болтающееся число свободных байт. Добавим в код вызов garbage collector через System.gc() - после его вызова лишнее и ненужное в памяти насильно будет удалено, может, число свободных байт станет более стабильным:
g.setColor(0,0,0);
g.fillRect(0,0,getWidth(),getHeight());
g.setColor(0,200,0);
System.gc();
g.drawString(String.valueOf(Runtime.getRuntime().freeMemory()),5,5,Graphics.LEFT|Graphics.TOP);
g.drawString(String.valueOf(Runtime.getRuntime().totalMemory()),5,25,Graphics.LEFT|Graphics.TOP);
Проверим поедание памяти при подгрузке MainForm еще на одной яве. Это телефон LG GT540. Вообще это изначально был Android 1.6, потом выходили обновления и он стал Android 2.1. Но в нем есть эмулятор Java от LG. Этот эмулятор прикидывается LG-телефоном на яве и может устанавливать и запускать J2ME-мидлеты в андроиде. Мидлеты появляются в списке программ прямо в том же списке что и андроид-приложения, и их можно даже вытащить на рабочий стол:

Изображение

Изображение

Проверка Loading без связи с MainForm - говорит что паинткад занял около 3 мегабайт (3000 килобайт), а всего доступно аж 20 мегабайт, поэтому 17 мегабайт свободны. Остановка мидлета и повторный запуск - бесконечно показывает одно и то же число свободной памяти:

Изображение

Проверка Loading со связь с MainForm. (на этом телефоне если его повернуть горизонтально-вертикально, то эмулятор перерисовывается и прекращает пытаться натянуть мидлет на экран. Шрифты становятся красивые, точка в точку, без масштабирования кривобокого). С подключенным классом MainForm числа заменялись от запуска к запуску, но совсем не сильно:

Изображение

Изображение

Разница с MainForm и без MainForm - около 10 килобайт. Но тут сразу заняты 3 мегабайта, поэтому, вероятно, он сразу подгрузил все классы, поэтому разницы и нет.

В общем:
- есть явы (Nokia N90), где подключение MainForm подгружает его и увеличивает лимит оперативной памяти чтобы все влезло. И становится нужно паинткаду 2,5 мегабайта памяти.
- есть явы (ява-эмулятор LG GT540, и просто запуск под Android APK), где подключение MainForm никак не влияет, вероятно, там память сразу выделяется на все классы и все их связи и переменные.

Есть еще эмуляторы Siemens в составе Benq-Siemens Mobility Toolkit - мощные эмуляторы для телефонов с большими (по меркам сименсов) экранами типа 240х320 пикселей. И там есть эмулятор слайдера Siemens SL75 - это телефон с экраном 132х176 пикселей как более старые сименсы. У них много оперативной памяти в яве.

Проверка Loading без связи с MainForm в эмуляторе Siemens SL75:

Изображение

Занято сразу под 2 мегабайта, зато всего 3,7 мегабайта. Может быть здесь влезет в такую большую память Loading с MainForm.

От запуску к запуску количество свободной памяти здорово меняется - от 800 килобайт до 2,5 мегабайт)

Изображение

Изображение

Изображение

Изображение

Изображение

Проверка Loading со связью с MainForm в эмуляторе Siemens SL75 - он не выдает OutOfMemory:

Изображение

Изображение

Изображение

Изображение

Изображение

Стабильно остается по 800-850 килобайт. Значит паинткаду нужно 3670-850 = 2,8 мегабайта после подключения MainForm.

Посчитаем разницу памяти до подгрузки MainForm и после подгрузки MainForm на всех вышеописанных устройствах и эмуляторах. Ориентироваться будем на самую большую свободную память (меньшие числа - это просто не доработал garbage collector):

Android-эмулятор 2.3.3
До: 5644 - 2845 = 2799 Кб
После: 5644 - 2833 = 2811 Кб
Разница: 12 Кб

Nokia N90
До: 1000 - 114 = 886 Кб
После: 2441 - 151 = 2290 Кб
Разница: 1404 Кб

Эмулятор явы в LG GT540
До: 20971 - 17937 = 3034 Кб
После: 20971 - 17932 = 3039 Кб
Разница: 5 Кб

Siemens SL75 эмулятор
До: 3670 - 2465 = 1205 Кб
После: 3670 - 852 = 2818 Кб
Разница: 1613 Кб

Выводы:
1) на тех телефонах, где подключение MainForm сильно увеличивало занятую память (Nokia N90, Siemens SL75) - это подключение потребовало 1400-1600 килобайт памяти;
2) после подключения MainForm занимаемая паинткадом память стала равна:
- 2,3 Мбайт на Nokia N90,
- 2,8 Мбайт на Android и на Siemens SL75
- 3 Мбайт на эмуляторе явы в LG GT540

Поэтому текущие "системные требования" паинткада: минимум 2,5 - 3 мегабайта памяти в яве только для загрузки классов. Вот такие дела

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

Проведем тест - запустим паинткад в 24-битном режиме с новым рисунком 32х32 пикселя. В меню "Помощь" есть пункт "Объем памяти", показывает свободную и полную память (эти же цифры что и наверху на скриншотах). Посмотрим сколько памяти занято при полной загрузке паинткада со всеми ресурсами, картинками и т.п. на этих же устройствах и эмуляторах:

Android-эмулятор 2.3.3

Изображение

Изображение

Изображение

Изображение

Изображение

Изображение

6365 - 3344 = 3021 Кб

Nokia N90

Изображение

Изображение

Изображение

Изображение

Изображение

3051 - 1441 = 1610 Кб

Сначала она модулю Loading давала всего 1000 Кб памяти, потом давала для Loading+MainForm всего 2441 Кб, а сейчас - уже для полного паинткада всего 3051 Кб =) Как она это делает? Динамически растит явовскую память до больших значений +) Это телефон 2005 года, тогда еще были в ходу сименсы с экраном 101х80 точек и 4096-цветным экраном или 132х176. А эта с гигантским экраном и очень большой памятью по сравнению с ними.

Эмулятор явы в LG GT540

Изображение

Изображение

20971 - 17158 = 3813 Кб

Siemens SL75 эмулятор

Раньше паинткад и тут выдавал OutOfMemory. Но сейчас, почему-то работает) Интересно, тогда, посмотреть как тут выглядит настройка клавиш - она тут даже работает и текст влезает во все элементы на экране:

Изображение Изображение Изображение

Изображение Изображение Изображение

Изображение Изображение Изображение

Изображение

Что касается оперативной памяти:

Изображение

Изображение

Изображение

3670 - 848 = 2822 Кб

Теперь можно высчитать сколько занимают буферы и ресурсы в памяти во всех этих устройствах:

Android-эмулятор 2.3.3
Loading: 2799 Кб
Loading+MainForm: 2811 Кб
Полностью PaintCAD: 3021 Кб
Чисто ресурсы: 3021 - 2811 = 210 Кб

Nokia N90
Loading: 886 Кб
Loading+MainForm: 2290 Кб
Полностью PaintCAD: 1610 Кб
Чисто ресурсы: 1610 - 2290 = минус 680 Кб (во бред)

Эмулятор явы в LG GT540
Loading: 3034 Кб
Loading+MainForm: 3039 Кб
Полностью PaintCAD: 3813 Кб
Чисто ресурсы: 3813 - 3039 = 774 Кб

Siemens SL75 эмулятор
Loading: 1205 Кб
Loading+MainForm: 2818 Кб
Полностью PaintCAD: 2822 Кб
Чисто ресурсы: 4 Кб

Ничего не понятно) Почему-то после прохождения полного цикла загрузки по MainForm, создания разных буферов и загрузки картинок в память:
- где-то памяти надо больше на 774 Кб (это нормально),
- где-то на 210 Кб (ну это андроид, он может чудить, ведь это портировщик с явы, что он там показывает хз),
- где-то минус 680 килобайт (Нокия N90 после загрузки ресурсов и создания буферов потребовала меньше памяти),
- где-то около нуля (эмулятор Сименса SL75 тоже, допустим, может чудить, хотя странно)

Допустим, у Нокии N90 где-то в пике загрузки классов потребовалось настолько много памяти, то она до загрузки ресурсов показала большее число, и garbage collector ничего этого лишнего очистить не мог, но уже после полной загрузки паинткада он смог и память освободилась, хз как там классы грузятся.

В общем, требуемая для сегодняшней версии память чтоб при запущенном паинткаде рисовать картинку 32х32 пикселя:

Android-эмулятор 2.3.3: 3021 Кб
Nokia N90: 1610 Кб
Эмулятор явы в LG GT540: 3813 Кб
Siemens SL75 эмулятор: 2822 Кб

И требуемая максимальная память (максимальное значение необходимой памяти из двух значений - до загрузки ресурсов и после загрузки ресурсов):

Android-эмулятор 2.3.3: 3021 Кб
Nokia N90: 2290 Кб
Эмулятор явы в LG GT540: 3813 Кб
Siemens SL75 эмулятор: 2822 Кб
PNG, JPEG и GIF - можно оптимизировать за счёт удаления или уменьшения ненужных чанков (в PNG) или метаданных (в JPEG и других форматах). Это позволяет уменьшить размер файла без потери визуального качества — так называемая lossless-оптимизация.

1. PNG (Portable Network Graphics)

PNG-файл состоит из чанков — блоков данных с определённой структурой. Некоторые из них обязательны (например, IHDR, IDAT, IEND), а другие — опциональны и часто содержат метаданные:

tEXt, zTXt, iTXt — текстовые комментарии, автор, описание и т.п.
gAMA — гамма-коррекция.
cHRM, sRGB, iCCP — цветовые профили.
tIME — дата создания.
pHYs — физическое разрешение (dpi).
bKGD, hIST, tRNS — могут быть полезны, но не всегда нужны.

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

Инструменты:

pngcrush — удаляет ненужные чанки и пересжимает данные.
optipng — lossless-оптимизатор, убирает лишнее.
pngquant — уже с потерями (lossy), но даёт сильное сжатие.
oxipng — быстрая Rust-альтернатива optipng.

2. JPEG

JPEG не использует чанки в том же смысле, что PNG, но содержит сегменты (segments), включая:

APP0, APP1 и др. — могут содержать EXIF, XMP, ICC-профили, комментарии, данные о камере и т.д.
COM — пользовательские комментарии.

Оптимизация: Удаление EXIF/XMP/ICC данных часто уменьшает размер на 10–30%, особенно для фото с камеры.

Инструменты:

jpegoptim — lossless-очистка метаданных и оптимизация таблиц Хаффмана.
mogrify -strip (из ImageMagick) — удаляет все профили и комментарии.
guetzli, mozjpeg — более агрессивные (иногда с потерями) оптимизаторы.

3. GIF

GIF может содержать:

Комментарии (Comment Extension).
Метаданные от программ (например, Adobe).
Лишние цвета в палитре.
Неоптимальные кадры (в анимированных GIF).

Удаление комментариев и оптимизация палитры/кадров помогает уменьшить размер.

Инструменты:

gifsicle — мощный инструмент для сжатия и оптимизации анимированных GIF.

Аватара пользователя
blackstrip
Админ
Сообщения: 1290
Зарегистрирован: Ср янв 02, 2008 1:42 pm
Откуда: Подольск
Контактная информация:

Re: PaintCAD Mobile - журнал разработки

Сообщение blackstrip » Вт окт 21, 2025 9:28 pm

jaguar50 писал(а): Вт окт 21, 2025 1:32 am PNG, JPEG и GIF - можно оптимизировать за счёт удаления или уменьшения ненужных чанков
Я так понял, что паинткадовские классы когда загружаются в памяти и инициализируются их переменные, то вся эта солянка занимает 2 мегабайта =) Надо какой-то ява профайлер для старых j2me-прог запустить и посмотреть что конкретно сколько ест.

И уже при подгрузке классов в яву все дохнет. Там еще нет PNG/JPG/GIF. Там просто классы. Потом к ним добавляются ресурсы (картинки), массивы (массив точек текущей рисуемой картинки, массив точек буфера обмена и т.д.). Так вот уже на этапе классов все помирает. Надо разбираться потом будет +) Пока только ясно что при текущем наборе классов и связях между ними - меньше 2 мегабайт памяти явы сразу приводят к OutOfMemory как только загружается первый большой класс, связывающий другие более мелкие между собой (подозрение что эти мелкие классы сразу все подгружаются после большого класса если ява видит что в этом большом классе они будут нужны, если задействованы их методы, переменные и др.).

jaguar50
Новичок
Сообщения: 25
Зарегистрирован: Вс ноя 22, 2009 6:50 pm

Re: PaintCAD Mobile - журнал разработки

Сообщение jaguar50 » Вт окт 21, 2025 11:15 pm

blackstrip писал(а): Вт окт 21, 2025 9:28 pm
jaguar50 писал(а): Вт окт 21, 2025 1:32 am PNG, JPEG и GIF - можно оптимизировать за счёт удаления или уменьшения ненужных чанков
Я так понял, что паинткадовские классы когда загружаются в памяти и инициализируются их переменные, то вся эта солянка занимает 2 мегабайта =) Надо какой-то ява профайлер для старых j2me-прог запустить и посмотреть что конкретно сколько ест.

И уже при подгрузке классов в яву все дохнет. Там еще нет PNG/JPG/GIF. Там просто классы. Потом к ним добавляются ресурсы (картинки), массивы (массив точек текущей рисуемой картинки, массив точек буфера обмена и т.д.). Так вот уже на этапе классов все помирает. Надо разбираться потом будет +) Пока только ясно что при текущем наборе классов и связях между ними - меньше 2 мегабайт памяти явы сразу приводят к OutOfMemory как только загружается первый большой класс, связывающий другие более мелкие между собой (подозрение что эти мелкие классы сразу все подгружаются после большого класса если ява видит что в этом большом классе они будут нужны, если задействованы их методы, переменные и др.).
Я бы все равно оптимизировал изображения

Аватара пользователя
blackstrip
Админ
Сообщения: 1290
Зарегистрирован: Ср янв 02, 2008 1:42 pm
Откуда: Подольск
Контактная информация:

Re: PaintCAD Mobile - журнал разработки

Сообщение blackstrip » Чт окт 23, 2025 7:48 pm

jaguar50 писал(а): Вт окт 21, 2025 11:15 pm Я бы все равно оптимизировал изображения
Ну насчет мобильного паинткада:
1) он JPG не сохраняет вообще, только открывает средствами явы/андроида (говорит яве/андроиду "сделай-ка массив цветных точек из того JPG файла")
2) PNG файлы открываются и сохраняются, можно там поискать лишние чанки, но, сомневаюсь, что там их много
3) GIF тоже открываются и сохраняются, но там уж точно по минимуму лишних чанков. А упаковка (оптимизация кадров) GIF-анимаций, например, в PaintCAD 4Windows есть - первый кадр сохраняется целиком, а остальные - только изменяющиеся части рисунка сохраняют, и кладутся при отрисовки анимации поверх первого кадра:

Изображение

Аватара пользователя
blackstrip
Админ
Сообщения: 1290
Зарегистрирован: Ср янв 02, 2008 1:42 pm
Откуда: Подольск
Контактная информация:

Re: PaintCAD Mobile - журнал разработки

Сообщение blackstrip » Пт ноя 07, 2025 6:27 pm

Проверка окна MainForm на тестовых телефонах

Возьмем 8-битный режим, откроем черно-белую картинку 32x32 пикселя с самолетом Aircraft.bmp с сименсов x55/x60. При этом масштаб будет автоматически установлен в размер виртуального пикселя (пиксели на картинке и все окантовки элементов будут одной и той же толщины, как будто это и есть точки экрана)

Доработанных экранов много. Будем тестировать следующие:
1) обычный режим окна рисования
2) сокращенный режим окна рисования
3) полноэкранный режим окна
4) режим BMX-анимации с включенной функцией "разбить"
5) предпросмотр с масштабированием
6) экран блокировки

1 - Android 2.3.3 - Samsung Galaxy Ace

Изображение

Изображение

Изображение

Изображение

Изображение

Изображение

2 - Android 4.2 - RugGear RG310

Изображение

Изображение

Изображение

Изображение

Изображение

Изображение

3 - Android (Mocor) 4.4.4 - Joy's S15

Изображение

Изображение

Изображение

Изображение

Изображение

Изображение

4 - Android 9 - Soyes XS13

Изображение

Изображение

Изображение

Изображение

Изображение

Изображение

5 - Android 12 - Xiaomi Duoqin F22 Pro

Изображение

Изображение

Изображение

Изображение

Изображение

Изображение

6 - Android 15 - Xiaomi Redmi Turbo 3 (Poco F6)

Изображение

Изображение

Изображение

Изображение

Изображение

Изображение

7 - Java 2 Microedition - Nokia N90

Изображение

Изображение

Изображение

Изображение

Изображение

Изображение

8 - Java 2 Microedition - Nokia 7900 Prism

Изображение

Изображение

Изображение

Изображение

Изображение

Изображение

9 - Java 2 Microedition - Siemens SL75 (эмулятор)

Изображение

Изображение

Изображение

Изображение

Изображение

Изображение

10 - Java 2 Microedition - Benq-Siemens EL71 (эмулятор)

Изображение

Изображение

Изображение

Изображение

Изображение

Изображение

Слово "Блокировка" не влезло в экран по ширине) Добавим мини-проверку, если ширина этого слова в пикселях больше экрана - то будем писать другое слово "Блок"/"Block", оно точно влезет. Получаем:

Изображение

Для сравнения как эти же экраны выглядели в прошлой бете:

Изображение

Изображение

Изображение

Изображение

Изображение

Изображение

APK-файл в Telegram: https://t.me/blackstrip_ru/637

Аватара пользователя
blackstrip
Админ
Сообщения: 1290
Зарегистрирован: Ср янв 02, 2008 1:42 pm
Откуда: Подольск
Контактная информация:

Re: PaintCAD Mobile - журнал разработки

Сообщение blackstrip » Сб ноя 08, 2025 1:47 pm

Следующий модуль с графическим интерфейсом - Moving:

Изображение

Ревизия окна Moving

Это окно используется чтобы указывать куда вставить рисунок (Вставить, Спецвставка, Сдвиг, Дубликат).

Управление:
Кнопки "1"-"9" кроме "5" - двигать вставляемый рисунок
Кнопка "Звездочка" - показать/скрыть вставляемый объект (чтоб посмотреть что будет под ним когда вставим, например, если вставляем Спецвставкой с полупрозрачностью)
Кнопка "Взять трубку" - включить/выключить показ текста (если он мешает смотреть)
Левый софт - Назад
Правый софт - Ок

Выглядит до масштабирования вот так:

Изображение

Сдвинем текст на сдвиги в виртуальных пикселях. На звездочку сделаем такой же режим прицеливания как при вставке текста в модуле AddText ранее (показ зоны 11x11 пикселей в левом нижнем углу экрана и полноэкранную крестовину на рисунке). А на решетку вместо звездочки поставим "показать/скрыть вставляемый объект".

При включенном по звездочке прицеливании будем скрывать подпись левой софт-клавиши "Назад".

В этом окне, в отличие от AddText, "курсор" может уезжать за границы рисунка, на который вставляем буфер. В области 11x11 в этом случае курсор рисуется полупрозрачным красным (потому что выехал за границы области выделения).

Еще в этом окне если рисунок больше экрана - вид переключается на один из 4 углов изображения. Например, двигаем изображение вниз-вправо - курсор в правом нижнем углу вставляемого изображения и следим чтобы он подъехал в нужное место. Дальше, например, двигаем вверх-влево - курсор перескакивает на левый верхний угол вставляемого изображения, следим за этим углом.

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

Тест доработанного окошка Moving:

Делаем изображение 320x320 с градиентом.

Изображение

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

Изображение

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

Изображение

Была мысль сделать не 4, а 8 положений курсора (еще справа вставляемого объекта и по его вертикали в центре, слева и по вертикали в центре, сверху и по горизонтали в центре, снизу и по горизонтали в центре). Но тогда будет неудобно подкатывать угол, например, сначала по диагонали вправо-вниз, а потом еще чуть-чуть вправо (когда положений 4, как сейчас, то это можно сделать, спокойно наблюдая за углом, т.к. мы только вправо или только вниз двигаемся в ту же сторону, в которую двигались по диагонали вправо-вниз).

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

Тесты на всех телефонах не нужны, т.к. код почти такой же, как в AddText, в котором уже тестировали область 11x11.

После доработки каждого окошка теперь APK и JAR выкладываются в телеграм ( https://t.me/blackstrip_ru ), пусть там лежат все эти сыроватые версии, чтоб если последняя кривая вдруг слишком - можно было откатиться к предыдущей, просто скачав ее повыше в телеграм-канале.

APK: https://t.me/blackstrip_ru/643
JAR: https://t.me/blackstrip_ru/644

Аватара пользователя
blackstrip
Админ
Сообщения: 1290
Зарегистрирован: Ср янв 02, 2008 1:42 pm
Откуда: Подольск
Контактная информация:

Re: PaintCAD Mobile - журнал разработки

Сообщение blackstrip » Сб ноя 08, 2025 9:31 pm

Следующий модуль с графическим интерфейсом - MsgBox:

Изображение

Ревизия окна MsgBox

Модуль не имеет собственной процедуры отрисовки, но имеет метод создания окон сообщений и метод их отрисовки в любом другом окне. Другие окна если хотят вывести сообщение - создают в модуле MsgBox новое окно сообщения (информационное с кнопкой "Ок", вопросительное с двумя вариантами на выбор и т.д.) и потом просят модуль MsgBox отрисовать его у себя. Обрабатывают нажатия на софт-клавиши и реакции на них уже сами окна.

Выглядит MsgBox сейчас вот так:

Изображение

Просто сдвигаем все на виртуальные пиксели вместо реальных. Всё встает на места.

Изображение

Изображение

Изображение

Окно поддерживает до 5 строк сообщения и еще строку в заголовке (обычно там пояснение или вопрос). 5 строк + строка заголовка + строка подписей к софт-клавишам всегда влезут на экран, т.к. на андроиде шрифт рассчитывается так, чтоб влезло 9-10 строк в любом случае. А на яве тоже все экраны вмещают 7 строк. Поэтому можно не проверять это окно на других телефонах.

Аватара пользователя
blackstrip
Админ
Сообщения: 1290
Зарегистрирован: Ср янв 02, 2008 1:42 pm
Откуда: Подольск
Контактная информация:

Re: PaintCAD Mobile - журнал разработки

Сообщение blackstrip » Вс ноя 09, 2025 12:23 pm

Дальше идет модуль NewFile:

Изображение

Ревизия окна NewFile

Окно с двумя полями для ввода чисел, сначала использовалось для ввода ширины/высоты рисунка при создании нового файла, поэтому и называется NewFile. Используется при указании размера новой картинки, максимального размера картинок в сессии, размера фото при съемке, размера холста/растра и др.

Управление:
Кнопки ДжойВверх/ДжойВниз - выбрать первое или второе поле для ввода размера
Кнопки 0-9 - ввести в первое или второе поле (смотря какое выбрано) еще одну цифру в конец числа
Кнопки ДжойВлево/ДжойВправо - уменьшить/увеличить число на 1 в первом или втором поле (смотря какое выбрано)
Кнопка "звездочка" - включить режим "Сохранить пропорции", запомнить пропорции между первым и вторым числом (шириной и высотой), чтобы потом при изменении одного поля пропорционально изменялось и другое
Кнопка Джойстик - выбрать размер с экран телефона
Левый софт - назад/отменить
Правый софт - выбрать введенный размер
Нажатие пальцем на сенсорном экране на одно из полей - выбирает его для ввода.

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

Изображение

Изображение

Делаем смещения элементов на виртуальные пиксели вместо реальных.

Эта "скоба" справа от полей ширины/высоты, показывающая что режим "сохранить пропорции" включен, раньше была из одной линии вроде бы. Потом на более крупных экранах была сделана из двух удвоенных линий. Но сейчас и ее на огромном экране не видно. Т.к. теперь есть виртуальные пиксели, которые всегда достаточно толстые на любом экране, то нарисуем эту скобу просто в виде "]" толщиной один виртуальный пиксель.

И она, почему-то, смещена куда-то вниз. Сделаем чтобы она точно указывала на поля с числами ширины/высоты.

Получилось так:

Изображение

Изображение

Исправление масштабирования значков

Попробовал запустить паинткад на одной древней андроид-консоли Exeq Ray с физическими кнопками. Экран 800x480. За вычетом нижней панели паинткаду остается 800x432.

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

Изображение

Изображение

Изображение

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

Но может быть просто длинный узкий экран.

Теперь в код масштабирования этих значков добавлена завязка на высоту экрана тоже)

Получилось:

Изображение

Изображение

Изображение

Паинткад теперь масштабирует значки так, чтобы они влезли в экран 3:4 (а ля сименсовский 132x176). Если оттяпать от экрана фрагмент 3:4 и стащить туда все инструменты, например, то как раз получается что такого размера хватит и увеличивать их не надо дальше.

Изображение

Аватара пользователя
blackstrip
Админ
Сообщения: 1290
Зарегистрирован: Ср янв 02, 2008 1:42 pm
Откуда: Подольск
Контактная информация:

Re: PaintCAD Mobile - журнал разработки

Сообщение blackstrip » Вс ноя 09, 2025 7:53 pm

Следующий идет модуль OpenFile - это интерфейс в виде формы, графики там нет.

После него идет Options:

Изображение

Ревизия окна Options

Окно Options - это разнобразные меню в окошке. Например, главное меню (которое по кнопке "0" в главном окне) или меню команд (которое по ДжойВправо в главном окне).

Сейчас это окно выглядит так в режиме главного меню (с кучей подменю, переключаемых по ДжойВлево/ДжойВправо) и обычного меню (просто один список):

Изображение

Изображение

Разложим по вертикали элементы так:
- 3 виртуальных пикселя зазор,
- заголовок окна (высота жирного шрифта),
- 1 виртуальный пиксель зазор,
- вариативно: если это главное меню, то тут свичбокс (выбор подменю главного меню) + 1 виртуальный пиксель зазор
- список (состоящий из 1 виртуального пикселя окантовки, N пунктов списка, и 1 виртуального пикселя окантовки в конце)
- 1 виртуальный пиксель зазор,
- панель софтклавиш

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

Получилось вот так:

Изображение

Изображение

Аватара пользователя
blackstrip
Админ
Сообщения: 1290
Зарегистрирован: Ср янв 02, 2008 1:42 pm
Откуда: Подольск
Контактная информация:

Re: PaintCAD Mobile - журнал разработки

Сообщение blackstrip » Пн ноя 10, 2025 9:05 pm

Вернемся к модулю AddText

Оказывается, там курсор может тоже, как в модуле Moving, выезжать за границы рисунка (вместе с вставляемым текстом). Но при включенном по "*" прицеливании паинткад пытается узнать цвет под курсором, чтоб нарисовать на области 11x11 рамку курсора нужного цвета (противоположного цвету под курсором).

За границей рисунка никаких цветов нет. И все сбивается. Теперь исправлено

Масштабируем дальше

Изображение

Следующий идет модуль PaintCAD - это главный модуль, вызывающий стартовый экран Loading. Там нет графического интерфейса.

Потом идет Palete (от слова Palette - палитра) - окошко палитры, спектрального подбора и вызова модуля EditColor с RGB-выбором цветов.

Ревизия окна Palete

Сейчас окно в разных режимах выглядит и работает так:

Окно палитры цветов (256 ячеек в виде 16x16 прямоугольников):

Изображение

Красный прямоугольник-курсор - это Передний Цвет (ПЦ), он же Foreground Color (FC).
Синий прямоугольник-курсор - это Задний Цвет (ЗЦ), он же Background Color (BC).

Внизу на панели софт-клавиш по центру написано какой цвет выбираем. Нажатие на Джойстик или ДжойВверх переключает его между ПЦ и ЗЦ.

В 8-битном режиме кнопка ДжойВправо включает показ в сетке используемых цветов (они становятся заполненными наполовину, и по бокам рисуются две черные стороны прозрачной "банки" с цветом, как будто краска немного истрачена и ее осталось меньше чем полная банка).

Вот на мелком экране в новом 8-битном рисунке белый "использованный цвет" с границами банки:

Изображение

Сделаем сверху под заголовком зазор 1 виртуальный пиксель, снизу над панель софт-клавиш тоже зазор 1 виртуальный пиксель, остальное поделим на 16 ячеек. Если не делится целочисленно - будем стягивать ячейки вверх (внизу останется пустое место).

Слева и справа сделаем зазоры 3 виртуальных пикселя, остальное поделим на 16. Если целочисленно не будет делить - будем центрировать это сетку цветов по горизонтали.

Каждая ячейка будет окантована либо рамкой цвета подложки (окна) толщиной 1 виртуальный пиксель либо цветом красного/синего курсора ПЦ/ЗЦ толщиной 1 виртуальный пиксель.

Получаем на большом экране с толщиной виртуального пикселя с 9 реальных пикселей:

Изображение

Получаем на сименсе с экраном 132х176 и толщиной виртуального пикселя с 1 реальный пиксель:

Изображение

Сделаем ячейки пошире, а зазоры между ячейками не 2 виртуальных пикселя, а только 1.

Получаем на большом экране:

Изображение

На сименсовском мелком экране:

Изображение

Так уже лучше. Теперь насчет функции "Используемые цвета" - в 8-битном режиме по ДжойВправо помечаются те цвета, которые использованы на текущем рисунке в паинткаде.

Нарисуем черно-белый градиент. Из uni-палитры (при включенной в главном окне опции ДжойВправо - Адаптация - Точная) выбираются близкие к серым цвета и смешиваются.

Изображение

Включаем "Использованные цвета" по ДжойВправо в окне палитры - и нарисуем эти же полупустые банки, только раньше они были пустые на треть - а теперь нарисуем их пустыми наполовину, виднее будет. Стенки будут черные толщиной с один виртуальный пиксель. Получается:

Изображение

Эти же цвета на мелком сименсовском экране:

Изображение

Изображение

Теперь "Используемые цвета" по ДжойВправо в окне Палитры работают с масштабированием.

Окно спектрального подбора цветов:

Сейчас оно такое:

Изображение

На сименсе на мелком экране:

Изображение

Разложим все спектры на экране так:
- 3 виртуальных пикселя
- заголовок окна
- 1 виртуальный пиксель
- оставшаяся до панели софт-клавиш область с тремя спектрами
- панель софт-клавиш

Оставшуюся до панели софт-клавиш область нарисуем так - поделим ее на 3 ровных части, в каждой из частей рисуем:
- стрелку ПЦ высотой 4 виртуальных пикселя
- спектр
- стрелку ЗЦ высотой 4 виртуальных пикселя
- зазор высотой 1 виртуальный пиксель

Последний зазор в 1 виртуальный пиксель последней третьей части как раз отделит всё от панели софт-клавиш на этот 1 виртуальный пиксель.

Справа вверху две строчки если выбираем спектр+яркость или одна строчка если выбираем серый оттенок.

Справа внизу две ячейки цветов высотой с высоту шрифта. И отделим из друг от друга на 1 виртуальный пиксель.

Получаем на большом экране:

Изображение

И на мелком экране сименса:

Изображение

И уже ранее отмасштабированное окошко EditColor, вызываемое из окна палитры цветов по левому софту ("RGB"):

Изображение

Его трогать не будем, т.к. это вообще другой модуль, да и тут уже все ок.

Окошки сетки и спектрального подбора сложные, поэтому проверим их на всех тестовых телефонах и эмуляторах.

Проверка окна Palete на тестовых телефонах

Смотрим одно окошко сетки и одно окошко спектрального подбора в состоянии по умолчанию (сразу после вызова на новом рисунке).

1 - Android 2.3.3 - Samsung Galaxy Ace

Изображение

Изображение

2 - Android 4.2 - RugGear RG310

Изображение

Изображение

3 - Android (Mocor) 4.4.4 - Joy's S15

Изображение

Изображение

4 - Android 9 - Soyes XS13

Изображение

Изображение

5 - Android 12 - Xiaomi Duoqin F22 Pro

Изображение

Изображение

6 - Android 15 - Xiaomi Redmi Turbo 3 (Poco F6)

Изображение

Изображение

7 - Java 2 Microedition - Nokia N90

Изображение

Изображение

8 - Java 2 Microedition - Nokia 7900 Prism

Изображение

Изображение

9 - Java 2 Microedition - Siemens SL75 (эмулятор)

Изображение

Изображение

10 - Java 2 Microedition - Benq-Siemens EL71 (эмулятор)

Изображение

Изображение

На всех телефонах ничего не налезает никуда. Все ок.

Ответить

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и 2 гостя