【问题标题】:Extract appended data from BMP从 BMP 中提取附加数据
【发布时间】:2021-07-02 17:05:42
【问题描述】:

我想从 BMP 图像文件中提取附加数据。

在我的函数中,选择 BMP 图像的数据流作为输入提供。在文件类型之后,我读取文件大小,然后我需要遍历流的其余部分。附加数据被附加到 BMP 文件中,因此在图像标题中编码的文件大小不变。

如何从文件大小字节数组中获取一个值,该值将确定在原始文件结束之前我需要读取多少字节? (我需要迭代正确数量的字节才能在附加数据之前获取)

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();
    }

【问题讨论】:

  • 不要尝试这样做。该阵列并非 100% 安全使用。您可能会发现 BMP 文件的大小错误。而是使用给定的分辨率、颜色深度和填充字节 + 标题大小 + 其他表格大小自行计算估计的文件大小。

标签: java bmp steganography


【解决方案1】:

维基百科writes:

Offset Length Description
2 4 bytes The size of the BMP file in bytes

所有整数值都以little-endian 格式存储(即最低有效字节在前)。

因此,我可能会这样做:

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

&lt;&lt; 将整数中的位向左移动指定数量的位置,| 然后将这些部分组合成一个数字。

【讨论】:

    【解决方案2】:
    /**
     * 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();
    }
    

    【讨论】:

      【解决方案3】:
      /**
       * 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);
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-04-24
        • 1970-01-01
        • 2021-08-06
        • 2019-09-01
        • 1970-01-01
        • 2012-05-20
        相关资源
        最近更新 更多