Search code examples
jpeg

How is a JPEG file formated?


I'm trying to write Bytes into a JPEG file, but I don't know the file's format and so the Bytes aren't in the right place of the image after writing into the file.

Does somebody know?


Solution

  • There are several markers that must appear in a JPEG file stream. I believe you can easily find the detailed description of the tags listed below on Internet.

    SOI(0xFFD8) Start of Image APP0(0xFFE0) Application [APPn(0xFFEn)] (alternative) DQT(0xFFDB) Define Quantization Table SOF0(0xFFC0) Start of Frame DHT(0xFFC4) Difine Huffman Table SOS(0xFFDA) Start of Scan DRI(0xFFDD) Define Restart Interval,(alternative) ...Image Stream EOI(0xFFD9) End of Image

    Those markers are followed by lengths in BIG ENDIAN format. You can decode Image Stream that exactly follows DRI using the huffman trees you decoded by DQT. For easier illustration, here are some functions I have written on my own in Java that decodes a header of JPEG, but without doubt there are many better JPEG Java projects on Github that you can refer to.

    public int[][] cutX(byte[] x){
        int s = x.length;int k = 1;int i = 2;int j;
        d2[0][0]=Tool.unsignDecoder(x[1]);d2[1][0]=0;d2[2][0]=1;
        while(d2[0][k-1]!=218){
            d2[1][k]=i;
            d2[0][k]=Tool.unsignDecoder(x[i+1]);
            i=i+2+Tool.unsignDecoder(x[i+2])*256+Tool.unsignDecoder(x[i+3]);
            d2[2][k]=i-1;
            k=k+1; 
        }
        for (j=s-1;j<i;j--){
                if((Tool.unsignDecoder(x[j-1])==255)&&(Tool.unsignDecoder(x[j])==217)) break;
        }
    
        d2[0][k]=217;d2[1][k]=i;d2[2][k]=j+1;
    
        return d2;
    }
    
    public void cutdata(byte[] x,int[][] d){
        int a =Tool.indexOf_1(d[0],218);
        int b =Tool.indexOf_1(d[0],217);
        head = Arrays.copyOfRange(x, 0, d[2][a]+1);
        byte[] im = Arrays.copyOfRange(x, d[1][b], d[2][b]-1);//-2:delete the last EOI message.
        im1 = new byte[im.length];
        int j=0;int i=0;//dynamically record the length of the revised sequence
        while(i<im.length){
            im1[j]=im[i];
            j++;
            if((i!=im.length-1)&&(Tool.unsignDecoder(im[i])==255)&&(Tool.unsignDecoder(im[i+1]))==0){
                i++;//move rightward i
            }
            i++;
        }
        im1=Arrays.copyOfRange(im1, 0, j);//delete zeros in the end of the sequence
    
    }
    
    public void sof(byte[] x,int[][] d){
        int z = Tool.indexOf_1(d[0],192);
        int i = d[1][z];
        int[] temp = new int[19];
        for(int j=0;j<19;j++){
            temp[j]=Tool.unsignDecoder(x[j+i]);
        }
        int ph=i+5;int pw=i+7;
        size[0] =  Tool.unsignDecoder(x[ph])*256+Tool.unsignDecoder(x[ph+1]);
        size[1] =  Tool.unsignDecoder(x[pw])*256+Tool.unsignDecoder(x[pw+1]);
        i += 11;//skip some unused letters
        for(int j=0;j<3;j++){
            int k = Tool.unsignDecoder(x[i]);
            Q[j][0] = (k & 0xF0)/16;
            Q[j][1] = k & 0x0F;
            i += 3;
        }
    }
    
    public void hfm(byte[] x,int[][] d){
        //the DHT marker may appear several times in a JPEG, or several huffman trees can be found in a single DHT.
      ArrayList res =Tool.indexOf(d[0],196);int thisLength;int pointer;int pointerOrigin;
      int a;int huffLength = 0;
      for(int z=0;z<res.size();z++){
        a=(int) res.get(z);
        pointer = d[1][a];pointerOrigin = d[1][a]+2;//please follow the straight-forward moving of this pointer
        thisLength = Tool.unsignDecoder(x[pointer+2])*256+Tool.unsignDecoder(x[pointer+3]);
        int[] temp = new int[thisLength+4];
        for(int i=0;i<thisLength;i++){
            temp[i]=Tool.unsignDecoder(x[pointer+i]);
        }
        pointer += 4;
        while(huffLength<thisLength){
        int mode = Tool.unsignDecoder(x[pointer]);pointer += 1;
        int[] huff_num = new int[16];int total=0;
        for(int i=0;i<16;i++){//码字总个数
            huff_num[i] = x[pointer+i];total+=huff_num[i];
        }
        pointer +=16;int codePointer=0;int code=0;
        int[][] huffmanTree = new int[3][total];
        for(int i=0;i<16;i++){
            if(i!=0){
                code *= 2;
            }
            for(int j=0;j<huff_num[i];j++){
                huffmanTree[0][codePointer]=i+1;
                huffmanTree[1][codePointer]=code;
                huffmanTree[2][codePointer]=Tool.unsignDecoder(x[pointer+codePointer]);
                code++;codePointer++;
            }
        }
        huffLength += pointer + codePointer - pointerOrigin;pointer += codePointer;
        pointerOrigin = pointer;
        switch(mode){
            case(0):d0 = huffmanTree;break;
            case(1):d1 = huffmanTree;break;
            case(16):a0 = huffmanTree;break;
            case(17):a1 = huffmanTree;break;
        }
        }
      }
    }
    
    public void dri(byte[] x,int[][] d){
        int z = Tool.indexOf_1(d[0],221);
        if(z!=-1){
        int pointer = d[1][z];
        int len = Tool.unsignDecoder(x[pointer+2])*256+Tool.unsignDecoder(x[pointer+3]);
        int[] temp = new int[len+2];
        for(int i=0;i<len;i++){
            temp[i]=Tool.unsignDecoder(x[pointer+i]);
        }
        DRI = Tool.unsignDecoder(x[d[1][z]+4])*256+Tool.unsignDecoder(x[d[1][z]+5]);}
    }
    
    public void sos(byte[] x,int[][] d){
        int z = Tool.indexOf_1(d[0],218);int a = d[1][z];
        int len = Tool.unsignDecoder(x[a+2])*256+Tool.unsignDecoder(x[a+3]);
        int[] temp = new int[len+2];
        for(int j=0;j<len+2;j++){
            temp[j]=Tool.unsignDecoder(x[j+a]);
        }
    
            int pointer = d[1][z]+6;
            for(int j=0;j<3;j++){
                treeSelect[j] = Tool.unsignDecoder(x[pointer]);
                pointer += 2;
            }
    
    }