JPEG compression

Help
2008-04-03
2013-04-23
  • Hello,

    I'm using the framewave library to compress images using the JPEG part.
    So I follow the JPEG compression steps :
    * colorspace conversion
    * downsampling
    * DCT
    * quantization
    * Huffman encoding

    This is this last point that causes problem.
    I think that I don't use correctly fwiEncodeHuffman8x8_JPEG_16s1u_C1 :

    //...
    //DCT contains the quantized DCT coefficient
    //lNbBlock = (number_of_8x8_blocks_in_the_image - 1)
    //EncodeHuffman structures have been correctly initialized

    for(int lBlockIndex = 0; lBlockIndex < lNbBlocks; lBlockIndex++)
    {
      fwiEncodeHuffman8x8_JPEG_16s1u_C1 ( lDCT + lBlockIndex * 64,
                             *pEncodedChannel , lSize, pLength,
                          &lLastDC,
                          &lDCEncHuffSpec,
                          &lACEncHuffSpec,
                               &lEncHuffState, 0);

    }
    //like it's written in the doc :
    //"To place all the accumulated bits in the buffer,
    //set the bFlashState bit to 1 before processing the last 8X8 block in the
    //stream, or restart the encoded interval."
    fwiEncodeHuffman8x8_JPEG_16s1u_C1 ( NULL,
                           *pEncodedChannel , lSize, pLength,
                        &lLastDC,
                        &lDCEncHuffSpec,
                            &lACEncHuffSpec,
                        &lEncHuffState, 1);

    fwiEncodeHuffman8x8_JPEG_16s1u_C1 ( lDCT + lNbBlocks * 64,                                                                     *pEncodedChannel , lSize, pLength,
                        &lLastDC,
                        &lDCEncHuffSpec,
                        &lACEncHuffSpec,
                        &lEncHuffState, 0);
    //All the values returned by the encodeHuffman method indicate no error.

    So when I decompress, the fwiDecodeHuffman8x8_JPEG_1u16s_C1 fails.
    The current positon in the encoded buffer reaches the end before I finish to decode all the 8x8 blocks.
    So finally, all the image is reconstructed except 2 or 5 8x8 blocks (it depends of the original image)

    Thanks for your help,

    Laurent

     
    • Hello, I'm back.

      Concerning my problem, I think (but not sure) I've found the solution.

      First, during the encoding step, I flush the accumulated bits after having processed the last 8x8 block (whereas the documentation indicated before the last 8x8 block).

      Finally, at the decoding step, when the current positon in the encoded buffer reaches the end before I finish to decode all the 8x8 blocks, I copy the last decoded 8x8 block into all the remaining blocks.

      I test on a dozen of images and it seems to work :-)

      Can someone confirm that what I've done is correct?

       
    • Ravi Korsa
      Ravi Korsa
      2008-04-08

      Hi verneaut,

                 I feel you probably have misunderstood the documentation. The flushing should be done when calling the huffman function with the last 8*8 block. I have analysed the above code and here are some corrections that need to be made. There's nothing wrong with your first for loop. You process all the 8*8 blocks except the last one.

                 For the last block you need to flush the huffman state. So there's only one more call to be made with the flush set to 1. But you are making two calls. In the first call

      fwiEncodeHuffman8x8_JPEG_16s1u_C1 ( NULL, 
      *pEncodedChannel , lSize, pLength,
      &lLastDC,
      &lDCEncHuffSpec,
      &lACEncHuffSpec,
      &lEncHuffState, 1);

      you are asking it to flush without giving any input buffer. So the encoder marks this as the last 8*8 block and even the 8*8 block will not be correct. After this you are making another call for the last 8*8 block. This block may not be decoded at all since the encoder has ended it with the earlier block. That's the reason why you were not able to decode the last 2 8*8 blocks properly.

      To encode it correctly make only one call to huffman after the for loop. And the buffer should be correctly pointed to and the flush bit should be set to 1. So your code should look as follows.

      for(int lBlockIndex = 0; lBlockIndex < lNbBlocks; lBlockIndex++)
      {
      fwiEncodeHuffman8x8_JPEG_16s1u_C1 ( lDCT + lBlockIndex * 64, 
      *pEncodedChannel , lSize, pLength,
      &lLastDC,
      &lDCEncHuffSpec,
      &lACEncHuffSpec,
      &lEncHuffState, 0);

      }

      fwiEncodeHuffman8x8_JPEG_16s1u_C1 ( lDCT + lNbBlocks * 64, *pEncodedChannel , lSize, pLength,
      &lLastDC,
      &lDCEncHuffSpec,
      &lACEncHuffSpec,
      &lEncHuffState, 1);

      This solution should work perfectly.

      With the solution you have mentioned above, you will be able to decode the image but you will get 2 invalid 8*8 blocks at the end.

      Hope this helps...

      Thanks,
      Korsa.

       
    • Hi Korsa,

      Thanks for your reply.

      Unfortunately, I've tried your solution and I always have the same problem.
      Depnding on the image, the number of undecoded 8x8 blocks can vary (2,3,...).
      Also, the number of undecoded blocks is not the same in each channel of an image.
      For example, on the Luminance all blocks can been decoded correctly,
      whereas on the Chroma red there are 2 undecoded blocks and on the Chroma green there are 3.

      Sorry,

      Laurent

       
    • Ravi Korsa
      Ravi Korsa
      2008-04-09

      Hi verneaut,

                  Would it be possible for you to give the source code(both the encoder and decoder). I will see if something is wrong there and make corrections if required.

      Thanks,
      Korsa.

       
    • Hi Korsa,
      Sorry for my late.

      Here is my source code for encoding and decoding (it will be a bit long :-) )

      /////////////
      // ENCODE  //
      /////////////

      /******************************************************************************
      * Method to encode the luminance channel
      * @param pWidth width of the luminance channel
      * @param pHeight height of the luminance channel
      * @param pLuminanceChannel the luminance channe
      * @param pEncodedChannel the encoded luminance channel (its allocation is done into this method)
      * @param pLength size in byte of the encoded luminance
      ******************************************************************************/
      void encodeLuminance(int pWidth, int pHeight, Fw16s *pLuminanceChannel, Fw8u **pEncodedChannel, int *pLength)
      {
        // step 1 : Discrete cosinus transform && Quantization
        //init quantization table
        Fw16u lQuantFwdTable[64];
        fwiQuantFwdTableInit_JPEG_8u16u (gDefaultLuminance, lQuantFwdTable);
        //DCT
        Fw16s *lDCT = (Fw16s*)fwMalloc(64*sizeof(Fw16s));

       
       

        // step 2  : huffman encoding
        //init encoding structure
        FwiEncodeHuffmanSpec lACEncHuffSpec, lDCEncHuffSpec;
        fwiEncodeHuffmanSpecInit_JPEG_8u(gDefaultLuminanceACBits, gDefaultLuminanceACValues, &lACEncHuffSpec );
        fwiEncodeHuffmanSpecInit_JPEG_8u(gDefaultLuminanceDCBits, gDefaultLuminanceDCValues, &lDCEncHuffSpec );
        FwiEncodeHuffmanState lEncHuffState;
        fwiEncodeHuffmanStateInit_JPEG_8u(&lEncHuffState);
         
        *pEncodedChannel = (Fw8u*)fwMalloc(pWidth * pHeight * sizeof(Fw8u));

        Fw16s lLastDC = 0;
        int lNbBlocks = pWidth * pHeight / 64 - 1 ; // nb 8x8 blocks
        int lSize = pWidth * pHeight * sizeof(Fw8u);
        *pLength = 0;

       
        for(int lBlockIndex = 0; lBlockIndex < lNbBlocks; lBlockIndex++)
        {
          //step 1
          fwiDCTQuantFwd8x8_JPEG_16s_C1 ( pLuminanceChannel + lBlockIndex * 64, lDCT, lQuantFwdTable );
          //step 2
          fwiEncodeHuffman8x8_JPEG_16s1u_C1 (  lDCT,
                            *pEncodedChannel , lSize, pLength,
                            &lLastDC,
                            &lDCEncHuffSpec,
                            &lACEncHuffSpec,
                            &lEncHuffState, 0);

         
        }
        //step 1
        fwiDCTQuantFwd8x8_JPEG_16s_C1 ( pLuminanceChannel + lNbBlocks * 64, lDCT, lQuantFwdTable );
        //step 2
        fwiEncodeHuffman8x8_JPEG_16s1u_C1 ( lDCT ,
                          *pEncodedChannel , lSize, pLength,
                          &lLastDC,
                          &lDCEncHuffSpec,
                          &lACEncHuffSpec,
                          &lEncHuffState, 1);

        fwFree(lDCT);
      }
        
      /******************************************************************************
      * Method to encode the chrominance Channels : chroma blue && red
      * @param pWidth width of the chrominance channels
      * @param pHeight height of the chrominance channels
      * @param pChrominanceChannels array containg first the Cb channnel && finally th Cr channel
      * @param pEncodedChannels array containing first the encoded Cb channel && finally the encoded Cr channel
      * @param pLengths array containing first the size in bytes of the encoded Cb channel && after this of the Cb channel
      ******************************************************************************/
      void encodeChrominance(int pWidth, int pHeight, Fw16s *pChrominanceChannels[2], Fw8u *pEncodedChannels[2],  int pLengths[2])
      {
        // step 1 : Discrete cosinus transform && Quantization
        //init quantization table
        Fw16u lQuantFwdTable[64];
        fwiQuantFwdTableInit_JPEG_8u16u (gDefaultChrominance, lQuantFwdTable);
        //DCT
        Fw16s *lCbDCT = (Fw16s*)fwMalloc(64*sizeof(Fw16s));
        Fw16s *lCrDCT = (Fw16s*)fwMalloc(64*sizeof(Fw16s));
       
        // step 2  : huffman encoding
        //init encoding structure
        FwiEncodeHuffmanSpec lACEncHuffSpec, lDCEncHuffSpec;
        fwiEncodeHuffmanSpecInit_JPEG_8u(gDefaultChrominanceACBits, gDefaultChrominanceACValues, &lACEncHuffSpec );
        fwiEncodeHuffmanSpecInit_JPEG_8u(gDefaultChrominanceDCBits, gDefaultChrominanceDCValues, &lDCEncHuffSpec );
        FwiEncodeHuffmanState lEncHuffStateCb;
        fwiEncodeHuffmanStateInit_JPEG_8u(&lEncHuffStateCb);
        FwiEncodeHuffmanState lEncHuffStateCr;
        fwiEncodeHuffmanStateInit_JPEG_8u(&lEncHuffStateCr);
         
        pEncodedChannels[0] = (Fw8u*)fwMalloc(pWidth * pHeight * sizeof(Fw8u));
        pEncodedChannels[1] = (Fw8u*)fwMalloc(pWidth * pHeight * sizeof(Fw8u));

        Fw16s lCrLastDC = 0;
        Fw16s lCbLastDC = 0;
        int lNbBlocks = pWidth * pHeight / 64 - 1;
        int lSize = pWidth * pHeight * sizeof(Fw8u);
        for
          (int lBlockIndex = 0; lBlockIndex < lNbBlocks; lBlockIndex++)
        {
          //Chroma blue
          //step 1
          fwiDCTQuantFwd8x8_JPEG_16s_C1 ( pChrominanceChannels[0] + lBlockIndex * 64, lCbDCT, lQuantFwdTable );
          //step 2
          fwiEncodeHuffman8x8_JPEG_16s1u_C1 ( lCbDCT,
                  pEncodedChannels[0] , lSize, pLengths,
                  &lCbLastDC,
                  &lDCEncHuffSpec,
                  &lACEncHuffSpec,
                  &lEncHuffStateCb, 0);
          //Chrom red
          //step 1
          fwiDCTQuantFwd8x8_JPEG_16s_C1 ( pChrominanceChannels[1] + lBlockIndex * 64, lCrDCT, lQuantFwdTable );
          //step 2
          fwiEncodeHuffman8x8_JPEG_16s1u_C1 ( lCrDCT,
                  pEncodedChannels[1] , lSize, (pLengths + 1),
                  &lCrLastDC,
                  &lDCEncHuffSpec,
                  &lACEncHuffSpec,
                  &lEncHuffStateCr, 0);
        }
        //Chroma blue
        //step 1
        fwiDCTQuantFwd8x8_JPEG_16s_C1 ( pChrominanceChannels[0] + lNbBlocks * 64, lCbDCT, lQuantFwdTable );
        //step 2 
        fwiEncodeHuffman8x8_JPEG_16s1u_C1 ( lCbDCT,
                  pEncodedChannels[0] , lSize, pLengths,
                  &lCbLastDC,
                  &lDCEncHuffSpec,
                  &lACEncHuffSpec,
                  &lEncHuffStateCb, 1);
        //Chrom red
        //step 1
        fwiDCTQuantFwd8x8_JPEG_16s_C1 ( pChrominanceChannels[1] + lNbBlocks * 64, lCrDCT, lQuantFwdTable );
        //step 2 
        fwiEncodeHuffman8x8_JPEG_16s1u_C1 ( lCrDCT,
                  pEncodedChannels[1] , lSize, (pLengths + 1),
                  &lCrLastDC,
                  &lDCEncHuffSpec,
                  &lACEncHuffSpec,
                  &lEncHuffStateCr, 1);

        fwFree(lCbDCT);
        fwFree(lCrDCT);
      }

      ////////////
      // DECODE //
      ////////////

      /******************************************************************************
      * Method to decode the luminance channels
      * @param pWidth of the luminance channel
      * @param pHeight height of the luminance channel
      * @param pEncodedLuminance the encodeded luminance
      * @param pLength length of the encoded data
      * @param pDecodedChannel the decoded channel (its allocation is done in this method)
      ******************************************************************************/
      void decodeLuminance(int pWidth, int pHeight, Fw8u* pEncodedLuminance, int pLength, Fw16s **pDecodedChannel)
      {
        //step 1 : Huffman decoding
        Fw16s lLastDC = 0;
        //init decoding structures
        FwiDecodeHuffmanSpec lDecDCTable;
        fwiDecodeHuffmanSpecInit_JPEG_8u ( gDefaultLuminanceDCBits, gDefaultLuminanceDCValues, &lDecDCTable );
        FwiDecodeHuffmanSpec lDecACTable;
        fwiDecodeHuffmanSpecInit_JPEG_8u ( gDefaultLuminanceACBits, gDefaultLuminanceACValues, &lDecACTable );
        FwiDecodeHuffmanState lDecHuffState;
        fwiDecodeHuffmanStateInit_JPEG_8u(&lDecHuffState);

        Fw16s *lDCT = (Fw16s*)fwMalloc(64 * sizeof(Fw16s));
       
        int lCurrentPos = 0;
        int lMarker = 0;
         
        //step 2 :inverse DCT && quantization
        //init inverse quantization table
        Fw16u lQuantInvTable[64];
        fwiQuantInvTableInit_JPEG_8u16u ( gDefaultLuminance,lQuantInvTable );
        *pDecodedChannel = (Fw16s*)fwMalloc(pWidth* pHeight * sizeof(Fw16s));
       
       

       
        int lNbBlocks = pWidth * pHeight / 64;
        int lOffset = 0;
        for
          (int lBlockIndex = 0; lBlockIndex < lNbBlocks; lBlockIndex++)
        {
            //step 1
            FwStatus lStatus = fwiDecodeHuffman8x8_JPEG_1u16s_C1 (  pEncodedLuminance , pLength, &lCurrentPos,
                              lDCT,
                              &lLastDC, &lMarker,
                              &lDecDCTable,
                              &lDecACTable,
                              &lDecHuffState );
            if
              (lStatus != fwStsNoErr)
            {
              cerr << "error while decoding luminance : " << (lBlockIndex+1) << "/" << lNbBlocks << endl;
            }
            else
            {
            //step 2
            fwiDCTQuantInv8x8_JPEG_16s_C1(  lDCT,
                            (*pDecodedChannel) + lOffset,
                            lQuantInvTable);
            }
            lOffset +=64;
         
        }

        //saveLToPPM("LDec.ppm", pWidth, pHeight, *pDecodedChannel);
        fwFree(lDCT);
      }

      /******************************************************************************
      * Method to decode the chrominance channels
      * @param pWidth of the chrominance channel
      * @param pHeight height of the chrominance channel
      * @param pEncodedChromiance the encodeded chrominance
      * @param pLengths length of the encoded datas
      * @param pDecodedChannels the decoded channel (its allocation is done in this method)
      ******************************************************************************/
      void decodeChrominance(int pWidth, int pHeight, Fw8u* pEncodedChrominance[2], int pLengths[2], Fw16s *pDecodedChannels[2])
      {
        //step 1 : Huffman decoding
        //init decoding structures
        FwiDecodeHuffmanSpec lDecDCTable;
        fwiDecodeHuffmanSpecInit_JPEG_8u ( gDefaultChrominanceDCBits, gDefaultChrominanceDCValues, &lDecDCTable );
        FwiDecodeHuffmanSpec lDecACTable;
        fwiDecodeHuffmanSpecInit_JPEG_8u ( gDefaultChrominanceACBits, gDefaultChrominanceACValues, &lDecACTable );
        FwiDecodeHuffmanState lCbDecHuffState;
        fwiDecodeHuffmanStateInit_JPEG_8u(&lCbDecHuffState);
        FwiDecodeHuffmanState lCrDecHuffState;
        fwiDecodeHuffmanStateInit_JPEG_8u(&lCrDecHuffState);

        Fw16s *lCbDCT = (Fw16s*)fwMalloc(64 * sizeof(Fw16s));
        Fw16s *lCrDCT = (Fw16s*)fwMalloc(64 * sizeof(Fw16s));

        int lCbCurrentPos = 0;
        int lCrCurrentPos = 0;
        int lCbMarker = 0;
        int lCrMarker = 0;
        Fw16s lCbLastDC = 0;
        Fw16s lCrLastDC = 0;
       
        //step 2 :inverse DCT && quantization
        //init inverse quantization table
        Fw16u lQuantInvTable[64];
        fwiQuantInvTableInit_JPEG_8u16u ( gDefaultChrominance,lQuantInvTable );
       
        pDecodedChannels[0] = (Fw16s*)fwMalloc(pWidth* pHeight * sizeof(Fw16s));
        pDecodedChannels[1] = (Fw16s*)fwMalloc(pWidth* pHeight * sizeof(Fw16s));

       
        
        int lNbBlocks = pWidth * pHeight / 64;
        int lOffset = 0;
        for
          (int lBlockIndex = 0; lBlockIndex < lNbBlocks; lBlockIndex++)
        {
            //Chroma blue
            //step 1
            FwStatus lStatus = fwiDecodeHuffman8x8_JPEG_1u16s_C1 (  pEncodedChrominance[0] , pLengths[0], &lCbCurrentPos,
                          lCbDCT ,
                          &lCbLastDC, &lCbMarker,
                          &lDecDCTable,
                          &lDecACTable,
                          &lCbDecHuffState );
            //step 2
            if
              (lStatus != fwStsNoErr)
            {
              cerr << "error while decoding Chroma blue  : " << (lBlockIndex+1) << "/" << lNbBlocks << endl;
            }
            else
            {
              fwiDCTQuantInv8x8_JPEG_16s_C1(  lCbDCT ,
                            pDecodedChannels[0] + lOffset,
                            lQuantInvTable);
            }
           
            //Chroma red
            //step 1
            fwiDecodeHuffman8x8_JPEG_1u16s_C1 (  pEncodedChrominance[1] , pLengths[1], &lCrCurrentPos,
                              lCrDCT ,
                              &lCrLastDC, &lCrMarker,
                              &lDecDCTable,
                              &lDecACTable,
                              &lCrDecHuffState );
            //step 2
            if
              (lStatus != fwStsNoErr)
            {
              cerr << "error while decoding Chroma red  : " << (lBlockIndex+1) << "/" << lNbBlocks << endl;
            }
            else
            {
              fwiDCTQuantInv8x8_JPEG_16s_C1(  lCrDCT ,
                      pDecodedChannels[1] + lOffset,
                      lQuantInvTable);
            }

            lOffset += 64;
        }
       
        fwFree(lCrDCT);
        fwFree(lCbDCT);
      }

      Thanks for your help,

      Laurent

       
    • Ravi Korsa
      Ravi Korsa
      2008-04-18

      Hi Laurent,

                Thanks for your feedback. Here is the correct code for encoding luminance. You can make the same changes to the encode chrominance part also. There is no need to change the decode part. It is working perfectly fine. You were correct when you said that all the 8x8 blocks should be encoded and then you should call encodeHuffman8x8 for one last time with psrc being NULL and flushState set to 1. But you need not do anything(like copying the last decoded 8x8 block..) on the decoding side. It should work just fine. I have given comments at the extreme right wherever there is a change.(Also please make sure that values in pLengths[2] in chrominance fn. are initialised to 0. I had problem with this.). Please let me know if everything is fine.

      void encodeLuminance(int pWidth, int pHeight, Fw16s *pLuminanceChannel, Fw8u **pEncodedChannel, int *pLength)
      {
      // step 1 : Discrete cosinus transform && Quantization
      //init quantization table
      Fw16u lQuantFwdTable[64];
      fwiQuantFwdTableInit_JPEG_8u16u (gDefaultLuminance, lQuantFwdTable);
      //DCT
      Fw16s *lDCT = (Fw16s*)fwMalloc(64*sizeof(Fw16s));

      // step 2 : huffman encoding
      //init encoding structure
      FwiEncodeHuffmanSpec lACEncHuffSpec, lDCEncHuffSpec;
      fwiEncodeHuffmanSpecInit_JPEG_8u(gDefaultLuminanceACBits, gDefaultLuminanceACValues, &lACEncHuffSpec );
      fwiEncodeHuffmanSpecInit_JPEG_8u(gDefaultLuminanceDCBits, gDefaultLuminanceDCValues, &lDCEncHuffSpec );
      FwiEncodeHuffmanState lEncHuffState;
      fwiEncodeHuffmanStateInit_JPEG_8u(&lEncHuffState);

      *pEncodedChannel = (Fw8u*)fwMalloc(pWidth * pHeight * sizeof(Fw8u));

      Fw16s lLastDC = 0;
      int lNbBlocks = pWidth * pHeight / 64 ; // nb 8x8 blocks                          // Process all the 8x8 blocks
      int lSize = pWidth * pHeight * sizeof(Fw8u);
      *pLength = 0;

      for(int lBlockIndex = 0; lBlockIndex < lNbBlocks; lBlockIndex++)
      {
      //step 1
      fwiDCTQuantFwd8x8_JPEG_16s_C1 ( pLuminanceChannel + lBlockIndex * 64, lDCT, lQuantFwdTable );
      //step 2
      fwiEncodeHuffman8x8_JPEG_16s1u_C1 ( lDCT, 
      *pEncodedChannel , lSize, pLength,
      &lLastDC,
      &lDCEncHuffSpec,
      &lACEncHuffSpec,
      &lEncHuffState, 0);

      }
      //step 1
                                                                               // removed quantisation..
      //step 2
      fwiEncodeHuffman8x8_JPEG_16s1u_C1 ( 0,                                   // set source pointer to NULL
      *pEncodedChannel , lSize, pLength,
      &lLastDC,
      &lDCEncHuffSpec,
      &lACEncHuffSpec,
      &lEncHuffState, 1);

      fwFree(lDCT);
      }

       
    • Hi,

      I'm really sorry for my late.
      So I try your code (thanks a lot).

      Unfortunately, symptoms are still present.
      I also notice a problem about decoded value. It seems that channels saturates, ie : I got that lots of pixels that are yellow, cyan, green ... while they shouldn't be. It happens espacially on color variation. I test with the last version in the trunk.

       
    • Ravi Korsa
      Ravi Korsa
      2008-05-21

      Hi Laurent,

                The following functions were corrected today. Hopefully that should solve your problem. Please checkout
                the latest code from trunk.

                fwiQuantFwd8x8_JPEG_16s_C1I
                fwiRGBToYCbCr411LS_MCU_8u16s_C3P3R

      -Korsa.

       
    • Hi Korsa,

      Great, there is no longer problem with pixels which seems saturating. Thanks a lot.

      But the other problem is still there.
      I'll also test the quality factor. So, if you don't mind, I'll report if it work.

      Laurent

       
    • Hello,

      I think I've found why errors occur at the end of the decoding step.
      I think it's because of the end condition of fwiDecodeHuffman8x8_JPEG_1u16s_C1 :

      if (srcLenBytes <0 || *pSrcCurrPos >= srcLenBytes)
          return fwStsSizeErr;

      Here the decoding won't be performed when the current position in the encoded source is greater than
      its length. But it's possible (in the last blocks) that we have reached last byte in the encoded source,
      whereas it remains some blocks to decode : encoded bits are in the accumulator buffer of
      the FwiDecodeHuffmanState structure. So I modified the end condition :

      if (srcLenBytes <0 ||
         ( (*pSrcCurrPos >= srcLenBytes) && ((Fw32u)((1 << pDecHuffState->accbitnum) - 1) == (pDecHuffState->accbuf)) )
         )
         return fwStsSizeErr;

      Here, the decoding stops if the position is greater than its length and if all bits placed in the accumulator are set
      to 1(when the EncStateFlush method is called at the end of encoding step, remaining bits are placed in the ultimate
      byte, and this ultimate byte is completed with a set of 1-bits).

      I also change :
      pDecHuffState->srcLenBytes = srcLenBytes;
      to :
      pDecHuffState->srcLenBytes = srcLenBytes - (*pSrcCurrPos);

      Finally, fwiDecodeHuffman8x8_JPEG_1u16s_C1 looks like this :

      //-----------------------------------------------------------------------
      //This function handles the Huffman Baseline decoding for a 8*8 block of the
      //quantized DCT coefficients. The decoding procedure follows CCITT Rec. T.81
      //section F.2.2
      //-----------------------------------------------------------------------
      FwStatus PREFIX_OPT(OPT_PREFIX, fwiDecodeHuffman8x8_JPEG_1u16s_C1)(
          const Fw8u *pSrc, int srcLenBytes, int *pSrcCurrPos, Fw16s *pDst,
          Fw16s *pLastDC, int *pMarker, const FwiDecodeHuffmanSpec *pDcTable,
          const FwiDecodeHuffmanSpec *pAcTable, FwiDecodeHuffmanState *pDecHuffState)
      {
        if (pSrc==0 || pSrcCurrPos==0 || pDst==0 || pLastDC ==0 ||
            pMarker==0 || pDcTable ==0 || pAcTable==0 ||
            pDecHuffState==0)
          return fwStsNullPtrErr;

          if (srcLenBytes == 0) {
              *pMarker = pDecHuffState->marker;
              return fwStsNoErr;
          }

        //end condition changed to take care of accumulated bits
        if (srcLenBytes <0 ||
           ( (*pSrcCurrPos >= srcLenBytes) && ((Fw32u)((1 << pDecHuffState->accbitnum) - 1) == (pDecHuffState->accbuf)) )
              )
          return fwStsSizeErr;

        int s, k, runlen;

        pDecHuffState->pCurrSrc = (unsigned char *)(pSrc+*pSrcCurrPos);
        //current length of src changed
        //to reflect the number of remaining bytes in the encoded source
        pDecHuffState->srcLenBytes = srcLenBytes - (*pSrcCurrPos);
        pDecHuffState->marker   = *pMarker;

        //Follow JPEG standard F.2.2.1 to decode DC coefficient
        if (!FW_HUFF_DECODE(&s, pDecHuffState, pDcTable)) return fwStsJPEGOutOfBufErr;
          if (s) {
              if (pDecHuffState->accbitnum < s) {
                  if (! dec_receivebits(pDecHuffState,pDecHuffState->accbuf,pDecHuffState->accbitnum,s))
                      return fwStsJPEGOutOfBufErr;
              }
              runlen = GET_ACCBITS(pDecHuffState, s);
              s = DEC_EXTEND(runlen, s);
          }

        //pLastDC
        s += *pLastDC;
        *pLastDC = (Fw16s) s;

        // clean pDst buffer since zero will be skipped
        memset(pDst, 0, 128);//pDst is 16s type

        pDst[0] = (Fw16s) s;

        // Follow JPEG standard F.2.2.2 to decode AC coefficient
        // Figure F.13
        for (k = 1; k < 64; k++) {

          //RS = DECODE
          if (!FW_HUFF_DECODE(&s, pDecHuffState, pAcTable)) return fwStsJPEGOutOfBufErr;

          runlen = s >> 4;
          s &= 0xf;

          if (s) {
          k += runlen;

          //Figure F.14
              //Decode_ZZ(K)
          if (pDecHuffState->accbitnum < s) {
            if (! dec_receivebits(pDecHuffState, pDecHuffState->accbuf,
              pDecHuffState->accbitnum, s))
              return fwStsJPEGOutOfBufErr;
             }
          runlen = GET_ACCBITS(pDecHuffState, s);
          s = DEC_EXTEND(runlen, s);

          pDst[zigZagFwdOrder[k]] = (Fw16s) s;
          } else {
          if (runlen != 15)   break;
          k += 15;
            }
        }
        *pSrcCurrPos = (int)(pDecHuffState->pCurrSrc - pSrc);
        *pMarker = pDecHuffState->marker;

        return fwStsNoErr;
      }

      I test it with the code of the previous message, it seems to work fine.

      Can you tell me if my modifications are correct, or it already exits a method that I haven't seen that does this ?

      Thanks,

      Laurent