import java.util.Arrays; import java.util.Vector; public class JPEGUtils extends Const { /** * Read the length of the block from the two bytes after the APP1 Marker * @param boundaryPos position of the APP1 Marker in the byte array * @param data byte array containing the block WITH APP1 Marker * @return length of the block */ public static int readBlockLength(int boundaryPos, byte[] data) { //Check whether entered position is APP1 Marker if(!JPEGUtils.isAPP1Marker(data,boundaryPos)) { System.err.println("JPEGUtils blockLength: Block is no APP1 Block!"); return -1; } int o; //Read length try { o = 256*(data[boundaryPos+2]&0xFF) + (data[boundaryPos+3]&0xFF); } catch(ArrayIndexOutOfBoundsException e) { System.err.println("JPEGUtils blockLength threw ArrayIndexOutOfBoundsException. Maybe the block is cut after APP1 Marker?"); e.printStackTrace(); return -1; } return o; } /** * decorate information with a block header of a certain type. The type is specified via the argument type. * In case, type == EXTENDEDXMP and data.length > CHUNKSIZE multiple ExtendedXMPBlocks will be generated and concatenated. * Available types: * Const.EXIF, Const.STANDARDXMP, Const.EXTENDEDXMP * @param data byte array of data that will be decorated * @param type String declaring the type of header for the block. * @return decorated block */ public static byte[] decorateBlock(byte[] data, String type) { //EXIF Block: 'APP1 + BLOCKLENGTH + EXIF\0\0 + data' if(type.equals(EXIF)) { data = ArrayUtils.concatenate(markEXIF, data); byte[] pre = ArrayUtils.concatenate(markAPP1, genLen(data.length+2)); return ArrayUtils.concatenate(pre, data); } //StandardXMP: 'APP1 + BLOCKLENGTH + http://ns.adobe.com/xap/1.0/\0 + data' else if(type.equals(STANDARDXMP)) { data = ArrayUtils.concatenate(markStandardXMP, data); byte[] pre = ArrayUtils.concatenate(markAPP1, genLen(data.length+2)); return ArrayUtils.concatenate(pre,data); } //ExtendedXMP: 'APP1 + BLOCKLENGTH + http://ns.adobe.com/xmp/extension/\0 + MD5 + EXTENDEDLENGTH + EXTENDEDOFFSET + DATAPORTION else if(type.equals(EXTENDEDXMP)) { byte[] out = new byte[0]; //MD5 checksum is digest of the datacontent byte[] md5 = HexUtil.generateMD5(data); int i=0; int blockCount = data.length/CHUNKSIZE; //decorate blockportions of size CHUNKSIZE while (i b = new Vector(); for(int i=0; i