windows-nt/Source/XPSP1/NT/shell/osshell/accesory/mspaint/interlac.cpp
2020-09-26 16:20:57 +08:00

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;
}