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); }
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()); } }