Я пытаюсь реализовать стеганографию. Я читаю изображение "a.jpeg" и вставляю в него байт, меняя свои последовательные 7 байтов на младший значащий бит, начиная со смещения 50. Это выполняется успешно, когда я печатаю байты, измененные последними битами. Затем я сохранил его как "ao.jpeg". Но когда я читаю байтовые значения от 50, они не совпадают с теми, которые я когда-то сохранил. здесь мой код
public static void main(String[] args) throws IOException {
BufferedImage inputImage = ImageIO.read(new File("a.jpeg"));
int offset=50;
byte data = 7;
byte[] image = get_byte_data(inputImage);//function converts bufferedimage to byte array
//add data at end of each byte starting from offset
System.out.println("bytes altered are :");
for(int bit=7; bit>=0; --bit, ++offset)//for each bit of data
{
int b = (data >>> bit) & 1;
image[offset] = (byte)((image[offset] & 0xFE) | b );
String s1 = String.format("%8s", Integer.toBinaryString(image[offset] & 0xFF)).replace(' ', '0');
System.out.println(s1);
}
//write changed image to ao.jpeg
BufferedImage outputImage = ImageIO.read(new ByteArrayInputStream(image));
File outputfile = new File("ao.jpeg");
ImageIO.write(outputImage,"jpeg",outputfile);
//read data from ao.jpeg
System.out.println("bytes from encoded image are :");
byte result=0;
offset=50;
BufferedImage oImage = ImageIO.read(new File("aoc.jpeg"));
byte[] image1 = get_byte_data(oImage);//function converts bufferedimage to byte array
for(int i=0; i<8; i++, ++offset)
{
result = (byte)((result << 1) | (image1[offset] & 1));
String s1 = String.format("%8s", Integer.toBinaryString(image1[offset] & 0xFF)).replace(' ', '0');
System.out.println(s1);
}
System.out.println("recovered data is :");
System.out.print(result);
}
вывод: данные вставлены 7. Если вы заметили наименее значащий бит каждого байта, он формирует 7. Но когда я его снова читаю, это случайные байты.
bytes altered are :
00010100
00011100
00011010
00011110
00011110
00011101
00011011
00011101
bytes from encoded image are :
00011110
00011101
00011010
00011100
00011100
00100000
00100100
00101110
recovered data is :
64
Как предложил Константин В. Салихов, я пробовал использовать другой формат файла (gif), и он сработал. Но есть ли способ, которым я могу использовать "jpeg"?
Как предположил Салинков, формат jpeg вызывает сжатие данных. Подводя итог тому, что вы сделали:
То, где ваш метод разваливается. Формат без потерь не приведет к возникновению этих проблем, поэтому работает gif. Или png, bmp и т.д....
Weeeeell, нет, не совсем. Во-первых, нам нужно понять, какие данные хранятся в jpeg-изображении.
Короткий ответ заключается в том, что отдельные байты не соответствуют фактическим пикселям изображения.
Длинная история заключается в том, что вы разбиваете изображение в массивах 8x8 и принимаете DCT для получения частотных коэффициентов. После этапа квантования многие из них станут 0, особенно более высокие частотные коэффициенты (внизу справа от массива DCT - см. Здесь). Это шаг с потерями jpeg. Вы жертвуете более высокими частотными коэффициентами для некоторых переносимых искажений изображения (потеря информации). Теперь вы сохраняете ненулевые коэффициенты, основываясь на их местоположении в матрице, то есть (0, 0, -26), (0, 1, -3) и т.д. Это может быть дополнительно сжато Хаффманом кодирование. Кстати, изменение любого одного частотного компонента влияет на все 64 пикселя.
Итак, как обычно выполняется стандартная стеганография? Он в основном следует за процессом кодирования jpeg:
Теперь мы получили квантованные коэффициенты DCT, и мы переходим от процесса jpeg-кодирования.
Примените некоторый стеганографический алгоритм, изменив значение квантованных коэффициентов.
Хаффман сжимает коэффициенты и продолжает с остальной частью процесса кодирования jpeg с этими модифицированными коэффициентами DCT.
JPEG - механизм хранения с потерями. Это означает, что он НЕ требуется (или даже желательно), который представляет каждый байт точно так же, как оригинал. На деле, в этом весь смысл, он жертвует небольшими несовершенствами, чтобы добиться большой экономии пространства. Если вам нужно идеальное хранилище, вам нужно будет выбрать другой формат, такой как GIF, PNG или некоторые варианты BMP.
Как указано ниже, технически возможно создать JPEG без потерь, но это было позднее дополнение, не полностью поддерживаемое, и, в частности, Java не поддерживает его. См. Этот ответ для получения дополнительной информации.