FUNC_STATUS WORD invert_openXform ( IP_XFORM_HANDLE *pXform) /* out: returned handle */ { PINVERT_INST g; INSURE (pXform != NULL); IP_MEM_ALLOC (sizeof(INVERT_INST), g); *pXform = g; memset (g, 0, sizeof(INVERT_INST)); g->dwValidChk = CHECK_VALUE; return IP_DONE; fatal_error: return IP_FATAL_ERROR; }
static WORD table_openXform ( IP_XFORM_HANDLE *pXform) /* out: returned handle */ { PTBL_INST g; INSURE (pXform != NULL); IP_MEM_ALLOC (sizeof(TBL_INST), g); *pXform = g; memset (g, 0, sizeof(TBL_INST)); g->dwValidChk = CHECK_VALUE; return IP_DONE; fatal_error: return IP_FATAL_ERROR; }
FUNC_STATUS WORD fakeMono_openXform ( IP_XFORM_HANDLE *pXform) /* out: returned handle */ { PFMON_INST g; INSURE (pXform != NULL); IP_MEM_ALLOC (sizeof(FMON_INST), g); *pXform = g; memset (g, 0, sizeof(FMON_INST)); g->dwValidChk = CHECK_VALUE; g->iFakeDPI = 8; return IP_DONE; fatal_error: return IP_FATAL_ERROR; }
static TBOOL generateTable ( PTBL_INST g, DWORD_OR_PVOID aXformInfo[]) { IP_TABLE_TYPE which; DWORD dwparam; PVOID pvparam; float flparam; PBYTE pTable; PWORD pwTable; int nTable; g->nTables = 1; g->bBigTable = TFALSE; pTable = g->bTables[0]; dwparam = aXformInfo[IP_TABLE_OPTION].dword; pvparam = aXformInfo[IP_TABLE_OPTION].pvoid; flparam = aXformInfo[IP_TABLE_OPTION].fl; which = (IP_TABLE_TYPE)aXformInfo[IP_TABLE_WHICH].dword; g->bWhich = (BYTE)which; switch (which) { case IP_TABLE_USER: if (pvparam == 0) return TFALSE; memcpy (pTable, (PBYTE)pvparam, 256); break; case IP_TABLE_USER_WORD: if (pvparam == 0) return TFALSE; IP_MEM_ALLOC (4097*sizeof(WORD), pwTable); /* 4097: extra entry at end */ g->pwTables[0] = pwTable; memcpy (pwTable, (PWORD)pvparam, 4096*sizeof(WORD)); pwTable[4096] = pwTable[4095]; /* extra entry to help interpolation */ g->bBigTable = TTRUE; break; case IP_TABLE_USER_THREE: if (aXformInfo[IP_TABLE_COLOR_1].pvoid==0 || aXformInfo[IP_TABLE_COLOR_2].pvoid==0 || aXformInfo[IP_TABLE_COLOR_3].pvoid==0) return TFALSE; memcpy (g->bTables[0], (PBYTE)aXformInfo[IP_TABLE_COLOR_1].pvoid, 256); memcpy (g->bTables[1], (PBYTE)aXformInfo[IP_TABLE_COLOR_2].pvoid, 256); memcpy (g->bTables[2], (PBYTE)aXformInfo[IP_TABLE_COLOR_3].pvoid, 256); g->nTables = 3; break; case IP_TABLE_USER_THREE_WORD: if (aXformInfo[IP_TABLE_COLOR_1].pvoid==0 || aXformInfo[IP_TABLE_COLOR_2].pvoid==0 || aXformInfo[IP_TABLE_COLOR_3].pvoid==0) return TFALSE; for (nTable=0; nTable<3; nTable++) { IP_MEM_ALLOC (4097*sizeof(WORD), pwTable); /* 4097: extra entry at end */ g->pwTables[nTable] = pwTable; memcpy (pwTable, (PWORD)aXformInfo[IP_TABLE_COLOR_1+nTable].pvoid, 4096*sizeof(WORD)); pwTable[4096] = pwTable[4095]; /* extra entry to help interpolation */ } g->nTables = 3; g->bBigTable = TTRUE; break; case IP_TABLE_PASS_THRU: { int i; for (i=0; i<=255; i++) pTable[i] = i; } break; case IP_TABLE_GAMMA: { int index; float fval; float gamma; float gamval; gamma = (float)flparam / (float)(1L<<16); if (gamma<=0.0f || gamma>=10.0f) return TFALSE; gamma = 1.0f / gamma; if (g->traits.iBitsPerPixel==16 || g->traits.iBitsPerPixel==48) { WORD *pwTable; IP_MEM_ALLOC (4097*sizeof(WORD), pwTable); /* 4097: extra entry at end */ g->pwTables[0] = pwTable; for (index=0; index<=4095u; index++) { fval = (float)index / 4095.0f; gamval = 65535.0f * (float)pow(fval, gamma); pwTable[index] = (WORD)(gamval + 0.5f); } pwTable[4096] = pwTable[4095]; /* extra entry to help interpolation */ g->bBigTable = TTRUE; } else { for (index=0; index<=255u; index++) { fval = (float)index / 255.0f; gamval = 255.0f * (float)pow(fval, gamma); pTable[index] = (BYTE)(gamval + 0.5f); } } } break; case IP_TABLE_THRESHOLD: if (dwparam<1 || dwparam>255) return TFALSE; memset (pTable, 0, dwparam); memset (pTable+dwparam, 255, 256-dwparam); break; case IP_TABLE_MIRROR: { UINT index, mask; for (index=0; index<=255; index++) { for (mask=0x01u; mask<=0x80u; mask<<=1) { pTable[index] <<= 1; if (index & mask) pTable[index] += 1; } } } break; case IP_TABLE_BW_CLIP: { DWORD nBlack, nWhite, nMid, slopeMid, posMid, index; nBlack = dwparam >> 16; nWhite = dwparam & 0xFFFFu; if (nBlack+nWhite > 256) return TFALSE; for (index=0; index<nBlack; index++) pTable[index] = 0; for (index=256-nWhite; index<=255; index++) pTable[index] = 255; nMid = 256 - nBlack - nWhite; slopeMid = (255ul<<16) / (nMid + 1); posMid = 0x8000u; /* offset for rounding */ for (index=nBlack; index<256-nWhite; index++) { posMid += slopeMid; pTable[index] = (BYTE)(posMid >> 16); } } break; default: return TFALSE; } return TTRUE; fatal_error: return TFALSE; }
EXPORT(WORD) ipConvert ( IP_HANDLE hJob, /* in: handle to conversion job */ DWORD dwInputAvail, /* in: # avail bytes in input buf */ PBYTE pbInputBuf, /* in: ptr to input buffer */ PDWORD pdwInputUsed, /* out: # bytes used from input buf */ PDWORD pdwInputNextPos, /* out: file-pos to read from next */ DWORD dwOutputAvail, /* in: # avail bytes in output buf */ PBYTE pbOutputBuf, /* in: ptr to output buffer */ PDWORD pdwOutputUsed, /* out: # bytes written in out buf */ PDWORD pdwOutputThisPos) /* out: file-pos to write this data */ { PINST g; WORD ipResult; int iXform; WORD result; PGENBUF pgbIn, pgbOut; BOOL atTheHead, atTheTail; PXFORM_INFO pXform, pPriorXform, pNextXform; BOOL needInput, selectCnvState; DWORD dwBytes; int i; DWORD n; DWORD dwInUsed, dwOutUsed; DWORD dwInNextPos, dwOutThisPos; DWORD dwTheInLen, dwTheOutLen; PBYTE pbTemp; PBYTE pbTheInBuf, pbTheOutBuf; DWORD dwJunk; if (pbOutputBuf == NULL) { /* client wants us to discard all data */ pdwOutputUsed = &dwJunk; pdwOutputThisPos = &dwJunk; dwOutputAvail = 0xfffffffu; } PRINT0 (_T("ipConvert: hJob=%p, pbInputBuf=%p InputBufSize=%d pbOutputBuf=%p OutputBufSize=%d\n"), (void*)hJob, pbInputBuf, dwInputAvail, pbOutputBuf, dwOutputAvail); INSURE (pdwInputUsed !=NULL && pdwInputNextPos !=NULL && pdwOutputUsed!=NULL && pdwOutputThisPos!=NULL); HANDLE_TO_PTR (hJob, g); INSURE (g->xfCount>=1); pgbIn = &g->gbIn; pgbOut = &g->gbOut; *pdwInputUsed = 0; *pdwOutputUsed = 0; ipResult = 0; /**************************/ /* Beginning of Main Loop */ /**************************/ while (TRUE) { /**** Output any data in the output genbuf ****/ if (*pdwOutputUsed == 0) *pdwOutputThisPos = pgbOut->dwFilePos; if (pgbOut->dwValidLen != 0) { /* output genbuf is not empty */ /* Logic below: * * 1. If next output file-pos doesn't match output genbuf, exit loop. * * 2. Copy as much as possible from output genbuf to clients output buf. * 2.1 decide number of bytes to copy * 2.2 copy them * 2.3 update misc variables * * 3. If output genbuf is not empty, exit loop (client's buf is full), * else set wValidStart to 0 because output genbuf is empty. */ if ((*pdwOutputThisPos+*pdwOutputUsed) != pgbOut->dwFilePos) { PRINT0 (_T("ipConvert: output seek to %d\n"), pgbOut->dwFilePos); goto exitLoop; } dwBytes = pgbOut->dwValidLen; if (dwOutputAvail < dwBytes) dwBytes = dwOutputAvail; if (pbOutputBuf != NULL) { memcpy (pbOutputBuf + *pdwOutputUsed, pgbOut->pbBuf + pgbOut->dwValidStart, dwBytes); } *pdwOutputUsed += dwBytes; dwOutputAvail -= dwBytes; pgbOut->dwValidStart += dwBytes; pgbOut->dwFilePos += dwBytes; pgbOut->dwValidLen -= dwBytes; if (pgbOut->dwValidLen != 0) goto exitLoop; pgbOut->dwValidStart = 0; /* output genbuf is now empty */ } if (g->pendingInsert) { g->pendingInsert = FALSE; ipResult |= IP_WRITE_INSERT_OK; } /**** If ipResult has any returnable bits set, exit loop now ****/ if (ipResult & g->wResultMask) goto exitLoop; /**** Select an xform to run ****/ /* select the owner of input midbuf, or negative means 'none selected' */ iXform = g->iOwner; if (iXform < 0) { for (i=g->xfCount-1; i>=0; i--) { if (g->xfArray[i].eState == XS_CONV_NOT_RFD) { /* select last xform that's convnotrfd; this xform * is outputting (or thinking) but not inputting */ iXform = i; break; } } } if (iXform < 0) { for (i=0; i<g->xfCount; i++) { if (g->xfArray[i].eState != XS_DONE) { /* select first xform that's not done */ iXform = i; break; } } } if (iXform < 0) { /* all xforms are done: discard all input, and report that we're done */ *pdwInputUsed = dwInputAvail; ipResult |= IP_DONE; /* patch the last outtraits with actual # of rows output, so that * ipGetImageTraits will return actual row-count after we're done */ g->xfArray[g->xfCount-1].outTraits.lNumRows = g->lOutRows; /* patch first intraits for the same reason */ g->xfArray[0].inTraits.lNumRows = g->lInRows; goto exitLoop; } /**** Miscellaneous preparation ****/ pXform = &(g->xfArray[iXform]); atTheHead = (iXform == 0); atTheTail = (iXform == g->xfCount-1); pPriorXform = atTheHead ? NULL : &(g->xfArray[iXform-1]); pNextXform = atTheTail ? NULL : &(g->xfArray[iXform+1]); /**** Create the Xform if necessary ****/ if (pXform->eState == XS_NONEXISTENT) { PRINT0 (_T("ipConvert: creating xform %d\n"), iXform); INSURE (atTheHead || pPriorXform->eState>=XS_CONVERTING); if (atTheHead) { /* this xform's input traits were set by ipSetDefaultInputTraits */ } else { /* this xform's input traits are prior xform's output traits */ memcpy (&pXform->inTraits, &pPriorXform->outTraits, sizeof(IP_IMAGE_TRAITS)); if (atTheTail) { /* apply any DPI overrides */ if (g->dwForcedHorizDPI != 0) pXform->inTraits.lHorizDPI = (long)g->dwForcedHorizDPI; if (g->dwForcedVertDPI != 0) pXform->inTraits.lVertDPI = (long)g->dwForcedVertDPI; } } result = pXform->pXform->openXform (&pXform->hXform); INSURE (result == IP_DONE); result = pXform->pXform->setDefaultInputTraits ( pXform->hXform, &pXform->inTraits); INSURE (result == IP_DONE); result = pXform->pXform->setXformSpec ( pXform->hXform, pXform->aXformInfo); INSURE (result == IP_DONE); result = pXform->pXform->getHeaderBufSize ( pXform->hXform, &pXform->dwMinInBufLen); INSURE (result == IP_DONE); if (! atTheHead) { /* a header is only allowed on first xform */ INSURE (pXform->dwMinInBufLen == 0); } else { /* allocate the input genbuf */ if (pXform->dwMinInBufLen == 0) pXform->dwMinInBufLen = 1; PRINT0 (_T("ipConvert: alloc input genbuf, len=%d\n"), pXform->dwMinInBufLen); IP_MEM_ALLOC (pXform->dwMinInBufLen, pgbIn->pbBuf); pgbIn->dwBufLen = pXform->dwMinInBufLen; pgbIn->dwValidStart = 0; pgbIn->dwValidLen = 0; pgbIn->dwFilePos = 0; } pXform->eState = XS_PARSING_HEADER; } /**** Enter flushing state if appropriate ****/ if (pXform->eState == XS_CONVERTING && (( atTheHead && pbInputBuf==NULL && pgbIn->dwValidLen==0) || (!atTheHead && pPriorXform->eState==XS_DONE && g->iOwner<0))) { /* there will never be any more input to this xform: start flushing */ PRINT0 (_T("ipConvert: xform %d is now flushing\n"), iXform); pXform->eState = XS_FLUSHING; } /**** Check that input data and output space are available ****/ needInput = (pXform->eState==XS_PARSING_HEADER || pXform->eState==XS_CONVERTING); if (needInput) { if (! atTheHead) { /* the input midbuf must contain data */ INSURE (g->iOwner>=0 && g->dwMidValidLen>0); PRINT1 (_T("not at head, pixels = %08x\n"), *(DWORD*)(g->pbMidInBuf)); } else if (pbInputBuf != NULL) { DWORD dwUnusedStart; /* left-justify data in input genbuf if necessary */ if (pgbIn->dwBufLen-pgbIn->dwValidStart < pXform->dwMinInBufLen) { /* too much wasted space on left end, so left justify */ memmove (pgbIn->pbBuf, pgbIn->pbBuf + pgbIn->dwValidStart, pgbIn->dwValidLen); pgbIn->dwValidStart = 0; PRINT1 (_T("left just, pixels = %08x\n"), *(DWORD*)(pgbIn->pbBuf)); } /* put as much client input as possible into the input genbuf */ dwUnusedStart = pgbIn->dwValidStart + pgbIn->dwValidLen; dwBytes = pgbIn->dwBufLen - dwUnusedStart; if (dwBytes > dwInputAvail) dwBytes = dwInputAvail; memcpy (pgbIn->pbBuf + dwUnusedStart, pbInputBuf + *pdwInputUsed, dwBytes); pgbIn->dwValidLen += dwBytes; *pdwInputUsed += dwBytes; dwInputAvail -= dwBytes; *pdwInputNextPos += dwBytes; /* if input genbuf has insufficient data, exit loop */ if (pgbIn->dwValidLen < pXform->dwMinInBufLen) goto exitLoop; PRINT1 (_T("at head, pixels = %08x\n"), *(DWORD*)(pgbIn->pbBuf)); } } if (atTheTail && pXform->eState!=XS_PARSING_HEADER) { /* output might be produced; output genbuf must be empty */ INSURE (pgbOut->dwValidLen == 0); } /**** Call the Conversion Routine ****/ pbTheInBuf = atTheHead ? pgbIn->pbBuf + pgbIn->dwValidStart : g->pbMidInBuf; dwTheInLen = atTheHead ? pgbIn->dwValidLen : g->dwMidValidLen; pbTheOutBuf = atTheTail ? pgbOut->pbBuf : g->pbMidOutBuf; dwTheOutLen = atTheTail ? pgbOut->dwBufLen : g->dwMidLen; if (pXform->eState == XS_PARSING_HEADER) { result = pXform->pXform->getActualTraits ( pXform->hXform, dwTheInLen, pbTheInBuf, &dwInUsed, &dwInNextPos, &pXform->inTraits, &pXform->outTraits); dwOutUsed = 0; dwOutThisPos = 0; } else { if (pXform->eState == XS_FLUSHING) pbTheInBuf = NULL; result = pXform->pXform->convert ( pXform->hXform, dwTheInLen, pbTheInBuf, &dwInUsed, &dwInNextPos, dwTheOutLen, pbTheOutBuf, &dwOutUsed, &dwOutThisPos); } PRINT1 (_T("ipConvert: xform %d returned %04x\n"), iXform, result); PRINT1 (_T("ipConvert: consumed %d and produced %d bytes\n"), dwInUsed, dwOutUsed); if (pbTheOutBuf != NULL) PRINT1 (_T("ipConvert: out data = %08x\n"), *(DWORD*)pbTheOutBuf); INSURE ((result & IP_FATAL_ERROR) == 0); /**** Update Input and Output Buffers ****/ if (dwInUsed > 0) { if (pXform->pfReadPeek != NULL) { #if defined _WIN32 __try { #endif pXform->pfReadPeek (hJob, &(pXform->inTraits), dwInUsed, pbTheInBuf, pgbIn->dwFilePos, pXform->pUserData); #if defined _WIN32 } __except (EXCEPTION_EXECUTE_HANDLER) { goto fatal_error; } #endif } if (! atTheHead) { /* We _assume_ that the xform consumed all the data in the midbuf */ g->iOwner = -1; /* input midbuf is consumed and un-owned now */ g->dwMidValidLen = 0; } } if (needInput && atTheHead) { if (dwInUsed >= pgbIn->dwValidLen) { /* consumed all input; mark input genbuf as empty */ pgbIn->dwValidLen = 0; pgbIn->dwValidStart = 0; pgbIn->dwFilePos = dwInNextPos; } else { /* advance counters in genbuf */ pgbIn->dwValidLen -= dwInUsed; pgbIn->dwValidStart += dwInUsed; pgbIn->dwFilePos += dwInUsed; } /* if new genbuf file-pos doesn't match what xform wants, * discard remainder of buffer */ if (pgbIn->dwFilePos != dwInNextPos) { PRINT0 (_T("ipConvert: input seek to %d\n"), dwInNextPos); pgbIn->dwValidLen = 0; pgbIn->dwValidStart = 0; pgbIn->dwFilePos = dwInNextPos; } } if (dwOutUsed > 0) { if (pXform->pfWritePeek != NULL) { #if defined _WIN32 __try { #endif pXform->pfWritePeek (hJob, &(pXform->outTraits), dwOutUsed, pbTheOutBuf, dwOutThisPos, pXform->pUserData); #if defined _WIN32 } __except (EXCEPTION_EXECUTE_HANDLER) { goto fatal_error; } #endif } if (atTheTail) { pgbOut->dwFilePos = dwOutThisPos; pgbOut->dwValidStart = 0; pgbOut->dwValidLen = dwOutUsed; } else { INSURE (g->iOwner < 0); /* mid inbuf must be unowned here */ g->iOwner = iXform + 1; /* next xform hereby owns mid inbuf */ /* swap input and output midbuf pointers */ pbTemp = g->pbMidInBuf; g->pbMidInBuf = g->pbMidOutBuf; g->pbMidOutBuf = pbTemp; g->dwMidValidLen = dwOutUsed; } }
EXPORT(WORD) ipOpen ( int nXforms, /* in: number of xforms in lpXforms below */ LPIP_XFORM_SPEC lpXforms, /* in: the xforms we should perform */ int nClientData, /* in: # bytes of additional client data */ PIP_HANDLE phJob) /* out: handle for conversion job */ { PINST g; int i; PIP_XFORM_SPEC src; PXFORM_INFO dest; #ifdef HPIP_DEBUG char *ipIn = "/tmp/ipIn.dib"; #endif PRINT0 (_T("ipOpen: nXforms=%d\n"), nXforms); INSURE (nXforms>0 && lpXforms!=NULL && nClientData>=0 && phJob!=NULL); #ifdef HPIP_DEBUG for (i=0; i<nXforms; i++) { switch (lpXforms[i].eXform) { case X_FAX_DECODE: PRINT0("Fax_format=%d\n", lpXforms[i].aXformInfo[IP_FAX_FORMAT].dword); ipIn = "/tmp/ipIn.pbm"; break; case X_JPG_DECODE: PRINT0("JPG_decode=%d\n", lpXforms[i].aXformInfo[IP_JPG_DECODE_FROM_DENALI].dword); ipIn = "/tmp/ipIn.jpg"; break; case X_CNV_COLOR_SPACE: PRINT0("Color_space conversion=%d\n", lpXforms[i].aXformInfo[IP_CNV_COLOR_SPACE_WHICH_CNV].dword); PRINT0("Color_space gamma=%d\n", lpXforms[i].aXformInfo[IP_CNV_COLOR_SPACE_GAMMA].dword); break; case X_CROP: PRINT0("Crop_left=%d\n", lpXforms[i].aXformInfo[IP_CROP_LEFT].dword); PRINT0("Crop_right=%d\n", lpXforms[i].aXformInfo[IP_CROP_RIGHT].dword); PRINT0("Crop_top=%d\n", lpXforms[i].aXformInfo[IP_CROP_TOP].dword); PRINT0("Crop_maxoutrows=%d\n", lpXforms[i].aXformInfo[IP_CROP_MAXOUTROWS].dword); break; case X_PAD: PRINT0("Pad_left=%d\n", lpXforms[i].aXformInfo[IP_PAD_LEFT].dword); PRINT0("Pad_right=%d\n", lpXforms[i].aXformInfo[IP_PAD_RIGHT].dword); PRINT0("Pad_top=%d\n", lpXforms[i].aXformInfo[IP_PAD_TOP].dword); PRINT0("Pad_bottom=%d\n", lpXforms[i].aXformInfo[IP_PAD_BOTTOM].dword); PRINT0("Pad_value=%d\n", lpXforms[i].aXformInfo[IP_PAD_VALUE].dword); PRINT0("Pad_minheight=%d\n", lpXforms[i].aXformInfo[IP_PAD_MIN_HEIGHT].dword); break; default: PRINT0("Unknown xform\n"); break; } } infd = creat(ipIn, 0600); outfd = creat("/tmp/ipOut.ppm", 0600); #endif /**** Create Instance and Init Misc Variables ****/ IP_MEM_ALLOC (sizeof(INST) + nClientData, g); *phJob = g; memset (g, 0, sizeof(INST)); g->dwValidChk = CHECK_VALUE; g->iOwner = -1; g->wResultMask = PERMANENT_RESULTS; /**** Transfer the Xforms to xfArray ****/ g->xfCount = (WORD)nXforms; for (i=0; i<nXforms; i++) { src = &(lpXforms[i]); dest = &(g->xfArray[i]); dest->eState = XS_NONEXISTENT; dest->pXform = (src->pXform != NULL) ? src->pXform : xformJumpTables[src->eXform]; INSURE (dest->pXform != NULL); dest->pfReadPeek = src->pfReadPeek; dest->pfWritePeek = src->pfWritePeek; dest->pUserData = src->pUserData; memcpy (dest->aXformInfo, src->aXformInfo, sizeof(dest->aXformInfo)); } return IP_DONE; fatal_error: return IP_FATAL_ERROR; }
static WORD thumb_getActualTraits ( IP_XFORM_HANDLE hXform, /* in: handle for xform */ DWORD dwInputAvail, /* in: # avail bytes in input buf */ PBYTE pbInputBuf, /* in: ptr to input buffer */ PDWORD pdwInputUsed, /* out: # bytes used from input buf */ PDWORD pdwInputNextPos,/* out: file-pos to read from next */ PIP_IMAGE_TRAITS pInTraits, /* out: input image traits */ PIP_IMAGE_TRAITS pOutTraits) /* out: output image traits */ { PTN_INST g; int N; long lMaxSum; long nBytes; HANDLE_TO_PTR (hXform, g); /* Since there is no header, we'll report no usage of input */ *pdwInputUsed = 0; *pdwInputNextPos = 0; /* Compute N in our scale-factor of 1/N */ if (g->iFactorSpec <= 0) { N = -(g->iFactorSpec); } else { /* the +iFactorSpec-1 below biases N high (cieling function), * so the output width is biased low, so that we'll never go * larger than the requested output width. */ N = (g->inTraits.iPixelsPerRow + g->iFactorSpec - 1) / g->iFactorSpec; } if (N < 1) N = 1; g->wScale = N; /* Compute max summation of N-by-N input pixels */ lMaxSum = (long)N*N * (g->inTraits.iBitsPerPixel==1 ? 1 : 255); /* Compute pre-shift so that max sum does not exceed 16 bits */ if (lMaxSum >= (1L<<28)) g->wPreShift = 16; else if (lMaxSum >= (1L<<24)) g->wPreShift = 12; else if (lMaxSum >= (1L<<20)) g->wPreShift = 8; else if (lMaxSum >= (1L<<16)) g->wPreShift = 4; else g->wPreShift = 0; /* Now do the pre-shift on max sum */ lMaxSum >>= g->wPreShift; INSURE (lMaxSum < (1L<<16)); /* make sure it fits in 16 bits */ /* And compute the factor for converting a sum into a 0..255 pixel */ g->dwSumFac = (DWORD)((255.0/(float)lMaxSum) * (float)(1L<<16)); *pInTraits = g->inTraits; /* structure copies */ *pOutTraits = g->inTraits; if (pOutTraits->iBitsPerPixel == 1) pOutTraits->iBitsPerPixel = 8; pOutTraits->iPixelsPerRow = g->dwOutputWidth = pInTraits->iPixelsPerRow / N; if (pOutTraits->lNumRows >= 0) pOutTraits->lNumRows /= N; g->wMoreRows2Sum = N; g->dwInRowBytes = (pInTraits->iPixelsPerRow * pInTraits->iBitsPerPixel + 7) / 8; g->dwOutRowBytes = g->dwOutputWidth * pInTraits->iComponentsPerPixel; nBytes = g->dwOutRowBytes * sizeof(ULONG); IP_MEM_ALLOC (nBytes, g->pulSums); memset (g->pulSums, 0, nBytes); return IP_DONE | IP_READY_FOR_DATA; fatal_error: return IP_FATAL_ERROR; }