2016-11-10 41 views
1

我建立了一個小的Java程序,使用最低有效位的方法隱藏圖像中的消息。當輸入一個jpg文件時它工作正常。輸出可能是png或jpg。當輸入一個PNG時,結果看起來非常直觀。隱寫,只有JPG作爲輸入工作,當使用PNG的結果圖像看起來很奇怪

這裏分別原始和結果圖像是:

Original image

Output image

public abstract class Builder{ 

public static void leastSignificantBitEncryption(String imageSource, String message, String newPath) { 
    BufferedImage image = returnImage(imageSource); 
    //prepare variables 
    String[] messageBinString = null; 
    String[] pixelBinString = null; 
    final byte[] messageBin = message.getBytes(StandardCharsets.UTF_8); 
    final byte[] pixelsBin = ((DataBufferByte) image.getRaster().getDataBuffer()).getData(); 
    //convert message and image to binary string array 
    try { 
     messageBinString = stringToBinaryStrings(messageBin); 
     pixelBinString = stringToBinaryStrings(pixelsBin); 
    } catch (UnsupportedEncodingException e) { 
     e.printStackTrace(); 
    } 
    String[] messageBinStringCut = splitIn2Bit(messageBinString); //split message binary into 2 bit strings 
    String[] pixelBinStringNew = pixelBinString.clone(); //insert 2 bit strings in last 2 bits of bytes from bitmap 
    insert2Bit(messageBinStringCut, pixelBinStringNew); 
    byte[] pixelsBinNew = stringArrayToByteArray(pixelBinStringNew); //Convert string array to byte array 
    try { //Create new image out of bitmap 
     int w = image.getWidth(); 
     int h = image.getHeight(); 
     BufferedImage imageNew = new BufferedImage(w, h, BufferedImage.TYPE_3BYTE_BGR); 
     imageNew.setData(Raster.createRaster(imageNew.getSampleModel(), new DataBufferByte(pixelsBinNew, pixelsBinNew.length), new Point())); 
     File imageFile = new File(newPath); 
     ImageIO.write(imageNew, "png", imageFile); 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } 
} 

private static String[] stringToBinaryStrings(byte[] messageBin) throws UnsupportedEncodingException{ 
    String[] bytes = new String[messageBin.length]; 
    int i = 0; 
    for(byte b : messageBin) { 
     bytes[i] = String.format("%8s", Integer.toBinaryString(b & 0xFF)).replace(' ', '0'); 
     i++; 
    } 
    return bytes; 
} 

private static String binaryStringsToString(String[] messageBin) throws UnsupportedEncodingException{ 
    StringBuilder stringBuilder = new StringBuilder(); 
    int i = 0; 
    while(messageBin[i] != null) { 
     stringBuilder.append((char) Integer.parseInt(messageBin[i], 2)); 
     i++; 
    } 
    return stringBuilder.toString(); 
} 

private static BufferedImage returnImage(String imageSource) { 
    try{ 
     try { 
      return ImageIO.read(new URL(imageSource)); 
     } catch (MalformedURLException e) { 
      return ImageIO.read(new File(imageSource)); 
     } 
    } catch (IOException ioe) { 
     ioe.printStackTrace(); 
     return null; 
    } 
} 

private static byte[] stringArrayToByteArray(String[] stringArray) { 
    byte[] byteArray = new byte[stringArray.length]; 
    for(int i = 0; i < stringArray.length; i++) { 
     byteArray[i] = (byte) Integer.parseInt(stringArray[i], 2); 
    } 
    return byteArray; 
} 

private static String[] splitIn2Bit(String[] inputArray) { 
    String[] outputArray = new String[inputArray.length * 4]; 
    for(int i = 0; i < outputArray.length; i += 4) { 
     String[] splitByte = inputArray[i/4].split("(?<=\\G..)"); 
     outputArray[i] = splitByte[0]; 
     outputArray[i + 1] = splitByte[1]; 
     outputArray[i + 2] = splitByte[2]; 
     outputArray[i + 3] = splitByte[3]; 
    } 
    return outputArray; 
} 

private static String[] insert2Bit(String[] twoBitArray, String[] insertArray) { 
    for(int i = 0; i < twoBitArray.length; i++) { 
     insertArray[i] = insertArray[i].substring(0, 6) + twoBitArray[i]; 
    } 
    return insertArray; 
} 

} 

此外,識別TestClass:

public class Test { 

    public static void main(String[] args) { 
     Builder.leastSignificantBitEncryption("IMAGEPATH OR URL", "MESSAGE", "PATH FOR IMAGE CONTAINING MESSAGE"); 
     Builder.leastSignificantBitDecryption("PATH OF IMAGE CONTAINING MESSAGE", "PATH FOR TXT CONTAINING OUTPUT"); 
    } 
} 
+0

如果您清理意大利麪代碼,它將更易於閱讀,從而更容易理解並更容易發現問題;既爲你和我們。我可以很容易地檢查5行方法並給出關於正確性的聲明,但是對於40行方法很難。幫你一個忙,把大方法分成小塊。從前11行開始,從文件名中給出位圖 –

+0

將變量移近使用,例如'w'和'h'似乎不會在接下來的16行中使用。這讓我懷疑他們是否被使用過。如果他們沒有使用,刪除它。 –

+0

另外:你說圖片看起來不對。這告訴我問題在於加密方法。解密方法應該與問題無關。去掉它。最後,在我離開這裏之前,有太多的'String's。如果需要位操作的操作使用瞭如此多的字符串和很少的字節,那麼就會出現問題。 –

回答

0

錯誤的事實,源自PNG圖像有一個前透明通道。 System.out.println(pixelsBin.length);返回jpg的338355個字節和png的451140個字節。

最簡單的解決方案是根據格式文件創建合適的imageNew。例如,

int w = image.getWidth(); 
int h = image.getHeight(); 
BufferedImage imageNew = null; 
if (imageSource.matches(".*jpg$")) { 
    imageNew = new BufferedImage(w, h, BufferedImage.TYPE_3BYTE_BGR); 
} else if (imageSource.matches(".*png$")) { 
    imageNew = new BufferedImage(w, h, BufferedImage.TYPE_4BYTE_ABGR); 
} else { 
    // whatever 
} 
imageNew.setData(Raster.createRaster(imageNew.getSampleModel(), new DataBufferByte(pixelsBinNew, pixelsBinNew.length), new Point())); 

但是,你必須要知道該消息未嵌入這兩種類型在同一個像素。三通道圖像(不透明度)的字節數組是這樣

first-pixel-BLUE, first-pixel-GREEN, first-pixel-RED, second-pixel-BLUE, etc 

而對於一個4通道圖像

first-pixel-ALPHA, first-pixel-BLUE, first-pixel-GREEN, first-pixel-RED, second-pixel-ALPHA, etc 

如果你關心這個細節,你可能會感興趣的removing the alpha channel from the png首先,所以你總是使用3通道圖像。

相關問題