пятница, 26 декабря 2014 г.

Как нарисовать крестик в середине TImage


Суть даже не в крестике, а как рисовать в нужном месте. Координаты? Да, слыхал. И рисовал как бы даже... Но стоило с MSWindows перейти на Android - и "Шеф, всё пропало, все пропало!"(© Козодоев Г.П.)

Вот пример, замечательно работающий в Винде, но не работающий на моём Nexus 4:
const
  Ident = 10;
... 
      DrawLine( //Horizontal
        TPointF.Create( Ident, ( FRawBitmap.Height / 2 ) ),
        TPointF.Create( FRawBitmap.Width - Ident, FRawBitmap.Height / 2 ), 0.5 );
      DrawLine(  //Vertical
        TPointF.Create( FRawBitmap.Width / 2, Ident ),
        TPointF.Create( FRawBitmap.Width / 2, FRawBitmap.Height - Ident ), 0.5 );

Вот на компе рисует, а в телефоне - нет!

Отладчик говорит, что всё нормально - методы проходят. А сдвиг координат подсказал, что действительно - всё рисуется, но где-то за пределами картинки. Гром и молния! Как может что-то рисоваться за пределами, если мы рисуем в точке с координатами меньше пределов?!

Посмотрев в FMX.Objects как рисует TImage, я среди прочего заметил странную такую штуку - FScreenScale. Не "паблик", не свойство, а чисто "для себя". И берётся оно из свойства TControl.Scene:IScene. А Scene - это, как можно легко заметить, интерфейс, у которого есть даже не свойство SceneScale, а именно метод GetSceneScale. Мало того, интерфейс этот ещё может и отсутствовать, и тогда FScreenScale = 1.

Ещё есть у IScene функции расчёта координат экран-локаль, но они тут не работают, нужен именно  "Scale". Этот Скэйл у меня на ПК - 1, а на Нексусе - 2. Сама же Сцена есть и там, и там. Т.е. вроде бы получается, что проверять её наличие не обязательно (но я себе проверку всё же скопипастил), а нужно взять коэффициент и разделить координаты на него.

Поскольку я много делить не люблю, я разделил один раз, а потом умножаю:
var
  FScreenScale : Single;
... 
  if Assigned(Scene) then
    FScreenScale := 1 / Scene.GetSceneScale
  else
    FScreenScale := 1.0;
... 
      DrawLine( //Horizontal
        TPointF.Create( FScreenScale * Ident, FScreenScale * ( FRawBitmap.Height / 2 ) ),
        TPointF.Create( FScreenScale * ( FRawBitmap.Width - Ident ), FScreenScale * FRawBitmap.Height / 2 ), 0.5 );
      DrawLine(  //Vertical
        TPointF.Create( FScreenScale * FRawBitmap.Width / 2, FScreenScale * Ident ),
        TPointF.Create( FScreenScale * FRawBitmap.Width / 2, FScreenScale * ( FRawBitmap.Height - Ident ) ), 0.5 );

Ну вот, теперь мой крестик ровно в середине рисунка.

- Погоди-ка, а если там всё в два раза больше, то попиксельно ничего не нарисуешь????
- Да нарисуешь, координаты-то не целые!

Только зачем такие странности? Чтобы понять это, как сказал Ярослав Бровин "В общем ничего кроме стандартных знаний линейной алгебры здесь не требуется". И мне остаётся стыдливо воспринимать эти обстоятельства как данность, данную нам свыше.

четверг, 18 декабря 2014 г.

Как сканировать штрих-код


Конечно, баркоды как объект манипуляций программными средствами для меня - не новость, мы эти коды на ПК сто лет в обед как программировали - и печатали, и считывали. А что такого? Вставляешь в разъём клавиатуры считыватель, и вот - оно уже и считывается. А как быть с телефоном или планшетом?

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

А что же делать, если вдруг нужно? Конечно, готовые компоненты искать. И желательно - бесплатные :)

Но пойдите на Torry - что там? Там компонентов для распознавания кодов - раз, и обчёлся.

Например, для FMX есть компонент от WINSOFT. Даже с возможностью перед покупкой закомпилить примерчик. Только он у меня не пошёл - на телефоне что-то с синтаксическим нераспознаванием пакета, а на планшете запускается, но умирает - какой-то  libzbar хочет или что-то в этом духе. Я бы подробнее почитал, но не сошёлся же свет на них клином - должно же быть такого добра  (тем более, что и не за бесплатно) - море! Но что-то море это мелкое какое-то...

Я даже и дот-нетов смотрел, и, поскольку мне для Андроида, смотрел, что джависты предлагают - на всё кидался, там может и мне что найдётся. Вот, например, Java4less предлагает за сотню убитых енотов с хвостиком на каждый тип кода (а их не два и не три) отдельный Delphi-компонент. И ещё полторы сотни просит за редистрибуцию! А вот демку скомпилить - не даёт!

Но, долго ли, коротко ли, вариант подходящий отыскался. Вы не поверите! - БЕСПЛАТНАЯ библиотека на сайте - (барабанная дробь) - кто бы мог подумать, кому это в голову только могло прийти?! - EMBARCADERO!!!! (та-дам!!!)

http://cc.embarcadero.com/Item/29811 Там штрих-коды и для Андроида, и для йОса. И плюс ещё там какие-то другие нативные штуки типа всплывающих сообщений Андроида и проверки наличия сетевого подключения. Сборничек небольшой. Небольшой, но в общем интересный.

Да, я стокамногабуков написал, чтобы только ссылку дать. Но я просто рад очень, чес-слово!

Правда, оказалось, что проект был сделан для XE5. Для XE6 пришлось пробежаться по uses и расставить для Android новый юнит Androidapi.Helpers, а старую енумерацию aeBecameActive надо было заменить на TApplicationEvent.BecameActive. И вот - у меня на телефоне (некоторые утверждают, что правильно говорить "в телефоне") уже новое приложение!

Однако, счастье всё ещё никак не давалось в руки так просто. Как только я нажимал на кнопку сканирования - телефон уходил в задумчивость и предлагал приложение остановить. Тоже и планшет. И я тогда пошёл под отладчиком. Странно, но под отладчиком на телефоне у меня даже появилось такое зелёное окошко с видом через видеокамеру телефона. И там даже хелп был, и всё говорило, что сейчас штрих-код считается. Но не считывалось ничего. А казалось, что счастье уже было так близко, так возможно!

И вот - О, Моя Врождённая Чудо-Наблюдательность! - я обнаружил, что требуется пакет "com.google.zxing.client.android.SCAN". Ага! По этому поводу интернет делится на 2 лагеря: одни рассказывают, как пришить этот пакет в приложение, а другие, коих, как мне показалось, большинство - говорят, что не надо ни в коем случае пришивать, т.к. пакет обновляется часто, и лучше всегда отдельно скачивать свежачок - он же бесплатный!

Я всё понял! Я пошёл в АппСторр... Ой! Я зашёл в Гугл-Плэй, задал в поиске zxing и установил его. У меня появилось приложение, которое чего-то сканирует. Так вот, мой (ну, я же тоже его дописывал) MobileWrapers сразу же повеселел и стал ловко пикать совсем уже не зелёным, а полупрозрачным окошком с красивой красной полоской для прицеливания. Ура!

Теперь проблема сканирования штрих-кодов для Андроид-приложений - уже не проблема. И я верю, что для йОса тоже уже всё готово. Но я пока не компилил - может, там тоже что-то с юнитами поменялось со времён XE5.

Для желающих подкрученные мной исходники здесь - https://drive.google.com/file/d/0B8ZLqV359_X5R1ZKS3ktdF9FLXc/view?usp=sharing

Спасибо

 Fernando Rizzato!