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