java请求的数组大小超过VM限制
基于此[posted](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;
}
# 1 楼答案
你的嵌入是错误的。在RGBA像素中嵌入一个字节很容易,因为每个像素可以方便地容纳半个字节。但是对于RGB,您可以适应3/8字节,这不是一个整数。这里演示了RGB的复杂性(假设我们从像素(0,0)开始):
如您所见,有时您需要嵌入3或4个不同的像素,并且并不总是从R组件开始/结束。实现这一点所需的代码如下
编码信息
解码信息
我将简要解释这背后的逻辑。因为编码和解码都是相似的,所以我只描述前者。由于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开始,对于mod=2,我们从B开始start = start/3
告诉您必须从哪个像素开始。整数除法给出一个向下取整的整数结果,例如8/3=向下取整2.666=2。正如你所看到的,start和mod为我们提供了所有关于我们必须从哪里开始的信息。例如,在一个字节后,我们从像素2开始,B分量。现在我们可以开始将字节嵌入i和j循环中在循环中,我们获取新的rgb像素。根据到目前为止我们已经嵌入了多少位,我们可以嵌入整个RGB,或者只是其中的一部分。对象
count
告诉我们到目前为止嵌入了多少位,总共嵌入了8位。这就是if-else语句的作用。实际上,我们会问这样一个问题:“我们是否还有3位以上的数据需要嵌入?”这被翻译为8计数>;=当这是代数重排,你得到count <= 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<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<(9-count); p++)
),请查看上面字节1的示例。我们已经嵌入了前两个像素,所以我们还有两个比特。这意味着我们有count=6pp=0;退出的条件为pp<;9-6>;pp<;3,所以我们继续。我们将第7位嵌入R>;计数=7
pp=1;退出的条件为pp<;9-7>;pp<;2,所以我们继续。我们将第8位嵌入G>;计数=8
pp=2;退出的条件为pp<;9-8>;pp<;1>;我们必须退出
与这种逻辑相对应的一个更简单的等价物是以下内容,我不知道为什么我不这么做