Невозможно сохранить изменения после сохранения или загрузки измененного изображения

Я использую код стеганографии из этой ссылки на вставлять информацию во все каналы 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;

}

person user3551873    schedule 19.04.2014    source источник
comment
Вероятно, альфа-канал загружен неправильно и по умолчанию равен 255 (непрозрачный). Сделайте это: загрузите изображение, измените альфа-канал одного пикселя, сохраните изображение, перезагрузите его и проверьте значение.   -  person Reti43    schedule 20.04.2014
comment
@ Reti43 Reti43 Я изменил альфа-канал нескольких пикселей, но все равно получаю тот же результат, кажется, что длина увеличивается до максимального значения целого числа.   -  person user3551873    schedule 21.04.2014
comment
Я специально попросил вас проверить значение альфа-значения после его изменения, сохранения и перезагрузки. Длина сообщения выводится из того, что читается из первых 32 битов, независимо от их состояния. Если он дает вам неправильные результаты, это потому, что он читает неправильные вещи. Я работал с этим точным кодом встраивания/извлечения в java, поэтому я знаю, что встраивание/извлечение информации не должно быть проблемой. И этот код также загружал изображение неправильно, и его нужно было исправить. Итак, не могли бы вы сделать именно то, о чем я вас просил, и отчитаться?   -  person Reti43    schedule 21.04.2014
comment
@ Reti43 Извините, я, кажется, неправильно понял, о чем вы меня просили. Я постараюсь вернуться к вам с ответом.   -  person user3551873    schedule 21.04.2014
comment
@Reti43 Reti43 альфа-значение равно 255 во время кодирования и декодирования. это ответ, который вы ищете, или я снова сделал это неправильно? Мне очень жаль, если я снова сделал это неправильно.   -  person user3551873    schedule 21.04.2014
comment
Попробуй это. В методе 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.2014
comment
@ Reti43 Хорошо, я попробую. Мне нужно изменить его на setPixel() вместо setRGB(), потому что я использую растровое изображение.   -  person user3551873    schedule 21.04.2014
comment
@ Reti43 только первый пиксель v1 и v2 равны, остальные v1 - 255, а v2 - 254.   -  person user3551873    schedule 21.04.2014
comment
Хорошо, это сужает вашу проблему. v1 — это измененный пиксель после встраивания, а v2 — это значение, которое вы считываете для извлечения, которое ДОЛЖНО быть таким же, как v1. Таким образом, ваша проблема, скорее всего, возникает в том, как вы сохраняете изображение после встраивания или как вы загружаете его перед извлечением. Попробуйте отредактировать свой вопрос, чтобы показать часть вашего кода для сохранения/загрузки и выделить, как значение пикселя не сохраняется после сохранения/загрузки изображения. Боюсь, я не знаю внутренней работы Bitmap и не могу протестировать код Android на своей машине. Удачи. :(   -  person Reti43    schedule 21.04.2014
comment
@ Reti43 О, это очень плохо. Спасибо большое.   -  person user3551873    schedule 21.04.2014
comment
@Reti43 Reti43 Я обнаружил, что сохранение изображения в PNG изменит изображение на RGB_565. Нашел это здесь   -  person user3551873    schedule 21.04.2014
comment
Замечательно. Это похоже на проблему, с которой я столкнулся в Java с BufferedImage. Если бы вы были так любезны написать и принять ответ на свой вопрос, это поможет будущим читателям. Хотя вы можете указать ссылку на решение, было бы лучше, если бы вы нашли время, чтобы объяснить проблему своими словами и предоставить решение фрагмента кода. Здесь удобнее читать решение, чем гоняться по ссылкам.   -  person Reti43    schedule 21.04.2014