1 // ----------------------------------------------------------------------------
2 // MODULE : PTileFlashPix
3 // LANGUAGE : C++
4 // CREATOR : Philippe BOSSUT
5 // CREAT. DATE : Wednesday, March 20, 1996
6 // DESCRIPTION :
7 // COMMENTS :
8 // SCCSID : @(#)ptil_fpx.cpp 1.11 12:24:18 08 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 // ----------------------------------------------------------------------------
16 #include "ptil_fpx.h"
17 // ----------------------------------------------------------------------------
18
19 // Includes
20 // --------
21
22 #ifndef Memoire_h
23 #include "b_memory.h"
24 #endif
25
26 #ifndef Debug_h
27 #include "debug.h"
28 #endif
29
30 #ifndef FPXBaselineIO_h
31 #include "fpxlibio.h"
32 #endif
33
34 #ifndef FPXBaselineView_h
35 #include "fpxlib.h"
36 #endif
37
38
39 #ifndef OLECommun_h
40 #include "olecomm.h"
41 #endif
42
43 #ifndef OLECore_h
44 #include "olecore.h"
45 #endif
46
47 #ifndef OLEStorages_h
48 #include "olestorg.h"
49 #endif
50
51 #ifndef OLEHeaderStream_h
52 #include "olehstrm.h"
53 #endif
54
55 #ifndef OLEProperties_h
56 #include "oleprop.h"
57 #endif
58
59 #ifndef OLEPropertySet_h
60 #include "oleprops.h"
61 #endif
62
63 #ifndef OLEFiles_h
64 #include "olefiles.h"
65 #endif
66
67
68 #ifndef FlashPixUtils_h
69 #include "fpxutils.h"
70 #endif
71
72
73 #ifndef AdvancedIVUE_h
74 #include "viewimg.h"
75 #endif
76
77 #ifndef ColorTwist_h
78 #include "coltwist.h"
79 #endif
80
81
82 #ifndef FileFlashPixIO_h
83 #include "f_fpxio.h"
84 #endif
85
86 #ifndef PResolutionFlashPix_h
87 #include "pres_fpx.h"
88 #endif
89
90 #ifndef FlashPixFormat_h
91 #include "fpxformt.h"
92 #endif
93
94 #ifndef CompressorJPEG_h
95 #include "cp_jpeg.h"
96 #endif
97 #ifndef Compresseur32Vers24_h
98 #include "cp32to24.h"
99 #endif
100
101 #ifndef SwapBytes_h
102 #include "swapbyte.h"
103 #endif
104
105 // Constants
106 // ---------
107
108 // Variables
109 // ---------
110 Boolean gContrastVal = 0;
111 unsigned char gContrastLut[256];
112
113 // ----------------------------------------------------------------------------
114 // Internal Functions
115 // ----------------------------------------------------------------------------
116
117 // ----------------------------------------------------------------------------
118 // Member Functions
119 // ----------------------------------------------------------------------------
120
121 // ----------------------------------------------------------------------------
122 // Methods of the "PTileFlashPix" class
123 //
124 // Manage a tile of a sub-image (generaly a tile is 256 x 256 pixels)
125 // ----------------------------------------------------------------------------
126
PTileFlashPix()127 PTileFlashPix::PTileFlashPix()
128 {
129 pixelsSpace = NON_AUTHORIZED_SPACE;
130 rawPixelsSpace = NON_AUTHORIZED_SPACE;
131 dirtyCount = -1; // This value set when pixels read
132 tileInitialize = FALSE;
133 viewingParamApplied = FALSE;
134
135 //Initialize compression options
136 compression = 0;
137 compressionSubtype = 0;
138 idCodec = ConvertCompressionOption();
139 }
140
141
142 // ----------------------------------------------------------------------------
143 // suppress the 'pixels' buffer from the list of buffer in memory and delete it
~PTileFlashPix()144 PTileFlashPix::~PTileFlashPix()
145 {
146 }
147
148
149 // ----------------------------------------------------------------------------
150 // Initialize a tile with file assignment
151 // Use this constructor in Read mode
InitializeRead(PResolutionLevel * father,long pixelOffset,long sizetile,long id,long theCompression,long theCompressionSubtype)152 void PTileFlashPix::InitializeRead (PResolutionLevel* father, long pixelOffset,
153 long sizetile, long id, long theCompression, long theCompressionSubtype)
154 {
155 // Call the parent method
156 PTile::InitializeRead (father, pixelOffset, sizetile, id, theCompression);
157
158 // Set the compression type and subtype for tile
159 compression = theCompression;
160 compressionSubtype = theCompressionSubtype;
161 idCodec = ConvertCompressionOption();
162
163 // Set quality factor
164 qualityFactor = ((PResolutionFlashPix *)fatherSubImage)->qualityFactor;
165
166 // Set the number of channels
167 nbChannels = ((PResolutionFlashPix *)fatherSubImage)->nbChannels;
168
169 // Will have to expand the channels onto 32 bits per pixel if no compression
170 if ((idCodec == TLC_Aucun) && (((PResolutionFlashPix*)fatherSubImage)->nbChannels != 4))
171 idCodec = TLC_32Vers24;
172 }
173
174
175 // ----------------------------------------------------------------------------
176 // Convert the FPX compression code to index of compressor
ConvertCompressionOption()177 TLC_IdCodec PTileFlashPix::ConvertCompressionOption ()
178 {
179 TLC_IdCodec index;
180
181
182 switch ((FPXCompressionOption)compression) {
183 case NONE:
184 index = TLC_Aucun;
185 break;
186 case SINGLE_COLOR:
187 index = TLC_SingleColor;
188 break;
189 case JPEG_UNSPECIFIED:
190 case JPEG_BY_QUALITY:
191 case JPEG_BY_TABLE_GROUP:
192 index = TLC_JPEG;
193 break;
194
195 // For FlashPix, currently assume valid compressions are only these above modes, anything else is
196 // considered invalid and no compressur for it
197
198 default:
199 index = TLC_INVALID;
200 break;
201 }
202 return index;
203 }
204
205
206 // ----------------------------------------------------------------------------
207 // Write the data passed as parameters directly in the file
208 // The passed tile data is written to the file, no compression is performed.
209 // Returns: FPX_FILE_WRITE_ERROR
210 //
WriteRawTile(FPXCompressionOption compressOption,unsigned char compressQuality,long compressSubtype,unsigned int dataLength,void * data)211 FPXStatus PTileFlashPix::WriteRawTile (FPXCompressionOption compressOption,
212 unsigned char compressQuality,
213 long compressSubtype,
214 unsigned int dataLength,
215 void* data)
216 {
217 Boolean wasLocked, ok;
218 FPXStatus status = FPX_OK;
219
220
221 assert(data);
222
223 // Set the number of channels
224 nbChannels = ((PResolutionFlashPix *)fatherSubImage)->nbChannels;
225
226 wasLocked = IsLocked();
227 Lock();
228 OLEHeaderStream *subStreamData = ((PResolutionFlashPix*)fatherSubImage)->GetSubStreamData();
229
230 // If the tile has never been written, reset the compression with the one passed in parameter
231 if ( posPixelFic < 0 && !tileInitialize ) {
232 compression = compressOption;
233 idCodec = ConvertCompressionOption();
234 qualityFactor = compressQuality;
235 compressionSubtype = compressSubtype;
236 }
237
238 // TEMPORARY IN THIS VERSION: when no compression, should compress 32->nbChannel
239 if ((idCodec == TLC_Aucun) && (!fatherSubImage->fatherFile->existAlphaChannel))
240 idCodec = TLC_32Vers24;
241
242 // Compute position of the tile in file
243 // CAUTION : go to the end of the file if the new tile is bigger than the old one
244 // NO GARBAGE COLLECTION WITHIN THE FILE
245
246 if ((posPixelFic < 0) || ((unsigned long) tileSize < dataLength)) {
247 ok = subStreamData->GetEndOfFile(&posPixelFic);
248 }
249
250 if (ok) {
251 // Set the tilesize as size of compressed data
252 tileSize = dataLength;
253
254 // Go to the right position in the stream...
255 ok = subStreamData->Seek(posPixelFic);
256
257 // ... then write the pixels or the compressed tile (at last...)
258 if (ok)
259 if (subStreamData->Write((unsigned char *)data,tileSize) == 0)
260 ok = false;
261 }
262
263 if (!ok)
264 status = FPX_FILE_WRITE_ERROR;
265
266 // Clean up tile and release memory
267 if (wasLocked == false)
268 UnLock();
269
270 if (ok) {
271 // Update the global modification flag
272 PFileFlashPixIO* father = (PFileFlashPixIO*)(fatherSubImage->fatherFile);
273 father->tilesHasBeenModified = TRUE;
274 }
275 return status;
276 }
277
278
279 // --------------------------------------------------------------------------
280 // Write the tile in 'rawPixels' to the disk file. Use compression if necessary.
281 //
282 // Returns: FPX_MEMORY_ALLOCATION_FAILED
283 // FPX_ERROR - if no 'rawPixels' buffer exists in memory
284 // FPX_FILE_WRITE_ERROR
285 // FPX_INVALID_COMPRESSION_ERROR - if no decompressor available
286 //
Write()287 FPXStatus PTileFlashPix::Write()
288 {
289 register long TILE_WIDTH = fatherSubImage->fatherFile->tileWidth;
290 long sizeCompressed; // Size of data after compression
291
292 ptr_Compresseur monCompresseur;
293
294 Ptr buffer = NULL;
295 Pixel *entireTile;
296 Boolean wasLocked;
297 FPXStatus status = FPX_OK;
298
299 FPXBaselineColorSpace base = ((PResolutionFlashPix*)fatherSubImage)->baseSpace;
300 FPXBaselineColorSpace used = ((PFileFlashPixIO*)fatherSubImage->fatherFile)->usedSpace;
301
302 // Set the number of channels
303 nbChannels = ((PResolutionFlashPix *)fatherSubImage)->nbChannels;
304
305 if( rawPixels == NULL) {
306 assert( rawPixels);
307 return FPX_ERROR;
308 }
309
310 // Allocate an intermediate tile if we have to pad or convert the tile
311 if ((width < TILE_WIDTH) || (height < TILE_WIDTH) || (used != base)) {
312 FastCallocArray( entireTile, Pixel, TILE_WIDTH * TILE_WIDTH);
313
314 if (entireTile == NULL)
315 return FPX_MEMORY_ALLOCATION_FAILED;
316
317 short i, j;
318 Pixel *source = rawPixels;
319 Pixel *dest = entireTile;
320
321 // Copy line by line and pad (padding conform to spec p.22)
322 for (i = 0; i < height; i++, source+=width, dest+=TILE_WIDTH) {
323 // Copy the raw pixels of the row
324 memcpy (dest, source, width*sizeof(Pixel));
325
326 // Pad the rest of the line with the value of the last pixel
327 Pixel *pt = dest + width;
328 Pixel padPixel = *(source + width - 1);
329
330 for (j = width; j < TILE_WIDTH; j++, pt++)
331 *pt = padPixel;
332 }
333
334 // Pad the remaining lines with a copy of the last line
335 Pixel *pt = dest - TILE_WIDTH;
336
337 for (i = height; i < TILE_WIDTH; i++, dest+=TILE_WIDTH)
338 memcpy (dest, pt, TILE_WIDTH*sizeof(Pixel));
339 } else
340 entireTile = rawPixels;
341
342 wasLocked = IsLocked();
343 Lock();
344
345 PFlashPixFile* fileFPX = (PFlashPixFile*)(fatherSubImage->fatherFile->filePtr);
346 OLEHeaderStream *subStreamData = ((PResolutionFlashPix*)fatherSubImage)->GetSubStreamData();
347
348 // PTCH_104 - colorspace conversion is now in PTile::WriteRectangle()
349 // if (used != base)
350 // {
351 // ConvertPixelBuffer((unsigned char*)(entireTile),TILE_WIDTH*TILE_WIDTH,used,base);
352 // pixelsSpace = base;
353 // }
354
355 // If the tile has never been written, reset the compression with the one of the file
356 if ( (posPixelFic < 0) && !tileInitialize ) {
357
358 compression = (long)((PResolutionFlashPix *)fatherSubImage)->compression;
359 idCodec = ConvertCompressionOption();
360
361 // Set quality factor
362 qualityFactor = ((PResolutionFlashPix *)fatherSubImage)->qualityFactor;
363 }
364
365 // TEMPORARY IN THIS VERSION: single color compression is performed on tiles which consists
366 // of only one color
367 Pixel singleColorPixel = fatherSubImage->fatherFile->backgroundBase; // default color value of this tile
368
369 if ( (compression == SINGLE_COLOR) && !tileInitialize )
370 {
371 // Check to see if all pixels in this tile are same. If so apply single color compression,
372 // otherwise no compression is applied
373 if ( !IsTileAllSamePixel(entireTile, (short) TILE_WIDTH,(short) TILE_WIDTH, &singleColorPixel) ) {
374 compression = NONE;
375 idCodec = ConvertCompressionOption();
376 }
377 else
378 {
379 // Only rotate color components if opacity is not last in order PTCH_202
380 if (!((base == SPACE_32_BITS_RGBA) // PTCH_202
381 || (base == SPACE_32_BITS_YCCA))) { // PTCH_202
382 // Shift Pixels so that compsubtype gets written
383 // as RGBA not ARGB
384 // This should actually be the same channel order
385 // as specified in Subimage color of Image Contents
386 Pixel tmpPixel;
387
388 tmpPixel.alpha = singleColorPixel.rouge;
389 tmpPixel.rouge = singleColorPixel.vert;
390 tmpPixel.vert = singleColorPixel.bleu;
391
392 if( nbChannels > 3)
393 tmpPixel.bleu = singleColorPixel.alpha;
394 else
395 tmpPixel.bleu = 0x00;
396
397 singleColorPixel = tmpPixel;
398 } // PTCH_202
399 }
400 }
401
402 // TEMPORARY IN THIS VERSION: when no compression, should compress 32->nbChannel
403
404 if ((idCodec == TLC_Aucun) && (!fatherSubImage->fatherFile->existAlphaChannel))
405 idCodec = TLC_32Vers24;
406
407 compressionSubtype = 0; // subtype is 0 for all cases except TLC_SingleColor.
408
409 switch(idCodec) {
410 case TLC_Aucun: // If no Compression
411 // Set the tilesize
412 sizeCompressed = TILE_WIDTH * TILE_WIDTH * sizeof(Pixel);
413
414 // Set the output buffer to write
415 buffer = (Ptr)(entireTile);
416 break;
417
418 case TLC_SingleColor: // Single color compression
419 // Set the tile values for a single color tile (see spec p.46-48)
420 posPixelFic = 0;
421 tileSize = 0;
422 compression = SINGLE_COLOR;
423 compressionSubtype = (long)(singleColorPixel);
424 #ifndef IN_LITTLE_ENDIAN
425 compressionSubtype = (long) SwapBytes( (int32)compressionSubtype );
426 #endif
427 // Update local management values
428 sizeCompressed = 0;
429 buffer = NULL;
430 break;
431
432 case TLC_JPEG: // JPEG compression
433 // Set compression subtype ( The subtype is only used by jpeg compression )
434 compressionSubtype = ((PResolutionFlashPix *)fatherSubImage)->compressionSubtype;
435
436 // If channel is less than 4, compression the data
437 if ( nbChannels < 4 ) {
438 // Get the TLC_32Vers24 compressor
439 monCompresseur = (*tousLesCodecs)[TLC_32Vers24];
440 monCompresseur->Lock(); // Lock buffers used by the compressor
441
442 // In the case of simple compression, we have to set the number of channels and the direction
443 // of the compression. This is optimized only for the most common cases.
444 Boolean leftShift = false;
445 if ((base == SPACE_32_BITS_RGBA) || (base == SPACE_32_BITS_YCCA)) {
446 leftShift = true;
447 }
448 ((obj_Compresseur32Vers24 *)monCompresseur)->SetCompressionParameters(nbChannels,leftShift);
449
450 if(!monCompresseur->Compresse((Ptr)entireTile,(short) TILE_WIDTH,
451 (short)TILE_WIDTH, &buffer, &tileSize)) {
452 fileFPX->CompressionError(); // Compression failed => Signal error
453 posPixelFic = -1; // Compression failed => Delete reference pointer
454 monCompresseur->UnLock(); // Unlock buffers used by the compressor
455 assert (false);
456
457 if ((width < TILE_WIDTH) || (height < TILE_WIDTH) || (used != base))
458 FastDeleteArray( entireTile, Pixel);
459 status = FPX_MEMORY_ALLOCATION_FAILED; // CHG_FILE_ERR - the only error that occurs
460 goto RETURN;
461 }
462
463 LockDecompress ();
464 AllocDecompress(tileSize);
465 if(decompressBuffer == NULL) { // CHG_FILE_ERR - check for allocation failure
466 status = FPX_MEMORY_ALLOCATION_FAILED;
467 goto RETURN;
468 }
469 memcpy(decompressBuffer, buffer, tileSize);
470 } else
471 decompressBuffer = (Ptr)entireTile;
472
473 // Get the jpeg compressor
474 monCompresseur = (*tousLesCodecs)[idCodec];
475
476 unsigned char internalConv;
477
478 if(base == SPACE_32_BITS_RGBA || base == SPACE_32_BITS_RGB ||
479 base == SPACE_32_BITS_ARGB) {
480 internalConv = 1;
481 }
482 else {
483 internalConv = 0;
484 // clear the internal rotation bits from compression subtype
485 compressionSubtype &= 0xFF00FFFF; // Clear chroma subsample flags
486 }
487
488
489 // Set the jpeg parameters
490 if ( (status = (FPXStatus)((PCompressorJPEG *)monCompresseur)->SetCompressionParameters(
491 GET_InterleaveType(compressionSubtype),
492 GET_ChromaSubSample(compressionSubtype),
493 // GET_InternalColorConv(compressionSubtype),
494 internalConv,
495 compressionSubtype,
496 qualityFactor,
497 nbChannels,
498 NULL,
499 0,
500 FALSE ))) {
501 fileFPX->CompressionError(); // Compression failed => Signal error
502 posPixelFic = -1; // Compression failed => Delete reference pointer
503 assert (false);
504
505 if ((width < TILE_WIDTH) || (height < TILE_WIDTH) || (used != base))
506 FastDeleteArray(entireTile,Pixel);
507 status = (FPXStatus)jpegErrorToFPXerror( status);
508 goto RETURN;
509 }
510
511 // Do the JPEG compression
512
513 if ( ((PCompressorJPEG *)monCompresseur)->Compress((unsigned char *)decompressBuffer,
514 (short)TILE_WIDTH, (short)TILE_WIDTH, (unsigned char **)&buffer,
515 &sizeCompressed)) {
516 fileFPX->CompressionError(); // Compression failed => Signal error
517 posPixelFic = -1; // Compression failed => Delete reference pointer
518 assert (false);
519
520 if ((width < TILE_WIDTH) || (height < TILE_WIDTH) || (used != base))
521 FastDeleteArray(entireTile,Pixel);
522 status = FPX_MEMORY_ALLOCATION_FAILED; // CHG_FILE_ERR - this is the only Compresse error
523 goto RETURN;
524 }
525 if ( nbChannels < 4 )
526 UnLockDecompress (); // Unflag decompress buffer
527
528 // Write jpeg header to the image content property set
529 WriteHeader(fileFPX, ((PCompressorJPEG *)monCompresseur)->GetHeaderBuf(),
530 ((PCompressorJPEG *)monCompresseur)->GetHeaderSize());
531 break;
532
533 default:
534 // Get the corresponding compressor
535 monCompresseur = (*tousLesCodecs)[idCodec];
536 monCompresseur->Lock(); // Lock buffers used by the compressor
537
538 if (idCodec == TLC_32Vers24) {
539 // In the case of simple compression, we have to set the number of channels and the direction
540 // of the compression. This is optimized only for the most common cases.
541 long nbChan = ((PResolutionFlashPix*)fatherSubImage)->nbChannels;
542 Boolean leftShift = false;
543 if ((base == SPACE_32_BITS_RGBA) || (base == SPACE_32_BITS_YCCA)) {
544 leftShift = true;
545 }
546 ((obj_Compresseur32Vers24 *)monCompresseur)->SetCompressionParameters(nbChan,leftShift);
547 }
548
549 if (!monCompresseur->Compresse((Ptr)entireTile,(short) TILE_WIDTH,
550 (short) TILE_WIDTH, &buffer, &sizeCompressed)) {
551 fileFPX->CompressionError(); // Compression failed => Signal error
552 posPixelFic = -1; // Compression failed => Delete reference pointer
553 monCompresseur->UnLock(); // Unlock buffers used by the compressor
554 assert (false);
555
556 if ((width < TILE_WIDTH) || (height < TILE_WIDTH) || (used != base))
557 FastDeleteArray(entireTile,Pixel);
558 status = FPX_MEMORY_ALLOCATION_FAILED; // CHG_FILE_ERR - this is the only Compresse error
559 goto RETURN;
560 }
561 break;
562 }
563
564 // Compute position of the tile in file
565 // CAUTION : go to the end of the file if the new tile is bigger than the old one
566 // NO GARBAGE COLLECTION WITHIN THE FILE
567 if ((posPixelFic < 0) || (tileSize < sizeCompressed)) {
568 if (subStreamData->GetEndOfFile( &posPixelFic) == 0)
569 status = FPX_FILE_READ_ERROR;
570 }
571
572 if ((status == FPX_OK) && buffer) {
573 tileSize = sizeCompressed; // Set tilesize as size of compressed data
574
575 if (subStreamData->Seek(posPixelFic) == 0) // Go to the right position in the stream
576 status = FPX_FILE_READ_ERROR;
577 else // Write the pixels or the compressed tile
578 if (subStreamData->Write((unsigned char *)buffer,tileSize) == 0)
579 status = subStreamData->getFPXStatus();
580 }
581
582 // Clean up tile and release memory
583 if ((idCodec != TLC_Aucun) && (idCodec != TLC_SingleColor)) { // If Compression
584 ptr_Compresseur monCompresseur = (*tousLesCodecs)[idCodec];
585 monCompresseur->UnLock(); // Unlock buffers used by the compressor
586 }
587
588 #ifdef Memoire_Debug
589 VISU2 "Writing this tile successfull\n" FIN
590 #endif
591
592 RETURN:
593 if (wasLocked == false)
594 UnLock();
595
596 if ((width < TILE_WIDTH) || (height < TILE_WIDTH) || (used != base))
597 FastDeleteArray(entireTile,Pixel);
598
599 if (status == FPX_OK) {
600 // Update the global modification flag
601 PFileFlashPixIO* father = (PFileFlashPixIO*)(fatherSubImage->fatherFile);
602 father->tilesHasBeenModified = TRUE;
603 }
604 return (status);
605 }
606
607
608 // ----------------------------------------------------------------------------
609 // Read the data from the file directly in the passed parameters
610 // This returns the raw, possibly compressed tile data as stored in the file
611 // Returns: FPX_MEMORY_ALLOCATION_FAILED
612 // FPX_ERROR - if tile is missing in the file
613 // FPX_FILE_READ_ERROR
614 //
ReadRawTile(FPXCompressionOption * compressOption,unsigned char * compressQuality,long * compressSubtype,unsigned int * dataLength,void ** data)615 FPXStatus PTileFlashPix::ReadRawTile (FPXCompressionOption* compressOption,
616 unsigned char* compressQuality,
617 long* compressSubtype,
618 unsigned int* dataLength,
619 void** data)
620 {
621 // Declare some management variable
622
623 PFlashPixFile *fileFPX = NULL;
624 Boolean wasLocked = IsLocked();
625 FPXStatus status = FPX_OK;
626
627
628 // Init the passed parameters with default values
629 *compressOption = NONE;
630 *compressQuality = 0;
631 *compressSubtype = 0;
632 *dataLength = 0;
633 *data = NULL;
634
635 // If the tile has never been written, return an error
636 if (posPixelFic < 0) {
637 status = FPX_ERROR;
638 goto exit;
639 }
640
641 // Test if the file is already open
642 if (fatherSubImage->fatherFile->filePtr)
643 fileFPX = (PFlashPixFile*)fatherSubImage->fatherFile->filePtr;
644
645 else {
646 // This should never happen, however, we try to open the file
647 assert(false); // beeps...
648
649 // Open the FPX file
650 PFileFlashPixIO* parentFile = (PFileFlashPixIO*)(fatherSubImage->fatherFile);
651
652 // These calls are flacky because the pointed values may be obsolete by now... may crash...
653 if (parentFile->owningStorage)
654 fileFPX = new PFlashPixFile (parentFile->owningStorage,parentFile->storageName,mode_Lecture);
655 else
656 fileFPX = new PFlashPixFile (parentFile->fileName,parentFile->storageName,mode_Lecture);
657
658 // If error while opening : signal error and exit with error
659 if (fileFPX->Erreur() != FPX_OK) {
660 parentFile->UpdateErrorCount();
661 fileFPX->SignaleErreur();
662 status = FPX_FILE_READ_ERROR;
663 goto exit;
664 }
665 }
666
667 // dk 6aug96. need block so subStreamData goes out of scope before exit
668 {
669 OLEHeaderStream *subStreamData = ((PResolutionFlashPix*)fatherSubImage)->GetSubStreamData();
670
671 if (IVUE_System->GetErrorsList() != NULL) {
672 status = FPX_FILE_READ_ERROR;
673 goto exit;
674 }
675
676 Lock();
677
678 // Allocate the required memory
679 char* buffer;
680
681 FastAllocArray(buffer, char, tileSize);
682 if (buffer == NULL) {
683 status = FPX_MEMORY_ALLOCATION_FAILED;
684 goto exit;
685 }
686
687 // Read pixels data (at last...)
688 if (subStreamData->Seek(posPixelFic) == false) {
689 FastDeleteArray(buffer, char);
690 status = FPX_FILE_READ_ERROR;
691 goto exit;
692 }
693
694 if (subStreamData->Read(buffer,tileSize) == 0) {
695 FastDeleteArray(buffer, char);
696 status = FPX_FILE_READ_ERROR;
697 goto exit;
698 }
699
700 // Update the other parameters
701 *data = buffer;
702 *dataLength = tileSize;
703 *compressOption = (FPXCompressionOption)(compression);
704 *compressQuality = qualityFactor;
705 *compressSubtype = compressionSubtype;
706 }
707
708 exit:
709 // Close the file if IVUE opened in read only
710 if (!fatherSubImage->fatherFile->filePtr)
711 delete fileFPX;
712 if (wasLocked == false)
713 UnLock();
714 return status;
715 }
716
717
718 // ---------------------------------------------------------------------------------
719 // Read a tile's raw data and decompress it. The data is placed in 'rawPixels'.
720 // If 'rawPixels' contains data, then the data is lost.
721 //
722 // Returns: FPX_MEMORY_ALLOCATION_FAILED
723 // FPX_FILE_READ_ERROR
724 // FPX_INVALID_COMPRESSION_ERROR - if no decompressor available
725 //
ReadRawPixels()726 FPXStatus PTileFlashPix::ReadRawPixels()
727 {
728 ptr_Compresseur monDecompresseur;
729 PFlashPixFile *fileFPX;
730 Pixel *entireTile;
731 register long TILE_WIDTH = fatherSubImage->fatherFile->tileWidth;
732 Boolean wasLocked = false;
733 FPXStatus status = FPX_OK;
734 OLEHeaderStream *subStreamData = NULL;
735
736 FPXBaselineColorSpace base = ((PResolutionFlashPix*)fatherSubImage)->baseSpace;
737 FPXBaselineColorSpace used = ((PFileFlashPixIO*)fatherSubImage->fatherFile)->usedSpace;
738
739 // Allocate pixel buffer, if it's hasn't been done yet.
740 if (rawPixels == NULL)
741 if (AllocateRawPixels())
742 return FPX_MEMORY_ALLOCATION_FAILED;
743 rawPixelsSpace = base;
744
745 // If the tile has never been written (i.e., it's not in the file), then fill it with the
746 // background color and return. The file should always have all the tiles, unless the
747 // file is in the process of creation.
748 if ((posPixelFic < 0) && (idCodec != TLC_SingleColor)) { // PTCH_NEGONE
749 // If there was an error, fill the tile with the background color.
750 Pixel BACKGROUND = fatherSubImage->fatherFile->backgroundUsed;
751 Pixel* pt = rawPixels;
752 long i = width * height;
753
754 while (i--)
755 *pt++ = BACKGROUND;
756 return FPX_OK;
757 }
758
759 // Test that the file is already open
760 if (fatherSubImage->fatherFile->filePtr)
761 fileFPX = (PFlashPixFile*)fatherSubImage->fatherFile->filePtr;
762 else {
763 // This should never happen, however, we try to open the file
764 assert(false); // beeps...
765
766 // Open the FPX file
767 PFileFlashPixIO* parentFile = (PFileFlashPixIO*)(fatherSubImage->fatherFile);
768
769 // These calls are flacky because the pointed values may be obsolete by now... may crash...
770 if (parentFile->owningStorage)
771 fileFPX = new PFlashPixFile (parentFile->owningStorage,parentFile->storageName,mode_Lecture);
772 else
773 fileFPX = new PFlashPixFile (parentFile->fileName,parentFile->storageName,mode_Lecture);
774
775 // If error while opening : signal error and exit with error
776 if (fileFPX->Erreur() != FPX_OK) {
777 parentFile->UpdateErrorCount();
778 fileFPX->SignaleErreur();
779 freshPixels = 0;
780 status = FPX_FILE_READ_ERROR;
781 goto RETURN;
782 }
783 }
784
785 subStreamData = ((PResolutionFlashPix*)fatherSubImage)->GetSubStreamData();
786 if (IVUE_System->GetErrorsList() != NULL) {
787 status = FPX_FILE_READ_ERROR;
788 goto RETURN;
789 }
790 wasLocked = IsLocked();
791 Lock();
792
793 // This is a left or bottom edge tile and is not full size, then allocate a temporary
794 // buffer of full tile size.
795 if ((width < TILE_WIDTH) || (height < TILE_WIDTH)) {
796 FastCallocArray( entireTile, Pixel, TILE_WIDTH * TILE_WIDTH);
797 if (entireTile == NULL) {
798 status = FPX_MEMORY_ALLOCATION_FAILED;
799 goto RETURN;
800 }
801 } else
802 entireTile = rawPixels;
803
804 // Read the data from the file and decompress it into 'entireTile'
805 switch(idCodec) {
806 case TLC_Aucun: // If no Compression
807 // Read pixels data (at last...)
808 if (subStreamData->Seek(posPixelFic) == false)
809 status = subStreamData->getFPXStatus();
810 else if (subStreamData->Read((unsigned char*)entireTile,tileSize) == 0)
811 status = subStreamData->getFPXStatus();
812 break;
813
814 case TLC_SingleColor: { // Fill the tile with the single color info
815 Pixel tmpPixel;
816 Pixel *pt = entireTile;
817 long nbPixels = TILE_WIDTH*TILE_WIDTH;
818
819 #ifndef IN_LITTLE_ENDIAN
820 compressionSubtype = (long) SwapBytes( (int32)compressionSubtype );
821 #endif
822 unsigned char *tmpptr = (unsigned char*)&compressionSubtype;
823
824 long nbChan = ((PResolutionFlashPix*)fatherSubImage)->nbChannels;
825
826 if(nbChan == 4) {
827 tmpPixel.alpha = tmpptr[0];
828 tmpPixel.rouge = tmpptr[1];
829 tmpPixel.vert = tmpptr[2];
830 tmpPixel.bleu = tmpptr[3];
831 }
832 else {
833 tmpPixel.alpha = tmpptr[3];
834 tmpPixel.rouge = tmpptr[0];
835 tmpPixel.vert = tmpptr[1];
836 tmpPixel.bleu = tmpptr[2];
837 }
838 while (nbPixels--)
839 *pt++ = tmpPixel;
840 #ifndef IN_LITTLE_ENDIAN
841 compressionSubtype = (long) SwapBytes( (int32)compressionSubtype );
842 #endif
843 break; }
844
845
846 case TLC_JPEG: { // JPEG decompression
847 unsigned char* jpegHeader = ((PResolutionFlashPix*)fatherSubImage)->jpegHeader;
848 unsigned long headerSize = ((PResolutionFlashPix*)fatherSubImage)->headerSize;
849
850 decompressorIsMissing = true; // look for the decompressor
851
852 // Get the corresponding compressor
853 monDecompresseur = (*tousLesCodecs)[idCodec];
854
855 if (monDecompresseur != NULL)
856 // Read jpeg header to the image content property set
857 if ( ReadHeader(fileFPX, &jpegHeader, &headerSize) ) {
858 ((PResolutionFlashPix*)fatherSubImage)->jpegHeader = jpegHeader;
859 ((PResolutionFlashPix*)fatherSubImage)->headerSize = headerSize;
860 decompressorIsMissing = false;
861 }
862 if (!decompressorIsMissing) { // If decompressor is present
863 LockDecompress (); // Flag decompress buffer in use
864 AllocDecompress(tileSize); // Allocate a buffer for compressed data
865
866 if (!decompressBuffer) // If no buffer allocated�
867 decompressorIsMissing = true; // �decompression failed
868 else {
869 // Read pixels data (at last...)
870 if (subStreamData->Seek( posPixelFic) == false) {
871 status = FPX_FILE_READ_ERROR;
872 goto RETURN;
873 }
874 if (subStreamData->Read( (unsigned char*)decompressBuffer, tileSize) == 0) {
875 status = FPX_FILE_READ_ERROR;
876 goto RETURN;
877 }
878 // Set the jpeg parameters
879 if ( (status = (FPXStatus)((PCompressorJPEG *)monDecompresseur)->SetCompressionParameters(
880 GET_InterleaveType(compressionSubtype),
881 GET_ChromaSubSample(compressionSubtype),
882 GET_InternalColorConv(compressionSubtype),
883 compressionSubtype,
884 qualityFactor,
885 nbChannels,
886 jpegHeader,
887 headerSize,
888 TRUE ))) {
889 status = (FPXStatus)jpegErrorToFPXerror( status);
890 goto RETURN;
891 }
892
893 // Do the JPEG decompression
894 if ( (status = (FPXStatus)((PCompressorJPEG *)monDecompresseur)->Decompress((unsigned char *)entireTile,
895 (short) TILE_WIDTH,(short) TILE_WIDTH, (unsigned char*)decompressBuffer, tileSize) ) ) {
896 status = (FPXStatus)jpegErrorToFPXerror( status);
897 goto RETURN;
898 }
899
900 // Convert to 4-channel colorspace
901 if ( nbChannels < 4 ) {
902 // Get a pointer to the simple expansion function
903 monDecompresseur = (*tousLesCodecs)[TLC_32Vers24];
904
905 // Determine the alignment direction
906 Boolean leftShift = false;
907
908 if (((base == SPACE_32_BITS_RGB) && (used == SPACE_32_BITS_RGBA)) ||
909 ((base == SPACE_32_BITS_YCC) && (used == SPACE_32_BITS_YCCA))) {
910 leftShift = true;
911 rawPixelsSpace = used;
912 }
913
914 // Set the expansion parameters
915 ((obj_Compresseur32Vers24 *)monDecompresseur)->SetCompressionParameters(nbChannels,leftShift);
916
917 LockDecompress (); // Flag decompress buffer in use
918 AllocDecompress(TILE_WIDTH * TILE_WIDTH * nbChannels); // Allocate a buffer for compressed data
919 if(decompressBuffer == NULL) {
920 status = FPX_MEMORY_ALLOCATION_FAILED;
921 goto RETURN;
922 }
923 // Expand the buffer
924 memcpy( decompressBuffer, entireTile, TILE_WIDTH * TILE_WIDTH * nbChannels);
925 monDecompresseur->Decompresse((Ptr)entireTile,(short) TILE_WIDTH,
926 (short) TILE_WIDTH, decompressBuffer,
927 TILE_WIDTH * TILE_WIDTH * nbChannels);
928 UnLockDecompress (); // Unflag decompress buffer
929 }
930 }
931 UnLockDecompress (); // Unflag decompress buffer
932 }
933 break;
934 }
935 default:
936 {
937 decompressorIsMissing = true; // look for the decompressor
938
939 // Check if the tile is valid
940 if ( (unsigned long) compression == 0xFFFFFFFF )
941 break;
942
943 monDecompresseur = (*tousLesCodecs)[idCodec];
944
945 if (monDecompresseur != NULL)
946 if ( monDecompresseur->DecompresseurPresent() )
947 decompressorIsMissing = false;
948
949 if (!decompressorIsMissing) { // If decompressor is present
950 if (idCodec == TLC_32Vers24) {
951
952 // In the case of simple expansion, we have to set the number of channels and the direction
953 // of the expansion. This is optimized only for the most common cases.
954 long nbChan = ((PResolutionFlashPix*)fatherSubImage)->nbChannels;
955 Boolean leftShift = false;
956
957 if (((base == SPACE_32_BITS_RGB) && (used == SPACE_32_BITS_RGBA)) ||
958 ((base == SPACE_32_BITS_YCC) && (used == SPACE_32_BITS_YCCA))) {
959 leftShift = true;
960 rawPixelsSpace = used;
961 }
962 ((obj_Compresseur32Vers24 *)monDecompresseur)->SetCompressionParameters(nbChan,leftShift);
963 }
964
965 LockDecompress (); // Flag decompress buffer in use
966 AllocDecompress(tileSize); // Allocate a buffer for compressed data
967
968 if (!decompressBuffer) // If no buffer allocated�
969 decompressorIsMissing = true; // �decompression failed
970 else {
971 // Read pixels data (at last...)
972 if (subStreamData->Seek(posPixelFic) == false) {
973 status = FPX_FILE_READ_ERROR; // CHG_FILE_ERR - better error report
974 goto RETURN;
975 }
976 if (subStreamData->Read((unsigned char*)decompressBuffer,tileSize) == 0) {
977 status = FPX_FILE_READ_ERROR; // CHG_FILE_ERR - better error report
978 goto RETURN;
979 }
980 if ( !monDecompresseur->Decompresse((Ptr)entireTile,(short) TILE_WIDTH,
981 (short) TILE_WIDTH, decompressBuffer, tileSize) )
982 decompressorIsMissing = true; // Decompression failed
983 }
984 UnLockDecompress (); // Unflag decompress buffer
985 }
986 break;
987 }
988 }
989
990 // If the tile is not full-sized, then copy the pertinent pixels into 'rawPixels'
991 if ((width < TILE_WIDTH) || (height < TILE_WIDTH)) {
992 short i;
993 Pixel *source = entireTile;
994 Pixel *dest = rawPixels;
995
996 for (i = 0; i < height; i++, source += TILE_WIDTH, dest += width)
997 memcpy (dest, source, width * sizeof(Pixel));
998 FastDeleteArray( entireTile, Pixel);
999 }
1000
1001 // Invert alpha channel if requested by user
1002 if (fatherSubImage->fatherFile->inverseAlphaChannel && invertLUT) {
1003 unsigned char* pt = (unsigned char*)(rawPixels);
1004 long i, j;
1005
1006 for (i = 0; i < height; i++)
1007 for (j = 0; j < width; j++, pt+=4)
1008 *pt = invertLUT[*pt];
1009 }
1010
1011 RETURN:
1012 freshPixels = 0; // No modified pixels in buffer yet
1013 pixelsStale = true; // Buffer has not been modified yet
1014
1015 if (wasLocked == false)
1016 UnLock();
1017
1018 if (status != FPX_OK) {
1019 if (decompressorIsMissing)
1020 fileFPX->CompressionError(); // Signal error
1021
1022 int32 *pt = (int32*)(rawPixels);
1023 int32 i, j, pat_i, pat_j;
1024
1025 // CHG_FILE_ERR - fixed the following loops so only height x width pixels are
1026 // written into the rawPixels buffer (not TILE_WIDTH x TILE_WIDTH)
1027 for (i = 0, pat_i = 0; i < height; i++, pat_i++) {
1028 if (pat_i == 8)
1029 pat_i = 0;
1030 for (j = 0, pat_j = 8 - pat_i; j < width; j++, pat_j++, pt++) {
1031 if (pat_j == 8) pat_j = 0;
1032 switch (pat_j) {
1033 case 0 :
1034 case 4 :
1035 *pt = 0x7F7F7F; break;
1036 case 1 :
1037 case 2 :
1038 case 3 :
1039 *pt = 0xFFFFFF; break;
1040 case 5 :
1041 case 6 :
1042 case 7 :
1043 *pt = 0; break;
1044 }
1045 }
1046 }
1047 }
1048
1049 // Close the file if IVUE opened in read only
1050 if (!fatherSubImage->fatherFile->filePtr)
1051 delete fileFPX;
1052
1053 return status;
1054 }
1055
1056
1057 // ---------------------------------------------------------------------------------
1058 // Return a tile's display-modified data. If necessary, this will read the raw data in
1059 // from the file. If the 'rawPixels' have already been read and decompressed, then
1060 // file reading is not necessary.
1061 // The data returned has contrast, filtering and colortwist applied to it. This data
1062 // is cached in 'pixels' and, if missing, is created during this call.
1063 //
1064 // Returns: FPX_MEMORY_ALLOCATION_FAILED
1065 // FPX_COLOR_CONVERSION_ERROR - due to filtering problems
1066 // FPX_INVALID_COMPRESSION_ERROR - if no decompressor available
1067 //
Read()1068 FPXStatus PTileFlashPix::Read()
1069 {
1070 ViewImage *imageParam = fatherSubImage->fatherFile->imageParam;
1071 Boolean wasLocked = IsLocked();
1072 FPXStatus status = FPX_OK;
1073
1074 // Check if the pixels are already cached, or if they have been modified
1075 // FPXBaselineColorSpace base = ((PResolutionFlashPix*)fatherSubImage)->baseSpace;
1076 FPXBaselineColorSpace used = ((PFileFlashPixIO*)fatherSubImage->fatherFile)->usedSpace;
1077
1078
1079 // Determine if we need to read new 'rawPixels' or create a new set of 'pixels'
1080 Boolean needNewPixels = false;
1081
1082 if (pixels == NULL) // If the 'pixels' buffer has not been allocated,
1083 needNewPixels = true; // then a new set of pixels needs to be made
1084 else if (pixelsStale) // Otherwise, if pixels contains old image data
1085 needNewPixels = true; // then a new set of pixels needs to be made
1086
1087 if (imageParam) { // If there are display-modifications for image
1088 if (imageParam->GetDirtyCount() // and the # times modifications have been set
1089 != dirtyCount) // does not match the count when pixels were created
1090 needNewPixels = true; // then a new set of pixels needs to be made
1091 }
1092 if (needNewPixels == true) // If a new set of 'pixels' needs to be made
1093 if (rawPixels == NULL) // and we don't have any raw pixels cached
1094 if ((status = ReadRawPixels())) // then read-in it's uncompressed data
1095 return status;
1096 // If there are no viewing/display modifications
1097 if (needNewPixels == false) { // and we don't need to update pixels
1098 TouchRawPixelsBuffer( ); // then we can use 'rawPixels'
1099 return FPX_OK;
1100 }
1101
1102 // A new set of 'pixels' needs to be made. Make sure there is memory available
1103 Lock();
1104 if (pixels == NULL)
1105 if (AllocatePixels()) {
1106 if (wasLocked == false)
1107 UnLock();
1108 return FPX_MEMORY_ALLOCATION_FAILED;
1109 }
1110 dirtyCount = fatherSubImage->fatherFile->imageParam->GetDirtyCount();
1111 viewingParamApplied = fatherSubImage->fatherFile->applyParam;
1112
1113 // Copy rawPixels into pixels. Set it's timestamp.
1114 memcpy (pixels, rawPixels, width * height * sizeof(Pixel));
1115 pixelsSpace = rawPixelsSpace;
1116 TouchPixelsBuffer( );
1117
1118 // Take the viewing display parameters into account
1119 if(imageParam && viewingParamApplied) {
1120
1121 if (imageParam->HasFilteringValue()) // Apply filtering (sharpen/blur)
1122 if ((status = ApplyFilter( rawPixelsSpace)) != FPX_OK)
1123 return status;
1124
1125 if (imageParam->HasColorTwist()) { // Apply colortwist to 'pixels'
1126 PColorTwist colorTwist;
1127
1128 imageParam->GetColorTwist( &colorTwist);
1129
1130 switch (pixelsSpace) {
1131 case SPACE_32_BITS_RGB:
1132 case SPACE_32_BITS_ARGB:
1133 case SPACE_32_BITS_RGBA: {
1134 PColorTwist RGBtorgb (RGB8_to_rgb);
1135 PColorTwist rgbtoycc (rgb_to_ycc);
1136 PColorTwist ycctorgb (ycc_to_rgb);
1137 PColorTwist rgbtoRGB (rgb_to_RGB8);
1138
1139 colorTwist = rgbtoRGB * ycctorgb * colorTwist * rgbtoycc * RGBtorgb;
1140 break; }
1141 case SPACE_32_BITS_YCC:
1142 case SPACE_32_BITS_M:
1143 case SPACE_32_BITS_MA: {
1144 PColorTwist YCC8toycc (YCC8_to_ycc);
1145 PColorTwist ycctoYCC8 (ycc_to_YCC8);
1146
1147 colorTwist = ycctoYCC8 * colorTwist * YCC8toycc;
1148
1149 // CHG_MONO_TINT - FlashPix spec states that monochrome images are tinted using
1150 // the colorTwist matrix. To preserve color information, if the 'used' space
1151 // (i.e., the space used by the calling applic) has color, then we will set the
1152 // 'pixelSpace' (the tile buffer after color transforms) to YCC. The matrix we
1153 // just created will give YCC output. There is a final colorspace conversion
1154 // at the end of this section that will do RGB->YCC conversion if necessary.
1155 if ((used != SPACE_32_BITS_M) && (used != SPACE_32_BITS_MA)) {
1156 if (pixelsSpace == SPACE_32_BITS_M)
1157 pixelsSpace = SPACE_32_BITS_YCC;
1158 else if (pixelsSpace == SPACE_32_BITS_MA)
1159 pixelsSpace = SPACE_32_BITS_YCCA;
1160 }
1161 break; }
1162 case SPACE_32_BITS_YCCA:
1163 case SPACE_32_BITS_AYCC: {
1164 PColorTwist YCC8toycc (YCC8_to_ycc);
1165 PColorTwist ycctoYCC8 (ycc_to_YCC8);
1166
1167 colorTwist = ycctoYCC8 * colorTwist * YCC8toycc;
1168 colorTwist.UseAlphaChannel();
1169 break; }
1170 default:
1171 {
1172 }
1173 }
1174 colorTwist.ApplyToPixelBuffer( pixels, pixelsSpace, width * height);
1175 }
1176
1177 if (imageParam->HasContrastValue()) { // Apply contrast to 'pixels'
1178 float contrastValue;
1179
1180 // Since contrast is applied in RGB space, if the pixels are currently in a YCC space
1181 // but are to be returned in RGB or monochrome space, then apply that conversion
1182 // now.
1183 if ((pixelsSpace == SPACE_32_BITS_YCC)
1184 || (pixelsSpace == SPACE_32_BITS_YCCA)
1185 || (pixelsSpace == SPACE_32_BITS_AYCC))
1186 if (!((used == SPACE_32_BITS_YCC)
1187 || (used == SPACE_32_BITS_YCCA)
1188 || (used == SPACE_32_BITS_AYCC))) {
1189 // If need be, preserve the opacity component for clippint the
1190 // contrast-adjusted component(s)
1191 FPXBaselineColorSpace tmpPixelSpace = used;
1192
1193 if ((pixelsSpace == SPACE_32_BITS_YCCA)
1194 || (pixelsSpace == SPACE_32_BITS_AYCC))
1195 if (used == SPACE_32_BITS_RGB)
1196 tmpPixelSpace = SPACE_32_BITS_ARGB;
1197
1198 ConvertPixelBuffer((unsigned char*)(pixels), width * height,
1199 pixelsSpace, tmpPixelSpace);
1200 pixelsSpace = tmpPixelSpace;
1201 }
1202 imageParam->GetContrast( &contrastValue);
1203 Contrast( contrastValue, pixelsSpace, pixels, width * height);
1204 }
1205 }
1206
1207 // Do the color conversion
1208 if (pixelsSpace != used) {
1209 ConvertPixelBuffer((unsigned char*)(pixels), width * height,pixelsSpace, used);
1210 pixelsSpace = used;
1211 }
1212
1213 if (wasLocked == false)
1214 UnLock();
1215 pixelsStale = false;
1216
1217
1218 // VISU2 "Read tile %d of the image %s\n", identifier, fatherSubImage->fatherFile->fileName.nom.Texte() FIN
1219
1220 return (FPX_OK);
1221 }
1222
1223
1224
1225 // --------------------------------------------------------------------------
1226 // This method makes a version of the raw pixels which is padded on all four
1227 // sides by 'padLen'. If there are neighboring tiles, then the pad data is
1228 // obtained from them. If this is an edge tile, then the padding is made by
1229 // pixel replication (as per the FlashPix specification).
1230 // NOTE: This code assumes that 'padLen' is never greater than the width of a
1231 // full tile (which is currently 64x64 Pixels). RIght & bottom edge conditions
1232 // are handled properly for neighboring tiles which are not full-size.
1233 //
makePaddedRawPixels(long padLen,Pixel ** paddedRawPixels)1234 FPXStatus PTileFlashPix::makePaddedRawPixels (long padLen, Pixel **paddedRawPixels)
1235 {
1236 long x, y;
1237 Pixel *srcP, *dstP;
1238 long srcStride, // Source Pixel pointer increment
1239 padWidth, // Width (in Pixels) of padded tile being filled
1240 srcCnt, // # of rows or cols source tile can contribute
1241 numTiles, // Number of tiles in this resolution
1242 neighborID; // (zero-based) identifier of a tile
1243 PTileFlashPix *tileArr, // Tile list for this resolution
1244 *srcTile; // Neighboring tile for padding source
1245 Boolean wasLocked;
1246 FPXStatus status = FPX_OK;
1247
1248 wasLocked = IsLocked(); // Remember if this tile was initially locked
1249 Lock(); // Lock this tile so it's 'rawPixels' memory
1250 // does not get re-allocated
1251
1252 FastAllocArray( *paddedRawPixels, Pixel, (width + (2 * padLen)) * (height + (2 * padLen)));
1253 if (*paddedRawPixels == NULL) {
1254 status = FPX_MEMORY_ALLOCATION_FAILED;
1255 goto RETURN;
1256 }
1257
1258 padWidth = width + (2L * padLen);
1259 tileArr = (PTileFlashPix*)fatherSubImage->tiles;
1260 numTiles = fatherSubImage->nbTilesW * fatherSubImage->nbTilesH;
1261
1262
1263 // Surrounding tile positions for notes: |0|1|2|
1264 // |3|x|4|
1265 // |5|6|7|
1266 // where 'x' is the position of the tile to be padded.
1267
1268 // ------------------ Do top pad fill -- Position [1]
1269 neighborID = identifier - fatherSubImage->nbTilesW;
1270 if( neighborID >= 0) { // If there is a neighboring tile above
1271
1272 srcTile = tileArr + neighborID; // Get it's address
1273 if( srcTile == NULL) // If the tile doesn't exist
1274 return FPX_ERROR; // then we're in big trouble
1275 srcTile->TouchRawPixelsBuffer( ); // Set access time stamp
1276 srcP = srcTile->rawPixels; // Get the address of it's raw pixels
1277
1278 if( srcP == NULL) { // If there aren't any raw pixels in memory
1279 if( (status = srcTile->ReadRawPixels()) != FPX_OK) // Read-in neighbor tile's raw pixels
1280 return status;
1281 srcP = srcTile->rawPixels;
1282 }
1283 // Calc where the desired data is located in the source tile and set the read increment
1284 // to be a full line of pixels
1285 srcP += ((srcTile->height - padLen) * srcTile->width);
1286 srcStride = srcTile->width;
1287 }
1288 else { // Else there is no neighbor tile above,
1289 srcP = rawPixels; // so just point to the top line of the target tile
1290 srcStride = 0; // and set increment to 0 se we keep copying the
1291 } // same line over and over to form padding
1292
1293 dstP = *paddedRawPixels + padLen; // Skip over left pad area of destination buffer
1294 for( y = 0; y < padLen; y++) { // and copy data into it
1295 memcpy( dstP, srcP, width * sizeof(Pixel) );
1296 srcP += srcStride;
1297 dstP += padWidth;
1298 }
1299
1300 // ------------------ Copy source into center of padded dest -- Position [x]
1301 srcP = rawPixels; // Copy from the stored raw pixels
1302 srcStride = width;
1303 dstP = *paddedRawPixels + (padWidth * padLen) + padLen;
1304 for( y = 0; y < height; y++) {
1305 memcpy( dstP, srcP, width * sizeof(Pixel) );
1306 srcP += srcStride;
1307 dstP += padWidth;
1308 }
1309
1310 // ------------------ Do bottom pad fill -- Position [6]
1311 dstP = *paddedRawPixels + ((height + padLen) * padWidth) + padLen;
1312 neighborID = identifier + fatherSubImage->nbTilesW;
1313
1314 if( neighborID < numTiles) { // If there is a neighboring tile below
1315
1316 srcTile = tileArr + neighborID; // Get it's address
1317 if( srcTile == NULL) // If the tile doesn't exist
1318 return FPX_ERROR; // then we're in big trouble
1319 srcTile->TouchRawPixelsBuffer( ); // Set access time stamp
1320 srcP = srcTile->rawPixels; // Get the address of it's raw pixels
1321
1322 if( srcP == NULL) { // If there aren't any raw pixels in memory
1323 if( (status = srcTile->ReadRawPixels()) != FPX_OK) // Read-in neighbor tile's raw pixels
1324 return status;
1325 srcP = srcTile->rawPixels;
1326 }
1327 srcStride = srcTile->width;
1328 srcCnt = srcTile->height;
1329 }
1330 else { // No tile below. Replicate last line of tile.
1331 srcP = dstP - padWidth; // Back one line's length from destination Pixel
1332 srcStride = 0; // Never really used for this case
1333 srcCnt = 0; // Set to 0 so that srcP does not get incremented
1334 }
1335
1336 for( y = 0; y < padLen; y++) {
1337 memcpy( dstP, srcP, width * sizeof(Pixel) );
1338 dstP += padWidth;
1339 srcCnt--;
1340 if( srcCnt > 0)
1341 srcP += srcStride;
1342 }
1343
1344
1345 // ------------------ Start left fills
1346 if( (identifier % fatherSubImage->nbTilesW) == 0) {
1347 // ------------- Do left fills -- Positions [0], [3] and [5]
1348 // The tile being padded is at the left edge, so all we have to do is to copy/extend
1349 // the leftmost pixels that have already been loaded into the padded buffer to fill
1350 // the pad area along the left side.
1351 dstP = *paddedRawPixels; // 1st pixel in buffer
1352 for (y = 0; y < height + (2L * padLen); y++) {
1353 srcP = dstP + padLen; // 1st pixel in line copied from src
1354 for (x = 0; x < padLen; x++)
1355 *dstP++ = *srcP;
1356 dstP += (padWidth - padLen); // 1st pixel in line
1357 }
1358 }
1359 else {
1360 // -------------- Do left-top fill -- Position [0]
1361 dstP = *paddedRawPixels; // Start at top-left of destination buffer
1362 neighborID = identifier - fatherSubImage->nbTilesW - 1;
1363 if( neighborID >= 0) { // If there is a neighboring tile above
1364
1365 srcTile = tileArr + neighborID; // Get it's address
1366 if( srcTile == NULL) // If the tile doesn't exist
1367 return FPX_ERROR; // then we're in big trouble
1368 srcTile->TouchRawPixelsBuffer( ); // Set access time stamp
1369 srcP = srcTile->rawPixels; // Get the address of it's raw pixels
1370
1371 if( srcP == NULL) { // If there aren't any raw pixels in memory
1372 if( (status = srcTile->ReadRawPixels()) != FPX_OK) // Read-in neighbor tile's raw pixels
1373 return status;
1374 srcP = srcTile->rawPixels;
1375 }
1376 // Calc where the desired data is located in the source tile and set the read increment
1377 // to be a full line of pixels
1378 srcP += ((srcTile->height - padLen) * srcTile->width);
1379 srcP += (srcTile->width - padLen);
1380 srcStride = srcTile->width - padLen;
1381
1382 // Copy the data over
1383 for( y = 0; y < padLen; y++) {
1384 for (x = 0; x < padLen; x++)
1385 *dstP++ = *srcP++;
1386 srcP += srcStride;
1387 dstP += padWidth - padLen;
1388 }
1389 }
1390 else {
1391 // There is no neighbor tile above and to the left. All we can do is replicate the
1392 // top-left pixel of the target tile to fill this area.
1393 srcP = rawPixels; // so just point to the top line of the target tile
1394 for( y = 0; y < padLen; y++) {
1395 for( x = 0; x < padLen; x++)
1396 *dstP++ = *srcP;
1397 dstP += (padWidth - padLen);
1398 }
1399 }
1400
1401 // -------------- Do left-middle fill -- Position [3]
1402 dstP = *paddedRawPixels + (padWidth * padLen);
1403 neighborID = identifier - 1;
1404
1405 srcTile = tileArr + neighborID; // Get it's address
1406 if( srcTile == NULL) // If the tile doesn't exist
1407 return FPX_ERROR; // then we're in big trouble
1408 srcTile->TouchRawPixelsBuffer( ); // Set access time stamp
1409 srcP = srcTile->rawPixels; // Get the address of it's raw pixels
1410
1411 if( srcP == NULL) { // If there aren't any raw pixels in memory
1412 if( (status = srcTile->ReadRawPixels()) != FPX_OK) // Read-in neighbor tile's raw pixels
1413 return status;
1414 srcP = srcTile->rawPixels;
1415 }
1416 // Calc where the desired data is located in the source tile and set the read increment
1417 // to be a full line of pixels
1418 srcP += (srcTile->width - padLen);
1419 srcStride = srcTile->width - padLen;
1420
1421 // Copy the data over
1422 for( y = 0; y < height; y++) {
1423 for (x = 0; x < padLen; x++)
1424 *dstP++ = *srcP++;
1425 srcP += srcStride;
1426 dstP += (padWidth - padLen);
1427 }
1428
1429 // -------------- Do left-bottom fill -- Position [5]
1430 dstP = *paddedRawPixels + ((height + padLen) * padWidth);
1431 neighborID = identifier + (fatherSubImage->nbTilesW - 1);
1432
1433 if( neighborID < numTiles) { // If there is a neighboring tile below
1434
1435 srcTile = tileArr + neighborID; // Get it's address
1436 if( srcTile == NULL) // If the tile doesn't exist
1437 return FPX_ERROR; // then we're in big trouble
1438 srcTile->TouchRawPixelsBuffer( ); // Set access time stamp
1439 srcP = srcTile->rawPixels; // Get the address of it's raw pixels
1440
1441 if( srcP == NULL) { // If there aren't any raw pixels in memory
1442 if( (status = srcTile->ReadRawPixels()) != FPX_OK) // Read-in neighbor tile's raw pixels
1443 return status;
1444 srcP = srcTile->rawPixels;
1445 }
1446 srcP += (srcTile->width - padLen);
1447 srcStride = srcTile->width - padLen;
1448 srcCnt = srcTile->height;
1449 for( y = 0; y < padLen; y++) {
1450 for (x = 0; x < padLen; x++)
1451 *dstP++ = *srcP++;
1452 dstP += (padWidth - padLen);
1453 srcCnt--;
1454 if( srcCnt > 0) // If there are more lines of src data
1455 srcP += srcStride; // advance to next src line
1456 else // Else
1457 srcP -= padLen; // Move back and replicate last line
1458 }
1459 }
1460 else { // No tile below. Replicate last pixel
1461 srcP = dstP - padWidth; // of last line of target
1462 for( y = 0; y < padLen; y++) {
1463 for (x = 0; x < padLen; x++)
1464 *dstP++ = *srcP;
1465 dstP += (padWidth - padLen);
1466 }
1467 }
1468
1469 }
1470
1471
1472 // ------------------ Start right fills
1473 if( ((identifier + 1) % fatherSubImage->nbTilesW) == 0) {
1474 // ------------- Do right fills -- Positions [2], [4] and [7]
1475 // The tile being padded is at the right edge, so all we have to do is to copy/extend
1476 // the rightmost pixels that have already been loaded into the padded buffer to fill
1477 // the pad area along the right side.
1478 dstP = *paddedRawPixels + padWidth - padLen;
1479 for (y = 0; y < height + (2L * padLen); y++) {
1480 srcP = dstP - 1;
1481 for (x = 0; x < padLen; x++)
1482 *dstP++ = *srcP;
1483 dstP += (padWidth - padLen);
1484 }
1485 }
1486 else {
1487 // The tiles to the right may not be as wide as 'padLen'. So the next 2 sections will
1488 // copy whatever piel data is available. At the end of this section the rightmost
1489 // pixels in the padded buffer will be replicated, if need be, to fill the remainder.
1490 long srcLen = padLen;
1491
1492 // -------------- Do right-top fill -- Position [2]
1493 dstP = *paddedRawPixels + (padLen + width);
1494 neighborID = identifier - fatherSubImage->nbTilesW + 1;
1495 if( neighborID >= 0) { // If there is a neighboring tile above
1496
1497 srcTile = tileArr + neighborID; // Get it's address
1498 if( srcTile == NULL) // If the tile doesn't exist
1499 return FPX_ERROR; // then we're in big trouble
1500 srcTile->TouchRawPixelsBuffer( ); // Set access time stamp
1501 srcP = srcTile->rawPixels; // Get the address of it's raw pixels
1502
1503 if( srcP == NULL) { // If there aren't any raw pixels in memory
1504 if( (status = srcTile->ReadRawPixels()) != FPX_OK) // Read-in neighbor tile's raw pixels
1505 return status;
1506 srcP = srcTile->rawPixels;
1507 }
1508
1509 srcP += ((srcTile->height - padLen) * srcTile->width);
1510 if( srcLen > srcTile->width)
1511 srcLen = srcTile->width;
1512 srcStride = srcTile->width - srcLen;
1513
1514 // Copy the data over
1515 for( y = 0; y < padLen; y++) {
1516 for( x = 0; x < srcLen; x++)
1517 *dstP++ = *srcP++;
1518 srcP += srcStride;
1519 dstP += (padWidth - srcLen);
1520 }
1521 }
1522 else {
1523 // There is no neighbor tile above and to the right. All we can do is replicate the
1524 // top-right pixel of the target tile to fill this area.
1525 srcP = rawPixels + (width - 1); // Point to last pixel of top source line tile
1526 for( y = 0; y < padLen; y++) {
1527 for( x = 0; x < padLen; x++)
1528 *dstP++ = *srcP;
1529 dstP += (padWidth - padLen);
1530 }
1531 }
1532
1533 // -------------- Do right-middle fill -- Position [4]
1534 dstP = *paddedRawPixels + (padLen * padWidth) + width + padLen;
1535 neighborID = identifier + 1;
1536
1537 srcTile = tileArr + neighborID; // Get it's address
1538 if( srcTile == NULL) // If the tile doesn't exist
1539 return FPX_ERROR; // then we're in big trouble
1540 srcTile->TouchRawPixelsBuffer( ); // Set access time stamp
1541 srcP = srcTile->rawPixels; // Get the address of it's raw pixels
1542
1543 if( srcP == NULL) { // If there aren't any raw pixels in memory
1544 if( (status = srcTile->ReadRawPixels()) != FPX_OK) // Read-in neighbor tile's raw pixels
1545 return status;
1546 srcP = srcTile->rawPixels;
1547 }
1548
1549 if( srcLen > srcTile->width)
1550 srcLen = srcTile->width;
1551 srcStride = srcTile->width - srcLen;
1552
1553 // Copy the data over
1554 for( y = 0; y < height; y++) {
1555 for( x = 0; x < srcLen; x++)
1556 *dstP++ = *srcP++;
1557 srcP += srcStride;
1558 dstP += (padWidth - srcLen);
1559 }
1560
1561 // -------------- Do right-bottom fill -- Position [7]
1562 dstP = *paddedRawPixels + ((height + padLen) * padWidth) + padLen + width;
1563 neighborID = identifier + fatherSubImage->nbTilesW + 1;
1564 if( neighborID < numTiles) { // If there is a neighboring tile above
1565
1566 srcTile = tileArr + neighborID; // Get it's address
1567 if( srcTile == NULL) // If the tile doesn't exist
1568 return FPX_ERROR; // then we're in big trouble
1569 srcTile->TouchRawPixelsBuffer( ); // Set access time stamp
1570 srcP = srcTile->rawPixels; // Get the address of it's raw pixels
1571
1572 if( srcP == NULL) { // If there aren't any raw pixels in memory
1573 if( (status = srcTile->ReadRawPixels()) != FPX_OK) // Read-in neighbor tile's raw pixels
1574 return status;
1575 srcP = srcTile->rawPixels;
1576 }
1577
1578 if( srcLen > srcTile->width)
1579 srcLen = srcTile->width;
1580 srcStride = srcTile->width - srcLen;
1581
1582 // Copy the data over
1583 for( y = 0; y < padLen; y++) {
1584 for( x = 0; x < srcLen; x++)
1585 *dstP++ = *srcP++;
1586 srcP += srcStride;
1587 dstP += (padWidth - srcLen);
1588 }
1589 }
1590 else {
1591 // There is no neighbor tile below and to the right. All we can do is replicate the
1592 // bottom-right pixel of the target tile to fill this area.
1593 srcP = rawPixels + (width * height)- 1; // Point to last pixel of last source line tile
1594 for( y = 0; y < padLen; y++) {
1595 for( x = 0; x < srcLen; x++) // only need to copy 'srcLen' here
1596 *dstP++ = *srcP;
1597 dstP += (padWidth - srcLen);
1598 }
1599 }
1600
1601 // As promised, if there was insufficient pixels in the tiles on the right, then
1602 // some replication must be performed to fill the remaining pad area on the right.
1603 if( srcLen != padLen) {
1604 padLen -= srcLen;
1605 dstP = *paddedRawPixels + (padWidth - padLen);
1606 for (y = 0; y < height + (2L * padLen); y++) {
1607 srcP = dstP - 1;
1608 for (x = 0; x < padLen; x++)
1609 *dstP++ = *srcP;
1610 dstP += (padWidth - padLen);
1611 }
1612 }
1613 }
1614
1615 RETURN:
1616 if (wasLocked == false)
1617 UnLock();
1618 return status;
1619 }
1620
1621
1622 // ------------------------------------------------------------------------------
1623 // Read jpeg header from image content property set
1624 //
ReadHeader(PFlashPixFile * filePtr,unsigned char ** pJpegHeader,unsigned long * headerSize)1625 Boolean PTileFlashPix::ReadHeader(PFlashPixFile* filePtr, unsigned char** pJpegHeader,
1626 unsigned long* headerSize )
1627 {
1628 OLEProperty* aProp;
1629 OLEBlob jpegTable;
1630
1631
1632 // Get jpeg table index
1633 unsigned char JPEGtableSelector = GET_JPEGTablesIndex(compressionSubtype);
1634
1635 // Convert the index into property ID for jpeg table
1636 unsigned long PID_jpegTableIndex = PID_JPEGTables(JPEGtableSelector);
1637
1638 // If jpeg table index is 0, then the header is stored with tile data
1639 if ( !JPEGtableSelector )
1640 return TRUE;
1641
1642 // If no jpeg table for this resolution, read it from image content property set
1643 if ( !*pJpegHeader ) {
1644
1645 // Find the jpeg table specified by JPEGtableSelector in the image content property set
1646 if (filePtr->GetImageContentProperty (PID_jpegTableIndex, &aProp)) {
1647
1648 // Get the jpeg table
1649 if ( !(jpegTable = (BLOB *)(*aProp)) )
1650 return FALSE;
1651
1652 *headerSize = jpegTable.ReadVT_VECTOR(pJpegHeader);
1653
1654 // Set the table index and flag
1655 ((PResolutionFlashPix*)fatherSubImage)->compressTableGroup = JPEGtableSelector;
1656 }
1657 else
1658 return FALSE;
1659 }
1660 else
1661 // If table index is different from this resolution, read it from image content property set
1662 if ( JPEGtableSelector != ((PResolutionFlashPix*)fatherSubImage)->compressTableGroup ) {
1663
1664 // Delete header if it already exists
1665 delete *pJpegHeader;
1666
1667 // Find the jpeg table specified by JPEGtableSelector in the image content property set
1668
1669 if (filePtr->GetImageContentProperty (PID_jpegTableIndex, &aProp)) {
1670
1671 // Get the jpeg table
1672 if ( !(jpegTable = (BLOB *)(*aProp)) )
1673 return FALSE;
1674
1675 *headerSize = jpegTable.ReadVT_VECTOR(pJpegHeader);
1676 }
1677 else
1678 return FALSE;
1679
1680 // Set the jpeg table index for this resolution
1681 ((PResolutionFlashPix*)fatherSubImage)->compressTableGroup = JPEGtableSelector;
1682 }
1683 return TRUE;
1684 }
1685
1686
1687 // ------------------------------------------------------------------------------
1688 // Write jpeg table to image content property set.
1689 //
WriteHeader(PFlashPixFile * filePtr,unsigned char * jpegHeader,unsigned long headerSize)1690 Boolean PTileFlashPix::WriteHeader(PFlashPixFile* filePtr,
1691 unsigned char* jpegHeader,
1692 unsigned long headerSize )
1693 {
1694 OLEProperty* aProp;
1695 OLEBlob jpegTable;
1696
1697 // Get jpeg table index.
1698 // compressTableGroup is type unsigned char so it has a range of 0 - 255
1699 unsigned char JPEGtableSelector = ((PResolutionFlashPix*)fatherSubImage)->compressTableGroup;
1700
1701 // If jpeg table index is 0, then the header is stored with tile data
1702 if ( !JPEGtableSelector )
1703 return true;
1704
1705 // Convert the index into property ID for jpeg table
1706 unsigned long PID_jpegTableIndex = PID_JPEGTables(JPEGtableSelector);
1707
1708 // If jpeg table for this index doesn't exist, write it
1709 if ( !filePtr->GetImageContentProperty (PID_jpegTableIndex, &aProp) ) {
1710
1711 // Copy the stream in jpeg table into blob
1712 jpegTable.WriteVT_VECTOR(jpegHeader, headerSize);
1713
1714 // Save the jpeg table into image content property set
1715 if (filePtr->SetImageContentProperty (PID_jpegTableIndex, TYP_JPEGTables, &aProp)) {
1716 *aProp = jpegTable.GetBlob();
1717 }
1718 else
1719 return false;
1720
1721 // Save the maximum jpeg table index
1722 if ( !filePtr->GetImageContentProperty (PID_MaxJPEGTables, &aProp) )
1723 if (filePtr->SetImageContentProperty (PID_MaxJPEGTables, TYP_MaxJPEGTables, &aProp))
1724 *aProp = (int32_t)JPEGtableSelector;
1725 else
1726 return false;
1727 else {
1728 int32_t tempMaxIndex = (int32_t)(*aProp);
1729 tempMaxIndex = (tempMaxIndex < JPEGtableSelector) ? JPEGtableSelector : tempMaxIndex;
1730 *aProp = (int32_t)tempMaxIndex;
1731 }
1732 filePtr->Commit();
1733 }
1734 return true;
1735 }
1736
1737
1738 // ------------------------------------------------------------------------------
1739 // Does contrast correction
1740 // Note that if there is an opacity component, this routine assumes that the
1741 // other components have been pre-multiplied. In this case, the output of the
1742 // non-opacity component(s) is clamped to opacity. A more proper method would
1743 // be to reconstruct the original, non-premultiplied component(s) by multiplying
1744 // by the reciprocal of opacity, then performing the contrast adjustment and
1745 // then re-applying the opacity. This is not done here dur to the additional
1746 // multiplies that are required.
1747 // Note that contrast is not (and should not be) applied to the opacity channel.
1748 //
Contrast(double k,FPXBaselineColorSpace colorSpace,Pixel * pixels,long count)1749 FPXStatus PTileFlashPix::Contrast (
1750 double k, // Contrast factor (e.g. 1.2 = +20%contrast)
1751 FPXBaselineColorSpace colorSpace, // Which channels are which?
1752 Pixel *pixels, // array of 32-bit pixels
1753 long count ) // No. of pixels in array
1754 {
1755 unsigned char *lookup;
1756 unsigned char *red_pixel, *green_pixel, *blue_pixel, *opac_pixel;
1757 FPXBaselineColorSpace tempSpace;
1758 Boolean monochrome;
1759
1760
1761 // Set up lookup table, if need be
1762 if (gContrastVal != k) {
1763 double p = (float)0.43; // Center of contrast spread, per FPX specification
1764 double contrasted;
1765 int i;
1766
1767 for (i = 0; i < 256; i++) {
1768 contrasted = p * pow( ((double)i / 256.0) / p, k);
1769 if (contrasted >= 1.0)
1770 contrasted = (float)0.999; // Truncate to 0... 255
1771 gContrastLut[i] = (unsigned char)(contrasted * 256.0);
1772 }
1773 gContrastVal = (Boolean)k;
1774 }
1775 lookup = gContrastLut;
1776
1777 // Determine channel #'s in color space
1778 // Alpha channel is not contrasted, but if present it's address is loaded for
1779 // use in clipping later.
1780 // Note that the 'red_pixel' pointer is used for a monochrome component
1781 opac_pixel = 0;
1782 tempSpace = colorSpace;
1783 switch(pixelsSpace) {
1784 case SPACE_32_BITS_ARGB: // The 24 bits are stored in the LSB part of the long
1785 opac_pixel = ((unsigned char*)pixels);
1786 case SPACE_32_BITS_RGB: {
1787 red_pixel = ((unsigned char*)pixels) + 1;
1788 green_pixel = ((unsigned char*)pixels) + 2;
1789 blue_pixel = ((unsigned char*)pixels) + 3;
1790 monochrome = false;
1791 } break;
1792
1793 case SPACE_32_BITS_RGBA: {
1794 red_pixel = ((unsigned char*)pixels);
1795 green_pixel = ((unsigned char*)pixels) + 1;
1796 blue_pixel = ((unsigned char*)pixels) + 2;
1797 opac_pixel = ((unsigned char*)pixels) + 3;
1798 monochrome = false;
1799 } break;
1800
1801 case SPACE_32_BITS_AM:
1802 opac_pixel = ((unsigned char*)pixels) + 2;
1803 case SPACE_32_BITS_M: {
1804 red_pixel = ((unsigned char*)pixels) + 3;
1805 monochrome = true;
1806 } break;
1807
1808 case SPACE_32_BITS_MA: {
1809 red_pixel = ((unsigned char*)pixels) + 2;
1810 opac_pixel = ((unsigned char*)pixels) + 3;
1811 monochrome = true;
1812 } break;
1813
1814 case SPACE_32_BITS_AYCC:
1815 opac_pixel = ((unsigned char*)pixels);
1816 case SPACE_32_BITS_YCC: {
1817 tempSpace = SPACE_32_BITS_ARGB;
1818 red_pixel = ((unsigned char*)pixels) + 1;
1819 green_pixel = ((unsigned char*)pixels) + 2;
1820 blue_pixel = ((unsigned char*)pixels) + 3;
1821 monochrome = false;
1822 } break;
1823
1824 case SPACE_32_BITS_YCCA: {
1825 tempSpace = SPACE_32_BITS_RGBA;
1826 red_pixel = ((unsigned char*)pixels);
1827 green_pixel = ((unsigned char*)pixels) + 1;
1828 blue_pixel = ((unsigned char*)pixels) + 2;
1829 opac_pixel = ((unsigned char*)pixels) + 3;
1830 monochrome = false;
1831 } break;
1832
1833 default:
1834 return FPX_COLOR_CONVERSION_ERROR; // Invalid color space
1835 }
1836
1837 // If need be, convert from 'colorSpace' into an RGB 'tempSpace'
1838 if (tempSpace != colorSpace)
1839 ConvertPixelBuffer((unsigned char*)(pixels), width * height, colorSpace, tempSpace);
1840
1841 if (monochrome) {
1842 if (opac_pixel) { // If there is an opacity
1843 while (count--) { // component, then the new
1844 *red_pixel = lookup[*red_pixel]; // mono value must be clipped
1845 if (*red_pixel > *opac_pixel)
1846 *red_pixel = *opac_pixel;
1847 red_pixel += 4;
1848 opac_pixel += 4;
1849 }
1850 } else {
1851 while (count--) { // If there is no opacity
1852 *red_pixel = lookup[*red_pixel]; // component, then just blast
1853 red_pixel += 4; // through
1854 }
1855 }
1856 } else { // RGB
1857 if (opac_pixel) { // If there is an opacity
1858 while (count--) { // values must be clipped to it
1859 *red_pixel = lookup[ *red_pixel];
1860 if (*red_pixel > *opac_pixel)
1861 *red_pixel = *opac_pixel;
1862 *green_pixel = lookup[*green_pixel];
1863 if (*green_pixel > *opac_pixel)
1864 *green_pixel = *opac_pixel;
1865 *blue_pixel = lookup[ *blue_pixel];
1866 if (*blue_pixel > *opac_pixel)
1867 *blue_pixel = *opac_pixel;
1868
1869 red_pixel += 4;
1870 green_pixel += 4;
1871 blue_pixel += 4;
1872 opac_pixel += 4;
1873 }
1874 } else {
1875 while (count--) { // If there is no opacity
1876 *red_pixel = lookup[ *red_pixel];// no clipping is required
1877 *green_pixel = lookup[*green_pixel];
1878 *blue_pixel = lookup[ *blue_pixel];
1879
1880 red_pixel += 4;
1881 green_pixel += 4;
1882 blue_pixel += 4;
1883 }
1884 }
1885 }
1886
1887 // If need be, convert from an RGB 'tempSpace' back into 'colorSpace'
1888 if (tempSpace != colorSpace)
1889 ConvertPixelBuffer((unsigned char*)(pixels), width * height, tempSpace, colorSpace);
1890
1891 return FPX_OK;
1892 }
1893
1894
1895 // ----------------------------------------------------------------------------
1896 // External Functions
1897 // ----------------------------------------------------------------------------
1898
1899
1900 // - EOF ----------------------------------------------------------------------
1901
1902