Статьи

Класс Actionscript для создания QR-кодов


Уважаемый читатель!

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

В Интернете есть большие ресурсы для создания QR-кодов и сохранения их на вашем компьютере для последующего использования. Тем не менее, будучи разработчиком, я хотел что-то, с чем я мог бы поиграть и включить в свои собственные приложения. Проблема в том, что генерирование QR-кода не является тривиальной вещью. К счастью для нас, Google уже выполнил сложную часть, и все, что мне действительно нужно, — это обернуть их API в класс, и я могу использовать это в своих собственных приложениях.

Что нужно для начала

Если вы хотите создавать QR-коды, вы должны уметь делать две вещи, создавать их и читать их. Так как этот пост посвящен их созданию, я оставлю вам их чтение. Если у вас есть смартфон, вероятно, есть хорошее приложение для проверки вашей работы. Для ОС Android я использую сканер BarCode .

Вот и все. Все, что вам нужно, это способ проверить свою работу. Google делает тяжелую работу по созданию графики, и приведенный ниже код предоставляет вам удобную оболочку, позволяющую включать ее в приложения Flash Builder 4.

Весёлая часть

Хорошо, давайте разберем код. Это один из моих первых компонентов Flex, который я достаточно уверен, чтобы выпустить. Тем не менее, я приветствую любые комментарии или критику в отношении класса.

Если вы еще этого не сделали, перейдите на страницу Google Chart API на QR-кодах . Google свел это к основам, 3 обязательным параметрам и двум необязательным. Сердце класса объединяет эти параметры и вызывает API. Он берет изображение, которое он возвращает, и помещает его в форму, которую приложения Flex могут изменить.

Планирование всех событий

[Event(name="imageCreated", type="ImageCreatedEvent")]
[Event(name="imageFailed", type="ImageFailedEvent")]

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

Код для событий находится ниже, после основного класса. ImageFailedEvent является просто подклассом FaultEvent и служит только маркером, который может быть захвачен отдельно.

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

BINDABLEs

[Bindable] public var qualityArray:ArrayCollection = new ArrayCollection(["L","M","Q","H"]);
[Bindable] public var marginArray:ArrayCollection = new ArrayCollection([1,2,3,4,10,40]);

Из всех имеющихся у нас свойств только два являются связываемыми, два массива данных, которые определяют приемлемые параметры для исправления ошибок и поля.

Все остальные параметры имеют разумные значения по умолчанию, но при использовании класса нет никаких оснований делать их привязываемыми.

Суть дела

var loader:Loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, imageComplete);
loader.load(request);

Сердцем класса является метод createImage (). Чтобы использовать класс, вы создаете его экземпляр, устанавливаете необходимые свойства и затем вызываете createImage (). В рамках этого метода первое, что мы делаем, это проверка параметров. Убедитесь, что мы дали изображению правильную высоту и ширину, и нам действительно есть, что кодировать. Как только мы сможем сделать разумный вызов API, мы настроим вызов, сделаем его и обработаем результаты.


[
Примечание: QR-коды могут хранить различную информацию. На приведенном выше простом тексте. Все, что может быть представлено в виде текста, может быть закодировано.
ZXingбиблиотека может интерпретировать несколько различных типов данных, а приложение для Android позволит вам действовать с ними соответствующим образом. Если содержимое начинается с mailto: тогда приложение спросит меня, хочу ли я отправить электронное письмо этому человеку. Если он начинается с http: тогда приложение спросит меня, хочу ли я открыть его в браузере. Точно так же, если он начинается с BEGIN VCARD: тогда он позволит мне сохранить полученный VCARD в моих контактах. Ваше приложение, скорее всего, будет поддерживать аналогичные функции. В эталонном приложении, которое я создал для тестирования QRCode.as, я разрешаю кодировать текст, электронные письма, URL-адреса и VCARDS. Однако это связано со спецификацией QR Code. Спецификация не предписывает форматы, только максимумы для различных типов данных (числовые, буквенно-цифровые, двоичные и т. Д.), Которые будут сохранены.]

Еще в феврале я написал пост о динамической загрузке изображений из Интернета . В нем я говорил о том, что вызов API, который не возвращает XML или JSON, не так прост, как это может быть во Flex. Я использовал методы (и, вероятно, код), которые я отображал в этом посте, для вызова API Google Chart. Я не буду перефразировать предыдущий пост, вы можете просмотреть его как досуг. По своей сути это вызов import flash.display.Loader для загрузки содержимого из Интернета.

У createImage () есть одна новая функция отладка. Если вы установите debug = true, вы получите предупреждение о том, что параметры передаются в API Google. Я большой сторонник того, чтобы дать разработчикам возможность увидеть, что происходит, без необходимости взламывать код. Если у вас установлен и работает Чарльз, вы можете увидеть, что вызов действительно выполняется, однако мне проще включить в код отладку и предоставить разработчикам возможность выбора. Темная сторона этого заключается в том, что разработчики имеют возможность снимать себя в еде таким же образом. Более одного разработчика оставили отладку включенной при выпуске своего кода.

Имея дело с последствиями

Поскольку Flex асинхронный, у нас должен быть метод для работы с изображением после выполнения вызова API. imageComplete () — обработчик для события COMPLETE. В нем мы устанавливаем высоту и ширину фактического изображения, а также данные самого изображения. Затем мы отправляем событие imageComplete, чтобы основная программа могла что-то сделать с изображением.

Завершение

Вот и все для класса. Чтобы использовать его, просто создайте экземпляр, установите параметры и запустите createImage (). Потому что мы говорим с API в Google, это работает только с приложениями AIR. Если вам нужно приложение Flash, которое запускается из вашего собственного домена, чтобы иметь возможность использовать QRCode.as, вам придется настроить проект на своем сервере, чтобы прокси-вызов Google. (Тривиально, но выходит за рамки того, что мы обсуждаем здесь.)

До следующего раза,
я <3 | <
= C =

Код

/*
* Instantiate the object
*/
var qrCode:QRCode = new QRCode();

/*
* Add our event listeners
*/
qrCode.addEventListener('imageCreated',this.displayImage);
qrCode.addEventListener('imageFailed',this.cannotDisplayImage);


/*
* Setup for the call
*/
qrCode.width = parseInt(imageWidth.text);
qrCode.height = parseInt(imageHeight.text);
qrCode.margin = margin.selectedIndex;
qrCode.errorCorrectionLevel = errorCorrectionLevel.selectedIndex;
qrCode.content = contentToEncode;
qrCode.imageType = grpImageType.selectedValue.toString();

/*
* make the call
*/
qrCode.createImage();
/**
*
* http://code.google.com/apis/chart/docs/gallery/qr_codes.html
*/
package
{
[Event(name="imageCreated", type="ImageCreatedEvent")]
[Event(name="imageFailed", type="ImageFailedEvent")]

public class QRCode
{
import flash.display.BitmapData;
import flash.display.Loader;
import flash.display.LoaderInfo;
import flash.net.FileReference;
import flash.net.URLRequest;
import flash.net.URLVariables;
import flash.utils.ByteArray;

import mx.collections.ArrayCollection;
import mx.controls.Alert;
import mx.controls.Image;
import mx.graphics.codec.JPEGEncoder;
import mx.graphics.codec.PNGEncoder;
import mx.rpc.events.FaultEvent;
import mx.rpc.events.ResultEvent;


[Bindable] public var qualityArray:ArrayCollection = new ArrayCollection(["L","M","Q","H"]);
[Bindable] public var marginArray:ArrayCollection = new ArrayCollection([1,2,3,4,10,40]);

public var height:int = 150;
public var width:int = 150;

public var content:String = "";
public var debug:Boolean = false;
public var errorCorrectionLevel:int = 0;
public var imageType:String = 'PNG';

public var margin:int = 0;

protected var _image:Image = new Image();
protected var apiUrl:String = 'http://chart.apis.google.com/chart';

public function QRCode()
{
/*
* cht=qr
* chs=<width>x<height>
* chl=<data>
* chd
* choe=<output_encoding>
* chld=<error_correction_level>|<margin>
*
* Notes:
* changing the quality needs to make sure the max number of chs hasn't been exceeded.
* Add Types
*/
}



public function createImage():void
{
// do a property check and throw appropriate error for missing properties like content to encode
if (this.width<1) {
dispatchEvent(new ImageFailedEvent(ImageFailedEvent.IMAGE_FAILED,false,false));
return;
}
if (this.height<1) {
dispatchEvent(new ImageFailedEvent(ImageFailedEvent.IMAGE_FAILED,false,false));
return;
}
if (this.content.length<1) {
dispatchEvent(new ImageFailedEvent(ImageFailedEvent.IMAGE_FAILED,false,false));
return;
}

var params:URLVariables = new URLVariables();
params.cht = 'qr';
params.chs = this.height +'x'+ this.width;
params.chl = this.content;
params.chld = qualityArray[errorCorrectionLevel]+"|"+marginArray[margin];

var request:URLRequest = new URLRequest(apiUrl);
request.method="POST";
request.data = params;

// DEBUGGING
if (this.debug) {
var a:String = apiUrl +
'?cht='+params.cht
+"&chs="+params.chs
+"&chld="+params.chld
+"&chl="+params.chl
Alert.show(a);
} // if (this.debug)

var loader:Loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, imageComplete);
loader.load(request);
} // protected function createImage():void


protected function imageComplete(event:Event):void
{
var loader:Loader = (event.target as LoaderInfo).loader;
_image.data = loader.content;
_image.width = loader.width;
_image.height = loader.height;
dispatchEvent(new ImageCreatedEvent(ImageCreatedEvent.IMAGE_CREATED,false,false,_image));
return;
} // protected function displayImage(event:Event):void

protected function cannotDisplayImage(event:FaultEvent):void
{
dispatchEvent(new ImageFailedEvent(ImageFailedEvent.IMAGE_FAILED,false,false));
} // protected function cannotDisplayImage(event:FaultEvent):void

public function getImage():Image{
return this._image;
}

}
}

ImageCreatedEvent.as

package 
{
import flash.events.Event;
import mx.controls.Image;

public class ImageCreatedEvent extends Event
{
public static const IMAGE_CREATED:String = 'imageCreated';
protected var _image:Image;

public function ImageCreatedEvent(type:String, bubbles:Boolean=false, cancelable:Boolean=false, thisImage:Image=null)
{
super(type, bubbles, cancelable);
_image = thisImage;
return;
}

override public function clone():Event
{
return new ImageCreatedEvent(type, bubbles, cancelable, _image);
}

}
}

ImageFailedEvent.as

package
{
import mx.rpc.events.FaultEvent;

public class ImageFailedEvent extends FaultEvent
{
public static const IMAGE_FAILED:String = 'imageFailed';

public function ImageFailedEvent(type:String, bubbles:Boolean=false, cancelable:Boolean=false)
{
super(type, bubbles, cancelable);
}

}
}