| /*------------------------------------------------------------------------- |
| * drawElements Image Library |
| * -------------------------- |
| * |
| * Copyright 2014 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| * |
| *//*! |
| * \file |
| * \brief Image library. |
| *//*--------------------------------------------------------------------*/ |
| |
| #include "deImage.h" |
| #include "deMemory.h" |
| #include "deInt32.h" |
| #include "deMath.h" |
| |
| static int deImageFormat_getBytesPerPixel (deImageFormat format) |
| { |
| DE_ASSERT(format == DE_IMAGEFORMAT_XRGB8888 || format == DE_IMAGEFORMAT_ARGB8888); |
| DE_UNREF(format); |
| return 4; |
| } |
| |
| static void* getPixelAddress (const deImage* image, int x, int y) |
| { |
| int offset = ((y*image->width) + x) * deImageFormat_getBytesPerPixel(image->format); |
| DE_ASSERT(deInBounds32(x, 0, image->width)); |
| DE_ASSERT(deInBounds32(y, 0, image->height)); |
| return (void*)((deUint8*)image->pixels + offset); |
| } |
| |
| deImage* deImage_create (int width, int height, deImageFormat format) |
| { |
| deImage* image = DE_NEW(deImage); |
| int bpp = deImageFormat_getBytesPerPixel(format); |
| if (!image) |
| return DE_NULL; |
| |
| image->width = width; |
| image->height = height; |
| image->format = format; |
| image->pixels = deMalloc(width * height * bpp); |
| if (!image->pixels) |
| { |
| deFree(image); |
| return DE_NULL; |
| } |
| memset(image->pixels, 0, width * height * bpp); |
| |
| return image; |
| } |
| |
| void deImage_destroy (deImage* image) |
| { |
| deFree(image->pixels); |
| deFree(image); |
| } |
| |
| deARGB deImage_getPixel (const deImage* image, int x, int y) |
| { |
| void* addr = getPixelAddress(image, x, y); |
| switch (image->format) |
| { |
| case DE_IMAGEFORMAT_XRGB8888: return *(deARGB*)addr; |
| case DE_IMAGEFORMAT_ARGB8888: return *(deARGB*)addr; |
| default: |
| DE_FATAL("deImage_getPixel(): invalid format"); |
| return deARGB_black(); |
| } |
| } |
| |
| void deImage_setPixel (deImage* image, int x, int y, deARGB argb) |
| { |
| void* addr = getPixelAddress(image, x, y); |
| switch (image->format) |
| { |
| case DE_IMAGEFORMAT_XRGB8888: *(deARGB*)addr = argb; break; |
| case DE_IMAGEFORMAT_ARGB8888: *(deARGB*)addr = argb; break; |
| default: |
| DE_FATAL("deImage_getPixel(): invalid format"); |
| } |
| } |
| |
| deImage* deImage_convertFormat (const deImage* image, deImageFormat format) |
| { |
| int width = image->width; |
| int height = image->height; |
| deImage* converted = deImage_create(width, height, format); |
| if (!converted) |
| return DE_NULL; |
| |
| if (format == image->format) |
| memcpy(converted->pixels, image->pixels, width * height * deImageFormat_getBytesPerPixel(format)); |
| else |
| { |
| int x, y; |
| for (y = 0; y < height; y++) |
| for (x = 0; x < width; x++) |
| deImage_setPixel(converted, x, y, deImage_getPixel(image, x, y)); |
| } |
| |
| return converted; |
| } |
| |
| deImage* deImage_scale (const deImage* srcImage, int dstWidth, int dstHeight) |
| { |
| int srcWidth = srcImage->width; |
| int srcHeight = srcImage->height; |
| deImage* result = deImage_create(dstWidth, dstHeight, srcImage->format); |
| int x, y; |
| |
| for (y = 0; y < dstHeight; y++) |
| { |
| for (x = 0; x < dstWidth; x++) |
| { |
| float xFloat = ((float)x + 0.5f) / (float)dstWidth * (float)srcImage->width - 0.5f; |
| float yFloat = ((float)y + 0.5f) / (float)dstHeight * (float)srcImage->height - 0.5f; |
| int xFixed = deFloorFloatToInt32(xFloat * 256.0f); |
| int yFixed = deFloorFloatToInt32(yFloat * 256.0f); |
| int xFactor = (xFixed & 0xFF); |
| int yFactor = (yFixed & 0xFF); |
| int f00 = ((256-xFactor) * (256-yFactor)) >> 8; |
| int f10 = ((256-xFactor) * yFactor) >> 8; |
| int f01 = (xFactor * (256-yFactor)) >> 8; |
| int f11 = (xFactor * yFactor) >> 8; |
| int x0 = (xFixed >> 8); |
| int y0 = (yFixed >> 8); |
| int x1 = deClamp32(x0+1, 0, srcWidth-1); |
| int y1 = deClamp32(y0+1, 0, srcHeight-1); |
| DE_ASSERT(deInBounds32(x0, 0, srcWidth)); |
| DE_ASSERT(deInBounds32(y0, 0, srcHeight)); |
| |
| /* Filtering. */ |
| { |
| deARGB p00 = deImage_getPixel(srcImage, x0, y0); |
| deARGB p10 = deImage_getPixel(srcImage, x1, y0); |
| deARGB p01 = deImage_getPixel(srcImage, x0, y1); |
| deARGB p11 = deImage_getPixel(srcImage, x1, y1); |
| deARGB pix = deARGB_add(deARGB_add(deARGB_multiply(p00, f00), deARGB_multiply(p10, f10)), |
| deARGB_add(deARGB_multiply(p01, f01), deARGB_multiply(p11, f11))); |
| deImage_setPixel(result, x, y, pix); |
| } |
| } |
| } |
| |
| return result; |
| } |
| |
| void deImage_copyToUint8RGBA (const deImage* image, deUint8* pixels) |
| { |
| int width = image->width; |
| int height = image->height; |
| int x,y; |
| |
| for (y = 0; y < height; y++) |
| for (x = 0; x < width; x++) |
| { |
| deARGB pixel = deImage_getPixel(image, x, y); |
| int ndx = (y * width) + x; |
| pixels[4*ndx+0] = (deUint8)deARGB_getRed(pixel); |
| pixels[4*ndx+1] = (deUint8)deARGB_getGreen(pixel); |
| pixels[4*ndx+2] = (deUint8)deARGB_getBlue(pixel); |
| pixels[4*ndx+3] = (deUint8)deARGB_getAlpha(pixel); |
| } |
| } |
| |
| void* deImage_getPixelPtr (const deImage* image) |
| { |
| return image->pixels; |
| } |
| |
| int deImage_getWidth (const deImage* image) |
| { |
| return image->width; |
| } |
| |
| int deImage_getHeight (const deImage* image) |
| { |
| return image->height; |
| } |