Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import java.awt.image.BufferedImage;
- import java.util.Arrays;
- import org.apache.commons.lang3.math.NumberUtils;
- import org.apache.commons.math3.analysis.interpolation.SplineInterpolator;
- import org.apache.commons.math3.analysis.polynomials.PolynomialSplineFunction;
- public class ImageHandler
- {
- public static final int N = 8;
- private final int T1 = 6, T2 = 3, E=35;
- final int xn=24;
- private BufferedImage input;
- private int height, width, blocksNum;
- private byte[] dataToHide;
- private int[][] blocks;
- private int[][] blueBlocks;
- private int[][] delta;
- private int[][] zones;
- private int[][] masks;
- public ImageHandler(BufferedImage img)
- {
- input = img;
- height = input.getHeight();
- width = input.getWidth();
- blocksNum = height*width/(N*N);
- }
- public BufferedImage encrypt(String str) throws Exception
- {
- //convert input string to binary sequence
- dataToHide = this.stringToBinary(str);
- if (dataToHide.length > blocksNum)
- throw new Exception("There is not enough space in the image to hide the message");
- //System.out.println( Arrays.toString(dataToHide) );
- blocks = new int[blocksNum][N*N];
- blueBlocks = new int[blocksNum][N*N];
- zones = new int[blocksNum][N*N];
- masks = new int[blocksNum][N*N];
- delta = new int[blocksNum][4];
- //splitting image to 64-pixels blocks, picking out blue components
- splitInput();
- //splitting every block to zones according to intensity of its blue component
- splitToZones();
- //System.out.println( Arrays.toString(zones[0]) );
- //generating mask for each block
- generateMasks();
- //System.out.println( Arrays.toString(masks[0]) );
- //computing intensity shifts based on masks and zones
- computeDelta();
- //data integration into blue blocks
- shiftData();
- //normalizing blue blocks
- normalizeData();
- //integrating blue blocks back to the pixels blocks
- integrateData();
- BufferedImage output = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
- return uniteOutput(output);
- }
- public String decrypt()
- {
- blocks = new int[blocksNum][N*N];
- blueBlocks = new int[blocksNum][N*N];
- zones = new int[blocksNum][N*N];
- masks = new int[blocksNum][N*N];
- //splitting image to 64-pixels blocks, picking out blue components
- splitInput();
- //splitting every block to zones according to intensity of its blue component
- splitToZones();
- //System.out.println( Arrays.toString(zones[0]) );
- //generating mask for each block
- generateMasks();
- return extract();
- }
- private void splitInput()
- {
- int startX = 0, startY = 0;
- for (int i=0; i<blocksNum; i++)
- {
- if (startX>=width)
- {
- startX = 0;
- startY += N;
- }
- blocks[i] = input.getRGB(startX, startY, N, N, null, 0, N);
- for(int j=0; j<N*N; j++)
- blueBlocks[i][j] = getBlue(blocks[i][j]);
- startX += N;
- }
- }
- private void splitToZones()
- {
- for (int i=0; i<xn; i++)
- {
- int[] currentBlock = Arrays.copyOf(blueBlocks[i], N*N);
- //sorting the block
- Arrays.sort(currentBlock);
- //System.out.println( Arrays.toString(currentBlock) );
- //splining function
- int r = 10;
- double[] hi = new double[r];
- double[] fi = new double[r];
- for (int j=0; j<r; j++)
- {
- hi[j] = j*Math.round(N*N/(r-1));
- fi[j] = currentBlock[(int) hi[j]];
- }
- SplineInterpolator interpolator = new SplineInterpolator();
- PolynomialSplineFunction spline = interpolator.interpolate(hi,fi);
- double sMax = 0, alpha = -1;
- for (int x = 0; x<N*N; x++)
- {
- if (spline.derivative().value(x) > sMax)
- {
- sMax = spline.derivative().value(x);
- alpha = x;
- }
- }
- if (alpha == -1)
- alpha = N*N/2;
- else if (alpha == 0)
- alpha = 1;
- else if(alpha == N*N-1)
- alpha = N*N-2;
- int bminus=0, bplus=0;
- if (sMax < T1) // noise contrast
- {
- int k=0;
- for (int j=0; j<zones[i].length; j++)
- {
- zones[i][j] = (j+k)%2 + 1;
- if ( (j+1) % 8 == 0)
- ++k;
- }
- }
- else // sharp contrast
- {
- //bminus
- for (int j=(int)alpha; j>=0; j--)
- {
- if (j==0)
- bminus = (int)alpha;
- if (currentBlock[(int)alpha] - currentBlock[j] > T2)
- {
- bminus = j;
- break;
- }
- }
- //bplus
- for (int j=(int)alpha; j<N*N; j++)
- {
- if (j==N*N-1)
- bplus = (int)alpha;
- if (currentBlock[j] - currentBlock[(int)alpha] > T2)
- {
- bplus = j;
- break;
- }
- }
- // split pixels to zones
- for (int j=0; j<currentBlock.length; j++)
- {
- if ( getBlue(blocks[i][j]) < currentBlock[bminus] )
- zones[i][j] = 1;
- else if ( getBlue(blocks[i][j]) > currentBlock[bplus] )
- zones[i][j] = 2;
- else
- zones[i][j] = 0;
- }
- }
- }
- }
- private void generateMasks()
- {
- int k0=123;
- for (int i=0; i<xn; i++)
- {
- Arrays.fill(masks[i], 0);
- for (int j=0; j<N*N/2; j++)
- masks[i][ ( i+j*k0 ) % (N*N) ] = 1;
- for (int j=0; j<N*N; j++)
- if (masks[i][j] != 1)
- masks[i][j] = 2;
- }
- }
- private void computeDelta()
- {
- for (int i=0; i<xn; i++)
- {
- byte b = dataToHide[i];
- int[] B = blueBlocks[i];
- int[] Z = zones[i];
- int[] M = masks[i];
- int[] n = new int[4];
- double[] sl = new double[4];
- double[] sl_star = new double[4];
- for (int j=0; j<N*N; j++)
- {
- if (Z[j]==1 && M[j]==1) { ++n[0]; sl[0] += B[j]; }
- else if (Z[j]==1 && M[j]==2) { ++n[1]; sl[1] += B[j]; }
- else if (Z[j]==2 && M[j]==1) { ++n[2]; sl[2] += B[j]; }
- else if (Z[j]==2 && M[j]==2) { ++n[3]; sl[3] += B[j]; }
- }
- sl[0] = sl[0]==0 ? 0 : sl[0]/n[0];
- sl[1] = sl[1]==0 ? 0 : sl[1]/n[1];
- sl[2] = sl[2]==0 ? 0 : sl[2]/n[2];
- sl[3] = sl[3]==0 ? 0 : sl[3]/n[3];
- for (int x=0; x<2; x++)
- {
- double lx = (sl[2*x]*n[2*x] + sl[2*x+1]*n[2*x+1]);
- if (b == 1)
- {
- sl_star[2*x] = ( - lx - n[2*x+1]*E )/( - n[2*x] - n[2*x+1] );
- sl_star[2*x+1] = ( n[2*x]*E - lx )/( - n[2*x] - n[2*x+1] );
- } else
- {
- sl_star[2*x] = ( lx - n[2*x+1]*E )/( n[2*x] + n[2*x+1] );
- sl_star[2*x+1] = ( n[2*x]*E + lx )/( n[2*x] + n[2*x+1] );
- }
- }
- //with transposition
- delta[i][0] = (int) Math.round( sl_star[0] - sl[0] );
- delta[i][1] = (int) Math.round( sl_star[1] - sl[1] );
- delta[i][2] = (int) Math.round( sl_star[2] - sl[2] );
- delta[i][3] = (int) Math.round( sl_star[3] - sl[3] );
- //System.out.println( (sl_star[0] - sl[0]) + " " + (sl_star[1] - sl[1]) );
- //System.out.println( (sl_star[2] - sl[2]) + " " + (sl_star[3] - sl[3]) );
- //System.out.println(delta[i][0] + " " + delta[i][1]);
- //System.out.println(delta[i][2] + " " + delta[i][3]);
- }
- }
- private void shiftData()
- {
- for (int i=0; i<xn; i++)
- {
- int[] Z = zones[i];
- int[] M = masks[i];
- for (int j=0; j<xn; j++)
- {
- if (Z[j]==1 && M[j]==1) { blueBlocks[i][j] += delta[i][0]; }
- else if (Z[j]==1 && M[j]==2) { blueBlocks[i][j] += delta[i][1]; }
- else if (Z[j]==2 && M[j]==1) { blueBlocks[i][j] += delta[i][2]; }
- else if (Z[j]==2 && M[j]==2) { blueBlocks[i][j] += delta[i][3]; }
- }
- }
- }
- private void normalizeData()
- {
- int min = 256;
- int max = 0;
- for (int i=0; i<blueBlocks.length; i++)
- {
- if ( NumberUtils.min(blueBlocks[i]) < min)
- min = NumberUtils.min(blueBlocks[i]);
- if ( NumberUtils.max(blueBlocks[i]) > max)
- max = NumberUtils.max(blueBlocks[i]);
- }
- for (int i=0; i<blueBlocks.length; i++)
- for (int j=0; j<blueBlocks[i].length; j++)
- blueBlocks[i][j] = Math.round( (blueBlocks[i][j] + Math.abs(min))*255/(max + Math.abs(min)) );
- }
- private String extract()
- {
- StringBuilder res = new StringBuilder();
- for (int i=0; i<xn; i++)
- {
- int[] B = blueBlocks[i];
- int[] Z = zones[i];
- int[] M = masks[i];
- int[] n = new int[4];
- double[] sl = new double[4];
- for (int j=0; j<N*N; j++)
- {
- if (Z[j]==1 && M[j]==1) { ++n[0]; sl[0] += B[j]; }
- else if (Z[j]==1 && M[j]==2) { ++n[1]; sl[1] += B[j]; }
- else if (Z[j]==2 && M[j]==1) { ++n[2]; sl[2] += B[j]; }
- else if (Z[j]==2 && M[j]==2) { ++n[3]; sl[3] += B[j]; }
- }
- sl[0] = sl[0]==0 ? 0 : sl[0]/n[0];
- sl[1] = sl[1]==0 ? 0 : sl[1]/n[1];
- sl[2] = sl[2]==0 ? 0 : sl[2]/n[2];
- sl[3] = sl[3]==0 ? 0 : sl[3]/n[3];
- double E1 = sl[0] - sl[1];
- double E2 = sl[2] - sl[3];
- if ( E1*E2 > 0.05 )
- {
- if (E1 > 0)
- res.append('1');
- else
- res.append('0');
- } else if ( E1*E2 < -0.05 )
- {
- double Estar = E1*(n[0]+n[1]) + E2*(n[2]+n[3]);
- if (Estar > 0)
- res.append('1');
- else
- res.append('0');
- } else
- {
- double Estar = Math.max(E1, E2);
- if (Estar > 0)
- res.append('1');
- else
- res.append('0');
- }
- }
- return res.toString();
- }
- private void integrateData()
- {
- for (int i=0; i<xn; i++)
- {
- for (int j=0; j<blueBlocks[i].length; j++)
- blocks[i][j] = (int) changeBlue(blocks[i][j], blueBlocks[i][j]);
- }
- }
- private BufferedImage uniteOutput(BufferedImage img)
- {
- int startX = 0, startY = 0;
- for (int i=0; i<blocksNum; i++)
- {
- if (startX>=width)
- {
- startX = 0;
- startY += N;
- }
- img.setRGB(startX, startY, N, N, blocks[i], 0, N);
- startX += N;
- }
- return img;
- }
- private byte[] stringToBinary(String str)
- {
- byte[] bytes = str.getBytes();
- byte[] binary = new byte[bytes.length*8];
- for (int i=0; i<bytes.length; i++)
- {
- int val = bytes[i];
- for (int j = 0; j < 8; j++)
- {
- binary[i*8+j] = (byte) ((val & 128) == 0 ? 0 : 1);
- val <<= 1;
- }
- }
- return binary;
- }
- private int getBlue(int z) { return Integer.parseInt( String.format("%32s", Integer.toBinaryString( z ) ).replace(' ', '0').substring(24, 32), 2); }
- private long changeBlue(int b, int bb)
- {
- String sb = String.format("%32s", Integer.toBinaryString( b ) ).replace(' ', '0');
- String sbb = String.format("%8s", Integer.toBinaryString( bb ) ).replace(' ', '0');
- StringBuilder sBuilder = new StringBuilder(sb);
- sBuilder = sBuilder.replace(24, 32, sbb);
- return Long.parseLong(sBuilder.toString(),2);
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement