4

I have a requirement to read a Hex String with leading zeros which represents a JPEG file, from an xml file received and save it as an image file. The image data looks like

0000005000000050FF191818FF151715FF111413FF0E1...........................FF2A2322FF292221

In xml file The length of String between the tag is 51216 I read the Hex data in between the Photo tag as a String and Converted it to a byte[], and the using a FileOutputStream I am writing to a file. But when I try to open the image file it tells "the file appears to be damaged,corrupted or file is too large" I have tried many methods to save the image, but no success. I am listing the methods used below. Please help me out from this.

String photo="0000005000000050FF191818FF15"; //this is just a sample.The photo String actually contains the full Hex String which is 51216 long
//METHOD 1
    String[] v = photo.split(" ");
    byte[] arr = new byte[v.length];
    int x = 0;
    for(String val: v) {
        arr[x++] =  Integer.decode("0x" + val).byteValue();

    }
     FileOutputStream fos=new FileOutputStream("D:/Images/image6.jpg");
    fos.write(arr);
    fos.flush();
    fos.close();


  //METHOD 2
    byte[] arr = new byte[photo.length()/2];
    for ( int start = 0; start < photo.length(); start += 2 )
    {
        String thisByte = photo.substring(start, start+2);
        arr[start/2] = Byte.parseByte(thisByte, 16);
    }
    FileOutputStream fos=new FileOutputStream("D:/Images/image6.jpg");
    fos.write(arr);
    fos.flush();
    fos.close();


  //METHOD 3
    if ((photo.length() % 2) != 0)
        throw new IllegalArgumentException("Input string must contain an even number of characters");

    final byte result[] = new byte[photo.length()/2];
    final char enc[] = photo.toCharArray();
    for (int x = 0; x < enc.length; x += 2) 
    {
        StringBuilder curr = new StringBuilder(2);
        curr.append(enc[x]).append(enc[x + 1]);
        result[x/2] = (byte) Integer.parseInt(curr.toString(), 16);
    }
    FileOutputStream fos=new FileOutputStream("D:/Images/image6.jpg");
    fos.write(result);
    fos.flush();
    fos.close();


  //METHOD 4
    byte result[] = new byte[photo.length()/2];
    char enc[] = photo.toUpperCase().toCharArray();
    StringBuffer curr;
    for (int x = 0; x < enc.length; x += 2) 
    {
        curr = new StringBuffer("");
        curr.append(String.valueOf(enc[x]));
        curr.append(String.valueOf(enc[x + 1]));
        result[x] = (byte) Integer.parseInt(curr.toString(), 16);
    }
    FileOutputStream fos=new FileOutputStream("D:/Images/image6.jpg");
    fos.write(result);
    fos.flush();
    fos.close();


  //METHOD 5
    int len = photo.length();
    byte[] data = new byte[len / 2];
    for (int x = 0; x < len; x += 2)
    {
        data[x / 2] = (byte) ((Character.digit(photo.charAt(x), 16) << 4)
                             + Character.digit(photo.charAt(x+1), 16));
    }
    FileOutputStream fos=new FileOutputStream("D:/Images/image6.jpg");
    fos.write(data);
    fos.flush();
    fos.close();


  //METHOD 6
    byte[] bytes=new BigInteger(photo, 16).toByteArray();
    FileOutputStream fos=new FileOutputStream("D:/Images/image6.jpg");
    fos.write(bytes);
    fos.flush();
    fos.close();


  //METHOD 7
    byte[] bytes =DatatypeConverter.parseHexBinary(photo);
    FileOutputStream fos=new FileOutputStream("D:/Images/image6.jpg");
    fos.write(bytes);
    fos.flush();
    fos.close();


  //METHOD 8
     HexBinaryAdapter adapter = new HexBinaryAdapter();
    byte[] bytes = adapter.unmarshal(photo);
    FileOutputStream fos=new FileOutputStream("D:/Images/image6.png");
    fos.write(bytes);
    fos.flush();
    fos.close();


  //METHOD 9
    byte data[] = new byte[photo.length()/2];
    for(int x=0;i < photo.length();x+=2) {
        data[x/2] = (Integer.decode("0x"+photo.charAt(x)+photo.charAt(x+1))).byteValue();
    }
    FileOutputStream fos=new FileOutputStream("D:/Images/image6.jpg");
    fos.write(data);
    fos.flush();
    fos.close();


  //METHOD 10
    byte[] data = new byte[photo.length()/2];
    for (int x=0;i<photo.length()/2;x++) 
    {
        data[x] = (Integer.decode(
                "0x"+photo.substring(x*2, (x+1)*2))).byteValue();
    }
    FileOutputStream fos=new FileOutputStream("D:/Images/image6.jpg");
    fos.write(data);
    fos.flush();
    fos.close();


  //METHOD 11
    String hexVal ="0000005000000050FF";
    //String hexVal = "0123456789ABCDEF";
    byte[] out = new byte[photo.length() / 2];
    int n = photo.length();
    for( int x = 0; x < n; x += 2 ) {
        int hn = hexVal.indexOf( photo.charAt( x ) );
        int ln = hexVal.indexOf( photo.charAt( x + 1 ) );

        out[x/2] = (byte)( ( hn << 4 ) | ln );
    }
    FileOutputStream fos=new FileOutputStream("D:/Images/image6.jpg");
    fos.write(out);
    fos.flush();
    fos.close();



    //METHOD 12
     byte[] array=photo.getBytes();
     FileOutputStream fos=new FileOutputStream("D:/Images/image6.jpg");
    fos.write(array);
    fos.flush();
    fos.close();


    //METHOD 13
    byte[] array=photo.getBytes();
    byte[] bytes = Base64.decode(array);
    FileOutputStream fos=new FileOutputStream("D:/Images/image6.jpg");
    fos.write(bytes);
    fos.flush();
    fos.close();


    //METHOD 14
    byte[] array=photo.getBytes();
    Charset csets = Charset.forName("UTF-8");
    ByteBuffer bb=ByteBuffer.wrap(array);
    csets.decode(bb);
    bb.rewind();
    byte[] array1=bb.array();
    FileOutputStream fos=new FileOutputStream("D:/Images/image6.jpg");
    fos.write(array1);
    fos.flush();
    fos.close();
Bhushan
  • 18,329
  • 31
  • 104
  • 137
Nick
  • 222
  • 1
  • 2
  • 10

4 Answers4

0
public class test {

    static String HEX_STRING = "0123456789ABCDEF";

    public static byte[] convertHexadecimal2Binary(byte[] hex) {
        int block = 0;
        byte[] data = new byte[hex.length / 2];
        int index = 0;
        boolean next = false;
        for (int i = 0; i < hex.length; i++) {
            block <<= 4;
            int pos = HEX_STRING.indexOf(Character.toUpperCase((char) hex[i]));
            if (pos > -1) {
                block += pos;
            }
            if (next) {
                data[index] = (byte) (block & 0xff);
                index++;
                next = false;
            } else {
                next = true;
            }
        }
        return data;
    }

    public static void main(String args[]) {
        String line = "";
        String line_final = "";
        try {
            String sCurrentLine;
            BufferedReader br = new BufferedReader(new FileReader("D:\\test.txt"));//test.txt hex code string
            DataOutputStream os = new DataOutputStream(new FileOutputStream("D:\\mohit.jpg"));
            while ((sCurrentLine = br.readLine()) != null) {
                line = StringUtils.deleteWhitespace(sCurrentLine);
                byte[] temp = convertHexadecimal2Binary(line.getBytes());
                os.write(temp);
            }
            os.close();
            br.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
jensgram
  • 31,109
  • 6
  • 81
  • 98
0

When you retrieve a file a space will be appended at the beginning of the hex string so remove the space and store it in another byte array and it works fine:

here is code for removing starting space

byte a3[] = new BigInteger(str, 16).toByteArray();  
byte a[] = new byte[a3.length - 1];
for (int i = 1; i < a3.length; i++)
    a[i - 1] = a3[i];

Here a3 contains retrieved byte data;
         a1 contains actual byte stream

Unihedron
  • 10,902
  • 13
  • 62
  • 72
vineeth
  • 1
  • 1
0

Method 2 looks correct (haven't checked all others) -- your problem is probably elsewhere. Are you sure the string extracted from the XML is complete? Which parser are you using? Perhaps it returns long strings in multiple parts (I think this might be the case for SAX parsers), and you are extracting only the first part?

Here is how I would implement the decoding part (avoiding unneeded extra allocations via substring, BigInteger, char[] etc...; for performance, you may want to use a BufferedOutputStream though):

String photo = "0000005000000050FF191818FF15"; 
FileOutputStream fos = new FileOutputStream("D:/Images/image6.jpg");
for (int i = 0; i < photo.length; i += 2) {
  int byte = Character.digit(photo.charAt(i), 16) * 16 + 
             Character.digit(photo.charAt(i + 1), 16);
  fos.write(byte);
}
fos.close();
Stefan Haustein
  • 18,427
  • 3
  • 36
  • 51
0

The shortest way might be this.

String photo = "0000005000000050FF191818FF151715FF111413FF0E100FF2A2322FF292221";

// adds a dummy byte at the start to avoid truncation of leading zeros.
byte[] bytes = new BigInteger("10" + photo, 16).toByteArray();

System.out.println(Arrays.toString(bytes));

prints

[1, 0, 0, 0, 5, 0, 0, 0, 5, 15, -15, -111, -127, -113, -15, 81, 113, 95, -15, 17, 65, 63, -16, -31, 0, -1, 42, 35, 34, -1, 41, 34, 33]

Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
  • Hi Peter,This is also not working – Nick Dec 24 '11 at 11:52
  • @Nick in what way? Have you tried writing the resulting byte array into a file to test? – fge Dec 24 '11 at 12:40
  • @Nick, What do you mean not working? It produces the expected result for me. – Peter Lawrey Dec 24 '11 at 15:00
  • Yes i wrote the byte array to a file using FileOutputStram byte[] bytes = new BigInteger("10" + photo, 16).toByteArray(); FileOutputStream fos=new FileOutputStream("D://Images/image.jpg"); fos.write(bytes); fos.flush(); fos.close(); – Nick Dec 26 '11 at 04:53
  • You need to drop the "dummy byte"; e.g. `fos.write(bytes, 1, bytes.length-1);` – Peter Lawrey Dec 26 '11 at 10:37
  • what would be the dummy byte in my case? My image data(Hex String) always starts with 0000005000000050FF. – Nick Dec 27 '11 at 06:29
  • hmmm. try converting it without the dummy byte and see what happens. When reading a number, leading zeros are dropped but in your cause you want to keep them. – Peter Lawrey Dec 27 '11 at 09:55
  • tried that also.I am able to save the file ,but not able to open the file.Getting the same message "the file appears to be damaged,corrupted or file is too large" . – Nick Dec 27 '11 at 14:01
  • Can you take a an imagine file which you know is fine, turn it into a hex string and see if you can turn it back into the original file? – Peter Lawrey Dec 27 '11 at 14:04
  • Let me give the complete picture. The image is captured from a cell phone using a J2ME application, wrote in to the xml file as this Hex String and uploaded to a web application. I am downloading this xml file from the web application and parsing the xml file to get the photo hex string as a String variable and then trying to save it. – Nick Dec 27 '11 at 14:06
  • I would have thought with a J2ME application you would want to do as little processing as possible. Is there any reason you cannot send the image as a `byte[]` without converting to hex or XML. You wouldn't have to convert back and it would be faster. – Peter Lawrey Dec 27 '11 at 14:09
  • The J2ME part is done by some other third party. I cannot change the format of the photo being sent from cell phone. Also this third party has shown a demo in which they capture a photo from cell phone and uplod. In the client side they successfully downloaded the xml file and displayed the photo using a swing application. – Nick Dec 27 '11 at 14:15
  • So is it possible they use an image format which is different to what you expect? Can you try converting a known format image to the hex string and back to check whether the hex conversion is working? – Peter Lawrey Dec 27 '11 at 14:19