Я использую код стеганографии из этой ссылки на вставлять информацию во все каналы ARGB изображения. Код был написан для java, но я модифицировал его для Android, используя Bitmap для работы с изображением.
Я преобразовываю длину сообщения в 32-битное число, которое сохраняю в первых 8 пикселях. 4 бита на пиксель, по одному биту в младшем бите каждого канала A, R, G и B. Однако когда я извлекаю биты длины сообщения и преобразовываю их в целое число в функции extractInteger
, я получаю 2147483647, что позже приводит к исключению OutOfMemory.
Я попытался найти источник ошибки следующим образом.
- Я использую изображение M для встраивания своей информации, тем самым изменяя его на M'.
- Я проверяю значение модифицированных пикселей M'.
- Я спасаю М'.
- Я перезагружаю M' для извлечения, но значение пикселей не всегда такое же, как указано выше.
Поэтому я подозреваю, что есть проблема либо с сохранением M', либо с загрузкой M'. Последнее может возникнуть из-за того, что я изменяю значение альфа-канала как часть процесса встраивания, но при загрузке M' оно по умолчанию равно 255.
Если с кодом все в порядке, есть ли что-нибудь, что я мог бы решить, чтобы исправить проблему? Спасибо.
Функция сохранения изображения:
private void saveImage() {
path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES + "/Testing/");
date = new Date() ;
dateFormat = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()) ;
filename = new File(dateFormat.format(date) + ".png");
fileName = filename.toString();
file = new File(path, fileName);
filePath = file.toString();
FileOutputStream out = null;
try {
out = new FileOutputStream(filePath);
embeddedImg.compress(Bitmap.CompressFormat.PNG, 100, out);
out.close();
Toast.makeText(this, "Saved!", Toast.LENGTH_SHORT).show();
sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.parse("file://"+file.getAbsolutePath())));
} catch (Exception e) {
e.printStackTrace();
}
}
Вырезано из функции загрузки изображения:
Bundle getImage = this.getIntent().getExtras();
gotImage = getImage.getString("decode");
BitmapFactory.Options op = new BitmapFactory.Options();
op.inPreferredConfig = Bitmap.Config.ARGB_8888;
try {
bitmapImg = BitmapFactory.decodeFile(gotImage, op);
newBitmapImg = bitmapImg.copy(Bitmap.Config.ARGB_8888, true);
decodeMessage();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Функции декодирования:
private void decodeMessage() {
int len = extractInteger(newBitmapImg, 0);
byte b[] = new byte[len];
for(int i=0; i<len; i++)
b[i] = extractByte(newBitmapImg, i*2+8);
viewMessage.setText(new String(b));
}
private int extractInteger(Bitmap 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.getPixel(i, j), 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);
bit = getBitValue(rgb, 24); length = setBitValue(length, count+3, bit);
count = count+4;
}
}
return length;
}
private byte extractByte(Bitmap 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.getPixel(i, j), 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);
bit = getBitValue(rgb, 24); b = (byte)setBitValue(b, count+3, bit);
count = count+4;
}
}
return b;
}
private int getBitValue(int n, int location) { //n=messageLength, location=count
int v = n & (int) Math.round(Math.pow(2, location));
return v==0?0:1;
}
private int setBitValue(int n, int location, int bit) {
int toggle = (int) Math.pow(2, location), bv = getBitValue(n, location);
if(bv == bit)
return n;
if(bv == 0 && bit == 1){
n |= toggle;
System.out.println("n{toggle: "+n);
}else if(bv == 1 && bit == 0){
n ^= toggle;
}
return n;
}
embedInteger
, когда вы получаете значение текущего пикселя вint rgb = img.getRGB(i, j)
, печатайте его. В следующих нескольких строках вы вставляете свои биты в каналы ARGB, а затем сохраняете измененный пиксель вimg.setRGB(i, j, rgb);
. Распечатайте его после этой строки еще раз. Обозначим эти значения как v0 и v1 соответственно. В методеextractInteger
, как только вы получите пиксель вint rgb = img.getRGB(i, j)
, распечатайте его. Назовите это v2. Это делается для 8 пикселей. Во всех ли случаях v1 равно v2? - person Reti43   schedule 21.04.2014setPixel()
вместоsetRGB()
, потому что я использую растровое изображение. - person user3551873   schedule 21.04.2014