Reputation: 145
I have an image which is stored as a byte[] array, and I want to flip the image vertically before writing the bytes to disk elsewhere.
The image bytes come from a compressed jp2 image file. I've looked into implementing something like Flip image stored as a byte[] array, but I'm not working in android and don't have access to BitmapFactory. I've also looked into converting the byte array to a BufferedImage first, then flipping it, but the height and width of the image isn't known in the current context (EDIT: I've modified the code so the height and width are now known).
Is there a way to do this just with strict array manipulation?
EDIT: Attempted flip code
public static byte[] flip(byte[] imageBytes) {
//separate out the sub arrays
byte[] holder = new byte[imageBytes.length];
byte[] subArray = new byte[dimWidth];//dimWidth is the image width, or number of matrix columns
int subCount = 0;
for (int i = 0; i < imageBytes.length; i++) {
subArray[subCount] = imageBytes[i];
subCount++;
if (i% dimWidth == 0) {
subArray = reverse(subArray);
if (i == (dimWidth)) {
holder = subArray;
} else {
holder = concat(holder, subArray);
}
subCount = 0;
subArray = new byte[dimWidth];
}
}
subArray = new byte[dimWidth];
System.arraycopy(imageBytes, imageBytes.length - dimWidth, subArray, 0, subArray.length);
holder = concat(holder, subArray);
imageBytes = holder;
return imageBytes;
}
Upvotes: 5
Views: 1497
Reputation: 15881
I've also looked into converting the byte array to a
BufferedImage
first, then flipping it, but the height and width of the image isn't known in the current context.
You could just check the height & width directly from the header section of the JP2 file bytes.
import java.io.IOException;
import java.io.FileInputStream;
import java.io.File;
import java.nio.ByteBuffer;
import javax.xml.bind.DatatypeConverter;
public class parse_Header_JP2
{
static File myFile; static FileInputStream fileInStream = null;
static byte[] myBytes; static String myString = "";
static int myNum = 0; static int myWidth = 0; static int myHeight = 0;
static ByteBuffer byteBuff;
public static void main(String[] args)
{
myFile = new File("c:/test/image.jp2");
myBytes = getBytes_Header_JP2(myFile);
checkBytes_Header_JP2(myBytes); //# update myWidth & myHeight
//# Shows HEX of whole bytearray
System.out.println("First 64 bytes (as HEX) : \n" + bytesToHex( myBytes ) );
}
private static byte[] getBytes_Header_JP2(File file)
{
myBytes = new byte[64]; //will hold first 64 bytes of file as header bytes
try
{
//# convert file into array of bytes
fileInStream = new FileInputStream(file);
fileInStream.read(myBytes, 0, 64); //# Read only first 64 bytes
fileInStream.close();
}
catch (Exception e) { e.printStackTrace(); } //# error catching
byteBuff = ByteBuffer.wrap(myBytes); //associate ByteBuffer with bytes
return myBytes;
}
public static void checkBytes_Header_JP2(byte[] bytes)
{
int offset = 0; myHeight = 0; myWidth = 0; // resets
while(true)
{
//# set as byte value reading from offset
myNum = bytes[offset]; myString = Integer.toHexString(myNum).toUpperCase();
//# Check byte as : Hex value
System.out.println("Byte Value at [" + offset + "] : " + decimalToHex(myNum) );
//# Check byte as : Decimal value
//System.out.println("Byte Value at [" + offset + "] : " + myNum );
//# Find byte 0x69 (or Decimal = 105) which is letter "i" from "ihdr"
if (myNum == 0x69) //# if "i" is found at this offset within bytes
{
//# From this offset check if reading 4 bytes gives "ihdr" (as bytes 69-68-64-72)
if ( byteBuff.getInt(offset) == 0x69686472 ) //# if the 4 bytes make "ihdr"
{
System.out.println("found \"ihdr\" section at offset : " + offset );
//# extract Width or Height from this offset
myHeight = byteBuff.getInt(offset+4); //# +4 from "ihdr" is Height entry
myWidth = byteBuff.getInt(offset+8); //# +8 from "ihdr" is Width entry
//# check values
System.out.println("Image Width : " + myWidth);
System.out.println("Image Height : " + myHeight);
break; //# end the While loop (otherwise runs forever)
}
}
offset++; //# increment offset during While loop process
}
}
//# Convert byte values to Hex string for checking
private static String bytesToHex(byte[] bytes)
{ myString = ""; myString = DatatypeConverter.printHexBinary(bytes); return myString; }
private static int bytesToNumber( ByteBuffer input ) //throws IOException
{ input.rewind(); myNum = input.getInt(); return myNum; }
private static String decimalToHex(int input)
{
input = input & 0xFF; myString = Integer.toHexString(input);
if(myString.length() == 1) {myString="0"+myString;}
return myString.toUpperCase();
}
} //end Class
Upvotes: 0
Reputation: 145
Nevermind guys, I got it working. I just had to flip the high and low bytes BEFORE interleaving them into the final array. To any with the same problem as me, use the above flip function on your high and low byte arrays separately before interleaving them.
Thank you for your help!
Upvotes: 1