从 BMP 中提取附加数据
Extract appended data from BMP
我想从 BMP 图像文件中提取附加数据。
在我的函数中,所选 BMP 图像的数据流作为输入提供。在文件类型之后,我读取了文件大小,然后我需要遍历流的其余部分。附加数据已附加到 BMP 文件,因此图像中编码的文件大小 header 没有变化。
如何从文件大小字节数组中获取一个值,以确定在原始文件结束之前我需要读取多少字节? (我需要迭代正确数量的字节才能在附加数据之前获得)
private String getBMPAppendedData(DataInputStream in) {
StringBuilder message = new StringBuilder();
try {
// Read the fileType : always 0x4d42 = "BM"
in.readShort();
// Read the file size
byte[] fileSizeBytes = new byte[4];
in.readFully(fileSizeBytes);
// Read bytes in the loop
loop () {
in.readByte();
}
// Read appended byte by byte if present
boolean areSecretDataPresent = true;
while (areSecretDataPresent) {
try {
byte b = in.readByte();
message.append(String.format("%02X", b));
} catch (Exception e) {
areSecretDataPresent = false;
}
}
} catch (Exception exception) {
exception.printStackTrace();
}
return message.toString();
}
维基百科writes:
Offset
Length
Description
2
4 bytes
The size of the BMP file in bytes
All of the integer values are stored in little-endian format (i.e. least-significant byte first).
因此,我可能会这样做:
in.readShort(); // skip Header
int fileLength = in.readUnsignedByte()
| in.readUnsignedByte() << 8
| in.readUnsignedByte() << 16
| in.readUnsignedByte() << 24;
int bytesRead = 6;
while (bytesRead < fileLength) {
bytesRead += in.skipBytes(fileLength - bytesRead);
}
// proceed to read the extra data
<<
将整数中的位向左移动指定的位置数,然后 |
将这些部分组合成一个数字。
/**
* Read an extra message, if it exists, from an InputStream containing a BMP image.
*
* @param is the InputStream to read from
* @return the message found
* @throws IOException if any exception other than EndOfFile is thrown after the BMP image
*/
private static String readExtraMessage(final InputStream is) throws IOException {
final DataInputStream s = new DataInputStream(is);
final byte b = 0x42; // 'B'
final byte m = 0x4d; // 'M'
final byte sig1 = s.readByte();
final byte sig2 = s.readByte();
if (!(sig1 == b && sig2 == m)) {
throw new IllegalArgumentException("not a BMP file");
}
final byte[] fileSizeBuffer = new byte[4];
s.readFully(fileSizeBuffer);
final int fileSize = ByteBuffer.wrap(fileSizeBuffer, 0, 4).order(ByteOrder.LITTLE_ENDIAN).getInt();
int bytesToSkip = fileSize - 6; // 2 byte for the signature, 4 bytes for the filesize.
while (bytesToSkip > 0) {
bytesToSkip -= s.skipBytes(bytesToSkip);
}
final StringBuilder buf = new StringBuilder();
while (true) {
try {
final byte x = s.readByte();
buf.append((char) x);
} catch (final EOFException e) {
break;
}
}
return buf.toString();
}
/**
* Read an extra message, if it exists, from a File containing a BMP image.
*
* @param f the File to read
* @return the message found
* @throws IOException if any exception is thrown while reading
*/
private static String readExtraMessage(final File f) throws IOException {
final MappedByteBuffer mbb =
FileChannel.open(f.toPath(), StandardOpenOption.READ).map(FileChannel.MapMode.READ_ONLY, 0, f.length());
final byte B = 0x42;
final byte M = 0x4d;
if (!(mbb.get() == B && mbb.get() == M)) {
throw new IllegalArgumentException("not a BMP file");
}
final int fileSize = mbb.order(ByteOrder.LITTLE_ENDIAN).getInt();
if (fileSize == f.length()) {
return "";
}
final ByteBuffer extra = mbb.position(fileSize).slice();
final byte[] messageBytes = new byte[extra.remaining()];
extra.get(messageBytes);
return new String(messageBytes);
}
我想从 BMP 图像文件中提取附加数据。
在我的函数中,所选 BMP 图像的数据流作为输入提供。在文件类型之后,我读取了文件大小,然后我需要遍历流的其余部分。附加数据已附加到 BMP 文件,因此图像中编码的文件大小 header 没有变化。
如何从文件大小字节数组中获取一个值,以确定在原始文件结束之前我需要读取多少字节? (我需要迭代正确数量的字节才能在附加数据之前获得)
private String getBMPAppendedData(DataInputStream in) {
StringBuilder message = new StringBuilder();
try {
// Read the fileType : always 0x4d42 = "BM"
in.readShort();
// Read the file size
byte[] fileSizeBytes = new byte[4];
in.readFully(fileSizeBytes);
// Read bytes in the loop
loop () {
in.readByte();
}
// Read appended byte by byte if present
boolean areSecretDataPresent = true;
while (areSecretDataPresent) {
try {
byte b = in.readByte();
message.append(String.format("%02X", b));
} catch (Exception e) {
areSecretDataPresent = false;
}
}
} catch (Exception exception) {
exception.printStackTrace();
}
return message.toString();
}
维基百科writes:
Offset Length Description 2 4 bytes The size of the BMP file in bytes All of the integer values are stored in little-endian format (i.e. least-significant byte first).
因此,我可能会这样做:
in.readShort(); // skip Header
int fileLength = in.readUnsignedByte()
| in.readUnsignedByte() << 8
| in.readUnsignedByte() << 16
| in.readUnsignedByte() << 24;
int bytesRead = 6;
while (bytesRead < fileLength) {
bytesRead += in.skipBytes(fileLength - bytesRead);
}
// proceed to read the extra data
<<
将整数中的位向左移动指定的位置数,然后 |
将这些部分组合成一个数字。
/**
* Read an extra message, if it exists, from an InputStream containing a BMP image.
*
* @param is the InputStream to read from
* @return the message found
* @throws IOException if any exception other than EndOfFile is thrown after the BMP image
*/
private static String readExtraMessage(final InputStream is) throws IOException {
final DataInputStream s = new DataInputStream(is);
final byte b = 0x42; // 'B'
final byte m = 0x4d; // 'M'
final byte sig1 = s.readByte();
final byte sig2 = s.readByte();
if (!(sig1 == b && sig2 == m)) {
throw new IllegalArgumentException("not a BMP file");
}
final byte[] fileSizeBuffer = new byte[4];
s.readFully(fileSizeBuffer);
final int fileSize = ByteBuffer.wrap(fileSizeBuffer, 0, 4).order(ByteOrder.LITTLE_ENDIAN).getInt();
int bytesToSkip = fileSize - 6; // 2 byte for the signature, 4 bytes for the filesize.
while (bytesToSkip > 0) {
bytesToSkip -= s.skipBytes(bytesToSkip);
}
final StringBuilder buf = new StringBuilder();
while (true) {
try {
final byte x = s.readByte();
buf.append((char) x);
} catch (final EOFException e) {
break;
}
}
return buf.toString();
}
/**
* Read an extra message, if it exists, from a File containing a BMP image.
*
* @param f the File to read
* @return the message found
* @throws IOException if any exception is thrown while reading
*/
private static String readExtraMessage(final File f) throws IOException {
final MappedByteBuffer mbb =
FileChannel.open(f.toPath(), StandardOpenOption.READ).map(FileChannel.MapMode.READ_ONLY, 0, f.length());
final byte B = 0x42;
final byte M = 0x4d;
if (!(mbb.get() == B && mbb.get() == M)) {
throw new IllegalArgumentException("not a BMP file");
}
final int fileSize = mbb.order(ByteOrder.LITTLE_ENDIAN).getInt();
if (fileSize == f.length()) {
return "";
}
final ByteBuffer extra = mbb.position(fileSize).slice();
final byte[] messageBytes = new byte[extra.remaining()];
extra.get(messageBytes);
return new String(messageBytes);
}