static void no_interpolation(const ImageData *image, DBL xcoor, DBL ycoor, RGBFTColour& colour, int *index, bool premul) { int iycoor, ixcoor; if(image->Once_Flag) { // image is to be seen only once, so when taking samples for interpolation // coordinates should not wrap around; instead, take the samples from the nearest // pixel right at the edge of the image if(xcoor < 0.0) ixcoor = 0; else if(xcoor >= (DBL)image->iwidth) ixcoor = image->iwidth - 1; else ixcoor = (int)xcoor; if(ycoor < 0.0) iycoor = 0; else if(ycoor >= (DBL)image->iheight) iycoor = image->iheight - 1; else iycoor = (int)ycoor; } else { // image is to be repeated, so when taking samples for interpolation // have coordinates wrap around ixcoor = (int)wrap(xcoor, (DBL)image->iwidth); iycoor = (int)wrap(ycoor, (DBL)image->iheight); } image->data->GetRGBFTValue(ixcoor, iycoor, colour, premul); if(image->data->IsIndexed() == false) { *index = -1; if (image->AllTransmitLegacyMode) { // Legacy versions applied "transmit/filter all" before interpolation, // and with little respect to an image's inherent alpha information. colour.transm() += image->AllTransmit; colour.filter() += image->AllFilter; } } else *index = image->data->GetIndexedValue(ixcoor, iycoor); }
DBL image_pattern(const Vector3d& EPoint, const BasicPattern* pPattern) { DBL xcoor = 0.0, ycoor = 0.0; int index = -1; RGBFTColour colour; const ImageData *image = dynamic_cast<const ImagePatternImpl*>(pPattern)->pImage; DBL Value; colour.Clear(); // going to have to change this // need to know if bump point is off of image for all 3 points if(map_pos(EPoint, pPattern, &xcoor, &ycoor)) return 0.0; else image_colour_at(image, xcoor, ycoor, colour, &index); // TODO ALPHA - we should decide whether we prefer premultiplied or non-premultiplied alpha if((index == -1) || image->Use) { if(image->Use == USE_ALPHA) { // use alpha channel or red channel if(image->data->HasTransparency() == true) Value = colour.transm(); else Value = colour.red(); // otherwise, just use the red channel } else // use grey-scaled version of the color Value = colour.Greyscale(); } else Value = index / 255.0; if(Value < 0) Value = 0; else if(Value > 1.0) Value = 1.0; return Value; }
void image_colour_at(const ImageData *image, DBL xcoor, DBL ycoor, RGBFTColour& colour, int *index, bool premul) { *index = -1; bool doProperTransmitAll = image->data->HasTransparency() && !image->AllTransmitLegacyMode && !image->data->IsIndexed() && ( (image->AllTransmit != 0.0) || (image->AllFilter != 0.0) ); // If either source or destination uses premultiplied alpha, make sure interpolation is done in premultiplied space // as it makes the mathematical operations cleaner -- unless the alpha channel is modulated by "transmit all" or // "filter all", in which case we prefer non-premultiplied space. bool getPremul = doProperTransmitAll ? (premul && image->data->IsPremultiplied()) : (premul || image->data->IsPremultiplied()); switch(image->Interpolation_Type) { case NO_INTERPOLATION: no_interpolation(image, xcoor, ycoor, colour, index, getPremul); break; case BICUBIC: InterpolateBicubic(image, xcoor, ycoor, colour, index, getPremul); break; default: Interp(image, xcoor, ycoor, colour, index, getPremul); break; } bool havePremul = getPremul; if (!premul && havePremul) { // We fetched premultiplied data, but caller expects it non-premultiplied, so we need to fix that. // As "transmit/filter all" handling also works best on non-premultiplied data, we're doing this now. AlphaUnPremultiply(colour.rgb(), colour.FTtoA()); havePremul = false; } if (doProperTransmitAll) { COLC imageAlpha = colour.FTtoA(); if (imageAlpha != 0.0) // No need to apply "filter/transmit all" if the image is fully transparent here anyway. { colour.transm() += image->AllTransmit * imageAlpha; colour.filter() += image->AllFilter * imageAlpha; if (havePremul) { // We have premultiplied data here, and the caller expects it to stay that way (otherwise we'd already // have converted to non-premultiplied by now), so we need to fix the premultiplication of the colour // according to our modifications to the transparency components. COLC alphaCorrection = colour.FTtoA() / imageAlpha; AlphaPremultiply(colour.rgb(), alphaCorrection); } } } if (premul && !havePremul) { // We have non-premultiplied data here, but caller expects it premultiplied, so we need to fix that // As "transmit/filter all" handling works best on non-premultiplied data, we haven't done this earlier. AlphaPremultiply(colour.rgb(), colour.FTtoA()); } }