/* * Copyright (c) 2003, 2011, 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_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 }; /***************************************************************/ #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) { 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; else return MLIB_FAILURE; /* unknown image type */ 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: res = mlib_AffineFunArr_bl[4 * t_ind + (nchan - 1)] (param); break; case MLIB_BICUBIC: case MLIB_BICUBIC2: 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); 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); } else { res = mlib_ImageAffineEdgeExtend_BC(param, param_e); } break; default: /* nothing to do for other edge types. */ 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; } /***************************************************************/ JNIEXPORT mlib_status JNICALL 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); } /***************************************************************/