2002.09.05 09:56 "Decode group4", by Jan Edmundson

2002.09.09 12:27 "Re: Decode group4", by Jan Edmundson

Thanks for the advices I have received.

I am currently in the process of creating a class implementation of the fax group 4 codec.

In which language? C++?

C++

I have a class namned CCodec with 2 methods Decode and Encode. I am focusing on the decoding bit at the moment. I have a hypothesis that the Decode method would be sufficently declared as follows:

Decode( BYTE* pDest, DWORD dwDestSize, BYTE* pSrc, DWORD dwSrcSize, DWORD dwRowSize );

Dest should be uncompressed and Src should be compressed.

That assumes you will always be decoding the entire image. You need a different interface if line-at-a-time decoding is or becomes a requirement.

My intensions was to construct a generig codec that was compression oriented, not so much on what is compressed. But I am open for improvments. I think a pragmatic view that get the it properly working is favorable.

Is there someone out there that has a special intrest in the tiff decoding?

The roots of the libtiff g3/g4 decoder go back to my code in viewfax.

I took the liberty to look in to the viewfax code and found it easier to adopt to what I liked to do. At a first glance it looks less interconnected in the code.

I have ripped code out of libtiff but would like to get a clearer picture of what some of the variables is for in libtiff group 4 decoding.

Feel free to ask questions. Note that the code was originally developed in the era of 16MHz machines and the aim was to display faxes at acceptable interactive rates, rather than maintainability or understandability.

This is the point at were I am right now:

/*** HEADER

class CCodec
{
public:
 CCodec();
 virtual ~CCodec();

 virtual int Decode( BYTE* pDest, DWORD dwDestSize, BYTE* pSrc, DWORD dwSrcSize, DWORD dwRowSize );
 virtual int Encode( BYTE* pDest, BYTE* pSrc, DWORD dwSize );

protected:
 HANDLE m_hDecode;

};

class CCodecFax4 : public CCodec
{
public:
 int Decode( BYTE* pDest, DWORD dwDestSize, BYTE* pSrc, DWORD dwSrcSize, DWORD dwRowBytes, DWORD dwRowPixels );
 int Encode( BYTE* pDest, BYTE* pSrc, DWORD dwSize );

 void DecodeLine( pixnum *run, int linenum, struct pagenode *pn );

private:
 void Draw(pixnum *run, int linenum, struct pagenode *pn);

 BYTE* m_pDest;
 DWORD m_dwDestSize;

};

// *** CODE

static void drawline(pixnum *run, int linenum, struct pagenode *pn);


CCodec::CCodec()
{
 m_hDecode = CreateSemaphore( NULL, 1, 1, NULL );
}

CCodec::~CCodec()
{
 CloseHandle( m_hDecode );
}

int CCodec::Decode( BYTE* pDest, DWORD dwDestSize, BYTE* pSrc, DWORD dwSrcSize, DWORD dwRowSize )
{
 return 0;
}

int CCodec::Encode( BYTE* pDest, BYTE* pSrc, DWORD dwSize )
{
 return 0;
}

static CCodecFax4* pCodecFax4;

int CCodecFax4::Encode( BYTE* pDest, BYTE* pSrc, DWORD dwSize )
{
 return 0;
}

int CCodecFax4::Decode( BYTE* pDest, DWORD dwDestSize, BYTE* pSrc, DWORD dwSrcSize, DWORD dwRowBytes, DWORD dwRowPixels )
{
 int iRet = 0;
 struct pagenode pn;

 if ( m_hDecode && WaitForSingleObject( m_hDecode, 0L) == WAIT_OBJECT_0 ) {
  m_pDest = pDest;
  m_dwDestSize = dwDestSize;
  pCodecFax4 = this;

  // Setting up viewfax codec.

  pn.data = (unsigned short*) pSrc;
  pn.length = dwRowBytes;
  pn.width = (SHORT) dwRowPixels;

  // pn->vres
  // pn->stripnum
  // pn->inverse

  // Pimage(pn)->data
  // Pimage(pn)->bytes_per_line

  g4expand( &pn, drawline );

  pCodecFax4 = NULL;
  m_dwDestSize = 0;
  m_pDest = NULL;

  ReleaseSemaphore( m_hDecode, 1, NULL );

  iRet = 1;
  }

 return iRet;
}


// If I am correct this is where it should happen...
// this code doesent compile att the moment. Its pasted from viewfax drawline.
// The setting up of p and p1 seems to be the keys to success.

void CCodecFax4::DecodeLine( pixnum *run, int linenum, struct pagenode *pn )
{

    t32bits *p, *p1;  /* p - current line, p1 - low-res duplicate */
    pixnum *r;   /* pointer to run-lengths */
    t32bits pix;  /* current pixel value */
    t32bits acc;  /* pixel accumulator */
    int nacc;   /* number of valid bits in acc */
    int tot;   /* total pixels in line */
    int n;

    linenum += pn->stripnum * pn->rowsperstrip;
    p = (t32bits *) (Pimage(pn)->data + linenum*(2-pn->vres)*Pimage(pn)->bytes_per_line);
    p1 = pn->vres ? NULL : p + Pimage(pn)->bytes_per_line/sizeof(*p);
    r = run;
    acc = 0;
    nacc = 0;
    pix = pn->inverse ? ~0 : 0;
    tot = 0;
    while (tot < pn->width) {
 n = *r++;
 tot += n;
 if (pix)
     acc |= (~(t32bits)0 >> nacc);
 else if (nacc)
     acc &= (~(t32bits)0 << (32 - nacc));
 else
     acc = 0;
 if (nacc + n < 32) {
     nacc += n;
     pix = ~pix;
     continue;
 }
 *p++ = acc;
 if (p1)
     *p1++ = acc;
 n -= 32 - nacc;
 while (n >= 32) {
     n -= 32;
     *p++ = pix;
     if (p1)
  *p1++ = pix;
 }
 acc = pix;
 nacc = n;
 pix = ~pix;
    }
    if (nacc) {
 *p++ = acc;
 if (p1)
     *p1++ = acc;
    }
}

static void drawline( pixnum *run, int linenum, struct pagenode *pn )
{
 if ( pCodecFax4 )
  pCodecFax4->DecodeLine( run, linenum, pn );
}

// *** END