I've implemented a Huffman coding in java, that works on byte data from an input file. However, it only works when compressing ascii. I'd like to extend it so that it can deal with characters that are larger than 1 byte long, but I'm not sure how to do this exactly.
private static final int CHARS = 256;
private int [] getByteFrequency(File f) throws FileNotFoundException {
try {
FileInputStream fis = new FileInputStream(f);
byte [] bb = new byte[(int) f.length()];
int [] aa = new int[CHARS];
if(fis.read(bb) == bb.length) {
System.out.print("Uncompressed data: ");
for(int i = 0; i < bb.length; i++) {
System.out.print((char) bb[i]);
aa[bb[i]]++;
}
System.out.println();
}
return aa;
} catch (FileNotFoundException e) { throw new FileNotFoundException();
} catch (IOException e) { e.printStackTrace(); }
return null;
}
For example, this is what I'm using to get the frequency of the characters in the file, and obviously it only works on a single byte. If I give it a unicode file, I get an ArrayIndexOutOfBoundsException at aa[bb[i]]++;, and i is normally a negative number. I know this is because aa[bb[i]]++; is only looking at one byte, and the unicode character will be more than one, but I'm not sure on how I can change it.
Can anybody give me some pointers?
Try the following:
private static final int CHARS = 256;
private int [] getByteFrequency(File f) throws FileNotFoundException {
try {
FileInputStream fis = new FileInputStream(f);
byte [] bb = new byte[(int) f.length()];
int [] aa = new int[CHARS];
if(fis.read(bb) == bb.length) {
System.out.print("Uncompressed data: ");
for(int i = 0; i < bb.length; i++) {
System.out.print((char) bb[i]);
aa[((int)bb[i])&0xff]++;
}
System.out.println();
}
return aa;
} catch (FileNotFoundException e) { throw new FileNotFoundException();
} catch (IOException e) { e.printStackTrace(); }
return null;
}
If i'm correct (I haven't tested it), your problem is that byte is a SIGNED value in java. The cast to integer + masking it to 0xff should handle it correctly.
Related
I have been trying to hide an image in another image(both of same type) by making changes in the pixels.But it gives an error like this:
Exception in thread "main" java.lang.NumberFormatException: For input
string: "010010101101111111"
at java.lang.NumberFormatException.forInputString(Unknown Source)
at java.lang.Integer.parseInt(Unknown Source)
at java.lang.Integer.parseInt(Unknown Source)
at Image.main(Image.java:160)**
The code is shown as below:
public class Image {
public static void main(String argv[]) throws Exception
{
String imageFile1 = "C:/Users/Desktop/1.jpg";
String imageFile2 = "C:/Users/Desktop/2.jpg";
File file1 = new File(imageFile1);
FileInputStream fis1 = null;
try {
fis1 = new FileInputStream(imageFile1);
} catch (FileNotFoundException e2) {
// TODO Auto-generated catch block
e2.printStackTrace();
}
File file2 = new File(imageFile2);
FileInputStream fis2 = null;
try {
fis2 = new FileInputStream(imageFile2);
} catch (FileNotFoundException e2) {
// TODO Auto-generated catch block
e2.printStackTrace();
}
BufferedImage oimage1 = ImageIO.read(file1);
BufferedImage oimage2 = ImageIO.read(file2);
ByteArrayOutputStream baos1=new ByteArrayOutputStream();
byte[] buf1 = new byte[1024];
try {
for (int readNum; (readNum = fis1.read(buf1)) != -1;) {
baos1.write(buf1, 0, readNum);
}
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
ByteArrayOutputStream baos2=new ByteArrayOutputStream();
byte[] buf2 = new byte[1024];
try {
for (int readNum; (readNum = fis2.read(buf1)) != -1;) {
baos2.write(buf2, 0, readNum);
}
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
final byte[] imageInByte1 = baos1.toByteArray();
final int size1 = imageInByte1.length;
final byte[] imageInByte2 = baos2.toByteArray();
final int size2 = imageInByte2.length;
int width1 = oimage1.getWidth();
int height1 = oimage1.getHeight();
int pixel1 = 0;
int red1,green1,blue1;
int width2 = oimage2.getWidth();
int height2 = oimage2.getHeight();
int pixel2=0,red2,green2,blue2;
final BufferedImage newimg1 = new BufferedImage(width1, height1, BufferedImage.TYPE_INT_ARGB);
final BufferedImage newimg2 = new BufferedImage(width2, height2, BufferedImage.TYPE_INT_ARGB);
for (int i = 0; i < width1; i++)
for (int j = 0; j < height1; j++) {
//scan through each pixel
pixel1 = oimage1.getRGB(i, j);
pixel2 = oimage2.getRGB(i, j);
//for red
String redpix1=Integer.toBinaryString(pixel1);
String binaryred1 = redpix1.substring(20,23);
String redpix2=Integer.toBinaryString(pixel2);
String binaryred2=redpix2.substring(20,23);
String newred= binaryred1 + binaryred2;
//for green
String greenpix1=Integer.toBinaryString(pixel1);
String binarygreen1=greenpix1.substring(12,15);
String greenpix2=Integer.toBinaryString(pixel2);
String binarygreen2=greenpix2.substring(12,15);
String newgreen= binarygreen1 + binarygreen2;
//for blue
String bluepix1=Integer.toBinaryString(pixel1);
String binaryblue1=bluepix1.substring(4,7);
String bluepix2=Integer.toBinaryString(pixel2);
String binaryblue2=bluepix2.substring(4,7);
String newblue= binaryblue1 + binaryblue2;
//combining the new values
String spixel=newred +newgreen + newblue;
int newpixel = Integer.parseInt(spixel);
newimg2.setRGB(i,j,newpixel);
}
JFrame f =new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.getContentPane().add(new JLabel(new ImageIcon(newimg2)));
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
}
The size of 1.jpg is greater than size of 2.jpg.
Can this code be modified to get output? or is any another easy way to embed the image?
The error message isn’t very explanatory. The NumberFormatExceptiondocumentation isn’t either in this case. It says:
Thrown to indicate that the application has attempted to convert a
string to one of the numeric types, but that the string does not have
the appropriate format.
What happens is an int overflow. The largest int you can have is 2 147 483 647 (10 digits), so 10010101101111111 (17 digits after I removed the leading 0) is way too large. This problem shows as a NumberFormatException.
If you intended that to be a binary number, use Integer.parseInt(spixel, 2) to indicate radix 2 (that is, binary). Then you should be able to parse it since up to 31 binary digits fit in an ìnt (not 32 because it’s signed, so there’s a sign bit).
There is a similar question to this one: What is a NumberFormatException and how can I fix it? However, while the accepted answer to that one does mention overflow (pretty deep down in the answer), it doesn’t cover trying to parse a string with the wrong radix. Still you may want to read through the question and answers and learn.
I seem to have reached a dead-end. I try to display the first int values of a 32 bits per sample, 2 channels .wav file with the following code :
public static void main(String[] args) {
File inFile = new File("C:/.../1.wav");
FileInputStream fstream = null;
try {
fstream = new FileInputStream(inFile);
} catch (FileNotFoundException e1) {
e1.printStackTrace();
}
BufferedInputStream in = new BufferedInputStream(fstream);
byte[] bytes = null;
try {
bytes = IOUtils.toByteArray(in);
} catch (IOException e) {
e.printStackTrace();
}
ByteBuffer wrapped = ByteBuffer.wrap(bytes);
int num = wrapped.getInt();
System.out.println(num);
}
But i'm not sure what the number displayed means. I get "1380533830", first of all if I understood correctly is the int value is the not from 0 to 2^32-1 but from -2^31 to 2^31 - 1.
If that's the case it should be the first int from the first channel, but when I do an audioread in matlab I get a completely different value : "-1376256". I tried to see if "1380533830" was a value somewhere in my audioread but it wasn't so I don't know what I did.
I'm decrypting a regular text file and encountering an issue I cant solve,
My code works like this,
I receive a txt file with letters,numbers and the signs + and / (which is Radix64)
I then read 12 chars from the file, convert them into a string, and then using base64.decoder to decode the text into an 8 byte array.
Using system.out.print on both the byte array and on the string I build shows me that the reading was correct and I got what I needed from the file.
Now I shift the bytes a few times to the right or left and want to write the byte array to a new file which is the decrypted message.
I'm using FileOutputStream to write to a new file, now comes the problem, I open the file and its all Chinese letters.
I have no clue how is that even possible since the only thing I do is write bytes to a file.
I tried to find information regarding this subject without any success, only related topic was python/ruby related and was stating that its a UTF-8/UTF-16 problem but no answers to how to fix it.
Any help would be appreciated, and if posting parts of my code will help please let me know what exactly is needed.
private static void Decryption() {
InputStream byteReader = null;
FileOutputStream fop = null;
int byteByByte = 0;
char[] radixToByte = new char[12];
byte[] block = new byte[8];
byte[] decryptedBlock = new byte[8];
long key = 0;
//the file which will contain the plain text will be p.txt in the same directory c.txt is
try {
fop = new FileOutputStream(new File(fileName.substring(0, fileName.length()-5)+"p.txt"));
} catch (FileNotFoundException e) {
System.out.println("File was not found");
e.printStackTrace();
}
//open key file and read the key.
try {
byteReader = new FileInputStream(keyFileName);
} catch (FileNotFoundException e) {
System.out.println("File was not found");
System.exit(0);
}
//reading 56 bits in radix format and building the key accordingly
char[] keyByteArray = new char[12];
for(int k = 0; k < 12; k++){
try {
byteByByte = byteReader.read();
} catch (IOException e) {
e.printStackTrace();
}
keyByteArray[k] = (char) byteByByte;
}
Base64.Decoder decoder = Base64.getDecoder();
byte[] decodedByteArray = decoder.decode(new String(keyByteArray));
for(int k = 0; k < 7; k++){
key <<= 8;
key |= (decodedByteArray[k] & 0x00000000000000FF);
}
//open cipher text to decrypt.
try {
byteReader = new FileInputStream(fileName);
} catch (FileNotFoundException e) {
System.out.println("File was not found");
System.exit(0);
}
//while haven't reached end of cipher text message keep reading byte by byte and decrypting
//them block by block (each block 64 bits).
while(isFileReadingFinished == false){
for(int i = 0; i < 12; i++){
try {
byteByByte = byteReader.read();
} catch (IOException e) {
e.printStackTrace();
}
if(byteByByte == -1){
isFileReadingFinished = true;
break;
}
radixToByte[i] = (char)byteByByte;
}
//this is the block after radix but still decrypted so we will save it for CBC
block = decoder.decode(new String(radixToByte));
//encrypt via feistel
decryptedBlock = feistel(block, key);
//after decryption we still need to xor with previous encrypted data or IV.
for(int i = 0; i < 8; i++){
decryptedBlock[i] = (byte) (decryptedBlock[i] ^ initializationVector[i]);
}
//next decrypted text will need to be xored with the current encrypted text after decryption.
for(int i = 0; i < 8; i++){
initializationVector[i] = block[i];
}
try {
fop.write(decryptedBlock);
fop.flush();
} catch (IOException e1) {
e1.printStackTrace();
}
}
try {
fop.close();
} catch (IOException e) {
e.printStackTrace();
}
}
So I use the following methods
(File is converted to Byte Array through 'convertFileToByteArray()', then written to .txt file by 'convertByteArrayToBitTextFile()'
to convert any kind of file into a Binary Text file (and by that I mean only 1's and 0's in human readable form.)
public static byte[] convertFileToByteArray(String path) throws IOException
{
File file = new File(path);
byte[] fileData;
fileData = new byte[(int)file.length()];
FileInputStream in = new FileInputStream(file);
in.read(fileData);
in.close();
return fileData;
}
public static boolean convertByteArrayToBitTextFile(String path, byte[] bytes)
{
String content = convertByteArrayToBitString(bytes);
try
{
PrintWriter out = new PrintWriter(path);
out.println(content);
out.close();
return true;
}
catch (FileNotFoundException e)
{
return false;
}
}
public static String convertByteArrayToBitString(byte[] bytes)
{
String content = "";
for (int i = 0; i < bytes.length; i++)
{
content += String.format("%8s", Integer.toBinaryString(bytes[i] & 0xFF)).replace(' ', '0');
}
return content;
}
Edit: Additional Code:
public static byte[] convertFileToByteArray(String path) throws IOException
{
File file = new File(path);
byte[] fileData;
fileData = new byte[(int)file.length()];
FileInputStream in = new FileInputStream(file);
in.read(fileData);
in.close();
return fileData;
}
public static boolean convertByteArrayToBitTextFile(String path, byte[] bytes)
{
try
{
PrintWriter out = new PrintWriter(path);
for (int i = 0; i < bytes.length; i++)
{
out.print(String.format("%8s", Integer.toBinaryString(bytes[i] & 0xFF)).replace(' ', '0'));
}
out.close();
return true;
}
catch (FileNotFoundException e)
{
return false;
}
}
public static boolean convertByteArrayToByteTextFile(String path, byte[] bytes)
{
try
{
PrintWriter out = new PrintWriter(path);
for(int i = 0; i < bytes.length; i++)
{
out.print(bytes[i]);
}
out.close();
return true;
}
catch (FileNotFoundException e)
{
return false;
}
}
public static boolean convertByteArrayToRegularFile(String path, byte[] bytes)
{
try
{
PrintWriter out = new PrintWriter(path);
for(int i = 0; i < bytes.length; i++)
{
out.write(bytes[i]);
}
out.close();
return true;
}
catch (FileNotFoundException e)
{
return false;
}
}
public static boolean convertBitFileToByteTextFile(String path)
{
try
{
byte[] b = convertFileToByteArray(path);
convertByteArrayToByteTextFile(path, b);
return true;
}
catch (IOException e)
{
return false;
}
}
I do this to try methods of compression on a very fundamental level, so please let's not discuss why use human-readable form.
Now this works quite well so far, however I got two problems.
1)
It takes foreeeever (>20 Minutes for 230KB into binary text). Is this just a by-product of the relatively complicated conversion or are there other methods to do this faster?
2) and main problem:
I have no idea how to convert the files back to what they used to be. Renaming from .txt to .exe does not work (not too surprising as the resulting file is two times larger than the original)
Is this still possible or did I lose Information about what the file is supposed to represent by converting it to a human-readable text file?
If so, do you know any alternative that prevents this?
Any help is appreciated.
The thing that'll cost you most time is the construction of an ever increasing String. A better approach would be to write the data as soon as you have it.
The other problem is very easy. You know that every sequence of eight characters ('0' or '1') was made from a byte. Hence, you know the values of each character in an 8-character block:
01001010
^----- 0*1
^------ 1*2
^------- 0*4
^-------- 1*8
^--------- 0*16
^---------- 0*32
^----------- 1*64
^------------ 0*128
-----
64+8+2 = 74
You only need to add the values where an '1' is present.
You can do it in Java like this, without even knowing the individual bit values:
String sbyte = "01001010";
int bytevalue = 0;
for (i=0; i<8; i++) {
bytevalue *= 2; // shifts the bit pattern to the left 1 position
if (sbyte.charAt(i) == '1') bytevalue += 1;
}
Use StringBuilder to avoid generating enormous numbers of unused String instances.
Better yet, write directly to the PrintWriter instead of building it in-memory at all.
Loop through every 8-character subsequence and call Byte.parseByte(text, 2) to parse it back to a byte.
i convert a mp3 file into byte array and i read from byte array but it shows null pointer exception on line number 15
my code:
public class MainClass {
static byte[] bytesarray = null;
public static void main(String args[]) {
try {
FileInputStream fis = new FileInputStream("D:\\taxi.mp3");
try {
fis.read(bytesarray, 0, 32);
System.out.println(bytesarray.length);
} catch (IOException e) {
e.printStackTrace();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
ByteArrayInputStream in = new ByteArrayInputStream(bytesarray);
for (int i = 0; i < 32; i++) {
int c;
while ((c = in.read()) != -1) {
if (i == 0) {
System.out.print((char) c);
} else {
System.out.print(Character.toUpperCase((char) c));
}
}
System.out.println();
}
}
}
static byte[] bytesarray = new byte[32]; should do the work, you didn't initialize your array...
See the documentation of read.
static byte[] bytesarray = new byte[32];