1 //  ----------------------------------------------------------------------------
2 //  MODULE    : PHierarchicalImage
3 //  LANGUAGE  : C++
4 //  CREATOR   : Philippe BOSSUT
5 //  CREAT. DATE : Tuesday, March 12, 1996
6 //  DESCRIPTION :
7 //  COMMENTS  :
8 //    SCCSID          : @(#)ph_image.cpp  1.2 12:48:36 22 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 
17 //  ----------------------------------------------------------------------------
18 #include "ph_image.h"
19 #include "f_fpxio.h"
20 //  ----------------------------------------------------------------------------
21 
22 //  Includes
23 //  --------
24 
25 #include  <stdio.h>
26 #include  <stdlib.h>
27 #include  <string.h>
28 #ifndef _WINDOWS
29 #  include  <strings.h>
30 #endif
31 #include  <math.h>
32 #ifdef macintosh
33 #  include  <Errors.h>
34 #endif
35 
36 
37 #ifndef Debug_h
38 #  include  "debug.h"
39 #endif
40 #ifndef Memoire_h
41 #  include  "b_memory.h"
42 #endif
43 #ifndef Fichier_h
44 #  include  "a_file.h"
45 #endif
46 
47 #ifndef PResolutionLevel_h
48 #  include "pr_level.h"
49 #endif
50 #ifndef PTile_h
51 #  include "ptile.h"
52 #endif
53 #ifndef PImageFile_h
54 #  include "pimgfile.h"
55 #endif
56 
57 #ifndef Numbers_h
58 #  include  "numbers.h"
59 #endif
60 
61 #ifndef BufferDesc_h
62 #  include  "buffdesc.h"
63 #endif
64 
65 
66 //  Constants
67 //  ---------
68 
69 //  Variables
70 //  ---------
71 
72 //  ----------------------------------------------------------------------------
73 //  #pragma segment PHierarchicalImage
74 //  ----------------------------------------------------------------------------
75 
76 //  ----------------------------------------------------------------------------
77 //  Internal Functions
78 //  ----------------------------------------------------------------------------
79 
MIN(float a,float b,float c)80 inline float MIN(float a, float b, float c)
81 {
82   return MIN(a, MIN(b,c));
83 }
84 
85 //  ----------------------------------------------------------------------------
86 //  Member Functions
87 //  ----------------------------------------------------------------------------
88 
89 // Open a file in Create mode (compressed or uncompressed) :
90 // CAUTION : the file is opened as long as necessary
PHierarchicalImage(FicNom & refName,int width,int height,float resolution)91 PHierarchicalImage::PHierarchicalImage (FicNom& refName, int width, int height, float resolution) : PRIImage (width, height, resolution)
92 {
93   Init ();        // Init the object
94 
95   fileName = refName;     // Name of the image file
96   mode   = mode_Ecrasement;   // Opening mode: overwrite image
97 
98   if (EnoughDiskSpace() == false)
99     mode = mode_Lecture;    // If not enough disk space, invalid overwrite mode
100 }
101 
102 
103 //  ----------------------------------------------------------------------------
104 // Open a file in Read mode only (compressed or uncompressed) :
105 // CAUTION : the file is opened as long as necessary
PHierarchicalImage(FicNom & refName)106 PHierarchicalImage::PHierarchicalImage (FicNom& refName) : PRIImage ()
107 {
108   Init ();        // Init the object
109   fileName = refName;     // Name of the image file
110 }
111 
112 
113 //  ----------------------------------------------------------------------------
114 // Open a file in Read or Write mode (compressed or uncompressed) :
115 // CAUTION : the file is opened as long as necessary
PHierarchicalImage(FicNom & refName,mode_Ouverture openMode)116 PHierarchicalImage::PHierarchicalImage (FicNom& refName, mode_Ouverture openMode) : PRIImage ()
117 
118 {
119   Init ();        // Init the object
120   fileName = refName;     // Name of the image file
121   mode   = openMode;      // Opening mode: overwrite image
122 }
123 
124 
125 //  ----------------------------------------------------------------------------
126 // Open a file in Create mode (compressed or uncompressed) :
127 // CAUTION : the file is opened as long as necessary
PHierarchicalImage(int theFd,int width,int height,float resolution)128 PHierarchicalImage::PHierarchicalImage (int theFd, int width, int height, float resolution)
129   : PRIImage (width, height, resolution)
130 {
131   Init ();        // Init the object
132 
133   fd  = theFd;      // The caller opened the image
134   mode  = mode_Ecrasement;    // Opening mode: overwrite image
135 
136   if (EnoughDiskSpace() == false)
137     mode = mode_Lecture;    // If not enough disk space, invalid overwrite mode
138 }
139 
140 
141 //  ----------------------------------------------------------------------------
142 // Open a file in Read mode only (compressed or uncompressed) :
143 // CAUTION : the file is opened as long as necessary
PHierarchicalImage(int theFd)144 PHierarchicalImage::PHierarchicalImage (int theFd) : PRIImage ()
145 {
146   Init ();    // Init the object
147   fd = theFd;   // The caller opened the image
148 }
149 
150 
151 //  ----------------------------------------------------------------------------
152 // Open a file in Read or Write mode (compressed or uncompressed) :
153 // CAUTION : the file is opened as long as necessary
PHierarchicalImage(int theFd,mode_Ouverture openMode)154 PHierarchicalImage::PHierarchicalImage (int theFd, mode_Ouverture openMode) : PRIImage ()
155 
156 {
157   Init ();      // Init the object
158   fd    = theFd;  // The caller opened the image
159   mode  = openMode;   // Opening mode: overwrite image
160 }
161 
162 
163 //  ----------------------------------------------------------------------------
164 // Clean memory
~PHierarchicalImage()165 PHierarchicalImage::~PHierarchicalImage ()
166 {
167   if (filePtr) {
168     delete filePtr;
169     filePtr = NULL;
170   }
171   if (firstSubImage) {
172     delete firstSubImage;
173     firstSubImage = NULL;
174   }
175   if (subImages) {
176     delete [] subImages;
177     subImages = NULL;
178   }
179 }
180 
181 
182 //  ----------------------------------------------------------------------------
183 // Give default values to image information before starting reading or using them
Init()184 void PHierarchicalImage::Init ()
185 {
186   // PHierarchicalImage values
187   baseSpace     = SPACE_32_BITS_RGB;
188   baseUncalibrated  = FALSE;
189   usedSpace     = SPACE_32_BITS_RGB;
190   isFlatFile    =  FALSE;
191   alphaOffset     = (unsigned char) GetAlphaOffsetBaseline(usedSpace);
192   backgroundBase  = Toolkit_BackgroundColor();
193   backgroundUsed  = Toolkit_BackgroundColor();
194 
195   convolution   = Toolkit_Convolution();  // Default convolution mode
196   filter    = 0;        // No custom convolution function for the moment
197   automaticDecimation = true;       // Default is: yes, do decimation automatically
198 
199   compression   = Toolkit_Compression();  // Default compression mode
200   compressionHandle = NULL;       // Start with no compression handle�
201   handleSize    = 0;        // �which size is then null
202 
203   SetTileParameter (Toolkit_TileWidth(), Toolkit_TileWidth()); // Default tile size
204 
205                                                                   firstSubImage   = NULL;
206   nbSubImages   = 0;
207   subImages   = NULL;
208 
209   //  fileName  = "";       // Name of the image file
210 
211   filePtr   = NULL;       // File not opened yet�
212   fd      = 0;        // �or may be by the caller.
213   mode      = mode_Lecture;     // Opening mode: read only by default
214   posFic    = 0;        // Position at the begining os the file
215   version   = 0;        // Version of the file (we've no idea at that level...)
216 
217   posPath   = 0;        // No paths
218 }
219 
220 
221 //  ----------------------------------------------------------------------------
SetTileParameter(int width,int height)222 FPXStatus PHierarchicalImage::SetTileParameter (int width, int height)
223 {
224   // Test parameters consistency
225   assert((width>0) && (height>0));
226 
227   tileWidth = MAX(width,height);
228   tileSize = width * height * sizeof(Pixel);
229   tileLineSize = width * sizeof(Pixel);
230   log2TileWidth = (int)(Toolkit_Log2(tileWidth));
231   maskTileWidth = tileWidth - 1;
232   return FPX_OK;
233 }
234 
235 
236 //  ----------------------------------------------------------------------------
237 // Open the file, create it if necessary (if mode is write), write first information on the first block
OpenFile()238 FPXStatus PHierarchicalImage::OpenFile ()
239 {
240   return FPX_UNIMPLEMENTED_FUNCTION;
241 }
242 
243 
244 //  ----------------------------------------------------------------------------
245 // Store the header of the file before closing
CloseFile()246 FPXStatus PHierarchicalImage::CloseFile()
247 {
248   return FPX_UNIMPLEMENTED_FUNCTION;
249 }
250 
251 //  ----------------------------------------------------------------------------
DoNotCloseFileWhenDelete()252 void PHierarchicalImage::DoNotCloseFileWhenDelete()
253 {
254   filePtr->DoNotCloseFileWhenDelete();
255 }
256 
257 //  ----------------------------------------------------------------------------
CloseFileWhenDelete()258 void PHierarchicalImage::CloseFileWhenDelete()
259 {
260   filePtr->CloseFileWhenDelete();
261 }
262 
263 //  ----------------------------------------------------------------------------
UpdateErrorCount()264 void PHierarchicalImage::UpdateErrorCount()
265 {
266   PRIImage::UpdateErrorCount();
267   if (!Status()) {      // If error raised
268     nbSubImages = 0;    // Invalid the image
269     mode = mode_Lecture;  // Force mode to be read only
270   }
271 }
272 
273 
274 //  ----------------------------------------------------------------------------
275 // Open an image file and create the resolution level list "firstSubImage" and the "subImages" array of pointers
OpenImage()276 FPXStatus PHierarchicalImage::OpenImage()
277 {
278   FPXStatus status = FPX_OK;
279 
280   // Open the file if it hasn't been done yet
281   if (filePtr == NULL) {
282     status = OpenFile();
283     // Init the size parameters according to the infos read into the file
284     SetImageSize(width,height,resolution);
285   }
286 
287   if (firstSubImage == NULL && !Status()) {
288     if (nbSubImages != 0)                     // The file is open en read or write mode
289       CreateInitResolutionLevelList();            // Create and initialize the list of sub image reading the file "filePtr"
290     else if ((nbSubImages == 0) && (mode == mode_Ecrasement)) // The file is open in create mode
291       CreateEmptyResolutionLevelList();           // Create the list of empty sub images
292     else {
293       RaiseError( FPX_FILE_READ_ERROR);
294       status = FPX_FILE_READ_ERROR;
295     }
296     // Initialize the array of pointers "subImages"
297     // LS 1/11/96: We initialize the field 'subImages' even on error;
298     //         else, LP crashes when reading a compressed image without QuickTime installed
299     InitResolutionLevelsTable();
300   }
301   if (status == FPX_OK)
302     status = Status();
303   return status;
304 }
305 
306 
307 //  ----------------------------------------------------------------------------
GetFileName(FicNom & refName)308 FPXStatus PHierarchicalImage::GetFileName (FicNom& refName)
309 {
310   refName = fileName;
311   return(FPX_OK);
312 }
313 
314 
315 //  ----------------------------------------------------------------------------
316 // Store "pix" in a buffer, write it if it's full and compute sub-image buffer if necessary
WriteLine(Pixel * pix,short plan)317 FPXStatus PHierarchicalImage::WriteLine (Pixel* pix, short plan)
318 {
319   Pixel   *source;
320   FPXStatus status = FPX_OK;
321 
322   if (GtheSystemToolkit->interleaving == Interleaving_Pixel)
323     status = firstSubImage->WriteLine(pix, plan);
324   else {
325     FastAllocArray(source,Pixel,(unsigned int)(width));
326     if (source == NULL)
327       return FPX_MEMORY_ALLOCATION_FAILED;
328 
329     if ((GtheSystemToolkit->interleaving != Interleaving_Channel) || (plan == ActiveChannel_All)) {
330       if (Toolkit_UnInterleave (pix, source, width, 1, width, 1)) {
331         FastDeleteArray(source,Pixel);
332         return FPX_COLOR_CONVERSION_ERROR;  // error converting pixel buffer according to user's options
333       }
334 
335     } else {
336       // The buffer contain only the active channel
337       // we must create a temporary buffer to send to the image file
338       register int j;
339       register unsigned char *src, *dst;
340 
341       src = (unsigned char *)(pix);
342       dst = (unsigned char *)(source)  + plan;
343       for (j = 0; j < width; j++, src++, dst+=sizeof(Pixel))
344         *dst = *src;
345     }
346     status = firstSubImage->WriteLine(source, plan);
347     FastDeleteArray(source,Pixel);
348   }
349   return status;
350 }
351 
352 
353 //  ----------------------------------------------------------------------------
354 // Store "pix" in a buffer, write it if it's full and compute sub-image buffer if necessary
WriteRectangle(int x0,int y0,int x1,int y1,Pixel * pix,short plan,short resolution)355 FPXStatus PHierarchicalImage::WriteRectangle (int x0, int y0, int x1, int y1, Pixel* pix, short plan, short resolution)
356 {
357   FPXStatus status = FPX_OK;
358 
359   if ( GtheSystemToolkit->interleaving == Interleaving_Pixel) {
360     status = subImages[resolution]->WriteRectangle (x0, y0, x1, y1, pix, plan);
361   } else {
362     int pixWidth = (x1 - x0 + 1);    // width of the buffer 'pix'
363     int pixHeight = (y1 - y0 + 1);   // height of the buffer 'pix'
364     Pixel*  dest = NULL;        // temporary buffer
365     Pixel*  ptrDest = NULL;
366     int subX0, subY0, subX1, subY1;  // corners of the temporary buffer
367     int bufSize = 0;         // size of temporary buffer
368     int bufWidth, bufHeight;     // width ans height of temporary buffer
369     register int i, j;
370     register unsigned char *src, *dst, *ptrPix;
371 
372     src = dst = ptrPix = 0;
373     // cut the rectangle in sub-rectangles to avoid to create a big buffer
374     // in memory when converting the interleaving.
375     // These sub-rectangles have the size of a tile because writing tiles is optimum.
376     int incrRow = tileWidth;
377     int incrCol = tileWidth;
378     for (subY0 = y0; subY0 <= y1; subY0+=incrRow) {
379       subY1 = subY0 + incrRow-1;
380       if (subY1 > y1) subY1 = y1;
381       bufHeight = subY1 - subY0 +1;
382       for (subX0 = x0; subX0 <= x1; subX0+=incrCol) {
383         subX1 = subX0 + incrCol-1;
384         if (subX1 > x1) subX1 = x1;
385         bufWidth = subX1 - subX0 +1;
386         if (bufSize != (bufWidth*bufHeight)) {
387           bufSize = bufWidth*bufHeight;
388           FastDeleteArray(dest, Pixel);
389           FastAllocArray(dest, Pixel, bufSize);
390           if (!dest)
391             return FPX_MEMORY_ALLOCATION_FAILED;
392         }
393         assert(dest);
394         // search the position of the first pixel in the rectangle to copy in the sub_rectangle
395         if ((GtheSystemToolkit->interleaving != Interleaving_Channel) || (plan == ActiveChannel_All)) {
396           switch (GtheSystemToolkit->interleaving) {
397           case Interleaving_Line:
398             ptrPix = (unsigned char *)(pix);
399             ptrPix += (subY0-y0)*pixWidth*4 + (subX0-x0);
400             break;
401           case Interleaving_Channel:
402             ptrPix = (unsigned char *)(pix);
403             ptrPix += (subY0-y0)*pixWidth + (subX0-x0);
404             break;
405           case Interleaving_Pixel:
406             break;
407           }
408           // compute the Uninterleaving in the sub-rectangle
409           if (Toolkit_UnInterleave ((Pixel *)(ptrPix), dest, pixWidth, pixHeight, bufWidth, bufHeight)) {
410             FastDeleteArray(dest,Pixel);
411             return FPX_COLOR_CONVERSION_ERROR;  // error converting pixel buffer according to user's options
412           }
413         } else {
414           // The buffer contain only the active channel
415           // we must copy only this channel to the temporary buffer to send to the image file
416 
417           ptrPix = (unsigned char *)(pix);
418           ptrPix += (subY0-y0)*pixWidth + (subX0-x0);
419           ptrDest = dest;
420           for (i=subY0;i<=subY1;i++,ptrDest+=bufWidth,ptrPix+=pixWidth ) {
421             src = ptrPix;
422             dst = (unsigned char *)(ptrDest)  + plan;
423             for (j=subX0; j<=subX1;j++,src++,dst+=sizeof(Pixel))
424               *dst = *src;
425           }
426         }
427         // write the temporary buffer in the image file
428         status = subImages[resolution]->WriteRectangle (subX0, subY0, subX1, subY1, dest, plan);
429         if (status) {
430           FastDeleteArray(dest,Pixel);
431           return status;
432         }
433       }
434     }
435 
436     FastDeleteArray(dest,Pixel);
437     dest = NULL;
438   }
439   return status;
440 
441 }
442 
443 
444 //  ----------------------------------------------------------------------------
445 // To generate the hierarchy, we just have to generate the high res: because of the recursive
446 // nature of the DecimateTile() function, this will automatically decimate all the sub resolutions.
447 // Note that this routine does not ensure that modified tiles are written to the file.
448 // After this call returns, there may still be cached, modified tiles in memory.
RegenerateHierarchy()449 FPXStatus PHierarchicalImage::RegenerateHierarchy ()
450 {
451   FPXStatus err = FPX_OK;
452 
453   // Required to have the recursion working
454   SetAutomaticDecimation(true);
455 
456   // Save any changes to the full resolution's tiles and then decimate it's tiles.
457   if (firstSubImage) {
458     err = firstSubImage->FlushModifiedTiles();
459     if (err == FPX_OK)
460       err = firstSubImage->DecimateLevel();
461   }
462   else
463     err = FPX_ERROR;
464 
465   return err;
466 }
467 
468 
469 //  ----------------------------------------------------------------------------
470 // Read a rectangle in the correct resolution level and fill 'pix' with it
ReadRectangle(int x0,int y0,int x1,int y1,Pixel * pix,int resolution)471 FPXStatus PHierarchicalImage::ReadRectangle (int x0, int y0, int x1, int y1, Pixel* pix, int resolution)
472 {
473   FPXStatus status = FPX_OK;
474   FPXStatus   currentStatus;
475 
476   if (resolution == -1)
477     resolution = 0;
478   if (GtheSystemToolkit->interleaving == Interleaving_Pixel)
479     status = subImages[resolution]->ReadRectangle (x0, y0, x1, y1, pix);
480   else {
481     // Cut the rectangle in sub-rectangles to avoid to create a big buffer in memory
482     // when converting the interleaving.
483     // These sub-rectangles have the size of a tile because it's optimum.
484     int pixWidth = (x1 - x0 + 1);    // width of the buffer 'pix'
485     int pixHeight = (y1 - y0 + 1);   // height of the buffer 'pix'
486     Pixel*  source = NULL;      // temporary buffer
487     Pixel*  ptrSource = NULL;
488     int subX0, subY0, subX1, subY1;  // corners of the temporary buffer
489     int bufSize = 0;         // size of temporary buffer
490     int bufWidth, bufHeight;     // width ans height of temporary buffer
491     register int i, j;
492     register unsigned char *src, *dst, *ptrPix;
493 
494     short plan = Toolkit_ActiveChannel();
495     int incrRow = tileWidth;
496     int incrCol = tileWidth;
497     for (subY0 = y0; subY0 <= y1; subY0+=incrRow) {
498       subY1 = subY0 + incrRow-1;
499       if (subY1 > y1) subY1 = y1;
500       bufHeight = subY1 - subY0 +1;
501       for (subX0 = x0; subX0 <= x1; subX0+=incrCol) {
502         subX1 = subX0 + incrCol-1;
503         if (subX1 > x1) subX1 = x1;
504         bufWidth = subX1 - subX0 +1;
505         if (bufSize != (bufWidth*bufHeight)) {
506           bufSize = bufWidth*bufHeight;
507           FastDeleteArray(source, Pixel);
508           FastAllocArray(source, Pixel, bufSize);
509           if (!source)
510             return FPX_MEMORY_ALLOCATION_FAILED;
511         }
512         assert(source);
513         // read a sub rectangle in Pixel
514         currentStatus = subImages[resolution]->ReadRectangle (subX0, subY0, subX1, subY1, source);
515         if (currentStatus)
516           status = currentStatus;
517         if (status != FPX_MEMORY_ALLOCATION_FAILED) {
518           if ((GtheSystemToolkit->interleaving != Interleaving_Channel) || (plan == ActiveChannel_All)) {
519             if (Toolkit_Interleave (source, bufWidth, bufHeight))
520               status = FPX_MEMORY_ALLOCATION_FAILED;
521             else if (Toolkit_CopyInterleaved (pix, pixWidth, pixHeight,
522                                               source, bufWidth, bufHeight, subX0-x0, subY0-y0))
523               status = FPX_MEMORY_ALLOCATION_FAILED;
524           } else {
525             // Pixel by pixel if planes specified, the destination contains only the choosen channel
526             ptrPix  = (unsigned char *)(pix);
527             ptrPix += (subY0-y0)*pixWidth + (subX0-x0);
528             ptrSource = source;
529             for (i = subY0; i <= subY1; i++, ptrSource += bufWidth, ptrPix += pixWidth ) {
530               src = (unsigned char *)(ptrSource)  + plan;
531               dst = ptrPix;
532               for (j = subX0; j <= subX1; j++, src += sizeof(Pixel), dst++)
533                 *dst = *src;
534             }
535           }
536         }
537         if (status == FPX_MEMORY_ALLOCATION_FAILED) {
538           FastDeleteArray(source,Pixel);
539           return status;
540         }
541 
542       }
543     }
544     FastDeleteArray(source,Pixel);
545     source = NULL;
546   }
547   return status;
548 }
549 
550 
551 //  ----------------------------------------------------------------------------
552 // Read the path from the Image file: this function has to be derived to really write the things in
553 // the file. The following code handle only the memory management part.
ReadPaths(data_Record ** thePath,int * nbRecords,int * theClipPathNum)554 OSErr PHierarchicalImage::ReadPaths (data_Record** thePath, int* nbRecords, int* theClipPathNum)
555 {
556   return PRIImage::ReadPaths (thePath, nbRecords, theClipPathNum);
557 }
558 
559 
560 //  ----------------------------------------------------------------------------
561 // Write the path in the Image file: this function has to be derived to really write the things in
562 // the file. The following code handle only the memory management part.
WritePaths(data_Record * thePath,int nbRecords,int theClipPathNum)563 OSErr PHierarchicalImage::WritePaths (data_Record*  thePath, int  nbRecords, int  theClipPathNum)
564 {
565   OSErr  err = noErr;
566 
567   // Release the old path if any
568   ReleasePaths ();
569 
570   // Store the new path info
571   nbPaths   = nbRecords;
572   clipPathNum = theClipPathNum;
573 
574   // Allocate the intermediate path buffer
575   if ((path = new data_Record [nbPaths]) == NULL) {
576     err = memFullErr;   // error : can't reserve buffer
577     goto end;
578   }
579 
580   // Copy the given paths into the allocated path buffer
581   BlockMove(thePath,path,nbPaths*sizeof(data_Record));
582 
583  end:
584   if (err != noErr)
585     // If error, clean everything before exit
586     ReleasePaths ();
587   return err;
588 }
589 
590 
591 //  ----------------------------------------------------------------------------
Read4Points(int x0,int y0,int x1,int y1,int x2,int y2,int x3,int y3,Pixel * table,int levelSubImage)592 FPXStatus PHierarchicalImage::Read4Points (int x0, int y0, int x1, int y1, int x2, int y2, int x3, int y3, Pixel* table, int levelSubImage)
593 {
594   FPXStatus status = FPX_OK;        // Returned value
595   int    dx, dy;
596   int    n;
597   int    px[16], py[16];
598 
599 
600   dx = x1 - x0;
601   dy = y1 - y0;
602 
603   // Compute sub-image level
604   if (levelSubImage != -1)
605     n = levelSubImage;
606   else
607     n = Toolkit_Log2((((dx < 0 ? -dx:dx) + (dy < 0 ? -dy:dy)) >> 14) & 0x3ff); // (14 = 12 + 2) PARAM_ECHELLE_VUE;
608   // CHG_FIX_FLAT_TNAIL - if a non-hierarchical image is being created, then isFlatFile has
609   //    not been initialized, so it is misleading. However, if we're creating, then the
610   //    nbCreatedResolutions is 1. nbCreatedResolutions is set properly for reads and
611   //    creates, so it was added to the following test to ensure that we render using a
612   //    valid resoltion.
613   if(isFlatFile || (((PFileFlashPixIO*)this)->GetNumCreatedResolutions() == 1))
614     n = 0;
615   if (nbSubImages) {          // If image has been successfully opened (else, file is missing)
616     if (PRIImage::readInterpolated) {
617       if (n >= nbSubImages)
618         n = nbSubImages - 1;
619       if (n) {
620         x3 >>= n; y3 >>= n;
621         x2 >>= n; y2 >>= n;
622         x1 >>= n; y1 >>= n;
623         x0 >>= n; y0 >>= n;
624       }
625 
626       // Shift by half a pixel toward top left corner (origin): necessary to avoid misregistration when switching
627       // between with and without interpolation (classic difference between discrete and continuous coordinates)
628       x0 -= 2048; y0 -= 2048;   // Coordinates are with 12 bits precision, so 1 pixel = 4096 units...
629       x1 -= 2048; y1 -= 2048;
630       x2 -= 2048; y2 -= 2048;
631       x3 -= 2048; y3 -= 2048;
632 
633       px[P00] = x0 >> 4;          py[P00] = y0 >> 4;
634       dx = (x0+x3) >>1;         dy = (y0+y3) >>1;
635       px[P22] = dx >>4;         py[P22] = dy >>4;
636       px[P11] = (x0+dx)>>5;       py[P11] = (y0+dy)>>5;
637       px[P33] = (x3+dx)>>5;       py[P33] = (y3+dy)>>5;
638       px[P31] = (x1+dx)>>5;       py[P31] = (y1+dy)>>5;
639       px[P13] = (x2+dx)>>5;       py[P13] = (y2+dy)>>5;
640 
641       px[P32] = ((x3 += (x0 + x3)) + x1) >> 6;  py[P32] = ((y3 += (y0 + y3)) + y1) >> 6;
642       px[P23] = (x3 + x2) >> 6;   py[P23] = (y3 + y2) >> 6;
643 
644       x3 = (x0 + x1) >> 1;        y3 = (y0 + y1) >> 1;
645       px[P20] = x3 >> 4;          py[P20] = y3 >> 4;
646       px[P21] = (x3+dx)>>5;       py[P21] = (y3+dy)>>5;
647       px[P10] = (x0+x3)>>5;       py[P10] = (y0+y3)>>5;
648       px[P30] = (x1+x3)>>5;       py[P30] = (y1+y3)>>5;
649 
650       x3 = (x0 + x2) >> 1;        y3 = (y0 + y2) >> 1;
651       px[P02] = x3 >> 4;          py[P02] = y3 >> 4;
652       px[P12] = (x3+dx)>>5;       py[P12] = (y3+dy)>>5;
653       px[P01] = (x0+x3)>>5;       py[P01] = (y0+y3)>>5;
654       px[P03] = (x2+x3)>>5;       py[P03] = (y2+y3)>>5;
655 
656       status = subImages[n]->ReadInterpolated (px, py, table);
657     }
658     else {
659       if (n >= nbSubImages)
660         n = nbSubImages - 1;
661       if (n) {
662         x3 >>= n; y3 >>= n;
663         x2 >>= n; y2 >>= n;
664         x1 >>= n; y1 >>= n;
665         x0 >>= n; y0 >>= n;
666       }
667 
668       px[P00] = x0 >> 12;         py[P00] = y0 >> 12;
669       dx = (x0+x3) >>1;         dy = (y0+y3) >>1;
670       px[P22] = dx >>12;          py[P22] = dy >>12;
671       px[P11] = (x0+dx)>>13;        py[P11] = (y0+dy)>>13;
672       px[P33] = (x3+dx)>>13;        py[P33] = (y3+dy)>>13;
673       px[P31] = (x1+dx)>>13;        py[P31] = (y1+dy)>>13;
674       px[P13] = (x2+dx)>>13;        py[P13] = (y2+dy)>>13;
675 
676       px[P32] = ((x3 += (x0 + x3)) + x1) >> 14; py[P32] = ((y3 += (y0 + y3)) + y1) >> 14;
677       px[P23] = (x3 + x2) >> 14;    py[P23] = (y3 + y2) >> 14;
678 
679       x3 = (x0 + x1) >> 1;        y3 = (y0 + y1) >> 1;
680       px[P20] = x3 >> 12;         py[P20] = y3 >> 12;
681       px[P21] = (x3+dx)>>13;        py[P21] = (y3+dy)>>13;
682       px[P10] = (x0+x3)>>13;        py[P10] = (y0+y3)>>13;
683       px[P30] = (x1+x3)>>13;        py[P30] = (y1+y3)>>13;
684 
685       x3 = (x0 + x2) >> 1;        y3 = (y0 + y2) >> 1;
686       px[P02] = x3 >> 12;         py[P02] = y3 >> 12;
687       px[P12] = (x3+dx)>>13;        py[P12] = (y3+dy)>>13;
688       px[P01] = (x0+x3)>>13;        py[P01] = (y0+y3)>>13;
689       px[P03] = (x2+x3)>>13;        py[P03] = (y2+y3)>>13;
690       status = subImages[n]->Read(px,py,table);
691     }
692   } else
693     status = FPX_FILE_READ_ERROR;
694 
695   if (status != FPX_OK) {
696     // If the tile is missing, fill "table[]" with a chessboard pattern
697     Pixel* ptp = table;
698 
699     *ptp++ = 0x00000000; *ptp++ = 0x00000000; *ptp++ = 0xFFFFFFFF; *ptp++ = 0xFFFFFFFF;
700     *ptp++ = 0x00000000; *ptp++ = 0x00000000; *ptp++ = 0xFFFFFFFF; *ptp++ = 0xFFFFFFFF;
701     *ptp++ = 0xFFFFFFFF; *ptp++ = 0xFFFFFFFF; *ptp++ = 0x00000000; *ptp++ = 0x00000000;
702     *ptp++ = 0xFFFFFFFF; *ptp++ = 0xFFFFFFFF; *ptp++ = 0x00000000; *ptp++ = 0x00000000;
703   }
704 
705   return status;
706 }
707 
708 
709 //  ----------------------------------------------------------------------------
710 // Send back the smallest image contained in a rectangle width * height.
711 // Read it on disk if necessary.
712 // If decompressor is missing, send back NULL.
713 // CAUTION : bufferOut must be allocated and freed by calling routine
714 // CAUTION : we allocate a temporary buffer with pixelsPerLine*height pixels
ReadInARectangle(Pixel * bufferOut,short pixelsPerLine,short rectWidth,short rectHeight,const CorrectLut * correctLut,Boolean useAlphaChannel,const CombinMat * combinaisonMatrix)715 FPXStatus PHierarchicalImage::ReadInARectangle (Pixel* bufferOut, short pixelsPerLine, short rectWidth, short rectHeight,
716                   const CorrectLut* correctLut, Boolean useAlphaChannel, const CombinMat* combinaisonMatrix)
717 {
718   Pixel *bufferTemp, *ptrBufferTemp, *ptrBufferOut;
719   register int i;
720 
721   // allocate an intermediate buffer to read the rectangle
722   unsigned int size = (unsigned int)(pixelsPerLine * rectHeight);
723   FastAllocArray(bufferTemp,Pixel,size);
724   if (bufferTemp == NULL)
725     return FPX_MEMORY_ALLOCATION_FAILED;
726   ptrBufferTemp = bufferTemp;
727   ptrBufferOut = bufferOut;
728   for (i = 0; i < rectHeight; i++, ptrBufferTemp += pixelsPerLine, ptrBufferOut += pixelsPerLine )
729     memcpy(ptrBufferTemp, ptrBufferOut, pixelsPerLine*sizeof(Pixel));
730 
731   // search the corresponding sub-image and call 'ReadInARectangle()' on this sub-image
732   FPXStatus status = FPX_OK;
733   if (nbSubImages) {
734     i = 0;          // Start from the high resolution
735     int iWidth  = width; // Width  of the high res in pixels
736     int iHeight = height;  // Height of the high res in pixels
737     while ((iHeight >= rectHeight) && (iWidth >= rectWidth) && (i <= (nbSubImages-1))) {
738       iHeight = (iHeight + 1)/2;
739       iWidth  = (iWidth  + 1)/2;
740       i++;
741     }
742     if (i != 0)
743       i -= 1;
744     subImages[i]->ReadInARectangle(bufferTemp, pixelsPerLine, rectWidth, rectHeight, correctLut, useAlphaChannel, combinaisonMatrix);
745   }
746 
747   short plan = Toolkit_ActiveChannel();
748   if ((plan != ActiveChannel_All) && (GtheSystemToolkit->interleaving == Interleaving_Channel)) {
749     // Copy Pixel by pixel if planes specified, the destination contains only the choosen channel
750     register int j;
751     register unsigned char *src, *dst, *ptrCharBufferOut;
752     ptrCharBufferOut = (unsigned char *)(bufferOut);
753     for (i = 0; i < rectHeight; i++, bufferTemp += pixelsPerLine, ptrCharBufferOut += pixelsPerLine ) {
754       src = (unsigned char *)(bufferTemp)  + plan;
755       dst = ptrCharBufferOut;
756       for (j = 0; j < pixelsPerLine; j++, src += sizeof(Pixel), dst++)
757         *dst = *src;
758     }
759   } else {
760     // copy the buffer line by line
761     ptrBufferTemp = bufferTemp;
762     ptrBufferOut = bufferOut;
763     for (i = 0; i < rectHeight; i++, ptrBufferTemp += pixelsPerLine, ptrBufferOut += pixelsPerLine )
764       memcpy(ptrBufferOut, ptrBufferTemp, pixelsPerLine*sizeof(Pixel));
765     // interleave according to user's option
766     if (GtheSystemToolkit->interleaving != Interleaving_Pixel)
767       if (Toolkit_Interleave (bufferOut, pixelsPerLine, rectHeight))
768         status = FPX_MEMORY_ALLOCATION_FAILED;
769   }
770   FastDeleteArray(bufferTemp,Pixel);
771   return status;
772 }
773 
774 
775 //  ----------------------------------------------------------------------------
776 // Read size of full resolution image and size of tiles
GetInfo(int * width,int * height,int * tileWidth,int * tileHeight,Typ_Compression * compr)777 FPXStatus PHierarchicalImage::GetInfo (int* width, int* height, int* tileWidth, int* tileHeight, Typ_Compression* compr)
778 {
779   *width  = this->width;
780   *height = this->height;
781   *tileWidth  = this->tileWidth;
782   *tileHeight = this->tileWidth;
783   *compr  = this->compression;
784 
785   return FPX_OK;
786 }
787 
788 //  ----------------------------------------------------------------------------
GetTileSize(int * tileSize)789 FPXStatus PHierarchicalImage::GetTileSize (int* tileSize)
790 {
791   *tileSize = this->tileSize;
792   return FPX_OK;
793 }
794 
795 //  ----------------------------------------------------------------------------
GetCurrentFile()796 void* PHierarchicalImage::GetCurrentFile()
797 {
798   return filePtr;
799 }
800 
801 
802 //  ----------------------------------------------------------------------------
803 // Test if there is enough space on disk to create the file
804 // Prompt the user if not
EnoughDiskSpace()805 Boolean PHierarchicalImage::EnoughDiskSpace ()
806 {
807   Boolean enoughSpace = true;
808   int channelNumber;
809   float compressorRatio;
810   return true;
811 
812   channelNumber = GetNbChannel(baseSpace);
813 
814   switch (compression) {
815   case Compression_None:
816     compressorRatio = (float) 1.0;
817     break;
818   case Compression_NeoTech5:
819   case Compression_NeoTech15:
820   case Compression_NeoTech25:
821     compressorRatio =(float) 0.33;
822     break;
823   case Compression_QuickTime:
824     compressorRatio = (float) 0.33;
825     break;
826   case Compression_32to24:
827     if (existAlphaChannel)
828       compressorRatio =(float) 0.75;
829     else
830       compressorRatio = (float)1.0;
831     break;
832   case Compression_Other:
833     compressorRatio =(float) 0.33;
834     break;
835   default:
836     compressorRatio = (float) 1.0;
837     break;
838   }
839 
840   int size = (int) (((float)(width * height * channelNumber * compressorRatio * 4 / 3)/1024.0));
841 
842   enoughSpace = fileName.EnoughFreeSpace(size);
843 
844   return enoughSpace;
845 }
846 
847 
848 //  ----------------------------------------------------------------------------
849 // Set the Boolean existAlphaChannel and test if there is enougth space to use it
SetAlphaChannel(Boolean exist)850 Boolean PHierarchicalImage::SetAlphaChannel(Boolean exist)
851 {
852   PRIImage::SetAlphaChannel(exist);
853   return (ExistAlphaChannel() ? EnoughDiskSpace() : true);
854 }
855 
856 //  ----------------------------------------------------------------------------
857 // Set the decimation type when computing a subresolution
SetConvolution(Typ_Convolution newConvolution)858 void PHierarchicalImage::SetConvolution (Typ_Convolution newConvolution)
859 {
860   convolution = newConvolution;
861 }
862 
863 //  ----------------------------------------------------------------------------
SetAutomaticDecimation(Boolean automaticDecimationOn)864 void PHierarchicalImage::SetAutomaticDecimation (Boolean automaticDecimationOn)
865 {
866   automaticDecimation = automaticDecimationOn;
867 }
868 
869 //  ----------------------------------------------------------------------------
SetBackgroundColor(FPXBaselineColorSpace colorSpace,Pixel backgroundColor)870 void PHierarchicalImage::SetBackgroundColor (FPXBaselineColorSpace colorSpace, Pixel backgroundColor)
871 {
872   // Set the background color to the color passed in parameter
873   backgroundBase = backgroundColor;
874   backgroundUsed = backgroundColor;
875 
876   // Convert the passed color into the required color space
877   ConvertPixelBuffer ((unsigned char*)(&backgroundBase), 1, colorSpace, baseSpace);
878   ConvertPixelBuffer ((unsigned char*)(&backgroundUsed), 1, colorSpace, usedSpace);
879 }
880 
881 //  ----------------------------------------------------------------------------
SetUsedColorSpace(FPXBaselineColorSpace colorSpace)882 void PHierarchicalImage::SetUsedColorSpace (FPXBaselineColorSpace colorSpace)
883 {
884   // Convert the background color into the new used space
885   ConvertPixelBuffer ((unsigned char*)(&backgroundUsed), 1, usedSpace, colorSpace);
886   alphaOffset = (unsigned char) GetAlphaOffsetBaseline(colorSpace);
887   usedSpace   = colorSpace;
888 }
889 
890 //  ----------------------------------------------------------------------------
SetBaseColorSpace(FPXBaselineColorSpace colorSpace)891 void PHierarchicalImage::SetBaseColorSpace (FPXBaselineColorSpace colorSpace)
892 {
893   // Convert the background color into the new base space
894   ConvertPixelBuffer ((unsigned char*)(&backgroundBase), 1, baseSpace, colorSpace);
895   baseSpace = colorSpace;
896 }
897 
898 //  ----------------------------------------------------------------------------
InverseAlpha()899 FPXStatus PHierarchicalImage::InverseAlpha ()
900 {
901   for (int i = 0; i < nbSubImages; ++i)
902     subImages[i]->InverseAlpha();
903   return FPX_OK;
904 }
905 
906 
907 //  ----------------------------------------------------------------------------
908 // Read a pixel of a sub image. Read it on disk if necessary.
909 // If error, return false and pixel is set to 0.
910 // CAUTION : coordinates must be discrete with 12 bits precision (1 << 12).
ReadMean(int xi,int yi,Pixel & pix,int levelSubImage)911 FPXStatus PHierarchicalImage::ReadMean (int xi, int yi, Pixel& pix, int levelSubImage)
912 {
913   FPXStatus status = FPX_OK;
914 
915   if ((Status() == 0) && nbSubImages) {
916 
917     if (PRIImage::readInterpolated) {
918       // Conversion for ReadMeanInterpolated(): requires continuous coordinates with 8 bits precision
919       xi = (xi - 2048) >> 4;
920       yi = (yi - 2048) >> 4;
921       // Go to the next level for precision of interpolation
922       levelSubImage = (levelSubImage >= nbSubImages ? nbSubImages - 1 : levelSubImage - 1);
923       if (levelSubImage <= 0)
924         levelSubImage = 0;
925       // Read the pixel
926       status = subImages[levelSubImage]->ReadMeanInterpolated (xi >> levelSubImage, yi >> levelSubImage, pix);
927     } else {
928       // Conversion for ReadMean(): requires discrete coordinates with 0 bits precision
929       xi = xi >> 12;
930       yi = yi >> 12;
931       // Check level
932       if (levelSubImage >= nbSubImages)
933         levelSubImage = nbSubImages - 1;
934       if (levelSubImage <= 0)
935         levelSubImage = 0;
936       // Read the pixel
937       status = subImages[levelSubImage]->ReadMean (xi >> levelSubImage, yi >> levelSubImage, pix);
938     }
939 
940   } else
941     pix = backgroundUsed;
942 
943   return status;
944 }
945 
946 
947 //  ----------------------------------------------------------------------------
948 // Determine the dispersion of the alpha channel in a neighborhood: the idea is to compare the local value
949 // to the value of the same pixel on the next resolution level. Because of the convolution from a level to
950 // another, one can say that if the pixels are equal, there is no dispersion of the alpha channel, otherwise
951 // there is some. That way, we avoid effective dispersion computation.
952 // CAUTION : coordinates must be discrete with 12 bits precision (1 << 12).
DispersionAlphaChannel(int xNW,int yNW,int,int,int,int,int xSE,int ySE,int levelSubImage)953 Boolean PHierarchicalImage::DispersionAlphaChannel (int xNW,
954                                                     int yNW,
955                                                     int /*xNE*/,
956                                                     int /*yNE*/,
957                                                     int /*xSW*/,
958                                                     int /*ySW*/,
959                                                     int xSE,
960                                                     int ySE,
961                                                     int levelSubImage)
962 {
963   Boolean dispersion = false;
964 
965   if ((Status() == 0) && nbSubImages) {
966 
967     /*    The following is the full dispersion algorithm. More computation but less I/O...
968 
969     Pixel pix[16];
970     // Read the sample
971     Boolean status = Read4Points(xNW, yNW, xNE, yNE, xSW, ySW, xSE, ySE, pix, levelSubImage);
972 
973     if (status) {
974                 // Compute the dispersion with the usual algorithm (see CommandeQ2.cp for explanation)
975                 unsigned char alphaMax = pix[0].alpha;
976                 unsigned char alphaMin = pix[0].alpha;
977                 for (long i = 1; i < 16; ++i) {
978                 alphaMax &= pix[i].alpha;
979                 alphaMin |= pix[i].alpha;
980                 }
981                 dispersion = (alphaMin ^ alphaMax);
982 
983                 if (!dispersion) {
984         // Check if we are on the border to avoid interpolation with the outside of the image
985         Boolean onBorder = false;
986         if (levelSubImage < 0)
987                                 levelSubImage = 0;
988         if (levelSubImage >= nbSubImages)
989                                 levelSubImage = nbSubImages - 1;
990         long shift = levelSubImage + 12;
991         onBorder |= subImages[levelSubImage]->IsOnTheBorder(xNW >> shift, yNW >> shift);
992         onBorder |= subImages[levelSubImage]->IsOnTheBorder(xNE >> shift, yNE >> shift);
993         onBorder |= subImages[levelSubImage]->IsOnTheBorder(xSW >> shift, ySW >> shift);
994         onBorder |= subImages[levelSubImage]->IsOnTheBorder(xSE >> shift, ySE >> shift);
995         if (onBorder)
996                                 dispersion = !(alphaMax == 0);
997                                 }
998                                 }
999     */
1000     // Compute central point (>>1) and convert for ReadMean() (>>12)
1001     // ReadMean() requires discrete coordinates with 0 bits precision
1002     long xi = (xNW + xSE) >> 13;
1003     long yi = (yNW + ySE) >> 13;
1004 
1005     // Determine the levels to be compared: the two levels are 2 levels apart to check the
1006     // stability on a 9x9 neighborhood.
1007     long nextLevel;
1008 
1009     levelSubImage = levelSubImage - 1;
1010     if (levelSubImage >= (nbSubImages - 2))
1011       levelSubImage = nbSubImages - 3;
1012     if (levelSubImage < 0)
1013       levelSubImage = 0;
1014     nextLevel = levelSubImage + 2;
1015     if (nextLevel >= nbSubImages)
1016       nextLevel = nbSubImages - 1;
1017 
1018     if (levelSubImage != nextLevel) {
1019       // Read the pixels in each level
1020       Pixel pix0, pix1;
1021       Boolean status  = subImages[levelSubImage]->ReadMean (xi >> levelSubImage, yi >> levelSubImage, pix0);
1022       status &= subImages[nextLevel]->ReadMean (xi >> nextLevel, yi >> nextLevel, pix1);
1023 
1024       // Compare them and estimate the dispersion value
1025       dispersion = status && !(pix0.alpha == pix1.alpha);
1026 
1027       // Comparision for the border pixels: the alpha channel outside the image is supposed to be null, so
1028       // if the pixel is on the border and is not null, there is a dispersion with the outside of the image.
1029       dispersion |= ((subImages[nextLevel]->IsOnTheBorder(xi >> nextLevel, yi >> nextLevel)) && pix1.alpha);
1030     }
1031   }
1032 
1033   return dispersion;
1034 }
1035 
1036 
1037 //  ----------------------------------------------------------------------------
1038 // Read a rectangle (x0,y0,x1,y1: coordinates at full resolution) in a map
1039 // The correct sub image is read and sampled in order to fill the map with the rectangle
1040 // CAUTION : map must be allocated and freed by calling routine
ReadSampledRectangle(int x0,int y0,int x1,int y1,Pixel * map,short pixelsPerLine,int mapWidth,int mapHeight,Boolean showAlphaChannel,float ratio)1041 FPXStatus PHierarchicalImage::ReadSampledRectangle(int x0, int y0, int x1, int y1, Pixel* map, short pixelsPerLine, int mapWidth, int mapHeight, Boolean showAlphaChannel, float ratio)
1042 {
1043 
1044   if (ratio == 0.0){
1045     if (mapWidth <= MIN((float) mapHeight,(float) (x1-x0),(float) (y1-y0)) ) {
1046       if ( ABS(float(float(mapWidth) - float(x1-x0)*float(mapHeight)/float(y1-y0))) > 1.0) {
1047         assert (false);
1048         return FPX_BAD_COORDINATES;
1049       }
1050     } else if (mapHeight <= MIN((float) mapWidth,(float) (x1-x0),(float) (y1-y0)) ) {
1051       if ( ABS(float(float(mapHeight) - float(y1-y0)*float(mapWidth)/float(x1-x0))) > 1.0) {
1052         assert (false);
1053         return FPX_BAD_COORDINATES;
1054       }
1055     } else if (x1-x0 <= MIN((float) mapWidth,(float) mapHeight,(float) (y1-y0)) ) {
1056       if ( ABS(float(float(x1-x0) - float(mapWidth)*float(y1-y0)/float(mapHeight))) > 1.0) {
1057         assert (false);
1058         return FPX_BAD_COORDINATES;
1059       }
1060     } else if (y1-y0 <= MIN((float) mapWidth,(float) (x1-x0),(float) mapHeight) ) {
1061       if ( ABS(float(float(y1-y0) - float(mapHeight)*float(x1-x0)/float(mapWidth))) > 1.0 ) {
1062         assert (false);
1063         return FPX_BAD_COORDINATES;
1064       }
1065     }
1066     ratio = MIN(float(float(mapWidth)/float(x1 - x0)) , float(float(mapHeight)/float(y1 - y0)));
1067   }
1068 
1069   if (nbSubImages) {
1070     long i;
1071 
1072     for (i = nbSubImages-1; i>0; --i)
1073       if ((subImages[i]->realHeight >= FLOAT_TO_LONG(float(height) * ratio)) && (subImages[i]->realWidth >= FLOAT_TO_LONG(float(width) * ratio)))
1074         break;
1075 
1076     // compute the coordinates in the choosed sub image
1077     if (i) {
1078       x1 >>= i; y1 >>= i;
1079       x0 >>= i; y0 >>= i;
1080       ratio *= (float) (pow(2,(double) i));
1081     }
1082 
1083     // read the rectangle in the correct sub image
1084     return subImages[i]->ReadSampledRectangle(x0, y0,x1, y1, map, pixelsPerLine, mapWidth, mapHeight, showAlphaChannel, ratio);
1085   }
1086   return FPX_OK;
1087 }
1088 
1089 
1090 //  ----------------------------------------------------------------------------
1091 // Search the top and left corner of the screen pixel which contains the given position
1092 // This function is used when 1 image pixel is represented by more than 1 screen pixel
SearchPixelTopLeftCorner(int * x1,int * y1,float ratio)1093 FPXStatus PHierarchicalImage::SearchPixelTopLeftCorner(int* x1, int* y1, float ratio)
1094 {
1095   if (nbSubImages) {
1096     long i;
1097     for (i = nbSubImages-1; i>0; --i)
1098       if ((subImages[i]->realHeight >= FLOAT_TO_LONG(float(height) * ratio)) && (subImages[i]->realWidth >= FLOAT_TO_LONG(float(width) * ratio)))
1099         break;
1100 
1101     // compute the coordinates in the choosed sub image
1102     if (i)
1103       ratio *= (float) (pow(2,(double) i));
1104 
1105     // read the rectangle in the correct sub image
1106     return subImages[i]->SearchPixelTopLeftCorner(x1, y1, ratio);
1107   }
1108   return FPX_ERROR;
1109 }
1110 
1111 
1112 //  ----------------------------------------------------------------------------
1113 // Compute histogram for the 4 channels
GetHistogram(int * alpha,int * red,int * green,int * blue,int * brightness,const CorrectLut * correctLut)1114 FPXStatus PHierarchicalImage::GetHistogram (int* alpha, int* red, int* green, int* blue, int* brightness, const CorrectLut* correctLut)
1115 {
1116   FPXStatus status = FPX_OK;
1117 
1118   if (Status() == 0 && nbSubImages)
1119     // Compute only on the last sub-image�
1120     status = subImages[nbSubImages-1]->GetHistogram (alpha, red, green, blue, brightness, correctLut);
1121   else
1122     status = FPX_ERROR;
1123 
1124   return status;
1125 }
1126 
1127 //  ----------------------------------------------------------------------------
1128 // Make a sub resolution level in create mode
CreateEmptyResolutionLevel(int,int,int *)1129 PResolutionLevel* PHierarchicalImage::CreateEmptyResolutionLevel(int , int , int*)
1130 {
1131   return NULL;
1132 }
1133 
1134 //  ----------------------------------------------------------------------------
1135 // Make a sub resolution level in read or write mode
CreateInitResolutionLevel(int *,long int)1136 PResolutionLevel* PHierarchicalImage::CreateInitResolutionLevel(int* , long int)
1137 {
1138   return NULL;
1139 }
1140 
1141 //  ----------------------------------------------------------------------------
1142 // Make a resolution list in read or write mode and initialize it
1143 // Set the field 'error' and return it
CreateInitResolutionLevelList()1144 FPXStatus PHierarchicalImage::CreateInitResolutionLevelList()
1145 {
1146   return FPX_OK;
1147 }
1148 
1149 //  ----------------------------------------------------------------------------
1150 // Make a resolution list in create mode
CreateEmptyResolutionLevelList()1151 FPXStatus PHierarchicalImage::CreateEmptyResolutionLevelList()
1152 {
1153   return FPX_OK;
1154 }
1155 
1156 //  ----------------------------------------------------------------------------
1157 // Create the "subImages" array of pointers according to the "firstSubImage" list
InitResolutionLevelsTable()1158 FPXStatus PHierarchicalImage::InitResolutionLevelsTable()
1159 {
1160   PResolutionLevel* img;
1161   long i;
1162 
1163   // if (nbSubImages == 0) -> the PHierarchicalImage is invalid or impossible to open
1164   if (nbSubImages) {
1165     subImages = new PResolutionLevel*[nbSubImages];
1166     if (subImages)
1167       for (i = 0, img = firstSubImage; i < nbSubImages; i++, img = img->next)
1168         subImages[i] = img;
1169     else {
1170       nbSubImages = 0;
1171     }
1172   } else {
1173     // Invalid the PHierarchicalImage
1174     subImages   = NULL;
1175     nbSubImages = 0;
1176   }
1177 
1178   return FPX_OK;
1179 }
1180 
1181 
1182 //  ----------------------------------------------------------------------------
1183 //  External functions used by C code :
1184 //  This is the interface of the Standard Toolkit
1185 //  ----------------------------------------------------------------------------
DeleteGlobalArrays()1186 static Boolean DeleteGlobalArrays ()
1187 {
1188   return tousLesCodecs->Purge();
1189 }
1190 
1191 
1192 //  ----------------------------------------------------------------------------
DemandeMemoireUrgente(long,long size)1193 Boolean DemandeMemoireUrgente (long , long size)
1194 {
1195 #ifdef Memoire_Debug
1196   // FOR DEBUG PURPOSE
1197   VISU2 "ENTER IN DEMANDEMEMOIREURGENTE()\n" FIN
1198     VISU2 "Memory requested : %d\n", size FIN
1199     TraceMemoire();
1200   // END DEBUG PURPOSE
1201 #endif
1202   Boolean aPurge        = false;
1203   Boolean aPurgeImage     = false;
1204   Boolean aPurgeLockedImage = false;
1205   Boolean aPurgeCompress    = false;
1206   long  amountNowFree;
1207   long  remain = size;
1208 
1209   // Free any tiles not accessed within the last 5 minutes. The hope is that this will
1210   //  free-up clumps of blocks (i.e., tiles) from a resolution no longer being displayed, etc.
1211   PTile::FreeAncientBuffers( 2);
1212   GtheSystemToolkit->AvailableMemory (&amountNowFree);
1213 
1214   // For each iteration of the folowing loop, free the oldest, unlocked buffer used to hold
1215   //  a tile's 'pixels' or 'rawPixels'
1216   PTile *foundTile;
1217   long  isRawPixelsBuffer;
1218 
1219   while ((amountNowFree < size)
1220    &&   (PTile::FindOldestTileBuffer( &foundTile, &isRawPixelsBuffer) == 0)) {
1221     if (isRawPixelsBuffer)
1222       foundTile->FreeRawPixelsBuffer( );
1223     else
1224       foundTile->FreePixelsBuffer( );
1225 
1226     GtheSystemToolkit->AvailableMemory (&amountNowFree);
1227   }
1228 
1229   if (amountNowFree > size)
1230     return true;
1231 
1232   // Still need more. Purge unlocked image blocks
1233   PTile::Purge(&remain, 0);
1234   aPurgeImage = (remain != size ? true : false);
1235   aPurge = aPurgeImage || aPurge;
1236 
1237   // Purge locked Image if necessary
1238   if (!aPurge) {
1239     GtheSystemToolkit->LockImage(NULL);
1240     PTile::Purge(&remain);
1241     aPurgeLockedImage = (remain != size ? true : false);
1242   }
1243   aPurge = aPurge || aPurgeLockedImage;
1244 
1245   // Delete global arrays if nothing else to purge
1246   if (!aPurge)
1247     aPurgeCompress = DeleteGlobalArrays ();
1248   aPurge = aPurgeCompress || aPurge;
1249 
1250 #ifdef Memoire_Debug
1251   // FOR DEBUG PURPOSE
1252   if (aPurgeImage) {
1253     VISU2 "Image purged\n" FIN
1254       } else {
1255         VISU2 "Image NOT PURGED\n" FIN
1256           }
1257   if (aPurgeLockedImage) {
1258     VISU2 "Locked Image purged\n" FIN
1259       } else {
1260         VISU2 "Locked Image NOT PURGED\n" FIN
1261           }
1262   if (aPurgeCompress) {
1263     VISU2 "Global arrays purged\n" FIN
1264       } else {
1265         VISU2 "GLOBAL ARRAYS NOT PURGED\n" FIN
1266           }
1267   TraceMemoire();
1268   PrintAllocatedMemoryStat();
1269   VISU2 "Exit status = " FIN
1270     if (!aPurge) {
1271       VISU2 "Error, DemandeMemoireUrgente FAILED\n" FIN
1272   } else {
1273           VISU2 "OK\n" FIN
1274             }
1275   VISU2 "Exit of DemandeMemoireUrgente()\n\n\n" FIN
1276     // END DEBUG PURPOSE
1277 #endif
1278 
1279     return aPurge;
1280 }
1281 
1282 
1283 //  - EOF ----------------------------------------------------------------------
1284