A Aldeia Numaboa ancestral ainda está disponível para visitação. É a versão mais antiga da Aldeia que eu não quis simplesmente descartar depois de mais de 10 milhões de pageviews. Como diz a Sirley, nossa cozinheira e filósofa de plantão: "Misericórdia, ai que dó!"

Se você tiver curiosidade, o endereço é numaboa.net.br.

Leia mais...

Informática Numaboa - Tutoriais e Programação

Janela Numaboíssima (masm)

Qui

16

Abr

2009


00:00

(2 votos, média 5.00 de 5) 


Copiando os pixels não transparentes

No nosso exemplo, na segunda fileira, quando alcançarmos a coluna 4, encontraremos o primeiro pixel vermelho. Na coluna 6 encontra-se o último pixel vermelho desta série. Portanto, teremos que copiar os pixels 4, 5 e 6 desta fileira. Para determinar as coordenadas desta região numere as linhas horizontais e verticais a partir do ponto 0,0. A segunda linha horizontal é a linha 1 (x = 1) e a quarta linha vertical é a linha 3 (y = 3). Estas são as coordenadas do canto superior esquerdo da região (1,3). Repetindo o raciocínio para o último pixel vermelho desta fileira, verificamos que seu canto inferior direito é delimitado pela terceira linha horizontal (linha 2) e pela sétima linha vertical (linha 6). Suas coordenadas são x = 2 e y = 3).

No esquema abaixo estão as coordenadas de cada região que deverá ser copiada:

0,0  
Coordenada Superior Esquerda Coordenada Inferior Direita
 
                 
                 
                 
                 
                 
                 
                 
                 
                 
x = 4 e y = 0 x = 5 e y = 1
x = 3 e y = 1 x = 6 e y = 2
x = 2 e y = 2 x = 7 e y = 3
x = 1 e y = 3 x = 8 e y = 4
x = 0 e y = 4 x = 9 e y = 5
x = 1 e y = 5 x = 8 e y = 6
... ...
   
   

A lógica do nosso procedimento será a seguinte:

  • Percorrer cada fileira analisando bit por bit.
  • Quando encontrar o primeiro bit não transparente, marcar as coordenadas do canto superior esquerdo.
  • Continuar até encontrar o próximo bit transparente (acabou a sequência dos coloridos) ou o fim da fileira:
    • marcar as coordenadas do canto inferior direito
    • fazer a cópia dos bits coloridos usando as coordenadas obtidas
    • se for a primeira cópia, esta inicializará o "copião"
    • se não for a primeira cópia, adicioná-la ao "copião"
  • Retornar o copião

Os pontos vitais desta rotina são: identificar uma sequência de pixels não transparentes e determinar a primeira cópia (que servirá de "copião"). Para isto faremos uso de duas variáveis locais. A variável temCor nos indicará se o pixel analisado é transparente ou não e a variável fazerCopiao indicará se o "copião" já foi inicializado.

Convencionaremos que o primeiro pixel seja da cor que queremos transparente - é o pixel indicador de transparência. Sabendo disto, no início do processo a variável temCor deve ser falsa (FALSE) e depois sempre deve refletir o estado do pixel que está sendo analisado.

A primeira cópia de pixels não transparentes servirá para inicializar o "copião"; as cópias subsequentes serão apenas adicionadas ao mesmo. Portanto, no início do processo, precisamos indicar que o "copião" precisa ser feito, ou seja, fazCopiao deve ser verdadeiro (TRUE).

No esquema abaixo, siga os pontos (•) e acompanhe a lógica:

Fileira 1
(linha 0)
fazCopiao temCor esi (linha) Faz cópia de
ebx,esi edi,esi+1
edi ebx
                TRUE FALSE 0   3 -> 4  
                TRUE FALSE -> TRUE 0   4 -> 5 4
                TRUE -> FALSE TRUE -> FALSE 0 4,0 e 5,1 5  
                FALSE FALSE 0   5 -> 6  

Fileira 2
(linha 1)
fazCopiao temCor esi (linha) Faz cópia de
ebx,esi edi,esi+1
edi ebx
                FALSE FALSE 1   2 -> 3  
              FALSE FALSE -> TRUE 1   3 -> 4 3
                FALSE TRUE 1   4 -> 5  
                FALSE TRUE 1   5 -> 6  
                FALSE TRUE -> FALSE 1 3,1 e 6,2 6  
                  (adiciona ao copião)          

Para abrigar as cópias das regiões com pixels não transparentes vamos precisar de um contexto de dispositivo que funcionará como um temporário, o CMtemp, e de um contexto de dispositivo para o "copião", o CMcopiao. Agora é possível completar nosso processo:

grafiti proc USES ESI EDI EBX _mModelo:HDC, _largura:DWORD, _altura:DWORD LOCAL corT:DWORD LOCAL copiao:DWORD LOCAL temCor:DWORD LOCAL CMcopiao: DWORD LOCAL CMtemp: DWORD xor edi, edi ; zera o registrador edi (coluna 0) xor esi, esi ; zera o registrador esi (linha 0) mov temCor, FALSE ; como o primeiro pixel é transparente, ; temCor precisa ser falso mov copiao, TRUE ; o copião precisa ser feito invoke GetPixel, _mModelo, 0, 0 ; obtém a cor do primeiro pixel mov corT, eax ; inicializa corT com a cor da transparência _olhaPix: invoke GetPixel, _mModelo, edi, esi ; obtém a cor do pixel da linha atual na coluna atual cmp eax, corT ; a cor do pixel atual é transparente? jz _copiaPix ; sim, então verifica em _copiaPix se é o primeiro transparente depois de colorido(s) cmp edi, _largura ; não é transparente. Está dentro da largura? jnz _acheiPix ; sim, então atualiza o indicador temCor _copiaPix: cmp temCor, TRUE ; o pixel anterior era colorido? jnz _proxPix ; não, então vai para o próximo pixel mov temCor, FALSE ; sim, mas o atual é transparente mov eax, esi ; pega a coordenada x superior inc eax ; incrementa para obter a coordenada x inferior invoke CreateRectRgn, ebx, esi, edi, eax ; faz a cópia da região de pixels coloridos mov CMtemp, eax ; põe a cópia no contexto de dispositivo temporário cmp copiao, TRUE ; a cópia temporária é a primeira? jnz _poeCopiao ; não, então adicione ao copião push CMtemp ; sim, pega a cópia temporária pop CMcopiao ; e a transforma em copião mov copiao, FALSE ; desliga o indicador jmp _proxPix ; e analisa o próximo pixel _poeCopiao: invoke CombineRgn, CMcopiao, CMcopiao, CMtemp, RGN_OR ; combina a cópia temporária com o copião invoke DeleteObject, CMtemp ; "limpa" o contexto modelo temporário jmp _proxPix ; e analisa o próximo pixel _acheiPix: cmp temCor, FALSE ; pixel é colorido. O indicador já foi ajustado? jnz _proxPix ; sim, então analise o próximo pixel mov temCor, TRUE ; não, então ajuste o indicador temCor mov ebx, edi ; e guarde a coordenada x em ebx _proxPix: inc edi ; incrementa a coluna cmp edi, _largura ; a coluna é a última da linha? jbe _olhaPix ; se for menor ou igual, olha o próximo pixel ; se for maior... xor edi, edi ; é maior, então zera o contador de colunas inc esi ; passa para a próxima linha cmp esi, _altura ; a linha é a última do bitmap? jb _olhaPix ; não, então olha o próximo pixel _retorna: mov eax, CMcopiao ; sim, então põe o copião em eax para retornar ret ; retorna para o ponto de chamada grafiti endp
Regiões

Foram usadas algumas funções que ainda não foram vistas. A CreateRectRgn (que cria uma região retagular), a CombineRgn (que funde duas regiões retangulares) e a DeleteObject, todas da GDI32.DLL.

Uma região é um retângulo, polígono ou elipse (ou a combinação de duas ou mais destas formas) que pode ser preenchida, pintada, invertida, emoldurada e que pode ser usada para testar a localização do cursor (chamado de hit testing). CreateRectRgn cria uma região retangular, CreateEllipticRgn cria uma região elíptica, e assim por diante. As regiões assim criadas podem ser inseridas num contexto de dispositivo para que o aplicativo possa operar sobre elas.

A função CreateRectRgn cria uma região retangular e retorna um manipulador para a região criada:

HRGN CreateRectRgn( int nLeftRect, // coordenada x do canto superior esquerdo da região int nTopRect, // coordenada y do canto superior esquerdo da região int nRightRect, // coordenada x do canto inferior direito da região int nBottomRect // coordenada y do canto inferior direito da região );

A função CombineRgn combina duas regiões e armazena o resultado numa terceira região:

int CombineRgn( HRGN hrgnDest, // manipulador da região destino HRGN hrgnSrc1, // manipulador da região origem HRGN hrgnSrc2, // manipulador da região origem int fnCombineMode // modo de combinação );

O modo de combinação define o resultado desejado e pode ser RGN_AND, RGN_COPY, etc. No nosso exemplo foi usado o modo RGN_OR porque queremos "somar" as regiões. Veja abaixo:

Combinação
Devolvendo o controle ao gerente de mensagens

Após ter percorrido um a um os pixels do nosso bitmap e "montado" uma região que contém apenas os pixels não transparentes, vamos devolver o controle ao gerente de mensagens para que possa fazer uso desta máscara na janela.

Incorporando a região gráfica

Retornando da função grafiti, o manipulador para a região com o bitmap trabalhado, onde vazamos todos os pixels da cor que foi determinada para ser transparente, se encontra no registrador EAX. Existe uma função da API para incorporar a região gráfica a uma janela. É a SetWindowRgn:

int SetWindowRgn( HWND hWnd, // manipulador da janela que incorporará a região HRGN hRgn, // manipulador da região BOOL bRedraw // indicador de repintura );

Através desta função podemos trocar o bitmap original (aquele que nós carregamos e transferimos para o mBitmap) pelo novo bitmap obtido através da função grafiti. Fazendo a troca, termina o nosso serviço de criar a janela. Certifique-se de ter liberado o contexto de dispositivo para que outros aplicativos possam utilizá-lo. Além disso, o contexto de dispositivo de memória não é mais necessário e DEVE ser eliminado com DeleteDC.

gerenteMensagem proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM LOCAL mCMMem:HDC LOCAL retang:RECT .IF uMsg == WM_CREATE invoke LoadBitmap, mInstancia, BitmapID mov mBitmap, eax invoke GetWindowDC, hWnd mov mCM, eax invoke CreateCompatibleDC, NULL mov mCMMem, eax invoke SelectObject, mCMMem, mBitmap invoke GetWindowRect, hWnd, ADDR retang invoke grafiti, mCMMem, retang.right, retang.bottom invoke SetWindowRgn, hWnd, eax, TRUE invoke DeleteDC, mCMMem ...

Informações adicionais