java - how to end the nested loop -
i have code, trying encoding message in images using least significant bit method. can't figure out how end encoding of message when there no message encode left.
it continues until end of end of loop.
i tried counters limit. same did in decoding part no avail that's why removed it.
i included these methods because used , can used contain counters identify if message done encoding , can stop iterating
encoding , decoding in constructor.
public class steganography { public static steganographygui gui; public static string binarizedmessage = "", encodedmessage = "", decodedmessage = ""; public static int count = 0, limit = 0; public static bufferedimage image; public static int width, height, numlsb; public steganography() { if(gui.isencode()){ try { string messagetobehidden = gui.getmessage(); binarizedmessage = stringtobinary(messagetobehidden); file input = new file(gui.getpath()); image = imageio.read(input); width = image.getwidth(); height = image.getheight(); gui.appendstatus("file name: " + gui.getfilename() + "\nwidth: " + width + "\nheight: " + height + "\nlsb: " + gui.getselectedlsb()); numlsb = gui.getselectedlsb(); //encoding for(int = 0; < height; i++){ for(int j = 0; j < width; j++){ color c = new color(image.getrgb(j, i)); int red = binarytointeger(insertmessage(integertobinary((int)(c.getred())),numlsb)); int green = binarytointeger(insertmessage(integertobinary((int)(c.getgreen())),numlsb)); int blue = binarytointeger(insertmessage(integertobinary((int)(c.getblue())),numlsb)); color newcolor = new color(red,green,blue); image.setrgb(j,i,newcolor.getrgb()); } } gui.appendstatus("binarized message is: " + binarizedmessage); file output = new file(gui.getoutput()+"lossy.jpg"); imagewriter jpgwriter = imageio.getimagewritersbyformatname("jpg").next(); imagewriteparam jpgwriteparam = jpgwriter.getdefaultwriteparam(); jpgwriteparam.setcompressionmode(imagewriteparam.mode_explicit); jpgwriteparam.setcompressionquality(1f); fileimageoutputstream outputstream = new fileimageoutputstream(output); //for example, fileimageoutputstream jpgwriter.setoutput(outputstream); iioimage outputimage = new iioimage(image, null, null); jpgwriter.write(null, outputimage, jpgwriteparam); jpgwriter.dispose(); file output2 = new file(gui.getoutput()+"lossless.jpg"); imageio.write(image, "png", output2); gui.appendstatus("message \""+ messagetobehidden +"\" encoded in "+ gui.getfilename() +".\noutput files are: " + gui.getoutput() + "lossy.jpg \n\t"+ gui.getoutput() + "lossless.jpg"); } catch (exception e) {} } else{ file input = new file(gui.getpath()); string encodeddata = ""; try { image = imageio.read(input); } catch (ioexception ex) {} width = image.getwidth(); height = image.getheight(); gui.appendstatus("file name: " + gui.getfilename() + "\nwidth: " + width + "\nheight: " + height + "\nlsb: " + gui.getselectedlsb()); numlsb = gui.getselectedlsb(); string edata = ""; //decoding for(int = 0; < height; i++){ for(int j = 0; j < width; j++){ color c = new color(image.getrgb(j, i)); encodeddata += getlsb(integertobinary((int)(c.getred())),numlsb); encodeddata += getlsb(integertobinary((int)(c.getgreen())),numlsb); encodeddata += getlsb(integertobinary((int)(c.getblue())),numlsb); if(limit >= 8 * numlsb){ break; } } } int counter = 0; while(counter * 8 < encodeddata.length()){ int index = counter * 8; string str = encodeddata.substring(index, index + 8); edata += str; if(!str.equals("00000000")){ encodedmessage += new character((char)integer.parseint(str, 2)).tostring(); counter++; } else{ edata = edata.substring(0,edata.length()-8); break; } } gui.appendstatus("data decoded was: \"" + edata + "\"."); gui.appendstatus("message decoded was: \"" + encodedmessage + "\"."); gui.appendstatus("number of characters: " + counter); } reinitialize(); } public static void reinitialize(){ binarizedmessage = encodedmessage = decodedmessage = ""; count = limit = width = height = numlsb = 0; } public static string stringtobinary(string s){ byte[] bytes = s.getbytes(); // http://stackoverflow.com/questions/917163/convert-a-string-like-testing123-to-binary-in-java stringbuilder binary = new stringbuilder(); (byte b : bytes) { int val = b; (int = 0; < 8; i++){ binary.append((val & 128) == 0 ? 0 : 1); val <<= 1; } } return binary.tostring(); } public static string integertobinary(int i){ return string.format("%8s", integer.tobinarystring(i)).replace(' ', '0'); //http://stackoverflow.com/questions/21856626/java-integer-to-binary-string } public static int binarytointeger(string s){ return integer.parseint(s, 2); //http://stackoverflow.com/questions/7437987/how-to-convert-binary-string-value-to-decimal } //http://stackoverflow.com/questions/10178980/how-to-convert-a-binary-string-to-a-base-10-integer-in-java public static string clearlsb(string s, int x){ stringbuilder result = new stringbuilder(s); //http://stackoverflow.com/questions/6952363/java-replace-a-character-at-a-specific-index-in-a-string (int = 8 - x; < 8; i++){ result.setcharat(i, '0'); } return result.tostring(); //http://www.tutorialspoint.com/java/lang/stringbuilder_tostring.htm } public static string insertmessage(string s, int x){ string result = clearlsb(s, x); stringbuilder temp = new stringbuilder(result); (int = 8 - x; < 8; i++){ if(count < binarizedmessage.length()) temp.setcharat(i, binarizedmessage.charat(count++)); } return temp.tostring(); } public static string getlsb(string s, int x){ string result = ""; (int = 8 - x; < 8; i++){ result += s.charat(i); if(s.charat(i) == '0') limit += 1; else limit = 0; } return result; } public static string binarytotext(string s){ stringbuilder sb = new stringbuilder(); count = 0; while(count<s.length()){ stringbuilder sb2 = new stringbuilder(); (int = 0; < 8; i++){ if(count<s.length()) sb2.append(s.charat(count++)); else sb2.append('0'); break; } //binary char , append sb sb.append((char)integer.parseint( sb.tostring(), 2 ) ); } return sb.tostring(); } public static void main(string[] args) { gui = new steganographygui(); gui.setvisible(true); } }
edit:
seems first problem fixed created problem.
now i've changed decoding , encoding based on answer below reti43, cant datacomparison work. tried applying decoding lines pointed out fail encoded data in picture.
here original datacomparison
import java.awt.color; import java.awt.image.bufferedimage; import java.io.file; import java.util.arrays; import javax.imageio.imageio; public class datacomparison { public static datacomparisongui gui; public static bufferedimage image, image2; public static int width, height, lsb, limit = 0; public static string lossydata = "", losslessdata = "", lsdata = "", lydata = ""; public static string lossymessage = "", losslessmessage = ""; public static int[][][] clossydata, closslessdata; public datacomparison(){ lsb = gui.getlsb(); try{ file lossy = new file(gui.getlossypath()); file lossless = new file(gui.getlosslesspath()); image = imageio.read(lossy); image2 = imageio.read(lossless); width = image.getwidth(); height = image.getheight(); clossydata = new int[height][width][3]; closslessdata = new int[height][width][3]; for(int = 0; < height; i++){ for(int j = 0; j < width; j++){ color c = new color(image.getrgb(j, i)); color c2 = new color(image2.getrgb(j, i)); lossydata += getlsb(integertobinary((int)(c.getred())),lsb); lossydata += getlsb(integertobinary((int)(c.getgreen())),lsb); lossydata += getlsb(integertobinary((int)(c.getblue())),lsb); losslessdata += getlsb(integertobinary((int)(c2.getred())),lsb); losslessdata += getlsb(integertobinary((int)(c2.getgreen())),lsb); losslessdata += getlsb(integertobinary((int)(c2.getblue())),lsb); clossydata[i][j][0] = c.getred(); clossydata[i][j][1] = c.getgreen(); clossydata[i][j][2] = c.getblue(); closslessdata[i][j][0] = c2.getred(); closslessdata[i][j][1] = c2.getgreen(); closslessdata[i][j][2] = c2.getblue(); if(limit >= 8 * lsb){ break; } } } int counter = 0; while(counter * 8 < losslessdata.length()){ int index = counter * 8; string str = lossydata.substring(index, index + 8); string str2 = losslessdata.substring(index, index + 8); lydata += str; lsdata += str2; if(!str2.equals("00000000")){ lossymessage += new character((char)integer.parseint(str, 2)).tostring(); losslessmessage += new character((char)integer.parseint(str2, 2)).tostring(); counter++; } else{ lydata = lydata.substring(0,lydata.length()-8); lsdata = lsdata.substring(0,lsdata.length()-8); break; } } int = 0, lostbits = 0; while(i < lydata.length()){ if(lydata.charat(i) != lsdata.charat(i)){ lostbits++; } i++; } gui.appendstatus("data decoded (lossless):\n\"" + lsdata + "\"."); gui.appendstatus("data decoded (lossy):\n\"" + lydata + "\"."); gui.appendstatus("number of lsb: " + lsb); gui.appendstatus("number of bits (hidden message): " + counter * 8); gui.appendstatus("number of lost bits (hidden message): " + lostbits); float z = ((lostbits*100)/(counter*8)); string percentage = string.format("%.04f", z); gui.appendstatus("percentage of lost bits (hidden message): " + percentage + "%"); gui.appendstatus("message decoded (lossless): \"" + losslessmessage + "\"."); gui.appendstatus("message decoded (lossy): \"" + lossymessage + "\"."); gui.appendstatus("number of characters: " + counter); int counterr = 0, counterg = 0, counterb = 0; for(int p = 0; p < height; p++){ for(int q = 0; q < width; q++){ if(closslessdata[p][q][0] != clossydata[p][q][0]){ counterr++; } else if(closslessdata[p][q][1] != clossydata[p][q][1]){ counterg++; } else if(closslessdata[p][q][2] != clossydata[p][q][2]){ counterb++; } } } gui.appendstatus("total rgb values: " + width * height * 3); gui.appendstatus("altered red values: " + counterr); gui.appendstatus("altered green values: " + counterg); gui.appendstatus("altered blue values: " + counterb); gui.appendstatus("total altered values: " + (counterr + counterg + counterb)); z = ((counterr + counterg + counterb)*10000)/(width * height * 3); percentage = string.format("%.02f", z/100); gui.appendstatus("percentage altered values: " + percentage + "%"); reinitialize(); } catch (exception e) {} } public static void reinitialize(){ losslessdata = lossydata = lsdata = lydata = losslessmessage = lossymessage = ""; limit = width = height = lsb = 0; arrays.fill(clossydata, 0); arrays.fill(closslessdata, 0); } public static string integertobinary(int i){ return string.format("%8s", integer.tobinarystring(i)).replace(' ', '0'); //http://stackoverflow.com/questions/21856626/java-integer-to-binary-string } public static string getlsb(string s, int x){ string result = ""; (int = 8 - x; < 8; i++){ result += s.charat(i); if(s.charat(i) == '0') limit += 1; else limit = 0; } return result; } public static void main(string[] args) { // todo code application logic here gui = new datacomparisongui(); gui.setvisible(true); } }
the code above working based on original encoding/decoding algorithm. 1 doesnt stop loop. tried editing code , applying new decoding algorithm cant make work.
encoding changes
first things first, encoding part need change following line
binarizedmessage = stringtobinary(messagetobehidden);
to
binarizedmessage = stringtobinary(messagetobehidden) + "00000000";
this because in extraction, end of message reached when find 8 0s in row.
now, terminating encoding sequence, need modify loops accordingly.
encoding: for(int = 0; < height; i++){ for(int j = 0; j < width; j++){ color c = new color(image.getrgb(j, i)); int red = binarytointeger(insertmessage(integertobinary((int)(c.getred())),numlsb)); int green = binarytointeger(insertmessage(integertobinary((int)(c.getgreen())),numlsb)); int blue = binarytointeger(insertmessage(integertobinary((int)(c.getblue())),numlsb)); color newcolor = new color(red,green,blue); image.setrgb(j,i,newcolor.getrgb()); if (count == binarizedmessage.length()) break encoding; } }
the variable count
incremented every time embed bit in insertmessage
method. has reached value of binarizedmessage.length()
, stop embedding though called. so, need check whether have embedded bits every time access new pixel @ (i, j).
however, embedding may finished red color of pixel, calling insertmessage
green , blue, though not embed new, still clear lsbs of colors. so, let's modify insertmessage
prevent these unnecessary modifications.
public static string insertmessage(string s, int x){ string result; if (count < binarizedmessage.length()) { result = clearlsb(s, x); } else { result = s; } stringbuilder temp = new stringbuilder(result); (int = 8 - x; < 8; i++){ if(count < binarizedmessage.length()) temp.setcharat(i, binarizedmessage.charat(count++)); } return temp.tostring(); }
decoding changes
decoding: for(int = 0; < height; i++){ for(int j = 0; j < width; j++){ color c = new color(image.getrgb(j, i)); encodeddata += getlsb(integertobinary((int)(c.getred())),numlsb); if(limit >= 8) break decoding; encodeddata += getlsb(integertobinary((int)(c.getgreen())),numlsb); if(limit >= 8) break decoding; encodeddata += getlsb(integertobinary((int)(c.getblue())),numlsb); if(limit >= 8) break decoding; } }
every time extract new bits color, use limit
variable check whether (at least) last 8 bits 0, signifying end of message. condition must checked after embedding in each color , not after blue. consider case end of message found after red, carrying on green , blue, come across 1 resets limit
.
finally, need change following block
int counter = 0; while(counter * 8 < encodeddata.length()){ int index = counter * 8; string str = encodeddata.substring(index, index + 8); edata += str; if(!str.equals("00000000")){ encodedmessage += new character((char)integer.parseint(str, 2)).tostring(); counter++; } else{ edata = edata.substring(0,edata.length()-8); break; } }
to
for (int index = 0; index < encodeddata.length()/8; index++) { string str = encodeddata.substring(8*index, 8*index+8); edata += str; encodedmessage += new character((char)integer.parseint(str, 2)).tostring(); }
because of way check last 8 bits being 0, consider message "hello world". that's 11 characters, 88 bits + 8 terminating message = 96 bits. however, binary "d" 01100100, once have extracted 94 bits, have come across 8 0s , break extracting sequence. if integer division of 94 8, whole number 11, number of characters of our message. convert first 88 bits characters , our job done.
this out of scope answer, piece of advice. consider clearing, modifying , extracting bits using bitwise operations and
, or
. it's more elegant since don't have convert integers strings , integers , provide minor, though not noticeable in case, performance improvements.