1 /* $XConsortium: ilcrop.c /main/5 1996/06/19 12:24:05 ageorge $ */
2 /**---------------------------------------------------------------------
4 *** (c)Copyright 1991 Hewlett-Packard Co.
6 *** RESTRICTED RIGHTS LEGEND
7 *** Use, duplication, or disclosure by the U.S. Government is subject to
8 *** restrictions as set forth in sub-paragraph (c)(1)(ii) of the Rights in
9 *** Technical Data and Computer Software clause in DFARS 252.227-7013.
10 *** Hewlett-Packard Company
11 *** 3000 Hanover Street
12 *** Palo Alto, CA 94304 U.S.A.
13 *** Rights for non-DOD U.S. Government Departments and Agencies are as set
14 *** forth in FAR 52.227-19(c)(1,2).
16 ***-------------------------------------------------------------------*/
18 /* =============================================================================================================================
20 /ilc/ilcrop.c : Image Library crop routines.
22 ============================================================================================================================= */
26 #include "ilpipelem.h"
31 /* =========================== Compressed Crop Code ================================= */
32 /* This code crops compressed pipe images by ignoring strips that are outside of
36 /* Private data for compressed crop filter. */
38 long topStrip; /* index (from 0) of first strip to output */
39 long bottomStrip; /* last strip to output */
40 long stripIndex; /* Init(): current strip index */
41 } ilCropCompPrivRec, *ilCropCompPrivPtr;
44 /* ------------------------------ ilCropCompInit ----------------------------- */
45 /* Init() function for when cropping compressed images.
47 static ilError ilCropCompInit (
48 ilCropCompPrivPtr pPriv,
49 ilImageInfo *pSrcImage,
50 ilImageInfo *pDstImage
53 pPriv->stripIndex = 0; /* init current strip to first strip */
57 /* ------------------------------ ilCropCompExecute ----------------------------- */
58 /* Execute() function for when cropping compressed images.
60 static ilError ilCropCompExecute (
66 register ilCropCompPrivPtr pPriv;
68 /* If this strip is out of range of strips to be written, return 0 for
69 # lines written (crops the strip); otherwise pass strip on to next filter.
71 pPriv = (ilCropCompPrivPtr)pData->pPrivate;
72 if ((pPriv->stripIndex < pPriv->topStrip) || (pPriv->stripIndex > pPriv->bottomStrip)) {
73 *pNLines = 0; /* skip this strip */
74 *pData->compressed.pDstOffset = 0; /* next filter should not be called anyway */
75 *pData->compressed.pNBytesWritten = 0;
77 else { /* in range, pass this strip down pipe */
78 *pData->compressed.pDstOffset = pData->compressed.srcOffset;
79 *pData->compressed.pNBytesWritten = pData->compressed.nBytesToRead;
81 pPriv->stripIndex++; /* inc current strip count */
86 /* ------------------------------ ilCropCompressed ----------------------------- */
87 /* Called by ilCrop() when the pipe image is compressed. "pRect" must point to
88 a non-null rectangle which is the crop rectangle intersect with the image bounds.
89 "pInfo" must point to the current pipe info.
91 static ilBool ilCropCompressed (
98 register long stripHeight, bottom;
99 long topStrip, bottomStrip, topLine;
100 ilDstElementData dstData;
101 ilCropCompPrivPtr pPriv;
103 rect = *pRect; /* don't modify caller's copy */
105 /* Skip strips above and below the strips that intersect the crop rect.
106 Can only do that if strips are constant, because we must declare the size
107 of the image coming out of the filter added here. Set "top/bottomStrip" to
108 the index (from 0) of the top/bottom (first/last) strip within crop rect.
110 stripHeight = pInfo->stripHeight;
111 if (pInfo->constantStrip && (stripHeight > 0)) {
112 topStrip = rect.y / stripHeight;
113 bottom = rect.y + rect.height;
114 bottomStrip = (bottom - 1) / stripHeight;
116 /* Add a "no dst" filter to crop only if some strips would be skipped */
117 if ((topStrip > 0) || (bottomStrip < ((pInfo->height - 1) / stripHeight))) {
118 dstData.producerObject = (ilObject)NULL;
119 dstData.pDes = (ilImageDes *)NULL;
120 dstData.pFormat = (ilImageFormat *)NULL;
121 dstData.width = pInfo->width; /* width is not cropped */
122 topLine = topStrip * stripHeight; /* first line output from filter */
123 dstData.height = (bottomStrip + 1) * stripHeight - topLine;
124 dstData.stripHeight = stripHeight;
125 dstData.constantStrip = TRUE; /* checked above */
126 dstData.pPalette = pInfo->pPalette;
127 dstData.pCompData = pInfo->pCompData;
129 pPriv = (ilCropCompPrivPtr)ilAddPipeElement (pipe, IL_FILTER,
130 sizeof (ilCropCompPrivRec), IL_ADD_PIPE_NO_DST, (ilSrcElementData *)NULL,
131 &dstData, ilCropCompInit, IL_NPF, IL_NPF, ilCropCompExecute, NULL, 0);
134 pPriv->topStrip = topStrip;
135 pPriv->bottomStrip = bottomStrip;
137 /* Adjust the top of new crop rect by lines skipped by this filter. */
142 /* Decompress the pipe image and call ilCrop() recursively to crop the bits
143 that remain after this code has (possibly) skipped unnecessary strips.
145 ilGetPipeInfo (pipe, TRUE, (ilPipeInfo *)NULL, (ilImageDes *)NULL, (ilImageFormat *)NULL);
146 return ilCrop (pipe, &rect);
150 /* =========================== Uncompressed Crop Code =============================== */
151 /* This code crops uncompressed pipe images by copying only the relevant pixels.
160 int illinecount; /* running line count as pipe strips are executed */
161 int ilCropDstheight; /* destination height value saved to avoid strip sizes */
162 int ilCropSrcheight; /* src height value saved to avoid strip sizes */
163 int ilCropXoff; /* crop X origin */
164 int ilCropYoff; /* crop Y origin */
165 } ilCropPriv, *ilCropPrivptr;
168 /* =============================================================================================================================
169 ============================================================================================================================= */
171 static ilError ilCropInit(
172 ilCropPrivptr pPrivate,
173 ilImageInfo *pSrcImage,
174 ilImageInfo *pDstImage
178 /* Initialize counters */
179 pPrivate->illinecount = 1;
187 /* =============================================================================================================================
189 ilCropBitonalExecute - Crop processing for images with bit per pixel format .
191 ============================================================================================================================= */
192 static ilError ilCropBitonalExecute (
193 register ilExecuteData *pData,
194 unsigned long dstLine,
195 unsigned long *pNLines
198 register CARD32 *psrc, *pdst, *psrcline, *pdstline, srca, srcb;
199 register long srcnwords, dstnwords, nlines;
200 register unsigned long dstwidth;
201 register long nlongs, firstword;
202 ilImagePlaneInfo *pplane;
203 register unsigned long local_noDstLine, Lwordoff, Rwordoff;
204 register int x, y, lastcount, yextent;
205 register ilCropPrivptr pPriv;
210 if (nlines <= 0) return IL_OK;
212 pplane = &pData->pSrcImage->plane[0];
213 srcnwords = (pplane->nBytesPerRow + LONGSZ - 1)/LONGSZ;
214 psrcline = (CARD32 *) (pplane->pPixels) + pData->srcLine * srcnwords;
216 pplane = &pData->pDstImage->plane[0];
217 dstnwords = (pplane->nBytesPerRow + LONGSZ - 1)/LONGSZ;
218 pdstline = (CARD32 *) (pplane->pPixels) + dstLine * dstnwords;
219 pPriv = (ilCropPrivptr) pData->pPrivate;
222 dstwidth = pData->pDstImage->width;
223 yextent = pPriv->ilCropYoff + pPriv->ilCropDstheight;
225 firstword = (pPriv->ilCropXoff)/WORDPOS;
226 nlongs = (dstwidth - 1)/WORDPOS + 1;
227 Lwordoff = pPriv->ilCropXoff % WORDPOS;
228 Rwordoff = WORDPOS - Lwordoff;
232 lastcount = pPriv->illinecount - 1;
235 for ( y = lastcount; y < (lastcount + *pNLines); y++, pPriv->illinecount++) {
237 if ((y >= pPriv->ilCropYoff) && (y < yextent)) { /* process */
241 for( x = 0; x < firstword; x++, psrc++) { } /* skip long words up to the offset */
244 if ( Lwordoff == 0 ) {
245 for( x = 0; x < nlongs; x++ ) *pdst++ = *psrc++;
250 for( x = 0; x < nlongs; x++ ) {
253 *pdst++ = (srcb >> Rwordoff) | (srca << Lwordoff);
258 pdstline += dstnwords;
262 psrcline += srcnwords;
267 *pNLines = local_noDstLine;
273 /* =============================================================================================================================
275 ilCrop3ByteExecute - Crop processing for images with 24 bits per pixel format .
277 ============================================================================================================================= */
278 static ilError ilCrop3ByteExecute (
279 register ilExecuteData *pData,
280 unsigned long dstLine,
281 unsigned long *pNLines
284 register unsigned char *psrc, *pdst, *psrcline, *pdstline;
285 register unsigned long srcnbytes, dstnbytes, nlines;
286 register unsigned long dstwidth;
287 ilImagePlaneInfo *pplane;
288 register unsigned long local_noDstLine;
289 register int x, y, lastcount, yextent, xextent;
290 register ilCropPrivptr pPriv;
294 if (nlines <= 0) return IL_OK;
296 pplane = &pData->pSrcImage->plane[0];
297 srcnbytes = pplane->nBytesPerRow;
298 psrcline = (unsigned char *) (pplane->pPixels) + pData->srcLine * srcnbytes;
300 pplane = &pData->pDstImage->plane[0];
301 dstnbytes = pplane->nBytesPerRow;
302 pdstline = (unsigned char *) (pplane->pPixels) + dstLine * dstnbytes;
303 pPriv = (ilCropPrivptr) pData->pPrivate;
306 dstwidth = pData->pDstImage->width;
307 yextent = pPriv->ilCropYoff + pPriv->ilCropDstheight;
308 xextent = pPriv->ilCropXoff + dstwidth;
311 lastcount = pPriv->illinecount - 1;
313 for ( y = lastcount; y < (lastcount + *pNLines); y++, pPriv->illinecount++) {
315 if ((y >= pPriv->ilCropYoff) && (y < yextent)) { /* process */
319 for( x = 0; x < xextent; x++) {
320 if ( x < pPriv->ilCropXoff ) psrc += 3;
327 pdstline += dstnbytes;
330 psrcline += srcnbytes;
335 *pNLines = local_noDstLine;
343 /* =============================================================================================================================
345 ilCropByteExecute - Crop processing for images with byte per pixel format .
347 ============================================================================================================================= */
348 static ilError ilCropByteExecute (
349 register ilExecuteData *pData,
350 unsigned long dstLine,
351 unsigned long *pNLines
354 register unsigned char *psrc, *pdst, *psrcline, *pdstline;
355 register unsigned long srcnbytes, dstnbytes, nlines;
356 register unsigned long dstwidth;
357 ilImagePlaneInfo *pplane;
358 register unsigned long local_noDstLine;
359 register int x, y, lastcount, yextent, xextent;
360 register ilCropPrivptr pPriv;
364 if (nlines <= 0) return IL_OK;
366 pplane = &pData->pSrcImage->plane[0];
367 srcnbytes = pplane->nBytesPerRow;
368 psrcline = (unsigned char *) (pplane->pPixels) + pData->srcLine * srcnbytes;
370 pplane = &pData->pDstImage->plane[0];
371 dstnbytes = pplane->nBytesPerRow;
372 pdstline = (unsigned char *) (pplane->pPixels) + dstLine * dstnbytes;
373 pPriv = (ilCropPrivptr) pData->pPrivate;
376 dstwidth = pData->pDstImage->width;
377 yextent = pPriv->ilCropYoff + pPriv->ilCropDstheight;
378 xextent = pPriv->ilCropXoff + dstwidth;
381 lastcount = pPriv->illinecount - 1;
383 for ( y = lastcount; y < (lastcount + *pNLines); y++, pPriv->illinecount++) {
385 if ((y >= pPriv->ilCropYoff) && (y < yextent)) { /* process */
389 for( x = 0; x < xextent; x++) {
390 if ( x < pPriv->ilCropXoff ) psrc++;
391 else *pdst++ = *psrc++;
393 pdstline += dstnbytes;
396 psrcline += srcnbytes;
401 *pNLines = local_noDstLine;
408 /* =============================================================================================================================
410 ilCrop - Public function. Insert a pipe element which crops to the given rectangle.
411 Check for format types and do an explicit conversion if necessary.
413 ============================================================================================================================= */
421 register ilCropPrivptr pPriv;
422 ilDstElementData dstdata;
424 ilImageFormat imformat;
427 ilRect Srcrect, Dstrect;
430 /* Get ptr to pipe info and check state: don't decompress! */
431 state = ilGetPipeInfo(pipe, FALSE, &info, &imdes, &imformat);
432 if(state != IL_PIPE_FORMING) {
433 if (!pipe->context->error)
434 ilDeclarePipeInvalid(pipe, IL_ERROR_PIPE_STATE);
439 return ilDeclarePipeInvalid (pipe, IL_ERROR_NULL_RECT_PTR);
441 /* Clip the specified crop rectangle within the Src rectangle */
444 Srcrect.width = info.width;
445 Srcrect.height = info.height;
446 Dstrect = *pRect; /* bug #0067: don't modify caller's copy */
447 _ilIntersectRect ( &Srcrect, &Dstrect );
449 /* If crop rect = image rect; a noop - return. If null crop rect, error. */
450 if ( (Srcrect.height == Dstrect.height) && (Srcrect.width == Dstrect.width) &&
451 (Dstrect.x == 0) && (Dstrect.y == 0) ) return TRUE;
452 if ( (Dstrect.width <= 0) || (Dstrect.height <= 0) )
453 return ilDeclarePipeInvalid (pipe, IL_ERROR_ZERO_SIZE_IMAGE);
455 /* If the pipe image is compressed, handle separately. Code will crop
456 compressed data by ignoring strips outside of the range of the crop rect.
457 It will then force decompression of the pipe image and call ilCrop()
458 to crop within the strips.
460 if (imdes.compression != IL_UNCOMPRESSED)
461 return ilCropCompressed (pipe, &Dstrect, &info);
463 /* Check for valid Formats */
468 switch (imdes.nSamplesPerPixel) {
469 case 3: /* RGB or YUV */
470 if(imformat.sampleOrder != IL_SAMPLE_PIXELS) {
471 imformat.sampleOrder = IL_SAMPLE_PIXELS;
475 if((imformat.nBitsPerSample[0] != 8) ||
476 (imformat.nBitsPerSample[1] != 8) ||
477 (imformat.nBitsPerSample[2] != 8)) {
479 imformat.nBitsPerSample[0] = 8;
480 imformat.nBitsPerSample[1] = 8;
481 imformat.nBitsPerSample[2] = 8;
487 switch (imformat.nBitsPerSample[0]) {
488 case 8: /* Byte per pixel */
491 case 1: /* Bitonal */
493 if (imformat.rowBitAlign != 32) {
494 imformat.rowBitAlign = 32;
499 default: /* something other than 1 - try 8 */
500 imformat.nBitsPerSample[0] = 8;
506 return ilDeclarePipeInvalid(pipe, IL_ERROR_NOT_IMPLEMENTED);
510 if(convert && !ilConvert(pipe, &imdes, &imformat, 0, NULL))
513 dstdata.producerObject = (ilObject) NULL;
514 dstdata.pDes = (ilImageDes *) NULL;
515 dstdata.pFormat = (ilImageFormat *) NULL;
516 dstdata.width = Dstrect.width;
517 dstdata.height = Dstrect.height;
519 /* set output strip height */
520 dstdata.stripHeight = info.recommendedStripHeight;
521 dstdata.constantStrip = FALSE;
524 switch (imdes.nSamplesPerPixel) {
526 pPriv = (ilCropPrivptr) ilAddPipeElement(pipe, IL_FILTER, sizeof(ilCropPriv), 0, (ilSrcElementData *) NULL,
527 &dstdata, ilCropInit, IL_NPF, IL_NPF, ilCrop3ByteExecute, NULL, 0);
532 pPriv = (ilCropPrivptr) ilAddPipeElement(pipe, IL_FILTER, sizeof(ilCropPriv), 0, (ilSrcElementData *) NULL,
533 &dstdata, ilCropInit, IL_NPF, IL_NPF, ilCropBitonalExecute, NULL, 0);
535 pPriv = (ilCropPrivptr) ilAddPipeElement(pipe, IL_FILTER, sizeof(ilCropPriv), 0, (ilSrcElementData *) NULL,
536 &dstdata, ilCropInit, IL_NPF, IL_NPF, ilCropByteExecute, NULL, 0);
542 /* Save away true heights and offsets */
543 pPriv->ilCropSrcheight = info.height;
544 pPriv->ilCropDstheight = Dstrect.height;
545 pPriv->ilCropXoff = Dstrect.x;
546 pPriv->ilCropYoff = Dstrect.y;
549 pipe->context->error = IL_OK;