/*! * \ingroup WlzValuesUtils * \brief Convert a RGBA image to a compound object. The RGBA * channels are at array indices 0,1,2,3 respectively * and the sub-object grey types will be WLZ_GREY_UBYTE. * * \return Compound array of rgba values * \param obj Input domain object with value type * WLZ_GREY_RGBA * \param colSpc The colour space. * \param dstErr Destination error ponyer, may be NULL. */ WlzCompoundArray *WlzRGBAToCompound( WlzObject *obj, WlzRGBAColorSpace colSpc, WlzErrorNum *dstErr) { WlzCompoundArray *cobj=NULL; WlzErrorNum errNum=WLZ_ERR_NONE; /* check object type, and value type */ if( obj ){ switch( obj->type ){ case WLZ_2D_DOMAINOBJ: if( obj->domain.core == NULL ){ errNum = WLZ_ERR_DOMAIN_NULL; } else if ( obj->values.core == NULL ){ errNum = WLZ_ERR_VALUES_NULL; } else if( WlzGreyTypeFromObj(obj, &errNum) != WLZ_GREY_RGBA ){ errNum = WLZ_ERR_VALUES_TYPE; } break; case WLZ_3D_DOMAINOBJ: if( obj->domain.core == NULL ){ errNum = WLZ_ERR_DOMAIN_NULL; } else if( obj->domain.p->type != WLZ_PLANEDOMAIN_DOMAIN ){ errNum = WLZ_ERR_DOMAIN_TYPE; } else if ( obj->values.core == NULL ){ errNum = WLZ_ERR_VALUES_NULL; } else if( obj->values.vox->type != WLZ_VOXELVALUETABLE_GREY ){ errNum = WLZ_ERR_VALUES_TYPE; } else if( WlzGreyTypeFromObj(obj, &errNum) != WLZ_GREY_RGBA ){ errNum = WLZ_ERR_VALUES_TYPE; } return WlzRGBAToCompound3D(obj, colSpc, dstErr); case WLZ_TRANS_OBJ: /* not difficult, do it later */ errNum = WLZ_ERR_OBJECT_TYPE; break; case WLZ_COMPOUND_ARR_1: case WLZ_COMPOUND_ARR_2: /* bit recursive this ! */ errNum = WLZ_ERR_OBJECT_TYPE; break; case WLZ_EMPTY_OBJ: return (WlzCompoundArray *) WlzMakeEmpty(dstErr); default: errNum = WLZ_ERR_OBJECT_TYPE; } } else { errNum = WLZ_ERR_OBJECT_NULL; } /* check colour space */ if( errNum == WLZ_ERR_NONE ){ switch( colSpc ){ case WLZ_RGBA_SPACE_RGB: case WLZ_RGBA_SPACE_HSB: case WLZ_RGBA_SPACE_CMY: break; default: errNum = WLZ_ERR_PARAM_DATA; break; } } /* create compound object return */ if( errNum == WLZ_ERR_NONE ){ WlzValues values; WlzObject *objs[4]; WlzObjectType type; WlzPixelV oldBck, newBck; type = WlzGreyTableType( WlzGreyTableTypeToTableType(obj->values.core->type, &errNum), WLZ_GREY_UBYTE, &errNum); oldBck = WlzGetBackground(obj, &errNum); /* red */ newBck.type = WLZ_GREY_UBYTE; newBck.v.ubv = (WlzUByte )WLZ_RGBA_RED_GET(oldBck.v.rgbv); values.v = WlzNewValueTb(obj, type, newBck, &errNum); objs[0] = WlzMakeMain(obj->type, obj->domain, values, NULL, NULL, &errNum); /* green */ newBck.v.ubv = (WlzUByte )WLZ_RGBA_GREEN_GET(oldBck.v.rgbv); values.v = WlzNewValueTb(obj, type, newBck, &errNum); objs[1] = WlzMakeMain(obj->type, obj->domain, values, NULL, NULL, &errNum); /* blue */ newBck.v.ubv = (WlzUByte )WLZ_RGBA_BLUE_GET(oldBck.v.rgbv); values.v = WlzNewValueTb(obj, type, newBck, &errNum); objs[2] = WlzMakeMain(obj->type, obj->domain, values, NULL, NULL, &errNum); /* alpha */ newBck.v.ubv = (WlzUByte )WLZ_RGBA_ALPHA_GET(oldBck.v.rgbv); values.v = WlzNewValueTb(obj, type, newBck, &errNum); objs[3] = WlzMakeMain(obj->type, obj->domain, values, NULL, NULL, &errNum); /* create compound object, object pointers are assigned for mode=3 so no need to free objects */ cobj = WlzMakeCompoundArray(WLZ_COMPOUND_ARR_1, 3, 4, &(objs[0]), obj->type, &errNum); } /* iterate through objects setting values */ if( errNum == WLZ_ERR_NONE ){ WlzIntervalWSpace iwsp0, iwsp[4]; WlzGreyWSpace gwsp0, gwsp[4]; int i, j, k; int a, col[3]; errNum = WlzInitGreyScan(obj, &iwsp0, &gwsp0); for(i=0; i < 4; i++){ errNum = WlzInitGreyScan(cobj->o[i], &(iwsp[i]), &(gwsp[i])); } while((errNum == WLZ_ERR_NONE) && ((errNum = WlzNextGreyInterval(&iwsp0)) == WLZ_ERR_NONE)){ for(i=0; i < 4; i++){ errNum = WlzNextGreyInterval(&(iwsp[i])); } switch( colSpc ){ case WLZ_RGBA_SPACE_RGB: for(j=0, k=iwsp0.lftpos; k <= iwsp0.rgtpos; j++, k++, gwsp0.u_grintptr.rgbp++){ *(gwsp[0].u_grintptr.ubp++) = (WlzUByte )WLZ_RGBA_RED_GET(*(gwsp0.u_grintptr.rgbp)); *(gwsp[1].u_grintptr.ubp++) = (WlzUByte )WLZ_RGBA_GREEN_GET(*(gwsp0.u_grintptr.rgbp)); *(gwsp[2].u_grintptr.ubp++) = (WlzUByte )WLZ_RGBA_BLUE_GET(*(gwsp0.u_grintptr.rgbp)); *(gwsp[3].u_grintptr.ubp++) = (WlzUByte )WLZ_RGBA_ALPHA_GET(*(gwsp0.u_grintptr.rgbp)); } break; case WLZ_RGBA_SPACE_HSB: /* each normalised to [0,255] */ for(j=0, k=iwsp0.lftpos; k <= iwsp0.rgtpos; j++, k++, gwsp0.u_grintptr.rgbp++){ col[0] = WLZ_RGBA_RED_GET(*(gwsp0.u_grintptr.rgbp)); col[1] = WLZ_RGBA_GREEN_GET(*(gwsp0.u_grintptr.rgbp)); col[2] = WLZ_RGBA_BLUE_GET(*(gwsp0.u_grintptr.rgbp)); a = WLZ_RGBA_ALPHA_GET(*(gwsp0.u_grintptr.rgbp)); WlzRGBAConvertRGBToHSV_UBYTENormalised(col); *(gwsp[0].u_grintptr.ubp++) = (WlzUByte )(col[0]); *(gwsp[1].u_grintptr.ubp++) = (WlzUByte )(col[1]); *(gwsp[2].u_grintptr.ubp++) = (WlzUByte )(col[2]); *(gwsp[3].u_grintptr.ubp++) = (WlzUByte )a; } break; case WLZ_RGBA_SPACE_CMY: for(j=0, k=iwsp0.lftpos; k <= iwsp0.rgtpos; j++, k++, gwsp0.u_grintptr.rgbp++){ col[0] = WLZ_RGBA_RED_GET(*(gwsp0.u_grintptr.rgbp)); col[1] = WLZ_RGBA_GREEN_GET(*(gwsp0.u_grintptr.rgbp)); col[2] = WLZ_RGBA_BLUE_GET(*(gwsp0.u_grintptr.rgbp)); a = WLZ_RGBA_ALPHA_GET(*(gwsp0.u_grintptr.rgbp)); *(gwsp[0].u_grintptr.ubp++) = (WlzUByte )((col[1] + col[2]) / 2); *(gwsp[1].u_grintptr.ubp++) = (WlzUByte )((col[2] + col[0]) / 2); *(gwsp[2].u_grintptr.ubp++) = (WlzUByte )((col[0] + col[1]) / 2); *(gwsp[3].u_grintptr.ubp++) = (WlzUByte )a; } break; default: errNum = WLZ_ERR_GREY_TYPE; break; } } if( errNum == WLZ_ERR_EOO ){ errNum = WLZ_ERR_NONE; } } if( dstErr ){ *dstErr = errNum; } return cobj; }
/*! * \ingroup WlzValuesFilters * \brief Set new grey-range by simple linear interpolation. It assumes that the min and max values enclose the true range of grey-values in the object. Failure to check this could result in a segmentation fault. The transform function is: \f[g' = \frac{(gMax - gMin)}{(gmax - gmin)} (g - gmin) + gMin + \delta \f] Here \f$\delta\f$ is the dither value. * * \return Woolz error number * \param obj Input grey-level object whose values are to be reset. * \param min Initial minimum value * \param max Initial maximum value * \param Min Final minimum value * \param Max Final maximum value * \param Dither values if destination range is greater than source range * and this flag is non-zero. * \par Source: * WlzGreySetRange.c */ WlzErrorNum WlzGreySetRange( WlzObject *obj, WlzPixelV min, WlzPixelV max, WlzPixelV Min, WlzPixelV Max, int dither) { double gMin = 0.0, gMax = 0.0, sigma = 0.0, factor, val; WlzIntervalWSpace iwsp; WlzGreyWSpace gwsp; WlzGreyP gptr; WlzObject *tempobj; WlzValues *values; WlzDomain *domains; int i, j, nplanes; WlzErrorNum errNum = WLZ_ERR_NONE; /* check object */ if( obj == NULL ){ errNum = WLZ_ERR_OBJECT_NULL; } if( errNum == WLZ_ERR_NONE ){ switch( obj->type ){ case WLZ_2D_DOMAINOBJ: if( obj->domain.i == NULL ){ return WLZ_ERR_DOMAIN_NULL; } if( obj->values.core == NULL ){ return WLZ_ERR_VALUES_NULL; } if( WlzGreyTableIsTiled(obj->values.core->type) ){ return WLZ_ERR_VALUES_TYPE; } break; case WLZ_3D_DOMAINOBJ: /* check planedomain and voxeltable */ if( obj->domain.p == NULL ){ return WLZ_ERR_DOMAIN_NULL; } if( obj->domain.p->type != WLZ_PLANEDOMAIN_DOMAIN ){ return WLZ_ERR_PLANEDOMAIN_TYPE; } if( obj->values.vox == NULL ){ return WLZ_ERR_VALUES_NULL; } if( obj->values.vox->type != WLZ_VOXELVALUETABLE_GREY ){ return WLZ_ERR_VOXELVALUES_TYPE; } /* set range of each plane if non-empty - indicated by NULL */ domains = obj->domain.p->domains; values = obj->values.vox->values; nplanes = obj->domain.p->lastpl - obj->domain.p->plane1 + 1; for(i=0; i < nplanes; i++, domains++, values++){ if( (*domains).core == NULL || (*values).core == NULL ){ continue; } tempobj = WlzMakeMain(WLZ_2D_DOMAINOBJ, *domains, *values, NULL, NULL, &errNum); if((tempobj == NULL) && (errNum == WLZ_ERR_NONE) ){ errNum = WLZ_ERR_UNSPECIFIED; break; } errNum = WlzGreySetRange(tempobj, min, max, Min, Max, dither); WlzFreeObj( tempobj ); if( errNum != WLZ_ERR_NONE ){ break; } } return errNum; case WLZ_TRANS_OBJ: return WlzGreySetRange(obj->values.obj, min, max, Min, Max, dither); case WLZ_EMPTY_OBJ: return errNum; default: errNum = WLZ_ERR_OBJECT_TYPE; break; } } if( errNum == WLZ_ERR_NONE ){ /* get conversion function - should use LUT use 4 LUTS for rgb type since bounded */ if( WlzGreyTypeFromObj(obj, &errNum) == WLZ_GREY_RGBA ){ WlzUByte rgbaLut[4][256]; WlzUInt rgbamin[4], rgbaMin[4]; double rgbaFactor[4], val1; WlzUInt red, green, blue, alpha; rgbamin[0] = WLZ_RGBA_RED_GET(min.v.rgbv); rgbaMin[0] = WLZ_RGBA_RED_GET(Min.v.rgbv); if(WLZ_RGBA_RED_GET(max.v.rgbv) > WLZ_RGBA_RED_GET(min.v.rgbv)){ rgbaFactor[0] = (((double) WLZ_RGBA_RED_GET(Max.v.rgbv) - WLZ_RGBA_RED_GET(Min.v.rgbv))/ (WLZ_RGBA_RED_GET(max.v.rgbv) - WLZ_RGBA_RED_GET(min.v.rgbv))); } else { rgbaFactor[0] = 0.0; } rgbamin[1] = WLZ_RGBA_GREEN_GET(min.v.rgbv); rgbaMin[1] = WLZ_RGBA_GREEN_GET(Min.v.rgbv); if(WLZ_RGBA_GREEN_GET(max.v.rgbv) > WLZ_RGBA_GREEN_GET(min.v.rgbv)){ rgbaFactor[1] = (((double) WLZ_RGBA_GREEN_GET(Max.v.rgbv) - WLZ_RGBA_GREEN_GET(Min.v.rgbv))/ (WLZ_RGBA_GREEN_GET(max.v.rgbv) - WLZ_RGBA_GREEN_GET(min.v.rgbv))); } else { rgbaFactor[1] = 0.0; } rgbamin[2] = WLZ_RGBA_BLUE_GET(min.v.rgbv); rgbaMin[2] = WLZ_RGBA_BLUE_GET(Min.v.rgbv); if(WLZ_RGBA_BLUE_GET(max.v.rgbv) > WLZ_RGBA_BLUE_GET(min.v.rgbv)){ rgbaFactor[2] = (((double) WLZ_RGBA_BLUE_GET(Max.v.rgbv) - WLZ_RGBA_BLUE_GET(Min.v.rgbv))/ (WLZ_RGBA_BLUE_GET(max.v.rgbv) - WLZ_RGBA_BLUE_GET(min.v.rgbv))); } else { rgbaFactor[2] = 0.0; } rgbamin[3] = WLZ_RGBA_ALPHA_GET(min.v.rgbv); rgbaMin[3] = WLZ_RGBA_ALPHA_GET(Min.v.rgbv); if(WLZ_RGBA_ALPHA_GET(max.v.rgbv) > WLZ_RGBA_ALPHA_GET(min.v.rgbv)){ rgbaFactor[3] = (((double) WLZ_RGBA_ALPHA_GET(Max.v.rgbv) - WLZ_RGBA_ALPHA_GET(Min.v.rgbv))/ (WLZ_RGBA_ALPHA_GET(max.v.rgbv) - WLZ_RGBA_ALPHA_GET(min.v.rgbv))); } else { rgbaFactor[3] = 0.0; } /* now set up the LUTS */ for(i=0; i < 4; i++){ for(j=0; j < 256; j++){ val1 = rgbaFactor[i] * (j - rgbamin[i]) + rgbaMin[i]; rgbaLut[i][j] = (WlzUByte )WLZ_CLAMP(val1, 0, 255); } } /* set values - can assume rgba grey-type */ errNum = WlzInitGreyScan(obj, &iwsp, &gwsp); if(errNum == WLZ_ERR_NONE) { while( WlzNextGreyInterval(&iwsp) == WLZ_ERR_NONE ){ gptr = gwsp.u_grintptr; for (i=0; i<iwsp.colrmn; i++, gptr.rgbp++){ red = rgbaLut[0][WLZ_RGBA_RED_GET(*gptr.rgbp)]; green = rgbaLut[0][WLZ_RGBA_GREEN_GET(*gptr.rgbp)]; blue = rgbaLut[0][WLZ_RGBA_BLUE_GET(*gptr.rgbp)]; alpha = rgbaLut[0][WLZ_RGBA_ALPHA_GET(*gptr.rgbp)]; WLZ_RGBA_RGBA_SET(*gptr.rgbp, red, green, blue, alpha); } } (void )WlzEndGreyScan(&iwsp, &gwsp); if(errNum == WLZ_ERR_EOO){ errNum = WLZ_ERR_NONE; } } } else { WlzValueConvertPixel(&min, min, WLZ_GREY_DOUBLE); WlzValueConvertPixel(&max, max, WLZ_GREY_DOUBLE); WlzValueConvertPixel(&Min, Min, WLZ_GREY_DOUBLE); WlzValueConvertPixel(&Max, Max, WLZ_GREY_DOUBLE); if( fabs(max.v.dbv - min.v.dbv) < DBL_EPSILON ){ return WLZ_ERR_FLOAT_DATA; } errNum = WlzInitGreyScan(obj, &iwsp, &gwsp); if(errNum == WLZ_ERR_NONE) { factor = (Max.v.dbv - Min.v.dbv) / (max.v.dbv - min.v.dbv); if(dither) { if(fabs(factor) < 1.0 + DBL_EPSILON) { dither = 0; } else { sigma = fabs(2.0 / factor); AlgRandSeed(101); switch(gwsp.pixeltype) { case WLZ_GREY_INT: gMin = ALG_MAX(Min.v.dbv, INT_MIN); gMax = ALG_MIN(Max.v.dbv, INT_MAX); break; case WLZ_GREY_SHORT: gMin = ALG_MAX(Min.v.dbv, SHRT_MIN); gMax = ALG_MIN(Max.v.dbv, SHRT_MAX); break; case WLZ_GREY_UBYTE: gMin = ALG_MAX(Min.v.dbv, 0); gMax = ALG_MIN(Max.v.dbv, 255); break; case WLZ_GREY_FLOAT: gMin = ALG_MAX(Min.v.dbv, FLT_MIN); gMax = ALG_MIN(Max.v.dbv, FLT_MAX); break; case WLZ_GREY_DOUBLE: gMin = Min.v.dbv; gMax = Max.v.dbv; break; default: break; } } } while((errNum == WLZ_ERR_NONE) && ((errNum = WlzNextGreyInterval(&iwsp)) == WLZ_ERR_NONE)){ gptr = gwsp.u_grintptr; switch (gwsp.pixeltype) { case WLZ_GREY_INT: for (i=0; i<iwsp.colrmn; i++, gptr.inp++){ if(dither){ val = factor * (*gptr.inp + AlgRandZigNormal(0.0, sigma) - min.v.dbv) + Min.v.dbv; val = WLZ_CLAMP(val, gMin, gMax); } else { val = factor * (*gptr.inp - min.v.dbv) + Min.v.dbv; } *gptr.inp = WLZ_NINT(val); } break; case WLZ_GREY_SHORT: for (i=0; i<iwsp.colrmn; i++, gptr.shp++){ if(dither){ val = factor * (*gptr.shp + AlgRandZigNormal(0.0, sigma) - min.v.dbv) + Min.v.dbv; val = WLZ_CLAMP(val, gMin, gMax); } else { val = factor * (*gptr.shp - min.v.dbv) + Min.v.dbv; } *gptr.shp = (short )WLZ_NINT(val); } break; case WLZ_GREY_UBYTE: for (i=0; i<iwsp.colrmn; i++, gptr.ubp++){ if(dither){ val = factor * (*gptr.ubp + AlgRandZigNormal(0.0, sigma) - min.v.dbv) + Min.v.dbv; val = WLZ_CLAMP(val, gMin, gMax); } else { val = factor * (*gptr.ubp - min.v.dbv) + Min.v.dbv; } *gptr.ubp = (WlzUByte )WLZ_NINT(val); } break; case WLZ_GREY_FLOAT: for (i=0; i<iwsp.colrmn; i++, gptr.flp++){ if(dither){ val = factor * (*gptr.flp + AlgRandZigNormal(0.0, sigma) - min.v.dbv) + Min.v.dbv; val = WLZ_CLAMP(val, gMin, gMax); } else { val = factor * (*gptr.flp - min.v.dbv) + Min.v.dbv; } *gptr.flp = (float )val; } break; case WLZ_GREY_DOUBLE: for (i=0; i<iwsp.colrmn; i++, gptr.dbp++){ if(dither){ val = factor * (*gptr.dbp + AlgRandZigNormal(0.0, sigma) - min.v.dbv) + Min.v.dbv; val = WLZ_CLAMP(val, gMin, gMax); } else { val = factor * (*gptr.dbp - min.v.dbv) + Min.v.dbv; } *gptr.dbp = val; } break; default: errNum = WLZ_ERR_GREY_TYPE; break; } } (void )WlzEndGreyScan(&iwsp, &gwsp); if(errNum == WLZ_ERR_EOO){ errNum = WLZ_ERR_NONE; } } } } return errNum; }
WlzErrorNum WlzGreyScalarDivValue( WlzObject *obj, WlzPixelV val) { WlzObject *tmpObj; WlzIntervalWSpace iwsp; WlzGreyWSpace gwsp; WlzGreyP gptr; WlzPixelV tmpVal; WlzDomain *domains; WlzValues *values; int i, nplanes; int red = 0, green = 0, blue = 0, alpha = 0; WlzErrorNum errNum=WLZ_ERR_NONE; /* check object */ if( obj == NULL ){ errNum = WLZ_ERR_OBJECT_NULL; } else { switch( obj->type ){ case WLZ_2D_DOMAINOBJ: if( obj->domain.i == NULL ){ errNum = WLZ_ERR_DOMAIN_NULL; } else if( obj->values.v == NULL ){ errNum = WLZ_ERR_VALUES_NULL; } break; case WLZ_3D_DOMAINOBJ: /* check planedomain and voxeltable */ if( obj->domain.p == NULL ){ errNum = WLZ_ERR_DOMAIN_NULL; } else if( obj->domain.p->type != WLZ_PLANEDOMAIN_DOMAIN ){ errNum = WLZ_ERR_DOMAIN_TYPE; } else if( obj->values.vox == NULL ){ errNum = WLZ_ERR_VALUES_NULL; } else if( obj->values.vox->type != WLZ_VOXELVALUETABLE_GREY ){ errNum = WLZ_ERR_VALUES_TYPE; } else { /* set range of each plane if non-empty - indicated by NULL */ domains = obj->domain.p->domains; values = obj->values.vox->values; nplanes = obj->domain.p->lastpl - obj->domain.p->plane1 + 1; for(i=0; (errNum == WLZ_ERR_NONE) && (i < nplanes); i++, domains++, values++){ if( (*domains).core == NULL || (*values).core == NULL ){ continue; } if((tmpObj = WlzMakeMain(WLZ_2D_DOMAINOBJ, *domains, *values, NULL, NULL, NULL)) != NULL){ errNum = WlzGreyScalarDivValue(tmpObj, val); WlzFreeObj( tmpObj ); } } } return errNum; case WLZ_TRANS_OBJ: return WlzGreyScalarDivValue(obj->values.obj, val); case WLZ_EMPTY_OBJ: return errNum; default: errNum = WLZ_ERR_OBJECT_TYPE; break; } } if( errNum == WLZ_ERR_NONE ){ errNum = WlzInitGreyScan(obj, &iwsp, &gwsp); WlzValueConvertPixel(&tmpVal, val, WLZ_GREY_DOUBLE); while( (errNum = WlzNextGreyInterval(&iwsp)) == WLZ_ERR_NONE ){ gptr = gwsp.u_grintptr; switch (gwsp.pixeltype) { case WLZ_GREY_INT: for (i=0; i<iwsp.colrmn; i++, gptr.inp++) *gptr.inp /= tmpVal.v.dbv; break; case WLZ_GREY_SHORT: for (i=0; i<iwsp.colrmn; i++, gptr.shp++) *gptr.shp /= tmpVal.v.dbv; break; case WLZ_GREY_UBYTE: for (i=0; i<iwsp.colrmn; i++, gptr.ubp++) *gptr.ubp /= tmpVal.v.dbv; break; case WLZ_GREY_FLOAT: for (i=0; i<iwsp.colrmn; i++, gptr.flp++) *gptr.flp /= tmpVal.v.dbv; break; case WLZ_GREY_DOUBLE: for (i=0; i<iwsp.colrmn; i++, gptr.dbp++) *gptr.dbp /= tmpVal.v.dbv; break; case WLZ_GREY_RGBA: for (i=0; i<iwsp.colrmn; i++, gptr.rgbp++) red = WLZ_RGBA_RED_GET(*gptr.rgbp) / tmpVal.v.dbv; green = WLZ_RGBA_GREEN_GET(*gptr.rgbp) / tmpVal.v.dbv; blue = WLZ_RGBA_BLUE_GET(*gptr.rgbp) / tmpVal.v.dbv; alpha = WLZ_RGBA_ALPHA_GET(*gptr.rgbp); red = WLZ_CLAMP(red, 0, 255); green = WLZ_CLAMP(red, 0, 255); blue = WLZ_CLAMP(red, 0, 255); WLZ_RGBA_RGBA_SET(*gptr.rgbp, red, green, blue, alpha); break; default: errNum = WLZ_ERR_GREY_TYPE; break; } } if( errNum == WLZ_ERR_EOO ){ errNum = WLZ_ERR_NONE; } } return errNum; }