You have two problems in your program.
The first, as @Joop Eggen mentioned, is that you are not processing your input correctly.
In fact, Java does not promise you that even in the middle of a file you will read all 1024 bytes. It could just read 50 bytes and tell you that it reads 50 bytes, and then next time it will read more than 50 bytes.
Suppose you read 1024 bytes in the previous round. And now, in the current round, you are only reading 50. Now your byte array contains 50 new bytes, and the rest are old bytes from the previous read!
Therefore, you always need to copy the exact number of bytes copied to the new array and pass this to your encoding function.
So, to fix this specific problem, you need to do something like:
while ( ( r = imageInFile.read( buff)) > 0 ) { byte[] realBuff = Arrays.copyOf( buff, r ); String imageData = encodeImage(realBuff); ... }
However, this is not the only problem. Your real problem is the Base64 encoding itself.
What Base64 does is take your bytes, break them into 6-bit chunks, and then treat each of these fragments as a number between N 0 and 63. Then it takes the Nth character from its character table to represent that fragment.
But this means that it cannot simply encode one byte or two bytes, because the byte contains 8 bits, which means that one fragment of 6 bits and 2 remaining bits. Two bytes have 16 bits. These are 2 pieces of 6 bits and 4 remaining bits.
To solve this problem, Base64 always encodes 3 consecutive bytes. If the input is not evenly divided by three, it adds an extra zero bits .
Here is a small program that demonstrates the problem:
package testing; import java.util.Base64; public class SimpleTest { public static void main(String[] args) { // An array containing six bytes to encode and decode. byte[] fullArray = { 0b01010101, (byte) 0b11110000, (byte)0b10101010, 0b00001111, (byte)0b11001100, 0b00110011 }; // The same array broken into three chunks of two bytes. byte[][] threeTwoByteArrays = { { 0b01010101, (byte) 0b11110000 }, { (byte)0b10101010, 0b00001111 }, { (byte)0b11001100, 0b00110011 } }; Base64.Encoder encoder = Base64.getEncoder().withoutPadding(); // Encode the full array String encodedFullArray = encoder.encodeToString(fullArray); // Encode the three chunks consecutively StringBuilder encodedStringBuilder = new StringBuilder(); for ( byte [] twoByteArray : threeTwoByteArrays ) { encodedStringBuilder.append(encoder.encodeToString(twoByteArray)); } String encodedInChunks = encodedStringBuilder.toString(); System.out.println("Encoded full array: " + encodedFullArray); System.out.println("Encoded in chunks of two bytes: " + encodedInChunks); // Now decode the two resulting strings Base64.Decoder decoder = Base64.getDecoder(); byte[] decodedFromFull = decoder.decode(encodedFullArray); System.out.println("Byte array decoded from full: " + byteArrayBinaryString(decodedFromFull)); byte[] decodedFromChunked = decoder.decode(encodedInChunks); System.out.println("Byte array decoded from chunks: " + byteArrayBinaryString(decodedFromChunked)); } /** * Convert a byte array to a string representation in binary */ public static String byteArrayBinaryString( byte[] bytes ) { StringBuilder sb = new StringBuilder(); sb.append('['); for ( byte b : bytes ) { sb.append(Integer.toBinaryString(Byte.toUnsignedInt(b))).append(','); } if ( sb.length() > 1) { sb.setCharAt(sb.length() - 1, ']'); } else { sb.append(']'); } return sb.toString(); } }
So imagine my 6-byte array is your image file. And imagine that your buffer does not read 1024 bytes, but 2 bytes each time. This will be the encoding output:
Encoded full array: VfCqD8wz
Encoded in chunks of two bytes: VfAqg8zDM
As you can see, the encoding of the full array gave us 8 characters. Each group of three bytes is converted into four pieces of 6 bits, which, in turn, are converted to four characters.
But encoding three double-byte arrays gave you a string of 9 characters. This is a completely different line! Each group of two bytes was expanded to three pieces of 6 bits by filling with zeros. And since you did not request a registration, it only generates 3 characters without the extra = , which usually marks when the number of bytes is not divisible by 3.
Exiting the part of the program that decodes the 8-digit, correct encoded string is good:
Byte array decoded from full: [1010101,11110000,10101010,1111,11001100,110011]
But the result of trying to decode a 9-character invalid encoded string is:
Exception in thread "main" java.lang.IllegalArgumentException: Last unit does not have enough valid bits
at java.util.Base64 $ Decoder.decode0 (Base64.java:734)
at java.util.Base64 $ Decoder.decode (Base64.java=26)
at java.util.Base64 $ Decoder.decode (Base64.javahaps49)
at testing.SimpleTest.main (SimpleTest.java:34)
Not good! A good base64 string should always have a multiple of 4 characters, and we only have 9.
Since you selected a buffer size of 1024 that is not a multiple of 3, this problem will occur. You must encode several of the three bytes each time to create the correct string. So actually you need to create a buffer of size 3072 or something like that.
But because of the first problem, be very careful what you pass to the encoder. Because it always happens that you will read less than 3072 bytes. And then, if the number is not divided by three, the same problem will arise.