// SteganographyEncoder.java // Input: // publicImage.bmp // the "fake" image // secretImage.bmp // the black-and-white image containing the real secret // Output: // bwSecretImage.bmp // the actual black-and-white image encoded // codedImage.bmp // the "fake' image with the secretImage inside it import java.awt.*; import java.awt.image.*; import javax.imageio.*; import java.io.*; import javax.swing.*; class SteganographyEncoder { public static void main(String[] args) { BufferedImage secretImage = loadBufferedImage("secretImage.bmp"); BufferedImage publicImage = loadBufferedImage("publicImage.bmp"); Dimension publicDim = getImageSize(publicImage, 1, 0); Dimension secretDim = getImageSize(secretImage, 1, 0); BufferedImage bwSecretImage = new BufferedImage(secretDim.width, secretDim.height, BufferedImage.TYPE_INT_RGB); BufferedImage codedImage = new BufferedImage(publicDim.width, publicDim.height, BufferedImage.TYPE_INT_RGB); // Change all "nearly-black" pixels to blue! for (int x=0; x> 24) & 0xff; int red = (rgba >> 16) & 0xff; int green = (rgba >> 8) & 0xff; int blue = (rgba ) & 0xff; int pixel = 0; if ((x < secretDim.width) && (y < secretDim.height)) { int rgba2 = secretImage.getRGB(x,y); int alpha2 = (rgba2 >> 24) & 0xff; int red2 = (rgba2 >> 16) & 0xff; int green2 = (rgba2 >> 8) & 0xff; int blue2 = (rgba2 ) & 0xff; int grayscale2 = (int)((0.3*red2)+(0.59*green2)+(0.11*blue2)); if (grayscale2 < 128) { red2 = green2 = blue2 = 0; pixel = 0; } else { red2 = green2 = blue2 = 255; pixel = 1; } alpha2 = 0; rgba2 = (alpha2 << 24) | (red2 << 16) | (green2 << 8) | (blue2); bwSecretImage.setRGB(x,y,rgba2); } red = red/2*2 + pixel; rgba = (alpha << 24) | (red << 16) | (green << 8) | (blue); codedImage.setRGB(x,y,rgba); } saveBufferedImage(bwSecretImage, "bwSecretImage.bmp"); saveBufferedImage(codedImage, "codedImage.bmp"); } ////////////////////////////////////// /// Image Helper methods ///////////////////////////////////// // Paint the given image rotated and scaled with a top-left at x,y public static void drawImage(Graphics page, Image image, int x, int y, double scale, double radians) { double imageWidth = image.getWidth(null); double imageHeight = image.getHeight(null); Dimension newSize = getImageSize(image, scale, radians); java.awt.geom.AffineTransform transform = new java.awt.geom.AffineTransform(); transform.translate(x+newSize.getWidth()/2,y+newSize.getHeight()/2); // last (not first!) transform.rotate(radians); transform.scale(scale,scale); transform.translate(-imageWidth/2, -imageHeight/2); // first ((Graphics2D)page).drawImage(image,transform,null); } // Same as drawImage, only here we position the image by its center public static void drawCenteredImage(Graphics page, Image image, int cx, int cy, double scale, double radians) { Dimension newSize = getImageSize(image, scale, radians); drawImage(page, image, cx - newSize.width/2, cy - newSize.height/2, scale, radians); } // get the size of this image after it has been scaled and rotated public static Dimension getImageSize(Image image, double scale, double radians) { double imageWidth = image.getWidth(null); double imageHeight = image.getHeight(null); java.awt.geom.AffineTransform transform = new java.awt.geom.AffineTransform(); transform.rotate(radians); transform.scale(scale,scale); transform.translate(-imageWidth/2, -imageHeight/2); // first double[] x = { 0, imageWidth, imageWidth , 0 }; double[] y = { 0, 0 , imageHeight, imageHeight }; double minx=0, maxx=0, miny=0, maxy=0; java.awt.geom.Point2D.Double src = new java.awt.geom.Point2D.Double(); java.awt.geom.Point2D.Double dst = new java.awt.geom.Point2D.Double(); for (int i=0; i<4; i++) { src.setLocation(x[i],y[i]); transform.transform(src,dst); if (i == 0) { minx = maxx = dst.getX(); miny = maxy = dst.getY(); } else { minx = Math.min(dst.getX(),minx); miny = Math.min(dst.getY(),miny); maxx = Math.max(dst.getX(),maxx); maxy = Math.max(dst.getY(),maxy); } } return new Dimension((int)(maxx-minx), (int)(maxy-miny)); } // Convert a jpg/png/etc file into an awt BufferedImage public static BufferedImage loadBufferedImage(String filename) { File file = new File(filename); if (!file.exists()) throw new RuntimeException("File " + filename + " does not exist"); try { return ImageIO.read(file); } catch (Exception e) { throw new RuntimeException(e); } } // Verify the given the file format is one that is supported. public static void verifyFileFormatIsSupported(String format) { String[] legalFormats = ImageIO.getReaderFormatNames(); for (String legalFormat : legalFormats) if (legalFormat.equals(format)) return; throw new RuntimeException("Illegal format " + format + " not in " + java.util.Arrays.toString(legalFormats)); } // Save the BufferedImage into the given file -- the image type is determined // by the extension of the file (.bmp, .png, etc) public static void saveBufferedImage(BufferedImage image, String filename) { int dotIndex = filename.lastIndexOf('.'); if (dotIndex < 0) throw new RuntimeException("file must end in .bmp, .png, etc"); String format = filename.substring(dotIndex+1); verifyFileFormatIsSupported(format); try { ImageIO.write(image, format, new File(filename)); } catch (Exception e) { throw new RuntimeException(e); } } }