446 lines
14 KiB
C++
446 lines
14 KiB
C++
/*********************************************************************
|
|
Interlace.cpp
|
|
|
|
Definition file for interlace module.
|
|
*********************************************************************/
|
|
#include "stdafx.h"
|
|
#include "Image.h"
|
|
#include "Interlac.h"
|
|
|
|
/*--------------------------------------------------------------------
|
|
Data Structures and Definitions.
|
|
--------------------------------------------------------------------*/
|
|
#define ADAM7_BLOCK_SIZE 8
|
|
|
|
short kgacPassScanLines[NUM_PASSES] = { 1, 1, 1, 2, 2, 4, 4 };
|
|
short kgacPassStartHorzPosn[NUM_PASSES] = { 0, 4, 0, 2, 0, 1, 0 };
|
|
short kgacPassStartVertPosn[NUM_PASSES] = { 0, 0, 4, 0, 2, 0, 1 };
|
|
short kgacPassVertIncrements[NUM_PASSES] = { 8, 8, 8, 4, 4, 2, 2 };
|
|
short kgacPassHorzIncrements[NUM_PASSES] = { 8, 8, 4, 4, 2, 2, 1 };
|
|
|
|
/*--------------------------------------------------------------------
|
|
Local Function Prototypes.
|
|
--------------------------------------------------------------------*/
|
|
|
|
long iFindPass(pADAM7_STRUCT);
|
|
long iFindImageLine(pADAM7_STRUCT);
|
|
|
|
/*--------------------------------------------------------------------
|
|
Export Function Definitions.
|
|
--------------------------------------------------------------------*/
|
|
|
|
//************************************************************************************
|
|
// Given an image described by the parameters of the ADAM7_STRUCT, calculate the
|
|
// number of scan lines in the image file which has been interlaced using the Adam7
|
|
// scheme.
|
|
//************************************************************************************
|
|
int iADAM7CalculateNumberOfScanLines(pADAM7_STRUCT ptAdam7)
|
|
{
|
|
if (ptAdam7 == NULL)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
if (ptAdam7->iImageHeight == 0 || ptAdam7->iImageWidth == 0)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
if (ptAdam7->iImageHeight < ADAM7_BLOCK_SIZE)
|
|
{
|
|
switch(ptAdam7->iImageHeight)
|
|
{
|
|
case 1:
|
|
ptAdam7->cPassScanLines[0] = 1;
|
|
ptAdam7->cPassScanLines[1] = 1;
|
|
ptAdam7->cPassScanLines[2] = 1;
|
|
ptAdam7->cPassScanLines[3] = 1;
|
|
ptAdam7->cPassScanLines[4] = 1;
|
|
ptAdam7->cPassScanLines[5] = 1;
|
|
ptAdam7->cPassScanLines[6] = 0;
|
|
ptAdam7->cTotalScanLines = 6;
|
|
break;
|
|
|
|
case 2:
|
|
ptAdam7->cPassScanLines[0] = 1;
|
|
ptAdam7->cPassScanLines[1] = 1;
|
|
ptAdam7->cPassScanLines[2] = 1;
|
|
ptAdam7->cPassScanLines[3] = 1;
|
|
ptAdam7->cPassScanLines[4] = 1;
|
|
ptAdam7->cPassScanLines[5] = 1;
|
|
ptAdam7->cPassScanLines[6] = 1;
|
|
ptAdam7->cTotalScanLines = 7;
|
|
break;
|
|
|
|
case 3:
|
|
ptAdam7->cPassScanLines[0] = 1;
|
|
ptAdam7->cPassScanLines[1] = 1;
|
|
ptAdam7->cPassScanLines[2] = 1;
|
|
ptAdam7->cPassScanLines[3] = 1;
|
|
ptAdam7->cPassScanLines[4] = 1;
|
|
ptAdam7->cPassScanLines[5] = 2;
|
|
ptAdam7->cPassScanLines[6] = 1;
|
|
ptAdam7->cTotalScanLines = 8;
|
|
break;
|
|
|
|
case 4:
|
|
ptAdam7->cPassScanLines[0] = 1;
|
|
ptAdam7->cPassScanLines[1] = 1;
|
|
ptAdam7->cPassScanLines[2] = 1;
|
|
ptAdam7->cPassScanLines[3] = 1;
|
|
ptAdam7->cPassScanLines[4] = 1;
|
|
ptAdam7->cPassScanLines[5] = 2;
|
|
ptAdam7->cPassScanLines[6] = 2;
|
|
ptAdam7->cTotalScanLines = 9;
|
|
break;
|
|
|
|
case 5:
|
|
ptAdam7->cPassScanLines[0] = 1;
|
|
ptAdam7->cPassScanLines[1] = 1;
|
|
ptAdam7->cPassScanLines[2] = 1;
|
|
ptAdam7->cPassScanLines[3] = 2;
|
|
ptAdam7->cPassScanLines[4] = 1;
|
|
ptAdam7->cPassScanLines[5] = 3;
|
|
ptAdam7->cPassScanLines[6] = 2;
|
|
ptAdam7->cTotalScanLines = 11;
|
|
break;
|
|
|
|
case 6:
|
|
ptAdam7->cPassScanLines[0] = 1;
|
|
ptAdam7->cPassScanLines[1] = 1;
|
|
ptAdam7->cPassScanLines[2] = 1;
|
|
ptAdam7->cPassScanLines[3] = 2;
|
|
ptAdam7->cPassScanLines[4] = 1;
|
|
ptAdam7->cPassScanLines[5] = 3;
|
|
ptAdam7->cPassScanLines[6] = 3;
|
|
ptAdam7->cTotalScanLines = 12;
|
|
break;
|
|
|
|
case 7:
|
|
ptAdam7->cPassScanLines[0] = 1;
|
|
ptAdam7->cPassScanLines[1] = 1;
|
|
ptAdam7->cPassScanLines[2] = 1;
|
|
ptAdam7->cPassScanLines[3] = 2;
|
|
ptAdam7->cPassScanLines[4] = 2;
|
|
ptAdam7->cPassScanLines[5] = 4;
|
|
ptAdam7->cPassScanLines[6] = 3;
|
|
ptAdam7->cTotalScanLines = 14;
|
|
break;
|
|
}
|
|
|
|
return ptAdam7->cTotalScanLines;
|
|
}
|
|
|
|
|
|
ptAdam7->cScanBlocks = ptAdam7->iImageHeight / ADAM7_BLOCK_SIZE;
|
|
int iExtraLines = ptAdam7->iImageHeight % ADAM7_BLOCK_SIZE;
|
|
|
|
ptAdam7->cTotalScanLines = 0;
|
|
|
|
for (int i = 0; i < NUM_PASSES; i++)
|
|
{
|
|
ptAdam7->cPassScanLines[i] = ptAdam7->cScanBlocks * kgacPassScanLines[i];
|
|
ptAdam7->cTotalScanLines += ptAdam7->cPassScanLines[i];
|
|
}
|
|
|
|
switch(iExtraLines)
|
|
{
|
|
case 0:
|
|
break;
|
|
|
|
case 1:
|
|
ptAdam7->cPassScanLines[0] += 1;
|
|
ptAdam7->cPassScanLines[1] += 1;
|
|
ptAdam7->cPassScanLines[2] += 0; // Yes, I could have left these out: hopefully
|
|
ptAdam7->cPassScanLines[3] += 1;
|
|
ptAdam7->cPassScanLines[4] += 0; // these will help someone else figure out the
|
|
ptAdam7->cPassScanLines[5] += 1;
|
|
ptAdam7->cPassScanLines[6] += 0; // Adam7 de-interlacing scheme.
|
|
ptAdam7->cTotalScanLines += 4;
|
|
break;
|
|
|
|
case 2:
|
|
ptAdam7->cPassScanLines[0] += 1;
|
|
ptAdam7->cPassScanLines[1] += 1;
|
|
ptAdam7->cPassScanLines[2] += 0;
|
|
ptAdam7->cPassScanLines[3] += 1;
|
|
ptAdam7->cPassScanLines[4] += 0;
|
|
ptAdam7->cPassScanLines[5] += 1;
|
|
ptAdam7->cPassScanLines[6] += 1;
|
|
ptAdam7->cTotalScanLines += 5;
|
|
break;
|
|
|
|
case 3:
|
|
ptAdam7->cPassScanLines[0] += 1;
|
|
ptAdam7->cPassScanLines[1] += 1;
|
|
ptAdam7->cPassScanLines[2] += 0;
|
|
ptAdam7->cPassScanLines[3] += 1;
|
|
ptAdam7->cPassScanLines[4] += 1;
|
|
ptAdam7->cPassScanLines[5] += 2;
|
|
ptAdam7->cPassScanLines[6] += 1;
|
|
ptAdam7->cTotalScanLines += 7;
|
|
break;
|
|
|
|
case 4:
|
|
ptAdam7->cPassScanLines[0] += 1;
|
|
ptAdam7->cPassScanLines[1] += 1;
|
|
ptAdam7->cPassScanLines[2] += 0;
|
|
ptAdam7->cPassScanLines[3] += 1;
|
|
ptAdam7->cPassScanLines[4] += 1;
|
|
ptAdam7->cPassScanLines[5] += 2;
|
|
ptAdam7->cPassScanLines[6] += 2;
|
|
ptAdam7->cTotalScanLines += 8;
|
|
break;
|
|
|
|
case 5:
|
|
ptAdam7->cPassScanLines[0] += 1;
|
|
ptAdam7->cPassScanLines[1] += 1;
|
|
ptAdam7->cPassScanLines[2] += 1;
|
|
ptAdam7->cPassScanLines[3] += 2;
|
|
ptAdam7->cPassScanLines[4] += 1;
|
|
ptAdam7->cPassScanLines[5] += 3;
|
|
ptAdam7->cPassScanLines[6] += 2;
|
|
ptAdam7->cTotalScanLines += 11;
|
|
break;
|
|
|
|
case 6:
|
|
ptAdam7->cPassScanLines[0] += 1;
|
|
ptAdam7->cPassScanLines[1] += 1;
|
|
ptAdam7->cPassScanLines[2] += 1;
|
|
ptAdam7->cPassScanLines[3] += 2;
|
|
ptAdam7->cPassScanLines[4] += 1;
|
|
ptAdam7->cPassScanLines[5] += 3;
|
|
ptAdam7->cPassScanLines[6] += 3;
|
|
ptAdam7->cTotalScanLines += 12;
|
|
break;
|
|
|
|
case 7:
|
|
ptAdam7->cPassScanLines[0] += 1;
|
|
ptAdam7->cPassScanLines[1] += 1;
|
|
ptAdam7->cPassScanLines[2] += 1;
|
|
ptAdam7->cPassScanLines[3] += 2;
|
|
ptAdam7->cPassScanLines[4] += 2;
|
|
ptAdam7->cPassScanLines[5] += 4;
|
|
ptAdam7->cPassScanLines[6] += 3;
|
|
ptAdam7->cTotalScanLines += 14;
|
|
break;
|
|
|
|
default: /* Should never, ever get here! */
|
|
break;
|
|
}
|
|
|
|
return ptAdam7->cTotalScanLines;
|
|
}
|
|
|
|
|
|
//************************************************************************************
|
|
// Functions to generate a deinterlaced DIB; i.e., each pixel is in BGR in the case
|
|
// of RGB/RGBA image classes, and raster line data is stored in a contiguous block.
|
|
//************************************************************************************
|
|
LPBYTE *ppbADAM7InitDIBPointers(LPBYTE pbDIB, pADAM7_STRUCT ptAdam7, DWORD cbImageLine)
|
|
{
|
|
if (ptAdam7 == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
if (ptAdam7->iImageHeight == 0 || ptAdam7->iImageWidth == 0)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
BYTE **ppbRowPtrs = (BYTE **)HeapAlloc(GetProcessHeap(),
|
|
0, sizeof(BYTE *) * ptAdam7->iImageHeight);
|
|
if (ppbRowPtrs == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
/* DIBs are bottom up */
|
|
for (int i = 0; i < ptAdam7->iImageHeight; i++)
|
|
{
|
|
ppbRowPtrs[i] = pbDIB +
|
|
((DWORD)(ptAdam7->iImageHeight - i - 1) * (DWORD)cbImageLine);
|
|
}
|
|
|
|
int iScanLines = iADAM7CalculateNumberOfScanLines(ptAdam7);
|
|
|
|
ptAdam7->iPassLine = 0;
|
|
|
|
return ppbRowPtrs;
|
|
}
|
|
|
|
// The following returns TRUE if the scan line was an empty scan line.
|
|
BOOL ADAM7AddRowToDIB(LPBYTE *ppbDIBPtrs, LPBYTE pbScanLine, pADAM7_STRUCT ptAdam7)
|
|
{
|
|
BYTE *pbScan;
|
|
BYTE *pbImage;
|
|
BYTE *pbCurrentImageLine;
|
|
|
|
long iCurrentPass = iFindPass(ptAdam7);
|
|
long iImageLine = iFindImageLine(ptAdam7);
|
|
long i;
|
|
if (iImageLine < ptAdam7->iImageHeight)
|
|
{
|
|
|
|
pbCurrentImageLine = ppbDIBPtrs[iImageLine];
|
|
for (pbImage = pbCurrentImageLine + (kgacPassStartHorzPosn[iCurrentPass] * ptAdam7->cbPixelSize),
|
|
pbScan = pbScanLine, i = kgacPassStartHorzPosn[iCurrentPass];
|
|
i < ptAdam7->iImageWidth;
|
|
pbImage += (kgacPassHorzIncrements[iCurrentPass] * ptAdam7->cbPixelSize),
|
|
pbScan += ptAdam7->cbPixelSize,
|
|
i += kgacPassHorzIncrements[iCurrentPass])
|
|
{
|
|
{
|
|
switch (ptAdam7->Class)
|
|
{
|
|
case IFLCL_GRAY:
|
|
case IFLCL_GRAYA:
|
|
case IFLCL_PALETTE:
|
|
memcpy(pbImage, pbScan, ptAdam7->cbPixelSize);
|
|
break;
|
|
case IFLCL_RGBA:
|
|
*(pbImage + 3) = *(pbScan + 3); // And fall through . . .
|
|
case IFLCL_RGB:
|
|
*pbImage = *(pbScan + 2);
|
|
*(pbImage + 1) = *(pbScan + 1);
|
|
*(pbImage + 2) = *pbScan;
|
|
break;
|
|
default:
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
else
|
|
{
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
//************************************************************************************
|
|
// Generate a deinterlaced image; i.e., each pixel is in RGB in the case
|
|
// of RGB/RGBA image classes, and raster line data may not necessarily be stored
|
|
// in one contiguous block of memory.
|
|
//************************************************************************************
|
|
|
|
// The following returns TRUE if the scan line was an empty scan line.
|
|
BOOL ADAM7AddRowToImageBuffer(LPBYTE ppbImageBuffer[], LPBYTE pbScanLine, pADAM7_STRUCT ptAdam7)
|
|
{
|
|
BYTE *pbScan;
|
|
BYTE *pbImage;
|
|
BYTE *pbCurrentImageLine;
|
|
|
|
long iCurrentPass = iFindPass(ptAdam7);
|
|
long iImageLine = iFindImageLine(ptAdam7);
|
|
long i;
|
|
if (iImageLine < ptAdam7->iImageHeight)
|
|
{
|
|
|
|
pbCurrentImageLine = ppbImageBuffer[iImageLine];
|
|
for (pbImage = pbCurrentImageLine + (kgacPassStartHorzPosn[iCurrentPass] * ptAdam7->cbPixelSize),
|
|
pbScan = pbScanLine, i = kgacPassStartHorzPosn[iCurrentPass];
|
|
i < ptAdam7->iImageWidth;
|
|
pbImage += (kgacPassHorzIncrements[iCurrentPass] * ptAdam7->cbPixelSize),
|
|
pbScan += ptAdam7->cbPixelSize,
|
|
i += kgacPassHorzIncrements[iCurrentPass])
|
|
{
|
|
{
|
|
switch (ptAdam7->Class)
|
|
{
|
|
case IFLCL_GRAY:
|
|
case IFLCL_GRAYA:
|
|
case IFLCL_PALETTE:
|
|
memcpy(pbImage, pbScan, ptAdam7->cbPixelSize);
|
|
break;
|
|
case IFLCL_RGBA:
|
|
*(pbImage + 3) = *(pbScan + 3); // And fall through . . .
|
|
case IFLCL_RGB:
|
|
*pbImage = *pbScan;
|
|
*(pbImage + 1) = *(pbScan + 1);
|
|
*(pbImage + 2) = *(pbScan + 2);
|
|
break;
|
|
default:
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
else
|
|
{
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
//************************************************************************************
|
|
// Generate a deinterlaced alpha channel data block.
|
|
//************************************************************************************
|
|
BOOL ADAM7RMFDeinterlaceAlpha(LPWORD *ppwInterlaced, LPWORD *ppwDeinterlaced,
|
|
IFL_ALPHA_CHANNEL_INFO *ptAlphaInfo)
|
|
{
|
|
ADAM7_STRUCT tAdam7;
|
|
|
|
if (ppwInterlaced == NULL || ppwDeinterlaced == NULL || ptAlphaInfo == NULL)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
tAdam7.iImageHeight = ptAlphaInfo->dwHeight;
|
|
tAdam7.iImageWidth = ptAlphaInfo->dwWidth;
|
|
tAdam7.cbPixelSize = sizeof(WORD);
|
|
tAdam7.iPassLine = 0;
|
|
/* Simulate a class so we can use the AddRowToDIB function above. */
|
|
tAdam7.Class = IFLCL_GRAYA;
|
|
|
|
tAdam7.cTotalScanLines = iADAM7CalculateNumberOfScanLines(&tAdam7);
|
|
|
|
for (tAdam7.iScanLine = 0; tAdam7.iScanLine < tAdam7.cTotalScanLines; tAdam7.iScanLine++)
|
|
{
|
|
ADAM7AddRowToDIB((BYTE **)ppwDeinterlaced, (BYTE *)(ppwInterlaced[tAdam7.iScanLine]), &tAdam7);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------
|
|
Local Function Definitions.
|
|
--------------------------------------------------------------------*/
|
|
|
|
long iFindPass(pADAM7_STRUCT ptAdam7)
|
|
{
|
|
BOOL fFound = FALSE;
|
|
|
|
ptAdam7->iPass = 0;
|
|
int iSubTotal = ptAdam7->cPassScanLines[ptAdam7->iPass];
|
|
while (!fFound)
|
|
{
|
|
if (ptAdam7->iScanLine < iSubTotal)
|
|
{
|
|
fFound = TRUE;
|
|
ptAdam7->iPassLine = ptAdam7->iScanLine -
|
|
(iSubTotal - ptAdam7->cPassScanLines[ptAdam7->iPass]);
|
|
}
|
|
else
|
|
{
|
|
ptAdam7->iPass += 1;
|
|
iSubTotal += ptAdam7->cPassScanLines[ptAdam7->iPass];
|
|
}
|
|
}
|
|
|
|
return ptAdam7->iPass;
|
|
}
|
|
|
|
long iFindImageLine(pADAM7_STRUCT ptAdam7)
|
|
{
|
|
if (kgacPassStartHorzPosn[ptAdam7->iPass] >= ptAdam7->iImageWidth)
|
|
{
|
|
return (ptAdam7->iImageHeight + 1);
|
|
}
|
|
|
|
ptAdam7->iImageLine = kgacPassStartVertPosn[ptAdam7->iPass] +
|
|
ptAdam7->iPassLine * kgacPassVertIncrements[ptAdam7->iPass];
|
|
return ptAdam7->iImageLine;
|
|
}
|