blob: e0f479784900ebb1356f195881f5ce82b2b5e957 [file] [log] [blame]
/*
* Copyright (c) 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_ImageAffine - image affine transformation with edge condition
*
* SYNOPSIS
* mlib_status mlib_ImageAffine(mlib_image *dst,
* const mlib_image *src,
* const mlib_d64 *mtx,
* mlib_filter filter,
* mlib_edge edge)
*
* ARGUMENTS
* dst Pointer to destination image
* src Pointer to source image
* mtx Transformation matrix, where
* mtx[0] holds a; mtx[1] holds b;
* mtx[2] holds tx; mtx[3] holds c;
* mtx[4] holds d; mtx[5] holds ty.
* filter Type of resampling filter.
* edge Type of edge condition.
*
* DESCRIPTION
* xd = a*xs + b*ys + tx
* yd = c*xs + d*ys + ty
*
* The upper-left corner pixel of an image is located at (0.5, 0.5).
*
* The resampling filter can be one of the following:
* MLIB_NEAREST
* MLIB_BILINEAR
* MLIB_BICUBIC
* MLIB_BICUBIC2
*
* The edge condition can be one of the following:
* MLIB_EDGE_DST_NO_WRITE (default)
* MLIB_EDGE_DST_FILL_ZERO
* MLIB_EDGE_OP_NEAREST
* MLIB_EDGE_SRC_EXTEND
* MLIB_EDGE_SRC_PADDED
*
* RESTRICTION
* src and dst must be the same type and the same number of channels.
* They can have 1, 2, 3 or 4 channels. They can be in MLIB_BIT, MLIB_BYTE,
* MLIB_SHORT, MLIB_USHORT or MLIB_INT data type.
*
* src image can not have width or height larger than 32767.
*/
#include "mlib_ImageCheck.h"
#include "mlib_ImageColormap.h"
#include "mlib_ImageAffine.h"
/***************************************************************/
#define BUFF_SIZE 600
/***************************************************************/
const type_affine_fun mlib_AffineFunArr_nn[] = {
mlib_ImageAffine_u8_1ch_nn, mlib_ImageAffine_u8_2ch_nn,
mlib_ImageAffine_u8_3ch_nn, mlib_ImageAffine_u8_4ch_nn,
mlib_ImageAffine_s16_1ch_nn, mlib_ImageAffine_s16_2ch_nn,
mlib_ImageAffine_s16_3ch_nn, mlib_ImageAffine_s16_4ch_nn,
mlib_ImageAffine_s32_1ch_nn, mlib_ImageAffine_s32_2ch_nn,
mlib_ImageAffine_s32_3ch_nn, mlib_ImageAffine_s32_4ch_nn,
mlib_ImageAffine_d64_1ch_nn, mlib_ImageAffine_d64_2ch_nn,
mlib_ImageAffine_d64_3ch_nn, mlib_ImageAffine_d64_4ch_nn,
};
/***************************************************************/
const type_affine_fun mlib_AffineFunArr_bl[] = {
mlib_ImageAffine_u8_1ch_bl, mlib_ImageAffine_u8_2ch_bl,
mlib_ImageAffine_u8_3ch_bl, mlib_ImageAffine_u8_4ch_bl,
mlib_ImageAffine_s16_1ch_bl, mlib_ImageAffine_s16_2ch_bl,
mlib_ImageAffine_s16_3ch_bl, mlib_ImageAffine_s16_4ch_bl,
mlib_ImageAffine_s32_1ch_bl, mlib_ImageAffine_s32_2ch_bl,
mlib_ImageAffine_s32_3ch_bl, mlib_ImageAffine_s32_4ch_bl,
mlib_ImageAffine_u16_1ch_bl, mlib_ImageAffine_u16_2ch_bl,
mlib_ImageAffine_u16_3ch_bl, mlib_ImageAffine_u16_4ch_bl,
mlib_ImageAffine_f32_1ch_bl, mlib_ImageAffine_f32_2ch_bl,
mlib_ImageAffine_f32_3ch_bl, mlib_ImageAffine_f32_4ch_bl,
mlib_ImageAffine_d64_1ch_bl, mlib_ImageAffine_d64_2ch_bl,
mlib_ImageAffine_d64_3ch_bl, mlib_ImageAffine_d64_4ch_bl
};
/***************************************************************/
const type_affine_fun mlib_AffineFunArr_bc[] = {
mlib_ImageAffine_u8_1ch_bc, mlib_ImageAffine_u8_2ch_bc,
mlib_ImageAffine_u8_3ch_bc, mlib_ImageAffine_u8_4ch_bc,
mlib_ImageAffine_s16_1ch_bc, mlib_ImageAffine_s16_2ch_bc,
mlib_ImageAffine_s16_3ch_bc, mlib_ImageAffine_s16_4ch_bc,
mlib_ImageAffine_s32_1ch_bc, mlib_ImageAffine_s32_2ch_bc,
mlib_ImageAffine_s32_3ch_bc, mlib_ImageAffine_s32_4ch_bc,
mlib_ImageAffine_u16_1ch_bc, mlib_ImageAffine_u16_2ch_bc,
mlib_ImageAffine_u16_3ch_bc, mlib_ImageAffine_u16_4ch_bc,
mlib_ImageAffine_f32_1ch_bc, mlib_ImageAffine_f32_2ch_bc,
mlib_ImageAffine_f32_3ch_bc, mlib_ImageAffine_f32_4ch_bc,
mlib_ImageAffine_d64_1ch_bc, mlib_ImageAffine_d64_2ch_bc,
mlib_ImageAffine_d64_3ch_bc, mlib_ImageAffine_d64_4ch_bc
};
/***************************************************************/
const type_affine_i_fun mlib_AffineFunArr_bc_i[] = {
mlib_ImageAffineIndex_U8_U8_3CH_BC,
mlib_ImageAffineIndex_U8_U8_4CH_BC,
mlib_ImageAffineIndex_S16_U8_3CH_BC,
mlib_ImageAffineIndex_S16_U8_4CH_BC,
mlib_ImageAffineIndex_U8_S16_3CH_BC,
mlib_ImageAffineIndex_U8_S16_4CH_BC,
mlib_ImageAffineIndex_S16_S16_3CH_BC,
mlib_ImageAffineIndex_S16_S16_4CH_BC
};
/***************************************************************/
#ifdef i386 /* do not perform the coping by mlib_d64 data type for x86 */
#define MAX_T_IND 2
#else
#define MAX_T_IND 3
#endif /* i386 ( do not perform the coping by mlib_d64 data type for x86 ) */
/***************************************************************/
mlib_status mlib_ImageAffine_alltypes(mlib_image *dst,
const mlib_image *src,
const mlib_d64 *mtx,
mlib_filter filter,
mlib_edge edge,
const void *colormap)
{
mlib_affine_param param[1];
mlib_status res;
mlib_type type;
mlib_s32 nchan, t_ind, kw, kw1;
mlib_addr align;
mlib_d64 buff_lcl[BUFF_SIZE / 8];
mlib_u8 **lineAddr = NULL;
/* check for obvious errors */
MLIB_IMAGE_TYPE_EQUAL(src, dst);
MLIB_IMAGE_CHAN_EQUAL(src, dst);
type = mlib_ImageGetType(dst);
nchan = mlib_ImageGetChannels(dst);
switch (filter) {
case MLIB_NEAREST:
kw = 1;
kw1 = 0;
break;
case MLIB_BILINEAR:
kw = 2;
kw1 = 0;
break;
case MLIB_BICUBIC:
case MLIB_BICUBIC2:
kw = 4;
kw1 = 1;
break;
default:
return MLIB_FAILURE;
}
STORE_PARAM(param, lineAddr);
STORE_PARAM(param, filter);
res = mlib_AffineEdges(param, dst, src, buff_lcl, BUFF_SIZE,
kw, kw, kw1, kw1, edge, mtx, MLIB_SHIFT, MLIB_SHIFT);
if (res != MLIB_SUCCESS)
return res;
lineAddr = param->lineAddr;
if (type == MLIB_BYTE)
t_ind = 0;
else if (type == MLIB_SHORT)
t_ind = 1;
else if (type == MLIB_INT)
t_ind = 2;
else if (type == MLIB_USHORT)
t_ind = 3;
else if (type == MLIB_FLOAT)
t_ind = 4;
else if (type == MLIB_DOUBLE)
t_ind = 5;
if (colormap != NULL && filter != MLIB_NEAREST) {
if (t_ind != 0 && t_ind != 1)
return MLIB_FAILURE;
if (mlib_ImageGetLutType(colormap) == MLIB_SHORT)
t_ind += 2;
t_ind = 2 * t_ind;
if (mlib_ImageGetLutChannels(colormap) == 4)
t_ind++;
}
if (type == MLIB_BIT) {
mlib_s32 s_bitoff = mlib_ImageGetBitOffset(src);
mlib_s32 d_bitoff = mlib_ImageGetBitOffset(dst);
if (nchan != 1 || filter != MLIB_NEAREST)
return MLIB_FAILURE;
mlib_ImageAffine_bit_1ch_nn(param, s_bitoff, d_bitoff);
}
else {
switch (filter) {
case MLIB_NEAREST:
if (t_ind >= 3)
t_ind -= 2; /* correct types USHORT, FLOAT, DOUBLE; new values: 1, 2, 3 */
/* two channels as one channel of next type */
align = (mlib_addr) (param->dstData) | (mlib_addr) lineAddr[0];
align |= param->dstYStride | param->srcYStride;
while (((nchan | (align >> t_ind)) & 1) == 0 && t_ind < MAX_T_IND) {
nchan >>= 1;
t_ind++;
}
res = mlib_AffineFunArr_nn[4 * t_ind + (nchan - 1)] (param);
break;
case MLIB_BILINEAR:
if (colormap != NULL) {
res = mlib_AffineFunArr_bl_i[t_ind] (param, colormap);
}
else {
res = mlib_AffineFunArr_bl[4 * t_ind + (nchan - 1)] (param);
}
break;
case MLIB_BICUBIC:
case MLIB_BICUBIC2:
if (colormap != NULL) {
res = mlib_AffineFunArr_bc_i[t_ind] (param, colormap);
}
else {
res = mlib_AffineFunArr_bc[4 * t_ind + (nchan - 1)] (param);
}
break;
}
if (res != MLIB_SUCCESS) {
if (param->buff_malloc != NULL)
mlib_free(param->buff_malloc);
return res;
}
}
if (edge == MLIB_EDGE_SRC_PADDED)
edge = MLIB_EDGE_DST_NO_WRITE;
if (filter != MLIB_NEAREST && edge != MLIB_EDGE_DST_NO_WRITE) {
mlib_affine_param param_e[1];
mlib_d64 buff_lcl1[BUFF_SIZE / 8];
STORE_PARAM(param_e, lineAddr);
STORE_PARAM(param_e, filter);
res = mlib_AffineEdges(param_e, dst, src, buff_lcl1, BUFF_SIZE,
kw, kw, kw1, kw1, -1, mtx, MLIB_SHIFT, MLIB_SHIFT);
if (res != MLIB_SUCCESS) {
if (param->buff_malloc != NULL)
mlib_free(param->buff_malloc);
return res;
}
switch (edge) {
case MLIB_EDGE_DST_FILL_ZERO:
mlib_ImageAffineEdgeZero(param, param_e, colormap);
break;
case MLIB_EDGE_OP_NEAREST:
mlib_ImageAffineEdgeNearest(param, param_e);
break;
case MLIB_EDGE_SRC_EXTEND:
if (filter == MLIB_BILINEAR) {
res = mlib_ImageAffineEdgeExtend_BL(param, param_e, colormap);
}
else {
res = mlib_ImageAffineEdgeExtend_BC(param, param_e, colormap);
}
break;
}
if (param_e->buff_malloc != NULL)
mlib_free(param_e->buff_malloc);
}
if (param->buff_malloc != NULL)
mlib_free(param->buff_malloc);
return res;
}
/***************************************************************/
mlib_status mlib_ImageAffine(mlib_image *dst,
const mlib_image *src,
const mlib_d64 *mtx,
mlib_filter filter,
mlib_edge edge)
{
mlib_type type;
MLIB_IMAGE_CHECK(src);
MLIB_IMAGE_CHECK(dst);
type = mlib_ImageGetType(dst);
if (type != MLIB_BIT && type != MLIB_BYTE &&
type != MLIB_SHORT && type != MLIB_USHORT && type != MLIB_INT) {
return MLIB_FAILURE;
}
return mlib_ImageAffine_alltypes(dst, src, mtx, filter, edge, NULL);
}
/***************************************************************/