1 //  ----------------------------------------------------------------------------
2 //  MODULE    : BufferDesc
3 //  LANGUAGE  : C++
4 //  CREATOR   : Philippe BOSSUT
5 //  CREAT. DATE : Monday, March 25, 1996
6 //  DESCRIPTION :
7 //  COMMENTS  :
8 //      SCCSID          : @(#)buffdesc.cpp  1.10 12:46:27 01 Jul 1997
9 //  ----------------------------------------------------------------------------
10 //  Copyright (c) 1999 Digital Imaging Group, Inc.
11 //  For conditions of distribution and use, see copyright notice
12 //  in Flashpix.h
13 //  ----------------------------------------------------------------------------
14 
15 #ifndef BufferDesc_h
16   #include "buffdesc.h"
17 #endif
18   #include "thmbnail.h"
19 //  ----------------------------------------------------------------------------
20 
21 //  Includes
22 //  --------
23 
24   #include <stdlib.h>
25   #include <math.h>
26 #ifdef _WINDOWS
27   #include <windows.h>
28 #endif
29 
30 #ifndef Debug_h
31   #include "debug.h"
32 #endif
33 #ifndef ColorTwist_h
34   #include "coltwist.h"
35 #endif
36 #ifndef Compresseur32Vers24_h
37     #include "cp32to24.h"
38 #endif
39 #ifndef OLECore_h
40     #include "olecore.h"
41 #endif
42 #ifndef FlashPixUtils_h
43     #include "fpxutils.h"
44 #endif
45 #ifndef SwapBytes_h
46   #include "swapbyte.h"
47 #endif
48 
49 //  Constants
50 //  ---------
51 
52 //  Variables
53 //  ---------
54 
55 //  ----------------------------------------------------------------------------
56 //  Internal Functions
57 //  ----------------------------------------------------------------------------
58 
59 // Init alpha bytes to 255 (opaque) for each pixel starting at buffer
InitByteTo255(unsigned char * buffer,long size)60 static void InitByteTo255 (unsigned char* buffer, long size)
61 {
62   while (size--) {
63     *buffer = 255;
64     buffer += 4;
65   }
66 }
67 
68 #if 0
69 // Init alpha bytes to 0 (transparent) for each pixel starting at buffer
70 static void InitByteTo0 (unsigned char* buffer, long size)
71 {
72   while (size--) {
73     *buffer = 0;
74     buffer += 4;
75   }
76 }
77 #endif
78 
79 //Updated the procedure to work on both architedture --**IM-05/16/97
80 // Rotate on the left by 8 bits on each 32 bits long and wrap the last one
Shift8BitsLeft(unsigned char * buffer,long size)81 static void Shift8BitsLeft (unsigned char* buffer, long size)
82 {
83   unsigned char  tmp;
84   while (size--) {
85 	tmp = buffer[0];
86 	buffer[0] = buffer[1];
87 	buffer[1] = buffer[2];
88 	buffer[2] = buffer[3];
89 	buffer[3] = tmp;
90 	buffer += 4;
91   }
92 }
93 
94 // Rotate on the right by 8 bits on each 32 bits long and wrap the last one
Shift8BitsRight(unsigned char * buffer,long size)95 static void Shift8BitsRight (unsigned char* buffer, long size)
96 {
97   unsigned char  tmp;
98   while (size--) {
99 	tmp = buffer[3];
100 	buffer[3] = buffer[2];
101 	buffer[2] = buffer[1];
102 	buffer[1] = buffer[0];
103 	buffer[0] = tmp;
104 	buffer += 4;
105   }
106 }
107 
108 // Copy a byte and erase its ancient address be 2 bytes on the right (don't move the rest)
MoveByteRightBy2(unsigned char * buffer,long size)109 static void MoveByteRightBy2(unsigned char* buffer, long size)
110 {
111   register unsigned char* next;
112   next = buffer + 2;
113   while (size--) {
114     *next = *buffer;
115     *buffer = 0;
116     buffer += 4;
117     next   += 4;
118   }
119 }
120 
121 // Copy a byte and erase its ancient address be 2 bytes on the left (don't move the rest)
MoveByteLeftBy2(unsigned char * buffer,long size)122 static void MoveByteLeftBy2(unsigned char* buffer, long size)
123 {
124   register unsigned char* next;
125   next = buffer - 2;
126   while (size--) {
127     *next = *buffer;
128     *buffer = 0;
129     buffer += 4;
130     next   += 4;
131   }
132 }
133 
134 
135 // Apply the transformations :
136 // ---------------------------
137 // CAUTION: For the moment, we make the hypothesis that T44 is equal to 1 and that a
138 // pixel is 4 bytes wide.
139 
ConvertRGBtoYCC(unsigned char * buffer,long size)140 void ConvertRGBtoYCC(unsigned char* buffer, long size)
141 {
142   PColorTwist tRGBTorgb(RGB8_to_rgb);   // 8-bit NIF RGB to normalized PhotoRGB
143   PColorTwist trgbToycc(rgb_to_ycc);    // Normalized PhotoRGB to normalized PhotoYCC
144   PColorTwist tyccToYCC(ycc_to_YCC8);   // Normalized PhotoYCC to 8-bit PhotoYCC
145 
146   PColorTwist tRGBtoYCC;
147   tRGBtoYCC = trgbToycc * tRGBTorgb;
148   tRGBtoYCC = tyccToYCC * tRGBtoYCC;
149 
150   // PTCH_302 Added the following call to apply a shaping LUT to the output of
151   //  the matrix transform.
152   tRGBtoYCC.ApplyRGBtoYCCLut(buffer,size);
153 }
154 
ConvertYCCtoRGB(unsigned char * buffer,long size,Boolean useAlpha)155 void ConvertYCCtoRGB(unsigned char* buffer, long size, Boolean useAlpha)
156 {
157   PColorTwist tYCCtoycc(YCC8_to_ycc);   // 8-bit PhotoYCC to normalized PhotoYCC
158   PColorTwist tyccTorgb(ycc_to_rgb);    // Normalized PhotoYCC to normalized PhotoRGB
159   PColorTwist trgbToRGB(rgb_to_RGB8);   // Normalized PhotoRGB to 8-bit NIF RGB
160 
161   PColorTwist tYCCtoRGB;
162   tYCCtoRGB = tyccTorgb * tYCCtoycc;
163   tYCCtoRGB = trgbToRGB * tYCCtoRGB;
164 
165   tYCCtoRGB.UsePortfolioLut();
166   if(useAlpha)
167     tYCCtoRGB.UseAlphaChannel();
168   tYCCtoRGB.ApplyToBuffer(buffer,size);
169 }
170 
171 
172 // PTCH_302 ConvertYCCtoMonochrome() was completely rewritten
ConvertYCCtoMonochrome(unsigned char * buffer,long size)173 static void ConvertYCCtoMonochrome(unsigned char* buffer, long size)
174 {
175   PColorTwist tRGBtorgb(RGB8_to_rgb);
176   PColorTwist trgbTomono(rgb_to_mono);
177   PColorTwist tmonoToMONO(rgb_to_RGB8);
178 
179     ConvertYCCtoRGB(buffer, size, FALSE);
180 
181   PColorTwist tRGBtoMONO;
182   tRGBtoMONO = trgbTomono  * tRGBtorgb;
183   tRGBtoMONO = tmonoToMONO * tRGBtoMONO;
184 
185   tRGBtoMONO.ApplyToBuffer(buffer,size);
186 
187 /* pre-PTCH_302 code
188   while (size--) {
189     *(buffer+2) = *buffer;
190     *buffer     = 0;
191     *(buffer+1) = 0;
192     buffer += 4;
193   }
194 */
195 }
196 
197 // PTCH_302 ConvertRGBtoMonochrome() was completely rewritten
ConvertRGBtoMonochrome(unsigned char * buffer,long size)198 static void ConvertRGBtoMonochrome(unsigned char* buffer, long size)
199 {
200   PColorTwist tRGBtorgb(RGB8_to_rgb);
201   PColorTwist trgbTomono(rgb_to_mono);
202   PColorTwist tmonoToMONO(rgb_to_RGB8);
203 
204   PColorTwist tRGBtoMONO;
205   tRGBtoMONO = trgbTomono  * tRGBtorgb;
206   tRGBtoMONO = tmonoToMONO * tRGBtoMONO;
207 
208   tRGBtoMONO.ApplyToBuffer(buffer,size);
209 
210 /* pre-PTCH_302 code
211   ConvertRGBtoYCC(buffer,size);
212   ConvertYCCtoMonochrome(buffer,size);
213 */
214 }
215 
ConvertMonochrometoRGB(unsigned char * buffer,long size)216 static void ConvertMonochrometoRGB(unsigned char* buffer, long size)
217 {
218   while (size--) {
219     *buffer     = *(buffer+2);
220     *(buffer+1) = *(buffer+2);
221     buffer += 4;
222   }
223 }
224 
225 // PTCH_302 ConvertMonochrometoYCC() was completely rewritten
ConvertMonochrometoYCC(unsigned char * buffer,long size)226 static void ConvertMonochrometoYCC(unsigned char* buffer, long size)
227 {
228   ConvertMonochrometoRGB(buffer, size);
229   ConvertRGBtoYCC(buffer, size);
230 }
231 
232 
233 
234 //  ----------------------------------------------------------------------------
235 //  Member Functions
236 //  ----------------------------------------------------------------------------
InitImageDesc(FPXBaselineColorSpace colorSpace)237 void FPXBufferDesc::InitImageDesc(FPXBaselineColorSpace colorSpace)
238 {
239   colorSpaceType = colorSpace;
240 
241   // Allocate an image descriptor
242   FPXdesc = new FPXImageDesc;
243   if (FPXdesc==NULL) {
244     return;
245   }
246   localDesc = true;
247 
248   // Set the things common to all Baseline descriptors
249   FPXdesc->components[0].myColorType.myDataType = DATA_TYPE_UNSIGNED_BYTE;
250   FPXdesc->components[1].myColorType.myDataType = DATA_TYPE_UNSIGNED_BYTE;
251   FPXdesc->components[2].myColorType.myDataType = DATA_TYPE_UNSIGNED_BYTE;
252   FPXdesc->components[3].myColorType.myDataType = DATA_TYPE_UNSIGNED_BYTE;
253 
254   FPXdesc->components[0].horzSubSampFactor = 1;
255   FPXdesc->components[1].horzSubSampFactor = 1;
256   FPXdesc->components[2].horzSubSampFactor = 1;
257   FPXdesc->components[3].horzSubSampFactor = 1;
258 
259   FPXdesc->components[0].vertSubSampFactor = 1;
260   FPXdesc->components[1].vertSubSampFactor = 1;
261   FPXdesc->components[2].vertSubSampFactor = 1;
262   FPXdesc->components[3].vertSubSampFactor = 1;
263 
264   FPXdesc->components[0].columnStride = 4;
265   FPXdesc->components[1].columnStride = 4;
266   FPXdesc->components[2].columnStride = 4;
267   FPXdesc->components[3].columnStride = 4;
268 
269   FPXdesc->components[0].lineStride = width * 4;
270   FPXdesc->components[1].lineStride = width * 4;
271   FPXdesc->components[2].lineStride = width * 4;
272   FPXdesc->components[3].lineStride = width * 4;
273 
274   // Set the specific part according to the color space type
275   switch (colorSpaceType) {
276     case SPACE_32_BITS_RGB:
277       FPXdesc->numberOfComponents = 3;
278       FPXdesc->components[0].myColorType.myColor = NIFRGB_R;
279       FPXdesc->components[1].myColorType.myColor = NIFRGB_G;
280       FPXdesc->components[2].myColorType.myColor = NIFRGB_B;
281       FPXdesc->components[0].theData = (unsigned char*)(buffer) + 1;
282       FPXdesc->components[1].theData = (unsigned char*)(buffer) + 2;
283       FPXdesc->components[2].theData = (unsigned char*)(buffer) + 3;
284       break;
285     case SPACE_32_BITS_ARGB:
286       FPXdesc->numberOfComponents = 4;
287       FPXdesc->components[0].myColorType.myColor = ALPHA;
288       FPXdesc->components[1].myColorType.myColor = NIFRGB_R;
289       FPXdesc->components[2].myColorType.myColor = NIFRGB_G;
290       FPXdesc->components[3].myColorType.myColor = NIFRGB_B;
291       FPXdesc->components[0].theData = (unsigned char*)(buffer);
292       FPXdesc->components[1].theData = (unsigned char*)(buffer) + 1;
293       FPXdesc->components[2].theData = (unsigned char*)(buffer) + 2;
294       FPXdesc->components[3].theData = (unsigned char*)(buffer) + 3;
295       break;
296     case SPACE_32_BITS_RGBA:
297       FPXdesc->numberOfComponents = 4;
298       FPXdesc->components[0].myColorType.myColor = NIFRGB_R;
299       FPXdesc->components[1].myColorType.myColor = NIFRGB_G;
300       FPXdesc->components[2].myColorType.myColor = NIFRGB_B;
301       FPXdesc->components[3].myColorType.myColor = ALPHA;
302       FPXdesc->components[0].theData = (unsigned char*)(buffer);
303       FPXdesc->components[1].theData = (unsigned char*)(buffer) + 1;
304       FPXdesc->components[2].theData = (unsigned char*)(buffer) + 2;
305       FPXdesc->components[3].theData = (unsigned char*)(buffer) + 3;
306       break;
307     case SPACE_32_BITS_YCC:
308       FPXdesc->numberOfComponents = 3;
309       FPXdesc->components[0].myColorType.myColor = PHOTO_YCC_Y;
310       FPXdesc->components[1].myColorType.myColor = PHOTO_YCC_C1;
311       FPXdesc->components[2].myColorType.myColor = PHOTO_YCC_C2;
312       FPXdesc->components[0].theData = (unsigned char*)(buffer) + 1;
313       FPXdesc->components[1].theData = (unsigned char*)(buffer) + 2;
314       FPXdesc->components[2].theData = (unsigned char*)(buffer) + 3;
315       break;
316     case SPACE_32_BITS_AYCC:
317       FPXdesc->numberOfComponents = 4;
318       FPXdesc->components[0].myColorType.myColor = ALPHA;
319       FPXdesc->components[1].myColorType.myColor = PHOTO_YCC_Y;
320       FPXdesc->components[2].myColorType.myColor = PHOTO_YCC_C1;
321       FPXdesc->components[3].myColorType.myColor = PHOTO_YCC_C2;
322       FPXdesc->components[0].theData = (unsigned char*)(buffer);
323       FPXdesc->components[1].theData = (unsigned char*)(buffer) + 1;
324       FPXdesc->components[2].theData = (unsigned char*)(buffer) + 2;
325       FPXdesc->components[3].theData = (unsigned char*)(buffer) + 3;
326       break;
327     case SPACE_32_BITS_YCCA:
328       FPXdesc->numberOfComponents = 4;
329       FPXdesc->components[0].myColorType.myColor = PHOTO_YCC_Y;
330       FPXdesc->components[1].myColorType.myColor = PHOTO_YCC_C1;
331       FPXdesc->components[2].myColorType.myColor = PHOTO_YCC_C2;
332       FPXdesc->components[3].myColorType.myColor = ALPHA;
333       FPXdesc->components[0].theData = (unsigned char*)(buffer);
334       FPXdesc->components[1].theData = (unsigned char*)(buffer) + 1;
335       FPXdesc->components[2].theData = (unsigned char*)(buffer) + 2;
336       FPXdesc->components[3].theData = (unsigned char*)(buffer) + 3;
337       break;
338     case SPACE_32_BITS_M:
339       FPXdesc->numberOfComponents = 1;
340       FPXdesc->components[0].myColorType.myColor = MONOCHROME;
341       FPXdesc->components[0].theData = (unsigned char*)(buffer) + 3;
342       break;
343     case SPACE_32_BITS_AM:
344       FPXdesc->numberOfComponents = 2;
345       FPXdesc->components[0].myColorType.myColor = ALPHA;
346       FPXdesc->components[1].myColorType.myColor = MONOCHROME;
347       FPXdesc->components[0].theData = (unsigned char*)(buffer) + 2;
348       FPXdesc->components[1].theData = (unsigned char*)(buffer) + 3;
349       break;
350     case SPACE_32_BITS_MA:
351       FPXdesc->numberOfComponents = 2;
352       FPXdesc->components[0].myColorType.myColor = MONOCHROME;
353       FPXdesc->components[1].myColorType.myColor = ALPHA;
354       FPXdesc->components[0].theData = (unsigned char*)(buffer) + 2;
355       FPXdesc->components[1].theData = (unsigned char*)(buffer) + 3;
356       break;
357     case SPACE_32_BITS_O:
358       FPXdesc->numberOfComponents = 1;
359       FPXdesc->components[0].myColorType.myColor = ALPHA;
360       FPXdesc->components[0].theData = (unsigned char*)(buffer) + 3;
361       break;
362     default:    // Not authorized in Baseline
363       assert(false);
364       break;
365   }
366 }
367 
368 
FPXBufferDesc(unsigned char * theBuffer,long theWidth,long theHeight,FPXBaselineColorSpace colorSpace)369 FPXBufferDesc::FPXBufferDesc (unsigned char* theBuffer, long theWidth, long theHeight, FPXBaselineColorSpace colorSpace)
370 {
371   // Set the private datas
372   width  = theWidth;
373   height = theHeight;
374 
375   buffer = theBuffer;
376   localBuffer = false;
377   useInternalBuffer = true;                   // PTCH_102
378 
379   // Init the color space description
380   InitImageDesc(colorSpace);
381 }
382 
FPXBufferDesc(long theColor,long theWidth,long theHeight,FPXBaselineColorSpace colorSpace)383 FPXBufferDesc::FPXBufferDesc (long theColor, long theWidth, long theHeight, FPXBaselineColorSpace colorSpace)
384 {
385   // Set the private datas
386   width  = theWidth;
387   height = theHeight;
388 
389   localBuffer = true;
390   buffer = new unsigned char [width * height * 4];
391   if (buffer==NULL) {
392     return;
393   }
394   useInternalBuffer = false;                    // PTCH_102
395 
396   // Init the color space description
397   InitImageDesc(colorSpace);
398 
399   // Fill the buffer with the background color: copy 32 bits at once
400   int32_t *pt = (int32_t*)(buffer);
401   for (int i = 0; i < height; ++i)
402     for (int j = 0; j < width; ++j, ++pt)
403       *pt = theColor;
404 }
405 
FPXBufferDesc(FPXImageDesc * desc,long theWidth,long theHeight,unsigned char * internalBuffer)406 FPXBufferDesc::FPXBufferDesc (FPXImageDesc* desc, long theWidth, long theHeight,
407                 unsigned char *internalBuffer)
408 {
409   width     = theWidth;
410   height    = theHeight;
411   FPXdesc   = desc;
412   localDesc = false;
413 
414   FPXColorspace colorSpace;
415   ExtractFPXColorSpaceFromFPXImageDesc(*desc, &colorSpace);
416   colorSpaceType = AnalyseFPXColorSpace(colorSpace);
417   useInternalBuffer = false;
418 
419   if (IsASupportedDescriptor(*desc,width)) {
420     localBuffer = false;
421     buffer = FPXdesc->components[0].theData - (4 - FPXdesc->numberOfComponents);
422   }
423   else if (internalBuffer != NULL) {
424     localBuffer = true;
425     useInternalBuffer = true;
426     buffer = internalBuffer;
427   }
428   else {
429     localBuffer = true;
430     buffer = new unsigned char [width * height * 4];
431     if (buffer==NULL) {
432       return;
433     }
434   }
435 }
436 
~FPXBufferDesc()437 FPXBufferDesc::~FPXBufferDesc ()
438 {
439   if (localDesc)
440     delete FPXdesc;
441 
442   if (localBuffer && !useInternalBuffer)
443   {
444     delete [] buffer;
445     buffer = NULL;
446   }
447 }
448 
UpdateBuffer()449 void FPXBufferDesc::UpdateBuffer ()
450 {
451   // If the pixels are stored in a local buffer, they have to be transfered from the
452   // image descriptor to the buffer
453   if (localBuffer) {
454     register long i, j;
455 
456     register long incLine0 = FPXdesc->components[0].lineStride;
457     register long incLine1 = FPXdesc->components[1].lineStride;
458     register long incLine2 = FPXdesc->components[2].lineStride;
459     register long incLine3 = FPXdesc->components[3].lineStride;
460     register long incCol0  = FPXdesc->components[0].columnStride;
461     register long incCol1  = FPXdesc->components[1].columnStride;
462     register long incCol2  = FPXdesc->components[2].columnStride;
463     register long incCol3  = FPXdesc->components[3].columnStride;
464 
465     unsigned char* pt0;
466     unsigned char* pt1;
467     unsigned char* pt2;
468     unsigned char* pt3;
469 
470     unsigned char* pix;
471     long  nbChan = FPXdesc->numberOfComponents;
472     register long  incCol;
473 
474     if (nbChan == 1) {
475       pix    = buffer + 3;
476       incCol = 4;
477       for (j = 0; j < height; j++) {
478         pt0 = (unsigned char*)(FPXdesc->components[0].theData) + j*incLine0;
479         for (i = 0; i < width; i++, pix += incCol) {
480           *pix  = *pt0;
481            pt0 +=  incCol0;
482         }
483       }
484     } else if (nbChan == 2) {
485       pix    = buffer + 2;
486       incCol = 3;
487       for (j = 0; j < height; j++) {
488         pt0 = (unsigned char*)(FPXdesc->components[0].theData) + j*incLine0;
489         pt1 = (unsigned char*)(FPXdesc->components[1].theData) + j*incLine1;
490         for (i = 0; i < width; i++, pix += incCol) {
491           *pix++ = *pt0;    *pix  = *pt1;
492            pt0  +=  incCol0; pt1 +=  incCol1;
493         }
494       }
495     } else if (nbChan == 3) {
496       pix    = buffer + 1;
497       incCol = 2;
498       for (j = 0; j < height; j++) {
499         pt0 = (unsigned char*)(FPXdesc->components[0].theData) + j*incLine0;
500         pt1 = (unsigned char*)(FPXdesc->components[1].theData) + j*incLine1;
501         pt2 = (unsigned char*)(FPXdesc->components[2].theData) + j*incLine2;
502         for (i = 0; i < width; i++, pix += incCol) {
503           *pix++ = *pt0;    *pix++ = *pt1;    *pix  = *pt2;
504            pt0  +=  incCol0; pt1  +=  incCol1; pt2 +=  incCol2;
505         }
506       }
507     } else if (nbChan == 4) {
508       pix    = buffer;
509       for (j = 0; j < height; j++) {
510         pt0 = (unsigned char*)(FPXdesc->components[0].theData) + j*incLine0;
511         pt1 = (unsigned char*)(FPXdesc->components[1].theData) + j*incLine1;
512         pt2 = (unsigned char*)(FPXdesc->components[2].theData) + j*incLine2;
513         pt3 = (unsigned char*)(FPXdesc->components[3].theData) + j*incLine3;
514         for (i = 0; i < width; i++) {
515           *pix++ = *pt0;    *pix++ = *pt1;    *pix++ = *pt2;    *pix++ = *pt3;
516            pt0  +=  incCol0; pt1  +=  incCol1; pt2  +=  incCol2; pt3  +=  incCol3;
517         }
518       }
519     }
520 
521   }
522 }
523 
UpdateDescriptor()524 void FPXBufferDesc::UpdateDescriptor ()
525 {
526   // If the pixels are stored in a local buffer, they have to be transfered to the
527   // image descriptor
528   if (localBuffer) {
529     register long i, j;
530 
531     register long incLine0 = FPXdesc->components[0].lineStride;
532     register long incLine1 = FPXdesc->components[1].lineStride;
533     register long incLine2 = FPXdesc->components[2].lineStride;
534     register long incLine3 = FPXdesc->components[3].lineStride;
535     register long incCol0  = FPXdesc->components[0].columnStride;
536     register long incCol1  = FPXdesc->components[1].columnStride;
537     register long incCol2  = FPXdesc->components[2].columnStride;
538     register long incCol3  = FPXdesc->components[3].columnStride;
539 
540     unsigned char* pt0;
541     unsigned char* pt1;
542     unsigned char* pt2;
543     unsigned char* pt3;
544 
545     unsigned char* pix;
546     long  nbChan = FPXdesc->numberOfComponents;
547     register long  incCol;
548 
549     if (nbChan == 1) {
550       pix    = buffer + 3;
551       incCol = 4;
552       for (j = 0; j < height; j++) {
553         pt0 = (unsigned char*)(FPXdesc->components[0].theData) + j*incLine0;
554         for (i = 0; i < width; i++, pix += incCol) {
555           *pt0  = *pix;
556            pt0 += incCol0;
557         }
558       }
559     } else if (nbChan == 2) {
560       pix    = buffer + 2;
561       incCol = 3;
562       for (j = 0; j < height; j++) {
563         pt0 = (unsigned char*)(FPXdesc->components[0].theData) + j*incLine0;
564         pt1 = (unsigned char*)(FPXdesc->components[1].theData) + j*incLine1;
565         for (i = 0; i < width; i++, pix += incCol) {
566           *pt0  = *pix++;  *pt1  = *pix;
567            pt0 +=  incCol0; pt1 +=  incCol1;
568         }
569       }
570     } else if (nbChan == 3) {
571       pix    = buffer + 1;
572       incCol = 2;
573       for (j = 0; j < height; j++) {
574         pt0 = (unsigned char*)(FPXdesc->components[0].theData) + j*incLine0;
575         pt1 = (unsigned char*)(FPXdesc->components[1].theData) + j*incLine1;
576         pt2 = (unsigned char*)(FPXdesc->components[2].theData) + j*incLine2;
577         for (i = 0; i < width; i++, pix += incCol) {
578           *pt0  = *pix++;  *pt1  = *pix++;  *pt2  = *pix;
579            pt0 +=  incCol0; pt1 +=  incCol1; pt2 +=  incCol2;
580         }
581       }
582     } else if (nbChan == 4) {
583       pix    = buffer;
584       for (j = 0; j < height; j++) {
585         pt0 = (unsigned char*)(FPXdesc->components[0].theData) + j*incLine0;
586         pt1 = (unsigned char*)(FPXdesc->components[1].theData) + j*incLine1;
587         pt2 = (unsigned char*)(FPXdesc->components[2].theData) + j*incLine2;
588         pt3 = (unsigned char*)(FPXdesc->components[3].theData) + j*incLine3;
589         for (i = 0; i < width; i++) {
590           *pt0  = *pix++;  *pt1  = *pix++;  *pt2  = *pix++;  *pt3  = *pix++;
591            pt0 +=  incCol0; pt1 +=  incCol1; pt2 +=  incCol2; pt3 +=  incCol3;
592         }
593       }
594     }
595   }
596 }
597 
598 
599 //  ----------------------------------------------------------------------------
600 //  External Functions
601 //  ----------------------------------------------------------------------------
602 
603 // Tells if the space contains an alpha channel
IsAlphaBaseline(FPXBaselineColorSpace baseSpace)604 Boolean IsAlphaBaseline(FPXBaselineColorSpace baseSpace)
605 {
606   Boolean isAlpha = true;
607   if ((baseSpace == SPACE_32_BITS_RGB) ||
608     (baseSpace == SPACE_32_BITS_YCC) ||
609     (baseSpace == SPACE_32_BITS_M))
610     isAlpha = false;
611   return isAlpha;
612 }
613 
614 // Get the position of the alpha channel in a 32 bits pixel according to the color space used
GetAlphaOffsetBaseline(FPXBaselineColorSpace baseSpace)615 long GetAlphaOffsetBaseline(FPXBaselineColorSpace baseSpace)
616 {
617   long offset;
618   switch (baseSpace) {
619     case SPACE_32_BITS_ARGB:
620     case SPACE_32_BITS_AYCC:
621     case SPACE_32_BITS_RGB:
622     case SPACE_32_BITS_YCC:
623     case SPACE_32_BITS_M:
624       offset = 0;
625       break;
626     case SPACE_32_BITS_AM:
627       offset = 2;
628       break;
629     case SPACE_32_BITS_O:
630     case SPACE_32_BITS_RGBA:
631     case SPACE_32_BITS_YCCA:
632     case SPACE_32_BITS_MA:
633       offset = 3;
634       break;
635     default:        // This shouldn't happen
636       assert(false);    // Makes a beep for debug purposes
637       offset = 0;
638       break;
639   }
640   return offset;
641 }
642 
643 // Give the number of channels of a baseline color space description
GetNbChannel(FPXBaselineColorSpace baseSpace)644 long GetNbChannel(FPXBaselineColorSpace baseSpace)
645 {
646   long channelNumber;
647   switch (baseSpace) {
648     case SPACE_32_BITS_ARGB:
649     case SPACE_32_BITS_RGBA:
650     case SPACE_32_BITS_AYCC:
651     case SPACE_32_BITS_YCCA:
652       channelNumber = 4;
653       break;
654     case SPACE_32_BITS_RGB:
655     case SPACE_32_BITS_YCC:
656       channelNumber = 3;
657       break;
658     case SPACE_32_BITS_AM:
659     case SPACE_32_BITS_MA:
660       channelNumber = 2;
661       break;
662     case SPACE_32_BITS_M:
663     case SPACE_32_BITS_O:
664       channelNumber = 1;
665       break;
666     default:  // We go for the worst case to do our computation, but this shouldn't happen
667       assert(false);    // Makes a beep for debug purposes
668       channelNumber = 4;
669       break;
670   }
671   return channelNumber;
672 }
673 
674 // This function update a FPXColorspace structure according to the kind of
675 // baseline space chosen
CreateFPXColorSpace(FPXBaselineColorSpace baseSpace,FPXColorspace * colorSpace)676 void CreateFPXColorSpace (FPXBaselineColorSpace baseSpace, FPXColorspace* colorSpace)
677 {
678   switch (baseSpace) {
679     case SPACE_32_BITS_RGB: {
680       colorSpace->numberOfComponents = 3;
681       colorSpace->theComponents[0].myColor = NIFRGB_R;
682       colorSpace->theComponents[1].myColor = NIFRGB_G;
683       colorSpace->theComponents[2].myColor = NIFRGB_B;
684       colorSpace->theComponents[0].myDataType = DATA_TYPE_UNSIGNED_BYTE;
685       colorSpace->theComponents[1].myDataType = DATA_TYPE_UNSIGNED_BYTE;
686       colorSpace->theComponents[2].myDataType = DATA_TYPE_UNSIGNED_BYTE;
687       break;
688       }
689     case SPACE_32_BITS_ARGB: {
690       colorSpace->numberOfComponents = 4;
691       colorSpace->theComponents[0].myColor = ALPHA;
692       colorSpace->theComponents[1].myColor = NIFRGB_R;
693       colorSpace->theComponents[2].myColor = NIFRGB_G;
694       colorSpace->theComponents[3].myColor = NIFRGB_B;
695       colorSpace->theComponents[0].myDataType = DATA_TYPE_UNSIGNED_BYTE;
696       colorSpace->theComponents[1].myDataType = DATA_TYPE_UNSIGNED_BYTE;
697       colorSpace->theComponents[2].myDataType = DATA_TYPE_UNSIGNED_BYTE;
698       colorSpace->theComponents[3].myDataType = DATA_TYPE_UNSIGNED_BYTE;
699       break;
700       }
701     case SPACE_32_BITS_RGBA: {
702       colorSpace->numberOfComponents = 4;
703       colorSpace->theComponents[0].myColor = NIFRGB_R;
704       colorSpace->theComponents[1].myColor = NIFRGB_G;
705       colorSpace->theComponents[2].myColor = NIFRGB_B;
706       colorSpace->theComponents[3].myColor = ALPHA;
707       colorSpace->theComponents[0].myDataType = DATA_TYPE_UNSIGNED_BYTE;
708       colorSpace->theComponents[1].myDataType = DATA_TYPE_UNSIGNED_BYTE;
709       colorSpace->theComponents[2].myDataType = DATA_TYPE_UNSIGNED_BYTE;
710       colorSpace->theComponents[3].myDataType = DATA_TYPE_UNSIGNED_BYTE;
711       break;
712       }
713     case SPACE_32_BITS_YCC: {
714       colorSpace->numberOfComponents = 3;
715       colorSpace->theComponents[0].myColor = PHOTO_YCC_Y;
716       colorSpace->theComponents[1].myColor = PHOTO_YCC_C1;
717       colorSpace->theComponents[2].myColor = PHOTO_YCC_C2;
718       colorSpace->theComponents[0].myDataType = DATA_TYPE_UNSIGNED_BYTE;
719       colorSpace->theComponents[1].myDataType = DATA_TYPE_UNSIGNED_BYTE;
720       colorSpace->theComponents[2].myDataType = DATA_TYPE_UNSIGNED_BYTE;
721       break;
722       }
723     case SPACE_32_BITS_AYCC: {
724       colorSpace->numberOfComponents = 4;
725       colorSpace->theComponents[0].myColor = ALPHA;
726       colorSpace->theComponents[1].myColor = PHOTO_YCC_Y;
727       colorSpace->theComponents[2].myColor = PHOTO_YCC_C1;
728       colorSpace->theComponents[3].myColor = PHOTO_YCC_C2;
729       colorSpace->theComponents[0].myDataType = DATA_TYPE_UNSIGNED_BYTE;
730       colorSpace->theComponents[1].myDataType = DATA_TYPE_UNSIGNED_BYTE;
731       colorSpace->theComponents[2].myDataType = DATA_TYPE_UNSIGNED_BYTE;
732       colorSpace->theComponents[3].myDataType = DATA_TYPE_UNSIGNED_BYTE;
733       break;
734       }
735     case SPACE_32_BITS_YCCA: {
736       colorSpace->numberOfComponents = 4;
737       colorSpace->theComponents[0].myColor = PHOTO_YCC_Y;
738       colorSpace->theComponents[1].myColor = PHOTO_YCC_C1;
739       colorSpace->theComponents[2].myColor = PHOTO_YCC_C2;
740       colorSpace->theComponents[3].myColor = ALPHA;
741       colorSpace->theComponents[0].myDataType = DATA_TYPE_UNSIGNED_BYTE;
742       colorSpace->theComponents[1].myDataType = DATA_TYPE_UNSIGNED_BYTE;
743       colorSpace->theComponents[2].myDataType = DATA_TYPE_UNSIGNED_BYTE;
744       colorSpace->theComponents[3].myDataType = DATA_TYPE_UNSIGNED_BYTE;
745       break;
746       }
747     case SPACE_32_BITS_M: {
748       colorSpace->numberOfComponents = 1;
749       colorSpace->theComponents[0].myColor = MONOCHROME;
750       colorSpace->theComponents[0].myDataType = DATA_TYPE_UNSIGNED_BYTE;
751       break;
752       }
753     case SPACE_32_BITS_AM: {
754       colorSpace->numberOfComponents = 2;
755       colorSpace->theComponents[0].myColor = ALPHA;
756       colorSpace->theComponents[1].myColor = MONOCHROME;
757       colorSpace->theComponents[0].myDataType = DATA_TYPE_UNSIGNED_BYTE;
758       colorSpace->theComponents[1].myDataType = DATA_TYPE_UNSIGNED_BYTE;
759       break;
760       }
761     case SPACE_32_BITS_MA: {
762       colorSpace->numberOfComponents = 2;
763       colorSpace->theComponents[0].myColor = MONOCHROME;
764       colorSpace->theComponents[1].myColor = ALPHA;
765       colorSpace->theComponents[0].myDataType = DATA_TYPE_UNSIGNED_BYTE;
766       colorSpace->theComponents[1].myDataType = DATA_TYPE_UNSIGNED_BYTE;
767       break;
768       }
769     case SPACE_32_BITS_O: {
770       colorSpace->numberOfComponents = 1;
771       colorSpace->theComponents[0].myColor = ALPHA;
772       colorSpace->theComponents[0].myDataType = DATA_TYPE_UNSIGNED_BYTE;
773       break;
774       }
775     case NON_AUTHORIZED_SPACE:
776       break;
777   }
778 }
779 
780 // This function analyses a FPXColorSpace given by a user of the Toolkit and checks
781 // if it's consistent and handled by the Baseline implementation.
782 // It returns one of the 10 authorized model or NON_AUTHORIZED_SPACE if nothing fits.
AnalyseFPXColorSpace(FPXColorspace & colorSpace)783 FPXBaselineColorSpace AnalyseFPXColorSpace (FPXColorspace& colorSpace)
784 {
785   FPXBaselineColorSpace spaceFound = NON_AUTHORIZED_SPACE;
786 
787   // The data type must be DATA_TYPE_UNSIGNED_BYTE
788   for (long i = 0; i < colorSpace.numberOfComponents; i++) {
789     if (colorSpace.theComponents[i].myDataType != DATA_TYPE_UNSIGNED_BYTE) {
790       assert(false);
791       return spaceFound;
792     }
793   }
794 
795   // Switch according to the number of components
796   if (colorSpace.numberOfComponents == 1) {
797     if    (colorSpace.theComponents[0].myColor == MONOCHROME)
798       spaceFound = SPACE_32_BITS_M;
799     else if (colorSpace.theComponents[0].myColor == ALPHA)
800       spaceFound = SPACE_32_BITS_O;
801   } else if (colorSpace.numberOfComponents == 2) {
802     if    ((colorSpace.theComponents[0].myColor == ALPHA) &&
803            (colorSpace.theComponents[1].myColor == MONOCHROME))
804       spaceFound = SPACE_32_BITS_AM;
805     else if ((colorSpace.theComponents[0].myColor == MONOCHROME) &&
806          (colorSpace.theComponents[1].myColor == ALPHA))
807       spaceFound = SPACE_32_BITS_MA;
808   } else if (colorSpace.numberOfComponents == 3) {
809     if    ((colorSpace.theComponents[0].myColor == NIFRGB_R) &&
810          (colorSpace.theComponents[1].myColor == NIFRGB_G) &&
811          (colorSpace.theComponents[2].myColor == NIFRGB_B))
812       spaceFound = SPACE_32_BITS_RGB;
813     else if ((colorSpace.theComponents[0].myColor == PHOTO_YCC_Y) &&
814          (colorSpace.theComponents[1].myColor == PHOTO_YCC_C1) &&
815          (colorSpace.theComponents[2].myColor == PHOTO_YCC_C2))
816       spaceFound = SPACE_32_BITS_YCC;
817   } else if (colorSpace.numberOfComponents == 4) {
818     if    ((colorSpace.theComponents[0].myColor == ALPHA) &&
819          (colorSpace.theComponents[1].myColor == NIFRGB_R) &&
820          (colorSpace.theComponents[2].myColor == NIFRGB_G) &&
821          (colorSpace.theComponents[3].myColor == NIFRGB_B))
822       spaceFound = SPACE_32_BITS_ARGB;
823     else if ((colorSpace.theComponents[0].myColor == NIFRGB_R) &&
824          (colorSpace.theComponents[1].myColor == NIFRGB_G) &&
825          (colorSpace.theComponents[2].myColor == NIFRGB_B) &&
826          (colorSpace.theComponents[3].myColor == ALPHA))
827       spaceFound = SPACE_32_BITS_RGBA;
828     else if ((colorSpace.theComponents[0].myColor == ALPHA) &&
829          (colorSpace.theComponents[1].myColor == PHOTO_YCC_Y) &&
830          (colorSpace.theComponents[2].myColor == PHOTO_YCC_C1) &&
831          (colorSpace.theComponents[3].myColor == PHOTO_YCC_C2))
832       spaceFound = SPACE_32_BITS_AYCC;
833     else if ((colorSpace.theComponents[0].myColor == PHOTO_YCC_Y) &&
834          (colorSpace.theComponents[1].myColor == PHOTO_YCC_C1) &&
835          (colorSpace.theComponents[2].myColor == PHOTO_YCC_C2) &&
836          (colorSpace.theComponents[3].myColor == ALPHA))
837       spaceFound = SPACE_32_BITS_YCCA;
838   }
839 
840   assert(spaceFound != NON_AUTHORIZED_SPACE);
841   return spaceFound;
842 }
843 
ExtractFPXColorSpaceFromFPXImageDesc(FPXImageDesc & desc,FPXColorspace * colorSpace)844 void ExtractFPXColorSpaceFromFPXImageDesc(FPXImageDesc& desc, FPXColorspace* colorSpace)
845 {
846   colorSpace->numberOfComponents = (short) desc.numberOfComponents;
847   for (long i = 0; i < (long) desc.numberOfComponents; i++) {
848     colorSpace->theComponents[i] = desc.components[i].myColorType;
849   }
850 }
851 
IsA32bitsBufferDescriptor(FPXImageDesc & desc,long width)852 Boolean IsA32bitsBufferDescriptor(FPXImageDesc& desc, long width)
853 {
854   Boolean is32 = true;
855   long i;
856 
857   // Special case if only one channel
858   if (desc.numberOfComponents == 1) {
859     if (desc.components[0].columnStride != 4)
860       is32 = false;
861   }
862 
863   // Check the horizontal subsampling factors
864   if (is32) {
865     for (i = 0; i < (long) desc.numberOfComponents; i++)
866       is32 &= (desc.components[i].horzSubSampFactor == 1);
867   }
868 
869   // Check the vertical subsampling factors
870   if (is32) {
871     for (i = 0; i <(long) desc.numberOfComponents; i++)
872       is32 &= (desc.components[i].vertSubSampFactor == 1);
873   }
874 
875   // Check the column increment
876   if (is32) {
877     for (i = 0; i < (long) desc.numberOfComponents; i++)
878       is32 &= (desc.components[i].columnStride == 4);
879   }
880 
881   // Check the line increment
882   if (is32) {
883     long lineStride = width * 4;
884     for (i = 0; i < (long)desc.numberOfComponents; i++)
885       is32 &= (desc.components[i].lineStride == lineStride);
886   }
887 
888   // Check the buffer differences (must be one byte)
889   if (is32) {
890     for (i = 0; i < (long)(desc.numberOfComponents-1); i++)
891       is32 &= ((desc.components[i+1].theData - desc.components[i].theData) == 1);
892   }
893 
894   return is32;
895 }
896 
IsASupportedDescriptor(FPXImageDesc & desc,long width)897 Boolean IsASupportedDescriptor(FPXImageDesc& desc, long width)
898 {
899   Boolean isSupported = true;
900 
901   FPXColorspace colorSpace;
902   ExtractFPXColorSpaceFromFPXImageDesc(desc, &colorSpace);
903 
904   FPXBaselineColorSpace baselineSpace = AnalyseFPXColorSpace(colorSpace);
905   if (baselineSpace == NON_AUTHORIZED_SPACE)
906     isSupported = false;
907 
908   if (isSupported) {
909     isSupported = IsA32bitsBufferDescriptor(desc,width);
910   }
911 
912   return isSupported;
913 }
914 
915 // Check to see if all pixels in a tile are same and return the pixel value
IsTileAllSamePixel(Pixel * entireTile,short width,short height,Pixel * singleColorPixel)916 Boolean IsTileAllSamePixel(Pixel *entireTile, short width, short height, Pixel* singleColorPixel)
917 {
918   register unsigned long numofpixel = width * height;
919 
920   *singleColorPixel = entireTile[0];
921   for ( unsigned long i = 1; i< numofpixel; i++ )
922     if ( singleColorPixel->rouge != entireTile[i].rouge ||
923         singleColorPixel->vert != entireTile[i].vert ||
924         singleColorPixel->bleu != entireTile[i].bleu )
925       return false;
926 
927   return true;
928 }
929 
930 // Handle all the color conversion / 32 bits interleaving options available in Baseline.
931 // Basically, it's just moving bytes and converting 24bits per pixel colors... it's long so...
932 // We tried to minimize the quantities of computation for each individual case. Could have been done
933 // differently (and less efficiently) by going systematically to some kind of space and converting to all
934 // others... Or using a twist matrix (to much computation so...).
ConvertPixelBuffer(unsigned char * buffer,long size,FPXBaselineColorSpace source,FPXBaselineColorSpace destination)935 void ConvertPixelBuffer(unsigned char* buffer, long size, FPXBaselineColorSpace source, FPXBaselineColorSpace destination)
936 {
937   switch (source) {
938     case SPACE_32_BITS_RGB:
939       switch (destination) {
940         case SPACE_32_BITS_RGB:
941           // Nothing to do
942           break;
943         case SPACE_32_BITS_ARGB:
944           InitByteTo255(buffer,size);
945           break;
946         case SPACE_32_BITS_RGBA:
947           InitByteTo255(buffer,size);
948           Shift8BitsLeft(buffer,size);
949           break;
950         case SPACE_32_BITS_YCC:
951           ConvertRGBtoYCC(buffer+1,size);
952           break;
953         case SPACE_32_BITS_AYCC:
954           ConvertRGBtoYCC(buffer+1,size);
955           InitByteTo255(buffer,size);
956           break;
957         case SPACE_32_BITS_YCCA:
958           ConvertRGBtoYCC(buffer+1,size);
959           InitByteTo255(buffer, size);
960           Shift8BitsLeft(buffer,size);
961           break;
962         case SPACE_32_BITS_M:
963           ConvertRGBtoMonochrome(buffer+1,size);
964           break;
965         case SPACE_32_BITS_AM:
966           ConvertRGBtoMonochrome(buffer+1,size);
967           InitByteTo255(buffer+2,size);
968           break;
969         case SPACE_32_BITS_MA:
970           ConvertRGBtoMonochrome(buffer+1,size);
971           InitByteTo255(buffer,size);
972           Shift8BitsLeft(buffer,size);
973           break;
974         case SPACE_32_BITS_O:
975           ConvertRGBtoMonochrome(buffer+1,size);
976           break;
977         case NON_AUTHORIZED_SPACE:
978           break;
979       }
980       break;
981     case SPACE_32_BITS_ARGB:
982       switch (destination) {
983         case SPACE_32_BITS_RGB:
984           // InitByteTo0(buffer,size); now we prefer to preserve the alpha channel if any
985           break;
986         case SPACE_32_BITS_ARGB:
987           // Nothing to do
988           break;
989         case SPACE_32_BITS_RGBA:
990           Shift8BitsLeft(buffer,size);
991           break;
992         case SPACE_32_BITS_YCC:
993           // InitByteTo0(buffer,size); now we prefer to preserve the alpha channel if any
994           ConvertRGBtoYCC(buffer+1,size);
995           break;
996         case SPACE_32_BITS_AYCC:
997           ConvertRGBtoYCC(buffer+1,size);
998           break;
999         case SPACE_32_BITS_YCCA:
1000           ConvertRGBtoYCC(buffer+1,size);
1001           Shift8BitsLeft(buffer,size);
1002           //**IM--05/16/97--Maybe it's better to have:
1003           //Shift8BitsLeft(buffer,size);
1004           //ConvertRGBtoYCC(buffer+1,size);
1005           break;
1006         case SPACE_32_BITS_M:
1007           ConvertRGBtoMonochrome(buffer+1,size);
1008           // InitByteTo0(buffer,size); now we prefer to preserve the alpha channel if any
1009           break;
1010         case SPACE_32_BITS_AM:
1011           ConvertRGBtoMonochrome(buffer+1,size);
1012           MoveByteRightBy2(buffer,size);
1013           break;
1014         case SPACE_32_BITS_MA:
1015           ConvertRGBtoMonochrome(buffer+1,size);
1016           Shift8BitsLeft(buffer,size);
1017           break;
1018         case SPACE_32_BITS_O:
1019           ConvertRGBtoMonochrome(buffer+1,size);
1020           // InitByteTo0(buffer,size); now we prefer to preserve the alpha channel if any
1021           break;
1022         case NON_AUTHORIZED_SPACE:
1023           break;
1024       }
1025       break;
1026     case SPACE_32_BITS_RGBA:
1027       switch (destination) {
1028         case SPACE_32_BITS_RGB:
1029           Shift8BitsRight(buffer,size);
1030           // InitByteTo0(buffer,size); now we prefer to preserve the alpha channel if any
1031           break;
1032         case SPACE_32_BITS_ARGB:
1033           Shift8BitsRight(buffer,size);
1034           break;
1035         case SPACE_32_BITS_RGBA:
1036           // Nothing to do
1037           break;
1038         case SPACE_32_BITS_YCC:
1039           Shift8BitsRight(buffer,size);
1040           ConvertRGBtoYCC(buffer+1,size);
1041           // InitByteTo0(buffer,size); now we prefer to preserve the alpha channel if any
1042           break;
1043         case SPACE_32_BITS_AYCC:
1044           Shift8BitsRight(buffer,size);
1045           ConvertRGBtoYCC(buffer+1,size);
1046           break;
1047         case SPACE_32_BITS_YCCA:
1048           ConvertRGBtoYCC(buffer,size);
1049           break;
1050         case SPACE_32_BITS_M:
1051           Shift8BitsRight(buffer,size);
1052           ConvertRGBtoMonochrome(buffer+1,size);
1053           // InitByteTo0(buffer,size); now we prefer to preserve the alpha channel if any
1054           break;
1055         case SPACE_32_BITS_AM:
1056           ConvertRGBtoMonochrome(buffer,size);
1057           Shift8BitsRight(buffer,size);
1058           MoveByteRightBy2(buffer,size);
1059           break;
1060         case SPACE_32_BITS_MA:
1061           ConvertRGBtoMonochrome(buffer,size);
1062           break;
1063         case SPACE_32_BITS_O:
1064           Shift8BitsRight(buffer,size);
1065           ConvertRGBtoMonochrome(buffer+1,size);
1066           // InitByteTo0(buffer,size); now we prefer to preserve the alpha channel if any
1067           break;
1068         case NON_AUTHORIZED_SPACE:
1069           break;
1070       }
1071       break;
1072     case SPACE_32_BITS_YCC:
1073       switch (destination) {
1074         case SPACE_32_BITS_RGB:
1075           ConvertYCCtoRGB(buffer+1,size,FALSE);
1076           break;
1077         case SPACE_32_BITS_ARGB:
1078           ConvertYCCtoRGB(buffer+1,size,FALSE);
1079           InitByteTo255(buffer,size);
1080           break;
1081         case SPACE_32_BITS_RGBA:
1082           //ConvertYCCtoRGB(buffer+1,size,TRUE);
1083           //InitByteTo255(buffer,size);
1084           //Shift8BitsLeft(buffer,size);
1085           //**IM--05/16/97--If Opacity is used never use buffer + 1,..., TRUE
1086           Shift8BitsLeft(buffer,size); //get YCCA
1087           ConvertYCCtoRGB(buffer,size,TRUE);//get RGBA using the right Opacity
1088           InitByteTo255(buffer+3,size);//set Opacity 255;
1089           break;
1090         case SPACE_32_BITS_YCC:
1091           // Nothing to do
1092           break;
1093         case SPACE_32_BITS_AYCC:
1094           InitByteTo255(buffer,size);
1095           break;
1096         case SPACE_32_BITS_YCCA:
1097           InitByteTo255(buffer,size);
1098           Shift8BitsLeft(buffer,size);
1099           break;
1100         case SPACE_32_BITS_M:
1101           ConvertYCCtoMonochrome(buffer+1,size);
1102           break;
1103         case SPACE_32_BITS_AM:
1104           ConvertYCCtoMonochrome(buffer+1,size);
1105           InitByteTo255(buffer+2,size);
1106           break;
1107         case SPACE_32_BITS_MA:
1108           ConvertYCCtoMonochrome(buffer+1,size);
1109           Shift8BitsLeft(buffer,size);
1110           InitByteTo255(buffer+3,size);
1111           break;
1112         case SPACE_32_BITS_O:
1113           ConvertYCCtoMonochrome(buffer+1,size);
1114           break;
1115         case NON_AUTHORIZED_SPACE:
1116           break;
1117       }
1118       break;
1119     case SPACE_32_BITS_AYCC:
1120       switch (destination) {
1121         case SPACE_32_BITS_RGB:
1122           // InitByteTo0(buffer,size); now we prefer to preserve the alpha channel if any
1123           Shift8BitsLeft(buffer,size); //get YCCA--**IM--05/16/97
1124           //ConvertYCCtoRGB(buffer+1,size,TRUE);
1125           ConvertYCCtoRGB(buffer,size,TRUE);//get RGBA
1126           Shift8BitsRight(buffer,size);//get ARGB
1127           break;
1128         case SPACE_32_BITS_ARGB:
1129           //ConvertYCCtoRGB(buffer+1,size,TRUE);
1130           Shift8BitsLeft(buffer,size); //get YCCA--**IM--05/16/97
1131           ConvertYCCtoRGB(buffer,size,TRUE);//get RGBA
1132           Shift8BitsRight(buffer,size);//get ARGB
1133           break;
1134         case SPACE_32_BITS_RGBA:
1135           //ConvertYCCtoRGB(buffer+1,size,TRUE);
1136           //Shift8BitsLeft(buffer,size);
1137           Shift8BitsLeft(buffer,size);//get YCCA --**IM--05/16/97
1138           ConvertYCCtoRGB(buffer,size,TRUE);//get RGBA
1139           break;
1140         case SPACE_32_BITS_YCC:
1141           // InitByteTo0(buffer,size); now we prefer to preserve the alpha channel if any
1142           break;
1143         case SPACE_32_BITS_AYCC:
1144           // Nothing to do
1145           break;
1146         case SPACE_32_BITS_YCCA:
1147           Shift8BitsLeft(buffer,size);
1148           break;
1149         case SPACE_32_BITS_M:
1150           ConvertYCCtoMonochrome(buffer+1,size);
1151           // InitByteTo0(buffer,size); now we prefer to preserve the alpha channel if any
1152           break;
1153         case SPACE_32_BITS_AM:
1154           ConvertYCCtoMonochrome(buffer+1,size);
1155           MoveByteRightBy2(buffer,size);
1156           break;
1157         case SPACE_32_BITS_MA:
1158           ConvertYCCtoMonochrome(buffer+1,size);
1159           Shift8BitsLeft(buffer,size);
1160           break;
1161         case SPACE_32_BITS_O:
1162           ConvertYCCtoMonochrome(buffer+1,size);
1163           // InitByteTo0(buffer,size); now we prefer to preserve the alpha channel if any
1164           break;
1165         case NON_AUTHORIZED_SPACE:
1166           break;
1167       }
1168       break;
1169     case SPACE_32_BITS_YCCA:
1170       switch (destination) {
1171         case SPACE_32_BITS_RGB:
1172           //Shift8BitsRight(buffer,size);
1173           //ConvertYCCtoRGB(buffer+1,size);
1174           ConvertYCCtoRGB(buffer,size,TRUE);//get RGBA
1175           Shift8BitsRight(buffer,size); //get ARGB
1176           // InitByteTo0(buffer,size); now we prefer to preserve the alpha channel if any
1177           break;
1178         case SPACE_32_BITS_ARGB:
1179         //  Shift8BitsRight(buffer,size);
1180         //  ConvertYCCtoRGB(buffer+1,size,TRUE);
1181           ConvertYCCtoRGB(buffer,size,TRUE);//get RGBA --**IM--05/02/97--fixed bug 17998
1182           Shift8BitsRight(buffer,size);//get ARGB
1183           break;
1184         case SPACE_32_BITS_RGBA:
1185           ConvertYCCtoRGB(buffer,size,TRUE);
1186           break;
1187         case SPACE_32_BITS_YCC:
1188           Shift8BitsRight(buffer,size);
1189           // InitByteTo0(buffer,size); now we prefer to preserve the alpha channel if any
1190           break;
1191         case SPACE_32_BITS_AYCC:
1192           Shift8BitsRight(buffer,size);
1193           break;
1194         case SPACE_32_BITS_YCCA:
1195           // Nothing to do
1196           break;
1197         case SPACE_32_BITS_M:
1198           Shift8BitsRight(buffer,size);
1199           ConvertYCCtoMonochrome(buffer+1,size);
1200           // InitByteTo0(buffer,size); now we prefer to preserve the alpha channel if any
1201           break;
1202         case SPACE_32_BITS_AM:
1203           ConvertYCCtoMonochrome(buffer,size);
1204           Shift8BitsRight(buffer,size);
1205           MoveByteRightBy2(buffer,size);
1206           break;
1207         case SPACE_32_BITS_MA:
1208           ConvertYCCtoMonochrome(buffer,size);
1209           break;
1210         case SPACE_32_BITS_O:
1211           Shift8BitsRight(buffer,size);
1212           ConvertYCCtoMonochrome(buffer+1,size);
1213           // InitByteTo0(buffer,size); now we prefer to preserve the alpha channel if any
1214           break;
1215         case NON_AUTHORIZED_SPACE:
1216           break;
1217       }
1218       break;
1219     case SPACE_32_BITS_M:
1220     case SPACE_32_BITS_O:
1221       switch (destination) {
1222         case SPACE_32_BITS_RGB:
1223           ConvertMonochrometoRGB(buffer+1,size);
1224           break;
1225         case SPACE_32_BITS_ARGB:
1226           ConvertMonochrometoRGB(buffer+1,size);
1227           InitByteTo255(buffer,size);
1228           break;
1229         case SPACE_32_BITS_RGBA:
1230           ConvertMonochrometoRGB(buffer+1,size);
1231           InitByteTo255(buffer,size);
1232           Shift8BitsLeft(buffer,size);
1233           break;
1234         case SPACE_32_BITS_YCC:
1235           ConvertMonochrometoYCC(buffer+1,size);
1236           break;
1237         case SPACE_32_BITS_AYCC:
1238           ConvertMonochrometoYCC(buffer+1,size);
1239           InitByteTo255(buffer,size);
1240           break;
1241         case SPACE_32_BITS_YCCA:
1242           ConvertMonochrometoYCC(buffer+1,size);
1243           InitByteTo255(buffer,size);
1244           Shift8BitsLeft(buffer,size);
1245           break;
1246         case SPACE_32_BITS_M:
1247           // Nothing to do
1248           break;
1249         case SPACE_32_BITS_AM:
1250           InitByteTo255(buffer+2,size);
1251           break;
1252         case SPACE_32_BITS_MA:
1253           InitByteTo255(buffer,size);
1254           Shift8BitsLeft(buffer,size);
1255           break;
1256         case SPACE_32_BITS_O:
1257           // Nothing to do
1258           break;
1259         case NON_AUTHORIZED_SPACE:
1260           break;
1261       }
1262       break;
1263     case SPACE_32_BITS_AM:
1264       switch (destination) {
1265         case SPACE_32_BITS_RGB:
1266           MoveByteLeftBy2(buffer+2,size);
1267           ConvertMonochrometoRGB(buffer+1,size);
1268           // InitByteTo0(buffer,size); now we prefer to preserve the alpha channel if any
1269           break;
1270         case SPACE_32_BITS_ARGB:
1271           MoveByteLeftBy2(buffer+2,size);
1272           ConvertMonochrometoRGB(buffer+1,size);
1273           break;
1274         case SPACE_32_BITS_RGBA:
1275           MoveByteLeftBy2(buffer+2,size);
1276           ConvertMonochrometoRGB(buffer+1,size);
1277           Shift8BitsLeft(buffer,size);
1278           break;
1279         case SPACE_32_BITS_YCC:
1280           MoveByteLeftBy2(buffer+2,size);
1281           ConvertMonochrometoYCC(buffer+1,size);
1282           // InitByteTo0(buffer,size); now we prefer to preserve the alpha channel if any
1283           break;
1284         case SPACE_32_BITS_AYCC:
1285           MoveByteLeftBy2(buffer+2,size);
1286           ConvertMonochrometoYCC(buffer+1,size);
1287           break;
1288         case SPACE_32_BITS_YCCA:
1289           MoveByteLeftBy2(buffer+2,size);
1290           ConvertMonochrometoYCC(buffer+1,size);
1291           Shift8BitsLeft(buffer,size);
1292           break;
1293         case SPACE_32_BITS_M:
1294           // InitByteTo0(buffer+2,size); now we prefer to preserve the alpha channel if any
1295           break;
1296         case SPACE_32_BITS_AM:
1297           // Nothing to do
1298           break;
1299         case SPACE_32_BITS_MA:
1300           Shift8BitsLeft(buffer,size);
1301           MoveByteRightBy2(buffer+1,size);
1302           break;
1303         case SPACE_32_BITS_O:
1304           // InitByteTo0(buffer+2,size); now we prefer to preserve the alpha channel if any
1305           break;
1306         case NON_AUTHORIZED_SPACE:
1307           break;
1308       }
1309       break;
1310     case SPACE_32_BITS_MA:
1311       switch (destination) {
1312         case SPACE_32_BITS_RGB:
1313           Shift8BitsRight(buffer,size);
1314           ConvertMonochrometoRGB(buffer+1,size);
1315           // InitByteTo0(buffer,size); now we prefer to preserve the alpha channel if any
1316           break;
1317         case SPACE_32_BITS_ARGB:
1318           Shift8BitsRight(buffer,size);
1319           ConvertMonochrometoRGB(buffer+1,size);
1320           break;
1321         case SPACE_32_BITS_RGBA:
1322           ConvertMonochrometoRGB(buffer,size);
1323           break;
1324         case SPACE_32_BITS_YCC:
1325           Shift8BitsRight(buffer,size);
1326           ConvertMonochrometoYCC(buffer+1,size);
1327           // InitByteTo0(buffer,size); now we prefer to preserve the alpha channel if any
1328           break;
1329         case SPACE_32_BITS_AYCC:
1330           Shift8BitsRight(buffer,size);
1331           ConvertMonochrometoYCC(buffer+1,size);
1332           break;
1333         case SPACE_32_BITS_YCCA:
1334           ConvertMonochrometoYCC(buffer,size);
1335           break;
1336         case SPACE_32_BITS_M:
1337           Shift8BitsRight(buffer,size);
1338           // InitByteTo0(buffer,size); now we prefer to preserve the alpha channel if any
1339           break;
1340         case SPACE_32_BITS_AM:
1341           Shift8BitsRight(buffer,size);
1342           MoveByteRightBy2(buffer,size);
1343           break;
1344         case SPACE_32_BITS_MA:
1345           // Nothing to do
1346           break;
1347         case SPACE_32_BITS_O:
1348           Shift8BitsRight(buffer,size);
1349           // InitByteTo0(buffer,size); now we prefer to preserve the alpha channel if any
1350           break;
1351         case NON_AUTHORIZED_SPACE:
1352           break;
1353       }
1354       break;
1355   default:
1356     {
1357     }
1358   }
1359 }
1360 
1361 // Create a thumbnail image in windows DIB format
CreateThumbnail(unsigned char * buf,FPXBaselineColorSpace baseSpace,unsigned short thumbNailWidth,unsigned short thumbNailHeight,CLIPDATA * clipData)1362 Boolean CreateThumbnail(unsigned char* buf, FPXBaselineColorSpace baseSpace,
1363             unsigned short thumbNailWidth, unsigned short thumbNailHeight,
1364             CLIPDATA * clipData)
1365 {
1366   Ptr buffer;
1367   long  thumbnailSize;
1368   ptr_Compresseur monCompresseur;
1369   BITMAPINFOHEADER  bmpInfoHdr;
1370 
1371   // Get the TLC_32Vers24 compressor
1372   if ( !(monCompresseur = (*tousLesCodecs)[TLC_32Vers24]) )
1373     return FALSE;
1374 
1375   // Thumbnails cannot be stored in YCC. Convert to RGB if necessary
1376   if ( (baseSpace == SPACE_32_BITS_YCC) || (baseSpace == SPACE_32_BITS_YCCA) ) {
1377     ConvertPixelBuffer( (unsigned char*)(buf), thumbNailWidth * thumbNailHeight,
1378             baseSpace, SPACE_32_BITS_RGB);
1379     baseSpace = SPACE_32_BITS_RGB;
1380   }
1381 
1382   // In the case of simple compression, we have to set the number of channels and the direction
1383   // of the compression. This is optimized only for the most common cases.
1384   Boolean leftShift = FALSE;
1385   if ( (baseSpace == SPACE_32_BITS_RGBA) || (baseSpace == SPACE_32_BITS_YCCA) )
1386     leftShift = TRUE;
1387 
1388   // For thumbnail, 4 channels is compressed to 3 channels image, and 2 channels is compressed to 1 channel image
1389   short nbChannels = (short) GetNbChannel(baseSpace);
1390   switch(nbChannels)
1391   {
1392     case 4:
1393     case 3:
1394     {
1395       nbChannels = 3;
1396       ((obj_Compresseur32Vers24 *)monCompresseur)->SetCompressionParameters(nbChannels,leftShift);
1397 
1398       if ( !((obj_Compresseur32Vers24 *)monCompresseur)->Compresse((Ptr)buf, thumbNailWidth, thumbNailHeight,
1399           &buffer, &thumbnailSize))
1400         return FALSE;
1401       break;
1402     }
1403     case 2:
1404     {
1405       // For SPACE_32_BITS_MA, first convert to SPACE_32_BITS_AM image, then compressed to 1 channel image
1406       // For SPACE_32_BITS_AM, it can be considered as 1 channel image
1407       if ( baseSpace == SPACE_32_BITS_MA )
1408         ConvertPixelBuffer((unsigned char*)(buf),thumbNailWidth*thumbNailHeight,SPACE_32_BITS_MA,SPACE_32_BITS_AM);
1409 
1410       nbChannels = 1;
1411       ((obj_Compresseur32Vers24 *)monCompresseur)->SetCompressionParameters(nbChannels, leftShift);
1412       if ( !((obj_Compresseur32Vers24 *)monCompresseur)->Compresse((Ptr)buf, thumbNailWidth, thumbNailHeight,
1413           &buffer, &thumbnailSize))
1414         return FALSE;
1415 
1416       break;
1417     }
1418     case 1:
1419     {
1420       ((obj_Compresseur32Vers24 *)monCompresseur)->SetCompressionParameters(nbChannels,leftShift);
1421 
1422       if ( !((obj_Compresseur32Vers24 *)monCompresseur)->Compresse((Ptr)buf, thumbNailWidth, thumbNailHeight,
1423           &buffer, &thumbnailSize))
1424         return FALSE;
1425       break;
1426     }
1427     default:
1428       return FALSE;
1429   }
1430 
1431   // PTCH_203 Recalculate "thumbnailSize" and account for required DIB line padding ...
1432   if (nbChannels >= 3) {
1433     int padBytes = (4 - ((thumbNailWidth * 3) % 4)) & 0x03;
1434     thumbnailSize = (thumbNailWidth * 3 + padBytes) * thumbNailHeight;
1435   }
1436   else {
1437       int padWidth = ((thumbNailWidth + 3) /4) * 4;
1438     thumbnailSize = padWidth * thumbNailHeight;
1439   }
1440   // PTCH_203 ...end of change
1441 
1442   // Alloc for clipdata. For single channel image, additional space for palette is also included
1443   if ( nbChannels == 1 )
1444     clipData->cbSize = thumbnailSize + sizeof(BITMAPINFOHEADER) + 2 * sizeof(long) + DefaultPaletteSize * sizeof(RGBQUAD);
1445   else
1446     clipData->cbSize = thumbnailSize + sizeof(BITMAPINFOHEADER) + 2 * sizeof(long);
1447 
1448   clipData->pClipData = new unsigned char[clipData->cbSize];      // PTCH_103 mod:  + 300];
1449 
1450   if ( !clipData->pClipData )
1451     return FALSE;
1452 
1453   // Write thumbnail header
1454   unsigned long ignore1     = 0xFFFFFFFF;         // Write ignore1 of thumbnail header
1455   unsigned long ignore2     = 0x00000008;         // Write ignore2 of thumbnail header
1456 
1457   // Write bitmap info header
1458   bmpInfoHdr.biSize     = sizeof(BITMAPINFOHEADER); // Write size of bitmap info header
1459   bmpInfoHdr.biWidth      = thumbNailWidth;       // Write bitmap width
1460   bmpInfoHdr.biHeight     = thumbNailHeight;      // Write bitmap width
1461   bmpInfoHdr.biPlanes     = 1;            // Write bitmap planes
1462   /**
1463   if ( nbChannels == 1 )
1464     bmpInfoHdr.biBitCount   = 0x3d08;           // Write bitmap bit count for single channel
1465   else
1466     bmpInfoHdr.biBitCount   = 0x3d24;           // Write bitmap bit count for multi channels
1467   **/
1468   if ( nbChannels == 1 )
1469     bmpInfoHdr.biBitCount   = 8;          // Write bitmap bit count for single channel
1470 
1471   else
1472     bmpInfoHdr.biBitCount   = 24;           // Write bitmap bit count for multi channels
1473 
1474   bmpInfoHdr.biCompression  = BI_RGB;           // Write bitmap compression
1475   bmpInfoHdr.biSizeImage    = thumbnailSize;      // Write bitmap size
1476   bmpInfoHdr.biXPelsPerMeter  = 75 * 39;          // Write X dpi per meter
1477   bmpInfoHdr.biYPelsPerMeter  = 75 * 39;          // Write Y dpi per meter
1478   bmpInfoHdr.biClrUsed    = 0;            // Write biClrUsed
1479   bmpInfoHdr.biClrImportant   = 0;            // Write biClrImportant
1480 
1481   // Swap bytes if necessary
1482 #ifdef  IN_BIG_ENDIAN
1483   ignore1 = (unsigned long) SwapBytes( (int32) ignore1 );
1484   ignore2 = (unsigned long) SwapBytes( (int32) ignore2 );
1485 
1486   bmpInfoHdr.biSize          = (long) SwapBytes( (int32) bmpInfoHdr.biSize );
1487   bmpInfoHdr.biWidth         = (long) SwapBytes( (int32) bmpInfoHdr.biWidth );
1488   bmpInfoHdr.biHeight        = (long) SwapBytes( (int32) bmpInfoHdr.biHeight );
1489   bmpInfoHdr.biPlanes        = (unsigned short) SwapBytes( (int16) bmpInfoHdr.biPlanes );
1490   bmpInfoHdr.biBitCount      = (unsigned short) SwapBytes( (int16) bmpInfoHdr.biBitCount );
1491   bmpInfoHdr.biCompression   = (unsigned long) SwapBytes( (int32) bmpInfoHdr.biCompression );
1492   bmpInfoHdr.biSizeImage     = (unsigned long) SwapBytes( (int32) bmpInfoHdr.biSizeImage );
1493   bmpInfoHdr.biXPelsPerMeter = (unsigned long) SwapBytes( (int32) bmpInfoHdr.biXPelsPerMeter );
1494   bmpInfoHdr.biYPelsPerMeter = (unsigned long) SwapBytes( (int32) bmpInfoHdr.biYPelsPerMeter );
1495   bmpInfoHdr.biClrUsed       = (unsigned long) SwapBytes( (int32) bmpInfoHdr.biClrUsed );
1496   bmpInfoHdr.biClrImportant  = (unsigned long) SwapBytes( (int32) bmpInfoHdr.biClrImportant );
1497 #endif
1498 
1499   // Copy thumbnail header into clipdata
1500   memcpy(clipData->pClipData, &ignore1, sizeof(long));
1501   memcpy(clipData->pClipData + sizeof(long), &ignore2, sizeof(long));
1502 
1503   // Copy bitmap info header into clipdata
1504   memcpy(clipData->pClipData + 2 * sizeof(long), &bmpInfoHdr, sizeof(BITMAPINFOHEADER));
1505 
1506   // Get a new position for clipData->pClipData
1507   unsigned char * ptr = clipData->pClipData + 2 * sizeof(long) + sizeof(BITMAPINFOHEADER);
1508 
1509   // Get window DIB format data
1510   switch(nbChannels)
1511   {
1512     case 1:
1513     {
1514       // For single channel images, create a default palette
1515       SetDefaultPalette(ptr);
1516 
1517       // Get the new buffer pointer
1518       ptr += DefaultPaletteSize * sizeof(RGBQUAD);
1519 
1520       // Write the thumbnail data
1521       //memcpy(ptr, (unsigned char *)buffer, thumbnailSize);
1522       writeDIB1((unsigned char *)buffer, ptr, thumbNailWidth, thumbNailHeight);
1523       break;
1524     }
1525     case 3:
1526       // Convert RGB format to BGR (Windows DIB format)
1527       writeDIB24((unsigned char *)buffer, ptr, thumbNailWidth, thumbNailHeight);
1528       break;
1529 
1530     default:
1531       return FALSE;
1532   }
1533 
1534 #ifdef _WINDOWS
1535   clipData->ulClipFmt = -1;
1536 #else
1537 #ifdef macintosh
1538   clipData->ulClipFmt = -2;
1539 #endif
1540 #endif
1541 
1542   return TRUE;
1543 }
1544 
1545 // Create window DIB default palette, which is grayscale ramp of 256 RGBQUAD
SetDefaultPalette(unsigned char * palBuffer)1546 void SetDefaultPalette(unsigned char *palBuffer)
1547 {
1548   register unsigned long *all;
1549 
1550   // Set the grayscale ramp of RGBQUADs
1551   all = (unsigned long *)(palBuffer);
1552   for ( long i = 0; i < DefaultPaletteSize; i++ ) {
1553     *all =  i << 24 | i << 16 | i << 8 | 0 ;
1554 
1555 #ifdef  IN_LITTLE_ENDIAN
1556 
1557     *all = (unsigned long) SwapBytes( (int32) *all );
1558 
1559 #endif
1560 
1561 
1562     all++;
1563   }
1564 }
1565 
1566 // Convert RGB format to BGR (Windows DIB format)
writeDIB24(unsigned char * obp,unsigned char * pic24,unsigned long w,unsigned long h)1567 void writeDIB24(unsigned char *obp, unsigned char *pic24, unsigned long w, unsigned long h)
1568 {
1569   long i, j, padb;
1570   unsigned char *pp;
1571 
1572   padb = (4 - ((w * 3) % 4)) & 0x03;    // # of pad bytes to write at EOscanline */
1573 
1574   // DIBs are upside down... how typical...
1575   for ( i = h - 1; i >= 0; i-- ) {
1576      pp = pic24 + (i * (w * 3 + padb));
1577 
1578     for (j = 0; j < (long) w; j++) {
1579       pp[2] = *obp++;   /* B   (again, how typical...) */
1580       pp[1] = *obp++;   /* G */
1581       pp[0] = *obp++;   /* R */
1582       pp+=3;
1583     }
1584     for (j = 0; j < padb; j++)
1585       *pp++ = 0;
1586   }
1587 }
1588 
writeDIB1(unsigned char * obp,unsigned char * pic8,unsigned long w,unsigned long h)1589 void writeDIB1(unsigned char *obp, unsigned char *pic8, unsigned long w, unsigned long h)
1590 {
1591   unsigned long j, padw;
1592   long i;
1593   unsigned char *pp;
1594 
1595   padw = ((w + 3)/4) * 4;  /* 'w', padded to be a multiple of 32 */
1596 
1597   for (i=h-1; i>=0; i--) {
1598     pp = pic8 + (i * padw);
1599 
1600     for (j=0; j<w; j++) *pp++ = *obp++;
1601     for ( ; j<padw; j++) *pp++ = 0;
1602   }
1603 }
1604 //  - EOF ----------------------------------------------------------------------
1605