1 //  ------------------------------------------------------------------------------------------------
2 //
3 //                     IMAGE OUTPUT PAGE MANAGEMENT
4 //
5 //  This source code is the property of FITS Imaging inc.
6 //
7 //  MODULE    : PageIVUE
8 //  LANGUAGE  : C++
9 //  AUTHOR    : Philippe BOSSUT
10 //  DATE    : Thursday, December 16th 1993
11 //  DESCRIPTION :
12 //  COMMENT   : This package is a part of the IVUE Toolkit I/O and the FlashPix Baseline I/O Toolkit
13 //      SCCSID        : @(#)ri_page.cpp 1.4 12:41:25 08 Jul 1997
14 //  ------------------------------------------------------------------------------------------------
15 //  Copyright (c) 1999 Digital Imaging Group, Inc.
16 //  For conditions of distribution and use, see copyright notice
17 //  in Flashpix.h
18 //  ------------------------------------------------------------------------------------------------
19   #include "ri_page.h"
20 //  ------------------------------------------------------------------------------------------------
21 
22 //  Includes
23 //  --------
24 
25   #include  <stdlib.h>
26 
27 #ifndef Memoire_h
28   #include  "b_memory.h"
29 #endif
30 #ifndef Numbers_h
31   #include  "numbers.h"
32 #endif
33 #ifndef IVUEToolkit_h
34   #include "ri_lib.h"
35 #endif
36 #ifndef AdvancedIVUE_h
37   #include "viewimg.h"
38 #endif
39 #ifndef PHierarchicalImage_h
40   #include "ph_image.h"
41 #endif
42 
43 //  Constants
44 //  ---------
45 
46 //  Variables
47 //  ---------
48 
49 //  ------------------------------------------------------------------------------------------------
50 
51 //  ------------------------------------------------------------------------------------------------
52 
53 //  ------------------------------------------------------------------------------------------------
54 //  Internal Functions
55 //  ------------------------------------------------------------------------------------------------
56 
57 //  ------------------------------------------------------------------------------------------------
58 //  Methods of the PageImage class
59 //  ------------------------------------------------------------------------------------------------
60 
PageImage(PRIImage * rawImage,long width,long height,float rotation)61 PageImage::PageImage (PRIImage* rawImage, long width, long height, float rotation)
62 
63 {
64   // Set the image pointers first
65   image          = new ViewImage (rawImage);
66   if (image==NULL) {
67     return;
68   }
69   this->rawImage = rawImage;
70 
71   // Set values
72   pixHeight = height; // height of the page in pixels
73   pixWidth  = width;  // width of the page in pixels
74   numLine   = -1;   // first line number set to an invalid value
75   lineSize  = 0;    // length of each line
76   buffer    = NULL;   // no buffer allocated...
77   line[0]   = NULL;   // ...
78   line[1]   = NULL;   // ...
79   line[2]   = NULL;   // ...
80   line[3]   = NULL;   // ...
81   // By default the image covers the page which means that the height of the page is equal to 1.0mm
82   // in the image coordinate system. Thus, the resolution of the page is equal to (height)(pixels)/(1.0)(mm)
83   resolution  = (float)(height);
84   xOrigin   = (float) 0.0;    // the position of the page in the world is on (0,0) by default
85   yOrigin   = (float) 0.0;
86 
87   // Compute position transformation matrix : Rotate image in page
88   TransfoPerspective position;
89   ComputeRotationMatrix (&position, rotation);
90 
91   // Set the view image position
92   image->ApplyTransform(position);
93 }
94 
PageImage(PRIImage * rawImage,long width,long height,float r,float x,float y,TransfoPerspective trans)95 PageImage::PageImage (PRIImage* rawImage, long width, long height, float r, float x, float y, TransfoPerspective trans)
96 
97 {
98   // Set the image pointers first
99   image          = new ViewImage (rawImage);
100   if (image==NULL) {
101     return;
102   }
103   this->rawImage = rawImage;
104 
105   // Set values
106   pixHeight = height; // height of the page in pixels
107   pixWidth  = width;  // width of the page in pixels
108   numLine   = -1;   // first line number set to an invalid value
109   lineSize  = 0;    // length of each line
110   buffer    = NULL;   // no buffer allocated...
111   line[0]   = NULL;   // ...
112   line[1]   = NULL;   // ...
113   line[2]   = NULL;   // ...
114   line[3]   = NULL;   // ...
115   resolution  = r;    // Set the resolution of the page in pixels per mm
116   xOrigin   = x;    // Set the position of the page in the world
117   yOrigin   = y;
118 
119   // Set the view image position
120   image->ApplyTransform(trans);
121 }
122 
PageImage(ViewImage * viewImage,long width,long height,float rotation)123 PageImage::PageImage (ViewImage* viewImage, long width, long height, float rotation)
124 
125 {
126   // Set the image pointers first
127   image     = new ViewImage (viewImage->GetImage());
128   if (image==NULL) {
129     return;
130   }
131 
132   rawImage    = viewImage->GetImage();
133 
134   // Set values
135   pixHeight = height; // height of the page in pixels
136   pixWidth  = width;  // width of the page in pixels
137   numLine   = -1;   // first line number set to an invalid value
138   lineSize  = 0;    // length of each line
139   buffer    = NULL;   // no buffer allocated...
140   line[0]   = NULL;   // ...
141   line[1]   = NULL;   // ...
142   line[2]   = NULL;   // ...
143   line[3]   = NULL;   // ...
144   // By default the image covers the page which means that the height of the page is equal to 1.0mm
145   // in the image coordinate system. Thus, the resolution of the page is equal to (height)(pixels)/(1.0)(mm)
146   resolution  = (float)(height);
147   xOrigin   = (float) 0.0;    // the position of the page in the world is on (0,0) by default
148   yOrigin   = (float) 0.0;
149 
150   // Compute position transformation matrix : Rotate image in page
151   TransfoPerspective position;
152   ComputeRotationMatrix (&position, rotation);
153 
154   // Set the view image position
155   image->ApplyTransform(position);
156 }
157 
PageImage(ViewImage * viewImage,long width,long height,float r,float x,float y,TransfoPerspective trans)158 PageImage::PageImage (ViewImage* viewImage, long width, long height, float r, float x, float y, TransfoPerspective trans)
159 
160 {
161   // Set the image pointers first
162   image     = new ViewImage (viewImage->GetImage());
163   if (image==NULL) {
164     return;
165   }
166 
167   rawImage    = viewImage->GetImage();
168 
169   // Set values
170   pixHeight = height; // height of the page in pixels
171   pixWidth  = width;  // width of the page in pixels
172   numLine   = -1;   // first line number set to an invalid value
173   lineSize  = 0;    // length of each line
174   buffer    = NULL;   // no buffer allocated...
175   line[0]   = NULL;   // ...
176   line[1]   = NULL;   // ...
177   line[2]   = NULL;   // ...
178   line[3]   = NULL;   // ...
179   resolution  = r;    // Set the resolution of the page in pixels per mm
180   xOrigin   = x;    // Set the position of the page in the world
181   yOrigin   = y;
182 
183   // Set the view image position
184   image->ApplyTransform(trans);
185 }
186 
~PageImage()187 PageImage::~PageImage ()
188 
189 {
190   delete image;
191   image = NULL;
192 
193   // Free memory buffer
194   if (buffer) {
195     FastDeleteArray(buffer,Pixel);
196   }
197   return;
198 }
199 
ComputeRotationMatrix(TransfoPerspective * position,float rotation)200 void PageImage::ComputeRotationMatrix (TransfoPerspective* position, float rotation)
201 {
202   PositionMv pointUV;
203   PositionMv p[4];
204 
205   if (rotation) {
206     position->Rotate ((float) 0.0,(float) 0.0, rotation);
207 
208     // Inverse position matrix (position is the xy to uv transformation)
209     TransfoPerspective uvToxy (*position);
210     uvToxy.Inverse();
211 
212     // Set first corner of image and transform
213     pointUV.h = (float) 0.0;
214     pointUV.v = (float) 0.0;
215     p[0] = uvToxy * pointUV;
216 
217     // Set second corner of image and transform
218     pointUV.h = (float)(rawImage->width)/rawImage->resolution;
219     pointUV.v = (float) 0.0;
220     p[1] = uvToxy * pointUV;
221 
222     // Set third corner of image and transform
223     pointUV.h = (float)(rawImage->width) /rawImage->resolution;
224     pointUV.v = (float)(rawImage->height)/rawImage->resolution;
225     p[2] = uvToxy * pointUV;
226 
227     // Set fourth corner of image and transform
228     pointUV.h = (float) 0.0;
229     pointUV.v = (float)(rawImage->height)/rawImage->resolution;
230     p[3] = uvToxy * pointUV;
231 
232     // Compute bounding box :
233     // init min and max values with the first point
234     PositionMv p0 = p[0];
235     PositionMv p1 = p[0];
236 
237     // loop to find min and max values in both direction
238     for (short i = 1; i < 4; i++) {
239       if (p[i].h < p0.h) p0.h = p[i].h;
240       if (p[i].v < p0.v) p0.v = p[i].v;
241       if (p[i].h > p1.h) p1.h = p[i].h;
242       if (p[i].v > p1.v) p1.v = p[i].v;
243     }
244 
245     // Translate the minimum point of the bounding box to the origin of the page
246     position->Translate (-p0.h, -p0.v);
247 
248     // Scale to fit the page size
249     float sh = ((float)(pixWidth)/resolution)/(p1.h - p0.h);
250     float sv = ((float)(pixHeight)/resolution)/(p1.v - p0.v);
251     float sx = MIN (sh,sv);
252     position->Scale ((float) 0.0,(float) 0.0, sx, sx);
253   }
254 
255   // Note that virtually, the page is 1 mm high, but it still makes
256   // sense because we dont't care about the real page size in mm...
257 
258 }
259 
260 
261 // Read the entire image page
ReadPage(Pixel * image)262 FPXStatus PageImage::ReadPage (Pixel* image)
263 {
264   Pixel     *pt;
265   unsigned char   *dest = NULL;
266   FPXStatus     status = FPX_OK;
267 
268   for (long i = 0; i < pixHeight; i++) {
269     // get line pointer from page (read it in file if necessary)
270     // PTCH_105 - added following code to implement progress callbacks....
271     if ( GtheSystemToolkit->fnctProgFunc)
272        if (GtheSystemToolkit->fnctProgFunc( pixHeight, i))
273         return FPX_USER_ABORT;
274     // PTCH_105 ....end of addition
275 
276     if (((pt = ReadLine (i, &status)) == NULL) || (status != FPX_OK)) {
277       break;
278     } else {
279       short plan = GtheSystemToolkit->activeChannel;
280       if ((plan != ActiveChannel_All) && (GtheSystemToolkit->interleaving == Interleaving_Channel)) {
281         // allocate an intermediate buffer
282         if (!dest)
283           FastAllocArray(dest,unsigned char,(unsigned int)(pixWidth));
284         if (dest == NULL) {
285           status = FPX_MEMORY_ALLOCATION_FAILED;
286           break;
287         }
288         // Pixel by pixel if planes specified, the destination contains only the choosed channel
289         register long j;
290         register unsigned char *src, *dst;
291         src = (unsigned char *)(pt)  + plan;
292         dst = dest;
293         for (j=0; j<pixWidth;j++,src+=sizeof(Pixel),dst++)
294           *dst = *src;
295         pt = (Pixel*)(dest);
296       } else {
297         // convert according to the interleaving option
298         if (Toolkit_Interleave (pt, pixWidth, 1)) {
299           status = FPX_MEMORY_ALLOCATION_FAILED;
300           break;
301         }
302       }
303       if (Toolkit_CopyInterleaved (image, pixWidth, pixHeight, pt, pixWidth, 1, 0, i)) {
304         status = FPX_MEMORY_ALLOCATION_FAILED;
305         break;
306       }
307     }
308   }
309   FastDeleteArray(dest,unsigned char);
310   return(status);
311 }
312 
313 
314 // Read a line of the page taking into account all global options
ReadPageLine(long lineNumber,Pixel * pixLine)315 FPXStatus PageImage::ReadPageLine (long lineNumber, Pixel* pixLine)
316 {
317   Pixel   *pt;
318   FPXStatus   status;
319 
320   // get line pointer from page (read it in file if necessary)
321   pt = ReadLine (lineNumber, &status);
322 
323   if (pt && (status == FPX_OK)) {
324 
325     short plan = GtheSystemToolkit->activeChannel;
326     if ((plan != ActiveChannel_All) && (GtheSystemToolkit->interleaving == Interleaving_Channel)) {
327       // Pixel by pixel if planes specified, the destination contains only the choosen channel
328       register long j;
329       register unsigned char *src, *dst;
330       src = (unsigned char *)(pt)  + plan;
331       dst = (unsigned char *)pixLine;
332       for (j=0; j<pixWidth;j++,src+=sizeof(Pixel),dst++)
333         *dst = *src;
334     } else {
335       // copy pixels in pixLine
336       if (plan == ActiveChannel_All) {
337         // Copy pixels to the buffer
338         BlockMove(pt,pixLine,pixWidth*sizeof(Pixel));
339       } else {
340         // Pixel by pixel if planes specified
341         register long j;
342         register unsigned char *src, *dst;
343         src = (unsigned char *)(pt)  + plan;
344         dst = (unsigned char *)(pixLine) + plan;
345         for (j=0; j<pixWidth;j++,src+=sizeof(Pixel),dst+=sizeof(Pixel))
346           *dst = *src;
347       }
348       // convert according to the interleaving option
349       if (Toolkit_Interleave (pixLine, pixWidth, 1))
350         status = FPX_MEMORY_ALLOCATION_FAILED;
351     }
352   }
353 
354   return(status);
355 }
356 
357 
358 // Give a pointer on the pixel line
359 // Caution : this function doesn't take interleaving option into account
ReadLine(long lineNumber,FPXStatus * status)360 Pixel* PageImage::ReadLine (long lineNumber, FPXStatus* status)
361 {
362   // test if line has been already read :
363   if ((lineNumber & ~0x3) == numLine) {     // previous multiple by 4 of x is : x & ~0x3
364     *status = FPX_OK;
365     return (line[lineNumber & 0x3]);      // rest by 4 of x is : x & 0x3
366   }
367 
368   long lineLength = (pixWidth + 3) & ~3;
369   // Read 4 lines including the searched one
370   // PTCH_105 - removed non-FlashPix call and disabled progress reporting thru this routine
371   *status = ReadRectangle(0, lineNumber, lineLength, lineNumber+1, NULL, lineLength,
372         PRIImage::readInterpolated, 0);
373 
374   // return the buffer pointer to the calling routine
375   return (line[lineNumber & 0x3]);            // rest by 4 of x is : x & 0x3
376 }
377 
378 
379 
380 // read a rectangle by samples
381 // bufPix must be allowed before the call
382 // PTCH_105 - added 'reportProgress' argument
ReadRectangle(long left,long top,long right,long bottom,Pixel * bufPix,long bufWidth,Boolean withAntialias,Boolean reportProgress)383 FPXStatus PageImage::ReadRectangle(long left, long top, long right, long bottom, Pixel* bufPix,
384             long bufWidth, Boolean withAntialias, Boolean reportProgress)
385 {
386   Pixel     pix[16];
387   Pixel     pixEmpty[16];
388   Pixel   *dest;
389   long    i;
390   long    j;
391   FPXStatus status = FPX_OK;
392   const long  left4 = left & ~3;    // 'left' aligned to a multiple of 4
393 
394   // Allocate buffer if necessary
395   long lineLength = ((right+3) & ~3) - left4;
396   if (!buffer || (lineSize != lineLength)) {
397     if (buffer)
398       FastDeleteArray(buffer, Pixel);
399     FastAllocArray(buffer,Pixel,4*lineLength);  // size of the buffer : 4 full lines
400     if ( buffer == NULL)
401       return FPX_MEMORY_ALLOCATION_FAILED;
402     line[0] = buffer;
403     line[1] = line[0] + lineLength;
404     line[2] = line[1] + lineLength;
405     line[3] = line[2] + lineLength;
406     lineSize = lineLength;
407     numLine = -1;
408   }
409   long    line3 = lineSize*2;
410   long    line4 = lineSize*3;
411 
412   // Set the antialiasing
413   Boolean oldMode = PRIImage::readInterpolated;
414   if (withAntialias)
415     PRIImage::readInterpolated = true;
416 
417   // Initialize pixEmpty with the backGround
418   for (i = 0 ; i < 16 ; i++)
419     pixEmpty[i] = GtheSystemToolkit->backgroundColor;
420 
421   float xOrigin05 = (float) (xOrigin + 0.5/resolution);
422   float yOrigin05 = (float) (yOrigin + 0.5/resolution);
423 
424   for (j = top; j < bottom; j ++) {
425     // PTCH_105 added following to implement progress callbacks....
426     if ( reportProgress && GtheSystemToolkit->fnctProgFunc)
427        if (GtheSystemToolkit->fnctProgFunc( bottom - top, j - top))
428         return FPX_USER_ABORT;
429     // PTCH_105 ....end of addition
430 
431     if (((j & ~0x3) != numLine) || (j == top)) {
432       FPXStatus readStatus;     // CHG_FILE_ERR - used to save intermediate error
433       numLine = j & ~0x3;
434 
435       dest  = buffer;
436       for (i = left4 ; i < right; i += 4) {
437         // Erase the pix buffer with the background
438         memcpy (pix, pixEmpty, (unsigned int)(16*sizeof(Pixel)));
439 
440         // Read a sample
441         float x0 = (float)(i)  /resolution + xOrigin05;
442         float x1 = (float)(i+4)/resolution + xOrigin05;
443         float y0 = (float)(numLine)  /resolution + yOrigin05;
444         float y1 = (float)(numLine+4)/resolution + yOrigin05;
445         if((readStatus = image->Read4x4Points (x0, y0, x1, y1, pix))) // CHG_FILE_ERR - if error
446           status = readStatus;                  //  then copy it to 'status'
447         BlockMove(pix,dest,4*sizeof(Pixel));
448         BlockMove(pix+4,dest+lineSize,4*sizeof(Pixel));
449         BlockMove(pix+8,dest+line3,4*sizeof(Pixel));
450         BlockMove(pix+12,dest+line4,4*sizeof(Pixel));
451         dest+=4;
452       }
453     }
454     if (bufPix) {
455       dest  = bufPix + ((j-top)*bufWidth);
456       BlockMove(line[j & 0x3]+(left & 0x3),dest,(right-left)*sizeof(Pixel));
457     }
458   }
459 
460   // reset antialiasing
461   PRIImage::readInterpolated = oldMode;
462 
463   return status;
464 }
465 
466