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