123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628 |
- /*
- * The Python Imaging Library
- * $Id$
- *
- * paste image on another image
- *
- * history:
- * 96-03-27 fl Created
- * 96-07-16 fl Support "1", "L" and "RGBA" masks
- * 96-08-16 fl Merged with opaque paste
- * 97-01-17 fl Faster blending, added support for RGBa images
- * 97-08-27 fl Faster masking for 32-bit images
- * 98-02-02 fl Fixed MULDIV255 macro for gcc
- * 99-02-02 fl Added "RGBa" mask support
- * 99-02-06 fl Rewritten. Added support for masked fill operations.
- * 99-12-08 fl Fixed matte fill.
- *
- * Copyright (c) Fredrik Lundh 1996-97.
- * Copyright (c) Secret Labs AB 1997-99.
- *
- * See the README file for information on usage and redistribution.
- */
- #include "Imaging.h"
- static inline void
- paste(
- Imaging imOut,
- Imaging imIn,
- int dx,
- int dy,
- int sx,
- int sy,
- int xsize,
- int ysize,
- int pixelsize) {
- /* paste opaque region */
- int y;
- dx *= pixelsize;
- sx *= pixelsize;
- xsize *= pixelsize;
- for (y = 0; y < ysize; y++) {
- memcpy(imOut->image[y + dy] + dx, imIn->image[y + sy] + sx, xsize);
- }
- }
- static inline void
- paste_mask_1(
- Imaging imOut,
- Imaging imIn,
- Imaging imMask,
- int dx,
- int dy,
- int sx,
- int sy,
- int xsize,
- int ysize,
- int pixelsize) {
- /* paste with mode "1" mask */
- int x, y;
- if (imOut->image8) {
- for (y = 0; y < ysize; y++) {
- UINT8 *out = imOut->image8[y + dy] + dx;
- UINT8 *in = imIn->image8[y + sy] + sx;
- UINT8 *mask = imMask->image8[y + sy] + sx;
- for (x = 0; x < xsize; x++) {
- if (*mask++) {
- *out = *in;
- }
- out++, in++;
- }
- }
- } else {
- for (y = 0; y < ysize; y++) {
- INT32 *out = imOut->image32[y + dy] + dx;
- INT32 *in = imIn->image32[y + sy] + sx;
- UINT8 *mask = imMask->image8[y + sy] + sx;
- for (x = 0; x < xsize; x++) {
- if (*mask++) {
- *out = *in;
- }
- out++, in++;
- }
- }
- }
- }
- static inline void
- paste_mask_L(
- Imaging imOut,
- Imaging imIn,
- Imaging imMask,
- int dx,
- int dy,
- int sx,
- int sy,
- int xsize,
- int ysize,
- int pixelsize) {
- /* paste with mode "L" matte */
- int x, y;
- unsigned int tmp1;
- if (imOut->image8) {
- for (y = 0; y < ysize; y++) {
- UINT8 *out = imOut->image8[y + dy] + dx;
- UINT8 *in = imIn->image8[y + sy] + sx;
- UINT8 *mask = imMask->image8[y + sy] + sx;
- for (x = 0; x < xsize; x++) {
- *out = BLEND(*mask, *out, *in, tmp1);
- out++, in++, mask++;
- }
- }
- } else {
- for (y = 0; y < ysize; y++) {
- UINT8 *out = (UINT8 *)(imOut->image32[y + dy] + dx);
- UINT8 *in = (UINT8 *)(imIn->image32[y + sy] + sx);
- UINT8 *mask = (UINT8 *)(imMask->image8[y + sy] + sx);
- for (x = 0; x < xsize; x++) {
- UINT8 a = mask[0];
- out[0] = BLEND(a, out[0], in[0], tmp1);
- out[1] = BLEND(a, out[1], in[1], tmp1);
- out[2] = BLEND(a, out[2], in[2], tmp1);
- out[3] = BLEND(a, out[3], in[3], tmp1);
- out += 4;
- in += 4;
- mask++;
- }
- }
- }
- }
- static inline void
- paste_mask_RGBA(
- Imaging imOut,
- Imaging imIn,
- Imaging imMask,
- int dx,
- int dy,
- int sx,
- int sy,
- int xsize,
- int ysize,
- int pixelsize) {
- /* paste with mode "RGBA" matte */
- int x, y;
- unsigned int tmp1;
- if (imOut->image8) {
- for (y = 0; y < ysize; y++) {
- UINT8 *out = imOut->image8[y + dy] + dx;
- UINT8 *in = imIn->image8[y + sy] + sx;
- UINT8 *mask = (UINT8 *)imMask->image[y + sy] + sx * 4 + 3;
- for (x = 0; x < xsize; x++) {
- *out = BLEND(*mask, *out, *in, tmp1);
- out++, in++, mask += 4;
- }
- }
- } else {
- for (y = 0; y < ysize; y++) {
- UINT8 *out = (UINT8 *)(imOut->image32[y + dy] + dx);
- UINT8 *in = (UINT8 *)(imIn->image32[y + sy] + sx);
- UINT8 *mask = (UINT8 *)(imMask->image32[y + sy] + sx);
- for (x = 0; x < xsize; x++) {
- UINT8 a = mask[3];
- out[0] = BLEND(a, out[0], in[0], tmp1);
- out[1] = BLEND(a, out[1], in[1], tmp1);
- out[2] = BLEND(a, out[2], in[2], tmp1);
- out[3] = BLEND(a, out[3], in[3], tmp1);
- out += 4;
- in += 4;
- mask += 4;
- }
- }
- }
- }
- static inline void
- paste_mask_RGBa(
- Imaging imOut,
- Imaging imIn,
- Imaging imMask,
- int dx,
- int dy,
- int sx,
- int sy,
- int xsize,
- int ysize,
- int pixelsize) {
- /* paste with mode "RGBa" matte */
- int x, y;
- unsigned int tmp1;
- if (imOut->image8) {
- for (y = 0; y < ysize; y++) {
- UINT8 *out = imOut->image8[y + dy] + dx;
- UINT8 *in = imIn->image8[y + sy] + sx;
- UINT8 *mask = (UINT8 *)imMask->image[y + sy] + sx * 4 + 3;
- for (x = 0; x < xsize; x++) {
- *out = PREBLEND(*mask, *out, *in, tmp1);
- out++, in++, mask += 4;
- }
- }
- } else {
- for (y = 0; y < ysize; y++) {
- UINT8 *out = (UINT8 *)(imOut->image32[y + dy] + dx);
- UINT8 *in = (UINT8 *)(imIn->image32[y + sy] + sx);
- UINT8 *mask = (UINT8 *)(imMask->image32[y + sy] + sx);
- for (x = 0; x < xsize; x++) {
- UINT8 a = mask[3];
- out[0] = PREBLEND(a, out[0], in[0], tmp1);
- out[1] = PREBLEND(a, out[1], in[1], tmp1);
- out[2] = PREBLEND(a, out[2], in[2], tmp1);
- out[3] = PREBLEND(a, out[3], in[3], tmp1);
- out += 4;
- in += 4;
- mask += 4;
- }
- }
- }
- }
- int
- ImagingPaste(
- Imaging imOut, Imaging imIn, Imaging imMask, int dx0, int dy0, int dx1, int dy1) {
- int xsize, ysize;
- int pixelsize;
- int sx0, sy0;
- ImagingSectionCookie cookie;
- if (!imOut || !imIn) {
- (void)ImagingError_ModeError();
- return -1;
- }
- pixelsize = imOut->pixelsize;
- xsize = dx1 - dx0;
- ysize = dy1 - dy0;
- if (xsize != imIn->xsize || ysize != imIn->ysize || pixelsize != imIn->pixelsize) {
- (void)ImagingError_Mismatch();
- return -1;
- }
- if (imMask && (xsize != imMask->xsize || ysize != imMask->ysize)) {
- (void)ImagingError_Mismatch();
- return -1;
- }
- /* Determine which region to copy */
- sx0 = sy0 = 0;
- if (dx0 < 0) {
- xsize += dx0, sx0 = -dx0, dx0 = 0;
- }
- if (dx0 + xsize > imOut->xsize) {
- xsize = imOut->xsize - dx0;
- }
- if (dy0 < 0) {
- ysize += dy0, sy0 = -dy0, dy0 = 0;
- }
- if (dy0 + ysize > imOut->ysize) {
- ysize = imOut->ysize - dy0;
- }
- if (xsize <= 0 || ysize <= 0) {
- return 0;
- }
- if (!imMask) {
- ImagingSectionEnter(&cookie);
- paste(imOut, imIn, dx0, dy0, sx0, sy0, xsize, ysize, pixelsize);
- ImagingSectionLeave(&cookie);
- } else if (strcmp(imMask->mode, "1") == 0) {
- ImagingSectionEnter(&cookie);
- paste_mask_1(imOut, imIn, imMask, dx0, dy0, sx0, sy0, xsize, ysize, pixelsize);
- ImagingSectionLeave(&cookie);
- } else if (strcmp(imMask->mode, "L") == 0) {
- ImagingSectionEnter(&cookie);
- paste_mask_L(imOut, imIn, imMask, dx0, dy0, sx0, sy0, xsize, ysize, pixelsize);
- ImagingSectionLeave(&cookie);
- } else if (strcmp(imMask->mode, "LA") == 0 || strcmp(imMask->mode, "RGBA") == 0) {
- ImagingSectionEnter(&cookie);
- paste_mask_RGBA(
- imOut, imIn, imMask, dx0, dy0, sx0, sy0, xsize, ysize, pixelsize);
- ImagingSectionLeave(&cookie);
- } else if (strcmp(imMask->mode, "RGBa") == 0) {
- ImagingSectionEnter(&cookie);
- paste_mask_RGBa(
- imOut, imIn, imMask, dx0, dy0, sx0, sy0, xsize, ysize, pixelsize);
- ImagingSectionLeave(&cookie);
- } else {
- (void)ImagingError_ValueError("bad transparency mask");
- return -1;
- }
- return 0;
- }
- static inline void
- fill(
- Imaging imOut,
- const void *ink_,
- int dx,
- int dy,
- int xsize,
- int ysize,
- int pixelsize) {
- /* fill opaque region */
- int x, y;
- UINT8 ink8 = 0;
- INT32 ink32 = 0L;
- memcpy(&ink32, ink_, pixelsize);
- memcpy(&ink8, ink_, sizeof(ink8));
- if (imOut->image8 || ink32 == 0L) {
- dx *= pixelsize;
- xsize *= pixelsize;
- for (y = 0; y < ysize; y++) {
- memset(imOut->image[y + dy] + dx, ink8, xsize);
- }
- } else {
- for (y = 0; y < ysize; y++) {
- INT32 *out = imOut->image32[y + dy] + dx;
- for (x = 0; x < xsize; x++) {
- out[x] = ink32;
- }
- }
- }
- }
- static inline void
- fill_mask_1(
- Imaging imOut,
- const void *ink_,
- Imaging imMask,
- int dx,
- int dy,
- int sx,
- int sy,
- int xsize,
- int ysize,
- int pixelsize) {
- /* fill with mode "1" mask */
- int x, y;
- UINT8 ink8 = 0;
- INT32 ink32 = 0L;
- memcpy(&ink32, ink_, pixelsize);
- memcpy(&ink8, ink_, sizeof(ink8));
- if (imOut->image8) {
- for (y = 0; y < ysize; y++) {
- UINT8 *out = imOut->image8[y + dy] + dx;
- UINT8 *mask = imMask->image8[y + sy] + sx;
- for (x = 0; x < xsize; x++) {
- if (*mask++) {
- *out = ink8;
- }
- out++;
- }
- }
- } else {
- for (y = 0; y < ysize; y++) {
- INT32 *out = imOut->image32[y + dy] + dx;
- UINT8 *mask = imMask->image8[y + sy] + sx;
- for (x = 0; x < xsize; x++) {
- if (*mask++) {
- *out = ink32;
- }
- out++;
- }
- }
- }
- }
- static inline void
- fill_mask_L(
- Imaging imOut,
- const UINT8 *ink,
- Imaging imMask,
- int dx,
- int dy,
- int sx,
- int sy,
- int xsize,
- int ysize,
- int pixelsize) {
- /* fill with mode "L" matte */
- int x, y, i;
- unsigned int tmp1;
- if (imOut->image8) {
- for (y = 0; y < ysize; y++) {
- UINT8 *out = imOut->image8[y + dy] + dx;
- if (strncmp(imOut->mode, "I;16", 4) == 0) {
- out += dx;
- }
- UINT8 *mask = imMask->image8[y + sy] + sx;
- for (x = 0; x < xsize; x++) {
- *out = BLEND(*mask, *out, ink[0], tmp1);
- if (strncmp(imOut->mode, "I;16", 4) == 0) {
- out++;
- *out = BLEND(*mask, *out, ink[1], tmp1);
- }
- out++, mask++;
- }
- }
- } else {
- int alpha_channel = strcmp(imOut->mode, "RGBa") == 0 ||
- strcmp(imOut->mode, "RGBA") == 0 ||
- strcmp(imOut->mode, "La") == 0 ||
- strcmp(imOut->mode, "LA") == 0 ||
- strcmp(imOut->mode, "PA") == 0;
- for (y = 0; y < ysize; y++) {
- UINT8 *out = (UINT8 *)imOut->image[y + dy] + dx * pixelsize;
- UINT8 *mask = (UINT8 *)imMask->image[y + sy] + sx;
- for (x = 0; x < xsize; x++) {
- for (i = 0; i < pixelsize; i++) {
- UINT8 channel_mask = *mask;
- if (alpha_channel && i != 3 && channel_mask != 0) {
- channel_mask =
- 255 - (255 - channel_mask) * (1 - (255 - out[3]) / 255);
- }
- out[i] = BLEND(channel_mask, out[i], ink[i], tmp1);
- }
- out += pixelsize;
- mask++;
- }
- }
- }
- }
- static inline void
- fill_mask_RGBA(
- Imaging imOut,
- const UINT8 *ink,
- Imaging imMask,
- int dx,
- int dy,
- int sx,
- int sy,
- int xsize,
- int ysize,
- int pixelsize) {
- /* fill with mode "RGBA" matte */
- int x, y, i;
- unsigned int tmp1;
- if (imOut->image8) {
- sx = sx * 4 + 3;
- for (y = 0; y < ysize; y++) {
- UINT8 *out = imOut->image8[y + dy] + dx;
- UINT8 *mask = (UINT8 *)imMask->image[y + sy] + sx;
- for (x = 0; x < xsize; x++) {
- *out = BLEND(*mask, *out, ink[0], tmp1);
- out++, mask += 4;
- }
- }
- } else {
- dx *= pixelsize;
- sx = sx * 4 + 3;
- for (y = 0; y < ysize; y++) {
- UINT8 *out = (UINT8 *)imOut->image[y + dy] + dx;
- UINT8 *mask = (UINT8 *)imMask->image[y + sy] + sx;
- for (x = 0; x < xsize; x++) {
- for (i = 0; i < pixelsize; i++) {
- *out = BLEND(*mask, *out, ink[i], tmp1);
- out++;
- }
- mask += 4;
- }
- }
- }
- }
- static inline void
- fill_mask_RGBa(
- Imaging imOut,
- const UINT8 *ink,
- Imaging imMask,
- int dx,
- int dy,
- int sx,
- int sy,
- int xsize,
- int ysize,
- int pixelsize) {
- /* fill with mode "RGBa" matte */
- int x, y, i;
- unsigned int tmp1;
- if (imOut->image8) {
- sx = sx * 4 + 3;
- for (y = 0; y < ysize; y++) {
- UINT8 *out = imOut->image8[y + dy] + dx;
- UINT8 *mask = (UINT8 *)imMask->image[y + sy] + sx;
- for (x = 0; x < xsize; x++) {
- *out = PREBLEND(*mask, *out, ink[0], tmp1);
- out++, mask += 4;
- }
- }
- } else {
- dx *= pixelsize;
- sx = sx * 4 + 3;
- for (y = 0; y < ysize; y++) {
- UINT8 *out = (UINT8 *)imOut->image[y + dy] + dx;
- UINT8 *mask = (UINT8 *)imMask->image[y + sy] + sx;
- for (x = 0; x < xsize; x++) {
- for (i = 0; i < pixelsize; i++) {
- *out = PREBLEND(*mask, *out, ink[i], tmp1);
- out++;
- }
- mask += 4;
- }
- }
- }
- }
- int
- ImagingFill2(
- Imaging imOut,
- const void *ink,
- Imaging imMask,
- int dx0,
- int dy0,
- int dx1,
- int dy1) {
- ImagingSectionCookie cookie;
- int xsize, ysize;
- int pixelsize;
- int sx0, sy0;
- if (!imOut || !ink) {
- (void)ImagingError_ModeError();
- return -1;
- }
- pixelsize = imOut->pixelsize;
- xsize = dx1 - dx0;
- ysize = dy1 - dy0;
- if (imMask && (xsize != imMask->xsize || ysize != imMask->ysize)) {
- (void)ImagingError_Mismatch();
- return -1;
- }
- /* Determine which region to fill */
- sx0 = sy0 = 0;
- if (dx0 < 0) {
- xsize += dx0, sx0 = -dx0, dx0 = 0;
- }
- if (dx0 + xsize > imOut->xsize) {
- xsize = imOut->xsize - dx0;
- }
- if (dy0 < 0) {
- ysize += dy0, sy0 = -dy0, dy0 = 0;
- }
- if (dy0 + ysize > imOut->ysize) {
- ysize = imOut->ysize - dy0;
- }
- if (xsize <= 0 || ysize <= 0) {
- return 0;
- }
- if (!imMask) {
- ImagingSectionEnter(&cookie);
- fill(imOut, ink, dx0, dy0, xsize, ysize, pixelsize);
- ImagingSectionLeave(&cookie);
- } else if (strcmp(imMask->mode, "1") == 0) {
- ImagingSectionEnter(&cookie);
- fill_mask_1(imOut, ink, imMask, dx0, dy0, sx0, sy0, xsize, ysize, pixelsize);
- ImagingSectionLeave(&cookie);
- } else if (strcmp(imMask->mode, "L") == 0) {
- ImagingSectionEnter(&cookie);
- fill_mask_L(imOut, ink, imMask, dx0, dy0, sx0, sy0, xsize, ysize, pixelsize);
- ImagingSectionLeave(&cookie);
- } else if (strcmp(imMask->mode, "RGBA") == 0) {
- ImagingSectionEnter(&cookie);
- fill_mask_RGBA(imOut, ink, imMask, dx0, dy0, sx0, sy0, xsize, ysize, pixelsize);
- ImagingSectionLeave(&cookie);
- } else if (strcmp(imMask->mode, "RGBa") == 0) {
- ImagingSectionEnter(&cookie);
- fill_mask_RGBa(imOut, ink, imMask, dx0, dy0, sx0, sy0, xsize, ysize, pixelsize);
- ImagingSectionLeave(&cookie);
- } else {
- (void)ImagingError_ValueError("bad transparency mask");
- return -1;
- }
- return 0;
- }
|