【问题标题】:Requested array size exceeds VM limit请求的阵列大小超过 VM 限制
【发布时间】:2014-01-25 21:57:29
【问题描述】:

基于此的示例代码[已发布](Storing message into R,G,B instead of Alpha)

这次我只想使用 RGB 而不是 ARGB,但这次我收到的字节长度是 2147483647。下面是我更改的代码部分。

输入只有 128 字节的数组。

嵌入消息

private void openImage() {
    File f = new File("C:/TEMP/CROP.png");

        try {
            sourceImage = ImageIO.read(f); 


             sourceImage = new BufferedImage(sourceImage.getWidth(), sourceImage.getHeight(), BufferedImage.TYPE_INT_RGB); 
             Graphics2D g = sourceImage.createGraphics(); 
             g.drawImage(ImageIO.read(f), 0, 0, null); 
             g.dispose();

            this.embedMessage();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

private void embedInteger(BufferedImage img, int n, int start) {
    int maxX = img.getWidth(), maxY = img.getHeight(), 
            startX = start/maxY, startY = start - startX*maxY, count=0;

    for(int i=startX; i<maxX && count<32; i++) {
        for(int j=startY; j<maxY && count<32; j++) {
             int rgb = img.getRGB(i, j);
            // bit = getBitValue(n, count);
             //rgb = setBitValue(rgb, 0, bit);
         int bit = getBitValue(n, count); rgb = setBitValue(rgb, 0, bit);
             bit = getBitValue(n, count+1); rgb = setBitValue(rgb, 8, bit);
             bit = getBitValue(n, count+2); rgb = setBitValue(rgb, 16, bit);
             img.setRGB(i, j, rgb); 
             count = count+3;

        }
    }
}

private void embedByte(BufferedImage img, byte b, int start) {
    int maxX = img.getWidth(), maxY = img.getHeight(), 
            startX = start/maxY, startY = start - startX*maxY, count=0;

    for(int i=startX; i<maxX && count<8; i++) {
        for(int j=startY; j<maxY && count<8; j++) {
            if(j==maxY-1) {
                   startY = 0;
                }
             int rgb = img.getRGB(i, j);
             //bit = getBitValue(b, count);
            // rgb = setBitValue(rgb, 0, bit);
         int bit = getBitValue(b, count); rgb = setBitValue(rgb, 0, bit);
             bit = getBitValue(b, count+1); rgb = setBitValue(rgb, 8, bit);
             bit = getBitValue(b, count+2); rgb = setBitValue(rgb, 16, bit);
             img.setRGB(i, j, rgb);
             count = count+3;
        }
    }
}

解码消息

private void openImage() throws Exception {
    File f = new File("C:/TEMP/Four Area/Crop image/chest-CROP2.png");
    //File f = new File("C:/TEMP/chest2.png");

        try {
            image = ImageIO.read(f); 

            image = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_RGB); 
             Graphics2D g = image.createGraphics(); 
             g.drawImage(ImageIO.read(f), 0, 0, null); 
             g.dispose();

            this.decodeMessage();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }


}


private int extractInteger(BufferedImage img, int start) {
    int maxX = img.getWidth(), maxY = img.getHeight(), 
            startX = start/maxY, startY = start - startX*maxY, count=0;

    int length = 0;
    for(int i=startX; i<maxX && count<32; i++) {
        for(int j=startY; j<maxY && count<32; j++) {

             int rgb = img.getRGB(i, j); 
             //bit = getBitValue(rgb, 0);
             //length = setBitValue(length, count, bit);
         int bit = getBitValue(rgb, 0); length = setBitValue(length, count, bit);
             bit = getBitValue(rgb, 8); length = setBitValue(length, count+1, bit);
             bit = getBitValue(rgb, 16); length = setBitValue(length, count+2, bit);
             count = count+3;

        }
    }
    return length;

}


private byte extractByte(BufferedImage img, int start) {
    int maxX = img.getWidth(), maxY = img.getHeight(), 
            startX = start/maxY, startY = start - startX*maxY, count=0;

    byte b = 0;
    for(int i=startX; i<maxX && count<8; i++) {
        for(int j=startY; j<maxY && count<8; j++) {
            if(j==maxY-1) {
                   startY = 0;
                }
             int rgb = img.getRGB(i, j); 

             //bit = getBitValue(rgb, 0);
             //b = (byte)setBitValue(b, count, bit);
           int bit = getBitValue(rgb, 0); b = (byte)setBitValue(b, count, bit);
               bit = getBitValue(rgb, 8); b = (byte)setBitValue(b, count+1, bit);
               bit = getBitValue(rgb, 16); b = (byte)setBitValue(b, count+2, bit);
             count = count+3;
        }
    }
    return b;
}

【问题讨论】:

    标签: java embed rgb decode steganography


    【解决方案1】:

    您的嵌入错误。在 RGBA 像素中嵌入一个字节很容易,因为您可以方便地为每个像素放置半个字节。但是对于 RGB,您可以容纳 3/8 个字节,这不是整数。下面演示了 RGB 的复杂程度(假设我们从像素 (0, 0) 开始):

    // Byte 1
    (0, 0, R) (0, 0, G) (0, 0, B)
    (0, 1, R) (0, 1, G) (0, 1, B)
    (0, 2, R) (0, 2, G)
    
    // Byte 2
                        (0, 2, B)
    (0, 3, R) (0, 3, G) (0, 3, B)
    (0, 4, R) (0, 4, G) (0, 4, B)
    (0, 5, R)
    
    // Byte 3
              (0, 5, G) (0, 5, B)
    (0, 6, R) (0, 6, G) (0, 6, B)
    (0, 7, R) (0, 7, G) (0, 7, B)
    

    如您所见,有时您需要嵌入 3 或 4 个不同的像素,而且您并不总是从 R 组件开始/结束。实现这一点所需的代码如下。

    EncodeMessage

    private void embedMessage(BufferedImage img, String mess) {
       int messageLength = mess.length();
    
       int imageWidth = img.getWidth(), imageHeight = img.getHeight(),
          imageSize = imageWidth * imageHeight;
       if((messageLength * 8 + 32)/3 > imageSize) {
          JOptionPane.showMessageDialog(this, "Message is too long for the chosen image",
             "Message too long!", JOptionPane.ERROR_MESSAGE);
          return;
          }
       embedInteger(img, messageLength, 0);
    
       byte b[] = mess.getBytes();
       for(int i=0; i<b.length; i++)
          embedByte(img, b[i], i*8+32);
       }
    
    private void embedInteger(BufferedImage img, int n, int start) {
       int mod = start%3;
       start = start/3;
       int maxX = img.getWidth(), maxY = img.getHeight(), 
          startX = start/maxY, startY = start - startX*maxY, count=0;
       for(int i=startX; i<maxX && count<32; i++) {
          for(int j=startY; j<maxY && count<32; j++) {
             int rgb = img.getRGB(i, j), bit = 0, pp = 0;
             if(count <= 29) {
                for(pp=mod; pp<3; pp++) {
                   bit = getBitValue(n, count); rgb = setBitValue(rgb, 8*pp, bit);
                   count += 1;
                   }
                mod = 0;
                }
             else {
                for(pp=0; pp<(33-count); pp++) {
                   bit = getBitValue(n, count); rgb = setBitValue(rgb, 8*pp, bit);
                   count += 1;
                   }
                }
             img.setRGB(i, j, rgb);
             }
          }
       }
    
    private void embedByte(BufferedImage img, byte b, int start) {
       int mod = start%3;
       start = start/3;
       int maxX = img.getWidth(), maxY = img.getHeight(), 
          startX = start/maxY, startY = start - startX*maxY, count=0;
       for(int i=startX; i<maxX && count<8; i++) {
          for(int j=startY; j<maxY && count<8; j++) {
             if(j==maxY-1){
                startY = 0;
                }
             int rgb = img.getRGB(i, j), bit = 0, pp = 0;
             if(count <= 5) {
                for(pp=mod; pp<3; pp++) {
                   bit = getBitValue(b, count); rgb = setBitValue(rgb, 8*pp, bit);
                   count += 1;
                      }
                mod = 0;
                }
             else {
                for(pp=0; pp<(9-count); pp++) {
                   bit = getBitValue(b, count); rgb = setBitValue(rgb, 8*pp, bit);
                   count += 1;
                   }
                }        
             img.setRGB(i, j, rgb);
             }
          }
       }
    

    解码消息

    private void decodeMessage() {
       int len = extractInteger(image, 0);
       byte b[] = new byte[len];
       for(int i=0; i<len; i++)
          b[i] = extractByte(image, i*8+32);
       message.setText(new String(b));
       }
    
    private int extractInteger(BufferedImage img, int start) {
       int mod = start%3;
       start = start/3;
       int maxX = img.getWidth(), maxY = img.getHeight(), 
          startX = start/maxY, startY = start - startX*maxY, count=0;
       int length = 0;
       for(int i=startX; i<maxX && count<32; i++) {
          for(int j=startY; j<maxY && count<32; j++) {
             int rgb = img.getRGB(i, j), bit = 0, pp = 0;
             if(count <= 29) {
                for(pp=mod; pp<3; pp++) {
                   bit = getBitValue(rgb, 8*pp); length = setBitValue(length, count, bit);
                   count += 1;
                   }
                mod = 0;
                }
             else {
                for(pp=0; pp<(33-count); pp++) {
                   bit = getBitValue(rgb, 8*pp); length = setBitValue(length, count, bit);
                   count += 1;
                   }
                }
             }
          }
       return length;
       }
    
    private byte extractByte(BufferedImage img, int start) {
       int mod = start%3;
       start = start/3;
       int maxX = img.getWidth(), maxY = img.getHeight(), 
          startX = start/maxY, startY = start - startX*maxY, count=0;
       byte b = 0;
       for(int i=startX; i<maxX && count<8; i++) {
          for(int j=startY; j<maxY && count<8; j++) {
             if(j==maxY-1){
                startY = 0;
                }
             int rgb = img.getRGB(i, j), bit = 0, pp = 0;
             if(count <= 5) {
                for(pp=mod; pp<3; pp++) {
                   bit = getBitValue(rgb, 8*pp); b = (byte)setBitValue(b, count, bit);
                   count += 1;
                   }
                mod = 0;
                }
             else {
                for(pp=0; pp<(9-count); pp++) {
                   bit = getBitValue(rgb, 8*pp); b = (byte)setBitValue(b, count, bit);
                   count += 1;
                   }
                }
             }
          }
       return b;
       }
    

    我将简要解释这背后的逻辑。由于编码和解码都相似,我只描述前者。而且由于 embedInteger 和 embedByte 类似,所以我只描述embedByte。

    在embedMessage 中,我们需要在embedByte 中传递 i*8+32,因为我们需要到目前为止嵌入的位数。这是必要的,以便知道前一个字节的嵌入在哪里停止(如上所示,在字节 1 之后我们必须从 B 开始,而在字节 2 之后从 G 开始)。这是通过模运算 (int mod = start%3) 实现的,它为您提供除以 3 的余数。例如,8%3 = 2。对于 mod = 0,我们从 R 开始,对于 mod = 1 在 G 和在 B 处 mod = 2。

    start = start/3 告诉您我们必须从哪个像素开始。整数除法为您提供向下取整的整数结果,例如 8/3 = 向下取整 2.666 = 2。如您所见,start 和 mod 为我们提供了必须从哪里开始的所有信息。例如,在一个字节之后,我们从像素 2,B 分量开始。现在我们可以开始在 i 和 j 循环中嵌入字节了。

    在循环内部,我们获取新的 rgb 像素。根据到目前为止我们嵌入了多少位,我们可能会嵌入整个 RGB,或者只是其中的一部分。对象count 告诉我们到目前为止嵌入了多少位,总共嵌入了 8 位。这就是 if-else 语句的用武之地。实际上,我们问的是“我们是否还有超过 3 位要嵌入?”这被翻译为 8-count >= 3,当它被代数重新排列时,你得到count &lt;= 5。总结一下:

    if: we have enough bits left to embed in all 3 components

    else: we don't have enough bits left to embed in all 3 components

    现在,pp 决定我们在哪个颜色组件中嵌入我们的位,它可以采用值 0、1 和 2。Java 语法是 for(pp=0; p&lt;3; pp++)。就是这样。那么8*pp可以是0、8或16,即R、G或B的LSB。

    在 if 块中,我们有for(pp=mod; ...),因为我们可能不是从 0 开始。看上面的例子,字节 2 有 mod=2,因为我们从蓝色分量开始。但是一旦循环结束,mod 将被重置为 0,所以对于下一个像素,我们确实从 0 开始。

    要了解 else 块 (for(pp=0; pp&lt;(9-count); p++)),请查看上面的示例中的字节 1。我们已经嵌入了前 2 个像素,因此还剩下两个位。这意味着我们有 count=6。

    pp=0;退出的条件是 pp pp count=7。

    pp=1;退出的条件是 pp pp count=8。

    pp=2;退出的条件是 pp pp 我们必须退出。

    与该逻辑等效的更简单的逻辑如下,我不知道为什么我不这样做。

    for(pp=0; pp<(8-count); pp++) {
       getBit...; setBit...;
       }
    count = 8;
    

    【讨论】:

    • (i*8+32)/4 = i*2+8。只是第二种需要较少的计算。
    • 1) 因为消息长度是一个长整数,需要 4 个字节。它与您拥有多少颜色组件无关。 2) count
    • 那 3 是因为您嵌入了 3 个组件。像素有多少分量并不重要,但要嵌入多少并不重要。例如,在 RGB 像素中,如果您只想嵌入两个分量,则需要减去 2。在 ARGB 像素中,如果你想嵌入 3 个组件,你会做负 3。当然,你不能嵌入比你可用的更多的组件,所以在 RGB 中,你最多可以做 3 个。if-else 语句在那里是因为它取决于您是否会在当前像素中嵌入 1、2 或 3 位。
    • 从技术上讲,是的。但你不必这样做。就像我向您展示的那样,在 ARGB 中嵌入 4 位比在 RGB 中嵌入 3 位要简单得多。这是因为 8(字节中的位)/4(ARGB 中的嵌入位)= 2,这是一个整数,而 8/3 = 2.666。在 ARGB 中嵌入 4 位意味着您始终每两个像素嵌入一个字节,并且在每个像素中嵌入所有 4 个组件。
    • 你的想法是对的,但事实恰恰相反。嵌入的位将是 11011010。当我们从左到右写入和读取数字时,从最低有效数字到最高有效数字,我们从右到左进行。就像数字 1234 是 4-3-2-1。但总的来说,你明白了。
    猜你喜欢
    • 2015-11-03
    • 2018-10-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多