我正在尝试在Android中实现隐写术,我已经实现了代码来逐位编码图像。
private Bitmap add_text(Bitmap image, String text)
{
//convert all items to byte arrays: image, message, message length
byte img[] = get_byte_data(image);
byte msg[] = text.getBytes();
byte len[] = bit_conversion(msg.length);
displaybit(img, "Start");
try
{
encode_text(img, len, 0); //0 first positiong
encode_text(img, msg, 32); //4 bytes of space for length: 4bytes*8bit = 32 bits
return BitmapFactory.decodeByteArray(img, 0, img.length);
}
catch(Exception e)
{
e.printStackTrace();
}
return image;
}
private byte[] get_byte_data(Bitmap image)
{
ByteArrayOutputStream stream = new ByteArrayOutputStream();
image.compress(Bitmap.CompressFormat.JPEG, 100, stream);
return stream.toByteArray();
}
private byte[] bit_conversion(int i)
{
//originally integers (ints) cast into bytes
//byte byte7 = (byte)((i & 0xFF00000000000000L) >>> 56);
//byte byte6 = (byte)((i & 0x00FF000000000000L) >>> 48);
//byte byte5 = (byte)((i & 0x0000FF0000000000L) >>> 40);
//byte byte4 = (byte)((i & 0x000000FF00000000L) >>> 32);
//only using 4 bytes
byte byte3 = (byte)((i & 0xFF000000) >>> 24); //0
byte byte2 = (byte)((i & 0x00FF0000) >>> 16); //0
byte byte1 = (byte)((i & 0x0000FF00) >>> 8 ); //0
byte byte0 = (byte)((i & 0x000000FF) );
//{0,0,0,byte0} is equivalent, since all shifts >=8 will be 0
return(new byte[]{byte3,byte2,byte1,byte0});
}
private byte[] encode_text(byte[] image, byte[] addition, int offset)
{
//check that the data + offset will fit in the image
if(addition.length + offset > image.length)
{
throw new IllegalArgumentException("File not long enough!");
}
//loop through each addition byte
for(int i=0; i<addition.length; ++i)
{
//loop through the 8 bits of each byte
int add = addition[i]; //0
for(int bit=7; bit>=0; --bit, ++offset) //ensure the new offset value carries on through both loops
{
//assign an integer to b, shifted by bit spaces AND 1
//a single bit of the current byte
int b = (add >>> bit) & 1;
//assign the bit by taking: [(previous byte value) AND 0xfe] OR bit to add
//changes the last bit of the byte in the image to be the bit of addition
image[offset] = (byte)((image[offset] & 0xFE) | b );
}
}
return image;
}
但在将数据编码到图像后,我无法形成位图。
我在java中实现了相同的算法并且工作正常:
private BufferedImage add_text(BufferedImage image, String text)
{
//convert all items to byte arrays: image, message, message length
byte img[] = get_byte_data(image);
byte msg[] = text.getBytes();
byte len[] = bit_conversion(msg.length);
try
{
encode_text(img, len, 0); //0 first positiong
encode_text(img, msg, 32); //4 bytes of space for length: 4bytes*8bit = 32 bits
}
catch(Exception e)
{
JOptionPane.showMessageDialog(null,
"Target File cannot hold message!", "Error",JOptionPane.ERROR_MESSAGE);
}
return image;
}
所以有人可以帮我弄清楚为什么在android的情况下字节数组是无效的。
答案 0 :(得分:1)
您从byte[]
的JPEG数据开始。然后,您可以修改该数据,半随机更改位,而不考虑JPEG数据格式。然后,您尝试解码已修改的byte[]
。毫不奇怪,BitmapFactory
无法对其进行解码,因为它不再是有效的图像格式。
我最好的猜测是你认为byte[]
是ARGB格式的原始像素。
如果是这种情况,请使用getPixel()
上的setPixel()
和Bitmap
等方法修改像素,并跳过位图编码和解码步骤。
答案 1 :(得分:0)
我终于能够弄明白了,正如上面评论中提到的,解决方案是逐像素地解决它。所以我拿了一个像素并将数据一点一点地放在它的rgb值中。所以这是代码:
private Bitmap add_text(Bitmap image, String text, File tempFile) {
//convert all items to byte arrays: image, message, message length
byte msg[] = text.getBytes();
byte len[] = bit_conversion(msg.length);
try {
return encodeTextRGB(image, len, msg, tempFile);
} catch (Exception e) {
e.printStackTrace();
}
return image;
}
private byte[] bit_conversion(int i) {
//originally integers (ints) cast into bytes
//byte byte7 = (byte)((i & 0xFF00000000000000L) >>> 56);
//byte byte6 = (byte)((i & 0x00FF000000000000L) >>> 48);
//byte byte5 = (byte)((i & 0x0000FF0000000000L) >>> 40);
//byte byte4 = (byte)((i & 0x000000FF00000000L) >>> 32);
//only using 4 bytes
byte byte3 = (byte) ((i & 0xFF000000) >>> 24); //0
byte byte2 = (byte) ((i & 0x00FF0000) >>> 16); //0
byte byte1 = (byte) ((i & 0x0000FF00) >>> 8); //0
byte byte0 = (byte) ((i & 0x000000FF));
//{0,0,0,byte0} is equivalent, since all shifts >=8 will be 0
return (new byte[]{byte3, byte2, byte1, byte0});
}
public Bitmap encodeTextRGB(Bitmap buffer, byte[] len, byte[] data, File tempFile) {
pixelRow = 0;
pixelCol = 0;
byte[] overhead = len;
int bitCount = 0;
int iteration = 0;
while (iteration++ < 2) {
for (int i = 0; i < overhead.length; i++) {
byte currentByte = overhead[i];
System.out.println("add: " + currentByte);
for (int j = 7; j >= 0; j--) {
int bit = (currentByte & (0x1 << j)) >> j;
bit = bit & 0x1;
System.out.println("Bit: " + bit);
if (bitCount % 3 == 0) {
int red;
if (bit == 0) {
red = Color.red(buffer.getPixel(pixelCol, pixelRow)) & 0xFE;
} else {
red = Color.red(buffer.getPixel(pixelCol, pixelRow)) | 0x1;
}
buffer.setPixel(pixelCol, pixelRow, Color.argb(
Color.alpha(buffer.getPixel(pixelCol, pixelRow)), red,
Color.green(buffer.getPixel(pixelCol, pixelRow)),
Color.blue(buffer.getPixel(pixelCol, pixelRow))));
} else if (bitCount % 3 == 1) {
int blue;
if (bit == 0) {
blue = Color.blue(buffer.getPixel(pixelCol, pixelRow)) & 0xFE;
} else {
blue = Color.blue(buffer.getPixel(pixelCol, pixelRow)) | 0x1;
}
buffer.setPixel(pixelCol, pixelRow, Color.argb(
Color.alpha(buffer.getPixel(pixelCol, pixelRow)),
Color.red(buffer.getPixel(pixelCol, pixelRow)),
Color.green(buffer.getPixel(pixelCol, pixelRow)), blue));
} else {
int green;
if (bit == 0) {
green = Color.green(buffer.getPixel(pixelCol, pixelRow)) & 0xFE;
} else {
green = Color.green(buffer.getPixel(pixelCol, pixelRow)) | 0x1;
}
buffer.setPixel(pixelCol, pixelRow, Color.argb(
Color.alpha(buffer.getPixel(pixelCol, pixelRow)),
Color.red(buffer.getPixel(pixelCol, pixelRow)), green,
Color.blue(buffer.getPixel(pixelCol, pixelRow))));
incrementPixel(buffer.getWidth());
}
bitCount++;
}
}
overhead = data;
}
FileOutputStream out = null;
try {
out = new FileOutputStream(tempFile);
buffer.compress(Bitmap.CompressFormat.PNG, 100, out);
out.flush();
out.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
incrementPixel(buffer.getWidth());
return buffer;
}