1 //  ----------------------------------------------------------------------------
2 //  MODULE    : PResolutionFlashPix
3 //  LANGUAGE  : C++
4 //  CREATOR   : Philippe BOSSUT
5 //  CREAT. DATE : Wednesday, March 20, 1996
6 //  DESCRIPTION :
7 //  COMMENTS  :
8 //      SCCSID          : @(#)pres_fpx.cpp  1.6 13:18:52 02 Jun 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 "pres_fpx.h"
17 //  ----------------------------------------------------------------------------
18 
19 //  Includes
20 //  --------
21 
22   #include  <string.h>
23   #include  <stdio.h>
24 
25 #if defined(USE_LEGACY_INCLUDES)
26 #  include <fstream.h>
27 #else
28 #  include <fstream>
29    using namespace std;
30 #endif
31 
32 #ifdef macintosh
33   #include  <Errors.h>
34 #endif
35 #ifndef Couleur_h
36   #include  "fpx_color.h"
37 #endif
38 #ifndef Numbers_h
39   #include  "numbers.h"
40 #endif
41 #ifndef Memoire_h
42 //include "b_memory.h"
43 #endif
44 #ifndef CorrectLut_h
45   #include  "corr_lut.h"
46 #endif
47 #ifndef Debug_h
48   #include  "debug.h"
49 #endif
50 
51 #ifndef FileFlashPixIO_h
52   #include "f_fpxio.h"
53 #endif
54 #ifndef PTileFlashPix_h
55   #include "ptil_fpx.h"
56 #endif
57 #ifndef PImageFile_h
58   #include "pimgfile.h"
59 #endif
60 #ifndef FPXBaselineIO_h
61   #include "fpxlibio.h"
62 #endif
63 #ifndef FPXBaselineView_h
64   #include "fpxlib.h"
65 #endif
66 
67 
68 
69 #ifndef OLECommun_h
70   #include "olecomm.h"
71 #endif
72 #ifndef OLECore_h
73   #include "olecore.h"
74 #endif
75 #ifndef OLEStorages_h
76   #include  "olestorg.h"
77 #endif
78 #ifndef OLEHeaderStream_h
79   #include  "olehstrm.h"
80 #endif
81 #ifndef OLEProperties_h
82   #include  "oleprop.h"
83 #endif
84 #ifndef OLEPropertySet_h
85   #include  "oleprops.h"
86 #endif
87 #ifndef OLEFiles_h
88   #include  "olefiles.h"
89 #endif
90 
91 #ifndef FlashPixUtils_h
92   #include "fpxutils.h"
93 #endif
94 #ifndef FlashPixFormat_h
95   #include "fpxformt.h"
96 #endif
97 
98 //  Constants
99 //  ---------
100 
101 //  Variables
102 //  ---------
103 
104 //  ----------------------------------------------------------------------------
105 //  Internal Functions
106 //  ----------------------------------------------------------------------------
107 
108 // Convert a FPXColorspace element into a Subimage color data (see FPX Spec Table III.3)
109 // CAUTION: Algorithm limited to the Baseline spec.
110 
111 
ComputeChannelColor(DWORD * channelColor,FPXColorspace colorSpace,int index)112 static void ComputeChannelColor(DWORD* channelColor, FPXColorspace colorSpace, int index)
113 {
114   // Consistency check
115   assert (index < colorSpace.numberOfComponents);
116 
117   // Default color space value: this works only in the Baseline environment with the
118   // hypothesis that only Baseline compliant colorspace are given in parameter.
119   TypColorSpace space = ColorSpace_Colorless;
120   TypColor color = Color_Unspecified;
121 
122   // Determine the kind of color space coded in colorSpace
123   for (int i = 0; i < colorSpace.numberOfComponents; i++) {
124     switch (colorSpace.theComponents[i].myColor) {
125       case PHOTO_YCC_Y:
126         space = ColorSpace_PhotoYCC;
127         break;
128       case NIFRGB_R:
129         space = ColorSpace_NifRGB;
130         break;
131       case MONOCHROME:
132         space = ColorSpace_Monochrome;
133         break;
134     default:
135       {
136       }
137     }
138   }
139 
140   // Determine the color component coded in colorSpace.theComponents[index]
141   switch (colorSpace.theComponents[index].myColor) {
142     case PHOTO_YCC_Y:
143       color = Color_PhotoYCC_Y;
144       break;
145     case PHOTO_YCC_C1:
146       color = Color_PhotoYCC_C1;
147       break;
148     case PHOTO_YCC_C2:
149       color = Color_PhotoYCC_C2;
150       break;
151     case NIFRGB_R:
152       color = Color_Red;
153       break;
154     case NIFRGB_G:
155       color = Color_Green;
156       break;
157     case NIFRGB_B:
158       color = Color_Blue;
159       break;
160     case ALPHA:
161       color = Color_Opacity;
162       break;
163     case MONOCHROME:
164       color = Color_Monochrome;
165       break;
166   }
167 
168   // Build the color space subfield value
169   *channelColor = MakeColorSpec(space,color);
170 
171   // Handle the calibrated/uncalibrated flag
172   if (colorSpace.isUncalibrated)
173     SetUncalibrated(*channelColor);
174   else
175     UnsetUncalibrated(*channelColor);
176 }
177 
178 
179 //  ----------------------------------------------------------------------------
180 // Convert Subimage color data into a FPXColorspace element
181 // CAUTION: Algorithm limited to the Baseline spec.
AnalyseChannelColor(DWORD channelColor,FPXColorspace * colorSpace,int index)182 static void AnalyseChannelColor(DWORD channelColor, FPXColorspace* colorSpace, int index)
183 {
184   // Check the calibrated/uncalibrated bit
185   if (IsUncalibrated(channelColor))
186     colorSpace->isUncalibrated = TRUE;
187   else
188     colorSpace->isUncalibrated = FALSE;
189 
190   // Unset the flag bits
191   UnsetPremultiplied(channelColor);
192   UnsetUncalibrated(channelColor);
193 
194   // Analyse the color space according to Baseline rules. See Table III.6 of the FPX spec.
195   switch (channelColor) {
196     case MakeColorSpec(ColorSpace_Colorless,Color_Opacity):
197       colorSpace->theComponents[index].myColor    = ALPHA;
198       colorSpace->theComponents[index].myDataType = DATA_TYPE_UNSIGNED_BYTE;
199       break;
200     case MakeColorSpec(ColorSpace_Monochrome,Color_Monochrome):
201       colorSpace->theComponents[index].myColor    = MONOCHROME;
202       colorSpace->theComponents[index].myDataType = DATA_TYPE_UNSIGNED_BYTE;
203       break;
204     case MakeColorSpec(ColorSpace_Monochrome,Color_Opacity):
205       colorSpace->theComponents[index].myColor    = ALPHA;
206       colorSpace->theComponents[index].myDataType = DATA_TYPE_UNSIGNED_BYTE;
207       break;
208     case MakeColorSpec(ColorSpace_PhotoYCC,Color_PhotoYCC_Y):
209       colorSpace->theComponents[index].myColor    = PHOTO_YCC_Y;
210       colorSpace->theComponents[index].myDataType = DATA_TYPE_UNSIGNED_BYTE;
211       break;
212     case MakeColorSpec(ColorSpace_PhotoYCC,Color_PhotoYCC_C1):
213       colorSpace->theComponents[index].myColor    = PHOTO_YCC_C1;
214       colorSpace->theComponents[index].myDataType = DATA_TYPE_UNSIGNED_BYTE;
215       break;
216     case MakeColorSpec(ColorSpace_PhotoYCC,Color_PhotoYCC_C2):
217       colorSpace->theComponents[index].myColor    = PHOTO_YCC_C2;
218       colorSpace->theComponents[index].myDataType = DATA_TYPE_UNSIGNED_BYTE;
219       break;
220     case MakeColorSpec(ColorSpace_PhotoYCC,Color_Opacity):
221       colorSpace->theComponents[index].myColor    = ALPHA;
222       colorSpace->theComponents[index].myDataType = DATA_TYPE_UNSIGNED_BYTE;
223       break;
224     case MakeColorSpec(ColorSpace_RGB,Color_Red):   // treat unspecified RGB just like NIF RGB
225     case MakeColorSpec(ColorSpace_NifRGB,Color_Red):
226       colorSpace->theComponents[index].myColor    = NIFRGB_R;
227       colorSpace->theComponents[index].myDataType = DATA_TYPE_UNSIGNED_BYTE;
228       break;
229     case MakeColorSpec(ColorSpace_RGB,Color_Green):   // treat unspecified RGB just like NIF RGB
230     case MakeColorSpec(ColorSpace_NifRGB,Color_Green):
231       colorSpace->theComponents[index].myColor    = NIFRGB_G;
232       colorSpace->theComponents[index].myDataType = DATA_TYPE_UNSIGNED_BYTE;
233       break;
234     case MakeColorSpec(ColorSpace_RGB,Color_Blue):    // treat unspecified RGB just like NIF RGB
235     case MakeColorSpec(ColorSpace_NifRGB,Color_Blue):
236       colorSpace->theComponents[index].myColor    = NIFRGB_B;
237       colorSpace->theComponents[index].myDataType = DATA_TYPE_UNSIGNED_BYTE;
238       break;
239     case MakeColorSpec(ColorSpace_RGB,Color_Opacity): // treat unspecified RGB just like NIF RGB
240     case MakeColorSpec(ColorSpace_NifRGB,Color_Opacity):
241       colorSpace->theComponents[index].myColor    = ALPHA;
242       colorSpace->theComponents[index].myDataType = DATA_TYPE_UNSIGNED_BYTE;
243       break;
244     default:
245       assert(false);
246       break;
247   }
248 }
249 
250 //  ----------------------------------------------------------------------------
251 //  Member Functions
252 //  ----------------------------------------------------------------------------
253 
254 //  ----------------------------------------------------------------------------
255 //  Methods of the PResolutionFlashPix class : this is the Resolution object
256 //
257 //  Manage an array on PTileFlashPix objects which contain pixels
258 //  Each PResolutionFlashPix points to the next which has a resolution 1/4.
259 //  ----------------------------------------------------------------------------
260 
261 // Initialize resolution information and create the next sub-image
262 // Use this constructor in Read or Write mode
PResolutionFlashPix(PHierarchicalImage * father,int * offset,int id)263 PResolutionFlashPix::PResolutionFlashPix (PHierarchicalImage* father, int* offset, int id) :
264 PResolutionLevel (father, offset, id)
265 {
266   Init();
267 }
268 
269 
270 //  ----------------------------------------------------------------------------
271 // Initialize resolution information and create the next sub-image
272 // Use this constructor in Create mode
PResolutionFlashPix(PHierarchicalImage * father,int width,int height,int * whatImage)273 PResolutionFlashPix::PResolutionFlashPix (PHierarchicalImage* father, int width, int height, int* whatImage) :
274 PResolutionLevel (father, width, height, whatImage)
275 {
276   Init();
277 }
278 
279 
280 //  ----------------------------------------------------------------------------
281 // Clean resolution level and delete all related objects
~PResolutionFlashPix()282 PResolutionFlashPix::~PResolutionFlashPix()
283 {
284   if (tiles) {
285     delete [] tiles;
286     tiles = NULL;
287   }
288 
289   // Delete jpeg header if it exists
290   if ( jpegHeader )
291     delete[] jpegHeader;
292 
293   // CAUTION: delete streams before the storage which contain them
294   // Commit() makes sure that everything has been written on the disk (flush
295   // all ole buffers for the element) and delete releases the OLE object.
296 
297   if (subStreamHdr) {
298     subStreamHdr->Commit();
299     delete subStreamHdr;
300     subStreamHdr = NULL;
301   }
302   if (subStreamData) {
303     subStreamData->Commit();
304     delete subStreamData;
305     subStreamData = NULL;
306   }
307   if (subStorage) {
308     subStorage->Commit();
309     delete subStorage;
310     subStorage  = NULL;
311   }
312 }
313 
314 
315 //  ----------------------------------------------------------------------------
AllocTilesArray()316 FPXStatus PResolutionFlashPix::AllocTilesArray ()
317 {
318   tiles = new PTileFlashPix[nbTilesH * nbTilesW];
319   return ((tiles == NULL)? FPX_MEMORY_ALLOCATION_FAILED : FPX_OK);
320 }
321 
322 
323 //  ----------------------------------------------------------------------------
Init()324 void PResolutionFlashPix::Init ()
325 {
326   baseSpace     = ((PFileFlashPixIO*)fatherFile)->baseSpace;
327   CreateFPXColorSpace (baseSpace, &colorSpace);
328   colorSpace.isUncalibrated = ((PFileFlashPixIO*)fatherFile)->baseUncalibrated;
329   nbChannels    = colorSpace.numberOfComponents;
330   isAlpha     = IsAlphaBaseline(baseSpace);
331   premultiplied = true; // always premultiplied by default in Baseline FlashPix
332   alphaOffset   = (unsigned char) GetAlphaOffsetBaseline(baseSpace);
333   isICCprofile  = false;
334   ICCprofile    = 0;
335 
336   compression       = ((PFileFlashPixIO*)fatherFile)->FPXCompression;
337   compressionSubtype  = ((PFileFlashPixIO*)fatherFile)->FPXCompressionSubType;
338   qualityFactor     = ((PFileFlashPixIO*)fatherFile)->FPXQualityFactor;
339   compressTableGroup  = GET_JPEGTablesIndex(compressionSubtype);  // Set initial jpeg table id
340   jpegHeader      = NULL;     // Set initial jpeg table pointer to null
341   headerSize      = 0;      // Set initial jpeg table length
342 
343   subStreamHdr  = NULL;
344   subStreamData = NULL;
345   subStorage    = NULL;
346 }
347 
348 
349 //  ----------------------------------------------------------------------------
CreateHeaderStream()350 FPXStatus PResolutionFlashPix::CreateHeaderStream ()
351 {
352   // Create the Storage and the Streams to store the data
353   PFlashPixFile *fileFPX = (PFlashPixFile*)fatherFile->filePtr;
354   FPXStatus   status = FPX_OK;
355   char      resolutionName [33];
356   char      streamHdrName[33];
357   char      streamDataName[33];
358 
359   // the number associate to the resolution is the inverse than the one use internaly
360   // because in FlashPix the resolution 0 is the lowest resolution
361   GetResolutionName(resolutionName, fatherFile->nbSubImages - identifier - 1);
362 
363   // Baseline special: there is only 1 sub image level per resolution and 0 support data
364   GetSubImageHdrName(streamHdrName, 0);
365   GetSubImageDataName(streamDataName, 0);
366 
367   CLSID clsID = ID_Resolution;
368   if (fileFPX->CreateStorage (clsID, resolutionName, &subStorage)) {
369     CLSID clsID = ID_SubImageHdr;
370     if (subStorage->CreateHeaderStream (clsID, streamHdrName, &subStreamHdr)) {
371       CLSID clsID = ID_SubImageData;
372       if (subStorage->CreateHeaderStream (clsID, streamDataName, &subStreamData)) {
373         Allocation();
374       } else
375         status = FPX_FILE_CREATE_ERROR;
376     } else
377       status = FPX_FILE_CREATE_ERROR;
378   } else
379     status = FPX_FILE_CREATE_ERROR;
380 
381   // Update the number of resolution level created for this file
382   if (status == FPX_OK)
383     ((PFileFlashPixIO*)fatherFile)->nbCreatedResolutions++;
384 
385   return status;
386 }
387 
388 
389 //  ----------------------------------------------------------------------------
ReadHeaderStream()390 FPXStatus PResolutionFlashPix::ReadHeaderStream ()
391 {
392   // Open the Storage and the Streams to read or write the data
393   PFlashPixFile* fileFPX = (PFlashPixFile*)fatherFile->filePtr;
394   FPXStatus status = FPX_OK;
395   char resolutionName [33];
396   char streamHdrName[33];
397   char streamDataName[33];
398 
399   // The number associated to the resolution is the inverse than the one used internaly
400   // because in FlashPix the resolution 0 is the lowest resolution
401   GetResolutionName(resolutionName, fatherFile->nbSubImages - identifier - 1);
402 
403   // Baseline special: there is only 1 sub image level per resolution and 0 support data
404   GetSubImageHdrName(streamHdrName, 0);
405   GetSubImageDataName(streamDataName, 0);
406 
407   CLSID clsID = ID_Resolution;
408   if (fileFPX->OpenStorage (clsID, resolutionName, &subStorage)) {
409     CLSID clsID = ID_SubImageHdr;
410     if (subStorage->OpenHeaderStream (clsID, streamHdrName, &subStreamHdr)) {
411       CLSID clsID = ID_SubImageData;
412       if (subStorage->OpenHeaderStream (clsID, streamDataName, &subStreamData))
413         status = Read ();         // Create block array and read sub-image information
414       else
415         status = FPX_FILE_READ_ERROR;
416     } else
417       status = FPX_FILE_READ_ERROR;
418   } else
419     status = FPX_FILE_READ_ERROR;
420 
421   if ((status == FPX_OK) && (tiles == NULL))    // If failed, raise an error
422     status = FPX_ERROR;
423 
424   if (status)
425     imageStatus = status;
426   return status;
427 }
428 
429 
430 //  ----------------------------------------------------------------------------
UpdateHeaderStream()431 FPXStatus PResolutionFlashPix::UpdateHeaderStream ()
432 {
433   FPXStatus status = FPX_OK;
434 
435   // Try to read the header stream first
436   status = ReadHeaderStream ();
437 
438   // If failed, try to create the header stream
439   if (status != FPX_OK)
440     status = CreateHeaderStream();
441 
442   if ((status == FPX_OK) && (tiles == NULL))    // If failed, raise an error
443     status = FPX_ERROR;
444 
445   if (status)
446     imageStatus = status;
447   return status;
448 }
449 
450 
451 //  ----------------------------------------------------------------------------
GetResolutionDescription()452 FPXStatus PResolutionFlashPix::GetResolutionDescription()
453 {
454   PFlashPixFile *fileFPX = (PFlashPixFile*)fatherFile->filePtr;
455   FPXStatus     status = FPX_OK;
456   OLEProperty   *aProp;
457   int      FlashPixIdentifier = fatherFile->nbSubImages - identifier - 1;
458 
459   // SubImage pixel width (required)
460   if (fileFPX->GetImageContentProperty (PID_SubImageWidth(FlashPixIdentifier), &aProp))
461     realWidth = int(*aProp);
462   else
463     status = FPX_FILE_READ_ERROR;
464 
465   // Subimage pixel heigth (required)
466   if (fileFPX->GetImageContentProperty (PID_SubImageHeight(FlashPixIdentifier), &aProp))
467     realHeight = int(*aProp);
468   else
469     status = FPX_FILE_READ_ERROR;
470 
471   // Subimage color (required)
472   if (fileFPX->GetImageContentProperty (PID_SubImageColor(FlashPixIdentifier), &aProp)) {
473 
474     OLEBlob colorBlob((const BLOB*)(*aProp));
475     if (colorBlob.GetBlobSize()>0) {
476 
477       DWORD tmp, tmp0;
478       Boolean uncalibrated = false;
479 
480       colorBlob.ReadVT_I4(&tmp);            // Number of subimages
481       assert (tmp == 1);                // Only 1 subimage in Baseline
482 
483       colorBlob.ReadVT_I4(&tmp);            // Number of channels
484       assert (tmp <= FPX_MAX_COMPONENTS);       // Baseline limitation: RGB (or YCC) + alpha
485       colorSpace.numberOfComponents = (short)(tmp);
486       nbChannels =  (short)(tmp);
487 
488       colorBlob.ReadVT_I4(&tmp0);           // Color of channel 0
489       premultiplied = IsPremultiplied(tmp0);
490 
491       uncalibrated = IsUncalibrated(tmp0);
492       if( uncalibrated == true )
493         ((PFileFlashPixIO*)fatherFile)->SetUncalibratedFlag(uncalibrated);
494 
495       AnalyseChannelColor(tmp0,&colorSpace,0);
496       ExtractColorSpace(tmp0);
497 
498       for (int i = 1; i < colorSpace.numberOfComponents; i++) {
499         colorBlob.ReadVT_I4(&tmp);          // Color of channel i
500         AnalyseChannelColor(tmp,&colorSpace,i);
501         premultiplied |= IsPremultiplied(tmp);
502         assert ((ExtractColorSpace(tmp)) == tmp0);  // The color space part must be the same for all channels
503       // CAUTION: we don't analyse extra subimages (Baseline limitation)
504       }
505 
506       // Update the easy to use Baseline description...
507       baseSpace = AnalyseFPXColorSpace(colorSpace);
508       assert (baseSpace != NON_AUTHORIZED_SPACE);
509       isAlpha     = IsAlphaBaseline(baseSpace);
510       alphaOffset = (unsigned char) GetAlphaOffsetBaseline(baseSpace);
511     } else
512       status = FPX_FILE_READ_ERROR;
513 
514   } else
515     status = FPX_FILE_READ_ERROR;
516 
517   // Subimage numerical format (required)
518   if (fileFPX->GetImageContentProperty (PID_SubImageNumFormat(FlashPixIdentifier), &aProp)) {
519     const VECTOR *vector = (const VECTOR *)(*aProp);
520     assert (vector->cElements == 1);   // Only one subimage in Baseline
521     assert (vector->prgdw[0] == VT_UI1);  // Always 8-bit unsigned integer in Baseline
522   } else
523     status = FPX_FILE_READ_ERROR;
524 
525   // Decimation method (required)
526   if (fileFPX->GetImageContentProperty (PID_DecimationMethod(FlashPixIdentifier), &aProp)) {
527     DWORD decimation;
528     decimation = int(*aProp);
529     switch (decimation) {
530       case 0:
531         // For the high resolution level, there is no decimation and it's the only case...
532         assert (identifier == 0);
533         break;
534       case 2:           // 2x2 averaging
535         fatherFile->convolution = Convolution_Standard;
536         break;
537       case 4:           // 4x4 gaussian filter
538         fatherFile->convolution = Convolution_Gauss;
539         break;
540   //    case DecimationStandard:  // Default filter (still to be defined...)
541   //      fatherFile->convolution = Convolution_FlashPix;
542   //      break;
543       default:
544         // Not supported decimation method
545         // djk 14Apr1997 AI#18295: removed assert(false)
546         fatherFile->convolution = Convolution_Standard;
547         break;
548     }
549   } else
550     status = FPX_FILE_READ_ERROR;
551 
552   // Decimation prefilter width (optional)
553 
554   // Subimage attributes (optional)
555   // NOT SPECIFIED
556 
557   // Subimage ICC profile (optional)
558 
559   // Support data contents (optional)
560   // NOT SPECIFIED
561 
562   return status;
563 }
564 
565 
566 //  ----------------------------------------------------------------------------
SetResolutionDescription()567 FPXStatus PResolutionFlashPix::SetResolutionDescription()
568 {
569   PFlashPixFile *fileFPX = (PFlashPixFile*)fatherFile->filePtr;
570   FPXStatus     status = FPX_OK;
571   OLEProperty   *aProp;
572   int      FlashPixIdentifier = fatherFile->nbSubImages - identifier - 1;
573 
574   // SubImage pixel width (required)
575   if (fileFPX->SetImageContentProperty (PID_SubImageWidth(FlashPixIdentifier) , TYP_SubImageWidth, &aProp)) {   // Subimage width
576     *aProp = int(realWidth);
577   } else
578     status = FPX_FILE_WRITE_ERROR;
579 
580   // Subimage pixel heigth (required)
581   if (fileFPX->SetImageContentProperty (PID_SubImageHeight(FlashPixIdentifier), TYP_SubImageHeight, &aProp)) {  // Subimage heigth
582     *aProp = int(realHeight);
583   } else
584     status = FPX_FILE_WRITE_ERROR;
585 
586   // Subimage color (required)
587   if (fileFPX->SetImageContentProperty (PID_SubImageColor(FlashPixIdentifier), TYP_SubImageColor, &aProp)) {
588     OLEBlob colorBlob(8 + 4*colorSpace.numberOfComponents);
589     if (colorBlob.GetBlobSize()>0) {
590       DWORD tmp = 1;
591       colorBlob.WriteVT_I4(tmp);    // Number of subimages (only 1 subimage in Baseline...)
592       tmp = (DWORD)(colorSpace.numberOfComponents);
593       colorBlob.WriteVT_I4(tmp);    // Number of channels
594       for (int i = 0; i < colorSpace.numberOfComponents; i++) {
595         ComputeChannelColor(&tmp,colorSpace,i);   // Color of channel i
596         if (isAlpha) {
597           if (colorSpace.theComponents[i].myColor == ALPHA)
598             UnsetPremultiplied(tmp);
599           else if (premultiplied)
600             SetPremultiplied(tmp);
601           else
602             UnsetPremultiplied(tmp);
603         }
604         colorBlob.WriteVT_I4(tmp);
605         // CAUTION: we don't analyse extra subimages (Baseline limitation)
606       }
607       *aProp = (BLOB*)(colorBlob.GetBlob());
608     } else
609       status = FPX_FILE_WRITE_ERROR;
610   } else
611     status = FPX_FILE_WRITE_ERROR;
612 
613   // Subimage numerical format (required)
614   if (fileFPX->SetImageContentProperty (PID_SubImageNumFormat(FlashPixIdentifier), TYP_SubImageNumFormat, &aProp)) {  // Subimage numerical format
615     uint32_t format = VT_UI1;  // Always 8-bit unsigned integer in Baseline
616     FPXLongArray numericalFormat;
617     numericalFormat.length = 1;   // Only one subimage in Baseline
618     numericalFormat.ptr = &format;
619     *aProp = numericalFormat;
620   } else
621     status = FPX_FILE_WRITE_ERROR;
622 
623   // Decimation method (required)
624   if (fileFPX->SetImageContentProperty (PID_DecimationMethod(FlashPixIdentifier), TYP_DecimationMethod, &aProp)) {  // Subimage decimation method
625     DWORD decimation;
626     switch (fatherFile->convolution) {
627       case Convolution_Standard:      // 2x2 averaging
628         decimation = 2;
629         break;
630       case Convolution_Gauss:       // 4x4 gaussian filter
631         decimation = 4;
632         break;
633   //    case Convolution_FlashPix:        // Recommended filter (still to be defined...)
634   //      decimation = DecimationStandard;
635   //      break;
636     default:
637       {
638       }
639     }
640     if (identifier == 0)          // For the high resolution level, there is no decimation
641       decimation = 0;
642     *aProp = int(decimation);
643   } else
644     status = FPX_FILE_WRITE_ERROR;
645 
646   // Decimation prefilter width (optionnal)
647 
648   // Subimage attributes (optionnal)
649   // NOT SPECIFIED
650 
651   // Subimage ICC profile (optionnal)
652 
653   // Support data contents (optionnal)
654   // NOT SPECIFIED
655 
656   return status;
657 }
658 
659 
660 //  ----------------------------------------------------------------------------
661 // Read a resolution level and initialize the buffer 'pixels'
Read()662 FPXStatus PResolutionFlashPix::Read ()
663 {
664   int    i;
665   DWORD     tmp;
666   DWORD   n;
667   FPXStatus status = FPX_OK;
668   DWORD   lengthInfoStream, tileWidth, tileHeight, nbChannel, headersTableOffset;
669   DWORD   tileHeadersize, offsetTile, sizeTile, compressType;
670 
671   // The stream must be opened or created before calling Read()...
672   if (subStreamHdr == NULL)
673     return FPX_FILE_NOT_OPEN_ERROR;
674 
675   if (subStreamHdr->Seek(0)) {    // Position to the beginning of the header stream
676 
677     // Read the Subimage Header Stream
678     if (subStreamHdr->ReadVT_I4(&lengthInfoStream) == 0)  // length of the info stream
679       status = FPX_FILE_READ_ERROR;
680     if (subStreamHdr->ReadVT_I4(&tmp) == 0)         // Width of sub-image in pixels
681       status = FPX_FILE_READ_ERROR;
682     realWidth = tmp;
683     if (subStreamHdr->ReadVT_I4(&tmp) == 0)         // Height of sub-image in pixels
684       status = FPX_FILE_READ_ERROR;
685     realHeight = tmp;
686     if (subStreamHdr->ReadVT_I4(&n) == 0)         // nb of tiles in the sub-image
687       status = FPX_FILE_READ_ERROR;
688     if (subStreamHdr->ReadVT_I4(&tileWidth) == 0)     // Tiles width
689       status = FPX_FILE_READ_ERROR;
690     if (subStreamHdr->ReadVT_I4(&tileHeight) == 0)      // Tiles height
691       status = FPX_FILE_READ_ERROR;
692     if (subStreamHdr->ReadVT_I4(&nbChannel) == 0)     // number of channels
693       status = FPX_FILE_READ_ERROR;
694     if (subStreamHdr->ReadVT_I4(&headersTableOffset) == 0)  // Tile headers table offset
695       status = FPX_FILE_READ_ERROR;
696     if (subStreamHdr->ReadVT_I4(&tileHeadersize) == 0)    // Tile Header length
697       status = FPX_FILE_READ_ERROR;
698 
699     assert(tileHeadersize == 16); // Should be 16 in Baseline...
700     tileHeadersize = 16;
701 
702     // Compute numbers of tiles in the width and the height of the resolution level
703     nbTilesH = (short) (realHeight/tileHeight + (realHeight%tileHeight ? 1 : 0));
704     nbTilesW = (short) (realWidth /tileWidth  + (realWidth %tileWidth  ? 1 : 0));
705 
706     // Test values consistency
707     if ((!realHeight) || (!realWidth) || (!nbTilesH) || (!nbTilesW))
708       n = 0;
709 
710     int offset = headersTableOffset;               // Position to the tile table
711 
712     if (status == FPX_OK) {
713       AllocTilesArray ();
714       for (i = 0; i < (int) n; i++) {
715         if (subStreamHdr->Seek(offset) == false)        // Offset of each tile of the sub-image in the file
716           status = FPX_FILE_READ_ERROR;
717         if (subStreamHdr->ReadVT_I4(&offsetTile) == 0)      // Offset of each tile of the sub-image in the file
718           status = FPX_FILE_READ_ERROR;
719         if (subStreamHdr->ReadVT_I4(&sizeTile) == 0)      // Size of each tile
720           status = FPX_FILE_READ_ERROR;
721         if (subStreamHdr->ReadVT_I4(&compressType) == 0)    // Compression type
722           status = FPX_FILE_READ_ERROR;
723         if (subStreamHdr->ReadVT_I4((DWORD *)&compressionSubtype) == 0)   // Sub-compression type
724           status = FPX_FILE_READ_ERROR;
725 
726         // Break and exit if error
727         if (status != FPX_OK)
728           break;
729 
730         compression = (FPXCompressionOption)compressType;
731         tiles[i].InitializeRead(this,offsetTile,sizeTile,i, compressType, compressionSubtype);
732         offset += tileHeadersize;
733       }
734     }
735   }
736 
737   // Error handling
738   if (status != FPX_OK) {
739     fatherFile->filePtr->SignaleErreur();
740     delete [] tiles;
741     tiles = NULL;
742     realHeight = 0;
743     realWidth  = 0;
744     nbTilesH   = 0;
745     nbTilesW   = 0;
746   }
747 
748   return (status);
749 }
750 
751 
752 //  ----------------------------------------------------------------------------
753 // Write the tile header of a sub-image :
Write()754 FPXStatus PResolutionFlashPix::Write()
755 {
756   register int   TILE_WIDTH = fatherFile->tileWidth;
757   FPXStatus   status = FPX_OK;
758 
759   // If nothing has never been writen or read from this resolution level,
760   // there's no point to save anything in the subStreamHdr...
761   if (!HasBeenUsed())
762     return FPX_OK;
763 
764   if (subStreamHdr->Seek(0)) {  // Position to the beginning of the header stream
765 
766     DWORD offset = 36;              // 9 fields of 4 bytes each in this version...
767     DWORD n = nbTilesH * nbTilesW;        // number of tiles
768     DWORD tileWidth = TILE_WIDTH;       // Fixed and equal to 64 in Baseline...
769     DWORD nbChannel = GetNbChannel(baseSpace);  // Number of channels
770     DWORD length = 16;              // 4 fileds of 4 bytes each in this version...
771     DWORD tmp;
772 
773     // Write the SubImage Header Stream header
774     if (subStreamHdr->WriteVT_I4(&offset) == 0)   // Length of header stream header
775       status = FPX_FILE_WRITE_ERROR;
776     tmp = realWidth;
777     if (subStreamHdr->WriteVT_I4(&tmp) == 0)    // Width of the sub-images in pixels
778       status = FPX_FILE_WRITE_ERROR;
779     tmp = realHeight;
780     if (subStreamHdr->WriteVT_I4(&tmp) == 0)    // Height of the sub-images in pixels
781       status = FPX_FILE_WRITE_ERROR;
782     if (subStreamHdr->WriteVT_I4(&n) == 0)      // nb of tiles of the sub-image
783       status = FPX_FILE_WRITE_ERROR;
784     if (subStreamHdr->WriteVT_I4(&tileWidth) == 0)  // Tiles width
785       status = FPX_FILE_WRITE_ERROR;
786     if (subStreamHdr->WriteVT_I4(&tileWidth) == 0)  // Tiles height (the same in Baseline...)
787       status = FPX_FILE_WRITE_ERROR;
788     if (subStreamHdr->WriteVT_I4(&nbChannel) == 0)  // Number of channels
789       status = FPX_FILE_WRITE_ERROR;
790     if (subStreamHdr->WriteVT_I4(&offset) == 0)   // Tile header table offset
791       status = FPX_FILE_WRITE_ERROR;
792     if (subStreamHdr->WriteVT_I4(&length) == 0)   // Tile header table offset
793       status = FPX_FILE_WRITE_ERROR;
794 
795     // Write the Tile Header Table
796     if (status == FPX_OK) {
797 
798       // For each tile
799       for (int i = 0; i < (int) n; i++) {
800 
801         // Get the pointer for this tile
802         PTileFlashPix* pt   = (PTileFlashPix*)(tiles + i);
803 
804         // If this tile has never been written before, initialize it with background color
805         int offset = pt->GetposFic();
806         if ( (offset < 0 ) && (pt->compression != SINGLE_COLOR)) {  // PTCH_NEGONE
807           pt->tileInitialize = TRUE;
808 
809           // Set the compression to single color and write tile
810           pt->SetCompression(SINGLE_COLOR);
811           pt->WriteTile();
812         }
813 
814         // Get the infos for this tile
815         offset          = pt->GetposFic();
816         DWORD size          = pt->GetTileSize();
817         DWORD blocCompr     = (DWORD)pt->compression;
818         DWORD blocSubtype   = (DWORD)pt->compressionSubtype;
819 
820         // Change compression type to 2 (JPEG) only
821         if ( pt->compression == JPEG_BY_QUALITY || pt->compression == JPEG_BY_TABLE_GROUP )
822           blocCompr = JPEG_UNSPECIFIED;
823 
824         // Write the Tile Header for this tile
825         if (subStreamHdr->WriteVT_I4((DWORD *)&offset) == 0)// Write the offset of each tile of the sub-image in the file
826           status = FPX_FILE_WRITE_ERROR;
827         if (subStreamHdr->WriteVT_I4(&size) == 0)     // Write the size of each tile
828           status = FPX_FILE_WRITE_ERROR;
829         if (subStreamHdr->WriteVT_I4(&blocCompr) == 0)    // Write the compression type
830           status = FPX_FILE_WRITE_ERROR;
831         if (subStreamHdr->WriteVT_I4(&blocSubtype) == 0)  // Write the sub-compression type
832           status = FPX_FILE_WRITE_ERROR;
833 
834         // Break and exit if error
835         if (status != FPX_OK)
836           break;
837       }
838     }
839   }
840 
841   return (status);
842 }
843 
844 
845 //  ----------------------------------------------------------------------------
846 // Read the tile data from the file without decompression
ReadRawTile(unsigned int whichTile,FPXCompressionOption * compressOption,unsigned char * compressQuality,long * compressSubtype,unsigned int * dataLength,void ** data)847 FPXStatus PResolutionFlashPix::ReadRawTile (
848           unsigned int           whichTile,
849           FPXCompressionOption*  compressOption,
850           unsigned char*         compressQuality,
851           long*                  compressSubtype,
852           unsigned int*          dataLength,
853           void**                 data)
854 {
855   FPXStatus status = FPX_OK;
856 
857   // Read and allocate tile pointers if necessary
858   if (!HasBeenUsed()) {
859     status = ReadHeaderStream();
860     if(status != FPX_OK)
861       return status;
862   }
863 
864   if (status == 0) {
865     unsigned long nbTiles = nbTilesW * nbTilesH;
866     if (whichTile >= nbTiles)
867       status = FPX_BAD_COORDINATES;
868     else {
869       PTileFlashPix* tile = (PTileFlashPix*)(tiles) + whichTile;
870       status = tile->ReadRawTile (compressOption, compressQuality, compressSubtype, dataLength, data);
871     }
872   }
873   return status;
874 }
875 
876 
877 //  ----------------------------------------------------------------------------
878 // Write the tile data in the file without compression
WriteRawTile(unsigned int whichTile,FPXCompressionOption compressOption,unsigned char compressQuality,long compressSubtype,unsigned int dataLength,void * data)879 FPXStatus PResolutionFlashPix::WriteRawTile (
880           unsigned int        whichTile,
881           FPXCompressionOption  compressOption,
882           unsigned char       compressQuality,
883           long          compressSubtype,
884           unsigned int  dataLength,
885           void*           data)
886 {
887   FPXStatus status = FPX_OK;
888 
889   // Read and allocate tile pointers if necessary
890   if (!HasBeenUsed())
891     status = UpdateHeaderStream();
892 
893   if (status == FPX_OK) {
894     unsigned int nbTiles = nbTilesW * nbTilesH;
895     if (whichTile >= nbTiles)
896       status = FPX_BAD_COORDINATES;
897     else {
898       PTileFlashPix* tile = (PTileFlashPix*)(tiles) + whichTile;
899       status = tile->WriteRawTile (compressOption, compressQuality, compressSubtype, dataLength, data);
900     }
901   }
902   return status;
903 }
904 
905 
906 //  ----------------------------------------------------------------------------
WriteLine(Pixel * pix,short plan)907 FPXStatus PResolutionFlashPix::WriteLine (Pixel* pix, short plan)
908 {
909   FPXStatus status = FPX_OK;
910 
911   // Read and allocate tile pointers if necessary
912   if (!HasBeenUsed())
913     status = UpdateHeaderStream();
914 
915   // Call the parent method now
916   if (status == FPX_OK)
917     status = PResolutionLevel::WriteLine(pix, plan);
918 
919   return status;
920 }
921 
922 
923 //  ----------------------------------------------------------------------------
FlushModifiedTiles()924 FPXStatus PResolutionFlashPix::FlushModifiedTiles()
925 {
926   return PResolutionLevel::FlushModifiedTiles() ;
927 }
928 
929 
930 //  ----------------------------------------------------------------------------
Convolution(int x,int y,Pixel * pix,int width,int height)931 FPXStatus PResolutionFlashPix::Convolution (int x, int y, Pixel* pix, int width, int height)
932 {
933   FPXStatus status = FPX_OK;
934 
935   // Read and allocate tile pointers if necessary
936   if (!HasBeenUsed())
937     status = UpdateHeaderStream();
938 
939   // Call the parent method now
940   if (status == FPX_OK)
941     status = PResolutionLevel::Convolution (x, y, pix, width, height);
942 
943   return status;
944 }
945 
946 
947 //  ----------------------------------------------------------------------------
DecimateLevel()948 FPXStatus PResolutionFlashPix::DecimateLevel ()
949 {
950   FPXStatus status = FPX_OK;
951 
952   // Read and allocate tile pointers if necessary
953   if (!HasBeenUsed())
954       status = UpdateHeaderStream();
955 
956   // Call the parent method now
957   if (status == FPX_OK)
958     status = PResolutionLevel::DecimateLevel();
959 
960   return status;
961 }
962 
963 
964 //  ----------------------------------------------------------------------------
WriteRectangle(int x0,int y0,int x1,int y1,Pixel * pix,short plan)965 FPXStatus PResolutionFlashPix::WriteRectangle (int x0, int y0, int x1, int y1, Pixel* pix, short plan)
966 {
967   FPXStatus status = FPX_OK;
968 
969   // Read and allocate tile pointers if necessary
970   if (!HasBeenUsed())
971     status = UpdateHeaderStream();
972 
973   // Call the parent method now
974   if (status == FPX_OK)
975     status = PResolutionLevel::WriteRectangle(x0, y0, x1, y1, pix, plan);
976 
977   return status;
978 }
979 
980 
981 //  ----------------------------------------------------------------------------
ReadRectangle(int x0,int y0,int x1,int y1,Pixel * pix)982 FPXStatus PResolutionFlashPix::ReadRectangle (int x0, int y0, int x1, int y1, Pixel* pix)
983 {
984   FPXStatus status = FPX_OK;
985 
986   // Read and allocate tile pointers if necessary
987   if (!HasBeenUsed())
988     status = ReadHeaderStream();
989 
990   // Call the parent method now
991   if (status == FPX_OK)
992     status = PResolutionLevel::ReadRectangle(x0, y0, x1, y1, pix);
993 
994   return status;
995 }
996 
997 
998 //  ----------------------------------------------------------------------------
ReadInARectangle(Pixel * bufferOut,short pixelsPerLine,short width,short height,const CorrectLut * correctLut,Boolean useAlphaChannel,const CombinMat * combinaisonMatrix)999 FPXStatus PResolutionFlashPix::ReadInARectangle (Pixel* bufferOut, short pixelsPerLine, short width, short height,
1000                      const CorrectLut* correctLut, Boolean useAlphaChannel, const CombinMat* combinaisonMatrix)
1001 {
1002   FPXStatus status = FPX_OK;
1003 
1004   // Read and allocate tile pointers if necessary
1005   if (!HasBeenUsed())
1006     status = ReadHeaderStream();
1007 
1008   // Call the parent method now
1009   if (status == 0)
1010     status = PResolutionLevel::ReadInARectangle (bufferOut, pixelsPerLine, width, height,
1011                         correctLut, useAlphaChannel, combinaisonMatrix);
1012   return status;
1013 }
1014 
1015 
1016 //  ----------------------------------------------------------------------------
Read(int * px,int * py,Pixel * table)1017 FPXStatus PResolutionFlashPix::Read (int* px, int* py, Pixel* table)
1018 {
1019   FPXStatus status = FPX_OK;
1020 
1021   // Read and allocate tile pointers if necessary
1022   if (!HasBeenUsed())
1023     status = ReadHeaderStream();
1024 
1025   // Call the parent method now
1026   if (status == FPX_OK)
1027     status = PResolutionLevel::Read (px, py, table);
1028 
1029   return status;
1030 }
1031 
1032 
1033 //  ----------------------------------------------------------------------------
ReadInterpolated(int * px,int * py,Pixel * table)1034 FPXStatus PResolutionFlashPix::ReadInterpolated (int* px, int* py, Pixel* table)
1035 {
1036   FPXStatus status = FPX_OK;
1037 
1038   // Read and allocate tile pointers if necessary
1039   if (!HasBeenUsed())
1040     status = ReadHeaderStream();
1041 
1042   // Call the parent method now
1043   if (status == FPX_OK)
1044     status = PResolutionLevel::ReadInterpolated (px, py, table);
1045 
1046   return status;
1047 }
1048 
1049 
1050 //  ----------------------------------------------------------------------------
ReadMeanInterpolated(int xi,int yi,Pixel & pixel)1051 FPXStatus PResolutionFlashPix::ReadMeanInterpolated (int xi, int yi, Pixel& pixel)
1052 {
1053   FPXStatus status = FPX_OK;
1054 
1055   // Read and allocate tile pointers if necessary
1056   if (!HasBeenUsed())
1057     status = ReadHeaderStream();
1058 
1059   // Call the parent method now
1060   if (status == FPX_OK)
1061     status = PResolutionLevel::ReadMeanInterpolated (xi, yi, pixel);
1062 
1063   return status;
1064 }
1065 
1066 
1067 //  ----------------------------------------------------------------------------
IsOnTheBorder(int xi,int yi)1068 Boolean PResolutionFlashPix::IsOnTheBorder (int xi, int yi)
1069 {
1070   Boolean ok = true;
1071 
1072   // Read and allocate tile pointers if necessary
1073   if (!HasBeenUsed()) {
1074     if (UpdateHeaderStream() != FPX_OK)
1075       ok = false;
1076   }
1077 
1078   // Call the parent method now
1079   if (ok)
1080     ok = PResolutionLevel::IsOnTheBorder (xi, yi);
1081 
1082   return ok;
1083 }
1084 
1085 
1086 //  ----------------------------------------------------------------------------
1087 // Compute histogram for the 4 channels
GetHistogram(int * alpha,int * red,int * green,int * blue,int * brightness,const CorrectLut * correctLut)1088 FPXStatus PResolutionFlashPix::GetHistogram (int* alpha, int* red, int* green, int* blue, int* brightness, const CorrectLut* correctLut)
1089 {
1090   FPXStatus status = FPX_OK;
1091 
1092   // Read and allocate tile pointers if necessary
1093   if (!HasBeenUsed())
1094     status = UpdateHeaderStream();
1095 
1096   // Call the parent method now
1097   if (status == 0)
1098     status = PResolutionLevel::GetHistogram (alpha, red, green, blue, brightness, correctLut);
1099 
1100   return status;
1101 }
1102 
1103 
1104 //  ----------------------------------------------------------------------------
GetResolutionSizeInfo(int * width,int * height,int * nbTilesWidth,int * nbTilesHeight)1105 FPXStatus PResolutionFlashPix::GetResolutionSizeInfo (int* width, int* height, int* nbTilesWidth, int* nbTilesHeight)
1106 {
1107   FPXStatus status = FPX_OK;
1108 
1109   // Read and allocate tile pointers if necessary
1110   if (!HasBeenUsed())
1111     status = UpdateHeaderStream();
1112 
1113   // Call the parent method now
1114   if (status == 0)
1115     status = PResolutionLevel::GetResolutionSizeInfo (width, height, nbTilesWidth,
1116                       nbTilesHeight);
1117 
1118   return status;
1119 }
1120 
1121 
1122 //  ----------------------------------------------------------------------------
ReadSampledRectangle(int x0,int y0,int x1,int y1,Pixel * map,short pixelsPerLine,int mapWidth,int mapHeight,Boolean showAlphaChannel,float ratio)1123 FPXStatus PResolutionFlashPix::ReadSampledRectangle(int x0, int y0, int x1, int y1, Pixel* map, short pixelsPerLine, int mapWidth, int mapHeight, Boolean showAlphaChannel, float ratio)
1124 {
1125   FPXStatus status = FPX_OK;
1126 
1127   // Read and allocate tile pointers if necessary
1128   if (!HasBeenUsed())
1129     status = ReadHeaderStream();
1130 
1131   // Call the parent method now
1132   if (status == FPX_OK)
1133     status = PResolutionLevel::ReadSampledRectangle (x0, y0, x1, y1, map, pixelsPerLine,
1134                       mapWidth, mapHeight, showAlphaChannel, ratio);
1135   return status;
1136 }
1137 
1138 
1139 //  ----------------------------------------------------------------------------
SearchPixelTopLeftCorner(int * x1,int * y1,float ratio)1140 FPXStatus PResolutionFlashPix::SearchPixelTopLeftCorner(int* x1, int* y1, float ratio)
1141 {
1142   FPXStatus status = FPX_OK;
1143 
1144   // Read and allocate tile pointers if necessary
1145   if (!HasBeenUsed())
1146     status = UpdateHeaderStream();
1147 
1148   // Call the parent method now
1149   if (status == FPX_OK)
1150     status = PResolutionLevel::SearchPixelTopLeftCorner (x1, y1, ratio);
1151 
1152   return status;
1153 }
1154 
1155 
1156 //  ----------------------------------------------------------------------------
1157 // Read a pixel of a sub image. Read it on disk if necessary.
1158 // If error, return false and pixel is set to 0.
ReadMean(int xi,int yi,Pixel & pixel)1159 FPXStatus PResolutionFlashPix::ReadMean (int xi, int yi, Pixel& pixel)
1160 {
1161   FPXStatus status = FPX_OK;
1162 
1163   // Read and allocate tile pointers if necessary
1164   if (!HasBeenUsed())
1165     status = ReadHeaderStream();
1166 
1167   // Call the parent method now
1168   if (status == FPX_OK)
1169     status = PResolutionLevel::ReadMean (xi, yi, pixel);
1170 
1171   return status;
1172 }
1173 
1174 //  ----------------------------------------------------------------------------
1175 //  External Functions
1176 //  ----------------------------------------------------------------------------
1177 
1178 
1179 
1180 //  - EOF ----------------------------------------------------------------------
1181