Bitmaps em AdvPL – Parte 08

Introdução

No post anterior, vimos com mais detalhes o suporte a corres de uma imagem Bitmap. Agora, vamos ver mais um método interessante da classe ZBITMAP — o FlipV() — ou inversão vertical — usado para colocar a imagem ou uma parte dela literalmente “de ponta cabeça”. Quer ver esta sequência desde o início? Acesse clicando aqui o primeiro post.

Método FlipV()

Este método pode receber opcionalmente duas coordenadas, para permitir inverter verticalmente uma área da imagem. Caso nenhum parâmetro seja informado, ele inverte a imagem inteira. Ele é praticamente uma implementação “prima” da FlipH(), porém atua trocando as cores entre as linhas da área informada, enquanto a FlipH() troca as cores das colunas.

Como os dados do Bitmap estão em um array bidimensional, existem várias formas de se realizar a inversão. Em ambas as implementações, eu optei por usar a alternativa mais “econômica” de memória, criando uma instrução na forma de #translate para fazer uma troca de conteúdo entre duas variáveis, no caso a cor do ponto no array, sem alocar arrays intermediários ou temporários. Apenas tomei o cuidado de declarar uma variável local para ser usada como container temporário para fazer a troca sem perder a informação original. Vamos ao método:

// Inverte verticalmente uma área da imagem
// Ou a imagem inteira caso a área nao seja especificada
METHOD FlipV(L1,C1,L2,C2) CLASS ZBITMAP
Local nL  , nC            
Local nRow, nSwap
IF pCount() == 0
	// Faz flip vertical da imagem inteira
	L1 := 0
	C1 := 0
	L2 := ::nHeight-1
	C2 := ::nWidth-1
Else
	// Valida coordenadas informados
	IF L1 < 0 .or. L1 >= ::nHeight
		::cError := "Invalid 1o Line -- Out Of Image Area"
		Return .F.
	ElseIF L2 < 0 .or. L2 >= ::nHeight
		::cError := "Invalid 2o Line -- Out Of Image Area"
		Return .F.
	ElseIf C1 < 0 .or. C1 >= ::nWidth
		::cError := "Invalid 1o Column -- Out Of Image Area"
		Return .F.
	ElseIf C2 < 0 .or. C2 >= ::nWidth
		::cError := "Invalid 2o Column -- Out Of Image Area"
		Return .F.
	ElseIf L1 > L2
		::cError := "Invalid Lines -- Order mismatch"
		Return .F.
	ElseIf C1 > C2
		::cError := "Invalid Columns -- Order mismatch"
		Return .F.
	Endif
Endif

// Troca os pontos da primeira linha com a ultima
// depois da segunda com a penultima 
// até chegar na linha central da área a ser invertida      
nRow := L2+1
For nL := L1+1 to L1 + INT( ( L2-L1 ) / 2 ) + 1
	For nC := C1+1 to C2+1
		ZSWAP( ::aMatrix[nL][nC] , ::aMatrix[nRow][nC] , nSwap )
	Next
	nRow--
Next

Return .T.

Instrução ZSWAP

Se eu quero trocar conteúdos entre duas variáveis, para que uma assuma o conteúdo da outra, (ainda) não existe função da linguagem que permita fazer isso de forma direta. A alternativa mais eficiente é armazenar o conteúdo da primeira variável em uma variável de uso temporário, depois atribuir o conteúdo da segunda variável sobre a primeira, e então atribuir o conteúdo da primeira variável — salvo e armazenado na variável temporária — na segunda variável. Para isso, eu uso a instrução abaixo:

#TRANSLATE ZSWAP( <X> , <Y> , <S> ) => ( <S> := <X> , <X> := <Y> , <Y> := <S> )

Usando a diretiva de pré-compilação #TRANSLATE, é possível criar uma pseudo-função em tempo de compilação — algo equivalente a um método “inline”, disponível por exemplo no C++. A diretiva identifica as ocorrências de chamada da pseudo-função ZSWAP, recebendo três parâmetros: <X> é a primeira variável ou expressão, <Y> é a segunda variável ou expressão, e <S> é a variável de armazenamento temporário para fazer a troca. Veja abaixo um exemplo de uso e como ela será traduzida na pré-copilação deste código:

// Chamada original
ZSWAP ( nVar1 , nVar2, nTmp ) 

// Após a pré-compilação 
( nTmp := nVar1 , nVar1 := nVar2 , nVar2 := nTmp )

A utilização de diretivas de #TRANSLATE e similares no AdvPL (como a #COMMAND e #XCOMMAND) permite implementações desta ordem, e também aglutinação e tradução de chamadas, até a implementação de comandos — que serão traduzidos para chamadas de funções ou métodos, tornando a sintaxe para diversas operações bem mais leve e intuitiva.

Conclusão

Por hora, concluo apenas que falta pouco para a classe ZBITMAP ser declarada como “pronta”.

Agradeço a todos pela audiência, e desejo a todos TERABYTES DE SUCESSO !!! 

 

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair /  Alterar )

Foto do Google

Você está comentando utilizando sua conta Google. Sair /  Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair /  Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair /  Alterar )

Conectando a %s