rt

解决方案 »

  1.   

    http://expert.csdn.net/Expert/topic/2114/2114017.xml?temp=.5375788
      

  2.   

    我查找了很多jpeg的资料,了解了关于静止图象压缩标准,总结了有损压缩编码的文章,自己完成了一个jpeg编码类,虽然效率不高,最终还还是解决了我的问题,算是点经验吧,共享给大家。编码码的主要过程及环节:源图象数据-》块准备-》8*8DCT正变换-》量化器-》编码器-》压缩后的图象数据-》加上文件头尾-》jpeg文件下面把主要的函数贴上来,供大家参考:
    主编码函数:
    void CJpeg::Compress(BYTE *pInBuf, BYTE *pOutBuf, UINT nWidth, UINT nHeight, DWORD& dwOutSize)
    {
    ASSERT(pInBuf != NULL);
    ASSERT(pOutBuf != NULL);
    ASSERT(nWidth > 0);
    ASSERT(nHeight > 0);

    DWORD dwSize = nWidth * nHeight;
    dwOutSize = 0;
    UINT nOut = 0;
    int m;
    BYTE *pOut = pOutBuf; //开始分块
    BYTE *pY0;
    BYTE *pY1;
    BYTE *pY2;
    BYTE *pY3;
    BYTE *pU;
    BYTE *pV; //开辟一个临时缓冲
    BYTE *pTmp = new BYTE[1152];
    BYTE *pTY0 = pTmp;
    BYTE *pTY1 = pTmp + 64;
    BYTE *pTY2 = pTmp + 128;
    BYTE *pTY3 = pTmp + 192;
    BYTE *pTU = pTmp + 256;
    BYTE *pTV = pTmp + 320; UINT x,y;
    UINT cx,cy;
    //得出总共够多少个MCU
    cx = nWidth / 16;
    cy = nHeight / 16; //对Y数据分块,取出其中的16*16
    for(y = 0;y < cy; y++)
    {
    for(x = 0;x < cx;x++)
    {
    //准备MCU
    pY0 = pInBuf + (16 * x + nWidth * y * 16);
    pY1 = pY0 + 8;
    pY2 = pY0 + 8 * nWidth;
    pY3 = pY0 + 8 * nWidth + 8;
    pU = pInBuf + dwSize + (8 * x + 4 * nWidth * y);
    pV = pInBuf + dwSize + dwSize/2 + (8 * x + 4 * nWidth * y); for(m = 0;m < 8;m++)
    {
    memcpy(pTY0 + (8*m),pY0 + m*nWidth,8);
    memcpy(pTY1 + (8*m),pY1 + m*nWidth,8);
    memcpy(pTY2 + (8*m),pY2 + m*nWidth,8);
    memcpy(pTY3 + (8*m),pY3 + m*nWidth,8);
    memcpy(pTU + (8*m),pU + m*nWidth,8);
    memcpy(pTV + (8*m),pV + m*nWidth,8);
    }
    /*
    //把提取出来的一个MCU打印出来
    TRACE("以下是一个MCU:\n");
    for(int d = 0;d < 384;d++)
    {
    TRACE("%2X ",pTmp[d]);
    if((d+1)%8 == 0)
    {
    TRACE("\n");
    }
    if((d+1)%64 == 0)
    {
    TRACE("\n");
    }
    }
    */
    //压缩MCU
    CompressMCU(pTmp,nOut);
    memcpy(pOut,pTmp,nOut);
    pOut += nOut;
    }
    } delete [] pTmp; //如果全局的缓存中还有值的话,则把它们补足8位也写入。
    if(m_nBufBit > 0)
    {
    WriteBits(0x7F,7,pOut,nOut);
    pOut += nOut;
    m_nBufBit = 0;
    m_BitBuf = 0;
    }
    dwOutSize = pOut - pOutBuf;
    //TRACE("最终输出大小为:%u\n",dwOutSize);
    //
    m_dcY = m_dcU = m_dcV = 0;
    }
    这篇文章对我起了很大作用;
    http://www.csdn.net/develop/article/22/22948.shtm
      

  3.   

    CIF格式是YUV422格式的所以需要一个函数把YUV422转成RGB:
    //将YUV422数据转换成RGB数据,bVertFlip决定是得到顺序RGB还是得到倒序RGB,默认倒序
    void CJpeg::YUVToRGB(BYTE *pInBuf, BYTE *pOutBuf, UINT nWidth, UINT nHeight,bool bVertFlip)
    {
    ASSERT(pInBuf != NULL);
    ASSERT(pOutBuf != NULL);
    ASSERT(nWidth > 0);
    ASSERT(nHeight > 0); BYTE Y,U,V;

    DWORD dwSize = nWidth * nHeight * 3;
    BYTE *pY = pInBuf;
    BYTE *pU = pInBuf + nWidth * nHeight;
    BYTE *pV = pInBuf + nWidth * nHeight + nWidth * nHeight/2;

    for(UINT y = 0;y < nHeight;y++)
    {
    //因为RGB图象的读取是从最后一行开始的,所以存储要从最后一行开始
    for(UINT x = 0;x < nWidth;x++)
    {
    UINT nPos = y * nWidth + x;
    Y = pY[nPos];
    U = pU[(DWORD)(nPos/2)];
    V = pV[(DWORD)(nPos/2)]; if(bVertFlip)
    {
    //倒序
    nPos = nWidth * 3 * (nHeight - y - 1) + x * 3;
    }
    else
    {
    //正序
    nPos = nWidth * 3 * y + x * 3;
    }
    pOutBuf[nPos+2] = (BYTE)(Y + 1.402 * (V - 128));
    pOutBuf[nPos+1] = (BYTE)(Y - 0.34414 * (U - 128) - 0.71414 * (V - 128));
    pOutBuf[nPos] = (BYTE)(Y - 1.772 * (U - 128));
    }
    }
    }
      

  4.   

    //对一个MCU进行编码
    //输入为384的MCU
    void CJpeg::CompressMCU(BYTE *pBuf, UINT& nOutSize)
    {
    ASSERT(pBuf != NULL);

    BYTE *pIn = pBuf;
    UINT nOut = 0;
    nOutSize = 0; char *pInChar = new char[64];
    short *pInt = new short[64];
    BYTE *pOut = new BYTE[1152]; for(UINT i = 0;i < 6;i++)
    {
    //把输入到FDCT变换的数据缩减到-128~127
    ByteToChar(pIn,pInChar); //FDCT变换
    //一维变换
    Fdct_1_1(pInChar,pInt); //Fdct64(pInChar,pInt); //Fdct1(pInChar,pInt); //二维变换
    //Fdct2(pInChar,pInt);

    //量化
    Quantize(pInt,i); //Huffman编码
    Huffman(pInt,pOut + nOutSize,i,nOut);
    nOutSize += nOut; pIn += 64;
    } delete [] pInChar;
    delete [] pInt;
    memcpy(pBuf,pOut,nOutSize);
    delete [] pOut;/*
    TRACE("MCU编码结果:\n");
    for(UINT d = 0;d < nOutSize;d++)
    {
    TRACE("%4u ",pBuf[d]);
    if((((d+1)%8 == 0) && (d !=0)) || (d+1 == nOutSize))
    {
    TRACE("\n");
    }
    }
    */
    }
    void CJpeg::Fdct_1_1(char *pInBuf, short *pOutBuf)
    {
    char *pIn = pInBuf;
    short *pOut = pOutBuf; short tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;
    short tmp10, tmp11, tmp12, tmp13;
    short z1, z2, z3, z4, z5, z11, z13;
    int i;

    for(i = 0; i < 8; i++)
    {
    tmp0 = pIn[0] + pIn[7];
    tmp7 = pIn[0] - pIn[7];
    tmp1 = pIn[1] + pIn[6];
    tmp6 = pIn[1] - pIn[6];
    tmp2 = pIn[2] + pIn[5];
    tmp5 = pIn[2] - pIn[5];
    tmp3 = pIn[3] + pIn[4];
    tmp4 = pIn[3] - pIn[4];

    tmp10 = tmp0 + tmp3;
    tmp13 = tmp0 - tmp3;
    tmp11 = tmp1 + tmp2;
    tmp12 = tmp1 - tmp2;

    pOut[0] = tmp10 + tmp11;
    pOut[4] = tmp10 - tmp11;

    z1 = (short)((tmp12 + tmp13) * 0.707106781);
    pOut[2] = tmp13 + z1;
    pOut[6] = tmp13 - z1;

    tmp10 = tmp4 + tmp5;
    tmp11 = tmp5 + tmp6;
    tmp12 = tmp6 + tmp7;

    z5 = (short)((tmp10 - tmp12) * 0.382683433);
    z2 = (short)(0.541196100 * tmp10 + z5);
    z4 = (short)(1.306562965 * tmp12 + z5);
    z3 = (short)(tmp11 * 0.707106781);

    z11 = tmp7 + z3;
    z13 = tmp7 - z3;

    pOut[5] = z13 + z2;
    pOut[3] = z13 - z2;
    pOut[1] = z11 + z4;
    pOut[7] = z11 - z4; pIn += 8;
    pOut += 8;
    } pOut = pOutBuf;
    for (i = 0; i < 8; i++)
    {
    tmp0 = pOut[0] + pOut[56];
    tmp7 = pOut[0] - pOut[56];
    tmp1 = pOut[8] + pOut[48];
    tmp6 = pOut[8] - pOut[48];
    tmp2 = pOut[16] + pOut[40];
    tmp5 = pOut[16] - pOut[40];
    tmp3 = pOut[24] + pOut[32];
    tmp4 = pOut[24] - pOut[32];

    tmp10 = tmp0 + tmp3;
    tmp13 = tmp0 - tmp3;
    tmp11 = tmp1 + tmp2;
    tmp12 = tmp1 - tmp2;

    pOut[0] = tmp10 + tmp11;
    pOut[32] = tmp10 - tmp11;

    z1 = (short)((tmp12 + tmp13) * 0.707106781);
    pOut[16] = tmp13 + z1;
    pOut[48] = tmp13 - z1;

    tmp10 = tmp4 + tmp5;
    tmp11 = tmp5 + tmp6;
    tmp12 = tmp6 + tmp7;

    z5 = (short)((tmp10 - tmp12) * 0.382683433);
    z2 = (short)(0.541196100 * tmp10 + z5);
    z4 = (short)(1.306562965 * tmp12 + z5);
    z3 = (short)(tmp11 * 0.707106781);

    z11 = tmp7 + z3;
    z13 = tmp7 - z3;

    pOut[40] = z13 + z2;
    pOut[24] = z13 - z2;
    pOut[8] = z11 + z4;
    pOut[56] = z11 - z4; pOut++;
    }
    /*
    TRACE("以下是经过一维FDCT变换后的数据:\n");
    for(int d = 0;d<64;d++)
    {
    TRACE("%5d ",pOutBuf[d]);
    if((d+1)%8 ==0)
    {
    TRACE("\n");
    }
    }
    */
    }//量化函数
    void CJpeg::Quantize(short *pBuf, UINT nType)
    {
    BYTE *pQuanTbl;
    double f; pQuanTbl = (nType < 4)?m_QuanYEnc:m_QuanUVEnc; for(UINT i = 0;i < 64;i++)
    {
    //取整
    f = pBuf[i]/pQuanTbl[i];
    if(f >= 0)
    {
    f += 0.5;
    }
    else
    {
    f -= 0.5;
    }
    pBuf[i] = (short)f;
    }
    /*
    TRACE("%u量化后的结果:\n",nType);
    TRACE("输入地址为:%u\n",pBuf);
    for(int d = 0;d < 64;d++)
    {
    TRACE("%3d,",pBuf[d]);
    if((d+1)%8==0)
    {
    TRACE("\n");
    }
    }
    */
    }//对Y8*8矩阵进行Huffman编码
    //其中首先包含了对DC进行的DPCM编码和对AC的RLN编码
    //接着进行Huffman编码
    void CJpeg::Huffman(short *pInBuf, BYTE *pOutBuf, UINT nType, UINT &nOutBytes)
    {
    ASSERT(pInBuf != NULL);
    ASSERT(pOutBuf != NULL);
    ASSERT(nType >=0 && nType < 6); //输出指针
    BYTE *pOut = pOutBuf;
    //数据、差值的位数
    USHORT nBits = 0;
    //差值或者数据
    int iDiff0,iDiff1;
    //最终输出数据字节数
    nOutBytes = 0;
    //临时输出数据长度,每个WriteBits写入的字节数
    UINT nOut = 0; //指定使用的Huffman表
    BYTE *bitDC;
    USHORT *valDC;
    BYTE *bitAC;
    USHORT *valAC;
    //上次保留下来的DC值的指针
    short *pLastDC; //根据不同的类型给出不同的Huffman编码表
    //pLastDC代表上一个8*8矩阵中DC的值,并保留下在本矩阵中DC值
    if(nType < 4)
    {
    bitDC = m_bitYDC;
    valDC = m_valYDC;
    bitAC = m_bitYAC;
    valAC = m_valYAC;
    pLastDC = &m_dcY;
    }
    else
    {
    bitDC = m_bitUVDC;
    valDC = m_valUVDC;
    bitAC = m_bitUVAC;
    valAC = m_valUVAC;
    pLastDC = (nType == 4)?&m_dcU:&m_dcV;
    } //////////////////////////////////////////////////////////////////////////
    // 对DC采用APCM编码,差分编码
    //开始DC Huffman编码
    iDiff0 = iDiff1 = pInBuf[0] - *pLastDC;
    *pLastDC = pInBuf[0]; //如果是负数,则求绝对值和反码
    if(iDiff0 < 0)
    {
    //求绝对值
    iDiff0 = -iDiff0;
    //取绝对值的反码
    iDiff1 = ~iDiff0;
    }
    //求得码长
    while(iDiff0)
    {
    nBits++;
    iDiff0 >>= 1;
    } //写入DC Huffman 识别码(标志码)
    /*
    TRACE("DC标志码 : Value : 0x%X  Bits : %u \n",valDC[nBits],bitDC[nBits]);
    TRACE("DC : Value : 0x%X  Bits : %u \n",iDiff1,nBits);
    */
    WriteBits(valDC[nBits],bitDC[nBits],pOut,nOut);
    pOut += nOut;
    //写入DC差值二进制码
    WriteBits(iDiff1,nBits,pOut,nOut);
    pOut += nOut; //DC Hufman编码结束 //////////////////////////////////////////////////////////////////////////
    // 对AC采用RLE编码,游程编码
    //开始AC Huffman编码
    BYTE nZeroAc = 0;
    BYTE n = 0;
    for(UINT i = 1;i < 64;i++)
    {
    iDiff0 = iDiff1 = pInBuf[m_ZagZig[i]];
    if(iDiff0 == 0)
    {
    //统计连续零的个数
    nZeroAc++;
    }
    else
    {
    while(nZeroAc > 15)
    {
    //如果连续的零超过15个则写入一个F0标志,代表此处有16个零
    WriteBits(valAC[0xF0],bitAC[0xF0],pOut,nOut);
    //WriteBits(0x7F9,11,pOut,nOut);
    pOut += nOut; nZeroAc -= 16;
    }

    //求绝对值和反码
    if(iDiff0 < 0)
    {
    iDiff0 = -iDiff0;
    //取反码
    iDiff1 = ~iDiff0;
    }
    //求得码长,码长至少为1,不可能为零
    nBits = 1;
    while(iDiff0 >>= 1)
    {
    nBits++;
    }
    /*
    TRACE("0的个数 : 0x%X \n",nZeroAc);
    TRACE("AC标志码 : Value : 0x%X  Bits : %u \n",valAC[nBits],bitAC[nBits]);
    TRACE("AC : Value : 0x%X  Bits : %u \n",iDiff1,nBits);
    */
    //编码格式为:(零的个数+AC值编码位数)(正好一个字节,Huffman编码)+AC值(Huffman编码)
    //1. 把0的个数和AC值编码位数合并成一个字节
    n = (nZeroAc << 4) + nBits;
    WriteBits(valAC[n],bitAC[n],pOut,nOut);
    pOut += nOut; //2. 写入AC数据
    WriteBits(iDiff1,nBits,pOut,nOut);
    pOut += nOut; nZeroAc = 0;
    }
    }
    if(nZeroAc > 0)
    {
    //说明后面全是零
    WriteBits(valAC[0],bitAC[0],pOut,nOut);
    //WriteBits(10,4,pOut,nOut);
    pOut += nOut;
    }
    //AC 编码结束
    nOutBytes = pOut - pOutBuf;
    /*
    TRACE("Huffman编码后,%u块输出大小为:%u\n",nType,nOutBytes);
    for(UINT d = 0;d < nOutBytes;d++)
    {
    TRACE("%3d ",pOutBuf[d]);
    if((d+1)%8==0 || d+1 == nOutBytes)
    {
    TRACE("\n");
    }
    }
    */
    }
      

  5.   

    //对一个MCU进行编码
    //输入为384的MCU
    void CJpeg::CompressMCU(BYTE *pBuf, UINT& nOutSize)
    {
    ASSERT(pBuf != NULL);

    BYTE *pIn = pBuf;
    UINT nOut = 0;
    nOutSize = 0; char *pInChar = new char[64];
    short *pInt = new short[64];
    BYTE *pOut = new BYTE[1152]; for(UINT i = 0;i < 6;i++)
    {
    //把输入到FDCT变换的数据缩减到-128~127
    ByteToChar(pIn,pInChar); //FDCT变换
    //一维变换
    Fdct_1_1(pInChar,pInt); //Fdct64(pInChar,pInt); //Fdct1(pInChar,pInt); //二维变换
    //Fdct2(pInChar,pInt);

    //量化
    Quantize(pInt,i); //Huffman编码
    Huffman(pInt,pOut + nOutSize,i,nOut);
    nOutSize += nOut; pIn += 64;
    } delete [] pInChar;
    delete [] pInt;
    memcpy(pBuf,pOut,nOutSize);
    delete [] pOut;/*
    TRACE("MCU编码结果:\n");
    for(UINT d = 0;d < nOutSize;d++)
    {
    TRACE("%4u ",pBuf[d]);
    if((((d+1)%8 == 0) && (d !=0)) || (d+1 == nOutSize))
    {
    TRACE("\n");
    }
    }
    */
    }
    void CJpeg::Fdct_1_1(char *pInBuf, short *pOutBuf)
    {
    char *pIn = pInBuf;
    short *pOut = pOutBuf; short tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;
    short tmp10, tmp11, tmp12, tmp13;
    short z1, z2, z3, z4, z5, z11, z13;
    int i;

    for(i = 0; i < 8; i++)
    {
    tmp0 = pIn[0] + pIn[7];
    tmp7 = pIn[0] - pIn[7];
    tmp1 = pIn[1] + pIn[6];
    tmp6 = pIn[1] - pIn[6];
    tmp2 = pIn[2] + pIn[5];
    tmp5 = pIn[2] - pIn[5];
    tmp3 = pIn[3] + pIn[4];
    tmp4 = pIn[3] - pIn[4];

    tmp10 = tmp0 + tmp3;
    tmp13 = tmp0 - tmp3;
    tmp11 = tmp1 + tmp2;
    tmp12 = tmp1 - tmp2;

    pOut[0] = tmp10 + tmp11;
    pOut[4] = tmp10 - tmp11;

    z1 = (short)((tmp12 + tmp13) * 0.707106781);
    pOut[2] = tmp13 + z1;
    pOut[6] = tmp13 - z1;

    tmp10 = tmp4 + tmp5;
    tmp11 = tmp5 + tmp6;
    tmp12 = tmp6 + tmp7;

    z5 = (short)((tmp10 - tmp12) * 0.382683433);
    z2 = (short)(0.541196100 * tmp10 + z5);
    z4 = (short)(1.306562965 * tmp12 + z5);
    z3 = (short)(tmp11 * 0.707106781);

    z11 = tmp7 + z3;
    z13 = tmp7 - z3;

    pOut[5] = z13 + z2;
    pOut[3] = z13 - z2;
    pOut[1] = z11 + z4;
    pOut[7] = z11 - z4; pIn += 8;
    pOut += 8;
    } pOut = pOutBuf;
    for (i = 0; i < 8; i++)
    {
    tmp0 = pOut[0] + pOut[56];
    tmp7 = pOut[0] - pOut[56];
    tmp1 = pOut[8] + pOut[48];
    tmp6 = pOut[8] - pOut[48];
    tmp2 = pOut[16] + pOut[40];
    tmp5 = pOut[16] - pOut[40];
    tmp3 = pOut[24] + pOut[32];
    tmp4 = pOut[24] - pOut[32];

    tmp10 = tmp0 + tmp3;
    tmp13 = tmp0 - tmp3;
    tmp11 = tmp1 + tmp2;
    tmp12 = tmp1 - tmp2;

    pOut[0] = tmp10 + tmp11;
    pOut[32] = tmp10 - tmp11;

    z1 = (short)((tmp12 + tmp13) * 0.707106781);
    pOut[16] = tmp13 + z1;
    pOut[48] = tmp13 - z1;

    tmp10 = tmp4 + tmp5;
    tmp11 = tmp5 + tmp6;
    tmp12 = tmp6 + tmp7;

    z5 = (short)((tmp10 - tmp12) * 0.382683433);
    z2 = (short)(0.541196100 * tmp10 + z5);
    z4 = (short)(1.306562965 * tmp12 + z5);
    z3 = (short)(tmp11 * 0.707106781);

    z11 = tmp7 + z3;
    z13 = tmp7 - z3;

    pOut[40] = z13 + z2;
    pOut[24] = z13 - z2;
    pOut[8] = z11 + z4;
    pOut[56] = z11 - z4; pOut++;
    }
    /*
    TRACE("以下是经过一维FDCT变换后的数据:\n");
    for(int d = 0;d<64;d++)
    {
    TRACE("%5d ",pOutBuf[d]);
    if((d+1)%8 ==0)
    {
    TRACE("\n");
    }
    }
    */
    }//量化函数
    void CJpeg::Quantize(short *pBuf, UINT nType)
    {
    BYTE *pQuanTbl;
    double f; pQuanTbl = (nType < 4)?m_QuanYEnc:m_QuanUVEnc; for(UINT i = 0;i < 64;i++)
    {
    //取整
    f = pBuf[i]/pQuanTbl[i];
    if(f >= 0)
    {
    f += 0.5;
    }
    else
    {
    f -= 0.5;
    }
    pBuf[i] = (short)f;
    }
    /*
    TRACE("%u量化后的结果:\n",nType);
    TRACE("输入地址为:%u\n",pBuf);
    for(int d = 0;d < 64;d++)
    {
    TRACE("%3d,",pBuf[d]);
    if((d+1)%8==0)
    {
    TRACE("\n");
    }
    }
    */
    }//对Y8*8矩阵进行Huffman编码
    //其中首先包含了对DC进行的DPCM编码和对AC的RLN编码
    //接着进行Huffman编码
    void CJpeg::Huffman(short *pInBuf, BYTE *pOutBuf, UINT nType, UINT &nOutBytes)
    {
    ASSERT(pInBuf != NULL);
    ASSERT(pOutBuf != NULL);
    ASSERT(nType >=0 && nType < 6); //输出指针
    BYTE *pOut = pOutBuf;
    //数据、差值的位数
    USHORT nBits = 0;
    //差值或者数据
    int iDiff0,iDiff1;
    //最终输出数据字节数
    nOutBytes = 0;
    //临时输出数据长度,每个WriteBits写入的字节数
    UINT nOut = 0; //指定使用的Huffman表
    BYTE *bitDC;
    USHORT *valDC;
    BYTE *bitAC;
    USHORT *valAC;
    //上次保留下来的DC值的指针
    short *pLastDC; //根据不同的类型给出不同的Huffman编码表
    //pLastDC代表上一个8*8矩阵中DC的值,并保留下在本矩阵中DC值
    if(nType < 4)
    {
    bitDC = m_bitYDC;
    valDC = m_valYDC;
    bitAC = m_bitYAC;
    valAC = m_valYAC;
    pLastDC = &m_dcY;
    }
    else
    {
    bitDC = m_bitUVDC;
    valDC = m_valUVDC;
    bitAC = m_bitUVAC;
    valAC = m_valUVAC;
    pLastDC = (nType == 4)?&m_dcU:&m_dcV;
    } //////////////////////////////////////////////////////////////////////////
    // 对DC采用APCM编码,差分编码
    //开始DC Huffman编码
    iDiff0 = iDiff1 = pInBuf[0] - *pLastDC;
    *pLastDC = pInBuf[0]; //如果是负数,则求绝对值和反码
    if(iDiff0 < 0)
    {
    //求绝对值
    iDiff0 = -iDiff0;
    //取绝对值的反码
    iDiff1 = ~iDiff0;
    }
    //求得码长
    while(iDiff0)
    {
    nBits++;
    iDiff0 >>= 1;
    } //写入DC Huffman 识别码(标志码)
    /*
    TRACE("DC标志码 : Value : 0x%X  Bits : %u \n",valDC[nBits],bitDC[nBits]);
    TRACE("DC : Value : 0x%X  Bits : %u \n",iDiff1,nBits);
    */
    WriteBits(valDC[nBits],bitDC[nBits],pOut,nOut);
    pOut += nOut;
    //写入DC差值二进制码
    WriteBits(iDiff1,nBits,pOut,nOut);
    pOut += nOut; //DC Hufman编码结束 //////////////////////////////////////////////////////////////////////////
    // 对AC采用RLE编码,游程编码
    //开始AC Huffman编码
    BYTE nZeroAc = 0;
    BYTE n = 0;
    for(UINT i = 1;i < 64;i++)
    {
    iDiff0 = iDiff1 = pInBuf[m_ZagZig[i]];
    if(iDiff0 == 0)
    {
    //统计连续零的个数
    nZeroAc++;
    }
    else
    {
    while(nZeroAc > 15)
    {
    //如果连续的零超过15个则写入一个F0标志,代表此处有16个零
    WriteBits(valAC[0xF0],bitAC[0xF0],pOut,nOut);
    //WriteBits(0x7F9,11,pOut,nOut);
    pOut += nOut; nZeroAc -= 16;
    }

    //求绝对值和反码
    if(iDiff0 < 0)
    {
    iDiff0 = -iDiff0;
    //取反码
    iDiff1 = ~iDiff0;
    }
    //求得码长,码长至少为1,不可能为零
    nBits = 1;
    while(iDiff0 >>= 1)
    {
    nBits++;
    }
    /*
    TRACE("0的个数 : 0x%X \n",nZeroAc);
    TRACE("AC标志码 : Value : 0x%X  Bits : %u \n",valAC[nBits],bitAC[nBits]);
    TRACE("AC : Value : 0x%X  Bits : %u \n",iDiff1,nBits);
    */
    //编码格式为:(零的个数+AC值编码位数)(正好一个字节,Huffman编码)+AC值(Huffman编码)
    //1. 把0的个数和AC值编码位数合并成一个字节
    n = (nZeroAc << 4) + nBits;
    WriteBits(valAC[n],bitAC[n],pOut,nOut);
    pOut += nOut; //2. 写入AC数据
    WriteBits(iDiff1,nBits,pOut,nOut);
    pOut += nOut; nZeroAc = 0;
    }
    }
    if(nZeroAc > 0)
    {
    //说明后面全是零
    WriteBits(valAC[0],bitAC[0],pOut,nOut);
    //WriteBits(10,4,pOut,nOut);
    pOut += nOut;
    }
    //AC 编码结束
    nOutBytes = pOut - pOutBuf;
    /*
    TRACE("Huffman编码后,%u块输出大小为:%u\n",nType,nOutBytes);
    for(UINT d = 0;d < nOutBytes;d++)
    {
    TRACE("%3d ",pOutBuf[d]);
    if((d+1)%8==0 || d+1 == nOutBytes)
    {
    TRACE("\n");
    }
    }
    */
    }