Program składa się z 3 głównych metod, odpowiedzialnych za otwieranie plików graficznych oraz tekstowych, zamykanie programu, a także ukrywanie oraz odkrywanie wiadomości. Dodatkowo metody odpowiedzialne za ukrywanie oraz odkrywanie wiadomości składają się z kilku mniejszych metod, które są niezbędne do ich prawidłowego funkcjonowania.
Ukrywanie wiadomości
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 |
private void JHideActionPerformed(java.awt.event.ActionEvent evt) { try { String msg = textarea.getText(); byte[] msg_bytes = msg.getBytes(); if(msg_bytes.length == 0) { throw new Exception("Wpisz wiadomo?? do ukrycia."); } int[] addon = get_msg(msg_bytes); if(imageLoaded.getWidth()*imageLoaded.getHeight() < addon.length) throw new Exception("Wiadomo?? zbyt d?uga by ukry? j? w wybranym obrazie"); encode_image(addon); JImage.setIcon(new ImageIcon(imageLoaded)); File imageFile = new File("out.png"); ImageIO.write(imageLoaded, "png", imageFile); }catch (IOException ex) { System.out.println("Problem z zapisem pliku "); } catch (NullPointerException ex) { System.out.println("Nie za?adowano obrazu."); JOptionPane.showMessageDialog(jError, "Nie za?adowano obrazu. \nAby ukry? wiadomo?c najpierw trzeba za?adowa? obraz."); } catch (Exception ex) { System.out.println("Nie za?adowano obrazu: "+ex); JOptionPane.showMessageDialog(jError, ""+ex); } } |
Metoda ta odpowiedzialna jest za ukrycie wiadomości w pliku graficznym. Na początku następuje odczytanie wiadomości z pola tekstowego programu, a następnie zamiana wiadomości na bajty. Jeśli w polu tekstowym nie została wpisana żadna wiadomość, wyrzucany jest wyjątek o treści „Wpisz wiadomość do ukrycia.”. Kolejnym elementem jest odwołanie do metody get_msg(), która zwraca tablicę addon z długością ukrywanej wiadomości oraz samą wiadomością w postaci bitowej. Metoda ta zostanie bardziej szczegółowo opisana w dalszej części. Jeśli ilość bitów potrzebna do zapisania wiadomości jest większa niż wybrany do jej ukrycia plik graficzny, wyrzucony zostaje wyjątek informujący o tym fakcie. Jeśli wybrany obraz jest w stanie pomieścić wiadomość następuje wywołanie metody encode_image(), która odpowiedzialna jest za ukrycie w pliku graficznym wpisanej wiadomości. Metoda ta zostanie przedstawiona w dalszej części strony. Następnie następuje zapisanie obrazu z ukrytą wiadomością do pliku .png. Jeżeli wystąpi problem z zapisem pliku lub nie wybrano obrazu, w którym ukryta ma zostać wiadomość wyświetlony zostanie komunikat o błędzie.
Metoda get_msg()
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 |
private int[] get_msg(byte[] msg_bytes) { int addon_position = 0; int[] addon = new int[msg_bytes.length*8+33]; byte[] length = new byte[4]; int msg_len = msg_bytes.length*8+33; for(int i = 0; i<33;i++){ addon[i]=0; } length[0] =(byte)( msg_len >> 24 ); length[1] =(byte)( (msg_len << 8) >> 24 ); length[2] =(byte)( (msg_len << 16) >> 24 ); length[3] =(byte)( (msg_len << 24) >> 24 ); for(int i = 0; i<4 ;i++){ for (int k=7;k>=0;k--){ addon[addon_position] = length[i] >>> k & 1; addon_position++; } } addon_position=33; for(int i=0; i<msg_bytes.length; i++){ String msg_bin = Integer.toBinaryString(msg_bytes[i]); for (int k=7;k>=0;k--){ addon[addon_position] = msg_bytes[i] >>> k & 1; String msg_bin2 = Integer.toBinaryString(msg_bytes[i]); addon_position++; } } return addon; } |
Metoda ta na wejściu otrzymuje tablicę z zapisaną w postaci bajtów wiadomością. Następnie stworzona zostaje stworzona tablica addon, w której pierwsze 33 bity zarezerwowane zostały do zapisania długości wiadomości, natomiast w kolejnych bitach zapisana zostaje wiadomość w postaci bitowej. Otrzymana w ten sposób tablica addon zostaje zwrócona jako efekt metody.
Metoda encode_image()
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 |
private void encode_image(int[] addon) { int addon_position=0; System.out.println("addon.length = "+addon.length); outerLoop: for (int i = 0; i < imageLoaded.getHeight() & addon_position<addon.length; i++) { for (int j = 0; j < imageLoaded.getWidth() & addon_position<addon.length; j++) { int pixel = imageLoaded.getRGB(j, i); int alpha = (pixel >> 24) & 0xff; int red = (pixel >> 16) & 0xff; int green = (pixel >> 8) & 0xff; int blue = (pixel) & 0xff; if(addon_position>=addon.length) break outerLoop; red = (red & 0xFE) | addon[addon_position]; addon_position++; if(addon_position>=addon.length) break outerLoop; green = (green & 0xFE) | addon[addon_position]; addon_position++; if(addon_position>=addon.length) break outerLoop; blue = (blue & 0xFE) | addon[addon_position]; addon_position++; pixel = (alpha << 24) | (red << 16) | (green << 8) | blue; imageLoaded.setRGB(j, i, pixel); }} } |
Metoda ta na wejściu otrzymuje tablicę addon, w której zapisana jest wiadomość w postaci binarnej. Następnie następuje sczytanie wartości RGB poszczególnych pikseli i rozbicie piksela na pojedyncze składowe red, green, blue. Najmniej znaczący bit każdej składowej zamieniany jest na kolejny z kolei bit ukrywanej wiadomości, po czym ustawiana jest nowa wartość RGB danego piksela. Proces ten powtarzany jest do momentu, gdy ukryta zostanie cała wiadomość.
Odkrywanie wiadomości
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 |
private void JRevealActionPerformed(java.awt.event.ActionEvent evt) { try{ int[] msg = decode_image(); String[] text = new String[msg.length/8]; String finalText = ""; for(int i = 0; i<msg.length/8;i++){ text[i]=""; for(int j=i*8; j<8*(i+1); j++){ text[i]+= Integer.toString(msg[j]); } } for(int i=0; i<text.length;i++){ int letterCode = Integer.parseInt(text[i], 2); finalText += new Character((char)letterCode).toString(); } System.out.println(finalText); textarea.setText(finalText); }catch (NumberFormatException ex) { System.out.println("W otworzonym obrazie nie ma ukrytej wiadomo?ci."); JOptionPane.showMessageDialog(jError, "W otworzonym obrazie nie ma ukrytej wiadomo?ci."); } catch (NullPointerException ex) { System.out.println("Nie za?adowano obrazu"); JOptionPane.showMessageDialog(jError, "Nie otworzono obrazu. \nAby ukry? wiadomo?c nale?y najpierw za?adowa? obraz."); } catch (NegativeArraySizeException ex) { System.out.println("Brak ukrytej wiadomo?ci w otworzonym obrazie."); JOptionPane.showMessageDialog(jError, "Brak ukrytej wiadomo?ci w otworzonym obrazie."); } catch (OutOfMemoryError ex) { System.out.println("Brak ukrytej wiadomo?ci w otworzonym obrazie."); JOptionPane.showMessageDialog(jError, "Brak ukrytej wiadomo?ci w wybranym obrazie."); } } |
Metoda ta odpowiedzialna jest za odczytanie ukrytej w obrazie wiadomości. Na początku następuje zadeklarowanie tablicy liczb całkowitych msg, w której znajdą się wartości zwrócone przez metodę decode_image(), a także ciągu znaków finalText, w którym zapisana zostanie finalna wersja odczytanej wiadomości. Metoda decode_image() jest odpowiedzialna za odczytanie z obrazu ukrytej w nim wiadomości w postaci bitowej i przedstawiona zostanie bardziej szczegółowo w dalszej części strony. Następnie zadeklarowana zostaje tablica o nazwie text. Następnie w pętli każdemu elementowi tablicy text przypisanych zostaje kolejnych 8 bitów odczytanej wiadomości. Każdy 8 bitowy element zamieniany jest na postać dziesiętną, a następnie konwertowany do odpowiadającemu danej liczbie całkowitej znakowi i dodawany do finalText. Otrzymany w ten sposób tekst wyświetlany jest w polu tekstowym programu. W przypadku, gdy w wybranym pliku graficznym nie została ukryta żadna wiadomość lub użytkownik nie wybrał pliku, z którego ma zostać odczytana wiadomość zostanie wyświetlony odpowiedni komunikat.
Metoda decode_image()
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 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
private int[] decode_image() { int addon_position=0; int[] length = new int[32]; int move_bits = 0; int h=0; int w=0; checkLengthLoop: for (int i = 0; i < imageLoaded.getHeight(); i++, h++) { for (int j = 0; j < imageLoaded.getWidth(); j++, w++) { int pixel = imageLoaded.getRGB(j, i); int alpha = (pixel >> 24) & 0xff; int red = (pixel >> 16) & 0xff; int green = (pixel >> 8) & 0xff; int blue = (pixel) & 0xff; if(addon_position>=32) break checkLengthLoop; length[addon_position] = red >>> move_bits & 1; addon_position++; if(addon_position>=32) break checkLengthLoop; length[addon_position] = green >>> move_bits & 1; addon_position++; if(addon_position>=32) break checkLengthLoop; length[addon_position] = blue >>> move_bits & 1; addon_position++; }} String str_length = ""; for(int j=0; j<32; j++){ str_length+= Integer.toString(length[j]); } int msg_len = Integer.parseInt(str_length, 2)-33; int[] result = new int[msg_len]; addon_position=0; if(w+1 >=imageLoaded.getWidth()) { w=0; h++; } else w++; outerLoop: for (int i = h; i < imageLoaded.getHeight(); i++) { for (int j = w; j < imageLoaded.getWidth(); j++) { int pixel = imageLoaded.getRGB(j, i); int alpha = (pixel >> 24) & 0xff; int red = (pixel >> 16) & 0xff; int green = (pixel >> 8) & 0xff; int blue = (pixel) & 0xff; if(addon_position>=msg_len) break outerLoop; result[addon_position] = red >>> move_bits & 1; addon_position++; if(addon_position>=msg_len) break outerLoop; result[addon_position] = green >>> move_bits & 1; addon_position++; if(addon_position>=msg_len) break outerLoop; result[addon_position] = blue >>> move_bits & 1; addon_position++; }} return result; } |
Metoda ta odpowiedzialna jest za odczytanie z pliku graficznego ukrytej w nim wiadomości. W pierwszej części metody następuje sczytanie wartości RGB kolejnych pikseli i odczytanie z ich składowych red, green, blue najmniej znaczących bitów. Pętla ta jest wykonywana do momentu sczytania pierwszych 32 bitów, które informują o długości ukrytej w obrazie wiadomości. Następnie odczytana długość wiadomości wykorzystywana jest do określenia rozmiaru nowo stworzonej tablicy nazwie result, w której zapisana zostanie postać bitowa wiadomości. Ostatnia część metody sczytuje wartości RGB kolejnych pikseli i zapisuje najmniej znaczące bity jako kolejne elementy tablicy result. Jako wynik metody zwracana jest tablica result z odczytaną z pliku wiadomością.