当前位置: 首页 > 知识库问答 >
问题:

隐写术,只有jpg作为输入工作,当使用png时,生成的图像看起来很奇怪

钱青青
2023-03-14

构建了一个小java程序,使用最低有效位方法在图像中隐藏消息。输入jpg文件时,它可以正常工作。输出可以是png或jpg。但当输入png时,结果看起来非常奇怪。

以下分别是原始图像和结果图像:

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;
}

}

此外,测试类:

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");
    }
}

共有1个答案

程景胜
2023-03-14

错误源于png图像具有额外的透明度通道<代码>系统。出来println(像素长度)为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()));

但是,您必须知道,这两种类型中的消息并不是以相同的像素嵌入的。3通道图像的字节数组(无透明度)如下所示

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

如果您关心该细节,您可能有兴趣首先从png中删除alpha通道,因此您始终使用3通道图像。

 类似资料:
  • 问题内容: 我环顾四周,阅读文档,没有找到任何方法或解决方案,所以我在这里问。是否有可用的软件包可用于使用Python将JPG图像转换为PNG图像? 问题答案: 为此,您始终可以使用Python图像库(PIL)。可能还会有其他包/库,但是我之前曾用过它来在格式之间进行转换。 这适用于Windows下的Python 2.7(适用于Python 2.7的Python Imaging Library 1

  • 这是我的 这是我的文件 这是我的依赖项

  • 问题内容: 我正在尝试调整一些图像的大小,其中大多数是JPG。但是在一些图像中,我得到了错误: 我没有更改图像类型,而是使用了枕头库。我的操作系统是Mac OSX。如何解决该问题? 问题答案: 您需要将图像转换为RGB模式。

  • 我有一个jsf表单,它包括p: autoCompelete字段。给你; 表单中有3个验证。它们是“必需=真”。此外,它们位于p:自动完成字段中。 所以,问题是,当我在没有输入的情况下单击“保存按钮”时,验证工作正常。然而,当我只在一个p:autocomplete字段中输入,然后单击“保存”按钮时,primefaces验证不起作用,我得到了java错误。我的意思是,由于另外两个必填字段为空,我希望得

  • 问题内容: 使用PHP将jpg图像转换为gif,png和bmp格式的可能重复项 我有一个PHP表单,该表单允许图像上传和检查以确保图像有效。 但是,我希望所有格式(PNG,JPG,JPEG和GIF)最终在提交后都是PNG。 我该怎么做呢? 问题答案: 然后,您只需要。实际上,它几乎变成了单线: 您将使用文件名,并且显然使用不同的输出文件名。但是图像格式探测本身将变得多余。

  • 问题内容: 如何使用PHP将单个jpg图像转换为3种不同的图像格式gif,png和bmp? 请帮助 问题答案: 首先,使用imagecreatefromjpeg()从文件中创建图像对象。然后,您将该对象转储为不同的格式(例如,使用imagegif()):