⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 jpegencoder.java

📁 基于JPEG图像的数字密写方法 F5算法的JAVA程序
💻 JAVA
📖 第 1 页 / 共 4 页
字号:
// Version 1.0a// Copyright (C) 1998, James R. Weeks and BioElectroMech.// Visit BioElectroMech at www.obrador.com.  Email James@obrador.com.// See license.txt for details about the allowed used of this software.// This software is based in part on the work of the Independent JPEG Group.// See IJGreadme.txt for details about the Independent JPEG Group's license.// This encoder is inspired by the Java Jpeg encoder by Florian Raemy,// studwww.eurecom.fr/~raemy.// It borrows a great deal of code and structure from the Independent// Jpeg Group's Jpeg 6a library, Copyright Thomas G. Lane.// See license.txt for details.// westfeld// todo:// switch for multi-volume embedding// indeterministic embedding// password switchpackage james;import crypt.Permutation;import crypt.F5Random;import java.applet.Applet;import java.awt.*;import java.awt.image.*;import java.io.*;import java.util.*;import java.lang.*;/** JpegEncoder - The JPEG main program which performs a jpeg compression of* an image.*/public class JpegEncoder extends Frame{    Thread runner;    BufferedOutputStream outStream;    Image image;    JpegInfo JpegObj;    Huffman Huf;    DCT dct;    int imageHeight, imageWidth;    int Quality;    int code;    public static int[] jpegNaturalOrder = {          0,  1,  8, 16,  9,  2,  3, 10,         17, 24, 32, 25, 18, 11,  4,  5,         12, 19, 26, 33, 40, 48, 41, 34,         27, 20, 13,  6,  7, 14, 21, 28,         35, 42, 49, 56, 57, 50, 43, 36,         29, 22, 15, 23, 30, 37, 44, 51,         58, 59, 52, 45, 38, 31, 39, 46,         53, 60, 61, 54, 47, 55, 62, 63,        };    // westfeld    FileInputStream embeddedData = null;    String password = null;    int n = 0;    public JpegEncoder(Image image, int quality, OutputStream out, String comment)    {                MediaTracker tracker = new MediaTracker(this);                tracker.addImage(image, 0);                try {                        tracker.waitForID(0);                }                catch (InterruptedException e) {// Got to do something?                }        /*        * Quality of the image.        * 0 to 100 and from bad image quality, high compression to good        * image quality low compression        */        Quality=quality;        /*        * Getting picture information        * It takes the Width, Height and RGB scans of the image.         */        JpegObj = new JpegInfo(image, comment);        imageHeight=JpegObj.imageHeight;        imageWidth=JpegObj.imageWidth;        outStream = new BufferedOutputStream(out);        dct = new DCT(Quality);        Huf=new Huffman(imageWidth,imageHeight);    }    public void setQuality(int quality) {        dct = new DCT(quality);    }    public int getQuality() {        return Quality;    }    public void Compress(FileInputStream embeddedData, String password) {    	this.embeddedData = embeddedData;    	this.password = password;	Compress();    }    public void Compress() {        WriteHeaders(outStream);        WriteCompressedData(outStream);        WriteEOI(outStream);        try {                outStream.flush();        } catch (IOException e) {                System.out.println("IO Error: " + e.getMessage());        }    }    public void WriteCompressedData(BufferedOutputStream outStream) {        int offset, i, j, r, c,a ,b, temp = 0;        int comp, xpos, ypos, xblockoffset, yblockoffset;        float inputArray[][];        float dctArray1[][] = new float[8][8];        double dctArray2[][] = new double[8][8];        int dctArray3[] = new int[8*8];        /*         * This method controls the compression of the image.         * Starting at the upper left of the image, it compresses 8x8 blocks         * of data until the entire image has been compressed.         */        int lastDCvalue[] = new int[JpegObj.NumberOfComponents];        int zeroArray[] = new int[64]; // initialized to hold all zeros        int Width = 0, Height = 0;        int nothing = 0, not;        int MinBlockWidth, MinBlockHeight;// This initial setting of MinBlockWidth and MinBlockHeight is done to// ensure they start with values larger than will actually be the case.        MinBlockWidth = ((imageWidth%8 != 0) ? (int) (Math.floor((double) imageWidth/8.0) + 1)*8 : imageWidth);        MinBlockHeight = ((imageHeight%8 != 0) ? (int) (Math.floor((double) imageHeight/8.0) + 1)*8: imageHeight);        for (comp = 0; comp < JpegObj.NumberOfComponents; comp++) {                MinBlockWidth = Math.min(MinBlockWidth, JpegObj.BlockWidth[comp]);                MinBlockHeight = Math.min(MinBlockHeight, JpegObj.BlockHeight[comp]);        }        xpos = 0;	// westfeld	// Before we enter these loops, we initialise the	// coeff for steganography here:	int shuffledIndex = 0;	int coeffCount = 0;        for (r = 0; r < MinBlockHeight; r++) {           for (c = 0; c < MinBlockWidth; c++) {              for (comp = 0; comp < JpegObj.NumberOfComponents; comp++) {                 for(i = 0; i < JpegObj.VsampFactor[comp]; i++) {		    for(j = 0; j < JpegObj.HsampFactor[comp]; j++) {			coeffCount += 64;                     }                  }               }            }        }        int coeff[] = new int[coeffCount];System.out.println("DCT/quantisation starts");System.out.println(imageWidth+" x "+imageHeight);        for (r = 0; r < MinBlockHeight; r++) {           for (c = 0; c < MinBlockWidth; c++) {               xpos = c*8;               ypos = r*8;               for (comp = 0; comp < JpegObj.NumberOfComponents; comp++) {                  Width = JpegObj.BlockWidth[comp];                  Height = JpegObj.BlockHeight[comp];                  inputArray = (float[][]) JpegObj.Components[comp];                  for(i = 0; i < JpegObj.VsampFactor[comp]; i++) {                     for(j = 0; j < JpegObj.HsampFactor[comp]; j++) {                        xblockoffset = j * 8;                        yblockoffset = i * 8;                        for (a = 0; a < 8; a++) {                           for (b = 0; b < 8; b++) {// I believe this is where the dirty line at the bottom of the image is// coming from.  I need to do a check here to make sure I'm not reading past// image data.// This seems to not be a big issue right now. (04/04/98)// westfeld - dirty line fixed, Jun 6 2000			int ia = ypos*JpegObj.VsampFactor[comp]			    + yblockoffset + a;			int ib = xpos*JpegObj.HsampFactor[comp]			    + xblockoffset + b;			if (imageHeight/2*JpegObj.VsampFactor[comp]<=ia)			    ia = imageHeight/2*JpegObj.VsampFactor[comp]-1;			if (imageWidth/2*JpegObj.HsampFactor[comp]<=ib)			    ib = imageWidth/2*JpegObj.HsampFactor[comp]-1;                              //dctArray1[a][b] = inputArray[ypos + yblockoffset + a][xpos + xblockoffset + b];                              dctArray1[a][b] = inputArray[ia][ib];                           }                        }// The following code commented out because on some images this technique// results in poor right and bottom borders.//                        if ((!JpegObj.lastColumnIsDummy[comp] || c < Width - 1) && (!JpegObj.lastRowIsDummy[comp] || r < Height - 1)) {                           dctArray2 = dct.forwardDCT(dctArray1);                           dctArray3 = dct.quantizeBlock(dctArray2, JpegObj.QtableNumber[comp]);//                        }//                        else {//                           zeroArray[0] = dctArray3[0];//                           zeroArray[0] = lastDCvalue[comp];//                           dctArray3 = zeroArray;//                        }			// westfeld			// For steganography, all dct			// coefficients are collected in			// coeff[] first. We do not encode			// any Huffman Blocks here (we'll do			// this later).			System.arraycopy(dctArray3, 0, coeff, shuffledIndex, 64);			shuffledIndex += 64;                     }                  }               }            }        }System.out.println("got "+coeffCount+" DCT AC/DC coefficients");	int _changed=0;	int _embedded=0;	int _examined=0;	int _expected=0;	int _one=0;	int _large=0;	int _thrown=0;	int _zero=0;	for (i=0; i<coeffCount; i++) {	    if ((i%64)==0) continue;	    if (coeff[i]==1) _one++;	    if (coeff[i]==-1) _one++;	    if (coeff[i]==0) _zero++;	}	_large=coeffCount-_zero-_one-coeffCount/64;	_expected=_large+(int)(0.49*_one);//// System.out.println("zero="+_zero);System.out.println("one="+_one);System.out.println("large="+_large);//System.out.println("expected capacity: "+_expected+" bits");System.out.println("expected capacity with");for (i=1; i<8; i++) {    int usable, changed, n;    n = (1<<i)-1;    usable = _expected*i/n-_expected*i/n%n;    changed = coeffCount-_zero-coeffCount/64;    changed = changed*i/n-changed*i/n%n;    changed = n*changed/(n+1)/i;    //    changed = _large-_large%(n+1);    changed = (changed+_one+_one/2-_one/(n+1))/(n+1);    usable /= 8;    if (usable == 0) break;    if (i==1)	System.out.print("default");    else	System.out.print("(1, "+n+", "+i+")");    System.out.println(" code: "+usable+" bytes (efficiency: "	    +((usable*8)/changed)+"."+(((usable*80)/changed)%10)	    +" bits per change)");}	// westfeld	if (embeddedData != null) {	// Now we embed the secret data in the permutated sequence.System.out.println("Permutation starts");	    F5Random random = new F5Random(password.getBytes());	    Permutation permutation = new Permutation(coeffCount, random);	    int nextBitToEmbed=0;	    int byteToEmbed=0;	    int availableBitsToEmbed=0;	    // We start with the length information.  Well,	    // the length information it is more than one	    // byte, so this first "byte" is 32 bits long.	    try {		byteToEmbed=embeddedData.available();	    } catch (Exception e) {		e.printStackTrace();	    }	    System.out.print("Embedding of "+(byteToEmbed*8+32)+" bits ("		+byteToEmbed+"+4 bytes) ");	    // We use the most significant byte for the 1 of n	    // code, and reserve one extra bit for future use.	    if (byteToEmbed>0x007fffff)		byteToEmbed=0x007fffff;	    // We calculate n now	    for (i=1; i<8; i++) {		int usable, changed;		n = (1<<i)-1;		usable = _expected*i/n-_expected*i/n%n;		usable /= 8;		if (usable == 0) break;		if (usable < byteToEmbed+4) break;	    }	    int k=i-1;	    n=(1<<k)-1;	    switch (n) {	    case 0:		System.out.println("using default code, file will not fit");		n++;		break;	    case 1:		System.out.println("using default code");		break;	    default:		System.out.println("using (1, "+n+", "+k+") code");	    }	    byteToEmbed |= k<<24;	// store k in the status word	    // Since shuffling cannot hide the distribution, the	    // distribution of all bits to embed is unified by	    // adding a pseudo random bit-string. We continue the random	    // we used for Permutation, initially seeked with password.	    byteToEmbed ^= random.getNextByte();	    byteToEmbed ^= random.getNextByte()<<8;	    byteToEmbed ^= random.getNextByte()<<16;	    byteToEmbed ^= random.getNextByte()<<24;	    nextBitToEmbed = byteToEmbed & 1;	    byteToEmbed >>= 1;	    availableBitsToEmbed=31;	    _embedded++;	    if (n > 1) {	// use 1 of n code		int kBitsToEmbed;		int extractedBit;		int[] codeWord = new int[n];		int hash;		int startOfN=0;		int endOfN=0;		boolean isLastByte = false;		// embed status word first		for(i=0; i<coeffCount; i++) {		    shuffledIndex = permutation.getShuffled(i);		    if (shuffledIndex%64 == 0) continue; // skip DC coefficients		    if (coeff[shuffledIndex] == 0) continue; // skip zeroes		    if (coeff[shuffledIndex] > 0) {			if ((coeff[shuffledIndex]&1) != nextBitToEmbed) {			    coeff[shuffledIndex]--; // decrease absolute value			    _changed++;			}		    } else {			if ((coeff[shuffledIndex]&1) == nextBitToEmbed) {			    coeff[shuffledIndex]++; // decrease absolute value			    _changed++;			}		    }		    if (coeff[shuffledIndex] != 0) {			// The coefficient is still nonzero. We			// successfully embedded "nextBitToEmbed".			// We will read a new bit to embed now.			if (availableBitsToEmbed==0)			    break;	// statusword embedded.			nextBitToEmbed = byteToEmbed & 1;			byteToEmbed >>= 1;			availableBitsToEmbed--;			_embedded++;		    } else _thrown++;		}		startOfN = i+1;		// now embed the data using 1 of n codeembeddingLoop:		do {		    kBitsToEmbed = 0;		    // get k bits to embed		    for (i=0; i<k; i++) {			if (availableBitsToEmbed==0) {			    // If the byte of embedded text is			    // empty, we will get a new one.			    try {				if (embeddedData.available()==0) {				    isLastByte = true;				    break;				}				byteToEmbed = embeddedData.read();				byteToEmbed ^= random.getNextByte();			    } catch (Exception e) {				e.printStackTrace();				break;			    }			    availableBitsToEmbed=8;			}			nextBitToEmbed = byteToEmbed & 1;			byteToEmbed >>= 1;			availableBitsToEmbed--;			kBitsToEmbed |= nextBitToEmbed << i;			_embedded++;		    }		    // embed k bits		    do {			j = startOfN;			// fill codeWord[] with the indices of the			// next n non-zero coefficients in coeff[]			for (i=0; i<n; j++) {			    if (j>=coeffCount) {				// in rare cases the estimated capacity is too small				System.out.println("Capacity exhausted.");				break embeddingLoop;			    }			    shuffledIndex = permutation.getShuffled(j);			    if (shuffledIndex%64 == 0) continue; // skip DC coefficients			    if (coeff[shuffledIndex] == 0) continue; // skip zeroes			    codeWord[i++]=shuffledIndex;			}			endOfN = j;			hash = 0;			for (i=0; i<n; i++) {			    if (coeff[codeWord[i]] > 0)				extractedBit = coeff[codeWord[i]]&1;			    else				extractedBit = 1-(coeff[codeWord[i]]&1);			    if (extractedBit == 1)				hash ^= i+1;			}			i = hash ^ kBitsToEmbed;			if (i==0) break; // embedded without change			i--;			if (coeff[codeWord[i]]>0)			    coeff[codeWord[i]]--;			else			    coeff[codeWord[i]]++;			_changed++;			if (coeff[codeWord[i]]==0) _thrown++;		    } while (coeff[codeWord[i]]==0);		    startOfN = endOfN;		} while (!isLastByte);	    } else {	// default code		// The main embedding loop follows. It works on the		// shuffled stream of coefficients.		for(i=0; i<coeffCount; i++) {		    shuffledIndex = permutation.getShuffled(i);		    if (shuffledIndex%64 == 0) continue; // skip DC coefficients

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -