PHP

Operações binárias

Posted in ASP.NET, ActionScript 3.0, Arduino, C++, Electronics, Flash, PHP on maio 25th, 2009 by Bruno Soares – 7 Comments

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)

1
2
3
4
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:

1
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)

1
2
3
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:

1
2
3
4
5
6
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).

1
2
3
4
5
6
7
8
9
10
// 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:

1
2
3
4
5
6
7
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++):

1
2
3
4
5
6
7
8
9
10
11
12
// 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:
Bitwise operation on Wikipedia
 

Controlando a Arduino com PHP via porta serial

Posted in Arduino, Electronics, PHP on maio 1st, 2009 by Bruno Soares – 66 Comments

É isso mesmo, o PHP pode escrever ou ler dados da porta serial, e com isso podemos controlar a Arduino.

Você pode ligar o seu ar-condicionado, cafeteira, luz, etc… via Internet, e de uma forma bem simples.
Serialproxy também é uma ótima forma de se conectar a Arduino via Internet, utilizei no projeto Twitter Hardware, mas este post é sobre PHP, então vamos lá.

Arduino + PHP Diagram

Vou utilizar o exemplo descrito no post “Controlando Led RGB com Arduino e Processing” (trocando o Processing pelo PHP).

A função fopen do PHP da suporte a escrita na porta serial:

1
2
3
$port = fopen('COM2', 'w');
fwrite($port, '1');
fclose($port);

Linha 1) Abre a conexão com a COM2 (porta serial onde a minha Arduino está conectada).
Linha 2) Escreve na porta
Linha 3) Fecha a conexão

Código PHP do exemplo:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<?php
/**
 * Arduino + PHP
 *
 * @author  Bruno Soares
 * @website www.bsoares.com.br
 */


$color = $_REQUEST['color'];

if (isset($color) && !empty($color)) {
    $color = hexdec($color);
    $message = '^' . $color . '$';

    // USB Serial Port (COM2)
    $portAddress = 'COM2';
   
    // Open connection on port
    $port = fopen($portAddress, 'w');
   
    // Necessary when the Arduino reset after the connection
    sleep(2);
   
    // Send chars
    fwrite($port, $message);
   
    // Close connection
    fclose($port);
}
?>

Linha 12) Converte a cor de hexadecimal para decimal.
Linha 13) Coloca os caracteres que indicam o inicio e fim da mensagem.
Linha 16) Define a variável com o endereço da porta (no meu caso COM2).
Linha 19) Abre a “conexão” com a porta serial.
Linha 22) Pausa o código por 2 segundo, pois a Arduino costuma reiniciar quando é feita uma conexão a ela.
Linha 25) Escreve a mensagem com a cor na porta serial.
Linha 28) Fecha a “conexão” com a porta serial.

Update 09/07/2009:
Lendo dados:
Tenho recebido diversos e-mails e até alguns comentários de pessoas que precisam ler dados de um sensor, potenciometro, ou qualquer coisa conectada a Arduino, e isso via PHP. Então vamos lá, preparei um código que faz isso de forma fácil.
Acredito que um problema que o pessoal tem tido com esta tarefa é: você deve se dar tempo para a mensagem chegar a Arduino (não que isso seja muito tempo), e também para que a Arduino consiga responder:

Código Arduino:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/**
 * Arduino + PHP
 *
 * @author  Bruno Soares
 * @website www.bsoares.com.br
 */


#define ANALOG_PIN 4

void setup()
{
  Serial.begin(9600);
}

void loop()
{
  if (Serial.available() > 0) {
    if (Serial.read() == '1')
      Serial.print(analogRead(ANALOG_PIN), DEC);
  }
}

Código PHP:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<?php
/**
 * Arduino + PHP
 *
 * @author  Bruno Soares
 * @website www.bsoares.com.br
 */


// Conecta na porta
$port = fopen('COM2', 'w+');

// Em alguns casos a Arduino pode reiniciar, por isso
// é bom esperar para enviar informação depois de conectar
sleep(2);

// Envia "1" para o programa na Arduino saber que deve responder
fwrite($port, '1');

// Espera para que o dado enviado pelo PHP chegue até a Arduino
sleep(1);

// Agora que a Arduino "Provavelmente já respondeu", pega
// o valor da resposta
echo fgets($port);

// Fecha a conexão com a porta
fclose($port);
?>

O que esse código faz?
A Arduino fica em loop esperando receber pela porta serial o numero 1, assim que recebido ela lê a voltagem do pino analógico 4 e escreve na porta serial.
O PHP abre a porta serial, escreve “1″, e espera para ler novamente, quando lê novamente encontra o valor do pino analógico 4, assim como a Arduino escreveu.
Bom, espero que este exemplo acabe com as dúvidas do pessoal que precise ler dados da Arduino :)

Observações:
Caso você precise fazer um projeto onde muitos usuário vão acessar o script que escreve na porta serial, você deve implementar uma fila, de forma a não ter um usuário escrevendo na porta ao mesmo tempo que outro, isto geraria um erro.
O código fonte escrito para a Arduino é o mesmo do post Controlando Led RGB com Arduino e Processing

Faça o download do código fonte aqui.

Conteúdo relacionado:
Arduino: http://www.arduino.cc/
Referência: http://www.arduinoprojects.com/?q=node/10
jQuery ColorPicker: http://www.eyecon.ro/colorpicker/

JPGEncoder (AS3) com AMFPHP

Posted in ActionScript 3.0, Flash, PHP, Remoting on abril 7th, 2009 by Bruno Soares – 3 Comments

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:

This movie requires Flash Player 9

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:

1
2
3
4
5
6
7
8
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:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
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:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?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:
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

Convertendo PNG para SWF com PHP 5

Posted in Flash, PHP on abril 4th, 2009 by Bruno Soares – 1 Comment

Bom para quem não sabe o Adobe Flash consegue uma compressão incrível com arquivos do tipo PNG, mantendo a sua qualidade e transparência. Vou deixar um exemplo de código PHP para fazer essa conversão sem a ajuda de softwares como o png2swf.exe pois a realidade é que muitos servidores (hosts) não permitem que o script PHP rode softwares.

Classe:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
<?php
/**
 * SwfConvertion
 *
 * @author Bruno Soares
 * @link   http://www.bsoares.com.br
 */

class SwfConvertion
{
    public function __construct () { }
   
    /**
     * image2swf
     *
     * @param  $imagePath String
     * @return void
     */

    public static function image2swf($imagePath, $outputPath = '')
    {
        if ($outputPath == '')
        {
            $outputPath = SwfConvertion::resolveOutputPath($imagePath);
        }
       
        $bitmap = new SWFBitmap(file_get_contents($imagePath));
       
        $shape = new SWFShape();
        $shape->setRightFill($shape->addFill($bitmap));
        $shape->drawLine($bitmap->getWidth(), 0);
        $shape->drawLine(0, $bitmap->getHeight());
        $shape->drawLine(-$bitmap->getWidth(), 0);
        $shape->drawLine(0, -$bitmap->getHeight());
       
        $movie = new SWFMovie();
        $movie->setDimension($bitmap->getWidth(), $bitmap->getHeight());
        $movie->add($shape);
        $movie->save($outputPath);
    }
   
    /**
     *
     *
     * @param $imagePath Object
     * @return String
     */

    private static function resolveOutputPath($imagePath)
    {
        return preg_replace('/^(.+)\.([A-Za-z]{3,4})$/i', '${1}.swf', $imagePath);
    }
}
?>

Exemplo de uso:

1
<?php SwfConvertion::image2swf('imagem_branco.png', 'imagem_branco_2.swf'); ?>

1º Teste:
PNG: imagem_branco.png 167KB
SWF: imagem_branco_2.swf 98KB
41,31% de compressão (menos 69KB)

2º Teste:
PNG: imagem_vermelho.png 309KB
SWF: imagem_vermelho_2.swf 264KB
14,56% de compressão (menos 45KB)

Obs.: É importante que você escolha bem as conversões que deseja fazer, pois em alguns casos o SWF pode ficar mais pesado que o PNG ou seja, se você vai utilizar este script para otimizar suas imagens compare os pesos antes de escolher a definitiva.

Conteúdo relacionado:
PHP Shockwave Flash: http://br2.php.net/manual/pt_BR/book.swf.php
Funções para SWF: http://br2.php.net/manual/pt_BR/ref.swf.php

Enjoy