Add GNU LGPL headers to all .c .C and .h files
[oweals/cde.git] / cde / lib / DtHelp / il / ilconvert.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these librararies and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /* $XConsortium: ilconvert.c /main/5 1996/06/19 12:24:11 ageorge $ */
24 /**---------------------------------------------------------------------
25 ***     
26 ***    (c)Copyright 1991 Hewlett-Packard Co.
27 ***    
28 ***                             RESTRICTED RIGHTS LEGEND
29 ***    Use, duplication, or disclosure by the U.S. Government is subject to
30 ***    restrictions as set forth in sub-paragraph (c)(1)(ii) of the Rights in
31 ***    Technical Data and Computer Software clause in DFARS 252.227-7013.
32 ***                             Hewlett-Packard Company
33 ***                             3000 Hanover Street
34 ***                             Palo Alto, CA 94304 U.S.A.
35 ***    Rights for non-DOD U.S. Government Departments and Agencies are as set
36 ***    forth in FAR 52.227-19(c)(1,2).
37 ***
38 ***-------------------------------------------------------------------*/
39
40 #include "ilint.h"
41 #include "ilpipelem.h"
42 #include "ilconvert.h"
43 #include "ilerrors.h"
44
45
46         /*  ---------------------- ilAddConversionFilter --------------------------- */
47         /*  Add a conversion filter to the given pipe, given a ptr to a structure
48             which defines the filter and its pipe element.  If failure, declare pipe
49             invalid (which sets error code) and return false; else true.
50                 pInfo must point to the current pipe info; pSrcDes/Format to the pipe
51             des/format.  The information they point to is updated after the pipe
52             element(s) is/are added; on return they will contain up-to-date data.
53         */
54 static ilBool ilAddConversionFilter (
55     ilPipe                  pipe,
56     ilPipeInfo             *pInfo,
57     ilImageDes             *pSrcDes,
58     ilImageFormat          *pSrcFormat,
59     void                   *pOptionData,
60     register ilConvertPtr   pCvtData
61     )
62 {
63 ilPtr                       pPriv;
64 ilDstElementData            dstData;
65 ilError                     error;
66
67         /*  Check src format against code for src format demanded by this filter.
68             If not the same, do ilConvert() to that format (recurse!), exit if error.
69         */
70     switch (pCvtData->srcFormatCode) {
71         case IL_DONT_CHECK_STD_FORMAT:      /* filter converts format: dont check */
72             break;
73
74         case IL_STD_FORMAT_BIT:
75             if ((pSrcFormat->rowBitAlign != 32)
76              || (pSrcFormat->nBitsPerSample[0] != 1)) {
77                 *pSrcFormat = *IL_FORMAT_BIT;
78                 ilConvert (pipe, (ilImageDes *)NULL, pSrcFormat, 0, NULL);
79                 if (pipe->context->error) return FALSE;
80                 ilGetPipeInfo (pipe, FALSE, pInfo, (ilImageDes *)NULL, (ilImageFormat *)NULL);
81                 }
82             break;
83
84         case IL_STD_FORMAT_BYTE:
85             if (pSrcFormat->nBitsPerSample[0] != 8) {
86                 *pSrcFormat = *IL_FORMAT_BYTE;
87                 ilConvert (pipe, (ilImageDes *)NULL, pSrcFormat, 0, NULL);
88                 if (pipe->context->error) return FALSE;
89                 ilGetPipeInfo (pipe, FALSE, pInfo, (ilImageDes *)NULL, (ilImageFormat *)NULL);
90                 }
91             break;
92
93         case IL_STD_FORMAT_3BYTE_PIXEL:
94             if ((pSrcFormat->sampleOrder != IL_SAMPLE_PIXELS)
95              || (pSrcFormat->nBitsPerSample[0] != 8)
96              || (pSrcFormat->nBitsPerSample[1] != 8)
97              || (pSrcFormat->nBitsPerSample[2] != 8)) {
98                 *pSrcFormat = *IL_FORMAT_3BYTE_PIXEL;
99                 ilConvert (pipe, (ilImageDes *)NULL, pSrcFormat, 0, NULL);
100                 if (pipe->context->error) return FALSE;
101                 ilGetPipeInfo (pipe, FALSE, pInfo, (ilImageDes *)NULL, (ilImageFormat *)NULL);
102                 }
103             break;
104         }
105
106         /*  Add a filter, from in *pCvtData.  Only the des and format may change;
107             other info (width, stripHeight, etc.) stays the same.
108         */
109     dstData.producerObject = (ilObject)NULL;
110     dstData.pDes = pCvtData->pDstDes;
111     dstData.pFormat = pCvtData->pDstFormat;
112     dstData.width = pInfo->width;
113     dstData.height = pInfo->height;
114     dstData.stripHeight = 0;
115     dstData.constantStrip = FALSE;
116     dstData.pPalette = (unsigned short *)NULL;
117     pPriv = ilAddPipeElement (pipe, IL_FILTER, pCvtData->nBytesPrivate, 0,
118                 (ilSrcElementData *)NULL, &dstData, pCvtData->Init, pCvtData->Cleanup, 
119                 pCvtData->Destroy, pCvtData->Execute, NULL, 0);
120     if (!pPriv) return FALSE;                               /* EXIT */
121
122         /*  If successful: call converters init function if non-null, return true.
123         */
124     if (pCvtData->AddElement) {
125         error = (*pCvtData->AddElement) (pPriv, pInfo->pPalette, pOptionData);
126         if (error) {
127             ilDeclarePipeInvalid (pipe, error);
128             return FALSE;                                   /* EXIT */
129             }
130         }
131
132         /*  Update the pipe info, return success.
133         */
134     ilGetPipeInfo (pipe, FALSE, pInfo, pSrcDes, pSrcFormat);
135     return TRUE;
136 }
137
138
139         /*  ---------------------- ilAddFormatFilter --------------------------- */
140         /*  Add a filter to the given pipe which converts format only to *pNewFormat.  
141             Similar to ilAddConversionFilter() but simpler.
142             *pInfo is updated with the new pipe info.
143         */
144 static ilBool ilAddFormatFilter (
145     ilPipe                  pipe,
146     ilPipeInfo             *pInfo,
147     const ilImageFormat    *pNewFormat,
148     register ilFormatPtr    pData
149     )
150 {
151 ilPtr                       pPriv;
152 ilDstElementData            dstData;
153 ilError                     error;
154
155         /*  Add a filter, from in *pData.  Only the format may change;
156             other info (des, width, stripHeight, etc.) stays the same.
157         */
158     dstData.producerObject = (ilObject)NULL;
159     dstData.pDes = (ilImageDes *)NULL;
160     dstData.pFormat = pNewFormat;
161     dstData.width = pInfo->width;
162     dstData.height = pInfo->height;
163     dstData.stripHeight = 0;
164     dstData.constantStrip = FALSE;
165     dstData.pPalette = (unsigned short *)NULL;
166     pPriv = ilAddPipeElement (pipe, IL_FILTER, pData->nBytesPrivate, 0,
167                 (ilSrcElementData *)NULL, &dstData, pData->Init, pData->Cleanup, 
168                 pData->Destroy, pData->Execute, NULL, 0);
169     if (!pPriv) return FALSE;                               /* EXIT */
170
171         /*  If successful: call converters init function if non-null, return true.
172         */
173     if (pData->AddElement) {
174         error = (*pData->AddElement) (pPriv, pInfo->pPalette);
175         if (error) {
176             ilDeclarePipeInvalid (pipe, error);
177             return FALSE;                                   /* EXIT */
178             }
179         }
180
181         /*  Update the pipe info, return success. */
182     ilGetPipeInfo (pipe, FALSE, pInfo, (ilImageDes *)NULL, (ilImageFormat *)NULL);
183     return TRUE;
184 }
185
186
187         /*  ---------------------------- ilConvert -------------------------------- */
188         /*  Public function; see spec.
189                 Convert the current pipe image to the given description (*pDes) and
190             format (*pFormat).  Either or both (a noop) may be null.  A null pDes means
191             "the same as before"; a null pFormat means "whatever is easiest/most 
192             efficient."
193                 If the current pipe image already fits the bill, no pipe element is added.
194             Note: compression is ignored in "pDes" - call ilCompress() to compress.
195         */
196 ilBool ilConvert (
197     ilPipe              pipe,
198     const ilImageDes    *pDes,
199     const ilImageFormat *pFormat,
200     int                 option,
201     void               *pOptionData
202     )
203 {
204 ilPipeInfo              info;
205 ilImageDes              pipeDes;
206 ilImageFormat           pipeFormat;
207 unsigned int            sample;
208 ilBool                  doConvert, doSubsample;
209 static unsigned long    defaultThreshold = 128; /* dflt threshold for gray->bitonal cvt */
210 #define ADD_CVT_FILTER(_filter) \
211     (ilAddConversionFilter (pipe, &info, &pipeDes, &pipeFormat, pOptionData, (_filter)))
212
213     /*  Macro to determine if the given YCbCr must be upsampled (any bits != 1) */
214 #define MUST_UPSAMPLE(_des)                              \
215     ( ((_des).typeInfo.YCbCr.sample[0].subsampleHoriz |  \
216        (_des).typeInfo.YCbCr.sample[0].subsampleVert |   \
217        (_des).typeInfo.YCbCr.sample[1].subsampleHoriz |  \
218        (_des).typeInfo.YCbCr.sample[1].subsampleVert |   \
219        (_des).typeInfo.YCbCr.sample[2].subsampleHoriz |  \
220        (_des).typeInfo.YCbCr.sample[2].subsampleVert) != 1)
221
222         /*  Overall approach: if pDes specified, try to convert image descriptor
223             if different, by adding filters with ilAddConversionFilter(): the des 
224             converting filter may add a reformat filter before it, and may change
225             the format - the new des and format are returned if changed.
226                 After converting the description if necessary, check format if
227             pFormat is non-null and reformat as necessary.  A format converter
228             cannot change the des.
229                 Note that we need not validate the format and des together.
230             ilAddPipeElement() will do that and return an error if they are incompatible
231             (e.g. des.type = IL_RGB with des.nSamplesPerPixel != 3).
232         */
233
234         /*  Get pipe info and decompress! if not ready for a filter, exit. 
235         */
236     if (ilGetPipeInfo (pipe, TRUE, &info, &pipeDes, &pipeFormat) != IL_PIPE_FORMING) {
237         if (!pipe->context->error)
238             ilDeclarePipeInvalid (pipe, IL_ERROR_PIPE_STATE);
239         return FALSE;                                   /* EXIT */
240         }
241
242         /*  If no pDes, point pDes to pipe des for format check below, else check for
243             descriptor conversions.
244         */
245     doSubsample = FALSE;    /* assume no subsampling; may be set below */
246     if (!pDes)
247         pDes = &pipeDes;
248     else {
249
250             /*  ilConvert() does not compress - use ilCompress() to compress. */
251         if (pDes->compression != IL_UNCOMPRESSED)
252             return ilDeclarePipeInvalid (pipe, IL_ERROR_CONVERT_COMPRESSION);
253
254         if (pipeDes.type == pDes->type)             /* cvt within type */
255             switch (pipeDes.type) {
256
257                 /*  Within YCbCr: check for changes to luma or refBlack/White.  If any, 
258                     convert to RGB; below cvt back to YCbCr will handle luma and ref.
259                 */
260               case IL_YCBCR: {
261                 const ilYCbCrSampleInfo   *pSrcSample, *pDstSample;
262                 ilBool              doCvtYCbCr;
263
264                     /* If must convert refBlack/White or lumaRed/Green/Blue, convert to 
265                        RGB and back to YCbCr; only those conversions handle this.
266                     */
267                 if ((pipeDes.typeInfo.YCbCr.lumaRed != pDes->typeInfo.YCbCr.lumaRed)
268                  || (pipeDes.typeInfo.YCbCr.lumaGreen != pDes->typeInfo.YCbCr.lumaGreen)
269                  || (pipeDes.typeInfo.YCbCr.lumaBlue != pDes->typeInfo.YCbCr.lumaBlue))
270                     doCvtYCbCr = TRUE;
271                 else {
272                     for (pSrcSample = pipeDes.typeInfo.YCbCr.sample,
273                          pDstSample = pDes->typeInfo.YCbCr.sample,
274                          doCvtYCbCr = FALSE, sample = 0; 
275                          sample < 3; sample++, pSrcSample++, pDstSample++) 
276                             if ((pSrcSample->refBlack != pDstSample->refBlack)
277                              || (pSrcSample->refWhite != pDstSample->refWhite))
278                                 doCvtYCbCr = TRUE;
279                     }
280                 if (doCvtYCbCr) {    /* cvt to RGB */
281                     if (!ilConvert (pipe, IL_DES_RGB, (ilImageFormat *)NULL, 0, NULL))
282                         return FALSE;
283                     ilGetPipeInfo (pipe, FALSE, &info, &pipeDes, &pipeFormat);
284                     }
285                 break;
286                 }
287
288                 /*  Within palette: if option is zero (0), or if option says to dither
289                     and image already dithered to requested levels: fine, done; otherwise
290                     cvt first to RGB, so below conversion to palette will be enabled.
291                 */
292               case IL_PALETTE:
293                 if (option == 0)
294                     break;                      /* default = accept as is; fine */
295                 if (option == IL_CONVERT_TO_PALETTE) {
296                     ilConvertToPaletteInfo *pData = (ilConvertToPaletteInfo *)pOptionData;
297                     if ((pipeDes.flags & IL_DITHERED_PALETTE)
298                      && (pipeDes.typeInfo.palette.levels[0] == pData->levels[0])
299                      && (pipeDes.typeInfo.palette.levels[1] == pData->levels[1])
300                      && (pipeDes.typeInfo.palette.levels[2] == pData->levels[2]))
301                         break;                  /* dithered to requested levels; fine */
302                     }
303                 if (!ADD_CVT_FILTER (&_ilPaletteToRGBByte))  /* cvt up to RGB */
304                     return FALSE;
305                 break;
306             }       /* END cvt within type */
307
308             /*  Loop converting image type until desired type reached.  May take some 
309                 iterations, e.g pal->bitonal = pal->rgb; rgb->gray; gray->bitonal.
310                     For conversion to YCbCr, cvt to RGB first.
311                     For conversion to palette, cvt to RGB first.
312             */
313         while (pipeDes.type != pDes->type) {
314             switch (pipeDes.type) {
315
316                 /*  Bitonal: cvt to gray, then to other types as necessary. */
317               case IL_BITONAL:
318                 switch (pDes->type) {
319                   case IL_GRAY:
320                   case IL_YCBCR:
321                   case IL_PALETTE:
322                   case IL_RGB: {
323                     if (!ilScale (pipe, info.width, info.height, IL_SCALE_BITONAL_TO_GRAY, NULL))
324                         return FALSE;
325                     ilGetPipeInfo (pipe, FALSE, &info, &pipeDes, &pipeFormat);
326                     break;
327                     }
328
329                   default:
330                     goto CantConvert;       /* unsupported conversion(s) */
331                     }
332                 break;
333
334               case IL_GRAY:
335
336                     /*  If not 256 levels/sample, cvt to 256 if possible. */
337                 if (pipeDes.nLevelsPerSample[0] != 256)
338                     if (!_ilAddLevelConversionFilter (pipe, &info, &pipeDes, IL_DES_GRAY, &pipeFormat))
339                         return FALSE;
340
341                 switch (pDes->type) {
342                   case IL_BITONAL:
343                     if (option == IL_CONVERT_THRESHOLD) {
344                         if (!pOptionData)
345                             pOptionData = &defaultThreshold;
346                         if (!ADD_CVT_FILTER (&_ilThresholdGrayToBitonal)) 
347                             return FALSE;   /* error, EXIT */
348                         }
349                     else if (!ADD_CVT_FILTER (&_ilDiffuseGrayToBitonal)) 
350                         return FALSE;       /* error, EXIT */
351                     break;
352
353                   case IL_YCBCR:
354                   case IL_PALETTE:
355                   case IL_RGB:
356                     if (!ADD_CVT_FILTER (&_ilGrayToRGB))
357                         return FALSE;       /* error, EXIT */
358                     break;
359
360                   default:
361                     goto CantConvert;       /* unsupported conversion(s) */
362                     }
363                 break;
364
365                 /*  Palette to anything (except self - but that case wont get here)
366                     is currently done by converting to RGB, then to des type if necessary.
367                 */
368               case IL_PALETTE:
369                 if (!ADD_CVT_FILTER (&_ilPaletteToRGBByte)) 
370                     return FALSE;           /* error, EXIT */
371                 break;
372
373                 /*  RGB goes to gray for gray or bitonal; handle conversion to YCbCr.
374                     If not 256 levels/sample, cvt to 256 if possible.
375                 */
376               case IL_RGB:
377                 if ((pipeDes.nLevelsPerSample[0] != 256)
378                  || (pipeDes.nLevelsPerSample[1] != 256)
379                  || (pipeDes.nLevelsPerSample[2] != 256))
380                     if (!_ilAddLevelConversionFilter (pipe, &info, &pipeDes, IL_DES_RGB, &pipeFormat))
381                         return FALSE;
382         
383                 switch (pDes->type) {
384                   case IL_BITONAL:
385                   case IL_GRAY:
386                     if (!ADD_CVT_FILTER (&_ilRGBToGray))
387                         return FALSE;       /* error, EXIT */
388                     break;
389
390                   case IL_YCBCR:
391                     if (!_ilConvertRGBToYCbCr (pipe, &info, &pipeDes, pDes, &pipeFormat))
392                         return FALSE;
393                     break;
394
395                     /*  Cvt RGB to palette: set pipeDes.type to IL_PALETTE to terminate
396                         loop: private type may actually have been created.
397                     */
398                   case IL_PALETTE:
399                     if (!_ilConvertRGBToPalette (pipe, &info, &pipeDes, &pipeFormat,
400                                     option, (ilConvertToPaletteInfo *)pOptionData))
401                         return FALSE;
402                     pipeDes.type = IL_PALETTE;          /* see note above */
403                     break;
404
405                   default:
406                     goto CantConvert;       /* unsupported conversion(s) */
407                     }
408                 break;
409
410                 /*  YCbCr (aka LUV): convert based on dst type and set "convertDone"
411                     to true, else convert to RGB, and then loop again until desired type.
412                 */
413               case IL_YCBCR: {
414                 ilBool  convertDone, upSample;
415
416                 upSample = MUST_UPSAMPLE (pipeDes);
417                 convertDone = FALSE;
418
419                 switch (pDes->type) {
420                   case IL_BITONAL:
421                   case IL_GRAY:         /* extract Y plane if Y range 0..255 */
422                     if ((pipeDes.typeInfo.YCbCr.sample[0].refBlack == 0)
423                      && (pipeDes.typeInfo.YCbCr.sample[0].refWhite == 255)) {
424                         if (!_ilUpsampleYCbCr (pipe, &info, &pipeDes, &pipeFormat, TRUE, 
425                                                upSample))
426                             return FALSE;
427                         convertDone = TRUE;
428                         }
429                     break;
430                   case IL_PALETTE:      /* try direct YCbCr to palette conversion */
431                     if (_ilDitherYCbCr (pipe, &info, &pipeDes, &pipeFormat, option,
432                                         (ilConvertToPaletteInfo *)pOptionData)) {
433                         convertDone = TRUE;
434                         pipeDes.type = IL_PALETTE;  /* see note above RGB->palette */
435                         }
436                     else if (pipe->context->error)
437                         return FALSE;   /* otherwise, no error; filter just cant do it */
438                     break;
439                     }
440
441                 if (!convertDone) {     /* no conversion; convert YCbCr to RGB */
442                     if (upSample && !_ilUpsampleYCbCr (pipe, &info, &pipeDes, 
443                                                        &pipeFormat, FALSE, upSample))
444                             return FALSE;
445                     if (!_ilConvertYCbCrToRGB (pipe, &info, &pipeDes, &pipeFormat))
446                         return FALSE;
447                     }
448                 break;
449                 }
450                 }   /* END switch source type */
451             }       /* END while convert type */
452
453
454             /*  Image type converted if different; check rest of des. */
455         if (pipeDes.nSamplesPerPixel != pDes->nSamplesPerPixel)
456             goto CantConvert;
457
458             /*  Check levels/sample, but not for palette images, where the levels/sample
459                 must be in range 2 .. (1<<nbits) - 1, but is otherwise ignored.
460             */
461         for (sample = 0; sample < pDes->nSamplesPerPixel; sample++)
462             if (pipeDes.nLevelsPerSample[sample] != pDes->nLevelsPerSample[sample]) {
463                 if ((pipeDes.type != IL_PALETTE) &&
464                  !_ilAddLevelConversionFilter (pipe, &info, &pipeDes, pDes, &pipeFormat))
465                     return FALSE;
466                 break;
467                 }
468
469             /*  Do image type-specific checks and conversions. */
470         switch (pipeDes.type) {
471
472             /*  "blackIsZero" applies only to bitonal and gray scale images. If different
473                 then invert bits if not "soft" invert (which means leave bits alone);
474                 if same, invert bits if "hard" invert (which means invert bits).
475             */
476           case IL_BITONAL:
477           case IL_GRAY:
478             if (pipeDes.blackIsZero != pDes->blackIsZero) {
479                 pipeDes.blackIsZero = pDes->blackIsZero;
480                 if (option == IL_CONVERT_SOFT_INVERT)
481                     _ilSetPipeDesFormat (pipe, &pipeDes, (ilImageFormat *)NULL);
482                 else if (!_ilAddInvertFilter (pipe, &pipeDes, &info)) 
483                     goto CantConvert;
484                  }
485             break;
486
487             /*  YCbCr: check sub/upsampling; up/subsample as necessary */
488           case IL_YCBCR: {
489                 const ilYCbCrSampleInfo   *pSrcSample, *pDstSample;
490                 ilBool              doUpsample;
491
492                 doSubsample = FALSE;        /* checked below */
493                 for (pSrcSample = pipeDes.typeInfo.YCbCr.sample,
494                      pDstSample = pDes->typeInfo.YCbCr.sample,
495                      doUpsample = FALSE, sample = 0; 
496                      sample < 3; sample++, pSrcSample++, pDstSample++) 
497                     {
498                     if (pSrcSample->subsampleHoriz < pDstSample->subsampleHoriz)
499                         doSubsample = TRUE;
500                     else if (pSrcSample->subsampleHoriz > pDstSample->subsampleHoriz)
501                         doUpsample = TRUE;
502                     if (pSrcSample->subsampleVert < pDstSample->subsampleVert)
503                         doSubsample = TRUE;
504                     else if (pSrcSample->subsampleVert > pDstSample->subsampleVert)
505                         doUpsample = TRUE;
506                     }
507                 if (doUpsample)
508                     if (!_ilUpsampleYCbCr (pipe, &info, &pipeDes, &pipeFormat, FALSE, TRUE))
509                         return FALSE;
510                 if (doSubsample) {
511                     pipeDes = *pDes;        /* pass subsample pars; des convert done */
512                     if (!_ilSubsampleYCbCr (pipe, &info, &pipeDes, &pipeFormat))
513                         return FALSE;
514                     }
515                 }   /* END YCbCr */
516             break;
517             }
518         }   /* END check pDes */
519
520
521         /*  If pFormat given, convert to requested format.
522             WARNING !!!!! - ilCheckPipeFormat() below also does format conversions -
523             May have to change it when adding new format filters !!!!
524         */
525     if (pFormat) {
526
527             /*  Check if bits/sample needs conversion and if that conversion supported.
528                 Currently supported: 4 to 8 bit, pixel mode only if multi-sample.
529             */
530         doConvert = FALSE;
531         for (sample = 0; sample < pDes->nSamplesPerPixel; sample++)
532             if (pipeFormat.nBitsPerSample[sample] != pFormat->nBitsPerSample[sample]) {
533                 doConvert = TRUE;
534                 break;
535                 }
536
537             /*  If any format conversions and YCbCr, upsample if necessary.
538                 However, if subsampling was done before, error: cant convert.
539             */
540         if ((pipeDes.type == IL_YCBCR) 
541          && MUST_UPSAMPLE (pipeDes)
542          && (doConvert || (pipeFormat.sampleOrder != pFormat->sampleOrder)
543                        || (pipeFormat.rowBitAlign != pFormat->rowBitAlign))) {
544             if (doSubsample)
545                 goto CantConvert;       /* cant upsample - subsampled before */
546             if (!_ilUpsampleYCbCr (pipe, &info, &pipeDes, &pipeFormat, FALSE, TRUE))
547                 return FALSE;
548             }
549
550             /*  If doConvert, then pipe image does not have desired # of bits/sample.
551                 Check if all planes have same # src, dst bits; else can't convert.
552                 Currently can convert 4->8 or 8->4.
553             */
554         if (doConvert) {
555             int         nSrcBits, nDstBits;
556             if ((pipeDes.nSamplesPerPixel > 1) && (pFormat->sampleOrder != IL_SAMPLE_PIXELS))
557                 goto CantConvert;
558             nSrcBits = pipeFormat.nBitsPerSample[0];
559             nDstBits = pFormat->nBitsPerSample[0];
560             for (sample = 1; sample < pDes->nSamplesPerPixel; sample++)
561                 if ((nSrcBits != pipeFormat.nBitsPerSample[sample])
562                  || (nDstBits != pFormat->nBitsPerSample[sample]))
563                     goto CantConvert;           /* not same # src,dst bits each plane */
564
565             if ((nSrcBits == 4) && (nDstBits == 8)) {
566                 if (!ilAddFormatFilter (pipe, &info, pFormat, &_ilFormat4To8Bit))
567                     return FALSE;
568                 }
569             else if ((nSrcBits == 8) && (nDstBits == 4)) {
570                 if (!ilAddFormatFilter (pipe, &info, pFormat, &_ilFormat8To4Bit))
571                     return FALSE;
572                 }
573             else goto CantConvert;
574             }
575
576             /*  Change sample order: only handles 3 samples, each 8 bits. */
577         if (pipeFormat.sampleOrder != pFormat->sampleOrder) {
578             if ((pipeDes.nSamplesPerPixel != 3)
579              || (pipeFormat.nBitsPerSample[0] != 8)
580              || (pipeFormat.nBitsPerSample[1] != 8)
581              || (pipeFormat.nBitsPerSample[2] != 8))
582                 goto CantConvert;
583             if (pipeFormat.sampleOrder == IL_SAMPLE_PIXELS) {
584                  if (!ilAddFormatFilter (pipe, &info, pFormat, &_ilFormat8Bit3PixelToPlane))
585                     return FALSE;
586                 }
587             else if (!ilAddFormatFilter (pipe, &info, pFormat, &_ilFormat8Bit3PlaneToPixel))
588                 return FALSE;
589             }
590
591         if (pipeFormat.rowBitAlign != pFormat->rowBitAlign) {
592             if (!ilAddFormatFilter (pipe, &info, pFormat, &_ilFormatRowBitAlign))
593                 return FALSE;
594             }
595         }
596
597         /*  Succesful conversion.
598         */
599     pipe->context->error = IL_OK;
600     return TRUE;                                   /* EXIT */
601
602
603     /*  GOTO point for when conversion not supported.  
604     */
605 CantConvert:
606     ilDeclarePipeInvalid (pipe, IL_ERROR_CANT_CONVERT);
607     return FALSE;
608 }
609
610 #ifdef NOTDEF
611
612     IN PROGRESS - NOT DONE YET !!!!!!!!!!
613
614     /*  ------------------------ ilCheckPipeFormat --------------------------------- */
615     /*  Return an IL_CPF_? code for the current pipe image format, or 
616         IL_CPF_ERROR if error or can't match formats in "formatMask".
617         The pipe info, des and/or format are returned to non-null
618         pInfo/Des/Format if IL_CPF_ERROR not returned.
619     */
620 unsigned int ilCheckPipeFormat (
621     ilPipe                  pipe,
622     register unsigned long  formatMask,
623     ilPipeInfo             *pInfo,              /* RETURNED */
624     register ilImageDes    *pDes,               /* RETURNED */
625     register ilImageFormat *pFormat             /* RETURNED */
626     )
627 {
628     ilPipeInfo          localInfo;
629     ilImageDes          localDes;
630     ilImageFormat       localFormat;
631
632         /*  Point pInfo/Des/Format to local structs if caller passed NULL */
633     if (!pInfo) pInfo = &localInfo;
634     if (!pDes) pDes = &localDes;
635     if (!pFormat) pFormat = &localFormat;
636
637         /*  Get pipe info and decompress; if pipe not in IL_PIPE_FORMING state: error. */                          
638     if (ilGetPipeInfo (pipe, TRUE, pInfo, pDes, pFormat) != IL_PIPE_FORMING) {
639         if (!pipe->context->error)
640             ilDeclarePipeInvalid (pipe, IL_ERROR_PIPE_STATE);
641         return IL_CPF_ERROR;
642         }
643
644         /*  Look at des, format and try to match/convert to format(s) caller accepts */
645     if (pDes->nSamplesPerPixel == 1) {
646
647             /*  1 sample/pixel: if bit/pixel and caller accepts, check rowBitAlign */
648         if ((formatMask & IL_CPF_BIT) && (pFormat->nBitsPerSample[0] == 1)) {
649             if (pFormat->rowBitAlign != 32) {
650                 pFormat->rowBitAlign = 32;
651                 if (!ilAddFormatFilter (pipe, pInfo, pFormat, &ilFormatRowBitAlign))
652                     return IL_CPF_ERROR;
653                 return IL_CPF_BIT;                  /* match found: bit/pixel */
654                 }
655             }
656         else {
657                 /*  1 sample, bit not accepted; error if byte not accepted, make byte */
658             if (!(formatMask & IL_CPF_BYTE))
659                 return IL_CPF_ERROR;
660             if (pFormat->nBitsPerSample[0] != 8) {
661                 if (pFormat->nBitsPerSample[0] == 4) {
662                     pFormat->nBitsPerSample[0] = 8;
663                     if (!ilAddFormatFilter (pipe, pInfo, pFormat, &ilFormat4To8Bit))
664                         return IL_CPF_ERROR;
665                     }
666                 else return IL_CPF_ERROR;   /* NOTE!! currently only 4-8 supported!!! */
667                 }
668             return IL_CPF_BYTE;                     /* match found: 1 byte/pixel */
669             }
670         }       /* END 1 sample/pixel */
671     else {      /* multi-sample/pixel */
672         }
673
674 }
675
676 #endif
677