Bitmaps em AdvPL – Parte 06

Introdução

No post anterior vimos como traçar um quadrado ou retângulo no Bitmap, e como fazer o efeito “negativo”. Agora, vamos implementar uma área de transferência interna na classe ZBITMAP, para fazer CUT() , COPY() e PASTE(), e fazer inversão horizontal da imagem ou de uma parte dela, usando o método FLIPH()

Operações e área de transferência

Como representamos a imagem em um array (::aMatrix), implementamos a área de transferência também como um Array bidimensional de cores. O método Clear(), que pintava todos os pontos da imagem com a cor de fundo, passa a receber opcionalmente parâmetros de duas coordenadas para limpar uma área retangular, limpando a imagem inteira apenas quando nenhuma coordenada for informada. O método COPY() cria um array com a área retangular das coordenadas informadas, o método CUT() usa internamente o COPY() e o CLEAR(), e o método PASTE() recebe a coordenada superior esquerda onde a imagem na área de transferência deve ser “colada”. Vejamos abaixo os métodos:

// ----------------------------------------------------
// Copia uma parte da imagem para a área interna 
// de transferência e limpa a área da imagem

METHOD Cut(L1,C1,L2,C2)            CLASS ZBITMAP
::Copy(L1,C1,L2,C2)
::Clear(L1,C1,L2,C2)
Return .T. 

// ----------------------------------------------------
// Copia uma parte da imagem para a área interna de transferência

METHOD Copy(L1,C1,L2,C2)           CLASS ZBITMAP
Local nL  , nC            
Local aRow := {}

IF pCount() == 0
	// Copia a imagem inteira para a area de transferencia
	::aTrans := aClone(::aMatrix)
    Return .T.
Endif

// 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

::aTrans := {}

// Copia a área informada para a area de transferencia interna
For nL := L1+1 to L2+1
	For nC := C1+1 to C2+1
		aadd(aRow,::aMatrix[nL][nC])
	Next
	aadd(::aTrans,aClone(aRow))
	aSize(aRow,0)
Next

Return .T.

// ----------------------------------------------------
// Plota a imagem da area interna de transferencia na coordenada indicada

METHOD Paste(L1,C1)                CLASS ZBITMAP
Local nL , nC

// Valida a area de transferencis
If empty(::aTrans)
	::cError := "Empty Transfer Area"
	Return .F.
Endif

// Valida as cordenadas
IF L1 < 0 .or. L1 >= ::nHeight
	::cError := "Invalid Target Line -- Out Of Image Area"
	Return .F.
ElseIf C1 < 0 .or. C1 >= ::nWidth
	::cError := "Invalid Target Column -- Out Of Image Area"
	Return .F.
Endif
                       
// Plota a imagem da area de transferencia
// Validando as coordenadas de colagem caso 
// a imagem colada nas coordenadas saia 
// "fora" da área total da imagem 
For nL := 0 to len(::aTrans)-1
	IF L1+nL < ::nHeight
		For nC := 0 to len(::aTrans[nL+1])-1
			If C1+nC < ::nWidth
				::aMatrix[L1+nL+1][C1+nC+1] := ::aTrans[nL+1][nC+1]
			Else
				EXIT
			Endif
		Next
	Else
		EXIT
	Endif
Next

Return .T.

A área de transferência pode ser compartilhada entre dois objetos de bitmap, bastando atribuir a propriedade ::aTrans. Os métodos CUT(), COPY() e CLEAR(), caso não recebam coordenadas, assumem por default a área total da imagem. Estes métodos são úteis quando precisamos mesclar partes da mesma imagem ou de outra imagem com a atual, ou mesmo para fazer um mosaico — cria-se uma pequena área da imagem com um mosaico, tira-se uma cópia e loops para colar esta parte da imagem de forma distribuída — igual ao efeito “lado a lado” de imagens de fundo do Windows.

Flip horizontal

Uma imagem ou parte dela pode ser invertida horizontalmente com este recurso. Por exemplo, uma imagem com uma foto de todas as pessoas olhando para a direita, pode ser invertida como se fosse uma transparência, e todos agora olham para a esquerda. Porém, se houver um texto na imagem, ele também será “invertido”.

// Inverte horizontalmente uma área da imagem
// Ou a imagem inteira caso a área nao seja especificada
METHOD FlipH(L1,C1,L2,C2) CLASS ZBITMAP
Local nL , nC 
Local nCol, nSwap
IF pCount() == 0
  // Faz flip horizontal 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

For nL := L1+1 to L2+1
  nCol := C2+1
  For nC := C1 + 1 TO C1 + INT( ( C2-C1 ) / 2 ) + 1
    ZSWAP( ::aMatrix[nL][nC] , ::aMatrix[nL][nCol] , nSwap )
    nCol--
  Next
Next

Return .T.

E este recurso é muito útil, principalmente para inverter propositalmente textos que devem ser lidos com um espelho. Por exemplo, a palavra “AMBULÂNCIA” pintada ou adesivada na parte frontal do devido veículo está horizontalmente invertida (ou “ao contrário”), para justamente ser lida de forma correta quando um motorista avistar este veículo no retrovisor. Veja abaixo a imagem original e invertida.

ambulancia

ambulancia_mirror

 

Conclusão

Usando a representação da imagem como array, e algumas funções de array do AdvPL fica fácil editar a imagem e realizar operações dessa natureza. Durante os testes e implementações, foram identificados falhas na gravação de bitmaps lidos do disco, os fontes atualizados da classe estão no GITHUB!

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

Referências

 

 

 

 

Um comentário sobre “Bitmaps em AdvPL – Parte 06

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