Advertisement
Guest User

Encoding arbitrary files in PNG's

a guest
Nov 12th, 2013
217
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 8.07 KB | None | 0 0
  1. package com.ignatieff.tepng;
  2.  
  3. import java.awt.image.BufferedImage;
  4. import java.io.File;
  5. import java.io.FileInputStream;
  6. import java.io.FileNotFoundException;
  7. import java.io.FileOutputStream;
  8. import java.io.IOException;
  9.  
  10. import javax.imageio.ImageIO;
  11.  
  12. public class Encoder {
  13.    
  14.     BufferedImage img;
  15.    
  16.     private static byte[] empty = { 0x00, 0x00, 0x00, 0x00, 0x00 };
  17.    
  18.     public Encoder(BufferedImage image){
  19.         img = image;
  20.     }
  21.    
  22.     public Encoder(String path) throws IOException{
  23.         this(loadImage(path));
  24.     }
  25.    
  26.     private static BufferedImage loadImage(String path) throws IOException{
  27.         File f = new File(path);
  28.         BufferedImage i = ImageIO.read(f);
  29.         return i;
  30.     }
  31.    
  32.     public void saveImage(String path) throws IOException{
  33.         File f = new File(path);
  34.         ImageIO.write(img, "png", f);
  35.     }
  36.    
  37.     public static int getBit(int input, int bit){
  38.         if((input & (1 << bit)) != 0)return 1;
  39.         return 0;
  40.     }
  41.    
  42.     private boolean writeChar(char c, int x, int y){
  43.         int i = translateChar(c);
  44.         if(i==-1)return false;
  45.         encodeData(i, x, y);
  46.         return true;
  47.     }
  48.    
  49.     private char readChar(int x, int y){
  50.         return translateInt(decodeData(x,y));
  51.     }
  52.    
  53.     public void encodeMessage(String message){
  54.         encodeMessage(message, 1);
  55.     }
  56.    
  57.     public void encodeMessage(String message, String key){
  58.         encodeMessage(message, key.hashCode());
  59.     }
  60.    
  61.     public String getMessage(){
  62.         return getMessage(1);
  63.     }
  64.    
  65.     public String getMessage(String key){
  66.         return getMessage(key.hashCode());
  67.     }
  68.    
  69.     public void encodeMessage(String message, int key){
  70.         int max = img.getHeight() * img.getWidth();
  71.         if(message.length()+5 >= max){return;}
  72.         Group g = new Group(max, key);
  73.         char[] c = (message+"'.!.'").toCharArray();
  74.         int x = 0, y = 0;
  75.         for(int i=0;i<c.length;i++){
  76.             if(writeChar(c[i],x,y)){
  77.                 x+=g.PRIME;
  78.                 while(x>=img.getWidth()){x-=img.getWidth();y++;}
  79.                 if(y>=img.getHeight()){y%=img.getHeight();}
  80.             }
  81.         }
  82.     }
  83.    
  84.     public String getMessage(int key){
  85.         String r = "";
  86.         Group g = new Group(img.getHeight() * img.getWidth(), key);
  87.         int x=0, y=0;
  88.         while(!r.contains("'.!.'")){
  89.             while(x>=img.getWidth()){x-=img.getWidth();y++;}
  90.             if(y>=img.getHeight()){y%=img.getHeight();}
  91.             r+=readChar(x,y);
  92.             x+=g.PRIME;
  93.         }
  94.         return r.substring(0,r.length()-5);
  95.     }
  96.    
  97.     private int decodeData(int x, int y){
  98.         int argb = img.getRGB(x, y);
  99.        
  100.         int r = (argb)&0xFF;
  101.         int g = (argb>>8)&0xFF;
  102.         int b = (argb>>16)&0xFF;
  103.        
  104.         int rDec = (getBit(r, 1) << 1) | getBit(r, 0);
  105.         int gDec = getBit(g, 0);
  106.         int bDec = (getBit(b, 1) << 1) | getBit(b, 0);
  107.        
  108.         int data = (bDec << 3)|(gDec << 2)|rDec;
  109.        
  110.         return data;
  111.     }
  112.    
  113.     private int getBit(byte b, int bit){
  114.         if((b & (1 << bit))!=0)return 1;return 0;
  115.     }
  116.    
  117.     private int[] convertToBits(byte[] bytes){
  118.         int a = bytes.length*8;
  119.         int[] r = new int[a];
  120.         for(int i=0; i<bytes.length; i++){
  121.             for(int j=0; j<8; j++){
  122.                 r[a-((bytes.length-1-i)*8+j)-1] = getBit(bytes[i], j);
  123.             }
  124.         }
  125.         return r;
  126.     }
  127.    
  128.     public byte[] readBytes(int x, int y){
  129.         int[] bits = new int[40];
  130.         for(int i=0; i<8; i++){
  131.             int a;
  132.             if(x+i<img.getWidth()){
  133.                 a = decodeData(x+i, y);
  134.             }else{
  135.                 a = decodeData((x+i)-img.getWidth(), y+1);
  136.             }
  137.             for(int j=0; j<5; j++){
  138.                 bits[i*5+j]=getBit(a, 4-j);
  139.             }
  140.         }
  141.         return convertToBytes(bits);
  142.     }
  143.    
  144.     private byte[] convertToBytes(int[] bits){
  145.         if(bits.length%8!=0)return null;
  146.         int p = bits.length/8;
  147.         byte[] r = new byte[p];
  148.         for(int i=0; i<p; i++){
  149.             int a = 0;
  150.             for(int j=0; j<8; j++){
  151.                 a |= bits[i*8+j];
  152.                 if(j!=7)a<<=1;
  153.             }
  154.             r[i] = (byte)a;
  155.         }
  156.         return r;
  157.     }
  158.    
  159.     private byte[] appendBytes(byte[] b){
  160.         byte[] r = b;
  161.         while(b.length%5!=0){
  162.             byte[] q = new byte[r.length+1];
  163.             for(int i=0; i<r.length; i++){
  164.                 q[i] = r[i];
  165.             }
  166.             q[r.length] = 0x00;
  167.             r=q;
  168.         }
  169.         return r;
  170.     }
  171.    
  172.     private byte[] appendBytes(byte[] b, byte[] c){
  173.         byte[] newArray = new byte[b.length+c.length];
  174.         for(int i=0; i<b.length; i++){
  175.             newArray[i] = b[i];
  176.         }
  177.         for(int i=0; i<c.length; i++){
  178.             newArray[b.length+i] = c[i];
  179.         }
  180.         return newArray;
  181.     }
  182.    
  183.     private boolean isNull(byte[] b){
  184.         for(int i=0; i<b.length; i++){
  185.             if(b[i] != 0)return false;
  186.         }
  187.         return true;
  188.     }
  189.    
  190.     public void encodeFile(String path, String key) throws IOException{
  191.         encodeFile(path, key.hashCode());
  192.     }
  193.    
  194.     public void encodeFile(String path, int key) throws IOException{
  195.         encodeFile(readFile(path), key);
  196.     }
  197.    
  198.     public void saveContentFile(String path, String key) throws IOException{
  199.         saveContentFile(path, key.hashCode());
  200.     }
  201.    
  202.     public void saveContentFile(String path, int key) throws IOException{
  203.         File f = new File(path);
  204.         byte[] data = readFile(key);
  205.         FileOutputStream fos = new FileOutputStream(f);
  206.         fos.write(data);
  207.         fos.close();
  208.     }
  209.    
  210.     private byte[] readFile(String path) throws IOException{
  211.         File f = new File(path);
  212.         FileInputStream fin = new FileInputStream(f);
  213.         byte fileContent[] = new byte[(int)f.length()];
  214.         fin.read(fileContent);
  215.         fin.close();
  216.         return fileContent;
  217.     }
  218.    
  219.     private void printByte(byte[] b){
  220.         String s = "{ '";
  221.         for(int i=0; i<b.length; i++){
  222.             s+=(int)b[i] + "', '";
  223.         }
  224.         System.out.println( s.substring(0, s.length()-3) + " }" );
  225.     }
  226.    
  227.     public byte[] readFile(int key){
  228.         byte[] bytes = new byte[0];
  229.         Group g = new Group((img.getWidth()*img.getHeight())/8, key);
  230.         boolean isDone = false;
  231.         int x = 0, y = 0;
  232.         while(!isDone){
  233.             //System.out.println("reading from ("+x+", "+y+")");
  234.             byte[] next = readBytes(x*8,y*8);
  235.             //printByte(next);
  236.             bytes = appendBytes(bytes, next);
  237.             if(isNull(next)){isDone=true;}
  238.             x+=g.PRIME;
  239.  
  240.             while(x>=img.getWidth()/8){x-=img.getWidth()/8;y++;}
  241.             if(y>=img.getHeight()/8){y%=img.getHeight()/8;}
  242.         }
  243.         return bytes;
  244.     }
  245.    
  246.     public void encodeFile(byte[] bytes, String key){
  247.         encodeFile(bytes, key.hashCode());
  248.     }
  249.    
  250.     public void encodeFile(byte[] bytes, int key){
  251.         if(bytes.length >= (img.getWidth() * img.getHeight())/5)return;
  252.         byte[] e = appendBytes(appendBytes(bytes, empty));
  253.         int max  = e.length/5;
  254.         int size = (img.getWidth()*img.getHeight())/8; 
  255.         Group g = new Group(size, key);
  256.         int x=0, y=0;
  257.         for(int i=0; i<max; i++){
  258.             encodeBytes(subarray(e,i*5,5),x*8,y*8);
  259.             x+=g.PRIME;
  260.             while(x>=img.getWidth()/8){x-=img.getWidth()/8;y++;}
  261.             if(y>=img.getHeight()/8){y%=img.getHeight()/8;}
  262.         }
  263.     }
  264.    
  265.     private byte[] subarray(byte[] array, int start, int len){
  266.         byte[] newArray = new byte[len];
  267.         for(int i=0; i<len; i++){
  268.             newArray[i] = array[start+i];
  269.         }
  270.         return newArray;
  271.     }
  272.    
  273.     private void encodeBytes(byte[] bytes, int x, int y){
  274.         if(bytes.length!=5){return;}
  275.         int[] bits = convertToBits(bytes);
  276.         for(int i=0; i<8; i++){
  277.             int a = 0;
  278.             for(int j=0; j<5; j++){
  279.                 a |= bits[i*5+j];
  280.                 if(j!=4)a<<=1;
  281.             }
  282.             if(x+i<img.getWidth()){
  283.                 encodeData(a, x+i, y);
  284.             }else{
  285.                 encodeData(a, (x+i)-img.getWidth(), y+1);
  286.             }
  287.         }
  288.     }
  289.    
  290.     private void encodeData(int data, int x, int y){
  291.        
  292.         if(data>=32){return;}
  293.        
  294.         int rEnc = (getBit(data, 1) << 1)|getBit(data, 0);
  295.         int gEnc = getBit(data, 2);
  296.         int bEnc = (getBit(data, 4) << 1)|getBit(data, 3);
  297.         int argb = img.getRGB(x, y);
  298.  
  299.         int r = (((argb)&0xFF) >> 2) << 2;
  300.         int g = (((argb>>8)&0xFF) >> 1) << 1;
  301.         int b = (((argb>>16)&0xFF) >> 2) << 2;
  302.        
  303.         int newR = r | rEnc;
  304.         int newG = g | gEnc;
  305.         int newB = b | bEnc;
  306.        
  307.         int newARGB = (newB << 16)|(newG << 8)|newR;
  308.        
  309.         img.setRGB(x, y, newARGB);
  310.     }
  311.    
  312.     public static char translateInt(int i){
  313.         if(i <= 25)return (char)(i+65);
  314.         switch(i){
  315.             case 26:
  316.                 return ' ';
  317.             case 27:
  318.                 return '.';
  319.             case 28:
  320.                 return ',';
  321.             case 29:
  322.                 return '!';
  323.             case 30:
  324.                 return '?';
  325.             case 31:
  326.                 return '\'';
  327.         }
  328.         return '#';
  329.     }
  330.    
  331.     public static int translateChar(char c){
  332.         if((int)c >= 65 && (int)c <=90){
  333.             return (int)c-65;
  334.         }
  335.         if((int)c >= 97 && (int)c <=122){
  336.             return (int)c-97;
  337.         }
  338.         switch(c){
  339.             case ' ':
  340.                 return 26;
  341.             case '.':
  342.                 return 27;
  343.             case ',':
  344.                 return 28;
  345.             case '!':
  346.                 return 29;
  347.             case '?':
  348.                 return 30;
  349.             case '\'':
  350.                 return 31;
  351.         }
  352.         return -1;
  353.     }
  354.    
  355. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement