/*
* Copyright (c) 1997, 2003, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* FUNCTION
* mlib_ImageCreateStruct - create image data structure
* mlib_ImageCreate - create image data structure and allocate
* memory for image data
* mlib_ImageDelete - delete image
* mlib_ImageCreateSubimage - create sub-image
*
* mlib_ImageCreateRowTable - create row starts pointer table
* mlib_ImageDeleteRowTable - delete row starts pointer table
*
* mlib_ImageSetPaddings - set paddings for clipping box borders
*
* mlib_ImageSetFormat - set image format
*
* SYNOPSIS
* mlib_image *mlib_ImageCreateStruct(mlib_type type,
* mlib_s32 channels,
* mlib_s32 width,
* mlib_s32 height,
* mlib_s32 stride,
* const void *data)
*
* mlib_image *mlib_ImageCreate(mlib_type type,
* mlib_s32 channels,
* mlib_s32 width,
* mlib_s32 height)
*
* void mlib_ImageDelete(mlib_image *img)
*
* mlib_image *mlib_ImageCreateSubimage(mlib_image *img,
* mlib_s32 x,
* mlib_s32 y,
* mlib_s32 w,
* mlib_s32 h)
*
* void *mlib_ImageCreateRowTable(mlib_image *img)
*
* void mlib_ImageDeleteRowTable(mlib_image *img)
*
* mlib_status mlib_ImageSetPaddings(mlib_image *img,
* mlib_u8 left,
* mlib_u8 top,
* mlib_u8 right,
* mlib_u8 bottom)
*
* mlib_status mlib_ImageSetFormat(mlib_image *img,
* mlib_format format)
* ARGUMENTS
* img pointer to image data structure
* type image data type, one of MLIB_BIT, MLIB_BYTE, MLIB_SHORT,
* MLIB_USHORT, MLIB_INT, MLIB_FLOAT or MLIB_DOUBLE
* channels number of image channels
* width image width in pixels
* height image height in pixels
* stride linebytes( bytes to next row) of the image
* data pointer to image data allocated by user
* x x coordinate of the left border in the source image
* y y coordinate of the top border in the source image
* w width of the sub-image
* h height of the sub-image
* left clipping box left padding
* top clipping box top padding
* right clipping box right padding
* bottom clipping box bottom padding
* format image format
*
* DESCRIPTION
* mlib_ImageCreateStruct() creates a mediaLib image data structure
* using parameter supplied by user.
*
* mlib_ImageCreate() creates a mediaLib image data structure and
* allocates memory space for image data.
*
* mlib_ImageDelete() deletes the mediaLib image data structure
* and frees the memory space of the image data if it is allocated
* through mlib_ImageCreate().
*
* mlib_ImageCreateSubimage() creates a mediaLib image structure
* for a sub-image based on a source image.
*
* mlib_ImageCreateRowTable() creates row starts pointer table and
* puts it into mlib_image->state field.
*
* mlib_ImageDeleteRowTable() deletes row starts pointer table from
* image and puts NULL into mlib_image->state field.
*
* mlib_ImageSetPaddings() sets new values for the clipping box paddings
*
* mlib_ImageSetFormat() sets new value for the image format
*/
#include <stdlib.h>
#include "mlib_image.h"
#include "mlib_ImageRowTable.h"
#include "mlib_ImageCreate.h"
#include "safe_math.h"
/***************************************************************/
mlib_image* mlib_ImageSet(mlib_image *image,
mlib_type type,
mlib_s32 channels,
mlib_s32 width,
mlib_s32 height,
mlib_s32 stride,
const void *data)
{
mlib_s32 wb; /* width in bytes */
mlib_s32 mask; /* mask for check of stride */
if (image == NULL) return NULL;
/* for some ugly functions calling with incorrect parameters */
image -> type = type;
image -> channels = channels;
image -> width = width;
image -> height = height;
image -> stride = stride;
image -> data = (void *)data;
image -> state = NULL;
image -> format = MLIB_FORMAT_UNKNOWN;
image -> paddings[0] = 0;
image -> paddings[1] = 0;
image -> paddings[2] = 0;
image -> paddings[3] = 0;
image -> bitoffset = 0;
if (width <= 0 || height <= 0 || channels < 1 || channels > 4) {
return NULL;
}
/* Check if stride == width
* If it is then image can be treated as a 1-D vector
*/
if (!SAFE_TO_MULT(width, channels)) {
return NULL;
}
wb = width * channels;
switch (type) {
case MLIB_DOUBLE:
if (!SAFE_TO_MULT(wb, 8)) {
return NULL;
}
wb *= 8;
mask = 7;
break;
case MLIB_FLOAT:
case MLIB_INT:
if (!SAFE_TO_MULT(wb, 4)) {
return NULL;
}
wb *= 4;
mask = 3;
break;
case MLIB_USHORT:
case MLIB_SHORT:
if (!SAFE_TO_MULT(wb, 2)) {
return NULL;
}
wb *= 2;
mask = 1;
break;
case MLIB_BYTE:
// wb is ready
mask = 0;
break;
case MLIB_BIT:
if (!SAFE_TO_ADD(7, wb)) {
return NULL;
}
wb = (wb + 7) / 8;
mask = 0;
break;
default:
return NULL;
}
if (stride & mask) {
return NULL;
}
image -> flags = ((width & 0xf) << 8); /* set width field */
image -> flags |= ((stride & 0xf) << 16); /* set stride field */
image -> flags |= ((height & 0xf) << 12); /* set height field */
image -> flags |= (mlib_addr)data & 0xff;
image -> flags |= MLIB_IMAGE_USERALLOCATED; /* user allocated data */
if ((stride != wb) ||
((type == MLIB_BIT) && (stride * 8 != width * channels))) {
image -> flags |= MLIB_IMAGE_ONEDVECTOR;
}
image -> flags &= MLIB_IMAGE_ATTRIBUTESET;
return image;
}
/***************************************************************/
mlib_image *mlib_ImageCreateStruct(mlib_type type,
mlib_s32 channels,
mlib_s32 width,
mlib_s32 height,
mlib_s32 stride,
const void *data)
{
mlib_image *image;
if (stride <= 0) {
return NULL;
}
image = (mlib_image *)mlib_malloc(sizeof(mlib_image));
if (image == NULL) {
return NULL;
}
if (mlib_ImageSet(image, type, channels, width, height, stride, data) == NULL) {
mlib_free(image);
image = NULL;
}
return image;
}
/***************************************************************/
mlib_image *mlib_ImageCreate(mlib_type type,
mlib_s32 channels,
mlib_s32 width,
mlib_s32 height)
{
mlib_image *image;
mlib_s32 wb; /* width in bytes */
void *data;
/* sanity check */
if (width <= 0 || height <= 0 || channels < 1 || channels > 4) {
return NULL;
};
if (!SAFE_TO_MULT(width, channels)) {
return NULL;
}
wb = width * channels;
switch (type) {
case MLIB_DOUBLE:
if (!SAFE_TO_MULT(wb, 8)) {
return NULL;
}
wb *= 8;
break;
case MLIB_FLOAT:
case MLIB_INT:
if (!SAFE_TO_MULT(wb, 4)) {
return NULL;
}
wb *= 4;
break;
case MLIB_USHORT:
case MLIB_SHORT:
if (!SAFE_TO_MULT(wb, 2)) {
return NULL;
}
wb *= 2;
break;
case MLIB_BYTE:
// wb is ready
break;
case MLIB_BIT:
if (!SAFE_TO_ADD(7, wb)) {
return NULL;
}
wb = (wb + 7) / 8;
break;
default:
return NULL;
}
if (!SAFE_TO_MULT(wb, height)) {
return NULL;
}
data = mlib_malloc(wb * height);
if (data == NULL) {
return NULL;
}
image = (mlib_image *)mlib_malloc(sizeof(mlib_image));
if (image == NULL) {
mlib_free(data);
return NULL;
};
image -> type = type;
image -> channels = channels;
image -> width = width;
image -> height = height;
image -> stride = wb;
image -> data = data;
image -> flags = ((width & 0xf) << 8); /* set width field */
image -> flags |= ((height & 0xf) << 12); /* set height field */
image -> flags |= ((wb & 0xf) << 16); /* set stride field */
image -> flags |= (mlib_addr)data & 0xff;
image -> format = MLIB_FORMAT_UNKNOWN;
image -> paddings[0] = 0;
image -> paddings[1] = 0;
image -> paddings[2] = 0;
image -> paddings[3] = 0;
image -> bitoffset = 0;
if ((type == MLIB_BIT) && (wb * 8 != width * channels)) {
image -> flags |= MLIB_IMAGE_ONEDVECTOR; /* not 1-d vector */
}
image -> flags &= MLIB_IMAGE_ATTRIBUTESET;
image -> state = NULL;
return image;
}
/***************************************************************/
void mlib_ImageDelete(mlib_image *img)
{
if (img == NULL) return;
if ((img -> flags & MLIB_IMAGE_USERALLOCATED) == 0) {
mlib_free(img -> data);
}
mlib_ImageDeleteRowTable(img);
mlib_free(img);
}
/***************************************************************/
mlib_image *mlib_ImageCreateSubimage(mlib_image *img,
mlib_s32 x,
mlib_s32 y,
mlib_s32 w,
mlib_s32 h)
{
mlib_image *subimage;
mlib_type type;
mlib_s32 channels;
mlib_s32 width; /* for parent image */
mlib_s32 height; /* for parent image */
mlib_s32 stride;
mlib_s32 bitoffset = 0;
void *data;
/* sanity check */
if (w <= 0 || h <= 0 || img == NULL) return NULL;
type = img -> type;
channels = img -> channels;
width = img -> width;
height = img -> height;
stride = img -> stride;
/* clip the sub-image with respect to the parent image */
if (((x + w) <= 0) || ((y + h) <= 0) ||
(x >= width) || (y >= height)) {
return NULL;
}
else {
if (x < 0) {
w += x; /* x is negative */
x = 0;
}
if (y < 0) {
h += y; /* y is negative */
y = 0;
}
if ((x + w) > width) {
w = width - x;
}
if ((y + h) > height) {
h = height - y;
}
}
/* compute sub-image origin */
data = (mlib_u8 *)(img -> data) + y * stride;
switch (type) {
case MLIB_DOUBLE:
data = (mlib_u8 *)data + x * channels * 8;
break;
case MLIB_FLOAT:
case MLIB_INT:
data = (mlib_u8 *)data + x * channels * 4;
break;
case MLIB_USHORT:
case MLIB_SHORT:
data = (mlib_u8 *)data + x * channels * 2;
break;
case MLIB_BYTE:
data = (mlib_u8 *)data + x * channels;
break;
case MLIB_BIT:
bitoffset = img -> bitoffset;
data = (mlib_u8 *)data + (x * channels + bitoffset) / 8;
bitoffset = (x * channels + bitoffset) & 7;
break;
default:
return NULL;
}
subimage = mlib_ImageCreateStruct(type,
channels,
w,
h,
stride,
data);
if (subimage != NULL && type == MLIB_BIT)
subimage -> bitoffset = bitoffset;
return subimage;
}
/***************************************************************/
mlib_image *mlib_ImageSetSubimage(mlib_image *dst,
const mlib_image *src,
mlib_s32 x,
mlib_s32 y,
mlib_s32 w,
mlib_s32 h)
{
mlib_type type = src -> type;
mlib_s32 channels = src -> channels;
mlib_s32 stride = src -> stride;
mlib_u8 *data = src -> data;
mlib_s32 bitoffset = 0;
data += y * stride;
switch (type) {
case MLIB_DOUBLE:
data += channels * x * 8;
break;
case MLIB_FLOAT:
case MLIB_INT:
data += channels * x * 4;
break;
case MLIB_USHORT:
case MLIB_SHORT:
data += channels * x * 2;
break;
case MLIB_BYTE:
data += channels * x;
break;
case MLIB_BIT:
bitoffset = src -> bitoffset + channels * x;
data += (bitoffset >= 0) ? bitoffset/8 : (bitoffset - 7)/8; /* with rounding toward -Inf */
bitoffset &= 7;
break;
default:
return NULL;
}
if (h > 0) {
dst = mlib_ImageSet(dst, type, channels, w, h, stride, data);
} else {
h = - h;
dst = mlib_ImageSet(dst, type, channels, w, h, - stride, data + (h - 1)*stride);
}
if (dst != NULL && type == MLIB_BIT) {
dst -> bitoffset = bitoffset;
}
return dst;
}
/***************************************************************/
void *mlib_ImageCreateRowTable(mlib_image *img)
{
mlib_u8 **rtable, *tline;
mlib_s32 i, im_height, im_stride;
if (img == NULL) return NULL;
if (img -> state) return img -> state;
im_height = mlib_ImageGetHeight(img);
im_stride = mlib_ImageGetStride(img);
tline = mlib_ImageGetData(img);
rtable = mlib_malloc((3 + im_height)*sizeof(mlib_u8 *));
if (rtable == NULL || tline == NULL) return NULL;
rtable[0] = 0;
rtable[1] = (mlib_u8*)((void **)rtable + 1);
rtable[2 + im_height] = (mlib_u8*)((void **)rtable + 1);
for (i = 0; i < im_height; i++) {
rtable[i+2] = tline;
tline += im_stride;
}
img -> state = ((void **)rtable + 2);
return img -> state;
}
/***************************************************************/
void mlib_ImageDeleteRowTable(mlib_image *img)
{
void **state;
if (img == NULL) return;
state = img -> state;
if (!state) return;
mlib_free(state - 2);
img -> state = 0;
}
/***************************************************************/
mlib_status mlib_ImageSetPaddings(mlib_image *img,
mlib_u8 left,
mlib_u8 top,
mlib_u8 right,
mlib_u8 bottom)
{
if (img == NULL) return MLIB_FAILURE;
if ((left + right) >= img -> width ||
(top + bottom) >= img -> height) return MLIB_OUTOFRANGE;
img -> paddings[0] = left;
img -> paddings[1] = top;
img -> paddings[2] = right;
img -> paddings[3] = bottom;
return MLIB_SUCCESS;
}
/***************************************************************/
mlib_status mlib_ImageSetFormat(mlib_image *img,
mlib_format format)
{
if (img == NULL) return MLIB_FAILURE;
img -> format = format;
return MLIB_SUCCESS;
}
/***************************************************************/