2016-12-04 31 views
1

我有以下问题,我想通过在LSB中编码消息来创建简单的隐写“程序”。我从图片中提取ARGB(每个都在它自己的数组中),用蓝色的LSB编码消息,并尝试使用这些新值(我将ARGB数组加回到int数组)中创建新图像。ImageWriter创建更小的图片(以KB为单位)

我遇到的一个明显问题是,当我更改LSB并尝试将它们写入图片时,我可以看到ImageWriter正在创建比kb小得多的图片,而且我无法再提取我的消息。

这是代码:

import javax.imageio.ImageWriteParam; 
import javax.imageio.ImageWriter; 
import javax.imageio.stream.ImageOutputStream; 
import java.awt.image.BufferedImage; 
import java.io.File; 
import java.io.IOException; 
public class Steganography { 


int [][] alpha; 
int [][] red; 
int [][] green; 
int [][] blue; 


public int [][] readPixels (String image) throws IOException { 

    //load image into img buffer 
    BufferedImage img = ImageIO.read(new File(image)); 

    //make matrix according to picture height and width 
    int [][] pixels = new int[img.getHeight()][img.getWidth()]; 


    // load matrix with image pixels 
    for(int i=0;i<pixels.length;i++) { 
     for (int j = 0; j < pixels[0].length; j++) { 
      pixels[i][j]=(img.getRGB(j, i)); 
     } 
    } 
    /* reminder to myself 

    values will be negative because of packing the 4 byte values into a 4-byte 

    The getRGB method returns an int whose 4 bytes are the alpha, red, green, and blue components in that order. 
    Assuming that the pixel is not transparent, the alpha is 255 (0xFF). 
    It's the most significant byte in the int, and the first bit is set in that value. 
    Because in Java int values are signed according to Two's Complement, 
    the value is actually negative because that first bit is on. 

    */ 

    return pixels ; 
} 


// extracts colors and alpha into their own matrix so we can reconstruct image later 
public void extractColors(int [][] pixel){ 


    this.alpha = new int[pixel.length][pixel[0].length]; 
    this.red = new int[pixel.length][pixel[0].length]; 
    this.green = new int[pixel.length][pixel[0].length]; 
    this.blue = new int[pixel.length][pixel[0].length]; 



    for(int i=0;i<pixel.length;i++) { 
     for(int j=0;j<pixel[i].length;j++){ 

     int clr = pixel[i][j]; 
     alpha[i][j] = (clr & 0xff000000) >> 24; 
     red[i][j] = (clr & 0x00ff0000) >> 16; 
     green[i][j] = (clr & 0x0000ff00) >> 8; 
     blue [i][j] = clr & 0x000000ff; 
    } 
} 

} // closed method 

//reconstruct image 
// need to make 32 bit integer again in correct order 
public void reconstructImage() throws IOException{ 

    int height = alpha.length; 
    int width= alpha[0].length; 

    BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); 


    for (int y = 0; y < width; y++) { 
     for (int x = 0; x < height; x++) { 


      int rgb= red[x][y]; 
      rgb = (rgb << 8) + green[x][y]; 
      rgb = (rgb << 8) + blue[x][y]; 
      image.setRGB(y, x, rgb); 
     } 
    } 

    ImageWriter writer = ImageIO.getImageWritersByFormatName("jpeg").next(); 
    ImageWriteParam param = writer.getDefaultWriteParam(); 
    param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT); // Needed see javadoc 
    param.setCompressionQuality(1.0F); // Highest quality 
    File file = new File("output.jpg"); 
    ImageOutputStream ios = ImageIO.createImageOutputStream(file); 
    writer.setOutput(ios); 
    writer.write(image); 

} 



public void codeMessage (String message){ 


    //first turn string into binary representation 
    // each character should have 7 bits 
    // ASCII uses 7 bit 

    message="START"+message.length()+message+"STOP"; 
    String binaryMessage =""; 

    for(int i =0;i<message.length();i++){ 

     //adding zeros if string has less than 8 characters 
     String binaryString= Integer.toBinaryString(message.charAt(i)); 

     while (binaryString.length() !=7) 
      binaryString = "0"+binaryString; 

     binaryMessage+=binaryString; 
    } 

    //binaryMessage is binary representation of string 
    // change value of LSB in blue color according to binaryMessage 
    //actually coding message into LSB is done here 
     int k=0; 
     for (int i = 0; i < blue.length; i++) { 
      for (int j = 0; j < blue[i].length; j++) { 

       if(k>=binaryMessage.length()) 
        break; 
       else if (binaryMessage.charAt(k) == '0') { 
        blue[i][j] = blue[i][j] & 0b1111110; 
        k++; 
       } 
       else { 
        blue[i][j] = blue[i][j] | 0b0000001; 
        k++; 
       } 
      } 
     } 
} //closed codeMessage 



public void readMessage(){ 

String LSB =""; 
char charLSB; 
String messageBinary =""; 

    for(int i=0;i<blue.length;i++){ 
     for(int j=0;j<blue[i].length;j++){ 
      LSB = Integer.toBinaryString(blue[i][j]); 
      charLSB = LSB.charAt(LSB.length()-1); 
      messageBinary+=charLSB; 
     } 
    } 


    char ArrayOfChars [] = new char [blue[0].length*blue.length]; 
    int k =0; 
    for(int i=0;i<messageBinary.length()-7;i+=7){ 
     String letter=(messageBinary.substring(i,i+7)); 
     int valueOfASCIIcharacter = Integer.parseInt(letter,2); 
     char c = (char)(valueOfASCIIcharacter); 
     System.out.println(c); 
     ArrayOfChars[k]=c; 
     k++; 
    } 

    } 
} 

我也曾尝试使用ARGB,而不是RGB为BufferedImage的,没有运气(仅弄乱了颜色,画面变得有点粉红色)。

这是我如何调用函数在主类

import java.io.IOException; 

public class Main { 




public static void main(String[] args) throws IOException{ 

    Steganography img = new Steganography(); 

    int pixels [][] =img.readPixels("image.jpg"); 
    img.extractColors(pixels); 


    img.codeMessage("Some message"); 


    img.reconstructImage(); 


    /*reading message from here on */ 


    int pixels2 [][] = img.readPixels("output.jpg"); 
    img.extractColors(pixels2); 

    img.readMessage(); 


} 
} 

原始图片有83,3 KB,并重建图像仅有24.3 KB。

回答

0

我找到了解决办法。

对于有同样的问题我和可能的未来寻求解决方案的人:

这种算法无法生存jpg扩展。将图片更改为bmp,需要的时间更长,但一切正常。

如果你想在jpg上使用隐写术,你必须使用别的而不是LSB。