Initial import of the CDE 2.1.30 sources from the Open Group.
[oweals/cde.git] / cde / lib / DtHelp / il / ilcrop.c
1 /* $XConsortium: ilcrop.c /main/5 1996/06/19 12:24:05 ageorge $ */
2 /**---------------------------------------------------------------------
3 ***     
4 ***    (c)Copyright 1991 Hewlett-Packard Co.
5 ***    
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).
15 ***
16 ***-------------------------------------------------------------------*/
17
18 /* =============================================================================================================================
19
20      /ilc/ilcrop.c : Image Library crop routines.   
21
22    ============================================================================================================================= */
23
24
25 #include "ilint.h"
26 #include "ilpipelem.h"
27 #include "ilerrors.h"
28
29
30
31 /*  =========================== Compressed Crop Code ================================= */
32 /*  This code crops compressed pipe images by ignoring strips that are outside of
33     the crop rectangle.
34 */
35
36     /*  Private data for compressed crop filter. */
37 typedef struct {
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;
42
43
44     /*  ------------------------------ ilCropCompInit ----------------------------- */
45     /*  Init() function for when cropping compressed images.
46     */
47 static ilError ilCropCompInit (
48     ilCropCompPrivPtr   pPriv,
49     ilImageInfo        *pSrcImage,
50     ilImageInfo        *pDstImage
51     )
52 {
53     pPriv->stripIndex = 0;          /* init current strip to first strip */
54     return IL_OK;
55 }
56
57     /*  ------------------------------ ilCropCompExecute ----------------------------- */
58     /*  Execute() function for when cropping compressed images.
59     */
60 static ilError ilCropCompExecute (
61     ilExecuteData          *pData,
62     long                    dstLine,
63     long                   *pNLines
64     )
65 {
66 register ilCropCompPrivPtr  pPriv;
67
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.
70         */
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;
76         }
77     else {                                  /* in range, pass this strip down pipe */
78         *pData->compressed.pDstOffset = pData->compressed.srcOffset;
79         *pData->compressed.pNBytesWritten = pData->compressed.nBytesToRead;
80         }
81     pPriv->stripIndex++;                    /* inc current strip count */
82     return IL_OK;
83 }
84
85
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.
90     */
91 static ilBool ilCropCompressed (
92     ilPipe              pipe,
93     ilRect             *pRect,
94     ilPipeInfo         *pInfo
95     )
96 {
97 ilRect                  rect;
98 register long           stripHeight, bottom;
99 long                    topStrip, bottomStrip, topLine;
100 ilDstElementData        dstData;
101 ilCropCompPrivPtr       pPriv;
102
103     rect = *pRect;                              /* don't modify caller's copy */
104
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.
109         */
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;
115
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;
128
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);
132             if (!pPriv)
133                 return FALSE;
134             pPriv->topStrip = topStrip;
135             pPriv->bottomStrip = bottomStrip;
136
137                 /*  Adjust the top of new crop rect by lines skipped by this filter. */
138             rect.y -= topLine;
139             }
140         }
141
142         /*  Decompress the pipe image and call ilCrop() recursively to crop the bits
143             that remain after this code has (possibly) skipped unnecessary strips.
144         */
145     ilGetPipeInfo (pipe, TRUE, (ilPipeInfo *)NULL, (ilImageDes *)NULL, (ilImageFormat *)NULL);
146     return ilCrop (pipe, &rect);
147 }
148
149
150 /*  =========================== Uncompressed Crop Code =============================== */
151 /*  This code crops uncompressed pipe images by copying only the relevant pixels.
152 */
153
154
155 #define LONGSZ        4
156 #define WORDPOS       32
157
158
159  typedef struct {
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;
166
167
168 /* =============================================================================================================================
169    ============================================================================================================================= */
170
171 static ilError ilCropInit(
172     ilCropPrivptr   pPrivate,
173     ilImageInfo     *pSrcImage,
174     ilImageInfo     *pDstImage
175     )
176
177 {
178    /* Initialize counters */
179    pPrivate->illinecount =  1;
180
181    return IL_OK;
182 }
183
184
185
186
187 /* =============================================================================================================================
188
189       ilCropBitonalExecute  -  Crop processing for images with bit per pixel format .
190
191    ============================================================================================================================= */
192 static ilError ilCropBitonalExecute (
193     register ilExecuteData  *pData,
194     unsigned long           dstLine,
195     unsigned long          *pNLines
196     )
197 {
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;
206
207
208
209    nlines                  =  *pNLines;
210    if (nlines <= 0)        return IL_OK;
211
212    pplane                  =  &pData->pSrcImage->plane[0];
213    srcnwords               =  (pplane->nBytesPerRow + LONGSZ - 1)/LONGSZ;
214    psrcline                =  (CARD32 *) (pplane->pPixels)  +  pData->srcLine * srcnwords; 
215
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;
220
221
222    dstwidth  = pData->pDstImage->width;
223    yextent   = pPriv->ilCropYoff + pPriv->ilCropDstheight;
224
225    firstword = (pPriv->ilCropXoff)/WORDPOS;
226    nlongs    = (dstwidth - 1)/WORDPOS + 1;
227    Lwordoff  = pPriv->ilCropXoff % WORDPOS;
228    Rwordoff  = WORDPOS - Lwordoff;
229
230
231    local_noDstLine = 0;
232    lastcount = pPriv->illinecount - 1;
233
234
235    for ( y = lastcount;  y < (lastcount + *pNLines);  y++, pPriv->illinecount++) {
236
237        if ((y >= pPriv->ilCropYoff) && (y < yextent)) {     /* process */
238               psrc = psrcline;
239               pdst = pdstline;
240
241               for( x = 0; x < firstword;  x++, psrc++)  { }  /* skip long words up to the offset */
242                                  
243   
244               if ( Lwordoff == 0 ) {
245                  for( x = 0; x < nlongs;  x++ )  *pdst++ = *psrc++;
246               }
247               else {
248
249                  srca = *psrc++;
250                  for( x = 0; x < nlongs;  x++ ) { 
251
252                    srcb     =  *psrc++;
253                    *pdst++  =  (srcb >> Rwordoff) | (srca << Lwordoff);
254                    srca     = srcb;
255                  }
256               }
257
258              pdstline += dstnwords;
259              local_noDstLine++;
260        }
261
262        psrcline += srcnwords;
263
264    }  /* end loop */
265
266
267    *pNLines = local_noDstLine;
268    return IL_OK;
269
270 }
271
272
273 /* =============================================================================================================================
274
275       ilCrop3ByteExecute  -  Crop processing for images with 24 bits per pixel format .
276
277    ============================================================================================================================= */
278 static ilError ilCrop3ByteExecute (
279     register ilExecuteData   *pData,
280     unsigned long           dstLine,
281     unsigned long          *pNLines
282     )
283 {
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;
291
292
293    nlines                  =  *pNLines;
294    if (nlines <= 0)        return IL_OK;
295
296    pplane                  =  &pData->pSrcImage->plane[0];
297    srcnbytes               =  pplane->nBytesPerRow;
298    psrcline                =  (unsigned char *) (pplane->pPixels)  +  pData->srcLine * srcnbytes; 
299
300    pplane                  =  &pData->pDstImage->plane[0];
301    dstnbytes               =  pplane->nBytesPerRow;
302    pdstline                =  (unsigned char *) (pplane->pPixels)  +  dstLine * dstnbytes; 
303    pPriv                   =  (ilCropPrivptr) pData->pPrivate;
304
305
306    dstwidth  = pData->pDstImage->width;
307    yextent   = pPriv->ilCropYoff + pPriv->ilCropDstheight;
308    xextent   = pPriv->ilCropXoff + dstwidth;
309
310    local_noDstLine = 0;
311    lastcount = pPriv->illinecount - 1;
312
313    for ( y = lastcount;  y < (lastcount + *pNLines);  y++, pPriv->illinecount++) {
314
315        if ((y >= pPriv->ilCropYoff) && (y < yextent)) {    /* process */
316               psrc = psrcline;
317               pdst = pdstline;
318
319               for( x = 0; x < xextent;  x++)  {
320                    if  ( x < pPriv->ilCropXoff )  psrc += 3;
321                    else {
322                        *pdst++ = *psrc++;
323                        *pdst++ = *psrc++;
324                        *pdst++ = *psrc++;
325                    }
326               }
327               pdstline += dstnbytes;
328               local_noDstLine++;
329        }
330        psrcline += srcnbytes;
331
332    }  /* end loop */
333
334
335    *pNLines = local_noDstLine;
336    return IL_OK;
337
338 }
339
340
341
342
343 /* =============================================================================================================================
344
345       ilCropByteExecute  -  Crop processing for images with byte per pixel format .
346
347    ============================================================================================================================= */
348 static ilError ilCropByteExecute (
349     register ilExecuteData   *pData,
350     unsigned long           dstLine,
351     unsigned long          *pNLines
352     )
353 {
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;
361
362
363    nlines                  =  *pNLines;
364    if (nlines <= 0)        return IL_OK;
365
366    pplane                  =  &pData->pSrcImage->plane[0];
367    srcnbytes               =  pplane->nBytesPerRow;
368    psrcline                =  (unsigned char *) (pplane->pPixels)  +  pData->srcLine * srcnbytes; 
369
370    pplane                  =  &pData->pDstImage->plane[0];
371    dstnbytes               =  pplane->nBytesPerRow;
372    pdstline                =  (unsigned char *) (pplane->pPixels)  +  dstLine * dstnbytes; 
373    pPriv                   =  (ilCropPrivptr) pData->pPrivate;
374
375
376    dstwidth  = pData->pDstImage->width;
377    yextent   = pPriv->ilCropYoff + pPriv->ilCropDstheight;
378    xextent   = pPriv->ilCropXoff + dstwidth;
379
380    local_noDstLine = 0;
381    lastcount = pPriv->illinecount - 1;
382
383    for ( y = lastcount;  y < (lastcount + *pNLines);  y++, pPriv->illinecount++) {
384
385        if ((y >= pPriv->ilCropYoff) && (y < yextent)) {    /* process */
386               psrc = psrcline;
387               pdst = pdstline;
388
389               for( x = 0; x < xextent;  x++)  {
390                    if  ( x < pPriv->ilCropXoff )  psrc++;
391                    else  *pdst++ = *psrc++;
392               }
393               pdstline += dstnbytes;
394               local_noDstLine++;
395        }
396        psrcline += srcnbytes;
397
398    }  /* end loop */
399
400
401    *pNLines = local_noDstLine;
402    return IL_OK;
403
404 }
405
406
407
408 /* =============================================================================================================================
409
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.
412
413    ============================================================================================================================= */
414 ilBool ilCrop (
415     ilPipe              pipe,
416     ilRect             *pRect
417     )
418 {
419 unsigned int            state;
420 ilPipeInfo              info;
421 register ilCropPrivptr  pPriv;
422 ilDstElementData        dstdata;
423 ilImageDes              imdes;
424 ilImageFormat           imformat;
425 ilBool                  convert;
426 ilBool                  bitonal;
427 ilRect                  Srcrect, Dstrect;
428
429
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);
435          return FALSE;
436        }
437
438       if (!pRect)
439         return ilDeclarePipeInvalid (pipe, IL_ERROR_NULL_RECT_PTR);
440
441        /* Clip the specified crop rectangle within the Src rectangle */
442        Srcrect.x      =  0;
443        Srcrect.y      =  0;
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 );
448     
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);
454
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.
459        */
460        if (imdes.compression != IL_UNCOMPRESSED)
461            return ilCropCompressed (pipe, &Dstrect, &info);
462
463        /* Check for valid Formats */
464
465        bitonal = FALSE;
466        convert = FALSE;
467
468        switch (imdes.nSamplesPerPixel)  {
469             case  3: /* RGB or YUV */  
470                      if(imformat.sampleOrder != IL_SAMPLE_PIXELS)  { 
471                            imformat.sampleOrder = IL_SAMPLE_PIXELS;
472                            convert = TRUE;
473                      }
474
475                      if((imformat.nBitsPerSample[0] != 8) ||
476                         (imformat.nBitsPerSample[1] != 8) ||
477                         (imformat.nBitsPerSample[2] != 8))  {
478
479                           imformat.nBitsPerSample[0] = 8;
480                           imformat.nBitsPerSample[1] = 8;
481                           imformat.nBitsPerSample[2] = 8;
482                           convert = TRUE;
483                      }
484                      break;
485
486             case  1:
487                      switch (imformat.nBitsPerSample[0]) {
488                              case 8:  /* Byte per pixel */
489                                       break;
490
491                              case 1:  /* Bitonal */
492                                       bitonal = TRUE; 
493                                       if (imformat.rowBitAlign != 32) {
494                                          imformat.rowBitAlign = 32;
495                                          convert = TRUE;
496                                       }
497                                       break;
498
499                              default: /* something other than 1 - try 8 */
500                                       imformat.nBitsPerSample[0] = 8;
501                                       convert = TRUE;
502                      }  
503                      break;
504
505             default:
506                       return ilDeclarePipeInvalid(pipe, IL_ERROR_NOT_IMPLEMENTED);
507        }
508
509
510        if(convert && !ilConvert(pipe, &imdes, &imformat, 0, NULL))
511            return FALSE;
512
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;
518
519        /* set output strip height */
520        dstdata.stripHeight    = info.recommendedStripHeight;
521        dstdata.constantStrip  = FALSE;
522
523
524        switch (imdes.nSamplesPerPixel) {
525             case 3:
526                             pPriv = (ilCropPrivptr) ilAddPipeElement(pipe, IL_FILTER, sizeof(ilCropPriv), 0, (ilSrcElementData *) NULL,
527                                                                      &dstdata, ilCropInit, IL_NPF, IL_NPF, ilCrop3ByteExecute, NULL, 0);
528                      break;
529
530             case 1:  
531                      if(bitonal) 
532                             pPriv = (ilCropPrivptr) ilAddPipeElement(pipe, IL_FILTER, sizeof(ilCropPriv), 0, (ilSrcElementData *) NULL,
533                                                                      &dstdata, ilCropInit, IL_NPF, IL_NPF, ilCropBitonalExecute, NULL, 0);
534                      else 
535                             pPriv = (ilCropPrivptr) ilAddPipeElement(pipe, IL_FILTER, sizeof(ilCropPriv), 0, (ilSrcElementData *) NULL,
536                                                                      &dstdata, ilCropInit, IL_NPF, IL_NPF, ilCropByteExecute, NULL, 0);
537        }
538
539        if(!pPriv)
540            return FALSE;
541
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;
547
548
549        pipe->context->error = IL_OK;
550        return TRUE;
551 }