domingo, 28 de novembro de 2010

StageVideo

Foi apresentado no Max Sneaks 2010 pelo saudoso Tinic Uro, um dos muitos melhoramentos de performances que estão sendo implementados no Flash Player. Vale a pena dar uma olhada e ficar impressionado. Isso vai melhorar e muito nossa vida na hora de criar um site com BG em vídeo, coisa que tem se tornado bastante comum.

domingo, 7 de junho de 2009

Operações binárias

Ultimamente tenho me deparado com muitos trechos de códigos que utilizam operações binárias, como chaveamento de multiplexador, extração de RGB a partir de um inteiro ou hexadecimal, bitshift para controlar LED Matrix, etc... E finalmente dei aquela estuda, agora vai ai um post sobre o que resultou o estudo.

Obs.: Os trechos de códigos deste post foram escritos em ActionScript, mas pode ser aplicado a C, C++, Java, Processing, PHP, entre outras linguagens.



Introdução
• Bit Shift
   • Operador >> (bitwise right shift)
   • Operador << (bitwise left shift)
• Operações Bitwise
   • Operador & (bitwise AND)
   • Operador | (bitwise OR)
   • Operador ^ (bitwise XOR)
   • Operador ~ (bitwise NOT)
• Exemplos
   • Extraindo o RGB de uma cor
   • Chaveando multiplexador 4051
 


Introdução
Um operador binário, como o nome sugere, é um operador que trabalha com a representação binária do número, e como normalmente não sabemos a representação binária dos números de cabeça, vamos utilizar a tabela abaixo:

 -----------------------
| BIN | DEC | HEX |
|-----------------------|
| 1 | 1 | 1 |
| 10 | 2 | 2 |
| 11 | 3 | 3 |
| 100 | 4 | 4 |
| 101 | 5 | 5 |
| 110 | 6 | 6 |
| 111 | 7 | 7 |
| 1000 | 8 | 8 |
| 1001 | 9 | 9 |
| 1010 | 10 | A |
| 1011 | 11 | B |
| 1100 | 12 | C |
| 1101 | 13 | D |
| 1110 | 14 | E |
| 1111 | 15 | F |
| 10000 | 16 | 10 |
| 10001 | 17 | 11 |
| 10010 | 18 | 12 |
| 10011 | 19 | 13 |
| 10100 | 20 | 14 |
|-----------------------|
| 11111111 | 255 | FF |
-----------------------


A tabela lista os números de 1 à 20 e 255 em três bases diferentes:
• Binário (BIN)
• Decimal (DEC)
• Hexadecimal (HEX)

Analisando a tabela podemos concluir que 3d = 11b, 19d = 10011b (as letras d e b significam decimal e binário respectivamente). Lembrando que pode ser utilizada uma calculadora que opere em binário (como a do windows) ou uma alternativa de conversão de bases on-line como está: "Conversão de número binário".

Então vamos deslocar, escorregar, escovar alguns bits para entender melhor.


Operador >>
Deslocamento de bits para a direita (bitwise right shift)
trace(8 >> 1); // 4
trace(8 >> 2); // 2
trace(8 >> 3); // 1
trace(8 >> 4); // 0

Olhando os números na base decimal faz pouco sentido, ou talvez nenhum sentido, então passamos os números corretos para a base binária e tudo fica mais claro:
8d = 1000b (8 decimal é igual a 1000 em binário), então:
1000b >> 1 (deslocando uma casa para direita) temos o número:
100b que em decimal é 4(dê uma olhada na tabela).


Agora ficou fácil não? Vamos deslocar o número 13:
trace(13 >> 1); // 6
13 em binário é 1101, deslocando uma casa para a direita (ou removendo 1 bit), fica 110, e 110 é igual a 6 em decimal.



Operador <<
Deslocamento de bits para a esquerda (bitwise left shift)
trace(2 << 1); // 4
trace(2 << 2); // 8
trace(2 << 3); // 16

Agora é só seguir o mesmo raciocino já utilizando anteriormente.
Se 2 em base binária é igual a 10 e deslocarmos um bit para esquerda, vamos ganhar mais um zero, ficando com 100 que é igual a 4 em decimal.



Operador &
AND binário (bitwise AND)
O operador & compara bit a bit os números a sua direita e esquerda, por exemplo o resultado de 10 & 11 é 10:



1010
& 1011
------
1010

A comparação bit-a-bit somente retorna True (1) quando os bits comparados são iguais a 1, caso contrário retorna False (0). Formando assim um novo número.
Mais alguns exemplos para fortalecer:



|14 & 9|13 & 11|20 & 9|14 & 10|89 & 112|45 & 77|255 & 13|112 & 255|
| | | | | | | | |
| 1110 | 1101 | 10100| 1110 | 1011001| 101101| 11111111| 1110000|
|& 1001 |& 1011 |& 1001|& 1010 |& 1110000|& 1001101|& 1101|& 11111111|
| ---- | ---- | -----| ---- | -------| -------| --------| --------|
| 1000 | 1001 | 0| 1010 | 1010000| 1101| 1101| 1110000|
| 8d | 9d | 0d| 10d | 80d| 13d| 13d| 112d|


Operador |
OR binário (bitwise OR)
O operador | tem a mesma função do operador OR comum (||) só que atua bit-a-bit, assim como os outros operadores binários. Vejamos um exemplo:



1010
| 1011
------
1011

Se um dos bits comparados forem iguais a 1 a expressão retornará 1, caso os dois bits comparados forem iguais a 0, a expressão retorna 0. Agora vamos refazer o exemplo anterior trocando apenas o operador & (and binário) por | (or binário):



|14 | 9|13 | 11|20 | 9|14 | 10|89 | 112|45 | 77|255 | 13|112 | 255|
| | | | | | | | |
| 1110 | 1101 | 10100| 1110 | 1011001| 101101| 11111111| 1110000|
|| 1001 || 1011 || 1001|| 1010 || 1110000|| 1001101|| 1101|| 11111111|
| ---- | ---- | -----| ---- | -------| -------| --------| --------|
| 1111 | 1111 | 11101| 1110 | 1111001| 1101101| 11111111| 11111111|
| 15d | 15d | 29d| 14d | 121d| 109d| 255d| 255d|


Operador ^
OU exclusivo (bitwise XOR)
A letra X na frente do OR significa Exclusive (Exclusive OR). Isso quer dizer que este operador faz a comparação binária de dois números e resulta os bits que são diferentes. Por exemplos, quais são os bits diferentes entre os números 10 e 11?



1010
^ 1011
------
1

Vamos novamente trocar o operador do exemplo anterior para analisar os resultados:



|14 ^ 9|13 ^ 11|20 ^ 9|14 ^ 10|89 ^ 112|45 ^ 77|255 ^ 13|112 ^ 255|
| | | | | | | | |
| 1110 | 1101 | 10100| 1110 | 1011001| 101101| 11111111| 1110000|
|^ 1001 |^ 1011 |^ 1001|^ 1010 |^ 1110000|^ 1001101|^ 1101|^ 11111111|
| ---- | ---- | -----| ---- | -------| -------| --------| --------|
| 111 | 110 | 11101| 100 | 101001| 1100000| 11110010| 10001111|
| 7d | 6d | 29d| 4d | 41d| 96d| 242d| 143d|


Operador ~
Negação (bitwise NOT)
O operador NOT inverte o sinal e complementa em um.
Negando o número 168 (~168) teremos -169.


Alguns exemplos:
trace(~7); // -8
trace(~-7); // 6
trace(~14); // -15
trace(~13); // -14
trace(~255); // -256
trace(~112); // -113


 


Extraindo o RGB de uma cor
Sabendo que uma cor no formato RGB utiliza dois dígitos hexadecimais para definir quanto existe de Vermelho, Verde e Azul (respectivamente), formando cores como: Vermelho (FF0000), Cinza (C0C0C0), Laranja (FF9900), etc. Temos ai a possibilidade de gerar 16.581.375 de cores com este código, é só fazer a conta para conferir: 255 * 255 * 255 ou FF * FF * FF.
Vamos desmembrar um tom de azul (#347BB7) para saber quanto esta cor tem de Vermelho, Verde e Azul (o valor dos canais RGB).

// DEC: 3439543
// BIN: 1101000111101110110111
var color:uint = 0x347BB7;

var r:uint = (color >> 16) & 0xFF;
var g:uint = (color >> 8) & 0xFF;
var b:uint = color & 0xFF;

trace("Red:", r, "Green:", g, "Blue:", b);
// Red: 52 Green: 123 Blue: 183

Linha 5) Deslocando 16 bits para a direita temos:

1101000111101110110111 >> 16
= 110100 (DEC: 52)


Para o caso do vermelho não precisamos continuar a expressão (& 0xFF),
pois deslocando 16 bits para a direita já temos o resultado do vermelho,
mas se a cor estivesse no formato ARGB (Alpha Red Green Blue), seria necessário.

Linha 6) Deslocando 8 bits para conseguir o verde:

1101000111101110110111 >> 8
= 11010001111011 (DEC: 13435)


Só com o valor do deslocamentos não vamos conseguir a cor verde, então utilizamos o
operador & (AND) com o valor 255 (0xFF) para extrair a parte binária que nos interessa:

11010001111011 (DEC: 13435)
& 11111111 (DEC: 255, HEX: 0xFF)
--------------
01111011 (DEC: 123)


Linha 7) Para extrair o azul não precisamos deslocar bits e sim pegar os últimos 8 bits:

1101000111101110110111
& 11111111 (DEC: 255, HEX: 0xFF)
----------------------
10110111 (DEC: 183)


Agora voltando para o hexadecimal:
var r:uint = 52;
var g:uint = 123;
var b:uint = 183;
var color:uint = (r << 16) | (g << 8) | b;

trace(color.toString(16));
// 347bb7


Linha 4) Deslocando 16 bits para a esquerda do número 52 (Vermelho):

110100 << 16
= 1101000000000000000000


Deslocando 8 bits para a esquerda do número 123 (Verde):

1111011 << 8
= 111101100000000


Efetuando o OR (|) com o resultado das duas operações ((r << 16) | (g << 8)):

1101000000000000000000
| 111101100000000
----------------------
1101000111101100000000


Efetuando a última operação, o OR com o Azul (183)

1101000111101100000000
| 0000000000000010110111
----------------------
1101000111101110110111


O resultado agora ficou claro. O número 1101000111101110110111 (binário) é igual a 3439543 (decimal) e 347BB7 (hexadecimal).

 


Chaveando multiplexador 4051
A tarefa de chavear um Multiplexador / Demultiplexador (MUX / DEMUX) 4051 é muito parecida com a extração dos canais RGB de uma cor. Você só precisa Ligar ou Desligar três pinos de seleção (select pins) para que o circuito interprete o valor gerado e transmita a voltagem da entrada desejada.
Existe um gif animado do RogerCom muito didático que demonstra o funcionamento do CI 4051, gif animado CI 4051 aqui.
Por exemplo, para ler a entrada 3, precisamos desligar o pino de seleção 0, ligar o 1 e o 2, formando assim o número 011 (binário) que é igual a 3 em decimal. Veja no código (Escrito em Arduino / C++):

// Entrada desejada
int count = 3;

// Extração dos bits ativos
byte s0 = count & 0x1;
byte s1 = (count >> 1) & 0x1;
byte s2 = (count >> 2) & 0x1;

// Ligando ou desligando os pinos de seleção
digitalWrite(2, s0);
digitalWrite(3, s1);
digitalWrite(4, s2);



Conteúdo relacionado:
• Post original: http://blog.bsoares.com.br/flash/operacoes-binarias
Bitwise operation on Wikipedia
 

sexta-feira, 24 de abril de 2009

Boas práticas.


Estou ensaiando de postar aqui algo sobre boas prática a tempos, foi uma das primeiras ideias que tive, pois odeio quando pego um código de algum dev que nem identar o código identa. Enfim, até hoje, NADA. Eu com minha correria diária nunca consegui juntar tudo e postar aqui, hoje falando com o BSoares, ele mencionou um link de boas práticas, imensooo e muito útil, em 5 min vi que tenho mais a aprender sobre boas práticas do que imaginava, isso por que eu idento meu código hein! haha!

Divirtam-se:

http://opensource.adobe.com/wiki/display/flexsdk/Coding+Conventions

E aqui, para quem não sabe o que é identar ;-)

http://pt.wikipedia.org/wiki/Indenta%C3%A7%C3%A3o

Update:
Conversando com o Cássio, acabei conhecendo o blog dele e vendo que ele também postou algo sobre boas práticas. :)

http://blog.devlab.com.br/post/85041607/desenvolvimento-flash-voc-est-fazendo-tudo-errado

Aproveite e conheça o Blog dele, tem muita coisa boa! :D



Se você também souber de algum post ou materia online sobre boas práticas, deixa ai o link nos comentários para outros devs também terem acesso.

[]s!





Twitter Hardware (Arduino)

Twitter Hardware é um projeto que utiliza a placa Arduino e um Display LCD para exibir as mensagens do Twitter. Para que a Arduino tenha as mensagens escrevi um software em Adobe AIR / Flex, que se conecta ao Serial Proxy enviando o conteúdo para a Arduino.



Arduino:
/**
* Twitter Hardware
*
* @author Bruno Soares
* @link http://www.bsoares.com.br
* @language Arduino / C++
*/

// Includes
#include

// Defines
#define DEBUG_PIN 13

#define COMMAND_RIGHT 0
#define COMMAND_LEFT 1
#define QUANTITY_COMMANDS 2

#define ANALOG_PIN_COMMAND_RIGHT 0
#define ANALOG_PIN_COMMAND_LEFT 1
#define ANALOG_PIN_SPEED 2

#define MESSAGE_START 94 // 94 = ^
#define MESSAGE_END 126 // 126 = ~

#define SERIAL_BOUND 9600

#define LCD_LINES 2
#define LCD_COLUMNS 16

#define ANIMATE_CMD_WIDTH 4

// Global variables
unsigned long time;

// LiquidCrystal display with:
// rs on pin 12
// rw on pin 11
// enable on pin 2
// dbs 3, 4, 5, 6, 7, 8, 9, 10
LiquidCrystal lcd(12, 11, 2, 3, 4, 5, 6, 7, 8, 9, 10);

// Analog configuration
unsigned int analogCmd[QUANTITY_COMMANDS];
unsigned int analogSpeed = 0;

// Control commands
boolean changingSpeed = true;
boolean readingSerial = false;
boolean pressedCmd[QUANTITY_COMMANDS];
unsigned int lastSpeed = 0;

// Massages
char currentMessage[400] = "No messages.";
unsigned int currentMessageLenght;

// ------------------------------------------------------------------------ \\
// Program
void setup() {
Serial.begin(SERIAL_BOUND);
pinMode(DEBUG_PIN, OUTPUT);

smartDelay(10);
lastSpeed = analogSpeed;

presentation();
changingSpeed = false;
}

void loop() {

// Show current message
clearLcd();
writeLongTextInLcd(currentMessage);
smartDelay(applySpeed(7000));

}

void presentation() {
lcd.clear();
writeLongTextInLcd("Twitter Hardwareby Bruno Soares");
smartDelay(3000);
}

void refreshAnalogVars() {
analogCmd[COMMAND_RIGHT] = analogRead(ANALOG_PIN_COMMAND_RIGHT);
analogCmd[COMMAND_LEFT] = analogRead(ANALOG_PIN_COMMAND_LEFT);
analogSpeed = analogRead(ANALOG_PIN_SPEED);
}

// ------------------------------------------------------------------------ \\
// [INI] Commands
void detectCommand() {
unsigned int i = 0;
while (i < QUANTITY_COMMANDS) {
if (analogCmd[i] > 500 && !pressedCmd[i]) {
executeCommand(i);
}
i++;
}
}

void executeCommand(int command) {
pressedCmd[command] = true;
digitalWrite(DEBUG_PIN, 1);

if (command == 0) {
animateNext();
} else {
animatePrevious();
}

currentMessage[0] = 'L';
currentMessage[1] = 'o';
currentMessage[2] = 'a';
currentMessage[3] = 'd';
currentMessage[4] = 'i';
currentMessage[5] = 'n';
currentMessage[6] = 'g';
currentMessage[7] = '\0';
currentMessageLenght = 7;

Serial.print(command);

while (analogCmd[command] > 500) {
smartDelay(4);
}

pressedCmd[command] = false;
digitalWrite(DEBUG_PIN, 0);
}

void animateNext() {
for (unsigned int i = 0; i < LCD_COLUMNS + ANIMATE_CMD_WIDTH; i++) {
if (i < LCD_COLUMNS) {
lcd.setCursor(i, 0);
lcd.print(">");
lcd.setCursor(i, 1);
lcd.print(">");
}
delay(5);
if (i - ANIMATE_CMD_WIDTH >= 0) {
lcd.setCursor(i - ANIMATE_CMD_WIDTH, 0);
lcd.print(" ");
lcd.setCursor(i - ANIMATE_CMD_WIDTH, 1);
lcd.print(" ");
}
delay(30);
}
}

void animatePrevious() {
for (int i = LCD_COLUMNS; i >= -ANIMATE_CMD_WIDTH; i--) {
if (i >= 0 && i < LCD_COLUMNS) {
lcd.setCursor(i, 0);
lcd.print("<");
lcd.setCursor(i, 1);
lcd.print("<");
}
delay(5);
if (i + ANIMATE_CMD_WIDTH < LCD_COLUMNS && i + ANIMATE_CMD_WIDTH >= 0) {
lcd.setCursor(i + ANIMATE_CMD_WIDTH, 0);
lcd.print(" ");
lcd.setCursor(i + ANIMATE_CMD_WIDTH, 1);
lcd.print(" ");
}
delay(30);
}
}
// [END] Commands

// ------------------------------------------------------------------------ \\
// [INI] Messages
void detectSerialMessage() {
if (Serial.available() > 0 && !readingSerial) {
if (Serial.read() == MESSAGE_START) {
serialReadMessage();
}
}
}

void serialReadMessage() {
digitalWrite(DEBUG_PIN, 1);
readingSerial = true;
currentMessageLenght = 0;

iniReading:
if (Serial.available() > 0) {
unsigned int _char = Serial.read();
if (_char == MESSAGE_END) {
goto endReading;
} else {
currentMessage[currentMessageLenght++] = _char;
delay(2);
goto iniReading;
}
}
goto iniReading;

endReading:
currentMessage[currentMessageLenght] = '\0';
digitalWrite(DEBUG_PIN, 0);
readingSerial = false;
}
// [END] Messages

// ------------------------------------------------------------------------ \\
// [INI] LCD manipulation
void writeLongTextInLcd(char text[]) {
writeInit:
clearLcd();
unsigned int cml = currentMessageLenght;
int loops = -1;
unsigned int chars = 1;
while (text[loops++ + 1] != 0) {
if (chars == 17) {
lcd.setCursor(0, 1);
smartDelay(applySpeed(600));
if (cml != currentMessageLenght) goto writeInit;
} else if (chars == 33) {
smartDelay(applySpeed(3000));
clearLcd();
if (cml != currentMessageLenght) goto writeInit;
chars = 1;
}
lcd.print(text[loops]);
smartDelay(applySpeed(60));
if (cml != currentMessageLenght) goto writeInit;
chars++;
}
Serial.print(2);
}

void writeInLcd(char text[], int quantity) {
for (unsigned int i = 0; i < quantity; i++) {
if (text[i] == 0) {
do {
lcd.print(" ");
} while (i++ < quantity);
break;
} else {
lcd.print(text[i]);
}
}
delay(2);
//smartDelay(5);
}

void clearLcd() {
lcd.setCursor(0, 0);
smartDelay(5);
lcd.print(" ");
smartDelay(applySpeed(400));
lcd.setCursor(0, 1);
smartDelay(5);
lcd.print(" ");
lcd.setCursor(0, 0);
smartDelay(applySpeed(0));
}
// [END] LCD manipulation

// ------------------------------------------------------------------------ \\
// [INI] Speed
void detectChangeSpeed() {
if (changingSpeed) return;
if (!(lastSpeed < analogSpeed + 6 && lastSpeed > analogSpeed - 6)) {
showGraderSpeed();
}
}

void showGraderSpeed() {
changingSpeed = true;
digitalWrite(DEBUG_PIN, 1);
lcd.clear();
writeInLcd("Speed:", LCD_COLUMNS);

// Create display velocity
showSpeed:
for (unsigned int i = 0; i < 10; i++) {
int charsSpeed = map(analogSpeed, 0, 1023, 0, LCD_COLUMNS);
int percentSpeed = map(analogSpeed, 0, 1023, 0, 100);
char* percentString;
itoa(100 - percentSpeed, percentString, 10);
percentString = strcat(percentString, "%");
lcd.setCursor(7, 0);
writeInLcd(percentString, 4);
charsSpeed = LCD_COLUMNS - charsSpeed;
lcd.setCursor(0, 1);
for (unsigned int x = 1; x < LCD_COLUMNS + 1; x++) {
if (x <= charsSpeed) {
lcd.print(">");
} else {
lcd.print(" ");
}
}
lastSpeed = analogSpeed;
smartDelay(40);
}

// Verify
for (unsigned int i = 0; i < 10; i++) {
if (!(lastSpeed < analogSpeed + 6 && lastSpeed > analogSpeed - 6)) {
goto showSpeed;
}
smartDelay(40);
}

// Finalize
lcd.clear();
changingSpeed = false;
digitalWrite(DEBUG_PIN, 0);
}

long applySpeed (unsigned int value) {
return map(analogSpeed, 0, 1023, 0, value);
}

// [END] Speed

// ------------------------------------------------------------------------ \\
// [INI] Milliseconds controller
void smartDelay(int milliseconds) {
if (milliseconds < 2) {
noDelayFunctions();
delay(milliseconds);
return;
}
do {
delay(1);
milliseconds -= noDelayFunctions();
milliseconds -= 1;
} while (milliseconds > 0);
}

int noDelayFunctions() {
time = millis();

// [INI] No delay functions here
refreshAnalogVars();
detectChangeSpeed();
detectCommand();
detectSerialMessage();
// [END] No delay functions here

return millis() - time;
}
// [END] Milliseconds controller



ActionScript (usando Serialproxy):
package br.com.bsoares.air.airtwitterhardware
{
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.events.IOErrorEvent;
import flash.events.ProgressEvent;
import flash.net.Socket;

/**
* Message Control
* Control messages between the Arduino and in AIR
* Application using Serial Proxy.
*
* @author Bruno Soares
* @link http://www.bsoares.com.br
*/
public class MessageControl extends EventDispatcher
{
// Properties
private var _host:String;
private var _port:uint;
private var _socket:Socket;
private var _messages:Array;
private var _currentMessage:uint;
private static var _instance:MessageControl;
private static var _allowInstantiation:Boolean = false;

// Constructor
public function MessageControl()
{
if (!_allowInstantiation)
throw new Error("Use instance property (this is a Singleton Class).");
init();
}

// Logic
private function init():void
{
_host = "127.0.0.1";
// COM2
_port = 5332;
_messages = [ ];
_currentMessage = 0;
socketConnect();
}

private function socketConnect():void
{
_socket = new Socket();
_socket.addEventListener(ProgressEvent.SOCKET_DATA, onSocketData);
_socket.addEventListener(Event.CLOSE, onSocketClose);
_socket.addEventListener(IOErrorEvent.IO_ERROR, onSocketIoError);
_socket.connect(_host, _port);
}

private function processData(data:String):void
{
trace("Arduino command:", data);
switch (true)
{
// Send next message
case data == "2" || data == "0":
{
sendNextMessage();
break;
}
// Send previous message
case data == "1":
{
sendPreviousMessage();
break;
}
}
}

private function sendMessage(message:String):void
{
if (message == null || message == "")
return;

trace("Message:", message);

// MESSAGE_START
_socket.writeUTFBytes("^");
_socket.flush();

// MESSAGE
for (var i:uint = 0; i < message.length; i++)
{
_socket.writeUTFBytes(message.charAt(i));
}
_socket.flush();

// MESSAGE_END
_socket.writeUTFBytes("~");
_socket.flush();

dispatchEvent(new Event(Event.CHANGE));
}

private function sendNextMessage():void
{
_currentMessage = _currentMessage == _messages.length - 1 ? 0 : _currentMessage + 1;
sendMessage(_messages[_currentMessage]);
}

private function sendPreviousMessage():void
{
_currentMessage = _currentMessage == 0 ? _messages.length - 1 : _currentMessage - 1;
sendMessage(_messages[_currentMessage]);
}

// Events
private function onSocketData(event:ProgressEvent):void
{
while (_socket.bytesAvailable > 0)
processData(_socket.readUTFBytes(1));
}

private function onSocketClose(event:Event):void
{
socketConnect();
}

private function onSocketIoError(event:IOErrorEvent):void
{
trace(event.text);
}

// Getters and Setters
public static function get instance():MessageControl
{
if (_instance == null) {
_allowInstantiation = true;
_instance = new MessageControl();
_allowInstantiation = false;
}
return _instance;
}

public function set messages(value:Array):void
{
_currentMessage = 0;
_messages = value;
if (_messages.length > 0)
sendMessage(_messages[0]);
}

public function get messages():Array
{
return _messages;
}

public function get currentMessage():uint
{
return _currentMessage;
}
}
}



Esquemático:
twitterhardware-schematic

Baixe o código fonte aqui.

Conteúdo relacionado:
Post original: http://blog.bsoares.com.br/arduino/twitter-hardware
Mais fotos: http://www.flickr.com/photos/bsoares/sets/72157616923436133/
Arduino: http://arduino.cc/
Adobe AIR: http://www.adobe.com/products/air/
Adobe Flex: http://www.adobe.com/products/flex/
LiquidCrystal Library: http://arduino.cc/en/Reference/LiquidCrystal?from=Tutorial.LCDLibrary
Twitter: http://twitter.com/

JPGEncoder (AS3) com AMFPHP

Tenho notado pelo Google Analytics que pessoas chegam ao blog procurando por AMFPHP, encode de imagens criadas no flash, salvar imagem com Flash + AMFPHP e outros critérios de busca. E por isso me sinto na obrigação de escrever algo sobre isto.

Exemplo:




Vou demonstrar exatamente o que o título do post propõe (Criar imagens no Flash com ActionScript 3, encodar essas imagens com a classe JPGEncoder presente na biblioteca as3corelib e salvar como um arquivo .jpg utilizando o AMFPHP). Já escrevi aqui como fazer isso em FluorineFx (ASP.NET Flash Remoting Gateway).

Suponho que quem esteja interessado em rodar o que está descrito neste tutorial tenha o Apache com PHP instalado, ou algum servidor com suporte. Caso você não tenha recomendo a instalação do XAMPP (é de fácil instalação e tem tudo que um programador precisa).

Configuração do AMFPHP:
A versão que utilizo neste tutorial é a 1.9 beta, mas versões posteriores devem funcionar perfeitamente.
• Baixe o AMFPHP do seguinte link: http://www.amfphp.org/
• Copie o conteúdo do ZIP para o diretório onde você está criando o projeto, recomendo a estrutura de diretórios como mostrada na imagem abaixo:
folders

• Para testar o funcionamento é só acessar o diretório browser do navegador (http://127.0.0.1/www/amf/browser/).

Fique entendido que a responsabilidade de gerar a imagem é do Flash, e o servidor deve apenas receber os binários para gravar em disco. Para gerarmos o código da imagem (binário), vamos utilizar a classe JPGEncoder.
Exemplo:
import flash.display.BitmapData;
import flash.utils.ByteArray;
import com.adobe.images.JPGEncoder;

var bmpData:BitmapData = new BitmapData(width, height);
bmpData.draw(MEU_MOVIECLIP);
var objJPGEncoder:JPGEncoder = new JPGEncoder(QUALIDADE);
var dadosEncode:ByteArray = objJPGEncoder.encode(bmpData);


Muito simples não? O método draw da classe BitmapData obtém a imagem atual do clip, criamos uma instância da JPGEncoder já passando a qualidade (0 à 100) e por fim “encodamos” o BitmapData utilizando o método encode da nossa instância da JPGEncoder, ele nos retorna um Array de Bytes (flash.utils.ByteArray).

Vamos a parte do actionscript que interessa:
private function encode():void
{
lblMessage.text = "Codificando dados (JPGEncoder.encode)";

var bmpData:BitmapData = new BitmapData(hit.width, hit.height);
bmpData.draw(target);
var objJPGEncoder:JPGEncoder = new JPGEncoder(sliderQuality.value);
var dadosEncode:ByteArray = objJPGEncoder.encode(bmpData);

sendToAmf(dadosEncode);
}

private function sendToAmf(data:ByteArray):void
{
lblMessage.text = "Enviando dados para o AMF...";

_objService = new NetConnection();
_objResponder = new Responder(onResultEvent, onStatusEvent);
_objService.connect(_amfGateway);
_objService.call("br.com.bsoares.Image.saveDataToFile", _objResponder, data);
}

private function onResultEvent(result:Object):void
{
lblMessage.text = "Abrindo imagem";
navigateToURL(new URLRequest("http://blog.bsoares.com.br/articles/jpgencoder_amfphp/generated_images/image.jpg"), "_blank");
}

private function onStatusEvent(event:Event):void
{
lblMessage.text = "Erro";
}


Agora a classe Image do PHP:
<?php
class Image
{
var $imagePath;

public function __construct ()
{
$this->imagePath = "../../../../../generated_images/image.jpg";
}

function saveDataToFile($byteArray)
{
file_put_contents($this->imagePath, $byteArray->data);
return $this->imagePath;
}
}
?>


O PHP só precisa pegar o ByteArray e salvar em um arquivo.

Dica: Para verificar os request usem o Charles Web Debugging Proxy.

É isso ai, qualquer dúvida só postar um comentário.

Conteúdo relacionado:
Post original: http://blog.bsoares.com.br/remoting/jpgencoder-as3-with-amfphp
Código fonte do exemplo: http://blog.bsoares.com.br/articles/jpgencoder_amfphp/jpgencoder-amfphp.zip
AMFPHP: http://www.amfphp.org/
AS3CoreLib: http://code.google.com/p/as3corelib/
Charles: http://www.charlesproxy.com/

Enjoy