1 //  ----------------------------------------------------------------------------
2 //  MODULE    : PTile
3 //  LANGUAGE  : C++
4 //  CREATOR   : Philippe BOSSUT
5 //  CREAT. DATE : Wednesday, March 13, 1996
6 //  DESCRIPTION :
7 //      The PTile object provides the base behavior for individual tiles. It
8 //    also provides methods for handling lists of tiles which have pixel memory
9 //    allocated to them.
10 //      Not all behaviors are implemented here. For example, reading and writing
11 //    are in the PTileFlashPix object which is derived from PTile.
12 //  COMMENTS  :
13 //  MODIFIED  : 11/96   PBH   Rewrote memory allocation; added comments
14 //        : 2/26/97 PBH   PTCH_101 fixes buffer reuse bugs; adds debug calls
15 //  SCCSID      : @(#)ptile.cpp 1.5 15:15:42 14 Apr 1997
16 //  ----------------------------------------------------------------------------
17 //  Copyright (c) 1999 Digital Imaging Group, Inc.
18 //  For conditions of distribution and use, see copyright notice
19 //  in Flashpix.h
20 //  ----------------------------------------------------------------------------
21 
22 //  ----------------------------------------------------------------------------
23 
24 //  ----------------------------------------------------------------------------
25   #include "ptile.h"
26 //  ----------------------------------------------------------------------------
27 
28 
29 //  Includes
30 //  --------
31 
32 #ifndef Memoire_h
33   #include  "b_memory.h"
34 #endif
35 #ifndef Debug_h
36   #include  "debug.h"
37 #endif
38 #ifndef Numbers_h
39   #include  "numbers.h"
40 #endif
41 
42 #ifndef PHierarchicalImage_h
43   #include "ph_image.h"
44 #endif
45 #ifndef PResolutionLevel_h
46   #include "pr_level.h"
47 #endif
48 #ifndef PImageFile_h
49   #include "pimgfile.h"
50 #endif
51 
52 #ifndef PTileFlashPix_h
53   #include "ptil_fpx.h"
54 #endif
55 
56 #ifndef PResolutionFlashPix_h // PTCH_104 added #include required for code change
57   #include "pres_fpx.h"
58 #endif
59 
60 
61 
62 //  Constants
63 //  ---------
64 
65   #define SW 0
66   #define SE 1
67   #define NW 2
68   #define NE 3
69 
70 //  Variables
71 //  ---------
72 
73   unsigned char*  PTile::invertLUT  = NULL;     // static LUT of inverted values
74 
75   PTile*      PTile::first    = NULL;     // Head of linked-list of tiles that have memory
76   PTile*      PTile::last     = NULL;     // Tail of linked-list of tiles that have memory
77   PTile**     PTile::locked   = NULL;     // An array of ptrs to tiles that have been locked
78   long        PTile::indexLocked  = 0;    // Current index into the 'locked' array
79   long        PTile::allocSize  = 0;      // Accumulate used during Purge() of memory
80   long        PTile::allocTiles = 0;      // Debug use
81 
82   Ptr         PTile::decompressBuffer = NULL;
83   long        PTile::decompressSize = 0;
84   Boolean     PTile::decompressLock = false;
85 
86 
87 //  ----------------------------------------------------------------------------
88 //  Internal Functions
89 //  ----------------------------------------------------------------------------
90 
91 // 2x2 decimation:
92 //
93 //    pNW(1/4)    pNE(1/4)
94 //
95 //    pSW(1/4)    pSE(1/4)
96 //
97 
ConvolStandard(Pixel * source,long width,long height,Pixel * dest,long pixelsPerLine)98 static void ConvolStandard (Pixel* source, long width, long height, Pixel* dest, long pixelsPerLine)
99 
100 {
101   register Pixel *pt, *pSE, *pSW, *pNE, *pNW;
102   register long i, j, lineWidth;
103 
104   // Compute loop control values
105   long oddLine    = width & 0x01;
106   long halfWidth  = width  >> 1;
107   long halfHeight = height >> 1;
108 
109   // Initialize loop pointers
110   pt = dest;
111   lineWidth = pixelsPerLine - halfWidth;
112 
113   // Check and handle degenerated cases...
114   if ((halfWidth == 0) && (halfHeight == 0)) {
115     *pt = *source;
116   } else if (halfWidth == 0) {
117     for (j = 0; j < halfHeight; j++, pt += lineWidth, source += (2*width))
118       *pt = *source;
119   } else if (halfHeight == 0) {
120     for (i = 0; i < halfWidth; i++, pt++, source += 2)
121       *pt = *source;
122   } else {
123 
124     // Convolution loop
125     pSW = source;
126     pSE = pSW + 1;
127     pNW = pSW + width;
128     pNE = pNW + 1;
129     for (j = 0; j < halfHeight; j++, pt += lineWidth) {
130       for (i = 0; i < halfWidth; i++, pt++, pSW+=2, pSE+=2, pNW+=2, pNE+=2) {
131         pt->alpha = (pSW->alpha + pSE->alpha + pNW->alpha + pNE->alpha) >> 2;
132         pt->rouge = (pSW->rouge + pSE->rouge + pNW->rouge + pNE->rouge) >> 2;
133         pt->vert  = (pSW->vert  + pSE->vert  + pNW->vert  + pNE->vert)  >> 2;
134         pt->bleu  = (pSW->bleu  + pSE->bleu  + pNW->bleu  + pNE->bleu)  >> 2;
135       }
136       if (oddLine) {
137         pSW++; pSE++; pNW++; pNE++;
138       }
139       pSW+=width; pSE+=width; pNW+=width; pNE+=width;
140     }
141 
142   }
143 }
144 
145 // 4x4 decimation:
146 //
147 //    p11(1/4)    p12(1/2)    p13(1/2)    p14(1/4)
148 //
149 //    p21(1/2)     p22(1)      p23(1)     p24(1/2)
150 //
151 //    p31(1/2)     p32(1)      p33(1)     p34(1/2)
152 //
153 //    p41(1/4)    p42(1/2)    p43(1/2)    p44(1/4)
154 //
155 
156 #ifdef _WINDOWS
157   #pragma optimize ("", off)
158 #endif
159 
ConvolGaussian4(Pixel * source,long width,long height,Pixel * dest,long lineOffset)160 static void ConvolGaussian4 (Pixel* source, long width, long height, Pixel* dest, long lineOffset)
161 
162 {
163 #ifdef macintosh
164   #pragma global_optimizer off
165 #endif
166 
167   // Simplification when width or height too small for the kernel
168   if ((width < 6) || (height < 6)) {
169     ConvolStandard (source, width, height, dest, lineOffset);
170     return;
171   }
172 
173   Pixel *pt, *p11, *p12, *p13, *p14, *p21, *p22, *p23, *p24, *p31, *p32, *p33, *p34, *p41, *p42, *p43, *p44;
174   long i, j, lineWidth;
175 
176   // Compute loop control values
177   long oddLine    = width & 0x01;
178   long halfWidth  = width  >> 1;
179   long halfHeight = height >> 1;
180 
181   // Initialize loop pointers
182   pt = dest;
183   lineWidth = lineOffset-halfWidth;
184 
185   // Init center pointers
186   p22 = source;
187   p23 = p22 + 1;
188   p32 = p22 + width;
189   p33 = p32 + 1;
190 
191   // Top line
192   for (i=0; i<halfWidth; i++, pt++, p22+=2, p23+=2, p32+=2, p33+=2) {
193     pt->alpha = (p22->alpha + p23->alpha + p32->alpha + p33->alpha) >> 2;
194     pt->rouge = (p22->rouge + p23->rouge + p32->rouge + p33->rouge) >> 2;
195     pt->vert  = (p22->vert  + p23->vert  + p32->vert  + p33->vert)  >> 2;
196     pt->bleu  = (p22->bleu  + p23->bleu  + p32->bleu  + p33->bleu)  >> 2;
197   }
198 
199   // Next line
200   if (oddLine) {
201     p22++; p23++; p32++; p33++;
202   }
203   p22+=width, p23+=width, p32+=width, p33+=width;
204   pt += lineWidth;
205 
206   // Init edge and corner pointers
207   p12 = p22 - width; p11 = p12 - 1; p13 = p12 + 1; p14 = p12 + 2;
208   p21 = p22 - 1; p24 = p23 + 1;
209   p31 = p32 - 1; p34 = p33 + 1;
210   p42 = p32 + width; p41 = p42 - 1; p43 = p42 + 1; p44 = p42 + 2;
211 
212 
213   // For every line (except the bottom most one)
214   for (j=1; j<(halfHeight-1); j++, pt += lineWidth) {
215 
216     // Left pixel of the line
217     pt->alpha = (p22->alpha + p23->alpha + p32->alpha + p33->alpha) >> 2;
218     pt->rouge = (p22->rouge + p23->rouge + p32->rouge + p33->rouge) >> 2;
219     pt->vert  = (p22->vert  + p23->vert  + p32->vert  + p33->vert)  >> 2;
220     pt->bleu  = (p22->bleu  + p23->bleu  + p32->bleu  + p33->bleu)  >> 2;
221 
222     // Next pixel
223     pt++;
224     p11+=2; p12+=2; p13+=2; p14+=2;
225     p21+=2; p22+=2; p23+=2; p24+=2;
226     p31+=2; p32+=2; p33+=2; p34+=2;
227     p41+=2; p42+=2; p43+=2; p44+=2;
228 
229     // For every pixel (except the right most one)
230     for (i=1; i<(halfWidth-1); i++, pt++) {
231       pt->alpha  = (p22->alpha+p23->alpha+p32->alpha+p33->alpha +
232             ((p12->alpha+p13->alpha+p21->alpha+p24->alpha+p31->alpha+p34->alpha+p42->alpha+p43->alpha)>>1) +
233             ((p11->alpha+p14->alpha+p41->alpha+p44->alpha)>>2)) / 9;
234       pt->rouge  = (p22->rouge+p23->rouge+p32->rouge+p33->rouge +
235             ((p12->rouge+p13->rouge+p21->rouge+p24->rouge+p31->rouge+p34->rouge+p42->rouge+p43->rouge)>>1) +
236             ((p11->rouge+p14->rouge+p41->rouge+p44->rouge)>>2)) / 9;
237       pt->vert  = (p22->vert+p23->vert+p32->vert+p33->vert +
238             ((p12->vert+p13->vert+p21->vert+p24->vert+p31->vert+p34->vert+p42->vert+p43->vert)>>1) +
239             ((p11->vert+p14->vert+p41->vert+p44->vert)>>2)) / 9;
240       pt->bleu  = (p22->bleu+p23->bleu+p32->bleu+p33->bleu +
241             ((p12->bleu+p13->bleu+p21->bleu+p24->bleu+p31->bleu+p34->bleu+p42->bleu+p43->bleu)>>1) +
242             ((p11->bleu+p14->bleu+p41->bleu+p44->bleu)>>2)) / 9;
243       p11+=2; p12+=2; p13+=2; p14+=2;
244       p21+=2; p22+=2; p23+=2; p24+=2;
245       p31+=2; p32+=2; p33+=2; p34+=2;
246       p41+=2; p42+=2; p43+=2; p44+=2;
247     }
248 
249     // Right pixel of the line
250     if (oddLine) {
251       pt->alpha  = (p22->alpha+p23->alpha+p32->alpha+p33->alpha +
252             ((p12->alpha+p13->alpha+p21->alpha+p24->alpha+p31->alpha+p34->alpha+p42->alpha+p43->alpha)>>1) +
253             ((p11->alpha+p14->alpha+p41->alpha+p44->alpha)>>2)) / 9;
254       pt->rouge  = (p22->rouge+p23->rouge+p32->rouge+p33->rouge +
255             ((p12->rouge+p13->rouge+p21->rouge+p24->rouge+p31->rouge+p34->rouge+p42->rouge+p43->rouge)>>1) +
256             ((p11->rouge+p14->rouge+p41->rouge+p44->rouge)>>2)) / 9;
257       pt->vert  = (p22->vert+p23->vert+p32->vert+p33->vert +
258             ((p12->vert+p13->vert+p21->vert+p24->vert+p31->vert+p34->vert+p42->vert+p43->vert)>>1) +
259             ((p11->vert+p14->vert+p41->vert+p44->vert)>>2)) / 9;
260       pt->bleu  = (p22->bleu+p23->bleu+p32->bleu+p33->bleu +
261             ((p12->bleu+p13->bleu+p21->bleu+p24->bleu+p31->bleu+p34->bleu+p42->bleu+p43->bleu)>>1) +
262             ((p11->bleu+p14->bleu+p41->bleu+p44->bleu)>>2)) / 9;
263       p11+=3; p12+=3; p13+=3; p14+=3;
264       p21+=3; p22+=3; p23+=3; p24+=3;
265       p31+=3; p32+=3; p33+=3; p34+=3;
266       p41+=3; p42+=3; p43+=3; p44+=3;
267       pt++;
268     } else {
269       pt->alpha = (p22->alpha + p23->alpha + p32->alpha + p33->alpha) >> 2;
270       pt->rouge = (p22->rouge + p23->rouge + p32->rouge + p33->rouge) >> 2;
271       pt->vert  = (p22->vert  + p23->vert  + p32->vert  + p33->vert)  >> 2;
272       pt->bleu  = (p22->bleu  + p23->bleu  + p32->bleu  + p33->bleu)  >> 2;
273       p11+=2; p12+=2; p13+=2; p14+=2;
274       p21+=2; p22+=2; p23+=2; p24+=2;
275       p31+=2; p32+=2; p33+=2; p34+=2;
276       p41+=2; p42+=2; p43+=2; p44+=2;
277       pt++;
278     }
279 
280     // Next line
281     p11+=width; p12+=width; p13+=width; p14+=width;
282     p21+=width; p22+=width; p23+=width; p24+=width;
283     p31+=width; p32+=width; p33+=width; p34+=width;
284     p41+=width; p42+=width; p43+=width; p44+=width;
285   }
286 
287   // Bottom line
288   for (i=0; i<halfWidth; i++, pt++, p22+=2, p23+=2, p32+=2, p33+=2) {
289     pt->alpha = (p22->alpha + p23->alpha + p32->alpha + p33->alpha) >> 2;
290     pt->rouge = (p22->rouge + p23->rouge + p32->rouge + p33->rouge) >> 2;
291     pt->vert  = (p22->vert  + p23->vert  + p32->vert  + p33->vert)  >> 2;
292     pt->bleu  = (p22->bleu  + p23->bleu  + p32->bleu  + p33->bleu)  >> 2;
293   }
294 
295 #ifdef macintosh
296   #pragma global_optimizer on
297 #endif
298 }
299 
300 #ifdef _WINDOWS
301   #pragma optimize ("", on)
302 #endif
303 
304 #if 0
305 // 3x3 decimation: non standard in FlashPix
306 //
307 //    pNW(1/4)     pN(1/2)    pNE(1/4)
308 //
309 //    pW(1/2)        pC(1)        pE(1/2)
310 //
311 //    pSW(1/2)     pS(1/2)    pSE(1/4)
312 //
313 //
314 
315 static void ConvolGaussian3 (Pixel* source, long width, long height,
316                              Pixel* dest, long pixelsPerLine)
317 
318 {
319   // Simplification when width or height too small for the kernel
320   if ((width < 4) || (height < 4)) {
321     ConvolStandard (source, width, height, dest, pixelsPerLine);
322     return;
323   }
324 
325   register Pixel *pt, *pSE, *pSW, *pNE, *pNW, *pC, *pS, *pN, *pE, *pW;
326   long i, j, lineWidth;
327 
328   // Compute loop control values
329   long oddLine    = width & 0x01;
330   long halfWidth  = width  >> 1;
331   long halfHeight = height >> 1;
332 
333   // Initialize loop pointers
334   pt = dest;
335   lineWidth = pixelsPerLine - halfWidth;
336 
337   // Convolution loop
338   pC = source;
339   *pt++ = *pC;                                      // SW corner
340   pC += 2;
341   pW = pC - 1;
342   pE = pC + 1;
343   for (i=1; i<halfWidth; i++, pt++, pC+=2, pW+=2, pE+=2) {              // Southern line
344     pt->alpha = (pC->alpha + ((pE->alpha+pW->alpha)>>1) + (pC->alpha<<1)) >> 2;
345     pt->rouge = (pC->rouge + ((pE->rouge+pW->rouge)>>1) + (pC->rouge<<1)) >> 2;
346     pt->vert  = (pC->vert + ((pE->vert+pW->vert)>>1) + (pC->vert<<1)) >> 2;
347     pt->bleu  = (pC->bleu + ((pE->bleu+pW->bleu)>>1) + (pC->bleu<<1)) >> 2;
348   }
349   if (oddLine) {
350     pC++; pW++; pE++;
351   }
352   pC+=width; pW+=width; pE+=width;
353   pN = pC + width;
354   pNW = pN - 1;
355   pNE = pN + 1;
356   pS = pC - width;
357   pSW = pS - 1;
358   pSE = pS + 1;
359   pt += lineWidth;
360   for (j=1; j<halfHeight; j++, pt += lineWidth) {
361     pt->alpha = (pC->alpha + ((pN->alpha+pS->alpha)>>1) + (pC->alpha<<1)) >> 2;   // Western pixel of the line
362     pt->rouge = (pC->rouge + ((pN->rouge+pS->rouge)>>1) + (pC->rouge<<1)) >> 2;
363     pt->vert  = (pC->vert + ((pN->vert+pS->vert)>>1) + (pC->vert<<1)) >> 2;
364     pt->bleu  = (pC->bleu + ((pN->bleu+pS->bleu)>>1) + (pC->bleu<<1)) >> 2;
365     pt++; pC += 2; pN += 2; pS += 2; pE += 2; pW += 2; pSW += 2; pSE += 2; pNW += 2; pNE += 2;
366     for (i=1; i<halfWidth; i++) {
367       pt->alpha = (pC->alpha + ((pN->alpha+pS->alpha+pE->alpha+pW->alpha)>>1) + ((pNE->alpha+pSE->alpha+pNW->alpha+pSW->alpha)>>2)) >> 2;
368       pt->rouge = (pC->rouge + ((pN->rouge+pS->rouge+pE->rouge+pW->rouge)>>1) + ((pNE->rouge+pSE->rouge+pNW->rouge+pSW->rouge)>>2)) >> 2;
369       pt->vert  = (pC->vert + ((pN->vert+pS->vert+pE->vert+pW->vert)>>1) + ((pNE->vert+pSE->vert+pNW->vert+pSW->vert)>>2)) >> 2;
370       pt->bleu  = (pC->bleu + ((pN->bleu+pS->bleu+pE->bleu+pW->bleu)>>1) + ((pNE->bleu+pSE->bleu+pNW->bleu+pSW->bleu)>>2)) >> 2;
371       pt++; pC += 2; pN += 2; pS += 2; pE += 2; pW += 2; pSW += 2; pSE += 2; pNW += 2; pNE += 2;
372     }
373     if (oddLine) {
374       pC++; pN++; pS++; pW++; pE++; pSW++; pSE++; pNW++; pNE++;
375     }
376     pC+=width; pN+=width; pS+=width; pW+=width; pE+=width; pSW+=width; pSE+=width; pNW+=width; pNE+=width;
377   }
378 }
379 #endif
380 
381 // 3x3 decimation: non standard in FlashPix
382 //
383 //             pN(1/2)
384 //
385 //    pW(1/2)        pC(1)        pE(1/2)
386 //
387 //             pS(1/2)
388 //
389 //
390 
ConvolGaussSimplified(Pixel * source,long width,long height,Pixel * dest,long pixelsPerLine)391 static void ConvolGaussSimplified (Pixel* source, long width, long height, Pixel* dest, long pixelsPerLine)
392 
393 {
394   // Simplification when width or height too small for the kernel
395   if ((width < 4) || (height < 4)) {
396     ConvolStandard (source, width, height, dest, pixelsPerLine);
397     return;
398   }
399 
400   register Pixel *pt, *pC, *pS, *pN, *pE, *pW;
401   long i, j, lineWidth;
402 
403   // Compute loop control values
404   long oddLine    = width & 0x01;
405   long halfWidth  = width  >> 1;
406   long halfHeight = height >> 1;
407 
408   // Initialize loop pointers
409   pt = dest;
410   lineWidth = pixelsPerLine - halfWidth;
411 
412   // Convolution loop
413   pC = source;
414   *pt++ = *pC;                                        // SW corner
415   pC += 2;
416   pW = pC - 1;
417   pE = pC + 1;
418   for (i=1; i<halfWidth; i++, pt++, pC+=2, pW+=2, pE+=2) {              // Southern line
419     pt->alpha = (pC->alpha + ((pE->alpha+pW->alpha)>>1)) >> 1;
420     pt->rouge = (pC->rouge + ((pE->rouge+pW->rouge)>>1)) >> 1;
421     pt->vert  = (pC->vert + ((pE->vert+pW->vert)>>1)) >> 1;
422     pt->bleu  = (pC->bleu + ((pE->bleu+pW->bleu)>>1)) >> 1;
423   }
424   if (oddLine) {
425     pC++; pW++; pE++;
426   }
427   pC+=width; pW+=width; pE+=width;
428   pN = pC + width;
429   pS = pC - width;
430   pt += lineWidth;
431   for (j=1; j<halfHeight; j++, pt += lineWidth) {
432     pt->alpha = (pC->alpha + ((pN->alpha+pS->alpha)>>1)) >> 1;            // Western pixel of the line
433     pt->rouge = (pC->rouge + ((pN->rouge+pS->rouge)>>1)) >> 1;
434     pt->vert  = (pC->vert + ((pN->vert+pS->vert)>>1)) >> 1;
435     pt->bleu  = (pC->bleu + ((pN->bleu+pS->bleu)>>1)) >> 1;
436     pt++; pC += 2; pN += 2; pS += 2; pE += 2; pW += 2;
437     for (i=1; i<halfWidth; i++) {
438       pt->alpha = (pC->alpha + ((pN->alpha+pS->alpha+pE->alpha+pW->alpha)>>2))>>1;
439       pt->rouge = (pC->rouge + ((pN->rouge+pS->rouge+pE->rouge+pW->rouge)>>2))>>1;
440       pt->vert  = (pC->vert + ((pN->vert+pS->vert+pE->vert+pW->vert)>>2))>>1;
441       pt->bleu  = (pC->bleu + ((pN->bleu+pS->bleu+pE->bleu+pW->bleu)>>2))>>1;
442       pt++; pC += 2; pN += 2; pS += 2; pE += 2; pW += 2;
443     }
444     if (oddLine) {
445       pC++; pN++; pS++; pW++; pE++;
446     }
447     pC+=width; pN+=width; pS+=width; pW+=width; pE+=width;
448   }
449 }
450 
451 //  ----------------------------------------------------------------------------
452 //  Member Functions
453 //  ----------------------------------------------------------------------------
454 
455 //  ----------------------------------------------------------------------------
456 //  Methods of the PTile class
457 //
458 //  Manage a tile of a resolution level.
459 //  ----------------------------------------------------------------------------
460 
PTile()461 PTile::PTile()
462 
463 {
464   // Allocate and compute the inversion LUT
465   AllocInvertTable();
466 }
467 
468 // Allocate and compute the inversion LUT
AllocInvertTable()469 void PTile::AllocInvertTable()
470 
471 {
472   // if LUT inexisting
473   if (!invertLUT) {
474     // Reserve LUT
475     FastAllocArray(invertLUT, unsigned char,256);
476     // Initialize LUT with inverted values
477     if (invertLUT) {
478       for (long i = 0; i < 256; i++)
479         invertLUT[i] = (unsigned char) (0xFF - i);
480     }
481   }
482 }
483 
484 // suppress the 'pixels' buffer from the list of buffer in memory and delete it
~PTile()485 PTile::~PTile()
486 
487 {
488   if (pixels || rawPixels) {
489     if (pixels) {
490       FastDeleteArray(pixels,Pixel);
491       pixels = NULL;
492 #ifdef Memoire_Debug
493       allocSize -= width * height * sizeof(Pixel);
494       VISU2 "Destruction of an image tile pixels \n" FIN
495       VISU2 "    Memory size available      = %d\n", allocSize FIN
496 #endif
497     }
498     if (rawPixels) {
499       FastDeleteArray(rawPixels,Pixel);
500       rawPixels = NULL;
501 #ifdef Memoire_Debug
502       allocSize -= width * height * sizeof(Pixel);
503       VISU2 "Destruction of an image tile rawPixels \n" FIN
504       VISU2 "    Memory size available      = %d\n", allocSize FIN
505 #endif
506     }
507     Dispose();
508   }
509 }
510 
511 
512 // Initialize a tile with compressor assignment
513 // Use this constructor in Create mode
InitializeCreate(PResolutionLevel * father,long width,long height,long id)514 void PTile::InitializeCreate (PResolutionLevel* father, long width, long height, long id)
515 
516 {
517   fatherSubImage    = father;     // Point to the father sub-image
518   this->height    = (short)height;
519   this->width     = (short)width;
520   rawPixels     = NULL;
521   freshPixels     = 0;
522   pixels        = NULL;
523   pixelsStale     = false;
524   idCodec       = TLC_Aucun;
525   decompressorIsMissing = false;
526   posPixelFic     = -1;
527   tileSize      = 0;
528   identifier      = id;
529   previous      = NULL;
530   next        = NULL;
531 }
532 
533 // Initialize a tile with file assignment
534 // Use this constructor in Read mode
535 
InitializeRead(PResolutionLevel * father,long offset,long sizetile,long id,long,long)536 void PTile::InitializeRead (PResolutionLevel* father, long offset, long sizetile,
537                             long id, long /*compression*/, long /*nouse*/)
538 
539 {
540   fatherSubImage    = father;   // Point to the father sub-image
541   height        = 0;
542   width       = 0;
543   rawPixels     = NULL;
544   freshPixels     = 0;
545   pixels        = NULL;
546   pixelsStale     = false;
547   idCodec       = TLC_Aucun;
548   decompressorIsMissing = false;
549   posPixelFic     = offset;
550   tileSize      = sizetile;
551   identifier      = id;
552   previous      = NULL;
553   next        = NULL;
554 
555   register long TILE_WIDTH = fatherSubImage->fatherFile->tileWidth;
556   register long TILE_MASK  = fatherSubImage->fatherFile->maskTileWidth;
557 
558   long curLine = id/fatherSubImage->nbTilesW;
559   long curCol =  id%fatherSubImage->nbTilesW;
560 
561   // Height of tile in pixels
562   if (curLine == (fatherSubImage->nbTilesH - 1))
563     height = ((fatherSubImage->realHeight - 1) & TILE_MASK) + 1;
564   else
565     height = (short) TILE_WIDTH;
566 
567   // Width of tile in pixels
568   if (curCol == (fatherSubImage->nbTilesW-1))
569     width = ((fatherSubImage->realWidth - 1) & TILE_MASK) + 1;
570   else
571     width = (short) TILE_WIDTH;
572 }
573 
574 // ---------------------------------------------------------------------------------
575 // Allocate memory to the 'pixels' buffer stored in this tile.
576 // Returns 0 if successful, else -1 if failed.
577 //
AllocatePixels()578 long PTile::AllocatePixels ()
579 {
580   if (AllocatePixelMemory( &pixels) == 0) {
581     TouchPixelsBuffer( );               // Set access time stamp
582     if ((this != first) && (this->previous == NULL))  // If not on the list
583       Insert();                   //  then add it to the list
584     return 0;
585   }
586   return -1;
587 }
588 
589 
590 // ---------------------------------------------------------------------------------
591 // Allocate memory to the 'rawPixels' buffer stored in this tile.
592 // Returns 0 if successful, else -1 if failed.
593 //
AllocateRawPixels()594 long PTile::AllocateRawPixels ()
595 {
596   if (AllocatePixelMemory( &rawPixels) == 0) {
597     TouchRawPixelsBuffer( );              // Set access time stamp
598     if ((this != first) && (this->previous == NULL))  // If not on the list
599       Insert();                   //  then add it to the list
600     return 0;
601   }
602   return -1;
603 }
604 
605 
606 // ---------------------------------------------------------------------------------
607 // Allocate memory for a buffer of pixel data If possible, allocate from the global
608 //  FPX pool; if not, then recycle memory that is currently being used by some
609 //  other tile.
610 // The size of the buffer is assumed to be square and all buffers are the same size
611 //  as determined by the "father file".
612 // Note that the call to AvailableMemory() will trigger a call to FreeAncientBuffers()
613 //  if memory is low.
614 // Returns 0 if successful, else -1 if failed.
615 //
616 
AllocatePixelMemory(Pixel ** memAddress)617 long PTile::AllocatePixelMemory( Pixel **memAddress)
618 {
619   long  numFreeBytes;
620   //  long  tileSize  = fatherSubImage->fatherFile->tileSize;
621   long  sizeNeeded  = width * height * sizeof( Pixel);      // PTCH_101 new
622 
623   *memAddress = NULL;
624 
625 #ifdef Memoire_Debug                        // PTCH_101 new - start...
626     VISU2 "AllocatePixelMemory: tile %d:%d sizeNeeded = %d\n",
627       this->fatherSubImage->identifier, this->identifier, sizeNeeded FIN
628     VISU2 "    Memory size available      = %d\n", allocSize FIN
629 #endif                                // PTCH_101 new - ...end
630 
631   // Get amount of memory currently available
632   GtheSystemToolkit->AvailableMemory (&numFreeBytes);
633 
634 //  if (tileSize < numFreeBytes) {                     PTCH_101 rep
635   if (sizeNeeded < numFreeBytes) {                // PTCH_101 mod
636     // Allocate new memory from the global memory pool
637     FastAllocArray( *memAddress, Pixel, width * height);
638     if (*memAddress == NULL)
639       return -1;
640     allocSize += (width * height * sizeof( Pixel));       // PTCH_101 new
641   }
642   else {
643     // No more global memory available, so search for the least recently used
644     //  buffer of tile memory and assign it to this tile.
645     PTile *foundTile;
646     long  isRawPixelsBuffer;
647 
648 // PTCH_101 replace the following
649 //    if (FindOldestTileBuffer( &foundTile, &isRawPixelsBuffer) != 0)
650 //      return -1;
651 // with
652 #ifdef Memoire_Debug
653     VISU2 "AllocatePixelMemory: call FindOldestTileBuffer\n", sizeNeeded FIN
654 #endif
655 
656     if (FindOldestTileBuffer( &foundTile, &isRawPixelsBuffer, sizeNeeded) != 0) {
657       // Failed to find a buffer for reuse. Calling FastAllocArray() will force
658       //  a Purge() to occur.  If that fails, there is nowhere left that we can
659       //  look for memory.
660 
661       FastAllocArray( *memAddress, Pixel, width * height);
662       if (*memAddress == NULL)
663         return -1;
664       else {
665         allocSize += (width * height * sizeof( Pixel));
666         return 0;
667       }
668     }
669 
670 #ifdef Memoire_Debug
671     VISU2 "AllocatePixelMemory: FindOldestTileBuffer returned tile %d:%d\n",
672       foundTile->fatherSubImage->identifier, foundTile->identifier FIN
673 #endif
674 // PTCH_101 - end of replacement
675 
676     if (isRawPixelsBuffer) {
677       if (foundTile->freshPixels)                 // PTCH_101 new
678         foundTile->WriteTile();                 // PTCH_101 new
679       *memAddress = foundTile->rawPixels;
680       foundTile->rawPixels = NULL;
681       foundTile->rawPixelsTime = 0;
682       if( foundTile->pixels == NULL)
683         foundTile->Dispose();
684     }
685     else {
686       *memAddress = foundTile->pixels;
687       foundTile->pixels = NULL;
688       foundTile->pixelsTime = 0;
689       if( foundTile->rawPixels == NULL)
690         foundTile->Dispose();
691     }
692   }
693   return 0;
694 }
695 
696 
697 // PTCH_101 - Replace the following
698 // ---------------------------------------------------------------------------------
699 // Find the least recently used tile buffer. Return the tile it belongs to and which
700 //  tile is oldest (e.g., if 'rawPixels' is the buffer found, then set 'isRawPixelsBuffer'
701 //  otherwise return 'isRawPixelsBuffer' as zero to indicate it's the 'pixels' buffer
702 //  that is oldest).
703 // Returns 0 if successful, else -1 if failed.
704 //
705 // long PTile::FindOldestTileBuffer( PTile **foundTile, long *isRawPixelsBuffer)
706 // with
707 
708 // ---------------------------------------------------------------------------------
709 // Find the least recently used tile buffer that contains at least 'minSize'.
710 //  Return the tile it belongs to and which buffer is oldest (e.g., if 'rawPixels' is
711 //  the buffer found, then set 'isRawPixelsBuffer'; otherwise return 'isRawPixelsBuffer'
712 //  as zero to indicate it's the 'pixels' buffer that is oldest).
713 // Returns 0 if successful, else -1 if failed (i.e., there are no allocated buffers!)
714 //
FindOldestTileBuffer(PTile ** foundTile,long * isRawPixelsBuffer,long minSize)715 long PTile::FindOldestTileBuffer( PTile **foundTile, long *isRawPixelsBuffer, long minSize)
716 
717 // PTCH_101 - end replacement
718 {
719   PTile *currTile  = first;
720   time_t  oldestTime = 0;
721 
722 
723   // Find the first buffer on the list that isn't locked. Use one of it's buffers
724   //  as the "oldest".
725   *foundTile = 0;
726   while (currTile) {
727 //    if ( !currTile->IsLocked()) {                          PTCH_101 rep
728     if ( !currTile->IsLocked()                          // PTCH_101 new
729      && ((currTile->width * currTile->height * sizeof( Pixel)) >= (unsigned long) minSize)) { // PTCH_101 new
730       if (currTile->rawPixels) {
731         oldestTime = currTile->rawPixelsTime;
732         *isRawPixelsBuffer = 1;
733       }
734       else {
735         oldestTime = currTile->pixelsTime;
736         *isRawPixelsBuffer = 0;
737       }
738       *foundTile = currTile;
739       break;
740     }
741     currTile = currTile->next;
742   }
743 
744   // Starting with the current tile, continue checking for a buffer that
745   // is older than the first one we found, above.
746   while (currTile) {
747 //    if (!currTile->IsLocked()) {                           PTCH_101 rep
748     if ( !currTile->IsLocked()                          // PTCH_101 new
749      && ((currTile->width * currTile->height * sizeof( Pixel)) >= (unsigned long) minSize)) { // PTCH_101 new
750       if (currTile->rawPixels)
751         if (currTile->rawPixelsTime < oldestTime) {
752           *foundTile = currTile;
753           oldestTime = currTile->rawPixelsTime;
754           *isRawPixelsBuffer = 1;
755         }
756       if (currTile->pixels)
757         if (currTile->pixelsTime < oldestTime) {
758           *foundTile = currTile;
759           oldestTime = currTile->pixelsTime;
760           *isRawPixelsBuffer = 0;
761         }
762     }
763     currTile = currTile->next;
764   }
765   return ((*foundTile == NULL)? -1 : 0);
766 }
767 
768 
769 // ---------------------------------------------------------------------------------
770 // Search through all of the buffers allocated by any tiles. If a buffer has not
771 //  been accessed within the number of minutes in 'numMinutesOld', then deallocate
772 //  the memory -- returning it to the global pool for other (possibly non-tile) use.
773 //
FreeAncientBuffers(long numMinutesOld)774 void PTile::FreeAncientBuffers( long numMinutesOld)
775 {
776   PTile *currTile = first;
777   PTile *nextTile = currTile->next;
778   time_t  ancientTime;
779 
780   // Calculate the minimum time for the last access to the tile. If a tile
781   //  has not been accessed within this amount of time, then we will consider
782   //  it to be "ancient"
783 #ifdef _WINDOWS
784   ancientTime = GetCurrentTime() - (numMinutesOld * 60L * CLOCKS_PER_SEC);
785 #else
786   ancientTime = clock() - (numMinutesOld * 60L * CLOCKS_PER_SEC);
787 #endif
788 
789   for (currTile = first; currTile; currTile = nextTile) {
790     nextTile = currTile->next;
791 
792     if (currTile->IsLocked() == false) {
793 //      // Free 'rawPixels' or 'pixels' if either is ancient          PTCH_101 rep
794 //      if (currTile->rawPixels)                        PTCH_101 rep
795 
796       // Free unmodified 'rawPixels' or 'pixels' if either is ancient   // PTCH_101 new
797       if (currTile->rawPixels && (currTile->freshPixels == 0))      // PTCH_101 new
798         if (currTile->rawPixelsTime < ancientTime)
799           currTile->FreeRawPixelsBuffer( );
800       if (currTile->pixels)
801         if (currTile->pixelsTime < ancientTime)
802           currTile->FreePixelsBuffer( );
803     }
804   }
805 }
806 
807 
808 // ---------------------------------------------------------------------------------
809 // Release the memory being used to cache pixels in this tile
810 //
FreePixelsBuffer()811 void PTile::FreePixelsBuffer( )
812 {
813   if (pixels) {
814     FastDeleteArray (pixels, Pixel);
815     pixels = NULL;
816     pixelsTime = 0;
817   }
818   if (rawPixels == NULL)
819     Dispose();
820 }
821 
822 
823 // ---------------------------------------------------------------------------------
824 // Release the memory being used to cache raw pixels in this tile
825 //
FreeRawPixelsBuffer()826 void PTile::FreeRawPixelsBuffer( )
827 {
828   if (rawPixels) {
829     if (freshPixels)                    // PTCH_101 new
830       WriteTile();                    // PTCH_101 new
831     FastDeleteArray (rawPixels, Pixel);
832     rawPixels = NULL;
833     rawPixelsTime = 0;
834   }
835   if (pixels == NULL)
836     Dispose();
837 }
838 
839 
840 
841 // ---------------------------------------------------------------------------------
842 // Check all of the 'rawPixel' buffers allocated by any tiles. If a buffer has
843 //  'freshPixels' (i.e., it has some pixels that have been modified but not written
844 //  to the file yet), then write the 'rawPixels' to the file.
845 // This is called to ensure that the file is updated and that all lower resolutions
846 //  have been updated (including the thumbnail).
847 // This does not free any memory.
848 //
FlushModifiedTiles()849 void PTile::FlushModifiedTiles( )
850 {
851   PTile *currTile;
852 
853   for (currTile = first; currTile; currTile = currTile->next)
854     if (currTile->freshPixels)
855       if (currTile->rawPixels)
856         currTile->WriteTile();
857 }
858 
859 
860 // ---------------------------------------------------------------------------------
861 // Release memory used by tiles of images : after several tests, we have decided to
862 // free up ALL the memory used by the images instead of what is just necessary
863 // in order to avoid the allocation of small tiles into the area reserved for the large
864 // ones. All other strategy will lead to fragment the memory or to release the more
865 // recently used images. The only tiles leaved in the memory are those belonging
866 // to the currently locked image file or those whitch are locked themself.
867 //
Purge(long * size,Boolean purgeAll)868 Boolean PTile::Purge(long* size, Boolean purgeAll)
869 {
870 #ifdef Memoire_Debug
871 // FOR DEBUG PURPOSE
872 VISU2 "\n\nEnter in PTile::Purge()\n" FIN
873 if (size) {
874 VISU2 "Size requested = %d\n", *size FIN
875 } else {
876 VISU2 "Soft purge\n" FIN
877 }
878 VISU2 "Memory size available      = %d\n", allocSize FIN
879 // END DEBUG PURPOSE
880 #endif
881 
882   long    freedSize = 0;
883   long    theSize = 0;
884   Boolean   status = false;
885   Boolean   forced = false;
886   PTile   *currTile, *nextTile;
887 
888 
889   // Calling Purge() results in default of size=NULL, so ...
890   if ( size != NULL ) theSize = *size;
891 
892   // If Purge requested with a size, force deletion of tiles
893   if ( purgeAll)
894     forced = true;
895 
896   // Free all the tiles already saved in a file
897   for (currTile = first; currTile; currTile = nextTile) {
898     nextTile = currTile->next;
899     freedSize += currTile->Free(forced);
900   }
901 
902   // Free all the tiles not entirely changed in memory (save them in a file before freeing the memory)
903   if ( theSize==0 || (freedSize < theSize) || purgeAll)
904     for (currTile = first; currTile; currTile = nextTile) {
905       nextTile = currTile->next;
906       freedSize += currTile->Free(forced, true);
907     }
908 
909   // Free eventually the decompression buffer
910   if (forced) {
911     if ( theSize==0 || (freedSize < theSize) || purgeAll)
912       freedSize += PurgeDecompress ();
913   }
914 
915   // Update size if requested
916   if (theSize) {
917     if (freedSize >= theSize) {     // If more than required, exit with success
918       if (size) *size = 0;
919     }
920     else {              // Else update size and exit with error
921       if (size) *size -= freedSize;
922       status = true;
923     }
924   }
925 
926 #ifdef Memoire_Debug
927 // FOR DEBUG PURPOSE
928 VISU2 "Exit from PTile::Purge()\n" FIN
929 VISU2 "Memory frees   = %d\n", freedSize FIN
930 if (size) {
931 VISU2 "Size remaining = %d\n", *size FIN
932 }
933 VISU2 "Exit status = " FIN
934 if (status) {
935 VISU2 "Error\n\n" FIN
936 } else {
937 VISU2 "OK\n\n" FIN
938 }
939 // END DEBUG PURPOSE
940 #endif
941 
942   return status;
943 }
944 
945 
946 // ---------------------------------------------------------------------------------
947 // Compute the quantity of memory purgeable without purging the locked tiles
948 //
GetPurgeableMemory()949 long PTile::GetPurgeableMemory()
950 
951 {
952   // Init purgeable memory size
953   long purgeableMemory = 0;
954 
955   // For each tile allocated...
956   PTile* ptTile = first;
957   while (ptTile) {
958     // If the image and the tile is not locked...
959     if (!(GtheSystemToolkit->IsLockedImage(ptTile->fatherSubImage->fatherFile))
960     && !(ptTile->IsLocked())) {
961       // ... and if the tile contains pixels and is not being written...
962       if ((ptTile->pixels != NULL) && (ptTile->freshPixels == 0))
963         // ... then this tile is purgeable.
964         purgeableMemory += ptTile->width * ptTile->height * sizeof(Pixel);  // compute memory purgeable
965       if (ptTile->rawPixels)
966         purgeableMemory += ptTile->width * ptTile->height * sizeof(Pixel);  // compute memory purgeable
967     }
968     // Jump to the next tile
969     ptTile = ptTile->next;
970   }
971   return purgeableMemory;
972 }
973 
974 
975 // ---------------------------------------------------------------------------------
976 // Remove a tile from the list of tiles that own memory buffers
977 //
Dispose()978 void PTile::Dispose()
979 
980 {
981   if (this == last)
982     last = previous;
983   else
984     next->previous = previous;
985   if (this == first)
986     first = next;
987   else
988     previous->next = next;
989 
990   previous  = NULL;
991   next      = NULL;
992 }
993 
994 
995 // ---------------------------------------------------------------------------------
996 // Insert tile at the end of the list
997 //
Insert()998 void PTile::Insert()
999 
1000 {
1001   previous   = last;
1002   next       = NULL;
1003   if (last)
1004     last->next = this;
1005   else
1006     first = this;
1007 
1008   last = this;
1009 }
1010 
1011 
1012 // ---------------------------------------------------------------------------------
1013 // Free any buffers assigned to this tile
1014 // Unless 'forced', tiles which are not the maximum size will not be freed.
1015 // Unless 'freeIncomplete' is set, tiles that still have 'freshPixels' (not written
1016 //  to the file yet, will not be freed. If 'freeIncomplete', then the buffer will
1017 //  be written to the file and then freed.
1018 //
Free(Boolean forced,Boolean freeIncomplete)1019 long PTile::Free (Boolean forced, Boolean freeIncomplete)
1020 {
1021   register long TILE_WIDTH = fatherSubImage->fatherFile->tileWidth;
1022   register long size = 0;
1023 
1024 #ifdef Memoire_Debug
1025   VISU2 "Free the tile: %d:%d, forced = %d\n", fatherSubImage->identifier, identifier, forced FIN
1026 #endif
1027 
1028   // If the tile belongs to the locked Image or is locked, do not free the tile
1029   if (GtheSystemToolkit->IsLockedImage(fatherSubImage->fatherFile) || IsLocked()) {
1030 
1031 #ifdef Memoire_Debug
1032     if (Toolkit_IsLockedIVUE(fatherSubImage->fatherFile)) {
1033     VISU2 "   Can't free the tile because the file is locked\n" FIN
1034     }
1035     if (IsLocked()) {
1036     VISU2 "   Can't free the tile because the tile is locked\n" FIN
1037     }
1038 #endif
1039   }
1040   else {
1041     if (IsLocked())
1042       if (forced == false)
1043         goto RETURN;
1044 
1045     // There's no reason to protect 'pixels' which is used for display, unless it is
1046     //  less than a full tile in size and deallocation is not 'forced'
1047     if (pixels) {
1048       if ((forced)
1049       || ((width == TILE_WIDTH) && (height == TILE_WIDTH))) {
1050         FastDeleteArray( pixels,Pixel);       // free this memory buffer
1051         pixels = NULL;
1052         pixelsTime = 0;
1053         size = width * height * sizeof(Pixel);    // compute memory freed
1054       }
1055       else {
1056         ;
1057 #ifdef Memoire_Debug
1058         VISU2 "   Can't free pixels because it is not maximum size\n" FIN
1059 #endif
1060       }
1061     }
1062     // If there are 'rawPixels' allocated, we can only free them if there are
1063     //  no 'freshPixels' (i.e., no pixel modifications that have not been saved
1064     //  to the file) or if the request is to 'freeIncomplete' (in which case
1065     //  we save what is there to the file and deallocate it)
1066     if (rawPixels) {
1067       if (freshPixels) {
1068         if (forced || freeIncomplete) {
1069           if (WriteTile()) {
1070 #ifdef Memoire_Debug
1071             VISU2 "   Can't free rawPixels because error while writing it in the file\n" FIN
1072 #endif
1073             goto RETURN;  // if an error occur during writing keep the tile in memory
1074           }
1075         }
1076         else {
1077 #ifdef Memoire_Debug
1078 //            VISU2 "   Can't free rawPixels because it's modified and not forced\n" FIN
1079 #endif
1080           goto RETURN;    // Didn't save changes to rawPixels, so can't free yet
1081         }
1082       }
1083 
1084       // Release only tile whose size is the maximum (avoid border tiles management),
1085       //  unless the request is 'forced'
1086       if ((forced || freeIncomplete)
1087       || ((width == TILE_WIDTH) && (height == TILE_WIDTH))) {
1088         FastDeleteArray (rawPixels,Pixel);      // free this memory buffer
1089         rawPixels = NULL;
1090         rawPixelsTime = 0;
1091         size += (width * height * sizeof(Pixel)); // compute memory freed
1092       }
1093       else {
1094 #ifdef Memoire_Debug
1095 //        VISU2 "   Can't free rawPixels because it's modified and not forced\n" FIN
1096 #endif
1097         ;
1098       }
1099     }
1100     // If all tile buffer memory has been deallocated, remove the tile from the tile list
1101     if ((pixels == NULL) && (rawPixels == NULL)) {
1102       UnLock();
1103       Dispose();
1104     }
1105   }
1106  RETURN:
1107 
1108 #ifdef Memoire_Debug
1109   allocSize -= size;
1110   if (size) {
1111     VISU2 "   Freed %d bytes\n", size FIN
1112   }
1113 #endif
1114   return(size);
1115 }
1116 
1117 
1118 // ---------------------------------------------------------------------------------
1119 // Return size of the tile. Return true if error, false if OK.
1120 //
GetInfo(long * width,long * height,Typ_Compression * compr)1121 Boolean PTile::GetInfo (long* width, long* height, Typ_Compression* compr)
1122 
1123 {
1124   Boolean status = false;
1125 
1126   *width  = this->width;
1127   *height = this->height;
1128   *compr  = (Typ_Compression)(idCodec);
1129   return (status);
1130 }
1131 
1132 // ---------------------------------------------------------------------------------
GetCompression()1133 long PTile::GetCompression ()
1134 {
1135   return 0;
1136 }
1137 
1138 // ---------------------------------------------------------------------------------
GetCompressionSubtype()1139 long PTile::GetCompressionSubtype ()
1140 {
1141   return 0;
1142 }
1143 
1144 // ---------------------------------------------------------------------------------
SetCompression(long theCompression)1145 void PTile::SetCompression (long theCompression)
1146 {
1147   compression = theCompression;
1148   idCodec   = ConvertCompressionOption();
1149 }
1150 
1151 // ---------------------------------------------------------------------------------
SetCompressionSubtype(long theCompressionSubType)1152 void PTile::SetCompressionSubtype (long theCompressionSubType)
1153 {
1154   compressionSubtype = theCompressionSubType;
1155 }
1156 
1157 // ---------------------------------------------------------------------------------
SetQualityFactor(unsigned char theQualityFactor)1158 void PTile::SetQualityFactor (unsigned char theQualityFactor)
1159 {
1160   qualityFactor = theQualityFactor;
1161 }
1162 
1163 // ---------------------------------------------------------------------------------
ConvertCompressionOption()1164 TLC_IdCodec PTile::ConvertCompressionOption ()
1165 {
1166    return TLC_Aucun;
1167 }
1168 
1169 // ---------------------------------------------------------------------------------
1170 // Write the set of raw pixels in the tile
WriteRectangle(Pixel * pix,long width,long height,long rowOffset,long x0,long y0,short plan)1171 FPXStatus PTile::WriteRectangle (Pixel* pix, long width, long height, long rowOffset,
1172         long x0, long y0, short plan)
1173 {
1174   register Pixel* pt;
1175   register long   i;
1176   FPXStatus   status = FPX_OK;
1177 
1178   // Read or allocate the tile if necessary
1179   if (rawPixels == NULL)
1180     if ((status = ReadRawPixels()) != FPX_OK)
1181       return status;
1182 
1183   assert (rawPixels);
1184   // Compute first pixel of the tile to be written
1185   pt = rawPixels + (y0 * this->width) + x0;
1186 
1187   // Copy pixels to the tile
1188   if (plan == ActiveChannel_All) {
1189     // Line by line if all planes available to copy
1190     for (i = 0; i < height; i++, pt += this->width, pix += rowOffset)
1191       BlockMove(pix,pt,width*sizeof(Pixel));
1192   } else {
1193     // Pixel by pixel if planes specified
1194     register long j;
1195     register unsigned char *src, *dst;
1196     for (i = 0; i < height; i++, pt += this->width, pix += rowOffset) {
1197       src = (unsigned char *)(pix) + plan;
1198       dst = (unsigned char *)(pt)  + plan;
1199       for (j = 0; j < width; j++, src += sizeof(Pixel), dst += sizeof(Pixel))
1200         *dst = *src;
1201     }
1202   }
1203 
1204   // PTCH_104 start of addition....
1205   // convert data from passed format into image/file format
1206   FPXBaselineColorSpace base = ((PResolutionFlashPix*)fatherSubImage)->GetBaselineSpace();
1207   FPXBaselineColorSpace used = fatherSubImage->fatherFile->GetUsedColorSpace();
1208 
1209   pt = rawPixels + (y0 * this->width) + x0;
1210   for (i = 0; i < height; i++, pt += this->width, pix += rowOffset)
1211     ConvertPixelBuffer((unsigned char*)pt, width, used, base);
1212   // .... PTCH_104 end of addition
1213 
1214   // Update amount of fresh pixels and mark pixels as stale
1215   freshPixels += width*height;
1216   pixelsStale = true;
1217 
1218   // If everything refreshed (so, we hope that�)
1219   if (freshPixels >= (this->width * this->height))
1220     status = WriteTile();
1221 
1222   return status;
1223 }
1224 
1225 
1226 // ---------------------------------------------------------------------------------
1227 // Compute convolution of a set of pixels in the tile
1228 //
Convolution(Pixel * pix,long srcWidth,long srcHeight,long quadrant)1229 FPXStatus PTile::Convolution (Pixel* pix, long srcWidth, long srcHeight, long quadrant)
1230 
1231 {
1232   Pixel   *pt;
1233   short   halfTileWidth = (short ) ((fatherSubImage->fatherFile->tileWidth) >> 1);
1234   short     writtenWidth, writtenHeight;
1235   FPXStatus status = FPX_OK;
1236 
1237   // Read or allocate the tile if necessary
1238   if (rawPixels == NULL)
1239     if ((status = ReadRawPixels()) != FPX_OK)
1240       return status;;
1241   assert(rawPixels);
1242 
1243   // Compute first pixel of the tile to be written and size to be written
1244   switch (quadrant) {
1245     case SW:
1246       writtenWidth  = MIN(halfTileWidth,width);
1247       writtenHeight = MIN(halfTileWidth,height);
1248       pt = rawPixels;
1249       break;
1250     case SE:
1251       writtenWidth  = width  - halfTileWidth;
1252       writtenHeight = MIN(halfTileWidth,height);
1253       pt = rawPixels + halfTileWidth;
1254       break;
1255     case NW:
1256       writtenWidth  = MIN(halfTileWidth,width);
1257       writtenHeight = height - halfTileWidth;
1258       pt = rawPixels + (halfTileWidth * width);
1259       break;
1260     case NE:
1261       writtenWidth  = width  - halfTileWidth;
1262       writtenHeight = height - halfTileWidth;
1263       pt = rawPixels + (halfTileWidth * width) + halfTileWidth;
1264       break;
1265   }
1266 
1267   // Compute convolution : for the moment, 3 convolution algorithms are available
1268   //    convolution takes alpha channel into account, loops are duplicated to improve speed.
1269   switch (fatherSubImage->fatherFile->convolution) {
1270     case Convolution_Cross:
1271       if (fatherSubImage->identifier <= 2)
1272         ConvolStandard (pix, srcWidth, srcHeight, pt, width);
1273       else
1274         ConvolGaussSimplified (pix, srcWidth, srcHeight, pt, width);
1275       break;
1276     case Convolution_Gauss:
1277       ConvolGaussian4 (pix, srcWidth, srcHeight, pt, width);
1278       break;
1279     case Convolution_Standard:
1280     case Convolution_Other:
1281     default:
1282       ConvolStandard (pix, srcWidth, srcHeight, pt, width);
1283       break;
1284   }
1285 
1286   // Take the extra column into account if any
1287   if ((writtenWidth > (srcWidth / 2)) && (srcWidth % 2)) {
1288     Pixel* src  = pix + (srcWidth - 1);
1289     Pixel* dest = pt  + (writtenWidth - 1);
1290     for (long i = 0; i < writtenHeight; ++i, dest += width, src  += (2 * srcWidth))
1291       *dest = *src;
1292   }
1293 
1294   // Take the extra line into account if any
1295   if ((writtenHeight > (srcHeight / 2)) && (srcHeight % 2)) {
1296     Pixel* src  = pix + ((srcHeight - 1) * srcWidth);
1297     Pixel* dest = pt  + ((writtenHeight - 1) * width);
1298     for (long i = 0; i < writtenWidth; ++i, ++dest, src += 2)
1299       *dest = *src;
1300   }
1301 
1302   // Update amount of fresh pixels
1303   freshPixels += writtenWidth * writtenHeight;
1304 
1305   // If everything refreshed (so, we hope that�)
1306   if (freshPixels >= (width * height))
1307     status = WriteTile();                   // Write tile on disk
1308 
1309   return status;
1310 }
1311 
1312 
1313 // ---------------------------------------------------------------------------------
1314 // Advanced tile writing
1315 //
WriteTile()1316 FPXStatus PTile::WriteTile()
1317 {
1318   FPXStatus status = FPX_OK;
1319 
1320   // Read or allocate the tile if necessary
1321   if (rawPixels == NULL)
1322     status = FPX_ERROR;
1323   else {
1324     status = Write();   // Write tile on disk
1325 
1326     // Decimate if automatic decimation is on
1327     if ((status == FPX_OK) && fatherSubImage->fatherFile->automaticDecimation)
1328       status = DecimateTile();
1329   }
1330   freshPixels = 0;
1331   return status;
1332 }
1333 
1334 
1335 // ---------------------------------------------------------------------------------
1336 // Tile Decimation decision and call
1337 //
DecimateTile()1338 FPXStatus PTile::DecimateTile()
1339 {
1340   FPXStatus   status = FPX_OK;
1341   Boolean   wasLocked;
1342 
1343   // Read or allocate the tile if necessary
1344   if (rawPixels == NULL)
1345     if ((status = ReadRawPixels()) != FPX_OK)
1346       return status;
1347 
1348    // Decimate the tile in the next subimage (if any)
1349    if ((status == FPX_OK) && fatherSubImage->next) {
1350      long y = identifier/fatherSubImage->nbTilesW;
1351      long x = identifier - y*fatherSubImage->nbTilesW;
1352      wasLocked = IsLocked();
1353      Lock();
1354      status = fatherSubImage->next->Convolution (x, y, rawPixels, width, height);
1355      if (wasLocked == false)
1356       UnLock();
1357    }
1358 
1359    Free();    // Delete pixels from memory
1360    return status;
1361 }
1362 
1363 
1364 // ---------------------------------------------------------------------------------
1365 // Read a set of unmodified, raw pixels from the tile. This would be called in a
1366 //  read-modify-write application where contrast, filtering and colortwist should
1367 //  not be applied to the data being modified.
1368 //
1369 //  SHOULD THIS HAVE A COLORSPACE ARG???
1370 //
ReadRectangleRawData(Pixel * pix,long width,long height,long rowOffset,long x0,long y0)1371 FPXStatus PTile::ReadRectangleRawData (Pixel* pix, long width, long height, long rowOffset,
1372           long x0, long y0)
1373 {
1374 
1375   return FPX_UNIMPLEMENTED_FUNCTION;
1376 }
1377 
1378 
1379 // ---------------------------------------------------------------------------------
1380 // Read a set of display-modified pixels from the tile. This should be called when
1381 //  data is intended for display and should have contrast, filtering and colortwist
1382 //  applied to it.
1383 //
ReadRectangle(Pixel * pix,long width,long height,long rowOffset,long x0,long y0)1384 FPXStatus PTile::ReadRectangle (Pixel* pix, long width, long height, long rowOffset,
1385           long x0, long y0)
1386 {
1387   register  Pixel *pt;
1388   register  long  i;
1389   FPXStatus     status;
1390 
1391   // Read the tile if necessary
1392   status = Read();
1393   if (status)       // must exit if read didn't failed
1394     return status;
1395 
1396   // Compute first pixel of the tile to be read
1397   pt = pixels + (y0 * this->width) + x0;
1398 
1399   short plan = Toolkit_ActiveChannel();
1400   // Copy pixels to the tile
1401   if (plan == ActiveChannel_All) {
1402     // Copy pixels to the buffer
1403     for (i = 0; i < height; i++, pt += this->width, pix += rowOffset)
1404       BlockMove(pt,pix,width*sizeof(Pixel));
1405   } else {
1406     // Pixel by pixel if planes specified
1407     register long j;
1408     register unsigned char *src, *dst;
1409     for (i = 0; i < height; i++, pt += this->width, pix += rowOffset) {
1410       src = (unsigned char *)(pt)  + plan;
1411       dst = (unsigned char *)(pix) + plan;
1412       for (j = 0; j < width; j++, src += sizeof(Pixel), dst += sizeof(Pixel))
1413         *dst = *src;
1414     }
1415   }
1416   return status;
1417 }
1418 
1419 
1420 // ---------------------------------------------------------------------------------
1421 // Write the tile in the disk file. Use compression if necessary.
1422 //
Write()1423 FPXStatus PTile::Write()
1424 {
1425   return FPX_OK;
1426 }
1427 
1428 // ---------------------------------------------------------------------------------
1429 // Read a tile from the disk file and store it in the "pixels[]" buffer.
1430 // If decompressor is missing, return false and "pixels" is set to a default pattern.
1431 //
Read()1432 FPXStatus PTile::Read()
1433 {
1434   return FPX_OK;
1435 }
1436 
1437 
ReadRawPixels()1438 FPXStatus PTile::ReadRawPixels()
1439 {
1440   return FPX_OK;
1441 }
1442 
1443 
1444 // ---------------------------------------------------------------------------------
AllocDecompress(long size)1445 void PTile::AllocDecompress (long size)
1446 {
1447   // If the desompressor buffer previously allocated is too small
1448   if (size > decompressSize) {
1449 
1450     // Free the old buffer
1451     FastDeleteArray(decompressBuffer, char);
1452 
1453     FastAllocArray(decompressBuffer, int8, size);
1454     if (decompressBuffer)
1455       decompressSize = size;
1456     else
1457       decompressSize = 0;
1458   }
1459 }
1460 
1461 // ---------------------------------------------------------------------------------
PurgeDecompress()1462 long PTile::PurgeDecompress ()
1463 
1464 {
1465   long size = 0;
1466 
1467   if (!decompressLock) {
1468     FastDeleteArray(decompressBuffer, char);
1469     decompressBuffer = NULL;
1470     size = decompressSize;
1471     decompressSize = 0;
1472   }
1473   return size;
1474 }
1475 
1476 // ---------------------------------------------------------------------------------
1477 // Inverse alpha channel in tile
1478 //
InverseAlpha()1479 long PTile::InverseAlpha()
1480 
1481 {
1482   if (pixels && invertLUT) {
1483     unsigned char* pt = (unsigned char*)(pixels);
1484     pt += fatherSubImage->alphaOffset;
1485     long i, j;
1486     for (i = 0; i < height; i++)
1487       for (j = 0; j < width; j++, pt+=4)
1488         *pt = invertLUT[*pt];
1489   }
1490 
1491   return 0;
1492 }
1493 
1494 // ---------------------------------------------------------------------------------
1495 // Add a tile in the list of locked tiles
1496 //
Lock()1497 void PTile::Lock()
1498 {
1499   if (!IsLocked()) {
1500     if (locked == NULL) {
1501       locked = new PTile*[10];
1502       if (locked==NULL) {
1503         return;
1504       }
1505     }
1506     if (indexLocked == 10) {  // there must be only 10 tiles locked at a time
1507       assert(false);      // erase the first and shift the others
1508       for (long i = 1; i < indexLocked; i++)
1509         locked[i-1] = locked[i];
1510       locked[9] = this;
1511     } else {
1512       locked[indexLocked] = this;
1513       indexLocked++;
1514     }
1515   }
1516 }
1517 
1518 
1519 // ---------------------------------------------------------------------------------
1520 // Delete a tile from the list of locked tiles
1521 //
UnLock()1522 void PTile::UnLock()
1523 
1524 {
1525   long i,j;
1526   // search the current tile in the list
1527   for (i = 0; i < indexLocked; i++) {
1528     if (this == locked[i])
1529       break;
1530   }
1531   if (i < indexLocked) {
1532     // shift all the tiles following the current one to delete it from the list
1533     for (j = i+1; j < indexLocked; j++)
1534       locked[j-1] = locked[j];
1535     indexLocked--;
1536   }
1537 }
1538 
1539 
1540 // ---------------------------------------------------------------------------------
1541 // test if the current tile is in the list of locked ones
1542 //
IsLocked()1543 Boolean PTile::IsLocked()
1544 
1545 {
1546   if (locked == NULL)
1547     return false;
1548   Boolean isLocked = false;
1549   for (long i = 0; i < indexLocked; i++)
1550     isLocked = isLocked || (this == locked[i]);
1551   return isLocked;
1552 }
1553 
1554 // ---------------------------------------------------------------------------------
ClearStaticArrays()1555 void PTile::ClearStaticArrays()
1556 {
1557   if (invertLUT) {
1558     FastDeleteArray(invertLUT, unsigned char);
1559     invertLUT = NULL;
1560   }
1561 
1562   if (locked) {
1563     delete [] locked;
1564     locked = NULL;
1565     indexLocked = 0;
1566   }
1567 
1568 }
1569 
1570 //  ----------------------------------------------------------------------------
1571 //  External Functions
1572 //  ----------------------------------------------------------------------------
1573 
1574 
1575 
1576 //  - EOF ----------------------------------------------------------------------
1577