/* * Copyright (c) 1997, 2018, 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 #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; } /***************************************************************/ JNIEXPORT 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; } /***************************************************************/ JNIEXPORT 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; } /***************************************************************/ JNIEXPORT 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); if (tline == NULL) return NULL; rtable = mlib_malloc((3 + im_height)*sizeof(mlib_u8 *)); if (rtable == 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; } /***************************************************************/