1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069 |
- #include "Imaging.h"
- /* For large images rotation is an inefficient operation in terms of CPU cache.
- One row in the source image affects each column in destination.
- Rotating in chunks that fit in the cache can speed up rotation
- 8x on a modern CPU. A chunk size of 128 requires only 65k and is large enough
- that the overhead from the extra loops are not apparent. */
- #define ROTATE_CHUNK 512
- #define ROTATE_SMALL_CHUNK 8
- #define COORD(v) ((v) < 0.0 ? -1 : ((int)(v)))
- #define FLOOR(v) ((v) < 0.0 ? ((int)floor(v)) : ((int)(v)))
- /* -------------------------------------------------------------------- */
- /* Transpose operations */
- Imaging
- ImagingFlipLeftRight(Imaging imOut, Imaging imIn)
- {
- ImagingSectionCookie cookie;
- int x, y, xr;
- if (!imOut || !imIn || strcmp(imIn->mode, imOut->mode) != 0)
- return (Imaging) ImagingError_ModeError();
- if (imIn->xsize != imOut->xsize || imIn->ysize != imOut->ysize)
- return (Imaging) ImagingError_Mismatch();
- ImagingCopyPalette(imOut, imIn);
- #define FLIP_LEFT_RIGHT(INT, image) \
- for (y = 0; y < imIn->ysize; y++) { \
- INT* in = (INT *)imIn->image[y]; \
- INT* out = (INT *)imOut->image[y]; \
- xr = imIn->xsize-1; \
- for (x = 0; x < imIn->xsize; x++, xr--) \
- out[xr] = in[x]; \
- }
- ImagingSectionEnter(&cookie);
- if (imIn->image8) {
- if (strncmp(imIn->mode, "I;16", 4) == 0) {
- FLIP_LEFT_RIGHT(UINT16, image8)
- } else {
- FLIP_LEFT_RIGHT(UINT8, image8)
- }
- } else {
- FLIP_LEFT_RIGHT(INT32, image32)
- }
- ImagingSectionLeave(&cookie);
- #undef FLIP_LEFT_RIGHT
- return imOut;
- }
- Imaging
- ImagingFlipTopBottom(Imaging imOut, Imaging imIn)
- {
- ImagingSectionCookie cookie;
- int y, yr;
- if (!imOut || !imIn || strcmp(imIn->mode, imOut->mode) != 0)
- return (Imaging) ImagingError_ModeError();
- if (imIn->xsize != imOut->xsize || imIn->ysize != imOut->ysize)
- return (Imaging) ImagingError_Mismatch();
- ImagingCopyPalette(imOut, imIn);
- ImagingSectionEnter(&cookie);
- yr = imIn->ysize - 1;
- for (y = 0; y < imIn->ysize; y++, yr--)
- memcpy(imOut->image[yr], imIn->image[y], imIn->linesize);
- ImagingSectionLeave(&cookie);
- return imOut;
- }
- Imaging
- ImagingRotate90(Imaging imOut, Imaging imIn)
- {
- ImagingSectionCookie cookie;
- int x, y, xx, yy, xr, xxsize, yysize;
- int xxx, yyy, xxxsize, yyysize;
- if (!imOut || !imIn || strcmp(imIn->mode, imOut->mode) != 0)
- return (Imaging) ImagingError_ModeError();
- if (imIn->xsize != imOut->ysize || imIn->ysize != imOut->xsize)
- return (Imaging) ImagingError_Mismatch();
- ImagingCopyPalette(imOut, imIn);
- #define ROTATE_90(INT, image) \
- for (y = 0; y < imIn->ysize; y += ROTATE_CHUNK) { \
- for (x = 0; x < imIn->xsize; x += ROTATE_CHUNK) { \
- yysize = y + ROTATE_CHUNK < imIn->ysize ? y + ROTATE_CHUNK : imIn->ysize; \
- xxsize = x + ROTATE_CHUNK < imIn->xsize ? x + ROTATE_CHUNK : imIn->xsize; \
- for (yy = y; yy < yysize; yy += ROTATE_SMALL_CHUNK) { \
- for (xx = x; xx < xxsize; xx += ROTATE_SMALL_CHUNK) { \
- yyysize = yy + ROTATE_SMALL_CHUNK < imIn->ysize ? yy + ROTATE_SMALL_CHUNK : imIn->ysize; \
- xxxsize = xx + ROTATE_SMALL_CHUNK < imIn->xsize ? xx + ROTATE_SMALL_CHUNK : imIn->xsize; \
- for (yyy = yy; yyy < yyysize; yyy++) { \
- INT* in = (INT *)imIn->image[yyy]; \
- xr = imIn->xsize - 1 - xx; \
- for (xxx = xx; xxx < xxxsize; xxx++, xr--) { \
- INT* out = (INT *)imOut->image[xr]; \
- out[yyy] = in[xxx]; \
- } \
- } \
- } \
- } \
- } \
- }
- ImagingSectionEnter(&cookie);
- if (imIn->image8) {
- if (strncmp(imIn->mode, "I;16", 4) == 0) {
- ROTATE_90(UINT16, image8);
- } else {
- ROTATE_90(UINT8, image8);
- }
- } else {
- ROTATE_90(INT32, image32);
- }
- ImagingSectionLeave(&cookie);
- #undef ROTATE_90
- return imOut;
- }
- Imaging
- ImagingTranspose(Imaging imOut, Imaging imIn)
- {
- ImagingSectionCookie cookie;
- int x, y, xx, yy, xxsize, yysize;
- int xxx, yyy, xxxsize, yyysize;
- if (!imOut || !imIn || strcmp(imIn->mode, imOut->mode) != 0)
- return (Imaging) ImagingError_ModeError();
- if (imIn->xsize != imOut->ysize || imIn->ysize != imOut->xsize)
- return (Imaging) ImagingError_Mismatch();
- ImagingCopyPalette(imOut, imIn);
- #define TRANSPOSE(INT, image) \
- for (y = 0; y < imIn->ysize; y += ROTATE_CHUNK) { \
- for (x = 0; x < imIn->xsize; x += ROTATE_CHUNK) { \
- yysize = y + ROTATE_CHUNK < imIn->ysize ? y + ROTATE_CHUNK : imIn->ysize; \
- xxsize = x + ROTATE_CHUNK < imIn->xsize ? x + ROTATE_CHUNK : imIn->xsize; \
- for (yy = y; yy < yysize; yy += ROTATE_SMALL_CHUNK) { \
- for (xx = x; xx < xxsize; xx += ROTATE_SMALL_CHUNK) { \
- yyysize = yy + ROTATE_SMALL_CHUNK < imIn->ysize ? yy + ROTATE_SMALL_CHUNK : imIn->ysize; \
- xxxsize = xx + ROTATE_SMALL_CHUNK < imIn->xsize ? xx + ROTATE_SMALL_CHUNK : imIn->xsize; \
- for (yyy = yy; yyy < yyysize; yyy++) { \
- INT* in = (INT *)imIn->image[yyy]; \
- for (xxx = xx; xxx < xxxsize; xxx++) { \
- INT* out = (INT *)imOut->image[xxx]; \
- out[yyy] = in[xxx]; \
- } \
- } \
- } \
- } \
- } \
- }
- ImagingSectionEnter(&cookie);
- if (imIn->image8) {
- if (strncmp(imIn->mode, "I;16", 4) == 0) {
- TRANSPOSE(UINT16, image8);
- } else {
- TRANSPOSE(UINT8, image8);
- }
- } else {
- TRANSPOSE(INT32, image32);
- }
- ImagingSectionLeave(&cookie);
- #undef TRANSPOSE
- return imOut;
- }
- Imaging
- ImagingTransverse(Imaging imOut, Imaging imIn)
- {
- ImagingSectionCookie cookie;
- int x, y, xr, yr, xx, yy, xxsize, yysize;
- int xxx, yyy, xxxsize, yyysize;
- if (!imOut || !imIn || strcmp(imIn->mode, imOut->mode) != 0)
- return (Imaging) ImagingError_ModeError();
- if (imIn->xsize != imOut->ysize || imIn->ysize != imOut->xsize)
- return (Imaging) ImagingError_Mismatch();
- ImagingCopyPalette(imOut, imIn);
- #define TRANSVERSE(INT, image) \
- for (y = 0; y < imIn->ysize; y += ROTATE_CHUNK) { \
- for (x = 0; x < imIn->xsize; x += ROTATE_CHUNK) { \
- yysize = y + ROTATE_CHUNK < imIn->ysize ? y + ROTATE_CHUNK : imIn->ysize; \
- xxsize = x + ROTATE_CHUNK < imIn->xsize ? x + ROTATE_CHUNK : imIn->xsize; \
- for (yy = y; yy < yysize; yy += ROTATE_SMALL_CHUNK) { \
- for (xx = x; xx < xxsize; xx += ROTATE_SMALL_CHUNK) { \
- yyysize = yy + ROTATE_SMALL_CHUNK < imIn->ysize ? yy + ROTATE_SMALL_CHUNK : imIn->ysize; \
- xxxsize = xx + ROTATE_SMALL_CHUNK < imIn->xsize ? xx + ROTATE_SMALL_CHUNK : imIn->xsize; \
- yr = imIn->ysize - 1 - yy; \
- for (yyy = yy; yyy < yyysize; yyy++, yr--) { \
- INT* in = (INT *)imIn->image[yyy]; \
- xr = imIn->xsize - 1 - xx; \
- for (xxx = xx; xxx < xxxsize; xxx++, xr--) { \
- INT* out = (INT *)imOut->image[xr]; \
- out[yr] = in[xxx]; \
- } \
- } \
- } \
- } \
- } \
- }
- ImagingSectionEnter(&cookie);
- if (imIn->image8) {
- if (strncmp(imIn->mode, "I;16", 4) == 0) {
- TRANSVERSE(UINT16, image8);
- } else {
- TRANSVERSE(UINT8, image8);
- }
- } else {
- TRANSVERSE(INT32, image32);
- }
- ImagingSectionLeave(&cookie);
- #undef TRANSVERSE
- return imOut;
- }
- Imaging
- ImagingRotate180(Imaging imOut, Imaging imIn)
- {
- ImagingSectionCookie cookie;
- int x, y, xr, yr;
- if (!imOut || !imIn || strcmp(imIn->mode, imOut->mode) != 0)
- return (Imaging) ImagingError_ModeError();
- if (imIn->xsize != imOut->xsize || imIn->ysize != imOut->ysize)
- return (Imaging) ImagingError_Mismatch();
- ImagingCopyPalette(imOut, imIn);
- #define ROTATE_180(INT, image) \
- for (y = 0; y < imIn->ysize; y++, yr--) { \
- INT* in = (INT *)imIn->image[y]; \
- INT* out = (INT *)imOut->image[yr]; \
- xr = imIn->xsize-1; \
- for (x = 0; x < imIn->xsize; x++, xr--) \
- out[xr] = in[x]; \
- }
- ImagingSectionEnter(&cookie);
- yr = imIn->ysize-1;
- if (imIn->image8) {
- if (strncmp(imIn->mode, "I;16", 4) == 0) {
- ROTATE_180(UINT16, image8)
- } else {
- ROTATE_180(UINT8, image8)
- }
- } else {
- ROTATE_180(INT32, image32)
- }
- ImagingSectionLeave(&cookie);
- #undef ROTATE_180
- return imOut;
- }
- Imaging
- ImagingRotate270(Imaging imOut, Imaging imIn)
- {
- ImagingSectionCookie cookie;
- int x, y, xx, yy, yr, xxsize, yysize;
- int xxx, yyy, xxxsize, yyysize;
- if (!imOut || !imIn || strcmp(imIn->mode, imOut->mode) != 0)
- return (Imaging) ImagingError_ModeError();
- if (imIn->xsize != imOut->ysize || imIn->ysize != imOut->xsize)
- return (Imaging) ImagingError_Mismatch();
- ImagingCopyPalette(imOut, imIn);
- #define ROTATE_270(INT, image) \
- for (y = 0; y < imIn->ysize; y += ROTATE_CHUNK) { \
- for (x = 0; x < imIn->xsize; x += ROTATE_CHUNK) { \
- yysize = y + ROTATE_CHUNK < imIn->ysize ? y + ROTATE_CHUNK : imIn->ysize; \
- xxsize = x + ROTATE_CHUNK < imIn->xsize ? x + ROTATE_CHUNK : imIn->xsize; \
- for (yy = y; yy < yysize; yy += ROTATE_SMALL_CHUNK) { \
- for (xx = x; xx < xxsize; xx += ROTATE_SMALL_CHUNK) { \
- yyysize = yy + ROTATE_SMALL_CHUNK < imIn->ysize ? yy + ROTATE_SMALL_CHUNK : imIn->ysize; \
- xxxsize = xx + ROTATE_SMALL_CHUNK < imIn->xsize ? xx + ROTATE_SMALL_CHUNK : imIn->xsize; \
- yr = imIn->ysize - 1 - yy; \
- for (yyy = yy; yyy < yyysize; yyy++, yr--) { \
- INT* in = (INT *)imIn->image[yyy]; \
- for (xxx = xx; xxx < xxxsize; xxx++) { \
- INT* out = (INT *)imOut->image[xxx]; \
- out[yr] = in[xxx]; \
- } \
- } \
- } \
- } \
- } \
- }
- ImagingSectionEnter(&cookie);
- if (imIn->image8) {
- if (strncmp(imIn->mode, "I;16", 4) == 0) {
- ROTATE_270(UINT16, image8);
- } else {
- ROTATE_270(UINT8, image8);
- }
- } else {
- ROTATE_270(INT32, image32);
- }
- ImagingSectionLeave(&cookie);
- #undef ROTATE_270
- return imOut;
- }
- /* -------------------------------------------------------------------- */
- /* Transforms */
- /* transform primitives (ImagingTransformMap) */
- static int
- affine_transform(double* xout, double* yout, int x, int y, void* data)
- {
- /* full moon tonight. your compiler will generate bogus code
- for simple expressions, unless you reorganize the code, or
- install Service Pack 3 */
- double* a = (double*) data;
- double a0 = a[0]; double a1 = a[1]; double a2 = a[2];
- double a3 = a[3]; double a4 = a[4]; double a5 = a[5];
- double xin = x + 0.5;
- double yin = y + 0.5;
- xout[0] = a0*xin + a1*yin + a2;
- yout[0] = a3*xin + a4*yin + a5;
- return 1;
- }
- static int
- perspective_transform(double* xout, double* yout, int x, int y, void* data)
- {
- double* a = (double*) data;
- double a0 = a[0]; double a1 = a[1]; double a2 = a[2];
- double a3 = a[3]; double a4 = a[4]; double a5 = a[5];
- double a6 = a[6]; double a7 = a[7];
- double xin = x + 0.5;
- double yin = y + 0.5;
- xout[0] = (a0*xin + a1*yin + a2) / (a6*xin + a7*yin + 1);
- yout[0] = (a3*xin + a4*yin + a5) / (a6*xin + a7*yin + 1);
- return 1;
- }
- static int
- quad_transform(double* xout, double* yout, int x, int y, void* data)
- {
- /* quad warp: map quadrilateral to rectangle */
- double* a = (double*) data;
- double a0 = a[0]; double a1 = a[1]; double a2 = a[2]; double a3 = a[3];
- double a4 = a[4]; double a5 = a[5]; double a6 = a[6]; double a7 = a[7];
- double xin = x + 0.5;
- double yin = y + 0.5;
- xout[0] = a0 + a1*xin + a2*yin + a3*xin*yin;
- yout[0] = a4 + a5*xin + a6*yin + a7*xin*yin;
- return 1;
- }
- /* transform filters (ImagingTransformFilter) */
- static int
- nearest_filter8(void* out, Imaging im, double xin, double yin)
- {
- int x = COORD(xin);
- int y = COORD(yin);
- if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize)
- return 0;
- ((UINT8*)out)[0] = im->image8[y][x];
- return 1;
- }
- static int
- nearest_filter16(void* out, Imaging im, double xin, double yin)
- {
- int x = COORD(xin);
- int y = COORD(yin);
- if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize)
- return 0;
- memcpy(out, im->image8[y] + x * sizeof(INT16), sizeof(INT16));
- return 1;
- }
- static int
- nearest_filter32(void* out, Imaging im, double xin, double yin)
- {
- int x = COORD(xin);
- int y = COORD(yin);
- if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize)
- return 0;
- memcpy(out, &im->image32[y][x], sizeof(INT32));
- return 1;
- }
- #define XCLIP(im, x) ( ((x) < 0) ? 0 : ((x) < im->xsize) ? (x) : im->xsize-1 )
- #define YCLIP(im, y) ( ((y) < 0) ? 0 : ((y) < im->ysize) ? (y) : im->ysize-1 )
- #define BILINEAR(v, a, b, d)\
- (v = (a) + ( (b) - (a) ) * (d))
- #define BILINEAR_HEAD(type)\
- int x, y;\
- int x0, x1;\
- double v1, v2;\
- double dx, dy;\
- type* in;\
- if (xin < 0.0 || xin >= im->xsize || yin < 0.0 || yin >= im->ysize)\
- return 0;\
- xin -= 0.5;\
- yin -= 0.5;\
- x = FLOOR(xin);\
- y = FLOOR(yin);\
- dx = xin - x;\
- dy = yin - y;
- #define BILINEAR_BODY(type, image, step, offset) {\
- in = (type*) ((image)[YCLIP(im, y)] + offset);\
- x0 = XCLIP(im, x+0)*step;\
- x1 = XCLIP(im, x+1)*step;\
- BILINEAR(v1, in[x0], in[x1], dx);\
- if (y+1 >= 0 && y+1 < im->ysize) {\
- in = (type*) ((image)[y+1] + offset);\
- BILINEAR(v2, in[x0], in[x1], dx);\
- } else\
- v2 = v1;\
- BILINEAR(v1, v1, v2, dy);\
- }
- static int
- bilinear_filter8(void* out, Imaging im, double xin, double yin)
- {
- BILINEAR_HEAD(UINT8);
- BILINEAR_BODY(UINT8, im->image8, 1, 0);
- ((UINT8*)out)[0] = (UINT8) v1;
- return 1;
- }
- static int
- bilinear_filter32I(void* out, Imaging im, double xin, double yin)
- {
- INT32 k;
- BILINEAR_HEAD(INT32);
- BILINEAR_BODY(INT32, im->image32, 1, 0);
- k = v1;
- memcpy(out, &k, sizeof(k));
- return 1;
- }
- static int
- bilinear_filter32F(void* out, Imaging im, double xin, double yin)
- {
- FLOAT32 k;
- BILINEAR_HEAD(FLOAT32);
- BILINEAR_BODY(FLOAT32, im->image32, 1, 0);
- k = v1;
- memcpy(out, &k, sizeof(k));
- return 1;
- }
- static int
- bilinear_filter32LA(void* out, Imaging im, double xin, double yin)
- {
- BILINEAR_HEAD(UINT8);
- BILINEAR_BODY(UINT8, im->image, 4, 0);
- ((UINT8*)out)[0] = (UINT8) v1;
- ((UINT8*)out)[1] = (UINT8) v1;
- ((UINT8*)out)[2] = (UINT8) v1;
- BILINEAR_BODY(UINT8, im->image, 4, 3);
- ((UINT8*)out)[3] = (UINT8) v1;
- return 1;
- }
- static int
- bilinear_filter32RGB(void* out, Imaging im, double xin, double yin)
- {
- int b;
- BILINEAR_HEAD(UINT8);
- for (b = 0; b < im->bands; b++) {
- BILINEAR_BODY(UINT8, im->image, 4, b);
- ((UINT8*)out)[b] = (UINT8) v1;
- }
- return 1;
- }
- #undef BILINEAR
- #undef BILINEAR_HEAD
- #undef BILINEAR_BODY
- #define BICUBIC(v, v1, v2, v3, v4, d) {\
- double p1 = v2;\
- double p2 = -v1 + v3;\
- double p3 = 2*(v1 - v2) + v3 - v4;\
- double p4 = -v1 + v2 - v3 + v4;\
- v = p1 + (d)*(p2 + (d)*(p3 + (d)*p4));\
- }
- #define BICUBIC_HEAD(type)\
- int x = FLOOR(xin);\
- int y = FLOOR(yin);\
- int x0, x1, x2, x3;\
- double v1, v2, v3, v4;\
- double dx, dy;\
- type* in;\
- if (xin < 0.0 || xin >= im->xsize || yin < 0.0 || yin >= im->ysize)\
- return 0;\
- xin -= 0.5;\
- yin -= 0.5;\
- x = FLOOR(xin);\
- y = FLOOR(yin);\
- dx = xin - x;\
- dy = yin - y;\
- x--; y--;
- #define BICUBIC_BODY(type, image, step, offset) {\
- in = (type*) ((image)[YCLIP(im, y)] + offset);\
- x0 = XCLIP(im, x+0)*step;\
- x1 = XCLIP(im, x+1)*step;\
- x2 = XCLIP(im, x+2)*step;\
- x3 = XCLIP(im, x+3)*step;\
- BICUBIC(v1, in[x0], in[x1], in[x2], in[x3], dx);\
- if (y+1 >= 0 && y+1 < im->ysize) {\
- in = (type*) ((image)[y+1] + offset);\
- BICUBIC(v2, in[x0], in[x1], in[x2], in[x3], dx);\
- } else\
- v2 = v1;\
- if (y+2 >= 0 && y+2 < im->ysize) {\
- in = (type*) ((image)[y+2] + offset);\
- BICUBIC(v3, in[x0], in[x1], in[x2], in[x3], dx);\
- } else\
- v3 = v2;\
- if (y+3 >= 0 && y+3 < im->ysize) {\
- in = (type*) ((image)[y+3] + offset);\
- BICUBIC(v4, in[x0], in[x1], in[x2], in[x3], dx);\
- } else\
- v4 = v3;\
- BICUBIC(v1, v1, v2, v3, v4, dy);\
- }
- static int
- bicubic_filter8(void* out, Imaging im, double xin, double yin)
- {
- BICUBIC_HEAD(UINT8);
- BICUBIC_BODY(UINT8, im->image8, 1, 0);
- if (v1 <= 0.0)
- ((UINT8*)out)[0] = 0;
- else if (v1 >= 255.0)
- ((UINT8*)out)[0] = 255;
- else
- ((UINT8*)out)[0] = (UINT8) v1;
- return 1;
- }
- static int
- bicubic_filter32I(void* out, Imaging im, double xin, double yin)
- {
- INT32 k;
- BICUBIC_HEAD(INT32);
- BICUBIC_BODY(INT32, im->image32, 1, 0);
- k = v1;
- memcpy(out, &k, sizeof(k));
- return 1;
- }
- static int
- bicubic_filter32F(void* out, Imaging im, double xin, double yin)
- {
- FLOAT32 k;
- BICUBIC_HEAD(FLOAT32);
- BICUBIC_BODY(FLOAT32, im->image32, 1, 0);
- k = v1;
- memcpy(out, &k, sizeof(k));
- return 1;
- }
- static int
- bicubic_filter32LA(void* out, Imaging im, double xin, double yin)
- {
- BICUBIC_HEAD(UINT8);
- BICUBIC_BODY(UINT8, im->image, 4, 0);
- if (v1 <= 0.0) {
- ((UINT8*)out)[0] = 0;
- ((UINT8*)out)[1] = 0;
- ((UINT8*)out)[2] = 0;
- } else if (v1 >= 255.0) {
- ((UINT8*)out)[0] = 255;
- ((UINT8*)out)[1] = 255;
- ((UINT8*)out)[2] = 255;
- } else {
- ((UINT8*)out)[0] = (UINT8) v1;
- ((UINT8*)out)[1] = (UINT8) v1;
- ((UINT8*)out)[2] = (UINT8) v1;
- }
- BICUBIC_BODY(UINT8, im->image, 4, 3);
- if (v1 <= 0.0)
- ((UINT8*)out)[3] = 0;
- else if (v1 >= 255.0)
- ((UINT8*)out)[3] = 255;
- else
- ((UINT8*)out)[3] = (UINT8) v1;
- return 1;
- }
- static int
- bicubic_filter32RGB(void* out, Imaging im, double xin, double yin)
- {
- int b;
- BICUBIC_HEAD(UINT8);
- for (b = 0; b < im->bands; b++) {
- BICUBIC_BODY(UINT8, im->image, 4, b);
- if (v1 <= 0.0)
- ((UINT8*)out)[b] = 0;
- else if (v1 >= 255.0)
- ((UINT8*)out)[b] = 255;
- else
- ((UINT8*)out)[b] = (UINT8) v1;
- }
- return 1;
- }
- #undef BICUBIC
- #undef BICUBIC_HEAD
- #undef BICUBIC_BODY
- static ImagingTransformFilter
- getfilter(Imaging im, int filterid)
- {
- switch (filterid) {
- case IMAGING_TRANSFORM_NEAREST:
- if (im->image8)
- switch (im->type) {
- case IMAGING_TYPE_UINT8:
- return nearest_filter8;
- case IMAGING_TYPE_SPECIAL:
- switch (im->pixelsize) {
- case 1:
- return nearest_filter8;
- case 2:
- return nearest_filter16;
- case 4:
- return nearest_filter32;
- }
- }
- else
- return nearest_filter32;
- break;
- case IMAGING_TRANSFORM_BILINEAR:
- if (im->image8)
- return bilinear_filter8;
- else if (im->image32) {
- switch (im->type) {
- case IMAGING_TYPE_UINT8:
- if (im->bands == 2)
- return bilinear_filter32LA;
- else
- return bilinear_filter32RGB;
- case IMAGING_TYPE_INT32:
- return bilinear_filter32I;
- case IMAGING_TYPE_FLOAT32:
- return bilinear_filter32F;
- }
- }
- break;
- case IMAGING_TRANSFORM_BICUBIC:
- if (im->image8)
- return bicubic_filter8;
- else if (im->image32) {
- switch (im->type) {
- case IMAGING_TYPE_UINT8:
- if (im->bands == 2)
- return bicubic_filter32LA;
- else
- return bicubic_filter32RGB;
- case IMAGING_TYPE_INT32:
- return bicubic_filter32I;
- case IMAGING_TYPE_FLOAT32:
- return bicubic_filter32F;
- }
- }
- break;
- }
- /* no such filter */
- return NULL;
- }
- /* transformation engines */
- Imaging
- ImagingGenericTransform(
- Imaging imOut, Imaging imIn, int x0, int y0, int x1, int y1,
- ImagingTransformMap transform, void* transform_data,
- int filterid, int fill)
- {
- /* slow generic transformation. use ImagingTransformAffine or
- ImagingScaleAffine where possible. */
- ImagingSectionCookie cookie;
- int x, y;
- char *out;
- double xx, yy;
- ImagingTransformFilter filter = getfilter(imIn, filterid);
- if (!filter)
- return (Imaging) ImagingError_ValueError("bad filter number");
- if (!imOut || !imIn || strcmp(imIn->mode, imOut->mode) != 0)
- return (Imaging) ImagingError_ModeError();
- ImagingCopyPalette(imOut, imIn);
- ImagingSectionEnter(&cookie);
- if (x0 < 0)
- x0 = 0;
- if (y0 < 0)
- y0 = 0;
- if (x1 > imOut->xsize)
- x1 = imOut->xsize;
- if (y1 > imOut->ysize)
- y1 = imOut->ysize;
- for (y = y0; y < y1; y++) {
- out = imOut->image[y] + x0*imOut->pixelsize;
- for (x = x0; x < x1; x++) {
- if ( ! transform(&xx, &yy, x-x0, y-y0, transform_data) ||
- ! filter(out, imIn, xx, yy)) {
- if (fill)
- memset(out, 0, imOut->pixelsize);
- }
- out += imOut->pixelsize;
- }
- }
- ImagingSectionLeave(&cookie);
- return imOut;
- }
- static Imaging
- ImagingScaleAffine(Imaging imOut, Imaging imIn,
- int x0, int y0, int x1, int y1,
- double a[6], int fill)
- {
- /* scale, nearest neighbour resampling */
- ImagingSectionCookie cookie;
- int x, y;
- int xin;
- double xo, yo;
- int xmin, xmax;
- int *xintab;
- if (!imOut || !imIn || strcmp(imIn->mode, imOut->mode) != 0)
- return (Imaging) ImagingError_ModeError();
- ImagingCopyPalette(imOut, imIn);
- if (x0 < 0)
- x0 = 0;
- if (y0 < 0)
- y0 = 0;
- if (x1 > imOut->xsize)
- x1 = imOut->xsize;
- if (y1 > imOut->ysize)
- y1 = imOut->ysize;
- /* malloc check ok, uses calloc for overflow */
- xintab = (int*) calloc(imOut->xsize, sizeof(int));
- if (!xintab) {
- ImagingDelete(imOut);
- return (Imaging) ImagingError_MemoryError();
- }
- xo = a[2] + a[0] * 0.5;
- yo = a[5] + a[4] * 0.5;
- xmin = x1;
- xmax = x0;
- /* Pretabulate horizontal pixel positions */
- for (x = x0; x < x1; x++) {
- xin = COORD(xo);
- if (xin >= 0 && xin < (int) imIn->xsize) {
- xmax = x+1;
- if (x < xmin)
- xmin = x;
- xintab[x] = xin;
- }
- xo += a[0];
- }
- #define AFFINE_SCALE(pixel, image)\
- for (y = y0; y < y1; y++) {\
- int yi = COORD(yo);\
- pixel *in, *out;\
- out = imOut->image[y];\
- if (fill && x1 > x0)\
- memset(out+x0, 0, (x1-x0)*sizeof(pixel));\
- if (yi >= 0 && yi < imIn->ysize) {\
- in = imIn->image[yi];\
- for (x = xmin; x < xmax; x++)\
- out[x] = in[xintab[x]];\
- }\
- yo += a[4];\
- }
- ImagingSectionEnter(&cookie);
- if (imIn->image8) {
- AFFINE_SCALE(UINT8, image8);
- } else {
- AFFINE_SCALE(INT32, image32);
- }
- ImagingSectionLeave(&cookie);
- #undef AFFINE_SCALE
- free(xintab);
- return imOut;
- }
- static inline int
- check_fixed(double a[6], int x, int y)
- {
- return (fabs(x*a[0] + y*a[1] + a[2]) < 32768.0 &&
- fabs(x*a[3] + y*a[4] + a[5]) < 32768.0);
- }
- static inline Imaging
- affine_fixed(Imaging imOut, Imaging imIn,
- int x0, int y0, int x1, int y1,
- double a[6], int filterid, int fill)
- {
- /* affine transform, nearest neighbour resampling, fixed point
- arithmetics */
- ImagingSectionCookie cookie;
- int x, y;
- int xin, yin;
- int xsize, ysize;
- int xx, yy;
- int a0, a1, a2, a3, a4, a5;
- ImagingCopyPalette(imOut, imIn);
- xsize = (int) imIn->xsize;
- ysize = (int) imIn->ysize;
- /* use 16.16 fixed point arithmetics */
- #define FIX(v) FLOOR((v)*65536.0 + 0.5)
- a0 = FIX(a[0]); a1 = FIX(a[1]);
- a3 = FIX(a[3]); a4 = FIX(a[4]);
- a2 = FIX(a[2] + a[0] * 0.5 + a[1] * 0.5);
- a5 = FIX(a[5] + a[3] * 0.5 + a[4] * 0.5);
- #undef FIX
- #define AFFINE_TRANSFORM_FIXED(pixel, image)\
- for (y = y0; y < y1; y++) {\
- pixel *out;\
- xx = a2;\
- yy = a5;\
- out = imOut->image[y];\
- if (fill && x1 > x0)\
- memset(out+x0, 0, (x1-x0)*sizeof(pixel));\
- for (x = x0; x < x1; x++, out++) {\
- xin = xx >> 16;\
- if (xin >= 0 && xin < xsize) {\
- yin = yy >> 16;\
- if (yin >= 0 && yin < ysize)\
- *out = imIn->image[yin][xin];\
- }\
- xx += a0;\
- yy += a3;\
- }\
- a2 += a1;\
- a5 += a4;\
- }
- ImagingSectionEnter(&cookie);
- if (imIn->image8)
- AFFINE_TRANSFORM_FIXED(UINT8, image8)
- else
- AFFINE_TRANSFORM_FIXED(INT32, image32)
- ImagingSectionLeave(&cookie);
- #undef AFFINE_TRANSFORM_FIXED
- return imOut;
- }
- Imaging
- ImagingTransformAffine(Imaging imOut, Imaging imIn,
- int x0, int y0, int x1, int y1,
- double a[6], int filterid, int fill)
- {
- /* affine transform, nearest neighbour resampling, floating point
- arithmetics*/
- ImagingSectionCookie cookie;
- int x, y;
- int xin, yin;
- int xsize, ysize;
- double xx, yy;
- double xo, yo;
- if (filterid || imIn->type == IMAGING_TYPE_SPECIAL) {
- return ImagingGenericTransform(
- imOut, imIn,
- x0, y0, x1, y1,
- affine_transform, a,
- filterid, fill);
- }
- if (a[1] == 0 && a[3] == 0) {
- /* Scaling */
- return ImagingScaleAffine(imOut, imIn, x0, y0, x1, y1, a, fill);
- }
- if (!imOut || !imIn || strcmp(imIn->mode, imOut->mode) != 0)
- return (Imaging) ImagingError_ModeError();
- if (x0 < 0)
- x0 = 0;
- if (y0 < 0)
- y0 = 0;
- if (x1 > imOut->xsize)
- x1 = imOut->xsize;
- if (y1 > imOut->ysize)
- y1 = imOut->ysize;
- /* translate all four corners to check if they are within the
- range that can be represented by the fixed point arithmetics */
- if (check_fixed(a, 0, 0) && check_fixed(a, x1-x0, y1-y0) &&
- check_fixed(a, 0, y1-y0) && check_fixed(a, x1-x0, 0))
- return affine_fixed(imOut, imIn, x0, y0, x1, y1, a, filterid, fill);
- /* FIXME: cannot really think of any reasonable case when the
- following code is used. maybe we should fall back on the slow
- generic transform engine in this case? */
- ImagingCopyPalette(imOut, imIn);
- xsize = (int) imIn->xsize;
- ysize = (int) imIn->ysize;
- xo = a[2] + a[1] * 0.5 + a[0] * 0.5;
- yo = a[5] + a[4] * 0.5 + a[3] * 0.5;
- #define AFFINE_TRANSFORM(pixel, image)\
- for (y = y0; y < y1; y++) {\
- pixel *out;\
- xx = xo;\
- yy = yo;\
- out = imOut->image[y];\
- if (fill && x1 > x0)\
- memset(out+x0, 0, (x1-x0)*sizeof(pixel));\
- for (x = x0; x < x1; x++, out++) {\
- xin = COORD(xx);\
- if (xin >= 0 && xin < xsize) {\
- yin = COORD(yy);\
- if (yin >= 0 && yin < ysize)\
- *out = imIn->image[yin][xin];\
- }\
- xx += a[0];\
- yy += a[3];\
- }\
- xo += a[1];\
- yo += a[4];\
- }
- ImagingSectionEnter(&cookie);
- if (imIn->image8)
- AFFINE_TRANSFORM(UINT8, image8)
- else
- AFFINE_TRANSFORM(INT32, image32)
- ImagingSectionLeave(&cookie);
- #undef AFFINE_TRANSFORM
- return imOut;
- }
- Imaging
- ImagingTransform(Imaging imOut, Imaging imIn, int method,
- int x0, int y0, int x1, int y1,
- double a[8], int filterid, int fill)
- {
- ImagingTransformMap transform;
- switch(method) {
- case IMAGING_TRANSFORM_AFFINE:
- return ImagingTransformAffine(
- imOut, imIn, x0, y0, x1, y1, a, filterid, fill);
- break;
- case IMAGING_TRANSFORM_PERSPECTIVE:
- transform = perspective_transform;
- break;
- case IMAGING_TRANSFORM_QUAD:
- transform = quad_transform;
- break;
- default:
- return (Imaging) ImagingError_ValueError("bad transform method");
- }
- return ImagingGenericTransform(
- imOut, imIn,
- x0, y0, x1, y1,
- transform, a, filterid, fill);
- }
|