diff -r 000000000000 -r 5d03bc08d59c graphicscomposition/openwfcompositionengine/common/src/owfimage.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graphicscomposition/openwfcompositionengine/common/src/owfimage.c Tue Feb 02 01:47:50 2010 +0200 @@ -0,0 +1,1936 @@ +/* Copyright (c) 2009 The Khronos Group Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and/or associated documentation files (the + * "Materials"), to deal in the Materials without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Materials, and to + * permit persons to whom the Materials are furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Materials. + * + * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. + */ + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include +#include +#include +#include + +#include "owfobject.h" +#include "owfimage.h" +#include "owfutils.h" +#include "owfmemory.h" +#include "owfdebug.h" +#include "owfdisplaycontextgeneral.h" + +#ifdef OWF_IMAGE_INTERNAL_PIXEL_IS_FLOAT +#define roundSubPixel(p) ((OWFuint32)((p) + 0.5f)) +#else +#define roundSubPixel(p) (p) +#endif + + +/*----------------------------------------------------------------------------*/ +OWF_API_CALL void +OWF_IMAGE_Ctor(void* self) +{ + self = self; +} + +/*----------------------------------------------------------------------------*/ +OWF_API_CALL void +OWF_IMAGE_Dtor(void* self) +{ + OWF_IMAGE* image; + + image = (OWF_IMAGE*)self; + + if (image && image->data) + { + if (!image->foreign) + { + OWF_Image_FreeData(0, &image->data); + } + } + + if (image) + { + memset(image, 0, sizeof(OWF_IMAGE)); + } +} + +/*----------------------------------------------------------------------------*/ +static OWFfloat +NonLinear(OWFfloat x) +{ + if (x <= 0.00304f) + { + return 12.92f * x; + } + return 1.0556f * pow(x, 1.f/2.4f) - 0.0556f; +} + +/*----------------------------------------------------------------------------*/ +static OWFfloat +Linear(OWFfloat x) +{ + if (x <= 0.03928) + { + return x / 12.92f; + } + return pow((x + 0.0556f) / 1.0556f, 2.4f); +} + +/*----------------------------------------------------------------------------*/ +OWF_API_CALL void +OWF_Image_NonLinearizeData(OWF_IMAGE* image)\ +{ + OWFpixel* ptr; + OWFint count; + + OWF_ASSERT(image != NULL && image->data != NULL); + OWF_ASSERT(image->format.pixelFormat==OWF_IMAGE_ARGB_INTERNAL); + + if (!image->format.linear) + { + return; + } + + ptr = (OWFpixel*) image->data; + count = image->width * image->height; + + while (count > 0) + { + ptr->color.red = (OWFsubpixel) NonLinear(ptr->color.red / + OWF_RED_MAX_VALUE) * OWF_RED_MAX_VALUE; + ptr->color.green = (OWFsubpixel) NonLinear(ptr->color.green / + OWF_GREEN_MAX_VALUE) * OWF_GREEN_MAX_VALUE; + ptr->color.blue = (OWFsubpixel) NonLinear(ptr->color.blue / + OWF_BLUE_MAX_VALUE) * OWF_BLUE_MAX_VALUE; + + --count; + ptr++; + } + + image->format.linear = OWF_FALSE; +} + +/*----------------------------------------------------------------------------*/ +OWF_API_CALL void +OWF_Image_LinearizeData(OWF_IMAGE* image) +{ + OWFpixel* ptr; + OWFuint count; + + OWF_ASSERT(image != NULL && image->data != NULL); + OWF_ASSERT(image->format.pixelFormat==OWF_IMAGE_ARGB_INTERNAL); + + if (image->format.linear) + { + return; + } + + ptr = (OWFpixel*) image->data; + count = image->width * image->height; + + while (count > 0) + { + ptr->color.red = (OWFsubpixel) Linear(ptr->color.red / + OWF_RED_MAX_VALUE) * OWF_RED_MAX_VALUE; + ptr->color.green = (OWFsubpixel) Linear(ptr->color.green / + OWF_GREEN_MAX_VALUE) * OWF_GREEN_MAX_VALUE; + ptr->color.blue = (OWFsubpixel) Linear(ptr->color.blue / + OWF_BLUE_MAX_VALUE) * OWF_BLUE_MAX_VALUE; + + --count; + ptr += image->pixelSize; + } + + image->format.linear = OWF_TRUE; + +} + +/*----------------------------------------------------------------------------*/ +#define GAMMA(color, max, gamma) (max * pow(color/max, gamma)) + +OWF_API_CALL void +OWF_Image_Gamma(OWF_IMAGE* image, OWFfloat gamma) +{ + OWFpixel* ptr; + OWFint count; + + OWF_ASSERT(image != NULL && image->data != NULL); + OWF_ASSERT(image->format.pixelFormat==OWF_IMAGE_ARGB_INTERNAL); + + if (gamma == 1.0f) + { + return; + } + + ptr = (OWFpixel*) image->data; + count = image->width * image->height; + + while (count > 0) + { + ptr->color.red = + (OWFsubpixel) GAMMA(ptr->color.red, OWF_RED_MAX_VALUE, gamma); + ptr->color.green = + (OWFsubpixel) GAMMA(ptr->color.green, OWF_GREEN_MAX_VALUE, gamma); + ptr->color.blue = + (OWFsubpixel) GAMMA(ptr->color.blue, OWF_BLUE_MAX_VALUE, gamma); + + --count; + ptr++; + } +} + +/*----------------------------------------------------------------------------*/ +OWF_API_CALL void +OWF_Image_EdgeReplication(OWF_IMAGE* image) +{ + OWFint y; + OWFint copyStride; + OWFuint8* srcPtr = NULL; + OWFuint8* dstPtr = NULL; + + OWF_ASSERT(image); + OWF_ASSERT(image->format.pixelFormat==OWF_IMAGE_ARGB_INTERNAL); + OWF_ASSERT(image->width >= 3 && image->height >= 3); + + copyStride = image->width * image->pixelSize; + + /* top side replication */ + srcPtr = (OWFuint8*) image->data; + srcPtr += 1 * image->stride + 0 * image->pixelSize; + dstPtr = (OWFuint8*) image->data; + + memcpy(dstPtr, srcPtr, copyStride); + + /* bottom side replication */ + srcPtr = (OWFuint8*) image->data; + srcPtr += (image->height-2) * image->stride + 0 * image->pixelSize; + dstPtr = (OWFuint8*) image->data; + dstPtr += (image->height-1) * image->stride + 0 * image->pixelSize; + + memcpy(dstPtr, srcPtr, copyStride); + + /* left side replication */ + for (y = 0; y < image->height; y++) + { + OWF_Image_SetPixel(image, 0, y, OWF_Image_GetPixelPtr(image, 1, y)); + } + + /* right side replication */ + for (y = 0; y < image->height; y++) + { + OWF_Image_SetPixel(image, image->width-1, y, OWF_Image_GetPixelPtr(image, + image->width-2, + y)); + } + +} + +/*----------------------------------------------------------------------------*/ +OWF_API_CALL OWFboolean +OWF_Image_SourceFormatConversion(OWF_IMAGE* dst, OWF_IMAGE* src) +{ + OWFint countY, widthDiff, heightDiff; + void* srcLinePtr; + OWFpixel* dstLinePtr; + OWFboolean replicateEdges = OWF_FALSE; + + + OWF_ASSERT(dst != 0 && dst->data != NULL); + OWF_ASSERT(src != 0 && src->data != NULL); + OWF_ASSERT(dst->format.pixelFormat==OWF_IMAGE_ARGB_INTERNAL); + + srcLinePtr = src->data; + dstLinePtr = (OWFpixel*) dst->data; + + /* dst image must either be the same size as the src image or 2 pixels + bigger (enough space to perform edge replication) */ + if (dst->width != src->width || dst->height != src->height) + { + widthDiff = dst->width - src->width; + heightDiff = dst->height - src->height; + + if (widthDiff == 2 && heightDiff == 2) + { + replicateEdges = OWF_TRUE; + /* start of the destination buffer should have a 1 pixel offset */ + dstLinePtr = (OWFpixel*) dst->data + 1 * dst->width + 1; + } + else + { + return OWF_FALSE; + } + } + + if (dst->format.pixelFormat != OWF_IMAGE_ARGB_INTERNAL) + { + return OWF_FALSE; + } + + for (countY = src->height; countY; countY--) + { + OWFint count = src->width; + OWFpixel* dstPtr = dstLinePtr; + + switch (src->format.pixelFormat) + { + case OWF_IMAGE_ARGB8888: + { + OWFuint32* srcPtr = (OWFuint32*) srcLinePtr; + + while (count > 0) + { + dstPtr->color.alpha = (OWFsubpixel) + OWF_ALPHA_MAX_VALUE * ((*srcPtr & ARGB8888_ALPHA_MASK) >> ARGB8888_ALPHA_SHIFT) / OWF_BYTE_MAX_VALUE; + dstPtr->color.red = (OWFsubpixel) + OWF_RED_MAX_VALUE * ((*srcPtr & ARGB8888_RED_MASK) >> ARGB8888_RED_SHIFT) / OWF_BYTE_MAX_VALUE; + dstPtr->color.green = (OWFsubpixel) + OWF_GREEN_MAX_VALUE * ((*srcPtr & ARGB8888_GREEN_MASK)>> ARGB8888_GREEN_SHIFT) / OWF_BYTE_MAX_VALUE; + dstPtr->color.blue = (OWFsubpixel) + OWF_BLUE_MAX_VALUE * ((*srcPtr & ARGB8888_BLUE_MASK) >> ARGB8888_BLUE_SHIFT) / OWF_BYTE_MAX_VALUE; + dstPtr ++; + srcPtr ++; + count--; + } + break; + } + + case OWF_IMAGE_XRGB8888: + { + OWFuint32* srcPtr = (OWFuint32*) srcLinePtr; + + while (count > 0) + { + dstPtr->color.alpha = OWF_FULLY_OPAQUE; + dstPtr->color.red = (OWFsubpixel) + OWF_RED_MAX_VALUE * ((*srcPtr & ARGB8888_RED_MASK) >> ARGB8888_RED_SHIFT) / OWF_BYTE_MAX_VALUE; + dstPtr->color.green = (OWFsubpixel) + OWF_GREEN_MAX_VALUE * ((*srcPtr & ARGB8888_GREEN_MASK) >> ARGB8888_GREEN_SHIFT) / OWF_BYTE_MAX_VALUE; + dstPtr->color.blue = (OWFsubpixel) + OWF_BLUE_MAX_VALUE * ((*srcPtr & ARGB8888_BLUE_MASK) >> ARGB8888_BLUE_SHIFT) / OWF_BYTE_MAX_VALUE; + dstPtr ++; + srcPtr ++; + count--; + } + break; + } + + case OWF_IMAGE_RGB565: + { + OWFfloat tmp; + OWFuint16* srcPtr = (OWFuint16*) srcLinePtr; + + while (count > 0) + { + /* + * Formula for converting channel value is: + * Each channel is multiplied by (2^d - 1)/(2^s -1) + * where d is dest channel bits and s is source channel bits. + */ + dstPtr->color.alpha = (OWFsubpixel) OWF_FULLY_OPAQUE; + + tmp = (OWFfloat)((*srcPtr & RGB565_RED_MASK) >> RGB565_RED_SHIFT); + dstPtr->color.red = (OWFsubpixel)OWF_RED_MAX_VALUE * tmp / 31.0f + OWF_SOURCE_CONVERSION_ROUNDING_VALUE; + + tmp = (OWFfloat)((*srcPtr & RGB565_GREEN_MASK) >> RGB565_GREEN_SHIFT); + dstPtr->color.green = (OWFsubpixel)OWF_GREEN_MAX_VALUE * tmp / 63.0f + OWF_SOURCE_CONVERSION_ROUNDING_VALUE; + + tmp = (OWFfloat)(*srcPtr & RGB565_BLUE_MASK); + dstPtr->color.blue = (OWFsubpixel)OWF_BLUE_MAX_VALUE * tmp / 31.0f + OWF_SOURCE_CONVERSION_ROUNDING_VALUE; + + dstPtr ++; + srcPtr ++; + count--; + } + break; + } + + default: + { + return OWF_FALSE; /* source format not supported */ + } + } + + dstLinePtr+=dst->width; + srcLinePtr=(OWFuint8*)srcLinePtr+src->stride; + } + + if (replicateEdges) + { + OWF_Image_EdgeReplication(dst); + } + + return OWF_TRUE; +} + +/*----------------------------------------------------------------------------*/ +OWF_PUBLIC OWFint +OWF_Image_GetStride(OWFint width, const OWF_IMAGE_FORMAT* format, OWFint minimumStride) +{ + OWFint size; + OWFint pixelSize; + + OWF_ASSERT(format); + + pixelSize = OWF_Image_GetFormatPixelSize(format->pixelFormat); + + if (pixelSize < 0) + { + /* negative pixelSize means that pixel size is a fraction + * (1/-pixelSize) of a byte, e.g. -8 means pixel has size + * of one bit. */ + + size = (width + 1) / -pixelSize; + } + else + { + size = width * pixelSize; + } + if (sizerowPadding) + { + size += format->rowPadding - 1; + size -= size % format->rowPadding; + } + return size; +} + +/*----------------------------------------------------------------------------*/ +OWF_API_CALL OWFboolean +OWF_Image_IsValidDestinationFormat(OWF_IMAGE_FORMAT* format) +{ + switch (format->pixelFormat) + { + case OWF_IMAGE_ARGB8888: + { + return OWF_TRUE; + } + case OWF_IMAGE_XRGB8888: + { + return OWF_TRUE; + } +#ifdef SUPPORT_565_OUTPUT + case OWF_IMAGE_RGB565: + { + return OWF_TRUE; + } +#endif + default: + { + return OWF_FALSE; /* destination format not supported */ + } + } +} + +/*----------------------------------------------------------------------------*/ +OWF_API_CALL OWFboolean +OWF_Image_DestinationFormatConversion(OWF_IMAGE* dst, OWF_IMAGE* src) +{ + OWFint countY; + OWFuint32* dstPtr; + OWFpixel* srcPtr; + + OWF_ASSERT(dst != 0 && dst->data != NULL); + OWF_ASSERT(src != 0 && src->data != NULL); + OWF_ASSERT(src->format.pixelFormat==OWF_IMAGE_ARGB_INTERNAL); + + if (src->format.pixelFormat != OWF_IMAGE_ARGB_INTERNAL) + { + return OWF_FALSE; + } + + /* src and data must have equal amount of pixels */ + if (dst->width != src->width || dst->height != src->height) + { + return OWF_FALSE; + } + + dstPtr = (OWFuint32*) dst->data; + srcPtr = (OWFpixel*) src->data; + + if (dst->format.premultiplied && !src->format.premultiplied) + { + OWF_Image_PremultiplyAlpha(src); + } + else if (!dst->format.premultiplied && src->format.premultiplied) + { + OWF_Image_UnpremultiplyAlpha(src); + } + + for (countY = 0; countY < src->height; countY++) + { + OWFuint8* destination = (OWFuint8*) dst->data; + destination += countY*dst->stride; + dstPtr = (OWFuint32*) destination; + + switch (dst->format.pixelFormat) + { + case OWF_IMAGE_ARGB8888: + { + OWFint countX; + OWFuint32 dstPixel = 0; + + for (countX = 0; countX < src->width; countX++) + { + dstPixel = ((OWFuint8)(roundSubPixel(OWF_BYTE_MAX_VALUE * srcPtr->color.alpha / OWF_ALPHA_MAX_VALUE)) << + ARGB8888_ALPHA_SHIFT); + dstPixel |= ((OWFuint8)(roundSubPixel(OWF_BYTE_MAX_VALUE * srcPtr->color.red / OWF_RED_MAX_VALUE)) << + ARGB8888_RED_SHIFT); + dstPixel |= ((OWFuint8)(roundSubPixel(OWF_BYTE_MAX_VALUE * srcPtr->color.green / OWF_GREEN_MAX_VALUE)) << + ARGB8888_GREEN_SHIFT); + dstPixel |= ((OWFuint8)(roundSubPixel(OWF_BYTE_MAX_VALUE * srcPtr->color.blue / OWF_BLUE_MAX_VALUE)) << + ARGB8888_BLUE_SHIFT); + *dstPtr = dstPixel; + dstPtr ++; + srcPtr ++; + } + break; + } + + case OWF_IMAGE_XRGB8888: + { + OWFint countX; + OWFuint32 dstPixel = 0; + + for (countX = 0; countX < src->width; countX++) + { + dstPixel = ARGB8888_ALPHA_MASK; + dstPixel |= ((OWFuint8)(roundSubPixel(OWF_BYTE_MAX_VALUE * srcPtr->color.red / OWF_RED_MAX_VALUE)) << + ARGB8888_RED_SHIFT); + dstPixel |= ((OWFuint8)(roundSubPixel(OWF_BYTE_MAX_VALUE * srcPtr->color.green / OWF_GREEN_MAX_VALUE)) << + ARGB8888_GREEN_SHIFT); + dstPixel |= ((OWFuint8)(roundSubPixel(OWF_BYTE_MAX_VALUE * srcPtr->color.blue / OWF_BLUE_MAX_VALUE)) << + ARGB8888_BLUE_SHIFT); + *dstPtr = dstPixel; + dstPtr ++; + srcPtr ++; + } + break; + } + + default: + { + return OWF_FALSE; /* destination format not supported */ + } + } + } + + return OWF_TRUE; +} + +/*----------------------------------------------------------------------------*/ +OWF_API_CALL void +OWF_Image_Init(OWF_IMAGE* image) +{ + OWF_ASSERT(NULL != image); + memset(image, 0, sizeof(OWF_IMAGE)); +} + +/*----------------------------------------------------------------------------*/ +OWF_PUBLIC OWF_IMAGE* +OWF_Image_Create(OWFint width, + OWFint height, + const OWF_IMAGE_FORMAT* format, + void* buffer, + OWFint minimumStride + ) +{ + OWF_IMAGE* image; + + image = CREATE(OWF_IMAGE); + + if (image) + { + + image->format.pixelFormat = format->pixelFormat; + image->format.linear = format->linear; + image->format.premultiplied = format->premultiplied; + image->format.rowPadding = format->rowPadding; + + image->pixelSize = OWF_Image_GetFormatPixelSize(format->pixelFormat); + image->width = width; + image->height = height; + + /* stride is row length in bytes (aligned according to image format) */ + image->stride = OWF_Image_GetStride(width, &image->format, minimumStride); + image->foreign = (buffer) ? OWF_TRUE : OWF_FALSE; + image->dataMax = image->stride * height; + + DPRINT(("OWF_Image_Create:")); + DPRINT((" Pixel format = %x", format->pixelFormat)); + DPRINT((" Linear = %d", format->linear)); + DPRINT((" Premultiplied = %d", format->premultiplied)); + DPRINT((" Row alignment = %d bytes", format->rowPadding)); + DPRINT((" Pixel size = %d", image->pixelSize)); + DPRINT((" Width = %d", image->width)); + DPRINT((" Height = %d", image->height)); + DPRINT((" Stride = %d", image->stride)); + DPRINT((" Foreign data = %d", image->foreign)); + DPRINT((" Data size = %d", image->dataMax)); + if (image->dataMax > 0) + { + image->data = (image->foreign) ? (buffer) : + OWF_Image_AllocData(0, width, height, format->pixelFormat); + } + else + { + /* either overflow occured or width/height is zero */ + if (width && height) + { + DPRINT(("OWF_Image_Create: Overflow in image size calculation.")); + } + else + { + DPRINT(("OWF_Image_Create: width or height is zero.")); + } + } + } + + if (!(image && image->data && (image->dataMax > 0))) + { + DPRINT(("OWF_Image_Create: Image creation failed (image = %p, " + "data = %p, dataSize = %d)", + image, image ? (void*)(image->data) : (void*)NULL, image?image->dataMax:-1)); + DESTROY(image); + return NULL; + } + return image; +} + +/*----------------------------------------------------------------------------*/ +OWF_PUBLIC void OWF_Image_Destroy(OWF_IMAGE* image) +{ + if (image) + { + DESTROY(image); + } +} + + +/*----------------------------------------------------------------------------*/ +OWF_API_CALL OWF_IMAGE* +OWF_Image_Copy(const OWF_IMAGE* image) +{ + OWF_IMAGE* newImage = NULL; + + OWF_ASSERT(image); + + newImage = CREATE(OWF_IMAGE); + if (newImage) + { + memcpy(newImage, image, sizeof(*newImage)); + if (!image->foreign) + { + newImage->data = xalloc(1, image->dataMax); + if (newImage->data) + { + memcpy(newImage->data, + image->data, + image->height*image->stride); + } + } + } + + return newImage; +} + +/*----------------------------------------------------------------------------*/ +OWF_API_CALL OWFboolean +OWF_Image_SetSize(OWF_IMAGE* image, + OWFint width, + OWFint height) +{ + OWFint size; + OWFint stride; + + OWF_ASSERT(image); + OWF_ASSERT(image->format.pixelFormat==OWF_IMAGE_ARGB_INTERNAL || + image->format.pixelFormat==OWF_IMAGE_L32); + + /** note that this setsize ignores any specialised stride **/ + stride = OWF_Image_GetStride(width, &image->format, 0); + size = height * stride; + + /* change source size if buffer have enough space */ + if (size > 0 && size <= image->dataMax) + { + image->height = height; + image->width = width; + image->stride = stride; + return OWF_TRUE; + } + return OWF_FALSE; +} +/*----------------------------------------------------------------------------*/ +OWF_API_CALL void +OWF_Image_SetFlags(OWF_IMAGE* image, + OWFboolean premultiply, + OWFboolean linear) + { + OWF_ASSERT(image); + OWF_ASSERT(image->format.pixelFormat==OWF_IMAGE_ARGB_INTERNAL || + image->format.pixelFormat==OWF_IMAGE_L32); + image->format.linear=linear; + image->format.premultiplied=premultiply; + } + +/*----------------------------------------------------------------------------*/ +OWF_API_CALL void +OWF_Image_SetPixelBuffer(OWF_IMAGE* image, void* buffer) + { + OWF_ASSERT(image); + OWF_ASSERT(buffer); + OWF_ASSERT(image->foreign); + if (image->foreign) + { + image->data=buffer; + } + } +/*----------------------------------------------------------------------------*/ +/* NEVER USED +OWF_API_CALL OWFboolean +OWF_Image_SetPixelData(OWF_IMAGE* image, + OWFint width, + OWFint height, + const OWF_IMAGE_FORMAT* format, + void* buffer) +{ + OWFint size = 0, + stride = 0; + + OWF_ASSERT(image && format); + + stride = OWF_Image_GetStride(width, format); + size = height * stride; + + if (size <= 0) + { + return OWF_FALSE; + } + + if (!image->foreign) + { + OWF_Image_FreeData(0, &image->data); + } + + image->format.pixelFormat = format->pixelFormat; + image->format.linear = format->linear; + image->format.premultiplied = format->premultiplied; + image->format.rowPadding = format->rowPadding; + + image->pixelSize = OWF_Image_GetFormatPixelSize(format->pixelFormat); + image->width = width; + image->height = height; + image->stride = stride; + image->foreign = OWF_TRUE; + image->dataMax = size; + image->data = buffer; + + return OWF_TRUE; +} +*/ +/*----------------------------------------------------------------------------*/ +OWF_API_CALL OWFboolean +OWF_Image_Blit(OWF_IMAGE* dst, + OWF_RECTANGLE const* dstRect, + OWF_IMAGE const* src, + OWF_RECTANGLE const* srcRect) +{ + OWF_RECTANGLE bounds, rect, drect, srect; + OWFint lineCount = 0; + OWFint copyStride = 0; + OWFuint8* srcPtr = NULL; + OWFuint8* dstPtr = NULL; + + OWF_ASSERT(dst != 0 && dst->data != NULL); + OWF_ASSERT(src != 0 && src->data != NULL); + OWF_ASSERT(dst->format.pixelFormat==OWF_IMAGE_ARGB_INTERNAL); + OWF_ASSERT(src->format.pixelFormat==OWF_IMAGE_ARGB_INTERNAL); + + OWF_Rect_Set(&bounds, 0, 0, dst->width, dst->height); + OWF_Rect_Set(&rect, + dstRect->x, dstRect->y, + srcRect->width, srcRect->height); + OWF_Rect_Set(&srect, + srcRect->x, srcRect->y, + srcRect->width, srcRect->height); + + /* clip destination rectangle against bounds */ + if (!OWF_Rect_Clip(&drect, &rect, &bounds)) + { + return OWF_FALSE; + } + + if (src->pixelSize != dst->pixelSize) + { + DPRINT(("OWF_Image_Blit(): pixels sizes differ\n")); + return OWF_FALSE; + } + + lineCount = srect.height; + copyStride = srect.width * src->pixelSize; + + /* use bytepointers in copy - generic */ + srcPtr = (OWFuint8*) src->data; + srcPtr += srect.y * src->stride + srect.x * src->pixelSize; + dstPtr = (OWFuint8*)dst->data; + dstPtr += drect.y * dst->stride + drect.x * src->pixelSize; + + while (lineCount > 0) + { + --lineCount; + + memcpy(dstPtr, srcPtr, copyStride); + + srcPtr += src->stride; + dstPtr += dst->stride; + } + + return OWF_TRUE; +} + +/*----------------------------------------------------------------------------*/ +OWF_API_CALL OWFpixel* +OWF_Image_GetPixelPtr(OWF_IMAGE* image, + OWFint x, + OWFint y) +{ + OWF_ASSERT(image && image->format.pixelFormat==OWF_IMAGE_ARGB_INTERNAL); + if (!(image && image->data)) + { + return 0; + } + + x = CLAMP(x, 0, image->width-1); + y = CLAMP(y, 0, image->height-1); + + return (OWFpixel*)image->data + y * image->width + x ; +} + +/*----------------------------------------------------------------------------*/ +OWF_API_CALL void +OWF_Image_GetPixel(OWF_IMAGE* image, + OWFint x, + OWFint y, + OWFpixel* pixel) +{ + OWFpixel* temp = NULL; + + OWF_ASSERT(pixel); + + if (!(image && image->data)) + { + return; + } + OWF_ASSERT(image->format.pixelFormat==OWF_IMAGE_ARGB_INTERNAL); + + pixel->color.alpha = 0; + pixel->color.red = 0; + pixel->color.green = 0; + pixel->color.blue = 0; + + if (x < 0 || y < 0 || x >= image->width || y >= image->height) + { + return; + } + + temp = (OWFpixel*)image->data + y * image->width + x; + + pixel->color.alpha = temp->color.alpha; + pixel->color.red = temp->color.red; + pixel->color.green = temp->color.green; + pixel->color.blue = temp->color.blue; +} + +/*----------------------------------------------------------------------------*/ +OWF_API_CALL void +OWF_Image_SetPixel(OWF_IMAGE* image, + OWFint x, + OWFint y, + OWFpixel const* pixel) +{ + OWFpixel* data = NULL; + + if (!(image && image->data)) + { + return; + } + OWF_ASSERT(image->format.pixelFormat==OWF_IMAGE_ARGB_INTERNAL); + + if(x < 0 || y < 0 || x >= image->width || y >= image->height) + { + return; + } + + + data = (OWFpixel*)image->data + y * image->width + x; + + data->color.red = pixel->color.red; + data->color.green = pixel->color.green; + data->color.blue = pixel->color.blue; + data->color.alpha = pixel->color.alpha; +} + +/*----------------------------------------------------------------------------*/ +OWF_API_CALL OWFboolean +OWF_Image_PointSamplingStretchBlit(OWF_IMAGE* dst, + OWF_RECTANGLE* dstRect, + OWF_IMAGE* src, + OWFfloat* srcRect) +{ + OWFint ox = 0, oy = 0; + OWFfloat dx = 0.f, dy = 0.f; + OWFint x, y; + + /* images must be valid */ + if (!((src != NULL) && (src->data != NULL) && + (dst != NULL) && (dst->data != NULL))) + { + return OWF_FALSE; + } + OWF_ASSERT(src->format.pixelFormat==OWF_IMAGE_ARGB_INTERNAL); + OWF_ASSERT(dst->format.pixelFormat==OWF_IMAGE_ARGB_INTERNAL); + + /* ditto with rectangles, too */ + if (!((dstRect != NULL) && (dstRect->width && dstRect->height) && + (srcRect != NULL) && (srcRect[2] && srcRect[3]))) + { + return OWF_FALSE; + } + + /* Note: bounds check missing */ + + if (src->pixelSize != dst->pixelSize) + { + return OWF_FALSE; + } + + /* solve scaling ratios for image */ + dx = (OWFfloat) srcRect[2] / (OWFfloat) dstRect->width; + dy = (OWFfloat) srcRect[3] / (OWFfloat) dstRect->height; + + for (y = 0; y < dstRect->height; y++) + { + for (x = 0; x < dstRect->width; x++) + { + OWFpixel* pixel; + + /* NOTE This code uses pixel center points to calculate distances + and factors. Results can differ slightly when pixel corner + coordinates are used */ + + /* coordinates of nearest pixel in original image */ + ox = (int) floor((((OWFfloat) x + 0.5) * dx) + srcRect[0]); + oy = (int) floor((((OWFfloat) y + 0.5) * dy) + srcRect[1]); + + pixel = OWF_Image_GetPixelPtr(src, + ox, + oy); + + OWF_Image_SetPixel(dst, + dstRect->x + x, + dstRect->y + y, + pixel); + + } + } + return OWF_TRUE; +} + +/*----------------------------------------------------------------------------*/ +OWF_API_CALL OWFboolean +OWF_Image_BilinearStretchBlit(OWF_IMAGE* dst, + OWF_RECTANGLE* dstRect, + OWF_IMAGE* src, + OWFfloat* srcRect) +{ + OWFint x = 0, y = 0; + OWFint ox = 0, oy = 0; + OWFfloat dx = 0.f, dy = 0.f, wx = 0.f, wy = 0.f; + OWFfloat w[2 * 2]; + OWFpixel* sample[4]; + OWFpixel* pixel = NULL; + + /* images must be valid */ + if (!((src != NULL) && (src->data != NULL) && + (dst != NULL) && (dst->data != NULL))) + { + return OWF_FALSE; + } + OWF_ASSERT(src->format.pixelFormat==OWF_IMAGE_ARGB_INTERNAL); + OWF_ASSERT(dst->format.pixelFormat==OWF_IMAGE_ARGB_INTERNAL); + + /* ditto with rectangles, too */ + if (!((dstRect != NULL) && (dstRect->width && dstRect->height) && + (srcRect != NULL) && (srcRect[2] && srcRect[3]))) + { + return OWF_FALSE; + } + + if (src->pixelSize != dst->pixelSize) + { + return OWF_FALSE; + } + + /* solve scaling ratios for image */ + dx = (OWFfloat) srcRect[2] / (OWFfloat) dstRect->width; + dy = (OWFfloat) srcRect[3] / (OWFfloat) dstRect->height; + + for (y = 0; y < dstRect->height; y++) + { + for (x = 0; x < dstRect->width; x++) + { + OWFfloat tempOx, tempOy; + + /* NOTE This code uses pixel center points to calculate distances + and factors. Results can differ slightly when pixel corner + coordinates are used */ + + /* coordinates of nearest pixel in original image */ + tempOx = (((OWFfloat) x + 0.5) * dx) + srcRect[0]; + tempOy = (((OWFfloat) y + 0.5) * dy) + srcRect[1]; + + ox = (int) floor((((OWFfloat) x + 0.5) * dx) + srcRect[0]); + oy = (int) floor((((OWFfloat) y + 0.5) * dy) + srcRect[1]); + + /* Distances to nearest pixel, eg. fractional part of coordinate */ + wx = (OWFfloat) ox + 0.5 - tempOx; + wy = (OWFfloat) oy + 0.5 - tempOy; + + /* If distance is positive, we should use left or upper pixel for + * second nearest pixel. */ + if (wx > 0.0) + { + ox--; + wx = 1.0 - wx; + } + else + { + wx = -wx; /* abs */ + } + + if (wy > 0.0) + { + oy--; + wy = 1.0 - wy; + } + else + { + wy = -wy; + } + + /* Calculate weights for samples */ + w[0] = (1.0 - wx) * (1.0 - wy); + w[1] = wx * (1.0 - wy); + w[2] = (1.0 - wx) * wy; + w[3] = wx * wy; + + /* get sample */ + sample[0] = OWF_Image_GetPixelPtr(src, ox + 0, oy + 0); + sample[1] = OWF_Image_GetPixelPtr(src, ox + 1, oy + 0); + sample[2] = OWF_Image_GetPixelPtr(src, ox + 0, oy + 1); + sample[3] = OWF_Image_GetPixelPtr(src, ox + 1, oy + 1); + + + /* get result pixel */ + pixel = OWF_Image_GetPixelPtr(dst, x, y); + + /* calculate final color */ + pixel->color.red = + sample[0]->color.red * w[0] + sample[1]->color.red * w[1] + + sample[2]->color.red * w[2] + sample[3]->color.red * w[3] + OWF_BILINEAR_ROUNDING_VALUE; + + pixel->color.green = + sample[0]->color.green * w[0] + sample[1]->color.green * w[1] + + sample[2]->color.green * w[2] + sample[3]->color.green * w[3] + OWF_BILINEAR_ROUNDING_VALUE; + + pixel->color.blue = + sample[0]->color.blue * w[0] + sample[1]->color.blue * w[1] + + sample[2]->color.blue * w[2] + sample[3]->color.blue * w[3] + OWF_BILINEAR_ROUNDING_VALUE; + + pixel->color.alpha = + sample[0]->color.alpha * w[0] + sample[1]->color.alpha * w[1] + + sample[2]->color.alpha * w[2] + sample[3]->color.alpha * w[3] + OWF_BILINEAR_ROUNDING_VALUE; + } + } + return OWF_TRUE; + +} + +/*----------------------------------------------------------------------------*/ +OWF_API_CALL OWFboolean +OWF_Image_Stretch(OWF_IMAGE* dst, + OWF_RECTANGLE* dstRect, + OWF_IMAGE* src, + OWFfloat* srcRect, + OWF_FILTERING filter) +{ + OWFboolean result = OWF_FALSE; + + switch (filter) + { + case OWF_FILTER_POINT_SAMPLING: + { + result = OWF_Image_PointSamplingStretchBlit(dst, dstRect, src, + srcRect); + break; + } + case OWF_FILTER_BILINEAR: + { + result = OWF_Image_BilinearStretchBlit(dst, dstRect, src, srcRect); + break; + } + } + + return result; +} + +/*----------------------------------------------------------------------------*/ +OWF_API_CALL void +OWF_Image_Clear(OWF_IMAGE* image, + OWFsubpixel red, + OWFsubpixel green, + OWFsubpixel blue, + OWFsubpixel alpha) +{ + OWFint i, numPixels; + OWFpixel* pixels; + + OWF_ASSERT(image != 0); + OWF_ASSERT(image->data != 0); + OWF_ASSERT(image->format.pixelFormat == OWF_IMAGE_ARGB_INTERNAL); + + numPixels = image->width * image->height; + pixels = (OWFpixel*) image->data; + + for (i = 0; i < numPixels; i++) + { + pixels[i].color.red = (OWFsubpixel) red; + pixels[i].color.green = (OWFsubpixel) green; + pixels[i].color.blue = (OWFsubpixel) blue; + pixels[i].color.alpha = (OWFsubpixel) alpha; + } +} + +/*----------------------------------------------------------------------------*/ +OWF_API_CALL void +OWF_Image_PremultiplyAlpha(OWF_IMAGE* image) +{ + OWFint x, y; + + OWF_ASSERT(image != 0); + + if (image->format.premultiplied) + { + return; + } + + /* only for internal format */ + if (image->format.pixelFormat != OWF_IMAGE_ARGB_INTERNAL) + { + return; + } + + for (y = 0; y < image->height; y++) + { + for (x = 0; x < image->width; x++) + { + OWFpixel* pixel; + OWFsubpixel alpha; + + pixel = OWF_Image_GetPixelPtr(image, x, y); + + alpha = pixel->color.alpha; + + if (0 == alpha) + { + pixel->color.red = + pixel->color.green = + pixel->color.blue = 0; + } + else + { + pixel->color.red = (pixel->color.red * alpha + OWF_PREMUL_ROUNDING_FACTOR ) / + OWF_ALPHA_MAX_VALUE; + pixel->color.green = (pixel->color.green * alpha + OWF_PREMUL_ROUNDING_FACTOR ) / + OWF_ALPHA_MAX_VALUE; + pixel->color.blue = (pixel->color.blue * alpha + OWF_PREMUL_ROUNDING_FACTOR ) / + OWF_ALPHA_MAX_VALUE; + } + } + } + + image->format.premultiplied = OWF_TRUE; +} + +/*----------------------------------------------------------------------------*/ +OWF_API_CALL void +OWF_Image_UnpremultiplyAlpha(OWF_IMAGE* image) +{ + OWFint count; + OWFpixel* pixelPtr; + + OWF_ASSERT(image != 0); + + if (!image->format.premultiplied) + { + return; + } + + /* only for internal format */ + if (image->format.pixelFormat != OWF_IMAGE_ARGB_INTERNAL) + { + return; + } + + count = image->width * image->height; + pixelPtr = (OWFpixel*)image->data; + + while (count > 0) + { + + OWFsubpixel a = pixelPtr->color.alpha; + + #ifdef OWF_IMAGE_INTERNAL_PIXEL_IS_FLOAT + OWF_ASSERT(a <= OWF_ALPHA_MAX_VALUE && a >= OWF_ALPHA_MIN_VALUE); + #endif + + if (a > OWF_ALPHA_MIN_VALUE) + { + OWFsubpixel r = pixelPtr->color.red * OWF_RED_MAX_VALUE / a; + OWFsubpixel g = pixelPtr->color.green * OWF_GREEN_MAX_VALUE / a; + OWFsubpixel b = pixelPtr->color.blue * OWF_BLUE_MAX_VALUE / a; + + pixelPtr->color.red = r; + pixelPtr->color.green = g; + pixelPtr->color.blue = b; + + --count; + pixelPtr++; + } + } + + image->format.premultiplied = OWF_TRUE; +} + +/*----------------------------------------------------------------------------*/ +OWF_API_CALL void +OWF_Image_Rotate(OWF_IMAGE* dst, + OWF_IMAGE* src, + OWF_ROTATION rotation) +{ + OWFint ox = 0, oy = 0, + w = 0, h = 0, + x = 0, y = 0; + OWFint xx = 0, xy = 0, + yx = 0, yy = 0; + + OWF_ASSERT(src && src->data); + OWF_ASSERT(dst && dst->data); + OWF_ASSERT(src->format.pixelFormat==OWF_IMAGE_ARGB_INTERNAL); + OWF_ASSERT(dst->format.pixelFormat==OWF_IMAGE_ARGB_INTERNAL); + + w = src->width; + h = src->height; + + switch (rotation) + { + case OWF_ROTATION_0: + { + /* + * origin: (0, 0) + * x-axis: (1, 0) + * y-axis: (0, 1) + */ + ox = 0; + oy = 0; + xx = 1; + xy = 0; + yx = 0; + yy = 1; + break; + } + case OWF_ROTATION_90: + { + /* + * origin: (height-1, 0) + * x-axis: (0, 1) + * y-axis: (-1, 0) + */ + ox = h - 1; + oy = 0; + xx = 0; + xy = 1; + yx = -1; + yy = 0; + break; + } + case OWF_ROTATION_180: + { + /* + * origin: (width-1, height-1) + * x-axis: (-1, 0) + * y-axis: (0, -1) + */ + ox = w - 1; + oy = h - 1; + xx = -1; + xy = 0; + yx = 0; + yy = -1; + break; + } + case OWF_ROTATION_270: + { + /* + * origin: (0, height-1) + * x-axis: (0, -1) + * y-axis: (1, 0) + */ + ox = 0; + oy = w - 1; + xx = 0; + xy = -1; + yx = 1; + yy = 0; + break; + + } + } + + for (y = 0; y < h; y++) + { + for (x = 0; x < w; x++) + { + /* + * O = [ox oy]' X = [xx xy]' Y = [yx yy]' + * + * p_dst(x_src,y_src) = O + x_src*X + y_src*Y + */ + OWF_Image_SetPixel(dst, + ox + x * xx + y * yx, + oy + x * xy + y * yy, + OWF_Image_GetPixelPtr(src, x, y)); + } + } +} + +/*----------------------------------------------------------------------------*/ +OWF_API_CALL void +OWF_Image_Flip(OWF_IMAGE* image, + OWF_FLIP_DIRECTION dir) +{ + OWFint x, y; + + if (!image) + { + return; + } + OWF_ASSERT(image->format.pixelFormat==OWF_IMAGE_ARGB_INTERNAL); + + if (dir & OWF_FLIP_VERTICALLY) + { + OWFint h = image->height/2; + + for (y = 0; y < h; y++) + { + for (x = 0; x < image->width; x++) + { + OWFpixel pix; + + OWF_Image_GetPixel(image, x, y, &pix); + OWF_Image_SetPixel(image, x, y, + OWF_Image_GetPixelPtr(image, + x, + image->height - 1 - y + )); + OWF_Image_SetPixel(image, x, image->height - 1 - y, &pix); + } + } + } + + if (dir & OWF_FLIP_HORIZONTALLY) + { + OWFint w = image->width/2; + + for (y = 0; y < image->height; y++) + { + for (x = 0; x < w; x++) + { + OWFpixel pix; + + OWF_Image_GetPixel(image, x, y, &pix); + OWF_Image_SetPixel(image, x, y, + OWF_Image_GetPixelPtr(image, + image->width - 1 - x, + y + )); + OWF_Image_SetPixel(image, image->width - 1 - x, y, &pix); + } + } + } +} + +/*----------------------------------------------------------------------------*/ +#define BLENDER_INNER_LOOP_BEGIN \ + OWFint rowCount = drect.height; \ + while (rowCount > 0) { \ + OWFint colCount = drect.width; \ + while (colCount > 0) { \ + if (!(blend->tsColor && COLOR_MATCH(SC, TSC))) \ + { \ + +#define BLENDER_INNER_LOOP_END \ + DA = blend->destinationFullyOpaque ? OWF_FULLY_OPAQUE : DA; \ + } /* end tsColor check */ \ + srcPtr ++; \ + dstPtr ++; \ + maskPtr++; \ + --colCount; \ + } \ + srcPtr += srcLineDelta; \ + dstPtr += dstLineDelta; \ + maskPtr += maskLineDelta; \ + --rowCount; \ + } + +#define TSC blend->tsColor->color +#define SC srcPtr->color + +/* Note: actually would be better to compare integer values + * for TSC match -> eliminate float arithmetic pitfalls + */ +#define COLOR_MATCH(x, y) (x.red==y.red && x.green==y.green && x.blue==y.blue) + +#define SA srcPtr->color.alpha +#define SR srcPtr->color.red +#define SG srcPtr->color.green +#define SB srcPtr->color.blue + +#define DA dstPtr->color.alpha +#define DR dstPtr->color.red +#define DG dstPtr->color.green +#define DB dstPtr->color.blue + +#define MA *maskPtr +#define GA blend->globalAlpha + +OWF_API_CALL void +OWF_Image_Blend(OWF_BLEND_INFO* blend, + OWF_TRANSPARENCY transparency) +{ + OWF_IMAGE* dst; + OWF_IMAGE* src; + OWF_IMAGE* mask; + OWF_RECTANGLE* srcRect; + OWF_RECTANGLE* dstRect; + OWF_RECTANGLE bounds, srect, drect, rect; + OWFint srcLineDelta, dstLineDelta, maskLineDelta; + OWFpixel* srcPtr; + OWFpixel* dstPtr; + OWFsubpixel* maskPtr; + + + /* preparation */ + OWF_ASSERT(blend); + DPRINT(("OWF_Image_Blend: transparency = %d", transparency)); + /* Mask must be set if mask-transparency is used */ + OWF_ASSERT(((transparency & OWF_TRANSPARENCY_MASK) && blend->mask) || + !(transparency & OWF_TRANSPARENCY_MASK)); + + OWF_ASSERT(blend->source.image->format.pixelFormat == OWF_IMAGE_ARGB_INTERNAL); + OWF_ASSERT(blend->destination.image->format.pixelFormat == OWF_IMAGE_ARGB_INTERNAL); + if (blend->mask) + { + OWF_ASSERT(blend->mask->format.pixelFormat == OWF_IMAGE_L32); + } + + dst = blend->destination.image; + src = blend->source.image; + mask = blend->mask; + dstRect = blend->destination.rectangle; + srcRect = blend->source.rectangle; + + /* this is actually asserted above */ + if (OWF_TRANSPARENCY_MASK == (transparency & OWF_TRANSPARENCY_MASK) && + NULL == mask) + { + return; + } + + OWF_Rect_Set(&bounds, 0, 0, dst->width, dst->height); + /* NOTE: src and dst rects should be of same size!!! */ + OWF_Rect_Set(&rect, + dstRect->x, dstRect->y, + dstRect->width, dstRect->height); + OWF_Rect_Set(&srect, + srcRect->x, srcRect->y, + srcRect->width, srcRect->height); + + /* clip destination rectangle against bounds */ + if (!OWF_Rect_Clip(&drect, &rect, &bounds)) + { + return; + } + + /* adjust source rectangle if needed */ + if (drect.x > rect.x) + { + OWFint dx = drect.x - rect.x; + srect.x += dx; + srect.width -= dx; + } + + if (drect.y > rect.y) + { + OWFint dy = drect.y - rect.y; + srect.y += dy; + srect.height -= dy; + } + + if (drect.width < srect.width) + { + srect.width = drect.width; + } + + if (drect.height < srect.height) + { + srect.height = drect.height; + } + + + srcPtr = (OWFpixel*) src->data; + srcPtr += srect.y * src->width + srect.x; + dstPtr = (OWFpixel*) dst->data; + dstPtr += drect.y * dst->width + drect.x; + + if (mask) + { + maskPtr = (OWFsubpixel*) mask->data + srect.y * mask->width + srect.x; + maskLineDelta = mask->width - drect.width; + } + else + { + maskPtr = 0; + maskLineDelta = 0; + } + srcLineDelta = src->width - srect.width; + dstLineDelta = dst->width - drect.width; + + /* inner loops */ + switch (transparency) + { + case OWF_TRANSPARENCY_NONE: + { + /* + rgb = src.rgb + alpha = 1 + */ + BLENDER_INNER_LOOP_BEGIN; + DR = SR; + DG = SG; + DB = SB; + DA = OWF_FULLY_OPAQUE; + BLENDER_INNER_LOOP_END; + break; + } + + case OWF_TRANSPARENCY_GLOBAL_ALPHA: + { + /* + rgb = src.rgb * elem.alpha + dst.rgb * (1 - elem.alpha) + alpha = elem.alpha + dst.alpha * (1 - elem.alpha) + */ + BLENDER_INNER_LOOP_BEGIN; + DR = (SR * GA + DR * (OWF_FULLY_OPAQUE - GA) + OWF_BLEND_ROUNDING_VALUE) / + OWF_ALPHA_MAX_VALUE; + DG = (SG * GA + DG * (OWF_FULLY_OPAQUE - GA) + OWF_BLEND_ROUNDING_VALUE) / + OWF_ALPHA_MAX_VALUE; + DB = (SB * GA + DB * (OWF_FULLY_OPAQUE - GA) + OWF_BLEND_ROUNDING_VALUE) / + OWF_ALPHA_MAX_VALUE; + DA = GA + (DA * (OWF_FULLY_OPAQUE - GA) + OWF_BLEND_ROUNDING_VALUE) / + OWF_ALPHA_MAX_VALUE; + BLENDER_INNER_LOOP_END; + break; + } + + case OWF_TRANSPARENCY_SOURCE_ALPHA: + { + /* + rgb = src.rgb + dst.rgb * (1 - src.alpha) + alpha = src.alpha + dst.alpha * (1 - src.alpha) + */ + BLENDER_INNER_LOOP_BEGIN; + DR = SR + (DR * (OWF_FULLY_OPAQUE - SA) + OWF_BLEND_ROUNDING_VALUE) / OWF_ALPHA_MAX_VALUE; + DG = SG + (DG * (OWF_FULLY_OPAQUE - SA) + OWF_BLEND_ROUNDING_VALUE) / OWF_ALPHA_MAX_VALUE; + DB = SB + (DB * (OWF_FULLY_OPAQUE - SA) + OWF_BLEND_ROUNDING_VALUE) / OWF_ALPHA_MAX_VALUE; + DA = SA + (DA * (OWF_FULLY_OPAQUE - SA) + OWF_BLEND_ROUNDING_VALUE) / OWF_ALPHA_MAX_VALUE; + BLENDER_INNER_LOOP_END; + break; + } + + case OWF_TRANSPARENCY_MASK: + { + /* + rgb = src.rgb * mask.alpha + dst.rgb * (1 - mask.alpha) + alpha = mask.alpha + dst.alpha * (1 - mask.alpha) + */ + BLENDER_INNER_LOOP_BEGIN; + DR = (SR * MA + DR * (OWF_FULLY_OPAQUE - MA) + OWF_BLEND_ROUNDING_VALUE) / + OWF_ALPHA_MAX_VALUE; + DG = (SG * MA + DG * (OWF_FULLY_OPAQUE - MA) + OWF_BLEND_ROUNDING_VALUE) / + OWF_ALPHA_MAX_VALUE; + DB = (SB * MA + DB * (OWF_FULLY_OPAQUE - MA) + OWF_BLEND_ROUNDING_VALUE) / + OWF_ALPHA_MAX_VALUE; + DA = MA + (DA * (OWF_FULLY_OPAQUE - MA) + OWF_BLEND_ROUNDING_VALUE) / + OWF_ALPHA_MAX_VALUE; + BLENDER_INNER_LOOP_END; + break; + } + + case OWF_TRANSPARENCY_GLOBAL_ALPHA | OWF_TRANSPARENCY_SOURCE_ALPHA: + { + /* + rgb = src.rgb * elem.a + dst.rgb * (1 - src.a * elem.a) + a = src.a * elem.a + dst.a * (1 - src.a * elem.a) + */ + OWFsubpixel SAEA; + + BLENDER_INNER_LOOP_BEGIN; + SAEA = SA * GA / OWF_ALPHA_MAX_VALUE; + DR = (SR * GA + DR * (OWF_FULLY_OPAQUE - SAEA) + OWF_BLEND_ROUNDING_VALUE) / + OWF_ALPHA_MAX_VALUE; + DG = (SG * GA + DG * (OWF_FULLY_OPAQUE - SAEA) + OWF_BLEND_ROUNDING_VALUE) / + OWF_ALPHA_MAX_VALUE; + DB = (SB * GA + DB * (OWF_FULLY_OPAQUE - SAEA) + OWF_BLEND_ROUNDING_VALUE) / + OWF_ALPHA_MAX_VALUE; + DA = SAEA + (DA * (OWF_FULLY_OPAQUE - SAEA) + OWF_BLEND_ROUNDING_VALUE) / + OWF_ALPHA_MAX_VALUE; + BLENDER_INNER_LOOP_END; + break; + } + + case OWF_TRANSPARENCY_GLOBAL_ALPHA | OWF_TRANSPARENCY_MASK: + { + /* + rgb = src.rgb * mask.a * elem.a + dst.rgb * (1 - mask.a * elem.a) + a = mask.a * elem.a + dest.a * (1 - mask.a * elem.a) + */ + OWFsubpixel MAEA; + + BLENDER_INNER_LOOP_BEGIN; + MAEA = MA * GA / OWF_ALPHA_MAX_VALUE; + DR = (SR * MAEA + DR * (OWF_FULLY_OPAQUE - MAEA) + OWF_BLEND_ROUNDING_VALUE) / + OWF_ALPHA_MAX_VALUE; + DG = (SG * MAEA + DG * (OWF_FULLY_OPAQUE - MAEA) + OWF_BLEND_ROUNDING_VALUE) / + OWF_ALPHA_MAX_VALUE; + DB = (SB * MAEA + DB * (OWF_FULLY_OPAQUE - MAEA) + OWF_BLEND_ROUNDING_VALUE) / + OWF_ALPHA_MAX_VALUE; + DA = MAEA + (DA * (OWF_FULLY_OPAQUE - MAEA) + OWF_BLEND_ROUNDING_VALUE) / + OWF_ALPHA_MAX_VALUE; + //No need to check with OWF_ALPHA_MIN_VALUE as it is zero + OWF_ASSERT(GA <= OWF_ALPHA_MAX_VALUE); + BLENDER_INNER_LOOP_END; + break; + } + + default: + { + DPRINT(("OWF_Image_Blend: whooops. invalid blending mode\n")); + abort(); + break; + } + } +} + +/*----------------------------------------------------------------------------*/ +OWF_API_CALL void* +OWF_Image_AllocData(OWF_DISPCTX dc, OWFint width, OWFint height, OWF_PIXEL_FORMAT pixelFormat) +{ + OWF_IMAGE_FORMAT imgf; + OWFint stride; + + /* kludge. GetStride need pixelFormat. */ + imgf.pixelFormat = pixelFormat; + imgf.rowPadding = OWF_Image_GetFormatPadding(pixelFormat); + stride = OWF_Image_GetStride(width, &imgf, 0); + + OWF_ASSERT (width > 0 && height > 0); + + if (stride == 0) + { + return NULL; + } + + if (dc) + { + return OWF_DisplayContext_ScratchBuffer_Allocate(dc, height * stride); + } + + return xalloc(1, height * stride); +} + +/*----------------------------------------------------------------------------*/ +OWF_API_CALL void +OWF_Image_FreeData(OWF_DISPCTX dc, void** data) +{ + if (*data) + { + if (dc) + { + OWF_DisplayContext_ScratchBuffer_Destroy(dc, *data); + } + else + { + xfree(*data); + } + } + *data = NULL; +} + +/*----------------------------------------------------------------------------*/ +OWF_API_CALL OWFint +OWF_Image_GetFormatPixelSize(OWF_PIXEL_FORMAT format) +{ + switch (format) + { + case OWF_IMAGE_ARGB_INTERNAL: + { + return sizeof(OWFpixel); + } + + case OWF_IMAGE_ARGB8888: + case OWF_IMAGE_XRGB8888: + case OWF_IMAGE_L32: + { + return 4; + } + + case OWF_IMAGE_RGB888: + { + return 3; + } + + case OWF_IMAGE_RGB565: + case OWF_IMAGE_L16: + { + return 2; + } + + case OWF_IMAGE_L8: + { + return 1; + } + + case OWF_IMAGE_L1: + { + /* Use negative numbers for divisor, e.g., -8 = 1/8. */ + /* L1 is 1 bit alpha, LSB->MSB, each row padded to 32-bit + * boundary. */ + return -8; + } + default: + { + return 0; + } + } +} + +/*----------------------------------------------------------------------------*/ +OWF_API_CALL OWFint +OWF_Image_GetFormatPadding(OWF_PIXEL_FORMAT format) +{ + OWFint padding = 1; + + switch (format) + { + case OWF_IMAGE_ARGB_INTERNAL: + { + padding = sizeof(OWFpixel); + break; + } + + case OWF_IMAGE_ARGB8888: + case OWF_IMAGE_XRGB8888: + case OWF_IMAGE_L32: + { + padding = 4; + break; + } + + /* + case OWF_IMAGE_RGB888: + { + return 3; + } + */ + + case OWF_IMAGE_RGB565: + case OWF_IMAGE_L16: + { + padding = 2; + break; + } + + case OWF_IMAGE_L8: + { + padding = 1; + break; + } + + case OWF_IMAGE_L1: + { + /* Use negative numbers for divisor, e.g., -8 = 1/8. */ + /* L1 is 1 bit alpha, LSB->MSB, each row padded to 32-bit + * boundary. */ + padding = 4; + break; + } + default: + { + break; + } + } + + OWF_ASSERT(padding); + + return padding; +} + +/*----------------------------------------------------------------------------*/ +OWF_API_CALL void +OWF_Image_SwapWidthAndHeight(OWF_IMAGE* image) +{ + /* swap w & h. Note that original stride is not restored if swap back. */ + image->width ^= image->height; + image->height ^= image->width; + image->width ^= image->height; + + image->stride = OWF_Image_GetStride(image->width, &image->format, 0); +} + +/*----------------------------------------------------------------------------*/ +OWF_API_CALL OWFboolean +OWF_Image_ConvertMask(OWF_IMAGE* output, OWF_IMAGE* input) +{ + OWFboolean result = OWF_TRUE; + void* srcLinePtr; + OWFsubpixel* dstLinePtr; + OWFint countY; + + DPRINT(("OWF_Image_ConvertMask:")); + DPRINT((" Converting mask from stream format to internal 8-bit")); + + OWF_ASSERT(input); + OWF_ASSERT(output); + + srcLinePtr = input->data; + dstLinePtr = (OWFsubpixel*) output->data; + + for (countY = input->height; countY; countY--) + { + OWFsubpixel* dstData = dstLinePtr; + + switch (input->format.pixelFormat) + { + case OWF_IMAGE_L1: + { + OWFint countX; + OWFuint8* srcData = (OWFuint8*) srcLinePtr; + + DPRINT(("1-bit alpha, width = %d, height = %d", + input->width, input->height)); + + for (countX = 0; countX < input->width; countX++) + { + /* + * alpha pixel ordering is LSB -> MSB + * + * byte# |----- byte 0 ----|----- byte 1-----|-- + * bit# | 7 6 5 4 3 2 1 0 | 7 6 5 4 3 2 1 0 | + * pix# | 7 6 5 4 3 2 1 0 | f e d c b a 9 8 | ... + */ + if (srcData[countX >> 3] & (1 << (countX & 7))) + { + dstData[countX] = OWF_FULLY_OPAQUE; + } + else + { + dstData[countX] = OWF_FULLY_TRANSPARENT; + } + } + break; + } + case OWF_IMAGE_L8: + { + OWFint countX; + OWFuint8* srcData = (OWFuint8*) srcLinePtr; + + DPRINT(("8-bit alpha, width = %d, height = %d", + input->width, input->height)); + + for (countX = 0; countX < input->width; countX++) + { + dstData[countX] = srcData[countX] * OWF_FULLY_OPAQUE / + (OWFfloat) OWF_BYTE_MAX_VALUE; + } + break; + } + case OWF_IMAGE_ARGB8888: + { + /* ARGB image - take the alpha channel and discard + * everything else */ + OWFint countX; + OWFuint32* srcData = (OWFuint32*) srcLinePtr; + + DPRINT(("32-bit ARGB, width = %d, height = %d", + input->width, input->height)); + + for (countX = 0; countX < input->width; countX++) + { + dstData[countX] = (srcData[countX] >> 24) * OWF_FULLY_OPAQUE / + (OWFfloat) OWF_BYTE_MAX_VALUE; + } + break; + } + default: + { + DPRINT(("Unsupported alpha format, ignoring mask")); + + result = OWF_FALSE; + break; + } + } + + dstLinePtr+=output->width; + /* Presumes that the stride is always whole bytes - eg. a 2x2-pixel mono + * image takes at least 2 bytes */ + srcLinePtr=(OWFuint8*)srcLinePtr+input->stride; + } + return result; +} + +#ifdef __cplusplus +} +#endif