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