2014-01-25 4 views
0
кода

образца, основанный на этом [вывешены] (Storing message into R,G,B instead of Alpha)Запрошенный размер массива превышает VM предел

На этот раз я хотел бы только 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; 
} 

ответ

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 нам необходимо передать i * 8 + 32 в embedByte, потому что нам нужно количество бит, которые мы вложили до сих пор. Это необходимо, чтобы знать, где остановилось вложение из предыдущего байта (как показано выше, после байта 1 мы должны начинать с B, а после байта 2 из G). Это достигается с помощью операции modulo (int mod = start%3), которая дает вам остальную часть деления на 3. Например, 8% 3 = 2. Для mod = 0 мы начинаем с R, для mod = 1 в G и для mod = 2 на B.

start = start/3 сообщает вам, с каким пикселем мы должны начать. Целочисленное деление дает результат округленного целого числа, так что, например, 8/3 = round down 2.666 = 2. Как вы можете видеть, start и mod дают нам всю информацию о том, где мы должны начинать. Например, после одного байта мы начинаем с пикселя 2, компонента B. Теперь мы можем начать встраивание байта в циклы i и j.

Внутри петель мы получаем наш новый пиксель rgb. В зависимости от того, сколько бит мы вложили до сих пор, мы можем вставлять весь RGB или только часть его. Объект count сообщает нам, сколько бит мы встроили до сих пор, и в целом мы вставляем 8 бит. В этом случае возникает инструкция if-else. Эффективно мы задаем вопрос «у нас осталось больше 3 бит для встраивания?» Это переводится как 8-count> = 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, что является LSB для R, G или B.

В блоке if у нас есть for(pp=mod; ...), так как мы не можем начинать с 0. Посмотрите на приведенный выше пример, где байт 2 имеет mod = 2, потому что мы начинаем с голубой компоненты. Но как только этот цикл закончен, мода будет сброшено на 0, поэтому для следующего пикселя мы начнем с 0.

Чтобы понять блок else (for(pp=0; pp<(9-count); p++)), посмотрите пример сверху для байта 1. У нас есть уже встроенный в первые 2 пикселя, поэтому у нас осталось еще два бита. Это означает, что мы имеем счет = 6.

pp = 0; условие выхода - pp < 9-6 -> pp < 3, поэтому мы продолжим. Мы вставляем 7-й бит в R -> count = 7.

pp = 1; условие выхода - pp < 9-7 -> pp < 2, поэтому мы продолжим. Мы вставляем 8-й бит в G -> count = 8.

pp = 2; условие выхода - pp < 9-8 -> pp < 1 -> МЫ ДОЛЖНО ВЫЙТИ.

Более простой эквивалент этой логике следующий, и я не знаю, почему я не занимаюсь этим.

for(pp=0; pp<(8-count); pp++) { 
    getBit...; setBit...; 
    } 
count = 8; 
+0

В 'embedMessage', (i * 8 + 32)/3, номер 3 здесь, поскольку компоненты R, G, B 3? но почему мы не делаем этого, когда делаем ARGB (например, do (i * 8 + 32)/4) –

+1

(i * 8 + 32)/4 = i * 2 + 8. Просто второе требует меньше вычислений. – Reti43

+0

Извините, у меня есть два последних вопроса о коде. 1) почему сообщение нужно 32 бит для первого, почему бы не 24 бита (потому что я думал, что 32-битный, потому что 4 компонента, или потому, что int?). 2) зачем делать 'count <= 29' в' embedInteger' и почему 29, то же самое, что 'embedByte', почему' count <= 5' и почему 5 ?? –

Смежные вопросы