--- /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 <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <math.h>
+
+#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 (size<minimumStride)
+ {
+ size=minimumStride;
+ }
+ if (format->rowPadding)
+ {
+ 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