static void composeRow(int const originleft, struct pam * const underlayPamP, struct pam * const overlayPamP, bool const invertAlpha, float const masterOpacity, struct pam * const composedPamP, enum sampleScale const sampleScale, enum alphaMix const alphaMix, const tuple * const underlayTuplerow, const tuple * const overlayTuplerow, const tuplen * const alphaTuplerown, tuple * const composedTuplerow) { /*---------------------------------------------------------------------------- Create a row of tuples ('composedTupleRow') which is the composition of row 'overlayTupleRow' laid over row 'underlayTupleRow', starting at column 'originLeft'. *underlayPamP and *overlayPamP describe the respective tuple rows. -----------------------------------------------------------------------------*/ unsigned int col; for (col = 0; col < composedPamP->width; ++col) { int const ovlcol = col - originleft; if (ovlcol >= 0 && ovlcol < overlayPamP->width) { tuplen const alphaTuplen = alphaTuplerown ? alphaTuplerown[ovlcol] : NULL; overlayPixel(overlayTuplerow[ovlcol], overlayPamP, underlayTuplerow[col], underlayPamP, alphaTuplen, invertAlpha, composedTuplerow[col], composedPamP, masterOpacity, sampleScale, alphaMix); } else /* Overlay image does not touch this column. */ pnm_assigntuple(composedPamP, composedTuplerow[col], underlayTuplerow[col]); } }
static void composite(int const originleft, int const origintop, struct pam * const underlayPamP, struct pam * const overlayPamP, struct pam * const alphaPamP, bool const invertAlpha, float const masterOpacity, struct pam * const composedPamP, bool const assumeLinear) { /*---------------------------------------------------------------------------- Overlay the overlay image in the array 'overlayImage', described by *overlayPamP, onto the underlying image from the input image file as described by *underlayPamP, output the composite to the image file as described by *composedPamP. Apply the overlay image with transparency described by the array 'alpha' and *alphaPamP. The underlying image is positioned after its header. 'originleft' and 'origintop' are the coordinates in the underlying image plane where the top left corner of the overlay image is to go. It is not necessarily inside the underlying image (in fact, may be negative). Only the part of the overlay that actually intersects the underlying image, if any, gets into the output. -----------------------------------------------------------------------------*/ enum sampleScale const sampleScale = assumeLinear ? INTENSITY_SAMPLE : GAMMA_SAMPLE; int underlayRow; /* NB may be negative */ int overlayRow; /* NB may be negative */ tuple * composedTuplerow; tuple * underlayTuplerow; tuple * overlayTuplerow; tuplen * alphaTuplerown; bool overlayHasOpacity; unsigned int opacityPlane; pnm_getopacity(overlayPamP, &overlayHasOpacity, &opacityPlane); composedTuplerow = pnm_allocpamrow(composedPamP); underlayTuplerow = pnm_allocpamrow(underlayPamP); overlayTuplerow = pnm_allocpamrow(overlayPamP); if (alphaPamP) alphaTuplerown = pnm_allocpamrown(alphaPamP); pnm_writepaminit(composedPamP); for (underlayRow = MIN(0, origintop), overlayRow = MIN(0, -origintop); underlayRow < MAX(underlayPamP->height, origintop + overlayPamP->height); ++underlayRow, ++overlayRow) { if (overlayRow >= 0 && overlayRow < overlayPamP->height) { pnm_readpamrow(overlayPamP, overlayTuplerow); adaptRowToOutputFormat(overlayPamP, overlayTuplerow, composedPamP); if (alphaPamP) pnm_readpamrown(alphaPamP, alphaTuplerown); } if (underlayRow >= 0 && underlayRow < underlayPamP->height) { pnm_readpamrow(underlayPamP, underlayTuplerow); adaptRowToOutputFormat(underlayPamP, underlayTuplerow, composedPamP); if (underlayRow < origintop || underlayRow >= origintop + overlayPamP->height) { /* Overlay image does not touch this underlay row. */ pnm_writepamrow(composedPamP, underlayTuplerow); } else { unsigned int col; for (col = 0; col < composedPamP->width; ++col) { int const ovlcol = col - originleft; if (ovlcol >= 0 && ovlcol < overlayPamP->width) { tuplen const alphaTuplen = alphaPamP ? alphaTuplerown[ovlcol] : NULL; overlayPixel(overlayTuplerow[ovlcol], overlayPamP, underlayTuplerow[col], underlayPamP, alphaTuplen, invertAlpha, overlayHasOpacity, opacityPlane, composedTuplerow[col], composedPamP, masterOpacity, sampleScale); } else /* Overlay image does not touch this column. */ pnm_assigntuple(composedPamP, composedTuplerow[col], underlayTuplerow[col]); } pnm_writepamrow(composedPamP, composedTuplerow); } } } pnm_freepamrow(composedTuplerow); pnm_freepamrow(underlayTuplerow); pnm_freepamrow(overlayTuplerow); if (alphaPamP) pnm_freepamrown(alphaTuplerown); }