基于此[已发布](Storing message into R,G,B instead of Alpha)
的示例代码这次我想只使用RGB而不是ARGB,但这次我收到的字节长度是2147483647.以下是我改变的代码部分。
输入只有128个字节的数组。
EmbedMessage
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;
}
}
}
DecodeMessage
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;
}
答案 0 :(得分: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);
}
}
}
<强> DecodeMessage 强>
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开始,而在G之后的字节2之后)。这是通过模运算(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&gt; = 3,当代数重新排列时,您得到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开始。看看上面的例子,其中byte 2有mod = 2,因为我们从蓝色组件开始。但是一旦该循环结束,mod将被重置为0,因此对于下一个像素,我们从0开始。
要理解else块(for(pp=0; pp<(9-count); p++)
),请查看上面的示例中的字节1.我们已经嵌入了前2个像素,因此我们还剩下两个比特。这意味着我们有count = 6。
PP = 0;退出的条件是pp <9-6 - > pp <3,所以我们继续。我们在R - >中嵌入了第7位。计数= 7。
PP = 1;退出的条件是pp <9-7 - > pp&lt; 2,所以我们继续。我们在G - >中嵌入了第8位。数= 8。
PP = 2;退出的条件是pp <9-8 - > pp&lt; 1 - &gt;我们必须退出。
这个逻辑的简单等价如下,我不知道为什么我不这样做。
for(pp=0; pp<(8-count); pp++) {
getBit...; setBit...;
}
count = 8;