/* fut_free_tbl frees any table regardless of type by checking the magic * number in the header. It will also free a fut_t or a fut_chan_t. * * fut_free_tbls will free a null terminated list of any type of table, * useful for disposing of a set of tables which were used for constructing * a fut (which the fut has now absorbed and made shared copies of). */ void fut_free_tbl (KpGenericPtr_t tbl) { /* Make sure that we do not have a NULL pointer */ if( tbl == NULL ) { return; } switch (*(KpInt32_p)tbl) { case FUT_MAGIC: fut_free ((fut_p) tbl); break; case FUT_CMAGIC: fut_free_chan ((fut_chan_p) tbl); break; case FUT_IMAGIC: fut_free_itbl ((fut_itbl_p) tbl); break; case FUT_OMAGIC: fut_free_otbl ((fut_otbl_p) tbl); break; case FUT_GMAGIC: fut_free_gtbl ((fut_gtbl_p) tbl); break; } }
/* TpFreeData frees all of the memory allocated for a fut. */ PTErr_t TpFreeData ( KpHandle_t PTData) { PTErr_t errnum = KCP_PTERR_2; fut_p fut; fut = fut_lock_fut ((KpHandle_t)PTData); if (IS_FUT(fut)) { fut_free (fut); errnum = KCP_SUCCESS; } return errnum; }
PTErr_t PTNewMonoPT ( ResponseRecord_p grayTRC, KpUInt32_t gridsize, KpBool_t invert, PTRefNum_p thePTRefNumP) { PTErr_t PTErr; KpInt32_t dim[3], inSpace, outSpace; fut_p theFut = NULL; /* Check for valid ptrs */ PTErr = KCP_BAD_ARG; if (thePTRefNumP == NULL) goto GetOut; if (grayTRC == NULL) goto GetOut; if (gridsize < 2) goto GetOut; *thePTRefNumP = 0; /* all dimensions are the same */ dim[0] = dim[1] = dim[2] = (KpInt32_t) gridsize; /* pass the input arguments along to the fut maker */ if (invert == KPFALSE) { /* Create (1D -> 3D) FuT */ theFut = fut_new_empty (1, dim, 3, KCP_FIXED_RANGE, KCP_LAB_PCS); if (theFut == NULL) { goto ErrOut4; } PTErr = makeForwardXformMono (grayTRC, theFut); inSpace = KCM_MONO; /* setup the foward color space */ outSpace = KCM_CIE_LAB; } else { /* Create (3D -> 1D) FuT */ theFut = fut_new_empty (3, dim, 1, KCP_LAB_PCS, KCP_FIXED_RANGE); if (theFut == NULL) { goto ErrOut4; } PTErr = makeInverseXformMono (grayTRC, theFut); inSpace = KCM_CIE_LAB; /* setup the inverse color space */ outSpace = KCM_MONO; } if (PTErr != KCP_SUCCESS) { goto ErrOut1; } if (fut_to_mft (theFut) != 1) { /* convert to reference tables */ goto ErrOut3; } PTErr = fut2PT (&theFut, inSpace, outSpace, PTTYPE_CALCULATED, thePTRefNumP); /* make into PT */ if (PTErr != KCP_SUCCESS) { goto ErrOut0; } GetOut: return (PTErr); ErrOut4: PTErr = KCP_NO_MEMORY; goto ErrOut0; ErrOut3: PTErr = KCP_INCON_PT; goto ErrOut0; ErrOut1: PTErr = KCP_BAD_ARG; ErrOut0: if (theFut != NULL) fut_free (theFut); if (*thePTRefNumP != 0) PTCheckOut (*thePTRefNumP); goto GetOut; }
/* fut_new allocates and initializes a new fut_t data structure. * iomask specifies which (common) input tables and which output channels * are being defined. Additional channels may be added later using * fut_defchan. * * NOTES: * 1. All the tables must be packed into a single array. * * 2. If a needed input table is not supplied (as determined from the * grid table) or if a supplied input table is NULL, then a ramp * input table will be automatically generated and inserted into * the common itbl list. The grid sizes are inferred from the * supplied grid tables. */ fut_p fut_new ( KpInt32_t iomask, fut_itbl_p FAR* itbls, fut_gtbl_p FAR* gtbls, fut_otbl_p FAR* otbls) { fut_itbl_p itbl[FUT_NICHAN]; fut_otbl_p otbl[FUT_NOCHAN]; fut_gtbl_p gtbl[FUT_NOCHAN]; fut_p fut; KpInt32_t tIndex, imask, omask, i; /* get input and output masks */ imask = (KpInt32_t)FUT_IMASK(iomask); omask = (KpInt32_t)FUT_OMASK(iomask); if ( imask > FUT_ALLIN || omask > FUT_ALLOUT ) { DIAG("fut_new: too many input or output channels.\n", 0); return (NULL); } /* get args specified by iomask */ for ( i=0, tIndex = 0; i<FUT_NICHAN; i++ ) { itbl[i] = (((imask & FUT_BIT(i)) != 0) && (itbls != NULL)) ? itbls[tIndex++] : FUT_NULL_ITBL; } for ( i=0, tIndex = 0; i<FUT_NOCHAN; i++ ) { gtbl[i] = FUT_NULL_GTBL; otbl[i] = FUT_NULL_OTBL; if ((omask & FUT_BIT(i)) != 0) { if (gtbls != NULL) { gtbl[i] = gtbls[tIndex]; } if (otbls != NULL) { otbl[i] = otbls[tIndex]; } tIndex++; } } /* allocate and clear the fut_t structure */ fut = fut_alloc_fut (); if ( fut == NULL ) { return (NULL); } /* set the interpolation order */ fut->iomask.order = (KpInt32_t)FUT_ORDMASK(iomask); /* insert the specified input tables */ for ( i=0; i<FUT_NICHAN; i++ ) { if ( itbl[i] == NULL) continue; if ( ! IS_ITBL (itbl[i]) ) { fut_free (fut); return (NULL); } fut->iomask.in |= FUT_BIT(i); fut->itbl[i] = fut_share_itbl(itbl[i]); fut->itblHandle[i] = fut->itbl[i]->handle; } /* define the specified output channels */ for ( i=0; i<FUT_NOCHAN; i++ ) { if ( gtbl[i] == NULL) continue; if ( ! fut_defchan(fut,FUT_OUT(FUT_BIT(i)),NULL,gtbl[i],otbl[i]) ) { fut_free (fut); return (NULL); } } fut->lutConfig = LUT_TYPE_UNKNOWN; return (fut); }
fut_p constructfut ( KpInt32_t iomask, KpInt32_p sizeArray, fut_calcData_p fData, fut_ifunc_p ifunArray, fut_gfunc_p gfunArray, fut_ofunc_p ofunArray, PTDataClass_t iClass, PTDataClass_t oClass) { fut_p futp; KpInt32_t i1, imask, omask; fut_itbl_p itbls[FUT_NICHAN] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}; fut_gtbl_p gtbls[FUT_NOCHAN] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}; fut_otbl_p otbls[FUT_NOCHAN] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}; fut_ifunc_t ifun; fut_gfunc_t gfun; fut_ofunc_t ofun; fData_t fDataL; fut_calcData_p fDataP; if (sizeArray == NULL) return NULL; if (fData == NULL) { fDataP = &fDataL.std; } else { fDataP = fData; } imask = FUT_IMASK(iomask); omask = FUT_OMASK(iomask); #if defined KCP_DIAG_LOG {KpChar_t string[256], str2[256]; KpInt32_t i1; sprintf (string, "constructfut\n iomask %x, sizeArray[]", iomask); for (i1 = 0; i1 < FUT_NICHAN; i1++) { if ((FUT_BIT(i1) & imask) != 0) { sprintf (str2, " %d", sizeArray[i1]); strcat (string, str2); } } sprintf (str2, ", fData %x, ifunArray %x, gfunArray %x, ofunArray %x, iClass %d, oClass %d\n", fData, ifunArray, gfunArray, ofunArray, iClass, oClass); strcat (string, str2); kcpDiagLog (string);} #endif /* Compute shared input tables: */ for (i1 = 0; i1 < FUT_NICHAN; i1++) { if ((imask & FUT_BIT(i1)) != 0) { if ((ifunArray == NULL) || (ifunArray[i1] == NULL)) { ifun = fut_irampEx; fDataP = &fDataL.std; if (iClass == KCP_VARIABLE_RANGE) { fDataL.scale = KCP_16_TO_8_ENCODING; } else { fDataL.scale = 1.0; } } else { ifun = ifunArray[i1]; } fDataP->chan = i1; /* define the channel # */ itbls[i1] = fut_new_itblEx (KCP_REF_TABLES, iClass, sizeArray[i1], ifun, fDataP); itbls[i1]->id = fut_unique_id (); itbls[i1]->dataClass = iClass; } } /* Compute grid tables and output tables: */ for (i1 = 0; i1 < FUT_NOCHAN; i1++) { if ((omask & FUT_BIT(i1)) != 0) { if ((gfunArray == NULL) || (gfunArray[i1] == NULL)) { gfun = fut_grampEx; } else { gfun = gfunArray[i1]; } fDataP->chan = i1; /* define the channel # */ gtbls[i1] = fut_new_gtblEx (KCP_REF_TABLES, iomask, gfun, fDataP, sizeArray); gtbls[i1]->id = fut_unique_id(); if ((ofunArray == NULL) || (ofunArray[i1] == NULL)) { ofun = fut_orampEx; fDataP = &fDataL.std; if (oClass == KCP_VARIABLE_RANGE) { fDataL.scale = KCP_8_TO_16_ENCODING; } else { fDataL.scale = 1.0; } } else { ofun = ofunArray[i1]; } otbls[i1] = fut_new_otblEx (KCP_REF_TABLES, oClass, ofun, fDataP); otbls[i1]->id = fut_unique_id(); otbls[i1]->dataClass = oClass; } } /* Assemble FuT: */ futp = fut_new (iomask, itbls, gtbls, otbls); fut_free_tbls (FUT_NICHAN, (KpGenericPtr_t *)itbls); fut_free_tbls (FUT_NOCHAN, (KpGenericPtr_t *)gtbls); fut_free_tbls (FUT_NOCHAN, (KpGenericPtr_t *)otbls); if (fut_to_mft (futp) != 1) { /* convert to reference tables */ fut_free (futp); futp = NULL; } return (futp); }
/*------------------------------------------------------------------------------ * PTGetRelToAbsPT -- generate a PT which converts from ICC relative colorimetry to ICC absolute colorimetry (absolute color) = ((media white point) / (profile white point)) * (relative color) so (source absolute color) = ((source media white point) / (source profile white point)) * (source relative color) and (dest absolute color) = ((dest media white point) / (dest profile white point)) * (dest relative color) equating source and dest absolute colors (dest relative color) = ((source media white point) / (dest media white point)) * ((dest profile white point) / (source profile white point)) * (source relative color) *------------------------------------------------------------------------------ */ PTErr_t PTGetRelToAbsPT( KpUInt32_t RelToAbsMode, PTRelToAbs_p PTRelToAbs, PTRefNum_p PTRefNumPtr) { PTErr_t PTErr; KpInt32_t status; FloatXYZColor_t sMWP, dMWP, sPWP, dPWP; Fixed_t matrix[MF_MATRIX_DIM * MF_MATRIX_DIM]; fut_p theFutFromMatrix = NULL; /* just one mode now. allows for future expansion of the function */ if (RelToAbsMode != 0) return KCP_NOT_IMPLEMENTED; if (PTRefNumPtr == NULL) return KCP_BAD_ARG; *PTRefNumPtr = 0; sMWP.X = PTRelToAbs->srcMediaWhitePoint.X / (KpFloat32_t)KpF15d16Scale; /* convert fixed point XYZ to floating point */ sMWP.Y = PTRelToAbs->srcMediaWhitePoint.Y / (KpFloat32_t)KpF15d16Scale; sMWP.Z = PTRelToAbs->srcMediaWhitePoint.Z / (KpFloat32_t)KpF15d16Scale; dMWP.X = PTRelToAbs->dstMediaWhitePoint.X / (KpFloat32_t)KpF15d16Scale; dMWP.Y = PTRelToAbs->dstMediaWhitePoint.Y / (KpFloat32_t)KpF15d16Scale; dMWP.Z = PTRelToAbs->dstMediaWhitePoint.Z / (KpFloat32_t)KpF15d16Scale; sPWP.X = PTRelToAbs->srcProfileWhitePoint.X / (KpFloat32_t)KpF15d16Scale; sPWP.Y = PTRelToAbs->srcProfileWhitePoint.Y / (KpFloat32_t)KpF15d16Scale; sPWP.Z = PTRelToAbs->srcProfileWhitePoint.Z / (KpFloat32_t)KpF15d16Scale; dPWP.X = PTRelToAbs->dstProfileWhitePoint.X / (KpFloat32_t)KpF15d16Scale; dPWP.Y = PTRelToAbs->dstProfileWhitePoint.Y / (KpFloat32_t)KpF15d16Scale; dPWP.Z = PTRelToAbs->dstProfileWhitePoint.Z / (KpFloat32_t)KpF15d16Scale; matrix[0] = (Fixed_t)(((sMWP.X * dPWP.X) / (dMWP.X * sPWP.X) * KpF15d16Scale) + 0.5); /* fill in the matrix */ matrix[1] = 0; matrix[2] = 0; matrix[3] = 0; matrix[4] = (Fixed_t)(((sMWP.Y * dPWP.Y) / (dMWP.Y * sPWP.Y) * KpF15d16Scale) + 0.5); matrix[5] = 0; matrix[6] = 0; matrix[7] = 0; matrix[8] = (Fixed_t)(((sMWP.Z * dPWP.Z) / (dMWP.Z * sPWP.Z) * KpF15d16Scale) + 0.5); status = makeOutputMatrixXform ((Fixed_p)&matrix, PTRelToAbs->gridSize, &theFutFromMatrix); if (status != 1) { goto ErrOut1; } if (fut_to_mft (theFutFromMatrix) != 1) { /* convert to reference tables */ goto ErrOut3; } PTErr = fut2PT (&theFutFromMatrix, KCM_CIE_XYZ, KCM_CIE_XYZ, PTTYPE_CALCULATED, PTRefNumPtr); /* make into PT */ if (PTErr != KCP_SUCCESS) { goto ErrOut0; } GetOut: return (PTErr); ErrOut3: PTErr = KCP_INCON_PT; goto ErrOut0; ErrOut1: PTErr = KCP_BAD_ARG; ErrOut0: if (theFutFromMatrix != NULL) fut_free (theFutFromMatrix); if (*PTRefNumPtr != 0) PTCheckOut (*PTRefNumPtr); goto GetOut; }
/* TpReadData reads a fut from a memory block and returns a handle to a newly allocated fut */ PTErr_t TpReadData( KpFd_p fd, PTType_t format, PTRefNum_t PTRefNum, KpHandle_t PTHdr, KpHandle_t FAR* PTData) { PTErr_t errnum; fut_p fut = NULL, theFutFromMatrix = NULL, newFut = NULL, lab2xyzFut = NULL, finalFut = NULL; fut_hdr_p futHdr; Fixed_t matrix[MF_MATRIX_DIM * MF_MATRIX_DIM + MF_MATRIX_DIM]; KpInt32_t ret, iomask; KpChar_t ENUM_String[20]; KpInt32_t inCS, i, i1; ResponseRecord_t inRedTRC, inGreenTRC, inBlueTRC; ResponseRecord_t outRedTRC, outGreenTRC, outBlueTRC; PTRefNum_t matrixPTRefNum; PTDataClass_t iClass, oClass; futHdr = (fut_hdr_p) lockBuffer (PTHdr); /* get buffer pointer */ if (futHdr == NULL) { errnum = KCP_MEM_LOCK_ERR; goto GetOut; } futHdr->profileType = getIntAttrDef (PTRefNum, KCM_ICC_PROFILE_TYPE); futHdr->spaceIn = getIntAttrDef (PTRefNum, KCM_SPACE_IN); futHdr->spaceOut = getIntAttrDef (PTRefNum, KCM_SPACE_OUT); futHdr->iDataClass = getDataClass (futHdr->spaceIn); futHdr->oDataClass = getDataClass (futHdr->spaceOut); switch (format) { case FUT_CIGAM: /* fut with bytes reversed */ case FUT_MAGIC: /* fut with bytes in correct order */ if ((fut = fut_alloc_fut ()) == NULL) { /* allocate a new fut structure */ errnum = KCP_NO_ACTIVATE_MEM; } else { if (fut_read_tbls (fd, fut, futHdr) != 1) { /* read fut tables */ errnum = KCP_PT_DATA_READ_ERR; } else { if (fut_io_decode (fut, futHdr) == 0) { errnum = KCP_PTERR_0; } else { errnum = KCP_SUCCESS; } } } break; case PTTYPE_MFT1: case PTTYPE_MFT2: fut = fut_readMFutTbls (fd, futHdr, matrix); /* read matrix fut tables */ if (fut == NULL) { errnum = KCP_NO_ACTIVATE_MEM; } else { inCS = getIntAttrDef (PTRefNum, KCM_SPACE_IN); if ((inCS == KCM_CIE_XYZ) && (isIdentityMatrix (matrix, MF_MATRIX_DIM) != 1)) { ret = makeOutputMatrixXform ((Fixed_p)&matrix, 8, &theFutFromMatrix); if (ret != 1) { errnum = KCP_INCON_PT; goto GetOut; } else { iomask = FUT_PASS(FUT_XYZ); /* get the Lab to XYZ fut */ lab2xyzFut = get_lab2xyz (KCP_GRID_DIM_SIXTEEN); newFut = fut_comp (theFutFromMatrix, lab2xyzFut, iomask); if (newFut != NULL) { finalFut = fut_comp (fut, newFut, iomask); } fut_free (theFutFromMatrix); /* free intermediate futs */ fut_free (lab2xyzFut); fut_free (fut); fut_free (newFut); fut = finalFut; /* set the input color space attribute to Lab */ KpItoa (KCM_CIE_LAB, ENUM_String); errnum = PTSetAttribute (PTRefNum, KCM_SPACE_IN, ENUM_String); if (errnum != KCP_SUCCESS) { goto GetOut; } /* set the input composition attribute to Lab */ errnum = PTSetAttribute (PTRefNum, KCM_IN_CHAIN_CLASS_2, "6"); if (errnum != KCP_SUCCESS) { goto GetOut; } } } if ((fut == NULL) || !fut_io_encode (fut, futHdr)) { /* make the info header */ errnum = KCP_INCON_PT; goto GetOut; } errnum = KCP_SUCCESS; } break; case PTTYPE_MA2B: case PTTYPE_MB2A: matrix[0] = matrix[4] = matrix[8] = KpF15d16FromDouble(1.0); matrix[1] = matrix[2] = matrix[3] = matrix[5] = matrix[6] = matrix[7] = matrix[9] = matrix[10] = matrix[11] = KpF15d16FromDouble(0.0); fut = fut_readMabFutTbls (fd, futHdr, matrix); /* read matrix fut tables */ if (fut == NULL) { errnum = KCP_NO_ACTIVATE_MEM; } else { if (fut->lutConfig & HAS_MATRIX_DATA) { i = MF_MATRIX_DIM * MF_MATRIX_DIM + MF_MATRIX_DIM; for (i1 = 0; i1 < i; i1++) { fut->matrix[i1] = matrix[i1]; } switch (fut->lutConfig) { case MAB_M_MATRIX_B_COMBO: case MBA_B_MATRIX_M_COMBO: inRedTRC.CurveCount = fut->mabInTblEntries[0]; inGreenTRC.CurveCount = fut->mabInTblEntries[1]; inBlueTRC.CurveCount = fut->mabInTblEntries[2]; inRedTRC.CurveData = fut->mabInRefTbl[0]; inGreenTRC.CurveData = fut->mabInRefTbl[1]; inBlueTRC.CurveData = fut->mabInRefTbl[2]; outRedTRC.CurveCount = fut->mabOutTblEntries[0]; outGreenTRC.CurveCount = fut->mabOutTblEntries[1]; outBlueTRC.CurveCount = fut->mabOutTblEntries[2]; outRedTRC.CurveData = fut->mabOutRefTbl[0]; outGreenTRC.CurveData = fut->mabOutRefTbl[1]; outBlueTRC.CurveData = fut->mabOutRefTbl[2]; iClass = getDataClass(futHdr->spaceIn); oClass = getDataClass(futHdr->spaceOut); ret = makeFutFromMatrix ((Fixed_p)&matrix, &inRedTRC, &inGreenTRC, &inBlueTRC, &outRedTRC, &outGreenTRC, &outBlueTRC, MATRIX_GRID_SIZE, iClass, oClass, (fut_p *)&theFutFromMatrix); break; case MBA_B_MATRIX_M_CLUT_A_COMBO: inRedTRC.CurveCount = fut->mabInTblEntries[0]; inGreenTRC.CurveCount = fut->mabInTblEntries[1]; inBlueTRC.CurveCount = fut->mabInTblEntries[2]; inRedTRC.CurveData = fut->mabInRefTbl[0]; inGreenTRC.CurveData = fut->mabInRefTbl[1]; inBlueTRC.CurveData = fut->mabInRefTbl[2]; iClass = getDataClass(futHdr->spaceIn); oClass = KCP_UNKNOWN; ret = makeFutFromMatrix ((Fixed_p)&matrix, &inRedTRC, &inGreenTRC, &inBlueTRC, NULL, NULL, NULL, MATRIX_GRID_SIZE, iClass, oClass, (fut_p *)&theFutFromMatrix); break; case MAB_A_CLUT_M_MATRIX_B_COMBO: outRedTRC.CurveCount = fut->mabOutTblEntries[0]; outGreenTRC.CurveCount = fut->mabOutTblEntries[1]; outBlueTRC.CurveCount = fut->mabOutTblEntries[2]; outRedTRC.CurveData = fut->mabOutRefTbl[0]; outGreenTRC.CurveData = fut->mabOutRefTbl[1]; outBlueTRC.CurveData = fut->mabOutRefTbl[2]; iClass = KCP_UNKNOWN; oClass = getDataClass(futHdr->spaceOut); ret = makeFutFromMatrix ((Fixed_p)&matrix, NULL, NULL, NULL, &outRedTRC, &outGreenTRC, &outBlueTRC, MATRIX_GRID_SIZE, iClass, oClass, (fut_p *)&theFutFromMatrix); break; default: break; } if (NULL != theFutFromMatrix) { /* Create a PT from the fut */ errnum = fut2PT (&theFutFromMatrix, KCM_UNKNOWN, KCM_UNKNOWN, PTTYPE_CALCULATED, &matrixPTRefNum); if (errnum != KCP_SUCCESS) { goto GetOut; } errnum = setMatrixPTRefNum (PTRefNum, matrixPTRefNum, fut->lutConfig); if (errnum != KCP_SUCCESS) { goto GetOut; } } if (ret != 1) { errnum = KCP_INCON_PT; goto GetOut; } } if ((fut == NULL) || !fut_io_encode (fut, futHdr)) { /* make the info header */ errnum = KCP_INCON_PT; goto GetOut; } errnum = KCP_SUCCESS; } break; default: break; } GetOut: if ((errnum != KCP_SUCCESS) || (fut == NULL)) { fut_free (fut); } else { /* return handle to fut to caller */ /* make sure the futs are in the reference state */ if (fut_to_mft (fut) == 1) { *PTData = (KpHandle_t)fut_unlock_fut (fut); } } if ( ! unlockBuffer (PTHdr)) { errnum = KCP_MEM_UNLOCK_ERR; } return errnum; }
fut_p fut_resize ( fut_p fut, KpInt32_p sizeArray) { fut_p reSizedGtblFut = NULL, gtblFut = NULL, reSizedFut = NULL, identityFut = NULL; KpInt32_t i1, i2, iomask, iiomask, imask, omask, sameDims; fut_chan_p chan; fut_itbl_p itbl, itbls[FUT_NICHAN]; fut_gtbl_p gtbls[FUT_NOCHAN]; fut_otbl_p otbls[FUT_NOCHAN]; #if defined KCP_DIAG_LOG kcpDiagLog ("fut_resize\n"); #endif if ( ! IS_FUT(fut)) { return NULL; } for (i1 = 0; i1 < FUT_NICHAN; i1++) { itbls[i1] = FUT_NULL_ITBL; /* init to null for freeing on error */ } /* collect the gtbls from the source fut */ /* make sure that all the gtbls use the same itbls */ omask = 0; for (i1 = 0, sameDims = 1; i1 < FUT_NOCHAN; i1++) { chan = fut->chan[i1]; if (IS_CHAN(chan)) { for (i2 = 0; i2 < FUT_NICHAN; i2++) { itbl = fut->itbl[i2]; if (chan->itbl[i2] != itbl) { /* must be shared */ goto GetOut; } if (IS_ITBL(itbl)) { if (itbl->size != sizeArray [i2]) { sameDims = 0; /* not the same */ } } } omask |= FUT_BIT(i1); /* resize this chan */ gtbls[i1] = chan->gtbl; /* collect gtbls */ } else { gtbls[i1] = NULL; } } if (sameDims == 1) { return fut; /* already the right size! */ } imask = fut->iomask.in; iomask = FUT_OUT(omask) | FUT_IN(imask); /* make a new fut with these gtbls and identity itbls and otbls */ gtblFut = fut_new (iomask, NULL, gtbls, NULL); if (gtblFut != NULL) { /* make an identity fut with itbls that have the specified sizes */ iiomask = FUT_OUT(imask) | FUT_IN(imask); identityFut = constructfut (iiomask, sizeArray, NULL, NULL, NULL, NULL, KCP_FIXED_RANGE, KCP_FIXED_RANGE); if (identityFut != NULL) { /* compose the new size fut with the gtbl fut */ reSizedGtblFut = fut_comp (gtblFut, identityFut, 0); if (reSizedGtblFut != NULL) { /* make a new fut with original itbls, ... */ for (i1 = 0; i1 < FUT_NICHAN; i1++) { if ((imask & FUT_BIT(i1)) != 0) { itbls[i1] = fut_copy_itbl (fut->itbl[i1]); /* copy (do not share!) original itbls */ if (itbls[i1] == NULL) { goto GetOut; } makeMftiTblDat (itbls[i1]); /* convert to mft to remove grid size dependancy */ itbls[i1]->size = reSizedGtblFut->itbl[i1]->size; /* set new grid size */ fut_free_itbldat (itbls[i1], freeData); /* free fixed table, it has incorrect grid indices */ } } /* ... resized gtbls, and original otbls */ for (i1 = 0; i1 < FUT_NOCHAN; i1++) { if ((omask & FUT_BIT(i1)) != 0) { gtbls[i1] = reSizedGtblFut->chan[i1]->gtbl; /* collect resized gtbls */ otbls[i1] = fut->chan[i1]->otbl; /* and original otbls */ } else { gtbls[i1] = NULL; otbls[i1] = NULL; } } reSizedFut = fut_new (iomask, itbls, gtbls, otbls); } } } GetOut: fut_free (reSizedGtblFut); /* free the intermediate futs */ fut_free (gtblFut); fut_free (identityFut); fut_free_tbls (FUT_NICHAN, (void **)itbls); return (reSizedFut); }
/* fut_comp_ilut composes a set of 8 or 12-bit, 256 element look-up tables * with the input tables of a fut. These may have been derived from * another separable fut. A new fut is returned which shares grid and * output tables with the original but has new input tables. * * Iomask usage: * imask => luts defined in vararglist to be composed with itbls. * A NULL imask indicates one lut which is composed with * the first defined input table. * omask => unused * pmask => unused * INPLACE may be set to perform the composition in place, * replacing the existing itbls and returning a pointer * to the original fut. * VARARGS may be used to specify an array of luts. * 12BITS if set, supplied luts are 12-bit data (KpInt16_t). * Otherwise, they are 8-bit (KpUInt8_t). */ fut_p fut_comp_ilut ( fut_p fut, KpInt32_t iomask, KpGenericPtr_t FAR* srcluts) { KpChar_p luts[FUT_NICHAN]; KpInt32_t i, i2; KpInt32_t imask; KpInt32_t is_12bits; KpInt32_t in_place; fut_p new_fut; fut_itbl_p new_itbl; fut_itbl_p orig_itbls[FUT_NICHAN]; if ( ! IS_FUT(fut) ) return (FUT_NULL); /* unpack input mask. If zero, use first defined channel */ imask = (KpInt32_t)FUT_IMASK(iomask); if (imask == 0 ) { imask = (KpInt32_t)FUT_BIT(fut_first_chan((KpInt32_t)fut->iomask.in)); iomask |= FUT_IN(imask); } /* get args specified by iomask */ for ( i=0, i2 = 0; i<FUT_NICHAN; i++ ) { if (imask & FUT_BIT(i)) { luts[i] = srcluts[i2]; /* save lut address in array */ i2++; } } /* if INPLACE is not set, create a new fut which shares all of its tables */ in_place = (KpInt32_t)FUT_IPMASK(iomask); if ( in_place ) { new_fut = fut; } else { new_fut = fut_copy (fut); } /* unpack 12bit data flag */ is_12bits = (KpInt32_t)FUT_12BMASK(iomask); /* for each lut passed, compose it with the specified input table(s) */ /* start by composing the common itbls */ for ( i=0; i<FUT_NICHAN; i++) { /* save original itbls for future comparison */ orig_itbls[i] = fut->itbl[i]; /* if no lut or no itbl, there's nothing to do. */ if ( luts[i] == 0 || fut->itbl[i] == FUT_NULL_ITBL ) continue; /* compose itbl with fut and replace the existing one. */ new_itbl = fut_comp_itbl_ilut (fut->itbl[i], luts[i], is_12bits); if ( new_itbl == FUT_NULL_ITBL ) { if ( ! in_place ) fut_free (new_fut); return (FUT_NULL); } fut_free_itbl (new_fut->itbl[i]); new_fut->itbl[i] = new_itbl; } /* now compose the itbls in each chan, re-sharing if possible */ for ( i=0; i<FUT_NOCHAN; i++) { if ( new_fut->chan[i] == FUT_NULL_CHAN ) continue; if ( ! fut_comp_chan_ilut (new_fut->chan[i], (KpChar_p FAR*)luts, orig_itbls, new_fut->itbl, is_12bits) ) { if ( ! in_place ) { fut_free (new_fut); } return (FUT_NULL); } } return (new_fut); }
fut_p fut_comp (fut_p fut1, fut_p fut0, KpInt32_t iomask) { KpInt32_t ok = 1, nGridPoints, omask, evalomask, imask, pmask, order, i, j, nEntries, nOutChans; fut_p fut2 = NULL, evalFut = NULL; fut_itbl_p oitbls[FUT_NICHAN]; mf2_tbldat_p indat[FUT_NICHAN], outdat[FUT_NOCHAN]; fut_gtbl_p fut1_gtbls[FUT_NOCHAN]; if (( ! IS_FUT(fut0)) || ( ! IS_FUT(fut1))) { return (NULL); } /* extract component masks from iomask */ omask = FUT_OMASK(iomask); /* which output chans? */ pmask = FUT_PMASK(iomask); /* which ones allowed to pass through? */ order = FUT_ORDMASK(iomask); /* which interpolation to use? */ if ( order == FUT_DEFAULT ) { order = fut1->iomask.order; } /* adjust masks for iomask_check below */ pmask &= fut0->iomask.out; /* available for "pass through" */ if ( omask == 0 ) { /* required outputs (0 means all) */ omask = fut1->iomask.out; } /* see if fut0 can provide required inputs to fut1 */ imask = fut0->iomask.out; /* available inputs for fut1 */ iomask = FUT_OUT(omask) | FUT_IN(imask) | FUT_PASS(pmask); if ( ! fut_iomask_check (fut1, iomask) ) { return (NULL); } /* make sure the futs are in the reference state */ if ((fut_to_mft (fut0) != 1) || (fut_to_mft (fut1) != 1)) { return (NULL); } /* fut1 will be used to process the grid tables of fut0, placing the * results in the grid tables of fut2. Fut0's grid table data must first * be passed through its output tables before sending it through fut1's * input tables. This is accomplished more efficiently by composing * fut1's input tables with fut0's output tables and using these directly * on fut0 grid data rather than the normal input tables. * * Create the result fut (fut2) which will be the composition of fut1 * and fut0. Fut2 will inherit the input tables of fut0 and the output * tables of fut1. Its grid data will be in the same color coordinates * as fut1's. */ fut2 = fut_new (FUT_IN(FUT_ALLIN), fut0->itbl, NULL, NULL); if ( fut2 == NULL ) { return (NULL); } /* for each desired channel i in fut2, create a new grid table. The * dimensions of each new grid table are derived from fut0 and fut1 * like so: for every input required for channel i of fut1, form the * union of the input sets of all corresponding fut0 outputs. */ /* null all io tables and table pointers */ KpMemSet (oitbls, 0, sizeof(oitbls)); imask = 0; /* will be the input mask for all inputs needed to fut1 */ evalomask = 0; /* omask for evaluation */ for (i = 0; (i < FUT_NOCHAN) && ok; i++) { KpInt32_t size[FUT_NICHAN]; fut_gtbl_p gtbl; KpInt32_t imask1, imask2; fut1_gtbls[i] = NULL; /* assume not needed */ if ((omask & FUT_BIT(i)) == 0) { /* is this output channel needed? */ continue; /* no */ } /* if a specified output is to be passed through from fut0, do that here */ if ( ! IS_CHAN(fut1->chan[i]) && IS_CHAN(fut0->chan[i])) { ok = fut_defchan (fut2, FUT_OUT(FUT_BIT(i)), NULL, fut0->chan[i]->gtbl, fut0->chan[i]->otbl); continue; /* no need to evaluate this ochan */ } if (! IS_CHAN(fut1->chan[i])) { ok = 0; /* something wrong */ goto GetOut; } /* At this point we know that (fut1->chan[i] != 0). We also * have determined (from iomask_check above) that fut0->chan[j] != 0. */ imask2 = 0; /* determine inputs from fut0 needed for this channel */ imask1 = fut1->chan[i]->imask; /* inputs used by this chan */ for (j = 0; (j < FUT_NICHAN) && ok; j++) { if ((imask1 & FUT_BIT(j)) != 0) { /* this input chan is needed */ if ( ! IS_CHAN(fut0->chan[j])) { /* available? */ ok = 0; /* composition fails */ goto GetOut; } if (fut1->itbl[j] != fut1->chan[i]->itbl[j]) { /* shared itbl? */ goto nextOChan; /* nope, ignore this ochan */ } imask2 |= fut0->chan[j]->imask; } } evalomask |= FUT_BIT(i); /* will be evalutating this channel */ imask |= imask1; /* build mask of all needed inputs */ /* determine required dimensions from mask */ for (j = 0; j < FUT_NICHAN; j++) { size[j] = (imask2 & (KpInt32_t)FUT_BIT(j)) ? fut0->itbl[j]->size : 1; } /* create the new grid table * insert it along with fut1's output table into fut2 */ gtbl = fut_new_gtblEx (FUT_IN(FUT_ALLIN), NULL, NULL, size); ok = fut_defchan (fut2, FUT_OUT(FUT_BIT(i)), NULL, gtbl, fut1->chan[i]->otbl); fut_free_gtbl (gtbl); if (!ok) { goto GetOut; } fut1_gtbls[i] = fut1->chan[i]->gtbl; /* collect gtbls for evaluation fut */ /* verify the input data for the evaluation of the output channel in fut1 */ for (j = 0; j < FUT_NICHAN; j++) { if ((imask1 & FUT_BIT(j)) != 0) { /* this channel needed as input */ if ((fut0->chan[j]->imask & (~fut2->chan[i]->imask)) != 0) { /* it's inputs must be used by output */ ok = 0; /* composition fails */ goto GetOut; } } } nextOChan:; } /* collect the gtbls which are the input data for the chan evaluation. * also pre-compose fut0's otbls with fut1's itbls. */ for (i = 0; i < FUT_NICHAN; i++) { oitbls[i] = NULL; if (ok) { fut_chan_p theChan = fut0->chan[i]; if ((imask & FUT_BIT(i)) == 0) { continue; /* this output from fut0 not required */ } indat[i] = theChan->gtbl->refTbl; /* collect gtbls: the input data for the evaluation */ ok = (indat[i] != NULL); /* allocate memory for composed i/o tables * these have the same size as the output tables of the channel supplying the input */ if (ok) { fut_itbl_p theITbl = fut1->itbl[i]; fut_otbl_p theOTbl = theChan->otbl; oitbls[i] = fut_alloc_itbl (); /* get an itbl */ oitbls[i]->size = theITbl->size; oitbls[i]->dataClass = KCP_FIXED_RANGE; nEntries = MAX(theITbl->refTblEntries, theOTbl->refTblEntries); ok = (fut_alloc_imftdat (oitbls[i], nEntries) != NULL); if (ok) { /* make input table for evaluation */ ok = fut_comp_iotblMF (theITbl, theOTbl, oitbls[i]); } } } } /* make an evaluation fut with the composed I/O tables, fut1's gtbls, and no otbls */ evalFut = fut_new (iomask, oitbls, fut1_gtbls, NULL); if (( ! ok) || (evalFut == NULL) || /* if evaluation fut ok */ (fut_to_mft (fut2) != 1)) { /* make sure the futs are in the reference state */ ok = 0; goto GetOut; } else { /* Finally, we are ready to pass fut0's grid tables through fut1 */ for (i = 0, nOutChans = 0; (i < FUT_NOCHAN) && ok; i++) { if ((evalomask & FUT_BIT(i)) != 0) { fut_gtbl_p gtbl; gtbl = fut2->chan[i]->gtbl; nGridPoints = gtbl->tbl_size / sizeof (fut_gtbldat_t); /* grid points for eval */ if (evalFut->iomask.in != evalFut->chan[i]->imask) { /* must evaluate this channel singly */ evalomask &= ~FUT_BIT(i); /* remove channel from multiple eval list */ ok = evaluateFut (evalFut, FUT_BIT(i), KCM_USHORT, nGridPoints, (KpGenericPtr_t FAR*) indat, (KpGenericPtr_t FAR*) &(gtbl->refTbl)); } else { outdat[nOutChans] = gtbl->refTbl; nOutChans++; } } } /* eval result is composed fut's gtbls */ ok = evaluateFut (evalFut, evalomask, KCM_USHORT, nGridPoints, (KpGenericPtr_t FAR*) indat, (KpGenericPtr_t FAR*) outdat); } GetOut: /* must always free up the evaluation fut and io tables, even if an error occurred! */ fut_free (evalFut); fut_free_tbls (FUT_NICHAN, (void *)oitbls); /* check for errors */ if ( !ok ) { fut_free (fut2); fut2 = NULL; } return (fut2); }
/* fut_copy copies an existing fut. */ fut_p fut_copy (fut_p fut) { fut_p new_fut; KpInt32_t i; KpHandle_t h; if ( ! IS_FUT(fut)) { return (0); } /* allocate basic fut_structure */ new_fut = fut_alloc_fut (); if ( new_fut == FUT_NULL ) { return (FUT_NULL); } /* save handle before copying over old fut */ h = new_fut->handle; /* copy over all data (including pointers */ *new_fut = *fut; /* now copy back handle */ new_fut->handle = h; /* copy id string */ new_fut->idstr = 0; /* (void) fut_set_idstr (new_fut, fut->idstr); */ /* copy input tables */ for ( i=0; i<FUT_NICHAN; i++ ) { new_fut->itbl[i] = (IS_SHARED (fut->itbl[i])) ? fut_share_itbl (fut->itbl[i]) : fut_copy_itbl (fut->itbl[i]); new_fut->itblHandle[i] = getHandleFromPtr((KpGenericPtr_t)new_fut->itbl[i]); } /* copy output channels */ for ( i=0; i<FUT_NOCHAN; i++ ) { new_fut->chan[i] = fut_copy_chan (fut->chan[i]); new_fut->chanHandle[i] = getHandleFromPtr((KpGenericPtr_t)new_fut->chan[i]); } /* now check that all copies were succesful */ if ( new_fut->idstr == 0 && fut->idstr != 0 ) { goto ErrOut; } for ( i=0; i<FUT_NICHAN; i++ ) { if ( new_fut->itbl[i] == 0 && fut->itbl[i] != 0) { goto ErrOut; } } for ( i=0; i<FUT_NOCHAN; i++ ) { if ( new_fut->chan[i] == 0 && fut->chan[i] != 0) { goto ErrOut; } } for ( i=0; i<FUT_NMCHAN; i++ ) { /* free extra reference tables */ if (NULL != fut->mabInRefTblHandles[i]) { new_fut->mabInTblEntries[i] = fut->mabInTblEntries[i]; new_fut->mabInRefTbl[i] = (mf2_tbldat_p) allocBufferPtr (new_fut->mabInTblEntries[i] * sizeof (mf2_tbldat_t)); KpMemCpy (new_fut->mabInRefTbl[i], fut->mabInRefTbl[i], new_fut->mabInTblEntries[i] * sizeof (mf2_tbldat_t)); new_fut->mabInRefTblHandles[i] = getHandleFromPtr ((KpGenericPtr_t)new_fut->mabInRefTbl[i]); } if (NULL != fut->mabOutRefTblHandles[i]) { new_fut->mabOutTblEntries[i] = fut->mabOutTblEntries[i]; new_fut->mabOutRefTbl[i] = (mf2_tbldat_p) allocBufferPtr (new_fut->mabOutTblEntries[i] * sizeof (mf2_tbldat_t)); KpMemCpy (new_fut->mabOutRefTbl[i], fut->mabOutRefTbl[i], new_fut->mabOutTblEntries[i] * sizeof (mf2_tbldat_t)); new_fut->mabOutRefTblHandles[i] = getHandleFromPtr ((KpGenericPtr_t)new_fut->mabOutRefTbl[i]); } } return (new_fut); ErrOut: fut_free (new_fut); return (FUT_NULL); }
/* frees source fut on error */ PTErr_t fut2PT (fut_p *futSrc, KpInt32_t inSpace, KpInt32_t outSpace, KpInt32_t srcFormat, PTRefNum_p PTRefNumNew) { PTErr_t PTErr; fut_hdr_p PTHdr = NULL; KpHandle_t PTHdrH = NULL, PTDataH = NULL; KpChar_t colorSpaceAttr[20]; *PTRefNumNew = 0; if ( ! IS_FUT(*futSrc)) goto ErrOut1; PTHdr = allocBufferPtr (sizeof(fut_hdr_t)); /* get buffer for resultant info header */ if (PTHdr == NULL) { goto ErrOut4; } if (!fut_io_encode (*futSrc, PTHdr)) { /* make the info header */ goto ErrOut3; } PTHdr->srcFormat = srcFormat; PTDataH = fut_unlock_fut (*futSrc); if (PTDataH == NULL) { goto ErrOut2; } *futSrc = NULL; PTHdrH = unlockBufferPtr (PTHdr); /* unlock the header buffer */ if (PTHdrH == NULL) { goto ErrOut2; } PTHdr = NULL; PTErr = registerPT (PTHdrH, NULL, PTRefNumNew); /* enter PT into list */ if (PTErr != KCP_SUCCESS) { goto ErrOut0; } makeActive (*PTRefNumNew, PTDataH); /* activate the new PT */ if (inSpace != -1) { /* set the input color space attribute */ KpItoa (inSpace, colorSpaceAttr); PTErr = PTSetAttribute (*PTRefNumNew, KCM_IN_SPACE, colorSpaceAttr); } if (outSpace != -1) { /* set the output color space attribute */ KpItoa (outSpace, colorSpaceAttr); PTErr = PTSetAttribute (*PTRefNumNew, KCM_OUT_SPACE, colorSpaceAttr); } if (PTErr != KCP_SUCCESS) { goto ErrOut0; } getOut: return PTErr; ErrOut4: PTErr = KCP_NO_CHECKIN_MEM; goto ErrOut0; ErrOut3: PTErr = KCP_ENCODE_PTHDR_ERR; goto ErrOut0; ErrOut2: PTErr = KCP_MEM_UNLOCK_ERR; goto ErrOut0; ErrOut1: PTErr = KCP_BAD_ARG; ErrOut0: if (PTDataH != NULL) { *futSrc = fut_lock_fut (PTDataH); } if (*futSrc != FUT_NULL) fut_free (*futSrc); if (PTHdr != NULL) freeBufferPtr (PTHdr); if (PTHdrH != NULL) freeBuffer (PTHdrH); if (*PTRefNumNew != 0) PTCheckOut (*PTRefNumNew); goto getOut; }