QNANO
utilities.h
1 #include <iostream>
2 #include <fstream>
3 #include <cstdlib>
4 #include <cctype>
5 #include <cmath>
6 
7 #define EM_GTE (1)
8 #define EM_DAT (2)
9 
10 using namespace std ;
11 
12 /* Routines in this file:
13 
14 int read_PNM_file( char * file_name,
15  int &width,
16  int &height,
17  int &max_color_depth,
18  int &type,
19  unsigned char ** data )
20 
21 int read_GTE_file( char * file_name,
22  double & length_x,
23  double & length_y,
24  int &points_x,
25  int &points_y,
26  int &max_color_depth,
27  unsigned char ** data )
28 
29 
30 int emit_PNM_file( int points_x,
31  int points_y,
32  unsigned char * data )
33 
34 int emit_data( int no_of_columns,
35  int no_of_rows ,
36  double length_x,
37  double length_y,
38  int mode,
39  unsigned char * image_data )
40 
41 int scale_data( int scale,
42  int points_x,
43  int points_y,
44  unsigned char * data )
45 
46 int invert_data( int points_x,
47  int points_y,
48  int relative,
49  unsigned char * data )
50 
51 int blow_up( int scale,
52  double scale_x,
53  double scale_y,
54  int & points_x,
55  int & points_y,
56  unsigned char ** data )
57 
58 
59 */
60 
61 /*------------------------------------------------------------------------
62  IMPLEMENTATION
63 ------------------------------------------------------------------------*/
64 
65 /*------------------------------------------------------------------------
66  read_PNM_file
67 ------------------------------------------------------------------------*/
68 
69 
70 int read_PNM_file( char * file_name,
71  int &width,
72  int &height,
73  int &max_color_depth,
74  int &type,
75  unsigned char ** data )
76 {
77 
78  /* returned type:
79  2 = Grayscale ASCII ( equiv. P2 )
80  3 = RGB ASCII ( equiv. P3 )
81  5 = Grayscale binary ( equiv. P5 )
82  6 = RGB binary ( equiv. P6 ) */
83 
84 
85  int status ;
86 
87  ifstream PNM_file ;
88  char PNM_descriptor[ 10 ] ;
89  char buffer, can_continue, endlin[ 10 ] ;
90  unsigned char byte_read ;
91  int int_read ;
92  long total_number_of_pixels ;
93  long index ;
94  int image_stats[ 3 ] ;
95 
96  status = 0 ;
97 
98 
99  if ( file_name != NULL )
100  {
101  PNM_file.open( file_name ) ;
102  if ( !PNM_file )
103  {
104  cerr << "ERROR! File " << file_name
105  << " could not be opened! Exiting.\n" ;
106  exit( 1 ) ;
107  }
108  }
109 
110  /* Trying to get the descriptor */
111 
112  while (
113  ( ( file_name != NULL )?PNM_file.peek():cin.peek() )
114  == (int)'#' )
115  {
116  ( file_name != NULL )?PNM_file.ignore( 1000, (int)'\n' ):
117  cin.ignore( 1000, (int)'\n' ) ;
118  }
119 
120  /* Recognize PNM descriptor */
121 
122  ( file_name != NULL )?PNM_file.getline( PNM_descriptor, 10 ):
123  cin.getline( PNM_descriptor, 10 ) ;
124 
125  switch( PNM_descriptor[1] )
126  {
127 
128  case '2':
129  type = 2 ;
130  break ;
131  case '3':
132  type = 3 ;
133  break ;
134  case '5':
135  type = 5 ;
136  break ;
137  case '6':
138  type = 6 ;
139  break ;
140  default:
141  type = 0 ;
142  status = -1 ;
143  cerr << "\nERROR: "
144  << "Unrecognized PNM format! Exiting\n" ;
145  exit( 1 ) ;
146  break ;
147 
148  }
149 
150  /* Establish image width, height, and color depth */
151 
152  index = 0 ;
153  do
154  {
155 
156  do
157  {
158  can_continue = 1 ;
159 
160  (file_name != NULL)?buffer = PNM_file.peek():
161  buffer = cin.peek() ;
162 
163  if ( buffer == '#')
164  {
165  (file_name != NULL)?
166  PNM_file.ignore( 1000, (int)'\n' ):
167  cin.ignore( 1000, (int)'\n' ) ;
168 
169  can_continue = 0 ;
170  }
171  else if ( !isdigit( buffer ) )
172  {
173  ( file_name != NULL )?
174  PNM_file.ignore( 1 ):
175  cin.ignore( 1 ) ;
176 
177  can_continue = 0 ;
178  }
179  }
180  while ( !can_continue ) ;
181 
182  ( file_name != NULL )?
183  PNM_file >> image_stats[ index ]:
184  cin >> image_stats[ index ] ;
185 
186  index++ ;
187  }
188  while ( index < 3 ) ;
189 
190 
191  width = image_stats[ 0 ] ;
192  height = image_stats[ 1 ] ;
193  max_color_depth = image_stats[ 2 ] ;
194 
195  /* Now allocate the data array depending on the type of the file */
196 
197  total_number_of_pixels = width * height ;
198 
199 
200  if ( ( type == 3 ) || ( type == 6 ) )
201  {
202  total_number_of_pixels *= 3 ;
203  }
204 
205  ( *data ) = new unsigned char [ total_number_of_pixels ] ;
206 
207 
208  /* Prepare to retrieve image data */
209  ( file_name != NULL )?
210  PNM_file.ignore( 1000, (int)'\n' ):
211  cin.ignore( 1000, (int)'\n' ) ;
212 
213 
214  /* Now perform the reading - either in ASCII or in binary */
215 
216  can_continue = 1 ;
217  if ( type > 4 )
218  {
219  /* WE ARE BINARY */
220  for ( index = 0 ; index < total_number_of_pixels ; index++ )
221  {
222 
223  if ( (file_name != NULL)?PNM_file.good():cin.good() )
224  {
225  (*data)[ index ] =
226  (file_name != NULL)?PNM_file.get():cin.get() ;
227  }
228  else
229  {
230  can_continue = 0 ;
231  break ;
232  }
233  }
234  }
235  else
236  {
237 
238  /* WE ARE ASCII */
239  for ( index = 0 ; index < total_number_of_pixels ; index++ )
240  {
241 
242  while( !( isdigit((file_name != NULL)?PNM_file.peek():
243  cin.peek() )
244  || ( (file_name != NULL)?PNM_file.eof():0 )
245  )
246  )
247  {
248  (file_name != NULL)?
249  PNM_file.ignore( 1 ):
250  cin.ignore( 1 );
251  }
252  if ( (file_name != NULL)?PNM_file.good():cin.good() )
253  {
254 
255  (file_name != NULL)?PNM_file >> int_read:
256  cin >> int_read ;
257  (*data)[ index ] = (unsigned char)int_read ;
258 
259  }
260  else
261  {
262  can_continue = 0 ;
263  break ;
264  }
265  }
266 
267 
268  }
269 
270  if ( !can_continue )
271  {
272  cerr << "Error! The PNM file appears to be too short! Exiting!\n" ;
273  delete [] (*data) ;
274  exit( 1 ) ;
275  }
276 
277  if ( file_name != NULL )
278  {
279  PNM_file.close() ;
280  }
281  return( status ) ;
282 
283 }
284 
285 
286 /*------------------------------------------------------------------------
287  read_GTE_file
288 ------------------------------------------------------------------------*/
289 
290 
291 int read_GTE_file( char * file_name,
292  double & length_x,
293  double & length_y,
294  int &points_x,
295  int &points_y,
296  unsigned char ** data )
297 {
298 
299  int status ;
300  ifstream GTE_file ;
301  char buffer ;
302  double numread ;
303  long total_number_of_points, position_in_dataset ;
304  int index_x, index_y ;
305  double delta_x, delta_y ;
306  int value ;
307 
308  status = 0 ;
309 
310 
311  if ( file_name != NULL )
312  {
313  GTE_file.open( file_name ) ;
314  if ( !GTE_file )
315  {
316  cerr << "ERROR! File " << file_name
317  << " could not be opened! Exiting.\n" ;
318  exit( 1 ) ;
319  }
320  }
321 
322  /* Information about the lengths and numbers of points */
323 
324  while( !( isdigit((file_name != NULL)?GTE_file.peek():
325  cin.peek() )
326  || ( (file_name != NULL)?GTE_file.eof():0 )
327  )
328  )
329  {
330  (file_name != NULL)?GTE_file.ignore( 1 ):cin.ignore( 1 );
331  }
332 
333  ( file_name != NULL)?(GTE_file >> length_x):( cin >> length_x ) ;
334 
335 
336  while( !( isdigit((file_name != NULL)?GTE_file.peek():
337  cin.peek() )
338  || ( (file_name != NULL)?GTE_file.eof():0 )
339  )
340  )
341  {
342  (file_name != NULL)?GTE_file.ignore( 1 ):cin.ignore( 1 );
343  }
344 
345  ( file_name != NULL)?(GTE_file >> numread):( cin >> numread ) ;
346  points_x = (int)numread ;
347 
348  while( !( isdigit((file_name != NULL)?GTE_file.peek():
349  cin.peek() )
350  || ( (file_name != NULL)?GTE_file.eof():0 )
351  )
352  )
353  {
354  (file_name != NULL)?GTE_file.ignore( 1 ):cin.ignore( 1 );
355  }
356 
357  ( file_name != NULL)?(GTE_file >> length_y):( cin >> length_y ) ;
358 
359 
360  while( !( isdigit((file_name != NULL)?GTE_file.peek():
361  cin.peek() )
362  || ( (file_name != NULL)?GTE_file.eof():0 )
363  )
364  )
365  {
366  (file_name != NULL)?GTE_file.ignore( 1 ):cin.ignore( 1 );
367  }
368 
369  ( file_name != NULL)?(GTE_file >> numread):( cin >> numread ) ;
370  points_y = (int)(numread) ;
371 
372  delta_x = length_x / ( (double)( points_x - 1 ) ) ;
373  length_x += delta_x ;
374 
375  delta_y = length_y / ( (double)( points_y - 1 ) ) ;
376  length_y += delta_y ;
377 
378  /* Get ready to read the data */
379 
380  total_number_of_points = points_x * points_y ;
381 
382  (*data) = new unsigned char [ total_number_of_points ] ;
383 
384  for ( index_y = 0 ; index_y < points_y ; index_y++ )
385  {
386 
387  position_in_dataset = ( points_y - 1 - index_y ) * points_x ;
388 
389  for ( index_x = 0 ; index_x < points_x ; index_x++ )
390  {
391  while( !( isdigit((file_name != NULL)?GTE_file.peek():
392  cin.peek() )
393  || ( (file_name != NULL)?GTE_file.eof():0 )
394  )
395  )
396  {
397  (file_name != NULL)?
398  GTE_file.ignore( 1 ):cin.ignore( 1 );
399  }
400 
401  if ( (file_name != NULL)?GTE_file.good():cin.good() )
402  {
403 
404  (file_name != NULL)?GTE_file >> value:
405  cin >> value ;
406 
407  (*data)[ position_in_dataset ]
408  = (unsigned char)value ;
409 
410  position_in_dataset++ ;
411 
412  }
413  else
414  {
415  status = 1 ;
416  break ;
417  }
418 
419  }
420 
421  if ( status == 1) break ;
422  }
423 
424 
425  if ( status == 1 )
426  {
427  cerr << "Error! The GTE file appears to be too short! Exiting!\n" ;
428  delete [] (*data) ;
429  exit( 1 ) ;
430  }
431 
432 
433  return( status ) ;
434 
435 }
436 
437 
438 /*------------------------------------------------------------------------
439  emit_PNM_file
440 ------------------------------------------------------------------------*/
441 
442 
443 int emit_PNM_file( int points_x,
444  int points_y,
445  unsigned char * data )
446 {
447 
448  long total_number_of_pixels, index ;
449 
450  int status ;
451 
452  status = 0 ;
453 
454  cout << "P5" << endl ;
455  cout << points_x << " " << points_y << endl ;
456  cout << "255" << endl ;
457 
458  total_number_of_pixels = points_x * points_y ;
459 
460  /* Now perform the writing - always in binary */
461 
462  for ( index = 0 ; index < total_number_of_pixels ; index++ )
463  {
464  cout << data[ index ] ;
465  }
466 
467  cout << endl ;
468 
469  return( status ) ;
470 
471 }
472 
473 
474 
475 /*------------------------------------------------------------------------
476  emit_data
477 ------------------------------------------------------------------------*/
478 
479 
480 int emit_data( int no_of_columns,
481  int no_of_rows ,
482  double length_x,
483  double length_y,
484  int mode,
485  unsigned char * image_data )
486 {
487 
488  int status ;
489  double delta_x, delta_y ;
490  int index_x, index_y ;
491  int image_pixel_row, image_pixel_column, index_in_image_data ;
492  double position_x, position_y ;
493  int value ;
494 
495  status = 0 ;
496 
497  if (length_x == 0.0 ) length_x = (double)no_of_columns ;
498  if (length_y == 0.0 ) length_y = (double)no_of_rows ;
499 
500  delta_x = length_x / ((double) no_of_columns ) ;
501  delta_y = length_y / ((double) no_of_rows ) ;
502 
503 
504  /* Emission starts with the length and resolution parameters */
505 
506  if ( mode == EM_GTE )
507  {
508  cout << length_x - delta_x << " "
509  << no_of_columns << endl ;
510  cout << length_y - delta_y << " "
511  << no_of_rows << endl ;
512  }
513 
514  /* Note that image_data contains data in order assuming that
515  the origin is the UPPER LEFT-HAND corner, and the Y-axis is
516  directed downwards. We have to change this. For us, the origin
517  has to be in the LOWER LEFT-HAND corner, and the Y-axis
518  is directed UPwards. We have to put image_data on its head then! */
519 
520  /* image_data has no_of_columns points in the x direction
521  and no_of_rows points in the y direction. Data is stored row-by-row. */
522 
523  /* Activity 1. Establish the scaling of the DISTANCEs - i.e.,
524  separation of "effective pixels " */
525 
526 
527  /* Activity 2. Loop through all new points. Find the pixels
528  they fall into. Retrieve the appropriate value. Emit it. */
529 
530  for ( index_y = 0 ; index_y < no_of_rows ; index_y++)
531  {
532 
533  /* We need to switch it around so that the origin is
534  actually the LOWER left hand corner */
535 
536  position_y = (double)index_y * delta_y ;
537 
538  image_pixel_row = no_of_rows - 1 - index_y ;
539 
540  for ( index_x = 0 ; index_x < no_of_columns ; index_x++ )
541  {
542 
543  position_x = (double)index_x * delta_x ;
544  image_pixel_column = index_x ;
545 
546  index_in_image_data = image_pixel_row * no_of_columns ;
547  index_in_image_data += image_pixel_column ;
548 
549  if ( mode == EM_GTE )
550  {
551  cout <<
552  (int) image_data[index_in_image_data] << " " ;
553  }
554  else if ( mode == EM_DAT )
555  {
556  cout << position_x << " "
557  << position_y << " "
558  <<(int) image_data[index_in_image_data]
559  << endl ;
560 
561  }
562  }
563  if ( mode == EM_GTE )
564  {
565  cout << endl ;
566  }
567  }
568 
569  return( status ) ;
570 
571 }
572 
573 /*------------------------------------------------------------------------
574  scale_data
575 ------------------------------------------------------------------------*/
576 
577 
578 int scale_data( int scale,
579  int points_x,
580  int points_y,
581  unsigned char * data )
582 {
583 
584  int status ;
585  long index ;
586  long no_of_points ;
587  unsigned char saturation_max, saturation_min, value ;
588 
589  status = 0 ;
590 
591  if ( scale == 0 )
592  {
593  return( status ) ;
594  }
595 
596  no_of_points = points_x * points_y ;
597 
598 
599  /* Parse the datafile. Find the max and the min saturation */
600 
601  saturation_max = 0 ;
602  saturation_min = 255 ;
603 
604  for ( index = 0 ; index < no_of_points ; index++ )
605  {
606 
607  value = data[ index ] ;
608  if ( value > saturation_max )
609  {
610  saturation_max = value ;
611  }
612  if ( value < saturation_min )
613  {
614  saturation_min = value ;
615  }
616  }
617 
618 
619  saturation_max = saturation_max - saturation_min ;
620 
621  /* The data have values from saturation_min to saturation_max.
622  We want to rescale so they range from 0 to 255. */
623 
624  for ( index = 0 ; index < no_of_points ; index++ )
625  {
626  value = data[ index ] ;
627  value = value - saturation_min ;
628  value = (unsigned char)( (double)value * 255.0 /
629  (double)saturation_max ) ;
630  data[ index ] = value ;
631  }
632 
633  return( status ) ;
634 
635 }
636 
637 /*------------------------------------------------------------------------
638  invert_data
639 ------------------------------------------------------------------------*/
640 
641 int invert_data( int points_x,
642  int points_y,
643  int relative,
644  unsigned char * data )
645 {
646 
647  int status ;
648  long index ;
649  long no_of_points ;
650  unsigned char saturation_max, saturation_min, temp ;
651 
652  status = 0 ;
653 
654  no_of_points = points_x * points_y ;
655 
656  if ( relative == 0 )
657  {
658  for ( index = 0 ; index < no_of_points ; index++ )
659  {
660 
661  temp = 255 - data[ index ] ;
662  data[ index ] = temp ;
663  }
664  }
665  else
666  {
667 
668  /* find max and min saturation */
669 
670  saturation_max = 0 ;
671  saturation_min = 255 ;
672 
673  for ( index = 0 ; index < no_of_points ; index++ )
674  {
675  temp = data[ index ];
676  if ( temp < saturation_min )
677  {
678  saturation_min = temp ;
679  }
680  if ( temp > saturation_max )
681  {
682  saturation_max = temp ;
683  }
684  }
685 
686  /* inversion proper */
687 
688  for ( index = 0 ; index < no_of_points ; index++ )
689  {
690  temp = saturation_max - data[ index ];
691  temp += saturation_min ;
692 
693  data[ index ] = temp ;
694 
695  }
696 
697 
698  }
699 
700  return( status ) ;
701 
702 }
703 
704 /*------------------------------------------------------------------------
705  blow_up
706 ------------------------------------------------------------------------*/
707 
708 int blow_up( int scale,
709  double scale_x,
710  double scale_y,
711  int & points_x,
712  int & points_y,
713  unsigned char ** data )
714 {
715 
716  int status ;
717  long no_of_points_old, no_of_points_new, index ;
718  int index_x, index_y, index_x_old, index_y_old ;
719  int points_x_new, points_y_new ;
720  long position_in_old, position_in_new ;
721  unsigned char value ;
722  unsigned char * new_data ;
723 
724  status = 0 ;
725 
726  /* scale = whether to adjust the clolr depth to max
727  scale_x = change of resolution along x axis
728  scale_y = change of resolution along y axis */
729 
730  scale_data( scale, points_x, points_y, (*data) ) ;
731 
732 
733  /* Be graceful when the scales happen to be negative */
734  scale_x = fabs( scale_x ) ;
735  scale_y = fabs( scale_y ) ;
736 
737  /* adjust for smallness */
738  if ( scale_x == 0.0 ) scale_x = 0.01 ;
739  if ( scale_y == 0.0 ) scale_y = 0.01 ;
740 
741  points_x_new = (int)( (double)points_x * scale_x ) ;
742  points_y_new = (int)( (double)points_y * scale_y ) ;
743 
744 
745  if ( ( scale_x != 1.0 ) || ( scale_y != 1.0 ) )
746  {
747 
748  no_of_points_old = points_x * points_y ;
749  no_of_points_new = points_x_new * points_y_new ;
750 
751 
752  new_data = new unsigned char [ no_of_points_new ] ;
753 
754  for ( index_y = 0 ; index_y < points_y_new ; index_y++ )
755  {
756 
757  position_in_new = index_y * points_x_new ;
758 
759  index_y_old = (int)( (double)index_y / scale_y ) ;
760 
761  for ( index_x = 0 ; index_x < points_x_new ; index_x++ )
762  {
763 
764  index_x_old = (int)( (double)index_x / scale_x ) ;
765 
766 
767  position_in_old = index_y_old * points_x +
768  index_x_old ;
769 
770  new_data[ position_in_new ] =
771  (*data)[ position_in_old ] ;
772 
773  position_in_new++ ;
774  }
775  }
776 
777  delete[] (*data) ;
778  (*data) = new_data ;
779 
780  }
781 
782  points_x = points_x_new ;
783  points_y = points_y_new ;
784 
785  return( status ) ;
786 }
787 
788 /*----------------------------------------------------------------------*/
789 
790 /*----------------------------------------------------------------------*/