Search code examples
javaimageimage-processingcompressionimage-compression

How to decompress an image stored using stenography?


I am currently doing project related to "image steganography" in Java, for that I want to compress and decompress the secret image. I have done the compression part. But I don't know how to perform the decompression part.

I have compressed the JPEG image using the following code:

public class CompressJPEGFile {

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

        File imageFile = new File("C:\\Users\\user\\Desktop\\encryption\\d.jpg");

        File compressedImageFile = new File("C:\\Users\\user\\Desktop\\encryption\\compress.jpg");

        InputStream is = new FileInputStream(imageFile);

        OutputStream os = new FileOutputStream(compressedImageFile);

        float quality = 0.5f;

        BufferedImage image = ImageIO.read(is);

        // get all image writers for JPG format

        Iterator<ImageWriter> writers = ImageIO.getImageWritersByFormatName("jpg");

        if (!writers.hasNext())

            throw new IllegalStateException("No writers found");

        ImageWriter writer = (ImageWriter) writers.next();

        ImageOutputStream ios = ImageIO.createImageOutputStream(os);

        writer.setOutput(ios);

        ImageWriteParam param = writer.getDefaultWriteParam();

        param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);

        param.setCompressionQuality(quality);



        //associated stream and image metadata and thumbnails to the output

        writer.write(null, new IIOImage(image, null, null), param);

        // close all streams

        is.close();

        os.close();

        ios.close();

        writer.dispose();

    }
}

I have written the code for decompression. Is the code right if I am not considering the quality of image?

 public static void decompress() throws FileNotFoundException {
        try {

            File compressedImageFile = new File("C:\\Users\\user\\Desktop\\encryption\\compressnew.jpg");
             File imageFile = new File("C:\\Users\\user\\Desktop\\encryption\\dnew.jpg");


            InputStream is = new FileInputStream(compressedImageFile);

            OutputStream os = new FileOutputStream(imageFile );

            BufferedImage image = ImageIO.read(is);

            // get all image writers for JPG format

            Iterator<ImageWriter> writers = ImageIO.getImageWritersByFormatName("jpg");

            if (!writers.hasNext()) {
                throw new IllegalStateException("No writers found");
            }

            ImageWriter writer = (ImageWriter) writers.next();

            ImageOutputStream ios = ImageIO.createImageOutputStream(os);

            writer.setOutput(ios);

            ImageWriteParam param = writer.getDefaultWriteParam();

            writer.write(null, new IIOImage(image, null, null), param);

            //associated stream and image metadata and thumbnails to the output

            is.close();

            os.close();

            ios.close();

            writer.dispose();
        } catch (IOException ex) {
            Logger.getLogger(CompressJPEGFile.class.getName()).log(Level.SEVERE, null, ex);
        }

    }

Solution

  • I think you are looking for a lossless a compression scheme that is such that you can retrieve a secret from steganography. That means you need to move away from jpg as your compression format - it is lossy. That means that once you have put your secret + cover image through the jpg compression, the original cannot be recovered by a simple 'decompression' call at the other end, i.e. the JPEG compression algorithm is not reversible.

    You ask in comments about libraries for compression / decompression rather than steganography. You are already using one in your code example (ImageIO). If you want to take your original image and transcode it to PNG (i.e. lossless compression), ImageIO can do that simply - see this question for details. JAI is commonly used if you need more advanced features. The PNG format offers a lossless compression option.

    EDIT:

    some code to show using ImageIO using PNG format as requested by OP in comments. By default ImageIO uses compression when you write PNG's. At the receive end, simply read the PNG, you get the original back.:

    public class JPEGFileToPNG {
    
    public static void main(String[] args) throws IOException {
    
        File imageFile = new File("C:\\Users\\user\\Desktop\\encryption\\d.jpg");
        File compressedImageFile = new File("C:\\Users\\user\\Desktop\\encryption\\compress.png");
    
        BufferedImage image = ImageIO.read(imageFile.toURI().toURL());
    
        ImageIO.write(image, "png", compressedImageFile);
    
    }
    

    P.S. There are two levels at which to answer your question. At the more advanced (maybe research) level - people do work on using the actual errors introduced by JPG encoding to encode the secret in steganography (e.g. http://ieeexplore.ieee.org/xpls/abs_all.jsp?arnumber=1357167&tag=1) From the wording of your question, I don't think this is what you want, but it might be. In which case, your task is quite hard (writing a JPEG encoder / decoder and adapting it to hide secrets in the encoding table), but it has been done (e.g. this paper describes the method).