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