Voltar de valor byte para letra [RESOLVIDO]

23 respostas
pedroroxd

Pessoal, tava dando uma olhada na Ascii Table, e tava mandando imprimir os valores de cada letra para teste:

int byteValue = 'B'; System.out.println("Valor Byte" + byteValues);

Depois, eu tento voltar para a letra assim:

String str = Integer.toBinaryString((byte) byteValue); int i = Integer.parseInt(str, 2); System.out.println((char) i);
Para todos os valores da taebla funcionam, mas para caracteres especiais não (do tipo á,à,â,ã,ä,ç).
Dá esse erro: [color=red]Exception in thread “main” java.lang.NumberFormatException: For input string: “11111111111111111111111111000111”[/color]

Se eu faço assim:
char b3 = (char) (byteValue);
Funciona, mas ae ele vai pegar de todos os pixels da imagem, inclusive os que eu não quero… Estou usando ele, mas como que eu faço para parar o algoritimo de varredura da imagem quando terminar a frase??
A imagem que estou falando é essa: http://www.guj.com.br/posts/list/15/221333.java

23 Respostas

ViniGodoy

O problema é que caracteres especiais, caracteres estrangeiros, simbolos, etc, seguem a tabela Unicode, e não a tabela ascii. É por isso que o char, no Java, tem 2 bytes e não 1.

Uma das formas de resolver isso é você parar de lidar com strings, e passar a lidar com o texto byte-a-byte, como se fosse um arquivo binário. E depois fazer o mesmo para recompor. Agora, seu texto ocupará o dobro do espaço, o que exigirá uma imagem duas vezes maior.

Por isso, além de tratar byte-a-byte, recomendo que você use um inputstream com compactação.

T

String str = Integer.toBinaryString(color=red[/color] byteValue);

Remove esse cast que funciona.

pedroroxd

Consegui… deu certo, vlw ae vini

Agora estou com um problema:
Saber quando parar de pegar texto da imagem
Eu fiz o seguinte: No primeiro pixel (0,0) eu do um setRed com o tamanho do texto…
Depois na hora de descriptografar eu volto lá e do um getRed no primeiro pixel…

Funciona certinho… Mas tem 1 problema… Quando o texto tem mais do que 255 caracteres não dá pra dar um setRed com ele…
Pensei em /1000 e depois fazer *1000 mas ele só aceita valor inteiro… Então se tiver 300 caracteres, vai pra 0,3 e volta pra 0…

ViniGodoy

Transforme o int da cor numa Color, diretamente. Aí grave essa color no primeiro pixel.

Outra opção é fazer como o C faz. Criptografa um 0 no final do texto.
Quando chegar no 0, você sabe que o texto acabou.

Não estou falando de um pixel com a cor 0, mas de colocar 0 em todos os bits que você usa para as esconder as letras.

pedroroxd

É isso que tava tentando fazer… Assim:

Color m = new Color(imagem.getRGB(0, 0)); Color newColorr = new Color(text.length(),m.getGreen(),m.getBlue(),m.getAlpha()); imagem.setRGB(0, 0, newColorr.getRGB());
Mas ae da erro quando é mais que 255…

Mas não pode ocorrer coincidentemente de ter um texto com 0 nakeles bits?

ViniGodoy

Não. O 0 em todas as tabelas representa NUL.

pedroroxd

Entendi…
Arranjei uma outra maneira:

imagem.setRGB(0, 0,  -text.length());

E na hora de voltar:

int tamanho = img1gp.getRGB(0, 0); tamanho = -tamanho *2; //* 2 pq é 2 pixels para cada letra
Testei com uns textos grandes aqui e deu certo…
RGB tem limite também? De quanto é?

ViniGodoy

Se você usar os 3 bytes do R, G e B, você terá 24 bits para guardar o número. Portanto, o limite será de (2^24)-1, ou seja: 16777215.

pedroroxd
ViniGodoy:
Se você usar os 3 bytes do R, G e B, você terá 24 bits para guardar o número. Portanto, o limite será de (2^24)-1, ou seja: 16777215.
Axo que dá! rs

Eu colokei para criptografar um texto "grandinho" (de 8940 caracteres):

Ele só conseguiu chegar até o 1370, depois deu isso:
[color=red]Exception in thread "Thread-4" java.lang.StackOverflowError
at sun.nio.cs.SingleByteEncoder.encodeArrayLoop(Unknown Source)
at sun.nio.cs.SingleByteEncoder.encodeLoop(Unknown Source)
at java.nio.charset.CharsetEncoder.encode(Unknown Source)
at sun.nio.cs.StreamEncoder.implWrite(Unknown Source)
at sun.nio.cs.StreamEncoder.write(Unknown Source)
at java.io.OutputStreamWriter.write(Unknown Source)
at java.io.BufferedWriter.flushBuffer(Unknown Source)
at java.io.PrintStream.write(Unknown Source)
at java.io.PrintStream.print(Unknown Source)
at java.io.PrintStream.println(Unknown Source)[/color]

Meu método chama ele mesmo várias vezes, deve tar estorando...
private static void start(BufferedImage imagem) {
	for (int x = 0; x < size; x++) {
			String qual = text.substring(y, y + 1);
			
			if (qual.equals(String.valueOf(letras[x]))) {				
				System.out.println(letras[x]);
				int xd = line + 1;
				
				Color pixel1 = new Color(imagem.getRGB(line, colum));  
				int r1 = pixel1.getRed() & 0xFC;    //Limpa os dois ultimos bit. FC=1111 1100  
				int g1 = pixel1.getGreen() & 0xFE; //Limpa o ultimo bit. FE=1111 1110  
				int b1 = pixel1.getBlue() & 0xFE;  
				
				Color pixel2 = new Color(imagem.getRGB(xd, colum));  
				int r2 = pixel2.getRed() & 0xFC;
				int g2 = pixel2.getGreen() & 0xFE;
				int b2 = pixel2.getBlue() & 0xFE;  

 
				/////
				int bits = letras[x];
				bits = bits & 3;  
				int novoRED1 = r1 | bits; 
							 
								 
				bits = letras[x];
				bits = bits >>2;
				bits = bits & 1;
				int novoGREEN1 = g1 | bits;
							     
				bits = letras[x];
				bits = bits >>3;
				bits = bits & 1;
				int novoBLUE1 = b1 | bits;
							     
							     
				/////////////////////
				bits = letras[x];
				bits = bits >>4; //5
				bits = bits & 3;
				int novoRED2 = r2 | bits;
							     
				bits = letras[x];
				bits = bits >>6;
				bits = bits & 1;
				int novoGREEN2 = g2|bits;
							     
				bits = letras[x];
				bits = bits >>7;
				bits = bits & 1;
				int novoBLUE2 = b2 |bits;
					

				Color newColorr = new Color(novoRED1,novoGREEN1,novoBLUE1,pixel1.getAlpha()); //pixel1.getAlpha()
				Color newColorr2 = new Color(novoRED2,novoGREEN2,novoBLUE2,pixel2.getAlpha());	//pixel2.getAlpha()

				
				imagem.setRGB(line, colum, newColorr.getRGB());
				imagem.setRGB(xd, colum, newColorr2.getRGB());

				line = line + 2;
				if (line == imagem.getWidth()) {
					colum++;
					line = 0;
				}

				y++;

				if (y < text.length()) {
					start(imagem); //AKI.. Ele se chama
				}
				break;
			}
		}
	}
Ali no (y<text.lenght) ele vai chamar dinovo, até completar o texto..>
ViniGodoy

Por que seu método chama a si mesmo várias vezes?

pedroroxd

Porque ele recebe como parâmetro a imagem…
Depois ele edita 1 pixel da imagem, e passa a nova imagem para si mesmo…

Vou ver se faço pra editar todos os pixels em vez de ficar chamando a si mesmo…

pedroroxd

Ae! Consegui!
Realmente não precisava ficar se chamando várias vezes…

Mandei criptografar um texto de 20.000 caracteres e deu certinho…
O unico caractere que não sai é o um abre aspas, que quando eu coloko aki no guj vira interrogação… O " sai…

Realmente, não percebesse nenhuma variação na imagem, só no primeiro pixel que é o RGB da quantidade de caracteres… no mais é tudo igualzinho…

Vlws ae vinigodoy, que me ajudou pra caramba mesmo, malz ae por ter enchido tanto o saco! kkkk
=]

pedroroxd

Ultima pergunta…
Agora que li com atenção seu post…
O que vc queria dizer com a compactação no texto?

ViniGodoy

Bom, acabei me empolgando e escrevi também meu algoritmo de esteganografia.

Em anexo, está o jar que faz o algoritmo rodar. E uma imagem, com a logo do GUJ.

Para esteganografar:
java -jar Esteganografia.jar -e NomeDaImagem.png NomeDoArquivo1 NomeDoArquivo2 …

Para reverter
java -jar Esteganografia.jar -r NomeDaImagem.png

Experimente rodar o programa para reverter os textos secretos que estão nessa logo.
Os textos saem na forma de arquivos. Então, não tentem só procurar uma frasezinha escrita no console.

Para quem perdeu, a explicação de como o processo funciona está aqui: http://www.guj.com.br/posts/list/221333.java#1132889

Entretanto, esse programa não usa o canal alfa. Uma otimização no PNG as vezes pré-multiplica o canal, o que o inviabiliza para o processo.
No lugar, uso 2 bits do canal vermelho, 1 do verde e 1 do azul para guardar meio byte, o que torna necessário usar 2 pixels para armazenar cada byte do que quero esconder.

pedroroxd

Legal!!
Ele funciona para outros tipos de documentos também? ou só txt?

ViniGodoy

pedroroxd:
Legal!!
Ele funciona para outros tipos de documentos também? ou só txt?

Pra qualquer tipo de arquivo.

ViniGodoy

A única limitação é que a imagem original precisa ser lossless, ou seja, .png ou bmp.
O arquivo de saída sempre chama-se output.png.

pedroroxd

tentei com 1 documento .doc, ele gera a imagem, mas na volta ele não gera o texto…

Mas com o logo do guj deu certo…
Bem bacana… Tem bastante coisa que não entendi, mas beleza… Devo ver isso quando entrar na faculdade ! rs
Por enquanto sou apenas um vestibulando rs…

Mas enfim, meu exemplo beeeem mais simples tá nesse site (não coube aki no guj):
http://www.easy-share.com/[telefone removido]/ProjetoPronto.jar

dá 1 olhada ae! dei 1 enfeitada nele… rs

ViniGodoy

Não faz o menor sentido. O programa nem sequer olha pro formato do arquivo. Ele lê um arquivo byte-a-byte e esconde. Pode ser qualquer coisa.
Você tem certeza que mandou reverter a imagem certa?

Em todo caso, está aqui uma demonstração. Essa imagem contém o doc dos fontes do programa.

ViniGodoy

Atualizei o post do programa. Agora ele permite que você esconda vários arquivos dentro da imagem.
Na logo, além dos fontes, agora está escondido também o arquivo manifest, usado para gerar o .jar.

Isso representou só uma mudança simples no processo de compactação.

O programa é compatível com imagens geradas na versão anterior.

ViniGodoy

Corrigido o tópico que contém programa. A palavra correta é esteganografia, e não estenografia.

E

Sabia que já tinha visto a palavra “estenografia” antes. É coisa de antigas secretárias (aquelas que tomavam ditado):

ViniGodoy

Sabia que já tinha visto a palavra “estenografia” antes. É coisa de antigas secretárias (aquelas que tomavam ditado):


Pois é, essa semelhança é que me confundiu.

Criado 16 de outubro de 2010
Ultima resposta 18 de out. de 2010
Respostas 23
Participantes 4